@12-apps/notifications 4.9.0 → 4.10.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/ADOPTING.md +60 -1
- package/README.md +73 -0
- package/dist/{chunk-M5XTROYM.js → chunk-5Y7QRORV.js} +8 -4
- package/dist/chunk-5Y7QRORV.js.map +1 -0
- package/dist/{chunk-BGI4BQ66.js → chunk-6W7INOYQ.js} +1 -1
- package/dist/chunk-6W7INOYQ.js.map +1 -0
- package/dist/chunk-JCVRQ42B.js +226 -0
- package/dist/chunk-JCVRQ42B.js.map +1 -0
- package/dist/chunk-RTURLH5U.js +33 -0
- package/dist/chunk-RTURLH5U.js.map +1 -0
- package/dist/{chunk-GGAZOLNN.js → chunk-SWOWHIFE.js} +2 -2
- package/dist/{chunk-KZG7QGFA.js → chunk-WVRODNXQ.js} +8 -4
- package/dist/chunk-WVRODNXQ.js.map +1 -0
- package/dist/{chunk-KU4FVOFA.js → chunk-ZIR3ILFH.js} +2 -2
- package/dist/{create-api-notifications-B-VMezVB.d.ts → create-api-notifications-CcPYrM3p.d.ts} +4 -4
- package/dist/{create-web-notifications-B-xQ6R0B.d.ts → create-web-notifications-_NVYmlvy.d.ts} +89 -4
- package/dist/{generators-BsuXe8Mp.d.ts → generators-qAD4fNPq.d.ts} +1 -1
- package/dist/hono/index.d.ts +5 -5
- package/dist/hono/index.js +4 -3
- package/dist/hono/index.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +12 -2
- package/dist/{jobs-D64B_bg7.d.ts → jobs--fex87-q.d.ts} +1 -1
- package/dist/live-DYxEFO49.d.ts +158 -0
- package/dist/manifest/server.d.ts +6 -6
- package/dist/manifest/server.js +5 -4
- package/dist/manifest/server.js.map +1 -1
- package/dist/manifest/web.d.ts +4 -3
- package/dist/manifest/web.js +1 -1
- package/dist/{panel-UFXNO4AF.js → panel-T36JEMO3.js} +37 -13
- package/dist/panel-T36JEMO3.js.map +1 -0
- package/dist/{preferences-screen-V3ZBWP7A.js → preferences-screen-SXUIGECY.js} +2 -2
- package/dist/react/index.d.ts +55 -6
- package/dist/react/index.js +8 -2
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +5 -4
- package/dist/{types-BFmAY0P5.d.ts → types-BlqZkCWZ.d.ts} +10 -1
- package/dist/web-push/index.d.ts +2 -2
- package/dist/{web-push-D-ysQd5h.d.ts → web-push-Dnyaha2z.d.ts} +21 -1
- package/dist/{wire-_coV3tJk.d.ts → wire-BG1kuoXX.d.ts} +1 -1
- package/package.json +2 -2
- package/src/index.ts +10 -0
- package/src/live.ts +179 -0
- package/src/react/create-web-notifications.tsx +15 -1
- package/src/react/index.ts +29 -0
- package/src/react/live-card.tsx +279 -0
- package/src/react/live-config.ts +79 -0
- package/src/react/live-section.tsx +141 -0
- package/src/react/panel-lazy.tsx +3 -0
- package/src/react/panel.tsx +57 -10
- package/src/react/relative-time.ts +14 -2
- package/src/server/transports/web-push.ts +22 -0
- package/src/types.ts +10 -1
- package/dist/chunk-BGI4BQ66.js.map +0 -1
- package/dist/chunk-KZG7QGFA.js.map +0 -1
- package/dist/chunk-M5XTROYM.js.map +0 -1
- package/dist/chunk-O5BVUXPO.js +0 -22
- package/dist/chunk-O5BVUXPO.js.map +0 -1
- package/dist/panel-UFXNO4AF.js.map +0 -1
- /package/dist/{chunk-GGAZOLNN.js.map → chunk-SWOWHIFE.js.map} +0 -0
- /package/dist/{chunk-KU4FVOFA.js.map → chunk-ZIR3ILFH.js.map} +0 -0
- /package/dist/{preferences-screen-V3ZBWP7A.js.map → preferences-screen-SXUIGECY.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { D as DeliveryStatus, a as NOTIFICATION_CHANNELS, b as NotificationCategory, c as NotificationChannel, d as NotificationContent, e as NotificationEvent, f as NotificationGenerateContext, N as NotificationGenerator, g as NotificationLogger, h as NotificationRecipient, i as NotificationTaxonomy, j as NotificationTransport, T as TransportRecipient, t as taxonomyOf } from './types-
|
|
2
|
-
export { N as NotificationGeneratorRegistry, c as createGeneratorRegistry } from './generators-
|
|
3
|
-
export { C as ChannelMatrix, a as ChannelRow, D as DEFAULT_CHANNEL_ROW, I as InboxNotification, L as ListNotificationsResult, N as NotificationMessages, b as NotificationRow, c as NotificationWireMessages, d as defaultChannelMatrix, e as enabledChannelsOf, i as inboxWire, m as mergeChoices, f as mergeStoredRow, g as messagesOf } from './wire-
|
|
1
|
+
export { D as DeliveryStatus, a as NOTIFICATION_CHANNELS, b as NotificationCategory, c as NotificationChannel, d as NotificationContent, e as NotificationEvent, f as NotificationGenerateContext, N as NotificationGenerator, g as NotificationLogger, h as NotificationRecipient, i as NotificationTaxonomy, j as NotificationTransport, T as TransportRecipient, t as taxonomyOf } from './types-BlqZkCWZ.js';
|
|
2
|
+
export { N as NotificationGeneratorRegistry, c as createGeneratorRegistry } from './generators-qAD4fNPq.js';
|
|
3
|
+
export { C as ChannelMatrix, a as ChannelRow, D as DEFAULT_CHANNEL_ROW, I as InboxNotification, L as ListNotificationsResult, N as NotificationMessages, b as NotificationRow, c as NotificationWireMessages, d as defaultChannelMatrix, e as enabledChannelsOf, i as inboxWire, m as mergeChoices, f as mergeStoredRow, g as messagesOf } from './wire-BG1kuoXX.js';
|
|
4
|
+
export { L as LIVE_PUSH_TAG_PREFIX, a as LIVE_SUBJECT_KEY, b as LiveActivity, c as LiveActivityLane, d as LiveActivityStep, l as liveActivityLane, e as livePushTag } from './live-DYxEFO49.js';
|
|
4
5
|
|
|
5
6
|
/** Thrown by `notify` when no generator is registered for the event type. */
|
|
6
7
|
declare class UnknownNotificationTypeError extends Error {
|
package/dist/index.js
CHANGED
|
@@ -9,17 +9,25 @@ import {
|
|
|
9
9
|
mergeChoices,
|
|
10
10
|
mergeStoredRow,
|
|
11
11
|
normalizePhoneE164
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SWOWHIFE.js";
|
|
13
13
|
import {
|
|
14
14
|
messagesOf
|
|
15
15
|
} from "./chunk-M2TVBVH2.js";
|
|
16
|
+
import {
|
|
17
|
+
LIVE_PUSH_TAG_PREFIX,
|
|
18
|
+
LIVE_SUBJECT_KEY,
|
|
19
|
+
liveActivityLane,
|
|
20
|
+
livePushTag
|
|
21
|
+
} from "./chunk-RTURLH5U.js";
|
|
16
22
|
import {
|
|
17
23
|
NOTIFICATION_CHANNELS,
|
|
18
24
|
taxonomyOf
|
|
19
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-6W7INOYQ.js";
|
|
20
26
|
import "./chunk-7QVYU63E.js";
|
|
21
27
|
export {
|
|
22
28
|
DEFAULT_CHANNEL_ROW,
|
|
29
|
+
LIVE_PUSH_TAG_PREFIX,
|
|
30
|
+
LIVE_SUBJECT_KEY,
|
|
23
31
|
NOTIFICATION_CHANNELS,
|
|
24
32
|
UnknownNotificationRecipientError,
|
|
25
33
|
UnknownNotificationTypeError,
|
|
@@ -27,6 +35,8 @@ export {
|
|
|
27
35
|
defaultChannelMatrix,
|
|
28
36
|
enabledChannelsOf,
|
|
29
37
|
inboxWire,
|
|
38
|
+
liveActivityLane,
|
|
39
|
+
livePushTag,
|
|
30
40
|
mergeChoices,
|
|
31
41
|
mergeStoredRow,
|
|
32
42
|
messagesOf,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WireJobBlueprint } from '@12-apps/wiring';
|
|
2
|
-
import { A as ApiNotifications } from './create-api-notifications-
|
|
2
|
+
import { A as ApiNotifications } from './create-api-notifications-CcPYrM3p.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The two background jobs getting a message out actually needs.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LIVE ACTIVITIES — the notification centre's second kind of entry.
|
|
3
|
+
*
|
|
4
|
+
* An inbox notification is an EVENT: it happened, it is stamped, it is read or
|
|
5
|
+
* unread, and it is still there tomorrow saying the same thing. A live activity
|
|
6
|
+
* is ONGOING STATE: it is pinned above the list, it has no read/unread, nobody
|
|
7
|
+
* deletes it, it updates itself, and it is GONE the moment the thing it tracks
|
|
8
|
+
* finishes.
|
|
9
|
+
*
|
|
10
|
+
* The distinction is not cosmetic. A row that says "your order is on its way",
|
|
11
|
+
* read an hour later, is a claim about the past presented as news — and the
|
|
12
|
+
* more reliable the inbox is, the more of those a person accumulates. Somewhere
|
|
13
|
+
* in that list is the one question they actually have, which is *where is it
|
|
14
|
+
* now*. A live activity answers that question and then removes itself, which is
|
|
15
|
+
* the property no amount of better event copy can buy.
|
|
16
|
+
*
|
|
17
|
+
* ## This file is domain-free, and that is the whole design
|
|
18
|
+
*
|
|
19
|
+
* Nothing here knows what is being tracked. A host publishes activities through
|
|
20
|
+
* `LiveActivitiesConfig.useActivities` (see `./react/live-config`) and this
|
|
21
|
+
* package owns the contract, the placement, the rendering and the OS-level
|
|
22
|
+
* collapse. The package that raises an alert has never been this package's
|
|
23
|
+
* business — see the `generators` seam — and the thing an alert is ABOUT is not
|
|
24
|
+
* either.
|
|
25
|
+
*
|
|
26
|
+
* ## The lane
|
|
27
|
+
*
|
|
28
|
+
* `steps` + `activeStepId` describe a progress lane, because "how far along is
|
|
29
|
+
* this" is the shape almost every ongoing subject has. Both are optional in
|
|
30
|
+
* effect: an activity with no lane (`steps: []`, `activeStepId: null`) is a
|
|
31
|
+
* perfectly good live entry — a heading, a sentence and a timestamp that keeps
|
|
32
|
+
* moving.
|
|
33
|
+
*/
|
|
34
|
+
/** One stop on a live activity's lane. */
|
|
35
|
+
interface LiveActivityStep {
|
|
36
|
+
/** Stable across updates — the id is what `activeStepId` names. */
|
|
37
|
+
id: string;
|
|
38
|
+
/** What the reader sees under the dot. The HOST's word, in the reader's language. */
|
|
39
|
+
label: string;
|
|
40
|
+
}
|
|
41
|
+
/** One thing that is happening right now, as the notification centre shows it. */
|
|
42
|
+
interface LiveActivity {
|
|
43
|
+
/**
|
|
44
|
+
* Stable for the whole life of the subject.
|
|
45
|
+
*
|
|
46
|
+
* The SAME id on every update, because it is the identity of the thing being
|
|
47
|
+
* tracked and not of the message: the panel keys on it so a stage change
|
|
48
|
+
* re-renders one card rather than swapping two, and it is what
|
|
49
|
+
* {@link livePushTag} collapses an OS notification onto.
|
|
50
|
+
*
|
|
51
|
+
* **Unique among the activities live at one moment**, for the same reason:
|
|
52
|
+
* it is the React key and the card's test id. Two activities sharing one
|
|
53
|
+
* gives a duplicate-key warning and a card that silently shows the wrong
|
|
54
|
+
* subject.
|
|
55
|
+
*/
|
|
56
|
+
id: string;
|
|
57
|
+
/**
|
|
58
|
+
* Which host concern this belongs to, e.g. `order`, `delivery`, `import`.
|
|
59
|
+
*
|
|
60
|
+
* Free-form and never rendered — it exists so a host publishing from two
|
|
61
|
+
* sources can tell its own activities apart in a test or a log without
|
|
62
|
+
* parsing `id`.
|
|
63
|
+
*/
|
|
64
|
+
kind: string;
|
|
65
|
+
/** The heading — what is happening. */
|
|
66
|
+
title: string;
|
|
67
|
+
/** The line under it: the detail that makes the heading actionable, or none. */
|
|
68
|
+
body: string | null;
|
|
69
|
+
/** Where tapping the card goes, as a same-origin path. `null` renders no link. */
|
|
70
|
+
link: string | null;
|
|
71
|
+
/** The lane, in the order it is walked. Empty when this subject has no lane. */
|
|
72
|
+
steps: readonly LiveActivityStep[];
|
|
73
|
+
/**
|
|
74
|
+
* The stop the subject is AT — one of `steps`, or `null` for a laneless entry.
|
|
75
|
+
*
|
|
76
|
+
* An id that names no step is neither, and it is handled rather than trusted:
|
|
77
|
+
* see {@link liveActivityLane}.
|
|
78
|
+
*/
|
|
79
|
+
activeStepId: string | null;
|
|
80
|
+
/**
|
|
81
|
+
* ISO-8601 — when the subject last MOVED, not when it was last polled.
|
|
82
|
+
*
|
|
83
|
+
* A timestamp that advances on every read would render "just now" forever,
|
|
84
|
+
* which is the one thing a live entry must not say when nothing is happening.
|
|
85
|
+
*/
|
|
86
|
+
updatedAt: string;
|
|
87
|
+
}
|
|
88
|
+
/** A live activity's lane, resolved for rendering. */
|
|
89
|
+
interface LiveActivityLane {
|
|
90
|
+
steps: readonly LiveActivityStep[];
|
|
91
|
+
activeStepId: string;
|
|
92
|
+
/** Every stop BEFORE the active one — never the active one itself. */
|
|
93
|
+
completed: ReadonlySet<string>;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The lane to draw, or `null` when this activity has none to draw.
|
|
97
|
+
*
|
|
98
|
+
* Three cases collapse to `null`, and the third is the one worth writing down:
|
|
99
|
+
* no steps, no active step, and **an active step the lane does not contain**.
|
|
100
|
+
* That last one is not a theoretical defect — it is what a host produces the
|
|
101
|
+
* first time a subject reaches a stage the lane was filtered to exclude, and
|
|
102
|
+
* the symptom is a row of dots with NONE of them lit, which reads as a process
|
|
103
|
+
* that has stopped. A card with no lane still says what is happening and when
|
|
104
|
+
* it last moved; a dead lane says the tracking is broken.
|
|
105
|
+
*
|
|
106
|
+
* `completed` deliberately stops short of the active stop: a completed step
|
|
107
|
+
* draws a tick, and ticking the stop the subject is sitting in claims it has
|
|
108
|
+
* already left.
|
|
109
|
+
*/
|
|
110
|
+
declare function liveActivityLane(activity: LiveActivity): LiveActivityLane | null;
|
|
111
|
+
/**
|
|
112
|
+
* The reserved `data` key that ties a NOTIFICATION to a live subject.
|
|
113
|
+
*
|
|
114
|
+
* A notification and a live activity are different objects with different
|
|
115
|
+
* lifetimes, and this is the only thing that joins them: a generator whose
|
|
116
|
+
* event is about something also tracked live puts the activity's id here, and
|
|
117
|
+
* every channel that can collapse gets to.
|
|
118
|
+
*
|
|
119
|
+
* data: { [LIVE_SUBJECT_KEY]: `order:${orderId}` }
|
|
120
|
+
*
|
|
121
|
+
* A plain string on purpose. An object here would grow a second wire contract
|
|
122
|
+
* inside a column this package stores verbatim.
|
|
123
|
+
*/
|
|
124
|
+
declare const LIVE_SUBJECT_KEY = "liveSubject";
|
|
125
|
+
/**
|
|
126
|
+
* Namespaces the tray tag, so a live tag does not collide with the ones a host
|
|
127
|
+
* already uses.
|
|
128
|
+
*
|
|
129
|
+
* A convention rather than an enforcement — nothing stops a host emitting its
|
|
130
|
+
* own `live:`-prefixed tags — but it means the two id spaces have to be made to
|
|
131
|
+
* meet rather than meeting by accident.
|
|
132
|
+
*/
|
|
133
|
+
declare const LIVE_PUSH_TAG_PREFIX = "live:";
|
|
134
|
+
/**
|
|
135
|
+
* The OS notification tag for a push about a live subject, or `null` for an
|
|
136
|
+
* ordinary event.
|
|
137
|
+
*
|
|
138
|
+
* ## What the tag buys, and why it is the PWA half of this feature
|
|
139
|
+
*
|
|
140
|
+
* A `tag` makes a new notification REPLACE the one already in the tray instead
|
|
141
|
+
* of stacking under it, and — unless the sender asks otherwise — replace it
|
|
142
|
+
* *silently*. So a subject that moves through four stages costs one tray entry
|
|
143
|
+
* and one buzz, and the entry that remains is the CURRENT one. Without it a
|
|
144
|
+
* phone accumulates one alert per stage, all of them still asserting a stage
|
|
145
|
+
* the subject has since left; the freshest is at the top and the reader has to
|
|
146
|
+
* work out that the three below it are history.
|
|
147
|
+
*
|
|
148
|
+
* That is as close as the web platform gets to an ongoing/live notification,
|
|
149
|
+
* and it is the half that reaches a person who does not have the app open —
|
|
150
|
+
* which is most of the time a live activity is live.
|
|
151
|
+
*
|
|
152
|
+
* The id is passed through unchanged: it is the host's, it is already unique
|
|
153
|
+
* per subject, and a hash would make the tray impossible to reason about from a
|
|
154
|
+
* log line.
|
|
155
|
+
*/
|
|
156
|
+
declare function livePushTag(data: Readonly<Record<string, unknown>> | null | undefined): string | null;
|
|
157
|
+
|
|
158
|
+
export { LIVE_PUSH_TAG_PREFIX as L, LIVE_SUBJECT_KEY as a, type LiveActivity as b, type LiveActivityLane as c, type LiveActivityStep as d, livePushTag as e, liveActivityLane as l };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { EmailPreviewRoute } from '../email/previews/index.js';
|
|
2
2
|
import * as _12_apps_wiring from '@12-apps/wiring';
|
|
3
3
|
import { WireRequest } from '@12-apps/wiring';
|
|
4
|
-
import { N as NotificationsServerConfig, A as ApiNotifications, b as NotificationsRoute } from '../create-api-notifications-
|
|
5
|
-
import { N as NotificationsJobDeps } from '../jobs-
|
|
4
|
+
import { N as NotificationsServerConfig, A as ApiNotifications, b as NotificationsRoute } from '../create-api-notifications-CcPYrM3p.js';
|
|
5
|
+
import { N as NotificationsJobDeps } from '../jobs--fex87-q.js';
|
|
6
6
|
import { E as EmailPreviewsConfig } from '../catalog-BOVZ2b-b.js';
|
|
7
|
-
import '../generators-
|
|
8
|
-
import '../types-
|
|
9
|
-
import '../wire-
|
|
10
|
-
import '../web-push-
|
|
7
|
+
import '../generators-qAD4fNPq.js';
|
|
8
|
+
import '../types-BlqZkCWZ.js';
|
|
9
|
+
import '../wire-BG1kuoXX.js';
|
|
10
|
+
import '../web-push-Dnyaha2z.js';
|
|
11
11
|
import '../template-Dlt5S54z.js';
|
|
12
12
|
|
|
13
13
|
/** One `NotificationsRoute` as the wiring contract reads it. */
|
package/dist/manifest/server.js
CHANGED
|
@@ -3,13 +3,14 @@ import {
|
|
|
3
3
|
} from "../chunk-FTFLU6KH.js";
|
|
4
4
|
import {
|
|
5
5
|
NOTIFICATIONS_JOBS
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-ZIR3ILFH.js";
|
|
7
7
|
import {
|
|
8
8
|
createApiNotifications
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-WVRODNXQ.js";
|
|
10
|
+
import "../chunk-SWOWHIFE.js";
|
|
11
11
|
import "../chunk-M2TVBVH2.js";
|
|
12
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-RTURLH5U.js";
|
|
13
|
+
import "../chunk-6W7INOYQ.js";
|
|
13
14
|
import "../chunk-EKUSNUBT.js";
|
|
14
15
|
import {
|
|
15
16
|
__name
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/manifest/server.ts"],"sourcesContent":["/**\n * `@12-apps/notifications/manifest/server` — the server capabilities.\n *\n * `http.create` wraps `createApiNotifications` in a WIRE VIEW, and the reason\n * is one field. `NotificationsRequest` carries `headers` — the contract's\n * `WireRequest` does not, because headers are the adapter's business\n * everywhere else — and exactly one descriptor reads it: push-subscribe takes\n * `user-agent` as the DEVICE HINT it labels a subscription with. Without the\n * view the field would simply be absent at runtime while still type-checking,\n * and every saved device would come back unnamed: a silent quality loss, the\n * failure mode the wiring contract exists to convert into a loud one.\n *\n * So the view derives `headers` from the raw request the contract already\n * carries for the handlers `params`/`query`/`body` cannot serve. A host whose\n * adapter leaves `request` unset still gets a working surface — every route\n * answers, the subscription saves — with an unnamed device, which is the\n * honest degradation for a hint. `@12-apps/notifications/hono` populates it.\n *\n * Everything else rides beside the mapped routes on the aggregate unchanged:\n * `notify`, `notifyByPermission`, `dispatchDeliveries`, `drainPending`, the\n * three stores, `registerGenerator` and the transports registry. A host still\n * calls those directly — being mounted does not make the emit front door stop\n * being a library.\n */\n\nimport type { AnyServerManifest, WireRequest } from '@12-apps/wiring';\n\nimport { emailPreviewRoutes } from '../email/previews/routes';\nimport type { EmailPreviewsConfig } from '../email/previews/catalog';\nimport {\n createApiNotifications,\n NOTIFICATIONS_JOBS,\n type ApiNotifications,\n type NotificationsRoute,\n type NotificationsServerConfig,\n} from '../server';\n\n/** The header names this surface reads — the device hint, and nothing else. */\nconst READ_HEADERS = ['user-agent'] as const;\n\n/** The headers the package expects, taken off the raw request when there is one. */\nfunction headersOf(request: WireRequest<never>): Record<string, string | undefined> {\n const raw = request.request;\n if (!raw) return {};\n return Object.fromEntries(\n READ_HEADERS.map((name) => [name, raw.headers.get(name) ?? undefined]),\n );\n}\n\n/** One `NotificationsRoute` as the wiring contract reads it. */\nfunction asWireRoute(route: NotificationsRoute): {\n method: NotificationsRoute['method'];\n path: string;\n handle(request: WireRequest<never>): Promise<{ status: number; body: unknown }>;\n} {\n return {\n method: route.method,\n path: route.path,\n handle: (request) =>\n route.handle({\n actor: request.actor,\n params: request.params,\n query: request.query,\n body: request.body,\n headers: headersOf(request),\n }),\n };\n}\n\n/** `createApiNotifications`, its routes re-shaped for the aggregate. */\nexport function createWireApiNotifications(\n config: NotificationsServerConfig,\n): Omit<ApiNotifications, 'routes'> & { routes: ReturnType<typeof asWireRoute>[] } {\n const api = createApiNotifications(config);\n return { ...api, routes: api.routes.map(asWireRoute) };\n}\n\nexport const notificationsServerManifest = {\n name: '@12-apps/notifications',\n http: { create: createWireApiNotifications },\n /**\n * The dispatch fast path and the retry sweep, with their cadence. The host\n * binds `{ dispatchDeliveries, drainPending }` off its own mount — the two\n * methods the aggregate already hands it — and deletes the hand-rolled\n * copies. See `../server/jobs` for why the numbers are the package's.\n */\n jobs: NOTIFICATIONS_JOBS,\n} as const satisfies AnyServerManifest;\n\n/**\n * The preview console's server half — the two endpoints over the catalogue.\n *\n * A CONSTANT, not a factory. `http.create(config)` receives whatever the host\n * bound at adoption, and \"which messages exist\" is precisely a host's binding:\n * a package cannot know that a product sends a \"your quota is exhausted\"\n * notice, let alone what data it renders from. Writing `EmailPreviewsConfig`\n * as a factory argument instead would move that decision out of\n * `bindings.http`, where `assemble()` can report on it, into a call the report\n * never sees.\n *\n * The routes carry `kind: 'authenticated'` — see `../email/previews/routes`\n * for why the descriptor states a posture it cannot itself enforce.\n */\nexport const notificationEmailPreviewsServerManifest = {\n name: '@12-apps/notifications-email-previews',\n http: {\n create: (config: EmailPreviewsConfig) => ({ routes: emailPreviewRoutes(config) }),\n },\n} as const satisfies AnyServerManifest;\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/manifest/server.ts"],"sourcesContent":["/**\n * `@12-apps/notifications/manifest/server` — the server capabilities.\n *\n * `http.create` wraps `createApiNotifications` in a WIRE VIEW, and the reason\n * is one field. `NotificationsRequest` carries `headers` — the contract's\n * `WireRequest` does not, because headers are the adapter's business\n * everywhere else — and exactly one descriptor reads it: push-subscribe takes\n * `user-agent` as the DEVICE HINT it labels a subscription with. Without the\n * view the field would simply be absent at runtime while still type-checking,\n * and every saved device would come back unnamed: a silent quality loss, the\n * failure mode the wiring contract exists to convert into a loud one.\n *\n * So the view derives `headers` from the raw request the contract already\n * carries for the handlers `params`/`query`/`body` cannot serve. A host whose\n * adapter leaves `request` unset still gets a working surface — every route\n * answers, the subscription saves — with an unnamed device, which is the\n * honest degradation for a hint. `@12-apps/notifications/hono` populates it.\n *\n * Everything else rides beside the mapped routes on the aggregate unchanged:\n * `notify`, `notifyByPermission`, `dispatchDeliveries`, `drainPending`, the\n * three stores, `registerGenerator` and the transports registry. A host still\n * calls those directly — being mounted does not make the emit front door stop\n * being a library.\n */\n\nimport type { AnyServerManifest, WireRequest } from '@12-apps/wiring';\n\nimport { emailPreviewRoutes } from '../email/previews/routes';\nimport type { EmailPreviewsConfig } from '../email/previews/catalog';\nimport {\n createApiNotifications,\n NOTIFICATIONS_JOBS,\n type ApiNotifications,\n type NotificationsRoute,\n type NotificationsServerConfig,\n} from '../server';\n\n/** The header names this surface reads — the device hint, and nothing else. */\nconst READ_HEADERS = ['user-agent'] as const;\n\n/** The headers the package expects, taken off the raw request when there is one. */\nfunction headersOf(request: WireRequest<never>): Record<string, string | undefined> {\n const raw = request.request;\n if (!raw) return {};\n return Object.fromEntries(\n READ_HEADERS.map((name) => [name, raw.headers.get(name) ?? undefined]),\n );\n}\n\n/** One `NotificationsRoute` as the wiring contract reads it. */\nfunction asWireRoute(route: NotificationsRoute): {\n method: NotificationsRoute['method'];\n path: string;\n handle(request: WireRequest<never>): Promise<{ status: number; body: unknown }>;\n} {\n return {\n method: route.method,\n path: route.path,\n handle: (request) =>\n route.handle({\n actor: request.actor,\n params: request.params,\n query: request.query,\n body: request.body,\n headers: headersOf(request),\n }),\n };\n}\n\n/** `createApiNotifications`, its routes re-shaped for the aggregate. */\nexport function createWireApiNotifications(\n config: NotificationsServerConfig,\n): Omit<ApiNotifications, 'routes'> & { routes: ReturnType<typeof asWireRoute>[] } {\n const api = createApiNotifications(config);\n return { ...api, routes: api.routes.map(asWireRoute) };\n}\n\nexport const notificationsServerManifest = {\n name: '@12-apps/notifications',\n http: { create: createWireApiNotifications },\n /**\n * The dispatch fast path and the retry sweep, with their cadence. The host\n * binds `{ dispatchDeliveries, drainPending }` off its own mount — the two\n * methods the aggregate already hands it — and deletes the hand-rolled\n * copies. See `../server/jobs` for why the numbers are the package's.\n */\n jobs: NOTIFICATIONS_JOBS,\n} as const satisfies AnyServerManifest;\n\n/**\n * The preview console's server half — the two endpoints over the catalogue.\n *\n * A CONSTANT, not a factory. `http.create(config)` receives whatever the host\n * bound at adoption, and \"which messages exist\" is precisely a host's binding:\n * a package cannot know that a product sends a \"your quota is exhausted\"\n * notice, let alone what data it renders from. Writing `EmailPreviewsConfig`\n * as a factory argument instead would move that decision out of\n * `bindings.http`, where `assemble()` can report on it, into a call the report\n * never sees.\n *\n * The routes carry `kind: 'authenticated'` — see `../email/previews/routes`\n * for why the descriptor states a posture it cannot itself enforce.\n */\nexport const notificationEmailPreviewsServerManifest = {\n name: '@12-apps/notifications-email-previews',\n http: {\n create: (config: EmailPreviewsConfig) => ({ routes: emailPreviewRoutes(config) }),\n },\n} as const satisfies AnyServerManifest;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAsCA,IAAM,eAAe,CAAC,YAAY;AAGlC,SAAS,UAAU,SAAiE;AAClF,QAAM,MAAM,QAAQ;AACpB,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,SAAO,OAAO;AAAA,IACZ,aAAa,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,QAAQ,IAAI,IAAI,KAAK,MAAS,CAAC;AAAA,EACvE;AACF;AANS;AAST,SAAS,YAAY,OAInB;AACA,SAAO;AAAA,IACL,QAAQ,MAAM;AAAA,IACd,MAAM,MAAM;AAAA,IACZ,QAAQ,wBAAC,YACP,MAAM,OAAO;AAAA,MACX,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,MACf,MAAM,QAAQ;AAAA,MACd,SAAS,UAAU,OAAO;AAAA,IAC5B,CAAC,GAPK;AAAA,EAQV;AACF;AAjBS;AAoBF,SAAS,2BACd,QACiF;AACjF,QAAM,MAAM,uBAAuB,MAAM;AACzC,SAAO,EAAE,GAAG,KAAK,QAAQ,IAAI,OAAO,IAAI,WAAW,EAAE;AACvD;AALgB;AAOT,IAAM,8BAA8B;AAAA,EACzC,MAAM;AAAA,EACN,MAAM,EAAE,QAAQ,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO3C,MAAM;AACR;AAgBO,IAAM,0CAA0C;AAAA,EACrD,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,QAAQ,wBAAC,YAAiC,EAAE,QAAQ,mBAAmB,MAAM,EAAE,IAAvE;AAAA,EACV;AACF;","names":[]}
|
package/dist/manifest/web.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { c as createEmailPreviewScreen } from '../preview-screen-DYJRAnAY.js';
|
|
2
|
-
import { c as createWebNotifications } from '../create-web-notifications-
|
|
2
|
+
import { c as createWebNotifications } from '../create-web-notifications-_NVYmlvy.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../wire-
|
|
5
|
-
import '../types-
|
|
4
|
+
import '../wire-BG1kuoXX.js';
|
|
5
|
+
import '../types-BlqZkCWZ.js';
|
|
6
|
+
import '../live-DYxEFO49.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* `@12-apps/notifications/manifest/web` — the web capabilities.
|
package/dist/manifest/web.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
+
LiveSection,
|
|
2
3
|
relativeTime
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JCVRQ42B.js";
|
|
4
5
|
import {
|
|
5
6
|
BellIcon,
|
|
6
7
|
useInboxList
|
|
7
8
|
} from "./chunk-BW723CX2.js";
|
|
9
|
+
import "./chunk-RTURLH5U.js";
|
|
8
10
|
import {
|
|
9
11
|
__name
|
|
10
12
|
} from "./chunk-7QVYU63E.js";
|
|
@@ -176,26 +178,39 @@ function PanelBody({
|
|
|
176
178
|
] });
|
|
177
179
|
}
|
|
178
180
|
__name(PanelBody, "PanelBody");
|
|
181
|
+
function usePanelOpeners(store, onClose, onNavigate) {
|
|
182
|
+
const follow = useCallback(
|
|
183
|
+
(link) => {
|
|
184
|
+
if (!link || !onNavigate) return;
|
|
185
|
+
onClose();
|
|
186
|
+
onNavigate(link);
|
|
187
|
+
},
|
|
188
|
+
[onClose, onNavigate]
|
|
189
|
+
);
|
|
190
|
+
return {
|
|
191
|
+
openNotification: useCallback(
|
|
192
|
+
(notification) => {
|
|
193
|
+
if (notification.readAt === null) store.markRead([notification.id]);
|
|
194
|
+
follow(notification.link);
|
|
195
|
+
},
|
|
196
|
+
[store, follow]
|
|
197
|
+
),
|
|
198
|
+
openLive: useCallback((activity) => follow(activity.link), [follow])
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
__name(usePanelOpeners, "usePanelOpeners");
|
|
179
202
|
function NotificationsPanel({
|
|
180
203
|
open,
|
|
181
204
|
onClose,
|
|
182
205
|
onNavigate,
|
|
183
206
|
store,
|
|
184
|
-
messages
|
|
207
|
+
messages,
|
|
208
|
+
live
|
|
185
209
|
}) {
|
|
186
210
|
const theme = useTheme();
|
|
187
211
|
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
|
188
212
|
const state = useInboxList(store, open);
|
|
189
|
-
const openNotification =
|
|
190
|
-
(notification) => {
|
|
191
|
-
if (notification.readAt === null) store.markRead([notification.id]);
|
|
192
|
-
if (notification.link && onNavigate) {
|
|
193
|
-
onClose();
|
|
194
|
-
onNavigate(notification.link);
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
[store, onClose, onNavigate]
|
|
198
|
-
);
|
|
213
|
+
const { openNotification, openLive } = usePanelOpeners(store, onClose, onNavigate);
|
|
199
214
|
const hasUnread = state.items.some((item) => item.readAt === null);
|
|
200
215
|
return /* @__PURE__ */ jsxs2(
|
|
201
216
|
Drawer,
|
|
@@ -209,6 +224,15 @@ function NotificationsPanel({
|
|
|
209
224
|
children: [
|
|
210
225
|
/* @__PURE__ */ jsx2(DrawerHeader, { onClose, children: messages.panelTitle }),
|
|
211
226
|
/* @__PURE__ */ jsxs2(DrawerContent, { children: [
|
|
227
|
+
live ? /* @__PURE__ */ jsx2(
|
|
228
|
+
LiveSection,
|
|
229
|
+
{
|
|
230
|
+
config: live,
|
|
231
|
+
messages,
|
|
232
|
+
active: open,
|
|
233
|
+
...onNavigate ? { onOpen: openLive } : {}
|
|
234
|
+
}
|
|
235
|
+
) : null,
|
|
212
236
|
hasUnread ? /* @__PURE__ */ jsx2(Box2, { sx: { display: "flex", justifyContent: "flex-end", pb: 1 }, children: /* @__PURE__ */ jsx2(
|
|
213
237
|
Button2,
|
|
214
238
|
{
|
|
@@ -240,4 +264,4 @@ __name(NotificationsPanel, "NotificationsPanel");
|
|
|
240
264
|
export {
|
|
241
265
|
NotificationsPanel
|
|
242
266
|
};
|
|
243
|
-
//# sourceMappingURL=panel-
|
|
267
|
+
//# sourceMappingURL=panel-T36JEMO3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/panel.tsx","../src/react/row.tsx"],"sourcesContent":["/**\n * The notification-centre slide-over: newest-first list with unread styling,\n * per-item open (marks read + deep-links), soft delete, mark-all, empty /\n * loading / error states and a \"load more\" cursor pager.\n *\n * Rendering is app-agnostic — the host passes `onNavigate` (its router's\n * navigate) for deep links. Without one a link is simply not followed, which is\n * what lets the panel mount in a host that has no router at all.\n */\nimport { useCallback, type JSX } from 'react';\n\nimport { EmptyState } from '@12-apps/ui/data-display/EmptyState';\nimport { LoadingState } from '@12-apps/ui/data-display/LoadingState';\nimport { Button } from '@12-apps/ui/form/Button';\nimport { Drawer, DrawerContent, DrawerHeader } from '@12-apps/ui/layout/Drawer';\nimport { Box } from '@12-apps/ui/mui/Box';\nimport { useMediaQuery } from '@12-apps/ui/mui/useMediaQuery';\nimport { useTheme } from '@12-apps/ui/mui/styles';\n\nimport type { LiveActivity } from '../live';\nimport type { NotificationMessages } from '../messages';\nimport type { InboxNotification } from '../wire';\n\nimport { BellIcon } from './bell-icon';\nimport { useInboxList } from './hooks';\nimport type { InboxState, InboxStore } from './inbox-state';\nimport type { LiveActivitiesConfig } from './live-config';\nimport { LiveSection } from './live-section';\nimport { NotificationRow } from './row';\n\ninterface PanelBodyProps {\n state: InboxState;\n messages: NotificationMessages;\n onRetry: () => void;\n onLoadMore: () => void;\n onOpen: (notification: InboxNotification) => void;\n onDelete: (id: string) => void;\n}\n\n/** The scrollable panel body: loading / error / empty / the list + pager. */\nfunction PanelBody({\n state,\n messages,\n onRetry,\n onLoadMore,\n onOpen,\n onDelete,\n}: PanelBodyProps): JSX.Element {\n if (state.status === 'pending' || state.status === 'idle') {\n return (\n <LoadingState\n variant=\"spinner\"\n message={messages.loading}\n size=\"md\"\n dataTestId=\"notifications-loading\"\n />\n );\n }\n if (state.status === 'error') {\n return (\n <EmptyState\n variant=\"minimal\"\n title={messages.loadFailedTitle}\n description={messages.loadFailedBody}\n onRefresh={onRetry}\n refreshLabel={messages.retry}\n dataTestId=\"notifications-error\"\n />\n );\n }\n if (state.items.length === 0) {\n return (\n <EmptyState\n variant=\"illustrated\"\n illustration={<BellIcon size={44} dim />}\n title={messages.emptyTitle}\n description={messages.emptyBody}\n dataTestId=\"notifications-empty\"\n />\n );\n }\n return (\n <Box>\n {state.items.map((notification) => (\n <NotificationRow\n key={notification.id}\n notification={notification}\n messages={messages}\n onOpen={onOpen}\n onDelete={onDelete}\n />\n ))}\n {state.nextCursor ? (\n <Box sx={{ display: 'flex', justifyContent: 'center', py: 1.5 }}>\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n disabled={state.loadingMore}\n onClick={onLoadMore}\n dataTestId=\"notifications-load-more\"\n >\n {state.loadingMore ? messages.loadingMore : messages.loadMore}\n </Button>\n </Box>\n ) : null}\n </Box>\n );\n}\n\n/**\n * The two open gestures, which are ONE deep-link path with a mark-read in front\n * of half of it.\n *\n * Lifted out of the component because both kinds of entry follow a link the\n * same way and a host with no router follows neither — one rule, stated once,\n * rather than the same three lines written twice.\n */\nfunction usePanelOpeners(\n store: InboxStore,\n onClose: () => void,\n onNavigate?: (link: string) => void,\n): {\n openNotification: (notification: InboxNotification) => void;\n openLive: (activity: LiveActivity) => void;\n} {\n const follow = useCallback(\n (link: string | null) => {\n if (!link || !onNavigate) return;\n onClose();\n onNavigate(link);\n },\n [onClose, onNavigate],\n );\n\n return {\n openNotification: useCallback(\n (notification: InboxNotification) => {\n if (notification.readAt === null) store.markRead([notification.id]);\n follow(notification.link);\n },\n [store, follow],\n ),\n openLive: useCallback((activity: LiveActivity) => follow(activity.link), [follow]),\n };\n}\n\nexport interface NotificationsPanelProps {\n open: boolean;\n onClose: () => void;\n /** Navigate to a notification's in-app link (the host's router). */\n onNavigate?: (link: string) => void;\n}\n\nexport function NotificationsPanel({\n open,\n onClose,\n onNavigate,\n store,\n messages,\n live,\n}: NotificationsPanelProps & {\n store: InboxStore;\n messages: NotificationMessages;\n live?: LiveActivitiesConfig;\n}): JSX.Element {\n // `useTheme` from @mui/material/styles falls back to the DEFAULT theme when\n // no provider is mounted, where the callback form of `useMediaQuery` would\n // hand the callback a null theme and throw. A published component must render\n // in a host that has not wrapped it yet.\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('sm'));\n const state = useInboxList(store, open);\n\n const { openNotification, openLive } = usePanelOpeners(store, onClose, onNavigate);\n\n const hasUnread = state.items.some((item) => item.readAt === null);\n\n return (\n <Drawer\n open={open}\n onClose={onClose}\n anchor=\"right\"\n variant=\"right\"\n width={isMobile ? '100vw' : 400}\n dataTestId=\"notifications-panel\"\n >\n <DrawerHeader onClose={onClose}>{messages.panelTitle}</DrawerHeader>\n <DrawerContent>\n {/*\n Above the mark-all control as well as above the list, deliberately:\n \"marcar todas como lidas\" belongs to the INBOX, and a live entry has\n nothing to mark. A control between the two blocks would read as\n applying to both.\n */}\n {live ? (\n <LiveSection\n config={live}\n messages={messages}\n active={open}\n {...(onNavigate ? { onOpen: openLive } : {})}\n />\n ) : null}\n {hasUnread ? (\n <Box sx={{ display: 'flex', justifyContent: 'flex-end', pb: 1 }}>\n <Button\n variant=\"ghost\"\n color=\"primary\"\n size=\"xs\"\n onClick={() => store.markAllRead()}\n dataTestId=\"notifications-mark-all-read\"\n >\n {messages.markAllRead}\n </Button>\n </Box>\n ) : null}\n <PanelBody\n state={state}\n messages={messages}\n onRetry={() => store.invalidate()}\n onLoadMore={() => store.loadMore()}\n onOpen={openNotification}\n onDelete={(id) => store.remove(id)}\n />\n </DrawerContent>\n </Drawer>\n );\n}\n","/** One inbox row: unread accent, content (opens/marks read), timestamp, delete. */\nimport type { JSX } from 'react';\n\nimport { Button } from '@12-apps/ui/form/Button';\nimport { Box } from '@12-apps/ui/mui/Box';\nimport { alpha, type Theme } from '@12-apps/ui/mui/styles';\nimport { Text } from '@12-apps/ui/typography/Text';\n\nimport type { NotificationMessages } from '../messages';\nimport type { InboxNotification } from '../wire';\n\nimport { relativeTime } from './relative-time';\n\nconst contentButtonSx = {\n flex: 1,\n minWidth: 0,\n display: 'flex',\n flexDirection: 'column',\n gap: 0.25,\n textAlign: 'left',\n border: 'none',\n background: 'none',\n p: 0,\n cursor: 'pointer',\n color: 'text.primary',\n fontFamily: 'inherit',\n} as const;\n\nconst unreadDotSx = {\n width: 8,\n height: 8,\n borderRadius: '50%',\n bgcolor: 'primary.main',\n flex: '0 0 auto',\n} as const;\n\nexport function NotificationRow({\n notification,\n messages,\n onOpen,\n onDelete,\n}: {\n notification: InboxNotification;\n messages: NotificationMessages;\n onOpen: (notification: InboxNotification) => void;\n onDelete: (id: string) => void;\n}): JSX.Element {\n const unread = notification.readAt === null;\n return (\n <Box\n data-testid={`notification-${notification.id}`}\n sx={{\n display: 'flex',\n alignItems: 'flex-start',\n gap: 1,\n py: 1.5,\n px: 1,\n borderBottom: '1px solid',\n borderColor: 'divider',\n bgcolor: unread ? (t: Theme) => alpha(t.palette.primary.main, 0.06) : 'transparent',\n }}\n >\n <Box\n component=\"button\"\n type=\"button\"\n onClick={() => onOpen(notification)}\n aria-label={\n unread ? `${notification.title} (${messages.unreadSuffix})` : notification.title\n }\n sx={contentButtonSx}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n {unread ? <Box aria-hidden sx={unreadDotSx} /> : null}\n <Text variant=\"body\" size=\"sm\" weight={unread ? 'bold' : 'medium'} as=\"span\">\n {notification.title}\n </Text>\n </Box>\n <Text variant=\"caption\" size=\"xs\" color=\"secondary\" as=\"span\">\n {notification.body}\n </Text>\n <Text variant=\"caption\" size=\"xs\" color=\"secondary\" as=\"span\" italic>\n {relativeTime(notification.createdAt, messages)}\n </Text>\n </Box>\n\n <Button\n variant=\"ghost\"\n color=\"neutral\"\n size=\"xs\"\n aria-label={messages.deleteOne(notification.title)}\n onClick={() => onDelete(notification.id)}\n dataTestId={`notification-delete-${notification.id}`}\n >\n ✕\n </Button>\n </Box>\n );\n}\n"],"mappings":"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","names":["Button","Box","jsx","jsxs","Box","Button"]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-CQZMTFPY.js";
|
|
5
5
|
import {
|
|
6
6
|
NOTIFICATION_CHANNELS
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6W7INOYQ.js";
|
|
8
8
|
import {
|
|
9
9
|
__name
|
|
10
10
|
} from "./chunk-7QVYU63E.js";
|
|
@@ -291,4 +291,4 @@ __name(PreferencesScreen, "PreferencesScreen");
|
|
|
291
291
|
export {
|
|
292
292
|
PreferencesScreen
|
|
293
293
|
};
|
|
294
|
-
//# sourceMappingURL=preferences-screen-
|
|
294
|
+
//# sourceMappingURL=preferences-screen-SXUIGECY.js.map
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { N as NotificationsApiClient } from '../create-web-notifications-
|
|
2
|
-
export { B as BADGE_POLL_MS, a as BADGE_RECONCILE_MS, b as BellButtonProps, I as InboxListStatus, d as InboxState, e as InboxStore, f as
|
|
1
|
+
import { L as LiveActivitiesConfig, N as NotificationsApiClient } from '../create-web-notifications-_NVYmlvy.js';
|
|
2
|
+
export { B as BADGE_POLL_MS, a as BADGE_RECONCILE_MS, b as BellButtonProps, I as InboxListStatus, d as InboxState, e as InboxStore, f as LiveActivitiesHook, g as LiveActivityMessages, h as NotificationsHttpError, i as NotificationsPanelProps, j as NotificationsResult, k as NotificationsSignalHook, l as NotificationsSubscribe, m as NotificationsTransport, n as NotificationsWebConfig, P as PAGE_SIZE, o as PreferencesPayload, p as PreferencesScreenProps, q as PushRegistrationPayload, W as WebNotifications, r as WebPushPlatformHint, s as WebPushSetupConfig, t as createInboxStore, u as createNotificationsApiClient, c as createWebNotifications, v as httpNotificationsTransport, w as useInboxList, x as useInboxState, y as useUnreadCount } from '../create-web-notifications-_NVYmlvy.js';
|
|
3
3
|
import { JSX } from 'react';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { b as LiveActivity } from '../live-DYxEFO49.js';
|
|
5
|
+
export { c as LiveActivityLane, d as LiveActivityStep, l as liveActivityLane } from '../live-DYxEFO49.js';
|
|
6
|
+
import { N as NotificationMessages } from '../wire-BG1kuoXX.js';
|
|
7
|
+
import '../types-BlqZkCWZ.js';
|
|
6
8
|
|
|
7
9
|
/** Inline SVG bell (no icon-library dependency in this package). */
|
|
8
10
|
|
|
@@ -11,12 +13,59 @@ declare function BellIcon({ size, dim, }: {
|
|
|
11
13
|
dim?: boolean;
|
|
12
14
|
}): JSX.Element;
|
|
13
15
|
|
|
16
|
+
/**
|
|
17
|
+
* The pinned block at the top of the panel: everything that is happening NOW,
|
|
18
|
+
* above everything that has already happened.
|
|
19
|
+
*
|
|
20
|
+
* ## Why it is here and not a second surface
|
|
21
|
+
*
|
|
22
|
+
* The notification centre is where a person goes to find out what they missed.
|
|
23
|
+
* Splitting "happening" into its own bell would make them check two places to
|
|
24
|
+
* answer one question, and the half they would stop checking is the one that
|
|
25
|
+
* only has something in it occasionally — which is this one. Above the list,
|
|
26
|
+
* inside the same drawer, it is on the path they already walk.
|
|
27
|
+
*
|
|
28
|
+
* ## What it deliberately does NOT do
|
|
29
|
+
*
|
|
30
|
+
* - It does not touch `unread`. A live entry is not news; counting it would put
|
|
31
|
+
* a number on the bell that no amount of reading can clear.
|
|
32
|
+
* - It renders nothing at all when there is nothing live — no heading, no empty
|
|
33
|
+
* state, no reserved space. A panel with one permanent empty section in it is
|
|
34
|
+
* a panel that has taught its reader to skip the top.
|
|
35
|
+
* - It does not fetch. `useActivities` is the host's, and `active` tells it
|
|
36
|
+
* whether anyone is looking.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
interface LiveSectionProps {
|
|
40
|
+
config: LiveActivitiesConfig;
|
|
41
|
+
messages: NotificationMessages;
|
|
42
|
+
/** Whether the panel is open — passed straight through to the host's hook. */
|
|
43
|
+
active: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Follow a card's link.
|
|
46
|
+
*
|
|
47
|
+
* Optional, and the panel omits it for a host with no router: a card that
|
|
48
|
+
* cannot go anywhere renders as text rather than as a named control that
|
|
49
|
+
* does nothing.
|
|
50
|
+
*/
|
|
51
|
+
onOpen?: (activity: LiveActivity) => void;
|
|
52
|
+
}
|
|
53
|
+
declare function LiveSection({ config, messages, active, onOpen, }: LiveSectionProps): JSX.Element | null;
|
|
54
|
+
|
|
14
55
|
/**
|
|
15
56
|
* "há 5 min"-style relative timestamp, falling back to an absolute date for
|
|
16
57
|
* anything older than a week. Every word comes from the messages table, so a
|
|
17
58
|
* host in another locale changes the copy and the locale together.
|
|
59
|
+
*
|
|
60
|
+
* `now` is a parameter rather than a read, and the live section is why. A
|
|
61
|
+
* relative phrase is only true for the instant it was computed, so something
|
|
62
|
+
* has to CAUSE the render that recomputes it — and the live entries' own data
|
|
63
|
+
* cannot: a host backed by react-query gets the previous object back whenever a
|
|
64
|
+
* poll is deep-equal (`structuralSharing`, on by default), which within one
|
|
65
|
+
* stage it always is. The section therefore ticks a clock and hands it down.
|
|
66
|
+
* Defaulted, so every existing caller reads the wall clock exactly as before.
|
|
18
67
|
*/
|
|
19
|
-
declare function relativeTime(iso: string, messages: NotificationMessages): string;
|
|
68
|
+
declare function relativeTime(iso: string, messages: NotificationMessages, now?: number): string;
|
|
20
69
|
|
|
21
70
|
/**
|
|
22
71
|
* The browser half of Web Push: register the service worker, ask permission,
|
|
@@ -44,4 +93,4 @@ declare function enableWebPush(api: NotificationsApiClient, swPath?: string): Pr
|
|
|
44
93
|
/** Disable flow: unsubscribe the browser and drop the server-side row. */
|
|
45
94
|
declare function disableWebPush(api: NotificationsApiClient): Promise<void>;
|
|
46
95
|
|
|
47
|
-
export { BellIcon, NotificationsApiClient, type PushSetupResult, disableWebPush, enableWebPush, getExistingPushSubscription, pushSupported, relativeTime };
|
|
96
|
+
export { BellIcon, LiveActivitiesConfig, LiveActivity, LiveSection, type LiveSectionProps, NotificationsApiClient, type PushSetupResult, disableWebPush, enableWebPush, getExistingPushSubscription, pushSupported, relativeTime };
|
package/dist/react/index.js
CHANGED
|
@@ -3,10 +3,11 @@ import {
|
|
|
3
3
|
createNotificationsApiClient,
|
|
4
4
|
createWebNotifications,
|
|
5
5
|
httpNotificationsTransport
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-5Y7QRORV.js";
|
|
7
7
|
import {
|
|
8
|
+
LiveSection,
|
|
8
9
|
relativeTime
|
|
9
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-JCVRQ42B.js";
|
|
10
11
|
import {
|
|
11
12
|
BADGE_POLL_MS,
|
|
12
13
|
BADGE_RECONCILE_MS,
|
|
@@ -24,11 +25,15 @@ import {
|
|
|
24
25
|
pushSupported
|
|
25
26
|
} from "../chunk-CQZMTFPY.js";
|
|
26
27
|
import "../chunk-M2TVBVH2.js";
|
|
28
|
+
import {
|
|
29
|
+
liveActivityLane
|
|
30
|
+
} from "../chunk-RTURLH5U.js";
|
|
27
31
|
import "../chunk-7QVYU63E.js";
|
|
28
32
|
export {
|
|
29
33
|
BADGE_POLL_MS,
|
|
30
34
|
BADGE_RECONCILE_MS,
|
|
31
35
|
BellIcon,
|
|
36
|
+
LiveSection,
|
|
32
37
|
NotificationsHttpError,
|
|
33
38
|
PAGE_SIZE,
|
|
34
39
|
createInboxStore,
|
|
@@ -38,6 +43,7 @@ export {
|
|
|
38
43
|
enableWebPush,
|
|
39
44
|
getExistingPushSubscription,
|
|
40
45
|
httpNotificationsTransport,
|
|
46
|
+
liveActivityLane,
|
|
41
47
|
pushSupported,
|
|
42
48
|
relativeTime,
|
|
43
49
|
useInboxList,
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { A as ApiNotifications } from '../create-api-notifications-
|
|
2
|
-
export { C as CommittedNotification, E as EMAIL_DRIVERS, c as EmailDriver, d as EmailDriverDeclaration, e as EmailMessage, f as ExtraDrivers, L as ListNotificationsInput, g as NotificationAudienceDirectory, h as NotificationChannelPolicy, i as NotificationCommittedListener, j as NotificationContactDirectory, k as NotificationCreateData, l as NotificationDelegate, m as NotificationDeliveryDelegate, n as NotificationDeliveryRow, o as NotificationDeliveryWhere, p as NotificationDispatchScheduler, q as NotificationInboxStore, r as NotificationPageAfter, s as NotificationPreferenceDelegate, t as NotificationPreferenceRow, u as NotificationPreferenceStore, v as NotificationRouter, w as NotificationWhere, a as NotificationsActor, x as NotificationsApiError, y as NotificationsDb, z as NotificationsDbClient, B as NotificationsDbProvider, D as NotificationsRequest, F as NotificationsResponse, b as NotificationsRoute, N as NotificationsServerConfig, G as NotifyByPermission, H as NotifyOptions, I as NotifyResult, P as PermissionNotificationResult, J as PermissionNotificationSkip, K as PushSubscriptionDelegate, M as PushSubscriptionInput, O as PushSubscriptionRow, Q as PushSubscriptionStore, S as SMS_DRIVERS, R as SmsDriver, T as SmsDriverDeclaration, U as SmsMessage, V as TransportDeclaration, W as TransportRegistry, X as WHATSAPP_DRIVERS, Y as WhatsAppDriver, Z as WhatsAppDriverDeclaration, _ as WhatsAppMessage, $ as createApiNotifications, a0 as createTransportRegistry, a1 as emailTransport, a2 as foldApiError, a3 as formatEmail, a4 as formatSms, a5 as formatWhatsApp, a6 as ok, a7 as smsTransport, a8 as whatsAppTransport } from '../create-api-notifications-
|
|
3
|
-
export { D as DriverDeclarationBase, F as FetchImpl, N as NotificationProviderError, W as WEB_PUSH_DRIVERS, a as WebPushDriverDeclaration, b as WebPushMessage, c as WebPushSender, d as WebPushSubscription, e as WebPushSubscriptionSource, f as absoluteLink, g as formatWebPush, w as webPushTransport } from '../web-push-
|
|
1
|
+
import { A as ApiNotifications } from '../create-api-notifications-CcPYrM3p.js';
|
|
2
|
+
export { C as CommittedNotification, E as EMAIL_DRIVERS, c as EmailDriver, d as EmailDriverDeclaration, e as EmailMessage, f as ExtraDrivers, L as ListNotificationsInput, g as NotificationAudienceDirectory, h as NotificationChannelPolicy, i as NotificationCommittedListener, j as NotificationContactDirectory, k as NotificationCreateData, l as NotificationDelegate, m as NotificationDeliveryDelegate, n as NotificationDeliveryRow, o as NotificationDeliveryWhere, p as NotificationDispatchScheduler, q as NotificationInboxStore, r as NotificationPageAfter, s as NotificationPreferenceDelegate, t as NotificationPreferenceRow, u as NotificationPreferenceStore, v as NotificationRouter, w as NotificationWhere, a as NotificationsActor, x as NotificationsApiError, y as NotificationsDb, z as NotificationsDbClient, B as NotificationsDbProvider, D as NotificationsRequest, F as NotificationsResponse, b as NotificationsRoute, N as NotificationsServerConfig, G as NotifyByPermission, H as NotifyOptions, I as NotifyResult, P as PermissionNotificationResult, J as PermissionNotificationSkip, K as PushSubscriptionDelegate, M as PushSubscriptionInput, O as PushSubscriptionRow, Q as PushSubscriptionStore, S as SMS_DRIVERS, R as SmsDriver, T as SmsDriverDeclaration, U as SmsMessage, V as TransportDeclaration, W as TransportRegistry, X as WHATSAPP_DRIVERS, Y as WhatsAppDriver, Z as WhatsAppDriverDeclaration, _ as WhatsAppMessage, $ as createApiNotifications, a0 as createTransportRegistry, a1 as emailTransport, a2 as foldApiError, a3 as formatEmail, a4 as formatSms, a5 as formatWhatsApp, a6 as ok, a7 as smsTransport, a8 as whatsAppTransport } from '../create-api-notifications-CcPYrM3p.js';
|
|
3
|
+
export { D as DriverDeclarationBase, F as FetchImpl, N as NotificationProviderError, W as WEB_PUSH_DRIVERS, a as WebPushDriverDeclaration, b as WebPushMessage, c as WebPushSender, d as WebPushSubscription, e as WebPushSubscriptionSource, f as absoluteLink, g as formatWebPush, w as webPushTransport } from '../web-push-Dnyaha2z.js';
|
|
4
4
|
import { NotifyPort } from '@12-apps/wiring/ports';
|
|
5
|
-
export { a as NOTIFICATIONS_DRAIN_CRON, b as NOTIFICATIONS_DRAIN_LEASE_MS, c as NOTIFICATIONS_JOBS, d as NOTIFICATIONS_SWEEP_QUEUE, N as NotificationsJobDeps } from '../jobs-
|
|
6
|
-
import '../generators-
|
|
7
|
-
import '../types-
|
|
8
|
-
import '../wire-
|
|
5
|
+
export { a as NOTIFICATIONS_DRAIN_CRON, b as NOTIFICATIONS_DRAIN_LEASE_MS, c as NOTIFICATIONS_JOBS, d as NOTIFICATIONS_SWEEP_QUEUE, N as NotificationsJobDeps } from '../jobs--fex87-q.js';
|
|
6
|
+
import '../generators-qAD4fNPq.js';
|
|
7
|
+
import '../types-BlqZkCWZ.js';
|
|
8
|
+
import '../wire-BG1kuoXX.js';
|
|
9
9
|
import '../template-Dlt5S54z.js';
|
|
10
10
|
import '@12-apps/wiring';
|
|
11
11
|
|
package/dist/server/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
NOTIFICATIONS_JOBS,
|
|
5
5
|
NOTIFICATIONS_SWEEP_QUEUE,
|
|
6
6
|
wireNotifyPort
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-ZIR3ILFH.js";
|
|
8
8
|
import {
|
|
9
9
|
EMAIL_DRIVERS,
|
|
10
10
|
NotificationProviderError,
|
|
@@ -25,10 +25,11 @@ import {
|
|
|
25
25
|
smsTransport,
|
|
26
26
|
webPushTransport,
|
|
27
27
|
whatsAppTransport
|
|
28
|
-
} from "../chunk-
|
|
29
|
-
import "../chunk-
|
|
28
|
+
} from "../chunk-WVRODNXQ.js";
|
|
29
|
+
import "../chunk-SWOWHIFE.js";
|
|
30
30
|
import "../chunk-M2TVBVH2.js";
|
|
31
|
-
import "../chunk-
|
|
31
|
+
import "../chunk-RTURLH5U.js";
|
|
32
|
+
import "../chunk-6W7INOYQ.js";
|
|
32
33
|
import "../chunk-EKUSNUBT.js";
|
|
33
34
|
import "../chunk-7QVYU63E.js";
|
|
34
35
|
export {
|
|
@@ -60,7 +60,16 @@ interface NotificationContent {
|
|
|
60
60
|
body: string;
|
|
61
61
|
/** In-app deep link (a same-origin path such as `/orders/123`). */
|
|
62
62
|
link?: string;
|
|
63
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Structured extras for consumers that want more than text.
|
|
65
|
+
*
|
|
66
|
+
* ONE KEY IS RESERVED: `liveSubject` (`LIVE_SUBJECT_KEY` in `./live`) ties
|
|
67
|
+
* this notification to a live activity, and the WEB_PUSH transport turns it
|
|
68
|
+
* into the tray `tag` that collapses every push about one subject onto a
|
|
69
|
+
* single entry. A host already using that name for something else acquires
|
|
70
|
+
* that behaviour without asking for it — so it is named here, on the field a
|
|
71
|
+
* generator actually writes, and not only where the feature is documented.
|
|
72
|
+
*/
|
|
64
73
|
data?: Record<string, unknown>;
|
|
65
74
|
}
|
|
66
75
|
/** Who receives a notification. `clientId` scopes it to a tenant when set. */
|