@voltro/plugin-notifications 0.81.0 → 0.83.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/CHANGELOG.md +1806 -6
- package/dist/define.d.ts +53 -0
- package/dist/define.js +15 -0
- package/dist/index.d.ts +235 -0
- package/dist/index.js +516 -215
- package/dist/rpc.d.ts +5 -0
- package/dist/rpc.js +23 -21
- package/dist/web.d.ts +2 -2
- package/package.json +10 -5
package/dist/define.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
|
|
3
|
+
export declare const defineNotification: <Audience, Payload>(config: DefineNotificationConfig<Audience, Payload>) => NotificationDescriptor<Audience, Payload>;
|
|
4
|
+
|
|
5
|
+
export declare interface DefineNotificationConfig<Audience, Payload> {
|
|
6
|
+
/** Stable name (`order.shipped`); also the default category. */
|
|
7
|
+
readonly name: string;
|
|
8
|
+
/** The notifications category preferences are keyed by. Default: `name`. */
|
|
9
|
+
readonly category?: string;
|
|
10
|
+
readonly audience: Schema.Schema<Audience, any>;
|
|
11
|
+
readonly payload: Schema.Schema<Payload, any>;
|
|
12
|
+
/** PURE: payload + locale → what the recipient sees. No IO. */
|
|
13
|
+
readonly render: (payload: Payload, ctx: RenderContext) => RenderedNotification;
|
|
14
|
+
/** Restrict to these channels (ids); default: every configured channel,
|
|
15
|
+
* subject to the recipient's preferences. */
|
|
16
|
+
readonly channels?: ReadonlyArray<string>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export declare interface NotificationDescriptor<Audience = unknown, Payload = unknown> {
|
|
20
|
+
readonly _tag: 'VoltroNotification';
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly category: string;
|
|
23
|
+
readonly audience: Schema.Schema<Audience, any>;
|
|
24
|
+
readonly payload: Schema.Schema<Payload, any>;
|
|
25
|
+
readonly render: (payload: Payload, ctx: RenderContext) => RenderedNotification;
|
|
26
|
+
readonly channels?: ReadonlyArray<string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export declare interface RenderContext {
|
|
30
|
+
/** The recipient's locale (from the device row, the user, or the app's default). */
|
|
31
|
+
readonly locale: string;
|
|
32
|
+
readonly recipientId: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export declare interface RenderedNotification {
|
|
36
|
+
readonly title: string;
|
|
37
|
+
readonly body: string;
|
|
38
|
+
/** Carried to every channel; `deepLink` is what a tap opens (web push, the
|
|
39
|
+
* mobile app's link table, the desktop shell). */
|
|
40
|
+
readonly data?: Readonly<Record<string, unknown>> & {
|
|
41
|
+
readonly deepLink?: string;
|
|
42
|
+
};
|
|
43
|
+
/** Rich push: an image url the push shows (Expo `richContent`, FCM
|
|
44
|
+
* `notification.image`, APNs through a mutable-content extension). */
|
|
45
|
+
readonly image?: string;
|
|
46
|
+
/** Rich push: action buttons. Each `id` comes back as the tapped action. */
|
|
47
|
+
readonly actions?: ReadonlyArray<{
|
|
48
|
+
readonly id: string;
|
|
49
|
+
readonly title: string;
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { }
|
package/dist/define.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/define.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (!e.name || !/^[a-z][a-zA-Z0-9._-]*$/.test(e.name)) throw Error(`defineNotification: name must be a dotted identifier (got ${JSON.stringify(e.name)})`);
|
|
4
|
+
return {
|
|
5
|
+
_tag: "VoltroNotification",
|
|
6
|
+
name: e.name,
|
|
7
|
+
category: e.category ?? e.name,
|
|
8
|
+
audience: e.audience,
|
|
9
|
+
payload: e.payload,
|
|
10
|
+
render: e.render,
|
|
11
|
+
...e.channels === void 0 ? {} : { channels: e.channels }
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { e as defineNotification };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,49 @@ import { Schema } from 'effect';
|
|
|
6
6
|
import { Table } from '@voltro/database';
|
|
7
7
|
import { VoltroPlugin } from '@voltro/protocol';
|
|
8
8
|
|
|
9
|
+
export declare const APNS_HOSTS: {
|
|
10
|
+
readonly production: "https://api.push.apple.com";
|
|
11
|
+
readonly sandbox: "https://api.sandbox.push.apple.com";
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** Reasons Apple answers that mean "this token will never work again". */
|
|
15
|
+
export declare const APNS_TOKEN_REJECTIONS: ReadonlySet<string>;
|
|
16
|
+
|
|
17
|
+
/** The APNs request body from the channel's payload. */
|
|
18
|
+
export declare const apnsBody: (payload: PushPayload) => Record<string, unknown>;
|
|
19
|
+
|
|
20
|
+
/** The ES256 provider token — `{ alg, kid }` . `{ iss, iat }` . signature. */
|
|
21
|
+
export declare const apnsProviderToken: (options: Pick<ApnsTransportOptions, "keyId" | "teamId" | "privateKey">, issuedAtMs: number) => string;
|
|
22
|
+
|
|
23
|
+
/** One HTTP/2 POST. Default: `node:http2`, one session per send. */
|
|
24
|
+
export declare type ApnsRequest = (input: ApnsRequestInput) => Promise<ApnsResponse>;
|
|
25
|
+
|
|
26
|
+
export declare interface ApnsRequestInput {
|
|
27
|
+
readonly url: string;
|
|
28
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
29
|
+
readonly body: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export declare interface ApnsResponse {
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly body: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export declare const apnsTransport: (options: ApnsTransportOptions) => ((payload: PushPayload) => Promise<void>);
|
|
38
|
+
|
|
39
|
+
export declare interface ApnsTransportOptions {
|
|
40
|
+
/** The 10-character key id from the Apple developer portal. */
|
|
41
|
+
readonly keyId: string;
|
|
42
|
+
readonly teamId: string;
|
|
43
|
+
/** The .p8 file's contents (a PEM-encoded private key, as Apple issues it). */
|
|
44
|
+
readonly privateKey: string;
|
|
45
|
+
/** The app's bundle id — the `apns-topic`. */
|
|
46
|
+
readonly bundleId: string;
|
|
47
|
+
readonly environment?: 'production' | 'sandbox';
|
|
48
|
+
readonly request?: ApnsRequest;
|
|
49
|
+
readonly now?: () => number;
|
|
50
|
+
}
|
|
51
|
+
|
|
9
52
|
export declare interface BroadcastResult {
|
|
10
53
|
/** How many topic subscribers the broadcast fanned out to. */
|
|
11
54
|
readonly recipients: number;
|
|
@@ -85,6 +128,22 @@ export declare const decryptWebPushPayload: (body: Buffer, receiver: {
|
|
|
85
128
|
readonly authSecret: Buffer;
|
|
86
129
|
}) => Buffer;
|
|
87
130
|
|
|
131
|
+
export declare const defineNotification: <Audience, Payload>(config: DefineNotificationConfig<Audience, Payload>) => NotificationDescriptor<Audience, Payload>;
|
|
132
|
+
|
|
133
|
+
export declare interface DefineNotificationConfig<Audience, Payload> {
|
|
134
|
+
/** Stable name (`order.shipped`); also the default category. */
|
|
135
|
+
readonly name: string;
|
|
136
|
+
/** The notifications category preferences are keyed by. Default: `name`. */
|
|
137
|
+
readonly category?: string;
|
|
138
|
+
readonly audience: Schema.Schema<Audience, any>;
|
|
139
|
+
readonly payload: Schema.Schema<Payload, any>;
|
|
140
|
+
/** PURE: payload + locale → what the recipient sees. No IO. */
|
|
141
|
+
readonly render: (payload: Payload, ctx: RenderContext) => RenderedNotification;
|
|
142
|
+
/** Restrict to these channels (ids); default: every configured channel,
|
|
143
|
+
* subject to the recipient's preferences. */
|
|
144
|
+
readonly channels?: ReadonlyArray<string>;
|
|
145
|
+
}
|
|
146
|
+
|
|
88
147
|
export declare const deliveriesTable: Table<"_voltro_notification_deliveries", FieldDefinitions<{
|
|
89
148
|
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
90
149
|
readonly recipient: ColumnBuilder<string, "text", boolean>;
|
|
@@ -118,6 +177,14 @@ export declare interface DeliveryRecord {
|
|
|
118
177
|
readonly clickedAt?: string | null;
|
|
119
178
|
}
|
|
120
179
|
|
|
180
|
+
export declare interface DurableNotificationPayload {
|
|
181
|
+
readonly notification: string;
|
|
182
|
+
readonly recipientId: string;
|
|
183
|
+
readonly locale: string;
|
|
184
|
+
readonly payload: unknown;
|
|
185
|
+
readonly tenantId: string | null;
|
|
186
|
+
}
|
|
187
|
+
|
|
121
188
|
/** Email channel — the app supplies the sender (compose with
|
|
122
189
|
* `@voltro/plugin-mail`'s `MailService.send`). Keeps the mail dep out of here. */
|
|
123
190
|
export declare const emailChannel: (send: (msg: {
|
|
@@ -156,10 +223,72 @@ declare interface EndpointDelivery {
|
|
|
156
223
|
|
|
157
224
|
export declare const endpointHashOf: (endpoint: string) => string;
|
|
158
225
|
|
|
226
|
+
export declare interface EnqueuedNotification {
|
|
227
|
+
readonly recipientId: string;
|
|
228
|
+
readonly locale: string;
|
|
229
|
+
readonly outboxId: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** One outbox row per recipient; rendering happens at delivery, in the recipient's locale as known NOW. */
|
|
233
|
+
export declare const enqueueNotification: <Audience, Payload>(outbox: OutboxEnqueue, descriptor: NotificationDescriptor<Audience, Payload>, options: EnqueueNotificationOptions<Audience, Payload>) => Promise<ReadonlyArray<EnqueuedNotification>>;
|
|
234
|
+
|
|
235
|
+
export declare interface EnqueueNotificationOptions<Audience, Payload> extends SendNotificationOptions<Audience, Payload> {
|
|
236
|
+
/** Dedupes per recipient as `<notification>:<recipient>:<key>` — a retried mutation enqueues once. */
|
|
237
|
+
readonly idempotencyKey?: string;
|
|
238
|
+
readonly maxAttempts?: number;
|
|
239
|
+
readonly delayMs?: number;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export declare const EXPO_PUSH_ENDPOINT = "https://exp.host/--/api/v2/push/send";
|
|
243
|
+
|
|
244
|
+
export declare const expoPushTransport: (options?: ExpoPushTransportOptions) => ((payload: PushPayload) => Promise<void>);
|
|
245
|
+
|
|
246
|
+
export declare interface ExpoPushTransportOptions {
|
|
247
|
+
/** Expo access token (`EXPO_ACCESS_TOKEN`); required for enhanced security
|
|
248
|
+
* push, optional otherwise. Never logged. */
|
|
249
|
+
readonly accessToken?: string;
|
|
250
|
+
readonly fetch?: typeof fetch;
|
|
251
|
+
readonly endpoint?: string;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export declare const FCM_SCOPE = "https://www.googleapis.com/auth/firebase.messaging";
|
|
255
|
+
|
|
256
|
+
/** FCM error codes that mean the token is gone for good. */
|
|
257
|
+
export declare const FCM_TOKEN_REJECTIONS: ReadonlySet<string>;
|
|
258
|
+
|
|
259
|
+
/** The RS256 JWT assertion Google's token endpoint exchanges for an access token. */
|
|
260
|
+
export declare const fcmAssertion: (sa: FcmServiceAccount, issuedAtMs: number) => string;
|
|
261
|
+
|
|
262
|
+
/** The HTTP v1 message from the channel's payload — data values must be strings. */
|
|
263
|
+
export declare const fcmMessage: (payload: PushPayload) => Record<string, unknown>;
|
|
264
|
+
|
|
265
|
+
export declare const fcmSendEndpoint: (projectId: string) => string;
|
|
266
|
+
|
|
267
|
+
export declare interface FcmServiceAccount {
|
|
268
|
+
readonly project_id: string;
|
|
269
|
+
readonly client_email: string;
|
|
270
|
+
/** The service account's PEM-encoded private key, as Google issues it. */
|
|
271
|
+
readonly private_key: string;
|
|
272
|
+
readonly token_uri?: string;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export declare const fcmTransport: (options: FcmTransportOptions) => ((payload: PushPayload) => Promise<void>);
|
|
276
|
+
|
|
277
|
+
export declare interface FcmTransportOptions {
|
|
278
|
+
/** The service-account JSON, parsed or as the string Google issued. */
|
|
279
|
+
readonly serviceAccount: FcmServiceAccount | string;
|
|
280
|
+
readonly fetch?: typeof fetch;
|
|
281
|
+
readonly now?: () => number;
|
|
282
|
+
/** Override the send endpoint (tests). */
|
|
283
|
+
readonly endpoint?: string;
|
|
284
|
+
}
|
|
285
|
+
|
|
159
286
|
/** Mint a fresh P-256 private scalar, base64url — what the dev secret mint and
|
|
160
287
|
* `voltro secret generate` produce for `VOLTRO_VAPID_PRIVATE_KEY`. */
|
|
161
288
|
export declare const generateVapidPrivateKey: () => string;
|
|
162
289
|
|
|
290
|
+
export declare const GOOGLE_TOKEN_URI = "https://oauth2.googleapis.com/token";
|
|
291
|
+
|
|
163
292
|
/** One notification held for later delivery — a digest window rollup or a
|
|
164
293
|
* quiet-hours deferral. `flushAt` is the ISO instant it becomes deliverable
|
|
165
294
|
* (the window boundary / the digest flush tick). `kind` marks WHY it was held
|
|
@@ -225,6 +354,8 @@ export declare const inboxTable: Table<"_voltro_notification_inbox", FieldDefini
|
|
|
225
354
|
* midnight, e.g. 22:00→08:00). An empty window (start === end) is never active. */
|
|
226
355
|
export declare const inQuietHours: (qh: QuietHours, at: Date) => boolean;
|
|
227
356
|
|
|
357
|
+
export declare const isExpoPushToken: (token: string) => boolean;
|
|
358
|
+
|
|
228
359
|
/**
|
|
229
360
|
* WHO an inbox belongs to.
|
|
230
361
|
*
|
|
@@ -276,6 +407,38 @@ export declare const memoryPushSubscriptionStore: () => PushSubscriptionStore;
|
|
|
276
407
|
* date-math library is needed; an unknown zone falls back to UTC. */
|
|
277
408
|
export declare const minuteOfDayInZone: (at: Date, tz: string) => number;
|
|
278
409
|
|
|
410
|
+
export declare const NOTIFICATION_SEND_EFFECT = "voltro.notification.send";
|
|
411
|
+
|
|
412
|
+
export declare interface NotificationDescriptor<Audience = unknown, Payload = unknown> {
|
|
413
|
+
readonly _tag: 'VoltroNotification';
|
|
414
|
+
readonly name: string;
|
|
415
|
+
readonly category: string;
|
|
416
|
+
readonly audience: Schema.Schema<Audience, any>;
|
|
417
|
+
readonly payload: Schema.Schema<Payload, any>;
|
|
418
|
+
readonly render: (payload: Payload, ctx: RenderContext) => RenderedNotification;
|
|
419
|
+
readonly channels?: ReadonlyArray<string>;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** The `*.outbox.ts` handler: render the row's descriptor for its recipient and send. */
|
|
423
|
+
export declare const notificationOutboxHandler: (options: NotificationOutboxHandlerOptions) => {
|
|
424
|
+
readonly effect: typeof NOTIFICATION_SEND_EFFECT;
|
|
425
|
+
readonly maxAttempts: number;
|
|
426
|
+
readonly handler: (ctx: {
|
|
427
|
+
readonly payload: Record<string, unknown>;
|
|
428
|
+
}) => Promise<SendResult>;
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
export declare interface NotificationOutboxHandlerOptions {
|
|
432
|
+
/** The notification service of THIS process; `undefined` fails the attempt loudly rather than dropping the row. */
|
|
433
|
+
readonly service: () => {
|
|
434
|
+
readonly send: (input: SendInput) => Promise<SendResult>;
|
|
435
|
+
} | undefined;
|
|
436
|
+
/** Every descriptor a row may name — an unknown name is a dead row, not a silent skip. */
|
|
437
|
+
readonly notifications: ReadonlyArray<NotificationDescriptor<any, any>>;
|
|
438
|
+
/** Default 5. */
|
|
439
|
+
readonly maxAttempts?: number;
|
|
440
|
+
}
|
|
441
|
+
|
|
279
442
|
export declare class NotificationService extends NotificationService_base {
|
|
280
443
|
}
|
|
281
444
|
|
|
@@ -475,6 +638,17 @@ export declare interface NotificationStore {
|
|
|
475
638
|
readonly clearHeld: (ids: ReadonlyArray<string>) => Promise<void>;
|
|
476
639
|
}
|
|
477
640
|
|
|
641
|
+
/** Structural: `ctx.outbox` from a handler, or `makeOutboxFacade`'s result. */
|
|
642
|
+
export declare interface OutboxEnqueue {
|
|
643
|
+
readonly enqueue: (effect: string, payload: Record<string, unknown>, options?: {
|
|
644
|
+
readonly idempotencyKey?: string;
|
|
645
|
+
readonly maxAttempts?: number;
|
|
646
|
+
readonly delayMs?: number;
|
|
647
|
+
}) => Promise<string>;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
export declare const parseServiceAccount: (value: FcmServiceAccount | string) => FcmServiceAccount;
|
|
651
|
+
|
|
478
652
|
export declare const preferencesTable: Table<"_voltro_notification_preferences", FieldDefinitions<{
|
|
479
653
|
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
480
654
|
readonly subjectId: ColumnBuilder<string, "text", boolean>;
|
|
@@ -518,6 +692,13 @@ export declare interface PushPayload {
|
|
|
518
692
|
readonly badge?: number;
|
|
519
693
|
/** The message `data` bag, forwarded as the push data/custom section. */
|
|
520
694
|
readonly data: Record<string, unknown>;
|
|
695
|
+
/** Rich push: from `msg.data.image` — an image url. */
|
|
696
|
+
readonly image?: string;
|
|
697
|
+
/** Rich push: from `msg.data.actions` — action buttons by id. */
|
|
698
|
+
readonly actions?: ReadonlyArray<{
|
|
699
|
+
readonly id: string;
|
|
700
|
+
readonly title: string;
|
|
701
|
+
}>;
|
|
521
702
|
}
|
|
522
703
|
|
|
523
704
|
/** A browser push subscription's crypto material, as `PushSubscription.toJSON()`
|
|
@@ -614,6 +795,30 @@ export declare const quietHoursTable: Table<"_voltro_notification_quiet_hours",
|
|
|
614
795
|
readonly policy: ColumnBuilder<string, "text", true>;
|
|
615
796
|
}>, true, never>;
|
|
616
797
|
|
|
798
|
+
export declare interface RenderContext {
|
|
799
|
+
/** The recipient's locale (from the device row, the user, or the app's default). */
|
|
800
|
+
readonly locale: string;
|
|
801
|
+
readonly recipientId: string;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
export declare interface RenderedNotification {
|
|
805
|
+
readonly title: string;
|
|
806
|
+
readonly body: string;
|
|
807
|
+
/** Carried to every channel; `deepLink` is what a tap opens (web push, the
|
|
808
|
+
* mobile app's link table, the desktop shell). */
|
|
809
|
+
readonly data?: Readonly<Record<string, unknown>> & {
|
|
810
|
+
readonly deepLink?: string;
|
|
811
|
+
};
|
|
812
|
+
/** Rich push: an image url the push shows (Expo `richContent`, FCM
|
|
813
|
+
* `notification.image`, APNs through a mutable-content extension). */
|
|
814
|
+
readonly image?: string;
|
|
815
|
+
/** Rich push: action buttons. Each `id` comes back as the tapped action. */
|
|
816
|
+
readonly actions?: ReadonlyArray<{
|
|
817
|
+
readonly id: string;
|
|
818
|
+
readonly title: string;
|
|
819
|
+
}>;
|
|
820
|
+
}
|
|
821
|
+
|
|
617
822
|
/** Test seam. */
|
|
618
823
|
export declare const resetWebPushStoreForTest: () => void;
|
|
619
824
|
|
|
@@ -624,6 +829,15 @@ export declare const resetWebPushStoreForTest: () => void;
|
|
|
624
829
|
*/
|
|
625
830
|
export declare const resolveChannels: (configured: ReadonlyArray<string>, category: string, requested: ReadonlyArray<string> | undefined, prefs: ReadonlyArray<ChannelPreference>, subjectId: string) => ReadonlyArray<string>;
|
|
626
831
|
|
|
832
|
+
/** Rich-push fields as a message's `data` carries them, or nothing. */
|
|
833
|
+
export declare const richPushOf: (data: Readonly<Record<string, unknown>> | undefined) => {
|
|
834
|
+
readonly image?: string;
|
|
835
|
+
readonly actions?: ReadonlyArray<{
|
|
836
|
+
readonly id: string;
|
|
837
|
+
readonly title: string;
|
|
838
|
+
}>;
|
|
839
|
+
};
|
|
840
|
+
|
|
627
841
|
/** What a caller asks to send. `channels` overrides the default routing. */
|
|
628
842
|
export declare interface SendInput {
|
|
629
843
|
readonly to: string;
|
|
@@ -635,6 +849,21 @@ export declare interface SendInput {
|
|
|
635
849
|
readonly tenantId?: string | null;
|
|
636
850
|
}
|
|
637
851
|
|
|
852
|
+
export declare const sendNotification: <Audience, Payload>(service: {
|
|
853
|
+
readonly send: (input: SendInput) => Promise<SendResult>;
|
|
854
|
+
}, descriptor: NotificationDescriptor<Audience, Payload>, options: SendNotificationOptions<Audience, Payload>) => Promise<ReadonlyArray<SentNotification>>;
|
|
855
|
+
|
|
856
|
+
export declare interface SendNotificationOptions<Audience, Payload> {
|
|
857
|
+
readonly audience: Audience;
|
|
858
|
+
readonly payload: Payload;
|
|
859
|
+
/** Audience → recipient subject ids. Default: `{ userId }` or `{ userIds }`. */
|
|
860
|
+
readonly recipients?: (audience: Audience) => Promise<ReadonlyArray<string>> | ReadonlyArray<string>;
|
|
861
|
+
/** The recipient's locale; null → `defaultLocale`. Default: none known. */
|
|
862
|
+
readonly localeFor?: (recipientId: string) => Promise<string | null>;
|
|
863
|
+
readonly defaultLocale?: string;
|
|
864
|
+
readonly tenantId?: string | null;
|
|
865
|
+
}
|
|
866
|
+
|
|
638
867
|
export declare interface SendResult {
|
|
639
868
|
readonly delivered: ReadonlyArray<string>;
|
|
640
869
|
readonly failed: ReadonlyArray<{
|
|
@@ -651,6 +880,12 @@ export declare interface SendResult {
|
|
|
651
880
|
/** POST one encrypted payload to one subscription's push service. */
|
|
652
881
|
export declare const sendWebPush: (target: WebPushTarget, payload: Buffer, options: WebPushSendOptions) => Promise<WebPushOutcome>;
|
|
653
882
|
|
|
883
|
+
export declare interface SentNotification {
|
|
884
|
+
readonly recipientId: string;
|
|
885
|
+
readonly locale: string;
|
|
886
|
+
readonly result: SendResult;
|
|
887
|
+
}
|
|
888
|
+
|
|
654
889
|
/** SMS via a generic REST sender (Twilio etc.) — app supplies the send fn. */
|
|
655
890
|
export declare const smsChannel: (send: (to: string, body: string) => Promise<void>) => Channel;
|
|
656
891
|
|