@12-apps/notifications 4.8.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 +173 -1
- package/README.md +138 -0
- package/dist/catalog-BOVZ2b-b.d.ts +132 -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-EKUSNUBT.js +222 -0
- package/dist/chunk-EKUSNUBT.js.map +1 -0
- package/dist/chunk-FTFLU6KH.js +114 -0
- package/dist/chunk-FTFLU6KH.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-7234ROOP.js → chunk-WVRODNXQ.js} +28 -6
- package/dist/chunk-WVRODNXQ.js.map +1 -0
- package/dist/chunk-ZFIYBNZ7.js +502 -0
- package/dist/chunk-ZFIYBNZ7.js.map +1 -0
- package/dist/{chunk-KU4FVOFA.js → chunk-ZIR3ILFH.js} +2 -2
- package/dist/{create-api-notifications-WaexrZnn.d.ts → create-api-notifications-CcPYrM3p.d.ts} +35 -4
- package/dist/{create-web-notifications-DrgqtU4Q.d.ts → create-web-notifications-_NVYmlvy.d.ts} +89 -4
- package/dist/email/index.d.ts +26 -0
- package/dist/email/index.js +20 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/locales.d.ts +43 -0
- package/dist/email/locales.js +29 -0
- package/dist/email/locales.js.map +1 -0
- package/dist/email/previews/hono.d.ts +46 -0
- package/dist/email/previews/hono.js +33 -0
- package/dist/email/previews/hono.js.map +1 -0
- package/dist/email/previews/index.d.ts +67 -0
- package/dist/email/previews/index.js +12 -0
- package/dist/email/previews/index.js.map +1 -0
- package/dist/email/previews/react/index.d.ts +43 -0
- package/dist/email/previews/react/index.js +58 -0
- package/dist/email/previews/react/index.js.map +1 -0
- package/dist/{generators-CH5m8Ucj.d.ts → generators-qAD4fNPq.d.ts} +1 -1
- package/dist/hono/index.d.ts +6 -5
- package/dist/hono/index.js +5 -3
- package/dist/hono/index.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +15 -5
- package/dist/{jobs-CcsSA0YR.d.ts → jobs--fex87-q.d.ts} +1 -1
- package/dist/live-DYxEFO49.d.ts +158 -0
- package/dist/manifest/index.d.ts +39 -1
- package/dist/manifest/index.js +9 -0
- package/dist/manifest/index.js.map +1 -1
- package/dist/manifest/server.d.ts +32 -7
- package/dist/manifest/server.js +16 -4
- package/dist/manifest/server.js.map +1 -1
- package/dist/manifest/web.d.ts +19 -4
- package/dist/manifest/web.js +9 -1
- package/dist/manifest/web.js.map +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/preview-screen-DYJRAnAY.d.ts +83 -0
- package/dist/react/index.d.ts +55 -6
- package/dist/react/index.js +16 -10
- package/dist/server/index.d.ts +8 -7
- package/dist/server/index.js +6 -4
- package/dist/template-Dlt5S54z.d.ts +196 -0
- package/dist/{types-CYJN1xCM.d.ts → types-BlqZkCWZ.d.ts} +11 -2
- package/dist/web-push/index.d.ts +2 -2
- package/dist/{web-push-iER5StBm.d.ts → web-push-Dnyaha2z.d.ts} +21 -1
- package/dist/{wire-CmRrB3_s.d.ts → wire-BG1kuoXX.d.ts} +1 -1
- package/package.json +22 -2
- package/src/email/chrome.en-US.ts +8 -0
- package/src/email/chrome.pt-BR.ts +21 -0
- package/src/email/index.ts +43 -0
- package/src/email/locales.ts +29 -0
- package/src/email/previews/catalog.ts +208 -0
- package/src/email/previews/hono.ts +69 -0
- package/src/email/previews/index.ts +26 -0
- package/src/email/previews/react/copy.en-US.ts +24 -0
- package/src/email/previews/react/copy.pt-BR.ts +24 -0
- package/src/email/previews/react/copy.ts +42 -0
- package/src/email/previews/react/index.tsx +14 -0
- package/src/email/previews/react/loadable.tsx +83 -0
- package/src/email/previews/react/message-list.tsx +133 -0
- package/src/email/previews/react/message-view.tsx +167 -0
- package/src/email/previews/react/preview-screen.tsx +342 -0
- package/src/email/previews/react/transport.ts +60 -0
- package/src/email/previews/routes.ts +111 -0
- package/src/email/template.ts +365 -0
- package/src/email/text.ts +59 -0
- package/src/email/theme.ts +77 -0
- package/src/index.ts +10 -0
- package/src/live.ts +179 -0
- package/src/manifest/index.ts +37 -0
- package/src/manifest/server.ts +23 -0
- package/src/manifest/web.ts +13 -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/email.ts +62 -0
- package/src/server/transports/web-push.ts +22 -0
- package/src/types.ts +10 -1
- package/dist/chunk-7234ROOP.js.map +0 -1
- package/dist/chunk-BGI4BQ66.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.js
CHANGED
|
@@ -9,17 +9,25 @@ import {
|
|
|
9
9
|
mergeChoices,
|
|
10
10
|
mergeStoredRow,
|
|
11
11
|
normalizePhoneE164
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import {
|
|
14
|
-
NOTIFICATION_CHANNELS,
|
|
15
|
-
taxonomyOf
|
|
16
|
-
} from "./chunk-BGI4BQ66.js";
|
|
12
|
+
} from "./chunk-SWOWHIFE.js";
|
|
17
13
|
import {
|
|
18
14
|
messagesOf
|
|
19
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";
|
|
22
|
+
import {
|
|
23
|
+
NOTIFICATION_CHANNELS,
|
|
24
|
+
taxonomyOf
|
|
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 };
|
package/dist/manifest/index.d.ts
CHANGED
|
@@ -63,5 +63,43 @@ declare const notificationsManifest: {
|
|
|
63
63
|
readonly server: readonly ["http", "jobs"];
|
|
64
64
|
readonly web: readonly ["surface"];
|
|
65
65
|
};
|
|
66
|
+
/**
|
|
67
|
+
* The e-mail PREVIEW console — a second manifest, from the same package.
|
|
68
|
+
*
|
|
69
|
+
* ## Why a second manifest and not two more keys on the first
|
|
70
|
+
*
|
|
71
|
+
* `notificationsManifest` has already spent both slots this surface needs:
|
|
72
|
+
* `http` is the account inbox at `/api/account`, `surface` is the bell and the
|
|
73
|
+
* preference matrix. A capability is singular by the contract's shape, so a
|
|
74
|
+
* package with two genuinely different surfaces declares two manifests — which
|
|
75
|
+
* is exactly what `@12-apps/auth` does with `@12-apps/auth-platform`, and for
|
|
76
|
+
* the same reason it gives: those two switches turn a sign-in method off for
|
|
77
|
+
* EVERYBODY, so they do not belong behind the same gate as "reset my password".
|
|
78
|
+
*
|
|
79
|
+
* The split here is the same one. The inbox ships to every signed-in user; this
|
|
80
|
+
* console publishes the product's whole transactional-mail inventory and the
|
|
81
|
+
* exact wording and link shape of its verification and reset mails, which is
|
|
82
|
+
* the reference someone writing a convincing phishing mail would want. Two
|
|
83
|
+
* manifests keep that expressible: a host mounts the inbox and DECLINES the
|
|
84
|
+
* console, in writing, rather than silently getting both behind one gate.
|
|
85
|
+
*
|
|
86
|
+
* ## What it deliberately does not declare
|
|
87
|
+
*
|
|
88
|
+
* No `db` — a catalogue is DERIVED from what a host already sends, so an
|
|
89
|
+
* adopter mounts it without touching its schema. No `notifications`, because
|
|
90
|
+
* this surface authors no alert. And no `email`: that capability is a DELIVERY
|
|
91
|
+
* port, and this manifest renders and never sends. The delivery port is the
|
|
92
|
+
* OTHER half of this package, and it stays where it is.
|
|
93
|
+
*/
|
|
94
|
+
declare const notificationEmailPreviewsManifest: {
|
|
95
|
+
readonly name: "@12-apps/notifications-email-previews";
|
|
96
|
+
readonly contract: 1;
|
|
97
|
+
/** A refusal to render a preview files under its own namespace, not nowhere. */
|
|
98
|
+
readonly observability: {
|
|
99
|
+
readonly namespace: "email-previews";
|
|
100
|
+
};
|
|
101
|
+
readonly server: readonly ["http"];
|
|
102
|
+
readonly web: readonly ["surface"];
|
|
103
|
+
};
|
|
66
104
|
|
|
67
|
-
export { notificationsManifest };
|
|
105
|
+
export { notificationEmailPreviewsManifest, notificationsManifest };
|
package/dist/manifest/index.js
CHANGED
|
@@ -13,7 +13,16 @@ var notificationsManifest = {
|
|
|
13
13
|
server: ["http", "jobs"],
|
|
14
14
|
web: ["surface"]
|
|
15
15
|
};
|
|
16
|
+
var notificationEmailPreviewsManifest = {
|
|
17
|
+
name: "@12-apps/notifications-email-previews",
|
|
18
|
+
contract: 1,
|
|
19
|
+
/** A refusal to render a preview files under its own namespace, not nowhere. */
|
|
20
|
+
observability: { namespace: "email-previews" },
|
|
21
|
+
server: ["http"],
|
|
22
|
+
web: ["surface"]
|
|
23
|
+
};
|
|
16
24
|
export {
|
|
25
|
+
notificationEmailPreviewsManifest,
|
|
17
26
|
notificationsManifest
|
|
18
27
|
};
|
|
19
28
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/manifest/index.ts"],"sourcesContent":["/**\n * `@12-apps/notifications/manifest` — the SHARED wiring manifest.\n *\n * Identity, the Prisma contribution (the four owned models) and the runtime\n * inventory: `http` on the server. Three narrowings are deliberate:\n *\n * - **No `notifications` blueprints.** This package is the notification\n * MECHANISM — the inbox, the preference matrix, the transports, the retry\n * sweep — not an author of alerts. The blueprints belong to whichever\n * package raises the alert (`@12-apps/product-research`'s budget warning\n * ships as a factory over host copy for exactly this reason), and this one\n * takes them through the `generators` seam at mount.\n * - **No `email` capability.** The transports are host-supplied config\n * (`config.transports`, `config.drivers`), so what would be declared here\n * is a seam the host already fills — and declaring it would oblige an\n * adopter to bind a mailer this package never owns.\n *\n * ON THE `jobs` DECLARATION. The dispatch fast path and the retry sweep are\n * this package's own cadence decisions — attempts, backoff, the five-minute\n * tick, the single-flight lease — and they were host code in every adopting\n * host, restated by hand from this package's docstrings. That is the\n * `paymentsJobBlueprints()` incident's shape exactly: a mechanism a host must\n * remember to schedule is a mechanism most hosts silently do not have, and the\n * one host that DID write them wrote them correctly only because someone read\n * the source. `./server`'s `NOTIFICATIONS_JOBS` declares both; a host with no\n * worker declines the capability in writing and the report says so.\n *\n * ON THE `web` INVENTORY, which this manifest used to narrow away. The reason\n * given — that listing it would oblige every SERVER host to answer for a React\n * surface it never mounts — is not how the consumer behaves: a capability\n * declared for the OTHER runtime is reported `out-of-scope`, and only an\n * applicable, unanswered one is `unbound`. So the narrowing protected nothing\n * and hid Bell, Panel and Preferences from every adopting host, which is why\n * the origin host hand-duplicated two of the three.\n *\n * ON THE `db` DECLARATION. The origin host already composes\n * `prisma/notifications.prisma` into its schema — but by STRUCTURAL\n * DISCOVERY, the assembler's fallback for a package that declares nothing.\n * That fallback is why the gap was invisible: four tables reached a host's\n * database with no declaration behind them, and the contract's whole claim\n * is that a package's models arrive because it said so. Declaring changes no\n * host behaviour (the assembler reads the declaration where it used to scan)\n * and closes the one case where composition was happening by accident.\n *\n * `@12-apps/wiring` is a TYPE-ONLY devDependency (the report-builder move):\n * the manifest is a plain `satisfies`-checked value, and the producer\n * factories' runtime assertions run in this package's own test suite.\n */\n\nimport type { PackageManifest } from '@12-apps/wiring';\n\nexport const notificationsManifest = {\n name: '@12-apps/notifications',\n contract: 1,\n db: { partial: 'prisma/notifications.prisma', migrations: 'prisma/migrations' },\n /**\n * Mandatory for runtime manifests since wiring 1.3.0: a delivery that\n * exhausts its attempts files under `notifications`, not nowhere.\n */\n observability: { namespace: 'notifications' },\n server: ['http', 'jobs'],\n web: ['surface'],\n} as const satisfies PackageManifest;\n"],"mappings":";;;AAmDO,IAAM,wBAAwB;AAAA,EACnC,MAAM;AAAA,EACN,UAAU;AAAA,EACV,IAAI,EAAE,SAAS,+BAA+B,YAAY,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAK9E,eAAe,EAAE,WAAW,gBAAgB;AAAA,EAC5C,QAAQ,CAAC,QAAQ,MAAM;AAAA,EACvB,KAAK,CAAC,SAAS;AACjB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/manifest/index.ts"],"sourcesContent":["/**\n * `@12-apps/notifications/manifest` — the SHARED wiring manifest.\n *\n * Identity, the Prisma contribution (the four owned models) and the runtime\n * inventory: `http` on the server. Three narrowings are deliberate:\n *\n * - **No `notifications` blueprints.** This package is the notification\n * MECHANISM — the inbox, the preference matrix, the transports, the retry\n * sweep — not an author of alerts. The blueprints belong to whichever\n * package raises the alert (`@12-apps/product-research`'s budget warning\n * ships as a factory over host copy for exactly this reason), and this one\n * takes them through the `generators` seam at mount.\n * - **No `email` capability.** The transports are host-supplied config\n * (`config.transports`, `config.drivers`), so what would be declared here\n * is a seam the host already fills — and declaring it would oblige an\n * adopter to bind a mailer this package never owns.\n *\n * ON THE `jobs` DECLARATION. The dispatch fast path and the retry sweep are\n * this package's own cadence decisions — attempts, backoff, the five-minute\n * tick, the single-flight lease — and they were host code in every adopting\n * host, restated by hand from this package's docstrings. That is the\n * `paymentsJobBlueprints()` incident's shape exactly: a mechanism a host must\n * remember to schedule is a mechanism most hosts silently do not have, and the\n * one host that DID write them wrote them correctly only because someone read\n * the source. `./server`'s `NOTIFICATIONS_JOBS` declares both; a host with no\n * worker declines the capability in writing and the report says so.\n *\n * ON THE `web` INVENTORY, which this manifest used to narrow away. The reason\n * given — that listing it would oblige every SERVER host to answer for a React\n * surface it never mounts — is not how the consumer behaves: a capability\n * declared for the OTHER runtime is reported `out-of-scope`, and only an\n * applicable, unanswered one is `unbound`. So the narrowing protected nothing\n * and hid Bell, Panel and Preferences from every adopting host, which is why\n * the origin host hand-duplicated two of the three.\n *\n * ON THE `db` DECLARATION. The origin host already composes\n * `prisma/notifications.prisma` into its schema — but by STRUCTURAL\n * DISCOVERY, the assembler's fallback for a package that declares nothing.\n * That fallback is why the gap was invisible: four tables reached a host's\n * database with no declaration behind them, and the contract's whole claim\n * is that a package's models arrive because it said so. Declaring changes no\n * host behaviour (the assembler reads the declaration where it used to scan)\n * and closes the one case where composition was happening by accident.\n *\n * `@12-apps/wiring` is a TYPE-ONLY devDependency (the report-builder move):\n * the manifest is a plain `satisfies`-checked value, and the producer\n * factories' runtime assertions run in this package's own test suite.\n */\n\nimport type { PackageManifest } from '@12-apps/wiring';\n\nexport const notificationsManifest = {\n name: '@12-apps/notifications',\n contract: 1,\n db: { partial: 'prisma/notifications.prisma', migrations: 'prisma/migrations' },\n /**\n * Mandatory for runtime manifests since wiring 1.3.0: a delivery that\n * exhausts its attempts files under `notifications`, not nowhere.\n */\n observability: { namespace: 'notifications' },\n server: ['http', 'jobs'],\n web: ['surface'],\n} as const satisfies PackageManifest;\n\n/**\n * The e-mail PREVIEW console — a second manifest, from the same package.\n *\n * ## Why a second manifest and not two more keys on the first\n *\n * `notificationsManifest` has already spent both slots this surface needs:\n * `http` is the account inbox at `/api/account`, `surface` is the bell and the\n * preference matrix. A capability is singular by the contract's shape, so a\n * package with two genuinely different surfaces declares two manifests — which\n * is exactly what `@12-apps/auth` does with `@12-apps/auth-platform`, and for\n * the same reason it gives: those two switches turn a sign-in method off for\n * EVERYBODY, so they do not belong behind the same gate as \"reset my password\".\n *\n * The split here is the same one. The inbox ships to every signed-in user; this\n * console publishes the product's whole transactional-mail inventory and the\n * exact wording and link shape of its verification and reset mails, which is\n * the reference someone writing a convincing phishing mail would want. Two\n * manifests keep that expressible: a host mounts the inbox and DECLINES the\n * console, in writing, rather than silently getting both behind one gate.\n *\n * ## What it deliberately does not declare\n *\n * No `db` — a catalogue is DERIVED from what a host already sends, so an\n * adopter mounts it without touching its schema. No `notifications`, because\n * this surface authors no alert. And no `email`: that capability is a DELIVERY\n * port, and this manifest renders and never sends. The delivery port is the\n * OTHER half of this package, and it stays where it is.\n */\nexport const notificationEmailPreviewsManifest = {\n name: '@12-apps/notifications-email-previews',\n contract: 1,\n /** A refusal to render a preview files under its own namespace, not nowhere. */\n observability: { namespace: 'email-previews' },\n server: ['http'],\n web: ['surface'],\n} as const satisfies PackageManifest;\n"],"mappings":";;;AAmDO,IAAM,wBAAwB;AAAA,EACnC,MAAM;AAAA,EACN,UAAU;AAAA,EACV,IAAI,EAAE,SAAS,+BAA+B,YAAY,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAK9E,eAAe,EAAE,WAAW,gBAAgB;AAAA,EAC5C,QAAQ,CAAC,QAAQ,MAAM;AAAA,EACvB,KAAK,CAAC,SAAS;AACjB;AA8BO,IAAM,oCAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,UAAU;AAAA;AAAA,EAEV,eAAe,EAAE,WAAW,iBAAiB;AAAA,EAC7C,QAAQ,CAAC,MAAM;AAAA,EACf,KAAK,CAAC,SAAS;AACjB;","names":[]}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { EmailPreviewRoute } from '../email/previews/index.js';
|
|
1
2
|
import * as _12_apps_wiring from '@12-apps/wiring';
|
|
2
3
|
import { WireRequest } from '@12-apps/wiring';
|
|
3
|
-
import { N as NotificationsServerConfig, A as ApiNotifications, b as NotificationsRoute } from '../create-api-notifications-
|
|
4
|
-
import { N as NotificationsJobDeps } from '../jobs-
|
|
5
|
-
import '../
|
|
6
|
-
import '../
|
|
7
|
-
import '../
|
|
8
|
-
import '../
|
|
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
|
+
import { E as EmailPreviewsConfig } from '../catalog-BOVZ2b-b.js';
|
|
7
|
+
import '../generators-qAD4fNPq.js';
|
|
8
|
+
import '../types-BlqZkCWZ.js';
|
|
9
|
+
import '../wire-BG1kuoXX.js';
|
|
10
|
+
import '../web-push-Dnyaha2z.js';
|
|
11
|
+
import '../template-Dlt5S54z.js';
|
|
9
12
|
|
|
10
13
|
/** One `NotificationsRoute` as the wiring contract reads it. */
|
|
11
14
|
declare function asWireRoute(route: NotificationsRoute): {
|
|
@@ -41,5 +44,27 @@ declare const notificationsServerManifest: {
|
|
|
41
44
|
};
|
|
42
45
|
};
|
|
43
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* The preview console's server half — the two endpoints over the catalogue.
|
|
49
|
+
*
|
|
50
|
+
* A CONSTANT, not a factory. `http.create(config)` receives whatever the host
|
|
51
|
+
* bound at adoption, and "which messages exist" is precisely a host's binding:
|
|
52
|
+
* a package cannot know that a product sends a "your quota is exhausted"
|
|
53
|
+
* notice, let alone what data it renders from. Writing `EmailPreviewsConfig`
|
|
54
|
+
* as a factory argument instead would move that decision out of
|
|
55
|
+
* `bindings.http`, where `assemble()` can report on it, into a call the report
|
|
56
|
+
* never sees.
|
|
57
|
+
*
|
|
58
|
+
* The routes carry `kind: 'authenticated'` — see `../email/previews/routes`
|
|
59
|
+
* for why the descriptor states a posture it cannot itself enforce.
|
|
60
|
+
*/
|
|
61
|
+
declare const notificationEmailPreviewsServerManifest: {
|
|
62
|
+
readonly name: "@12-apps/notifications-email-previews";
|
|
63
|
+
readonly http: {
|
|
64
|
+
readonly create: (config: EmailPreviewsConfig) => {
|
|
65
|
+
routes: EmailPreviewRoute[];
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
};
|
|
44
69
|
|
|
45
|
-
export { createWireApiNotifications, notificationsServerManifest };
|
|
70
|
+
export { createWireApiNotifications, notificationEmailPreviewsServerManifest, notificationsServerManifest };
|
package/dist/manifest/server.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
emailPreviewRoutes
|
|
3
|
+
} from "../chunk-FTFLU6KH.js";
|
|
1
4
|
import {
|
|
2
5
|
NOTIFICATIONS_JOBS
|
|
3
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-ZIR3ILFH.js";
|
|
4
7
|
import {
|
|
5
8
|
createApiNotifications
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-BGI4BQ66.js";
|
|
9
|
+
} from "../chunk-WVRODNXQ.js";
|
|
10
|
+
import "../chunk-SWOWHIFE.js";
|
|
9
11
|
import "../chunk-M2TVBVH2.js";
|
|
12
|
+
import "../chunk-RTURLH5U.js";
|
|
13
|
+
import "../chunk-6W7INOYQ.js";
|
|
14
|
+
import "../chunk-EKUSNUBT.js";
|
|
10
15
|
import {
|
|
11
16
|
__name
|
|
12
17
|
} from "../chunk-7QVYU63E.js";
|
|
@@ -51,8 +56,15 @@ var notificationsServerManifest = {
|
|
|
51
56
|
*/
|
|
52
57
|
jobs: NOTIFICATIONS_JOBS
|
|
53
58
|
};
|
|
59
|
+
var notificationEmailPreviewsServerManifest = {
|
|
60
|
+
name: "@12-apps/notifications-email-previews",
|
|
61
|
+
http: {
|
|
62
|
+
create: /* @__PURE__ */ __name((config) => ({ routes: emailPreviewRoutes(config) }), "create")
|
|
63
|
+
}
|
|
64
|
+
};
|
|
54
65
|
export {
|
|
55
66
|
createWireApiNotifications,
|
|
67
|
+
notificationEmailPreviewsServerManifest,
|
|
56
68
|
notificationsServerManifest
|
|
57
69
|
};
|
|
58
70
|
//# sourceMappingURL=server.js.map
|
|
@@ -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 {\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"],"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,7 +1,9 @@
|
|
|
1
|
-
import { c as
|
|
1
|
+
import { c as createEmailPreviewScreen } from '../preview-screen-DYJRAnAY.js';
|
|
2
|
+
import { c as createWebNotifications } from '../create-web-notifications-_NVYmlvy.js';
|
|
2
3
|
import 'react';
|
|
3
|
-
import '../wire-
|
|
4
|
-
import '../types-
|
|
4
|
+
import '../wire-BG1kuoXX.js';
|
|
5
|
+
import '../types-BlqZkCWZ.js';
|
|
6
|
+
import '../live-DYxEFO49.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* `@12-apps/notifications/manifest/web` — the web capabilities.
|
|
@@ -47,5 +49,18 @@ declare const notificationsWebManifest: {
|
|
|
47
49
|
readonly create: typeof createWebNotifications;
|
|
48
50
|
};
|
|
49
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* The preview console's web half.
|
|
54
|
+
*
|
|
55
|
+
* One screen, named `page`, because a screen's NAME is what an area row
|
|
56
|
+
* resolves against — a surface that was itself the component is the shape that
|
|
57
|
+
* made an area row resolve to `undefined` in `@12-apps/auth` for a release.
|
|
58
|
+
*/
|
|
59
|
+
declare const notificationEmailPreviewsWebManifest: {
|
|
60
|
+
readonly name: "@12-apps/notifications-email-previews";
|
|
61
|
+
readonly surface: {
|
|
62
|
+
readonly create: typeof createEmailPreviewScreen;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
50
65
|
|
|
51
|
-
export { notificationsWebManifest };
|
|
66
|
+
export { notificationEmailPreviewsWebManifest, notificationsWebManifest };
|
package/dist/manifest/web.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createWebNotifications
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-5Y7QRORV.js";
|
|
4
4
|
import "../chunk-BW723CX2.js";
|
|
5
|
+
import {
|
|
6
|
+
createEmailPreviewScreen
|
|
7
|
+
} from "../chunk-ZFIYBNZ7.js";
|
|
5
8
|
import "../chunk-M2TVBVH2.js";
|
|
6
9
|
import "../chunk-7QVYU63E.js";
|
|
7
10
|
|
|
@@ -10,7 +13,12 @@ var notificationsWebManifest = {
|
|
|
10
13
|
name: "@12-apps/notifications",
|
|
11
14
|
surface: { create: createWebNotifications }
|
|
12
15
|
};
|
|
16
|
+
var notificationEmailPreviewsWebManifest = {
|
|
17
|
+
name: "@12-apps/notifications-email-previews",
|
|
18
|
+
surface: { create: createEmailPreviewScreen }
|
|
19
|
+
};
|
|
13
20
|
export {
|
|
21
|
+
notificationEmailPreviewsWebManifest,
|
|
14
22
|
notificationsWebManifest
|
|
15
23
|
};
|
|
16
24
|
//# sourceMappingURL=web.js.map
|
package/dist/manifest/web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/manifest/web.ts"],"sourcesContent":["/**\n * `@12-apps/notifications/manifest/web` — the web capabilities.\n *\n * `surface.create` IS `createWebNotifications`, unchanged: the bell, the inbox\n * slide-over, the preferences screen and the bound store, built once per\n * adoption by the consumer's binder (the members are component TYPES, so\n * rebuilding per render unmounts the panel mid-interaction — the memoisation\n * rule every hand wiring carries as a comment today).\n *\n * ## Why this manifest exists now\n *\n * It was narrowed away with a reason that reads plausibly and is FALSE:\n * \"listing `web` would oblige every server host adopting this manifest to\n * answer for a React surface it never mounts.\" The consumer does not work\n * that way. A capability declared for the other runtime is reported\n * `out-of-scope` — \"a web host answers for this\" — and `assemble()` returns\n * fine; only a capability applicable to THIS runtime and unanswered is\n * `unbound`. `wiring`'s own fixture package declares both halves and its\n * server-host suite asserts exactly that.\n *\n * The narrowing therefore bought nothing and cost the thing the capability is\n * for. `./react` and `./web-push` ship Bell, Panel and Preferences — the exact\n * screens the adaptation report wanted to stop being hand-duplicated in hosts,\n * and the origin host duplicated the preferences screen and the push setup\n * anyway, because a manifest that never mentions them is a manifest nobody\n * discovers them from.\n *\n * ## Why there are no `areas`\n *\n * The bell is not a routed screen: it lives in a host's header chrome, beside\n * whatever else that host puts there, and no package can suggest a route for\n * it. Preferences IS routed, but where it belongs differs per host — under\n * account settings in one app, under a tenant's configuration in another — and\n * it is offered as `page` on the surface for the host to route at its own\n * call site. A suggested nav row would be wrong for every host but the first,\n * which is the `AreaContribution` doctrine's own test.\n */\n\nimport type { AnyWebManifest } from '@12-apps/wiring';\n\nimport { createWebNotifications } from '../react/create-web-notifications';\n\nexport const notificationsWebManifest = {\n name: '@12-apps/notifications',\n surface: { create: createWebNotifications },\n} as const satisfies AnyWebManifest;\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/manifest/web.ts"],"sourcesContent":["/**\n * `@12-apps/notifications/manifest/web` — the web capabilities.\n *\n * `surface.create` IS `createWebNotifications`, unchanged: the bell, the inbox\n * slide-over, the preferences screen and the bound store, built once per\n * adoption by the consumer's binder (the members are component TYPES, so\n * rebuilding per render unmounts the panel mid-interaction — the memoisation\n * rule every hand wiring carries as a comment today).\n *\n * ## Why this manifest exists now\n *\n * It was narrowed away with a reason that reads plausibly and is FALSE:\n * \"listing `web` would oblige every server host adopting this manifest to\n * answer for a React surface it never mounts.\" The consumer does not work\n * that way. A capability declared for the other runtime is reported\n * `out-of-scope` — \"a web host answers for this\" — and `assemble()` returns\n * fine; only a capability applicable to THIS runtime and unanswered is\n * `unbound`. `wiring`'s own fixture package declares both halves and its\n * server-host suite asserts exactly that.\n *\n * The narrowing therefore bought nothing and cost the thing the capability is\n * for. `./react` and `./web-push` ship Bell, Panel and Preferences — the exact\n * screens the adaptation report wanted to stop being hand-duplicated in hosts,\n * and the origin host duplicated the preferences screen and the push setup\n * anyway, because a manifest that never mentions them is a manifest nobody\n * discovers them from.\n *\n * ## Why there are no `areas`\n *\n * The bell is not a routed screen: it lives in a host's header chrome, beside\n * whatever else that host puts there, and no package can suggest a route for\n * it. Preferences IS routed, but where it belongs differs per host — under\n * account settings in one app, under a tenant's configuration in another — and\n * it is offered as `page` on the surface for the host to route at its own\n * call site. A suggested nav row would be wrong for every host but the first,\n * which is the `AreaContribution` doctrine's own test.\n */\n\nimport type { AnyWebManifest } from '@12-apps/wiring';\n\nimport { createEmailPreviewScreen } from '../email/previews/react/preview-screen';\nimport { createWebNotifications } from '../react/create-web-notifications';\n\nexport const notificationsWebManifest = {\n name: '@12-apps/notifications',\n surface: { create: createWebNotifications },\n} as const satisfies AnyWebManifest;\n\n/**\n * The preview console's web half.\n *\n * One screen, named `page`, because a screen's NAME is what an area row\n * resolves against — a surface that was itself the component is the shape that\n * made an area row resolve to `undefined` in `@12-apps/auth` for a release.\n */\nexport const notificationEmailPreviewsWebManifest = {\n name: '@12-apps/notifications-email-previews',\n surface: { create: createEmailPreviewScreen },\n} as const satisfies AnyWebManifest;\n"],"mappings":";;;;;;;;;;;AA2CO,IAAM,2BAA2B;AAAA,EACtC,MAAM;AAAA,EACN,SAAS,EAAE,QAAQ,uBAAuB;AAC5C;AASO,IAAM,uCAAuC;AAAA,EAClD,MAAM;AAAA,EACN,SAAS,EAAE,QAAQ,yBAAyB;AAC9C;","names":[]}
|
|
@@ -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
|