@rei-standard/amsg-shared 0.1.0 → 0.2.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/README.md CHANGED
@@ -48,6 +48,30 @@ origin** (`'instant'` for `amsg-instant`, `'scheduled'` for any
48
48
 
49
49
  ---
50
50
 
51
+ ## Notification directive
52
+
53
+ `ContentPush` and `ToolRequestPush` can carry an optional
54
+ `notification` object. It is a producer-side hint consumed by
55
+ `@rei-standard/amsg-sw` before rendering a system notification.
56
+
57
+ | Field | Type | Notes |
58
+ |----------------------|-------------------------------------------|-------|
59
+ | `show` | `'auto' \| 'always' \| 'when-hidden' \| false` | Display policy. `auto` follows SW defaults. |
60
+ | `title` | `string?` | Notification title override. |
61
+ | `body` | `string?` | Notification body override. |
62
+ | `icon` | `string?` | Notification icon URL. |
63
+ | `badge` | `string?` | Notification badge URL. |
64
+ | `tag` | `string?` | Notification grouping tag. |
65
+ | `renotify` | `boolean?` | Re-alert when a matching `tag` replaces an existing notification. |
66
+ | `requireInteraction` | `boolean?` | Keep the notification visible until the user dismisses it. |
67
+ | `silent` | `boolean?` | Suppress notification sound and vibration. |
68
+ | `data` | `Record<string, unknown>?` | Custom data passed to the notification. |
69
+
70
+ Unknown fields are preserved for forward compatibility, but the known
71
+ fields above are validated by the builders when present.
72
+
73
+ ---
74
+
51
75
  ## Per-kind fields
52
76
 
53
77
  ### `ContentPush` — final user-facing content
package/dist/index.cjs CHANGED
@@ -159,7 +159,7 @@ function validateNotificationArg(kind, value) {
159
159
  throw new Error(`[amsg-shared] ${kind}: 'notification.${f}' must be a string when present`);
160
160
  }
161
161
  }
162
- for (const f of ["renotify", "requireInteraction"]) {
162
+ for (const f of ["renotify", "requireInteraction", "silent"]) {
163
163
  if (n[f] !== void 0 && typeof n[f] !== "boolean") {
164
164
  throw new Error(`[amsg-shared] ${kind}: 'notification.${f}' must be a boolean when present`);
165
165
  }
package/dist/index.d.cts CHANGED
@@ -200,10 +200,10 @@ export function isErrorPush(value: unknown): value is ErrorPush;
200
200
  /**
201
201
  * Slice a string into UTF-8 byte chunks no larger than `maxBytes`,
202
202
  * always cutting at codepoint boundaries (never inside a multi-byte
203
- * char). Designed for the {@link ReasoningPush} byte-chunking path
204
- * in amsg-instant — producers facing the ~3 KB Web Push payload
205
- * limit slice oversized reasoning into N pushes with
206
- * `chunkIndex` / `totalChunks`, the SW reassembles by concat.
203
+ * char). This is a generic byte-safe string helper retained for
204
+ * callers that need deterministic UTF-8 chunking around small Web Push
205
+ * payload budgets; current amsg-instant oversized payload delivery uses
206
+ * BlobStore / generic multipart instead of reasoning-only wire fields.
207
207
  *
208
208
  * Algorithm: TextEncoder → Uint8Array → backward scan from each
209
209
  * candidate cut index until the byte is a UTF-8 lead byte (any byte
@@ -361,18 +361,21 @@ export type AmsgPushCommon = {
361
361
  };
362
362
  /**
363
363
  * SW-rendering directive. Mirrors the fields that `amsg-sw`'s
364
- * `createNotificationFromPayload` consumes (`notification.{title,body,icon,badge,tag,renotify,requireInteraction,data}`)
365
- * — typing all fields so callers don't lose IDE checking and slip back into the untyped-spread footgun.
364
+ * `createNotificationFromPayload` consumes (`notification.{show,title,body,icon,badge,tag,renotify,requireInteraction,silent,data}`)
365
+ * so producers get builder validation for the fields the SW actually reads.
366
366
  *
367
- * Routing in SW (kept here so producers don't have to cross-check):
367
+ * Routing in SW:
368
368
  * - By default (`show: "auto"` or omitted), `messageKind: 'content'` (and legacy un-kinded payloads)
369
369
  * will display a system notification. `reasoning` / `tool_request` / `error` will dispatch silently.
370
370
  * - `show: "always"`, `"when-hidden"`, or `false` overrides this default.
371
- * - When rendering, `notification.*` is consulted, with per-field fallback to
372
- * the top-level `title` / `avatarUrl` / `messageId` and finally
373
- * to the SW's `defaultIcon` / `defaultBadge` options. Everything
374
- * else (`tag`, `renotify`, `requireInteraction`) has no top-level
375
- * fallback — set them under `notification` or accept the SW default.
371
+ * - When rendering, `notification.*` is consulted first, with per-field
372
+ * fallback to the matching top-level payload fields (`title`,
373
+ * `body`/`message`, `icon`/`avatarUrl`, `badge`, `tag`/`messageId`,
374
+ * `renotify`, `requireInteraction`, `silent`, `data`), and finally to
375
+ * the SW's `defaultIcon` / `defaultBadge` options (boolean knobs
376
+ * default to `false` at the SW). Prefer setting overrides under
377
+ * `notification` for explicitness; top-level fallback exists so that
378
+ * legacy un-namespaced payloads keep working byte-for-byte.
376
379
  */
377
380
  export type NotificationDirective = {
378
381
  /**
@@ -380,35 +383,39 @@ export type NotificationDirective = {
380
383
  */
381
384
  show?: "auto" | "always" | "when-hidden" | false;
382
385
  /**
383
- * - Notification title override.
386
+ * - Notification title override (falls back to top-level `title`, then `来自 {contactName}`).
384
387
  */
385
388
  title?: string;
386
389
  /**
387
- * - Notification body override.
390
+ * - Notification body override (falls back to top-level `body`, then `message`).
388
391
  */
389
392
  body?: string;
390
393
  /**
391
- * - Icon URL override (falls back to top-level `avatarUrl` then SW `defaultIcon`).
394
+ * - Icon URL override (falls back to top-level `icon`/`avatarUrl`, then SW `defaultIcon`).
392
395
  */
393
396
  icon?: string;
394
397
  /**
395
- * - Badge URL override (falls back to SW `defaultBadge`).
398
+ * - Badge URL override (falls back to top-level `badge`, then SW `defaultBadge`).
396
399
  */
397
400
  badge?: string;
398
401
  /**
399
- * - Notification grouping tag; matching tag replaces the prior notification.
402
+ * - Notification grouping tag; matching tag replaces the prior notification (falls back to top-level `tag`, then `messageId`, then a generated unique tag).
400
403
  */
401
404
  tag?: string;
402
405
  /**
403
- * - When tag matches, still vibrate/sound. Default false at SW.
406
+ * - When tag matches, still vibrate/sound (falls back to top-level `renotify`, default false at SW).
404
407
  */
405
408
  renotify?: boolean;
406
409
  /**
407
- * - Notification stays until user dismisses. Default false at SW.
410
+ * - Notification stays until user dismisses (falls back to top-level `requireInteraction`, default false at SW).
408
411
  */
409
412
  requireInteraction?: boolean;
410
413
  /**
411
- * - Custom payload data to attach to the notification.
414
+ * - Suppress sound and vibration (falls back to top-level `silent`, default false at SW).
415
+ */
416
+ silent?: boolean;
417
+ /**
418
+ * - Custom payload data to attach to the notification (falls back to top-level `data`).
412
419
  */
413
420
  data?: Record<string, unknown>;
414
421
  };
package/dist/index.d.ts CHANGED
@@ -200,10 +200,10 @@ export function isErrorPush(value: unknown): value is ErrorPush;
200
200
  /**
201
201
  * Slice a string into UTF-8 byte chunks no larger than `maxBytes`,
202
202
  * always cutting at codepoint boundaries (never inside a multi-byte
203
- * char). Designed for the {@link ReasoningPush} byte-chunking path
204
- * in amsg-instant — producers facing the ~3 KB Web Push payload
205
- * limit slice oversized reasoning into N pushes with
206
- * `chunkIndex` / `totalChunks`, the SW reassembles by concat.
203
+ * char). This is a generic byte-safe string helper retained for
204
+ * callers that need deterministic UTF-8 chunking around small Web Push
205
+ * payload budgets; current amsg-instant oversized payload delivery uses
206
+ * BlobStore / generic multipart instead of reasoning-only wire fields.
207
207
  *
208
208
  * Algorithm: TextEncoder → Uint8Array → backward scan from each
209
209
  * candidate cut index until the byte is a UTF-8 lead byte (any byte
@@ -361,18 +361,21 @@ export type AmsgPushCommon = {
361
361
  };
362
362
  /**
363
363
  * SW-rendering directive. Mirrors the fields that `amsg-sw`'s
364
- * `createNotificationFromPayload` consumes (`notification.{title,body,icon,badge,tag,renotify,requireInteraction,data}`)
365
- * — typing all fields so callers don't lose IDE checking and slip back into the untyped-spread footgun.
364
+ * `createNotificationFromPayload` consumes (`notification.{show,title,body,icon,badge,tag,renotify,requireInteraction,silent,data}`)
365
+ * so producers get builder validation for the fields the SW actually reads.
366
366
  *
367
- * Routing in SW (kept here so producers don't have to cross-check):
367
+ * Routing in SW:
368
368
  * - By default (`show: "auto"` or omitted), `messageKind: 'content'` (and legacy un-kinded payloads)
369
369
  * will display a system notification. `reasoning` / `tool_request` / `error` will dispatch silently.
370
370
  * - `show: "always"`, `"when-hidden"`, or `false` overrides this default.
371
- * - When rendering, `notification.*` is consulted, with per-field fallback to
372
- * the top-level `title` / `avatarUrl` / `messageId` and finally
373
- * to the SW's `defaultIcon` / `defaultBadge` options. Everything
374
- * else (`tag`, `renotify`, `requireInteraction`) has no top-level
375
- * fallback — set them under `notification` or accept the SW default.
371
+ * - When rendering, `notification.*` is consulted first, with per-field
372
+ * fallback to the matching top-level payload fields (`title`,
373
+ * `body`/`message`, `icon`/`avatarUrl`, `badge`, `tag`/`messageId`,
374
+ * `renotify`, `requireInteraction`, `silent`, `data`), and finally to
375
+ * the SW's `defaultIcon` / `defaultBadge` options (boolean knobs
376
+ * default to `false` at the SW). Prefer setting overrides under
377
+ * `notification` for explicitness; top-level fallback exists so that
378
+ * legacy un-namespaced payloads keep working byte-for-byte.
376
379
  */
377
380
  export type NotificationDirective = {
378
381
  /**
@@ -380,35 +383,39 @@ export type NotificationDirective = {
380
383
  */
381
384
  show?: "auto" | "always" | "when-hidden" | false;
382
385
  /**
383
- * - Notification title override.
386
+ * - Notification title override (falls back to top-level `title`, then `来自 {contactName}`).
384
387
  */
385
388
  title?: string;
386
389
  /**
387
- * - Notification body override.
390
+ * - Notification body override (falls back to top-level `body`, then `message`).
388
391
  */
389
392
  body?: string;
390
393
  /**
391
- * - Icon URL override (falls back to top-level `avatarUrl` then SW `defaultIcon`).
394
+ * - Icon URL override (falls back to top-level `icon`/`avatarUrl`, then SW `defaultIcon`).
392
395
  */
393
396
  icon?: string;
394
397
  /**
395
- * - Badge URL override (falls back to SW `defaultBadge`).
398
+ * - Badge URL override (falls back to top-level `badge`, then SW `defaultBadge`).
396
399
  */
397
400
  badge?: string;
398
401
  /**
399
- * - Notification grouping tag; matching tag replaces the prior notification.
402
+ * - Notification grouping tag; matching tag replaces the prior notification (falls back to top-level `tag`, then `messageId`, then a generated unique tag).
400
403
  */
401
404
  tag?: string;
402
405
  /**
403
- * - When tag matches, still vibrate/sound. Default false at SW.
406
+ * - When tag matches, still vibrate/sound (falls back to top-level `renotify`, default false at SW).
404
407
  */
405
408
  renotify?: boolean;
406
409
  /**
407
- * - Notification stays until user dismisses. Default false at SW.
410
+ * - Notification stays until user dismisses (falls back to top-level `requireInteraction`, default false at SW).
408
411
  */
409
412
  requireInteraction?: boolean;
410
413
  /**
411
- * - Custom payload data to attach to the notification.
414
+ * - Suppress sound and vibration (falls back to top-level `silent`, default false at SW).
415
+ */
416
+ silent?: boolean;
417
+ /**
418
+ * - Custom payload data to attach to the notification (falls back to top-level `data`).
412
419
  */
413
420
  data?: Record<string, unknown>;
414
421
  };
package/dist/index.mjs CHANGED
@@ -122,7 +122,7 @@ function validateNotificationArg(kind, value) {
122
122
  throw new Error(`[amsg-shared] ${kind}: 'notification.${f}' must be a string when present`);
123
123
  }
124
124
  }
125
- for (const f of ["renotify", "requireInteraction"]) {
125
+ for (const f of ["renotify", "requireInteraction", "silent"]) {
126
126
  if (n[f] !== void 0 && typeof n[f] !== "boolean") {
127
127
  throw new Error(`[amsg-shared] ${kind}: 'notification.${f}' must be a boolean when present`);
128
128
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@rei-standard/amsg-shared",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "ReiStandard Active Messaging shared types and push builders — the lowest layer (no deps on other amsg packages)",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "https://github.com/Tosd0/ReiStandard",
7
+ "url": "git+https://github.com/Tosd0/ReiStandard.git",
8
8
  "directory": "packages/rei-standard-amsg/shared"
9
9
  },
10
10
  "license": "MIT",