- commit
- 7787b6a8ea647f61008ef13a4f0a35bee1081e0b
- parent
- ce387830a71d5822a78ce00ee1a0622e3962ec7c
- author
- Dami <dami.etoile@gmail.com>
| M | README.md | 6 | +++--- |
| M | cli/ | 3 | ++- |
| M | cli/ | 15 | +++++++++++++-- |
| M | cli/ | 15 | ++++++++++++++- |
| M | cli/ | 14 | ++++++++++++-- |
| M | skills/ | 3 | ++- |
@@ -94,7 +94,7 @@ nzip
9494 │ ├─ <body> [--title TEXT] [--open TARGET] [--tag TEXT]9595 │ ├─ test send a diagnostic notification9696 │ ├─ approve <code> --name NAME [--yes]97-│ ├─ devices list paired notification devices97+│ ├─ devices [--all] list current notification devices9898 │ └─ revoke <device-id> [--yes] revoke a notification device9999 └─ revert <target> [--to N] [--list] inspect or restore push history100100 @@ -135,8 +135,8 @@ Wait for `paired` before installing the PWA. In the installed app, tap
135135 `notifications off` to request permission and attach the subscription. Send a136136 message with `nzip notify "Build finished"`; add `--open work:report` to open an137137 existing same-origin site when the notification is tapped. Use138-`nzip notify devices` to inspect delivery health and `nzip notify revoke` to139-remove a device.138+`nzip notify devices` to inspect current delivery health and `nzip notify revoke` to139+remove a device. Pass `--all` to include disabled, revoked, and expired tombstones.140140 141141 Notification titles and bodies may be visible on a lock screen. Never put142142 passwords, tokens, private URLs, or sensitive personal data in them. If an@@ -55,7 +55,7 @@ nzip
5555 │ ├─ <body> [--title TEXT] [--open TARGET] [--tag TEXT]5656 │ ├─ test send a diagnostic notification5757 │ ├─ approve <code> --name NAME [--yes]58-│ ├─ devices list paired notification devices58+│ ├─ devices [--all] list current notification devices5959 │ └─ revoke <device-id> [--yes] revoke a notification device6060 └─ revert <target> [--to N] [--list] inspect or restore push history6161 @@ -82,6 +82,7 @@ authenticated CLI:
8282 ```sh8383 nzip notify approve ABCD-1234 --name "Personal phone"8484 nzip notify devices85+nzip notify devices --all # include disabled, revoked, and expired tombstones8586 nzip notify "Report ready" --title "nzip" --open work:report8687 ```8788 @@ -1,4 +1,4 @@
1-import type { NotifyApprovalPreview, NotifyRequest } from "@nzip/shared";1+import type { NotifyApprovalPreview, NotifyDeviceInfo, NotifyRequest } from "@nzip/shared";22 import { ApiClient, resolveCliTarget } from "../lib/api.ts";33 import type { Config } from "../lib/config.ts";44 import { ago, bold, cyan, dim, emit, fail, green, table } from "../lib/fmt.ts";@@ -43,6 +43,16 @@ function location(preview: NotifyApprovalPreview): string {
4343 return [preview.country, preview.region].filter(Boolean).join("/") || "unknown";4444 }4545 46+export function filterNotificationDevices(47+ devices: NotifyDeviceInfo[],48+ includeAll: boolean,49+): NotifyDeviceInfo[] {50+ if (includeAll) return devices;51+ return devices.filter((device) =>52+ device.status === "pending" || device.status === "approved" || device.status === "active"53+ );54+}55+4656 export async function cmdNotify(4757 config: Config,4858 rest: string[],@@ -52,13 +62,14 @@ export async function cmdNotify(
5262 tag?: string;5363 name?: string;5464 yes: boolean;65+ all: boolean;5566 },5667 ): Promise<void> {5768 const invocation = parseNotifyInvocation(rest);5869 const api = new ApiClient(config);5970 6071 if (invocation.kind === "devices") {61- const devices = await api.notificationDevices();72+ const devices = filterNotificationDevices(await api.notificationDevices(), options.all);6273 emit(() => {6374 if (devices.length === 0) return console.log(dim("no notification devices"));6475 console.log(table(@@ -1,4 +1,5 @@
1-import { parseNotifyInvocation } from "./notify.ts";1+import type { NotifyDeviceInfo } from "@nzip/shared";2+import { filterNotificationDevices, parseNotifyInvocation } from "./notify.ts";23 34 function assertEquals(actual: unknown, expected: unknown): void {45 if (JSON.stringify(actual) !== JSON.stringify(expected)) {@@ -32,3 +33,15 @@ Deno.test("notify parses test and device management subcommands", () => {
3233 deviceId: "device-1",3334 });3435 });36+37+Deno.test("notify devices hides tombstones unless all devices are requested", () => {38+ const devices = ["pending", "approved", "active", "disabled", "revoked", "expired"].map(39+ (status) => ({ status } as NotifyDeviceInfo),40+ );41+42+ assertEquals(43+ filterNotificationDevices(devices, false).map((device) => device.status),44+ ["pending", "approved", "active"],45+ );46+ assertEquals(filterNotificationDevices(devices, true), devices);47+});@@ -49,7 +49,7 @@ commands:
4949 │ ├─ <body> [--title TEXT] [--open TARGET] [--tag TEXT]5050 │ ├─ test queue a diagnostic notification5151 │ ├─ approve <code> --name NAME [--yes]52- │ ├─ devices list notification devices52+ │ ├─ devices [--all] list current notification devices5353 │ └─ revoke <device-id> [--yes] revoke a notification device5454 └─ revert <target> [--to N] [--list] inspect or restore push history5555 @@ -82,7 +82,16 @@ async function main(): Promise<void> {
8282 "open",8383 "tag",8484 ],85- boolean: ["yes", "list", "help", "no-password", "overwrite", "json", "no-description"],85+ boolean: [86+ "yes",87+ "list",88+ "help",89+ "no-password",90+ "overwrite",91+ "json",92+ "no-description",93+ "all",94+ ],8695 alias: { h: "help", y: "yes" },8796 });8897 setJsonMode(args.json);@@ -137,6 +146,7 @@ async function main(): Promise<void> {
137146 tag: args.tag,138147 name: args.name,139148 yes: args.yes,149+ all: args.all,140150 });141151 case "revert":142152 return await cmdRevert(config, rest[0], toSeq, args.list);@@ -138,7 +138,8 @@ own; approval still uses the configured owner bearer token.
138138 5. Run `nzip notify test` only when the user explicitly requests an end-to-end test.139139 6. Send only on explicit request with140140 `nzip notify <body> [--title TEXT] [--open TARGET] [--tag TEXT]`.141-7. Inspect delivery health with `nzip notify devices --json`.141+7. Inspect current delivery health with `nzip notify devices --json`. Add `--all` only when142+ disabled, revoked, or expired tombstones are relevant.142143 143144 If the installed app loses its pairing cookie, instruct the user to remove it, pair again in the144145 browser, wait for `paired`, and reinstall it. Revoke a device only on explicit request.