@robono/server 0.15.0 → 0.16.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 +6 -1
- package/NOTIFICATIONS.md +149 -0
- package/README.md +1 -1
- package/SBOM.spdx.json +8 -8
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/messaging-notification-postgres.d.ts +7 -0
- package/dist/messaging-notification-postgres.d.ts.map +1 -0
- package/dist/messaging-notification-postgres.js +32 -0
- package/dist/messaging-notification-postgres.js.map +1 -0
- package/dist/messaging-notification-providers.d.ts +26 -0
- package/dist/messaging-notification-providers.d.ts.map +1 -0
- package/dist/messaging-notification-providers.js +107 -0
- package/dist/messaging-notification-providers.js.map +1 -0
- package/dist/messaging-notifications.d.ts +66 -0
- package/dist/messaging-notifications.d.ts.map +1 -0
- package/dist/messaging-notifications.js +128 -0
- package/dist/messaging-notifications.js.map +1 -0
- package/dist/messaging.d.ts +7 -0
- package/dist/messaging.d.ts.map +1 -1
- package/dist/messaging.js +40 -2
- package/dist/messaging.js.map +1 -1
- package/dist/messenger.d.ts +53 -0
- package/dist/messenger.d.ts.map +1 -0
- package/dist/messenger.js +89 -0
- package/dist/messenger.js.map +1 -0
- package/package.json +4 -2
- package/sql/messaging-notifications.sql +41 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.0 — 2026-11-03
|
|
4
|
+
|
|
5
|
+
Add createRobonoMessengerServer for one authenticated messaging/media route, plus optional signed-event notification delivery using customer Apple/Google credentials and a durable private PostgreSQL queue. Announce supported group controls; keep actor identity server-verified and recheck customer permissions on search results. Include NOTIFICATIONS.md and the notification schema.
|
|
6
|
+
|
|
7
|
+
Requires matching service migrations 181–186 and coordinated package publication. Physical-device notification delivery is a separate acceptance check.
|
|
8
|
+
|
|
3
9
|
## 0.15.0
|
|
4
10
|
|
|
5
11
|
Add authenticated social previews, bounded private thumbnail requests, media replacement, per-user mute/delete-chat operations, and source-revision-aware translation caching.
|
|
@@ -25,7 +31,6 @@ Add network-triggered call countdowns, selected-recipient or all-participant war
|
|
|
25
31
|
Managed messaging and attachments, Maps and location sessions, movement consent, geofence rules, usage reporting and backend adapters. Existing Bridge and calling entry points remain available.
|
|
26
32
|
|
|
27
33
|
|
|
28
|
-
## Unreleased
|
|
29
34
|
|
|
30
35
|
- Group admission and relationship helpers, separate screen-sharing permission, group webhook verification/push routing, and an authenticated on-demand message transcription/translation adapter. Source content and private media are resolved server-side; access is rechecked after conversion.
|
|
31
36
|
|
package/NOTIFICATIONS.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Mobile message notifications
|
|
2
|
+
|
|
3
|
+
This installation uses your app's Apple/Google credentials. Robono's own app
|
|
4
|
+
credentials cannot send alerts for a customer's app. Chat in an open screen works
|
|
5
|
+
without push credentials; alerts with the app closed do not.
|
|
6
|
+
|
|
7
|
+
This guide requires `@robono/server` 0.16.0 and messaging packages 0.3.0,
|
|
8
|
+
with the matching Robono notification service. Older packages do not include
|
|
9
|
+
these helpers.
|
|
10
|
+
|
|
11
|
+
## Required once per app
|
|
12
|
+
|
|
13
|
+
| Platform | App configuration | Private server configuration |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| iPhone | Enable Push Notifications for the Bundle ID and provision the app accordingly. | Apple Team ID, APNs Key ID, `.p8` private key, Bundle ID, sandbox/production environment. |
|
|
16
|
+
| Android | Firebase project, Android application ID and `google-services.json`; configure the notifications plugin and rebuild. | Google project ID and service account authorized for Firebase Cloud Messaging. Prefer your existing secret manager; never bundle its private key in the app. |
|
|
17
|
+
|
|
18
|
+
Apple setup: https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns
|
|
19
|
+
|
|
20
|
+
Expo native-token setup: https://docs.expo.dev/push-notifications/sending-notifications-custom/
|
|
21
|
+
|
|
22
|
+
Google setup: https://firebase.google.com/docs/cloud-messaging/send/v1-api
|
|
23
|
+
|
|
24
|
+
The supplied Expo connector uses native APNs tokens on iPhone and FCM tokens on
|
|
25
|
+
Android. It does not use Expo Push tokens. Development iPhone builds use the APNs
|
|
26
|
+
sandbox; TestFlight and App Store builds use production. Keep test/live credentials,
|
|
27
|
+
notification scopes and webhook secrets separate.
|
|
28
|
+
|
|
29
|
+
## Server
|
|
30
|
+
|
|
31
|
+
Apply `@robono/server/sql/messaging-notifications.sql` to your **own PostgreSQL
|
|
32
|
+
database**, using the private server role. The tables have row security enabled and
|
|
33
|
+
no public grants. They must not be exposed through your browser/mobile database API.
|
|
34
|
+
Use your database's encrypted storage and normal backup policy. Device tokens are
|
|
35
|
+
private routing identifiers; the notification signing keys remain in server secrets.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import {createRobonoMessengerServer} from '@robono/server';
|
|
39
|
+
|
|
40
|
+
const messenger = createRobonoMessengerServer({
|
|
41
|
+
apiKey: process.env.ROBONO_API_KEY!,
|
|
42
|
+
allowedOrigins: ['https://your-company.com'],
|
|
43
|
+
authenticate: request => accounts.verifySession(request),
|
|
44
|
+
authorize: access => permissions.allowMessaging(access),
|
|
45
|
+
notifications: {
|
|
46
|
+
scope: 'your-app-production',
|
|
47
|
+
webhookSecret: process.env.ROBONO_WEBHOOK_SECRET!,
|
|
48
|
+
workerSecret: process.env.ROBONO_NOTIFICATION_WORKER_SECRET!,
|
|
49
|
+
query: (sql, values) => database.query(sql, values),
|
|
50
|
+
title: 'Your company',
|
|
51
|
+
apple: {
|
|
52
|
+
teamId: process.env.APNS_TEAM_ID!,
|
|
53
|
+
keyId: process.env.APNS_KEY_ID!,
|
|
54
|
+
privateKey: process.env.APNS_PRIVATE_KEY!,
|
|
55
|
+
bundleId: 'com.yourcompany.app',
|
|
56
|
+
sandbox: false,
|
|
57
|
+
},
|
|
58
|
+
google: {
|
|
59
|
+
projectId: process.env.FIREBASE_PROJECT_ID!,
|
|
60
|
+
clientEmail: process.env.FIREBASE_CLIENT_EMAIL!,
|
|
61
|
+
privateKey: process.env.FIREBASE_PRIVATE_KEY!,
|
|
62
|
+
},
|
|
63
|
+
authorizeRecipient: ({userId, conversationId}) =>
|
|
64
|
+
accounts.isActive(userId).then(active => active &&
|
|
65
|
+
permissions.mayReadConversation(userId, conversationId)),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Your framework mounts this single POST route at /api/robono.
|
|
70
|
+
export const POST = (request: Request) => messenger.handle(request);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`accounts`, `permissions`, and `database` are the customer's existing services.
|
|
74
|
+
Their checks must return a verified user ID or an explicit permission decision.
|
|
75
|
+
Do not replace them with unconditional approval. Omit `apple` or `google` only if
|
|
76
|
+
you do not support that platform. Missing credentials produce a registration error.
|
|
77
|
+
|
|
78
|
+
Set your Robono integration's signed event URL to:
|
|
79
|
+
`https://your-company.com/api/robono?service=events`.
|
|
80
|
+
If you already process other Robono events at one endpoint, verify/route those
|
|
81
|
+
events in your existing handler; this notification handler acknowledges unrelated
|
|
82
|
+
events without processing them and must not replace your cleanup/billing handler.
|
|
83
|
+
|
|
84
|
+
Schedule a POST to `/api/robono?service=notification-worker` at your chosen alert
|
|
85
|
+
interval, with `Authorization: Bearer <ROBONO_NOTIFICATION_WORKER_SECRET>`.
|
|
86
|
+
Use an independent random secret of at least 32 characters. A one-minute schedule
|
|
87
|
+
can delay an alert by a minute; use a continuously running worker for prompt alerts.
|
|
88
|
+
The worker processes up to 20 due jobs per invocation. Multiple workers safely
|
|
89
|
+
claim different jobs. Run the SQL file's cleanup statements daily.
|
|
90
|
+
|
|
91
|
+
The signed event is acknowledged only after it is durably queued. Every send
|
|
92
|
+
checks the current account, conversation, message, blocks, mute preference and
|
|
93
|
+
device ownership. Transient failures retry with backoff; permanent failures remain
|
|
94
|
+
in the private `jobs` table with a safe error code. Monitor failed jobs and credential
|
|
95
|
+
errors. Old alerts expire after 24 hours. Apple/Google acceptance does not mean the
|
|
96
|
+
phone displayed the alert; do not use it as a delivered/read receipt. Provider
|
|
97
|
+
timeouts can leave delivery uncertain; stable collapse identifiers reduce repeated
|
|
98
|
+
alerts, but exact-once OS notification display cannot be promised.
|
|
99
|
+
|
|
100
|
+
## Expo / React Native
|
|
101
|
+
|
|
102
|
+
Install `expo-notifications`, `expo-secure-store` and the package's existing
|
|
103
|
+
`expo-crypto` dependency using `npx expo install`. Configure the Expo notifications
|
|
104
|
+
plugin, then build the app; Expo Go is not the production verification target.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import {connectExpoMessagingNotifications} from
|
|
108
|
+
'@robono/messaging-react-native/expo-notifications';
|
|
109
|
+
|
|
110
|
+
const notifications = await connectExpoMessagingNotifications({
|
|
111
|
+
url: 'https://your-company.com/api/robono?service=notifications',
|
|
112
|
+
userId: signedInUser.id,
|
|
113
|
+
getAccessToken: () => accounts.accessToken(),
|
|
114
|
+
authorize: event => messagingClient.canOpenNotification(event),
|
|
115
|
+
open: event => navigation.openConversation(event.conversationId),
|
|
116
|
+
refresh: () => inbox.refresh(),
|
|
117
|
+
onError: error => showNotificationSetupError(error.message),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// When the person taps your "Enable notifications" button:
|
|
121
|
+
await notifications.enable();
|
|
122
|
+
|
|
123
|
+
// On logout, before destroying the session:
|
|
124
|
+
await Promise.allSettled([notifications.signOut(), messagingClient.signOut()]);
|
|
125
|
+
await accounts.signOut();
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Connect once per restored account. On navigation, keep the connector at app level;
|
|
129
|
+
do not recreate it for every chat. `dispose()` only removes listeners; use
|
|
130
|
+
`signOut()` to unregister the old account's device. If unregistering fails while
|
|
131
|
+
offline, clear local session data anyway and revoke that server session/account
|
|
132
|
+
access according to your existing sign-out policy. Alerts contain no message text,
|
|
133
|
+
media URLs or credentials. New registration moves the native token to the new
|
|
134
|
+
account, and notification opening always rechecks authorization.
|
|
135
|
+
|
|
136
|
+
The helper does not replace your app's global notification presentation handler
|
|
137
|
+
or interfere with calling notifications. Compose
|
|
138
|
+
`withMessagingNotificationPresentation` with that existing handler to suppress an
|
|
139
|
+
alert for the conversation already on screen. Set its active conversation to null
|
|
140
|
+
when the app is backgrounded. Browser background alerts are a separate capability;
|
|
141
|
+
these mobile credentials do not enable them.
|
|
142
|
+
|
|
143
|
+
## Ready means a device received an alert
|
|
144
|
+
|
|
145
|
+
Check both a foreground and background alert, a tap from a closed app, sign-out,
|
|
146
|
+
account switching, revoked chat access, muted conversations and token rotation.
|
|
147
|
+
Do not label notification setup complete merely because open-chat messages work
|
|
148
|
+
or Apple/Google accepted a request. The local automated tests use simulated provider
|
|
149
|
+
responses; they do not prove that a customer's credentials are provisioned correctly.
|
package/README.md
CHANGED
|
@@ -341,7 +341,7 @@ See [calling limits, billing rules and recovery](https://robono.com/docs#calling
|
|
|
341
341
|
for defaults, alert fields, revision conflicts, retry timing and active-call behavior.
|
|
342
342
|
|
|
343
343
|
|
|
344
|
-
### Sender message changes
|
|
344
|
+
### Sender message changes
|
|
345
345
|
|
|
346
346
|
The updated messaging adapter passes `edit`, `delete`, and `consume` through your
|
|
347
347
|
existing `authenticate` and `authorize` callbacks, always overriding caller-supplied
|
package/SBOM.spdx.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
"spdxVersion": "SPDX-2.3",
|
|
3
3
|
"dataLicense": "CC0-1.0",
|
|
4
4
|
"SPDXID": "SPDXRef-DOCUMENT",
|
|
5
|
-
"name": "@robono/server@0.
|
|
6
|
-
"documentNamespace": "http://spdx.org/spdxdocs/@robono%2fserver-0.
|
|
5
|
+
"name": "@robono/server@0.16.0",
|
|
6
|
+
"documentNamespace": "http://spdx.org/spdxdocs/@robono%2fserver-0.16.0-***",
|
|
7
7
|
"creationInfo": {
|
|
8
|
-
"created": "2026-11-
|
|
8
|
+
"created": "2026-11-03T12:40:11.342Z",
|
|
9
9
|
"creators": [
|
|
10
10
|
"Tool: npm/cli-11.6.2"
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
13
|
"documentDescribes": [
|
|
14
|
-
"SPDXRef-Package-robono.server-0.
|
|
14
|
+
"SPDXRef-Package-robono.server-0.16.0"
|
|
15
15
|
],
|
|
16
16
|
"packages": [
|
|
17
17
|
{
|
|
18
18
|
"name": "@robono/server",
|
|
19
|
-
"SPDXID": "SPDXRef-Package-robono.server-0.
|
|
20
|
-
"versionInfo": "0.
|
|
19
|
+
"SPDXID": "SPDXRef-Package-robono.server-0.16.0",
|
|
20
|
+
"versionInfo": "0.16.0",
|
|
21
21
|
"packageFileName": "",
|
|
22
22
|
"description": "Provider-neutral server SDK for the Robono Bridge API.",
|
|
23
23
|
"primaryPackagePurpose": "LIBRARY",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
{
|
|
30
30
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
31
31
|
"referenceType": "purl",
|
|
32
|
-
"referenceLocator": "pkg:npm/%40robono/server@0.
|
|
32
|
+
"referenceLocator": "pkg:npm/%40robono/server@0.16.0"
|
|
33
33
|
}
|
|
34
34
|
]
|
|
35
35
|
}
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"relationships": [
|
|
38
38
|
{
|
|
39
39
|
"spdxElementId": "SPDXRef-DOCUMENT",
|
|
40
|
-
"relatedSpdxElement": "SPDXRef-Package-robono.server-0.
|
|
40
|
+
"relatedSpdxElement": "SPDXRef-Package-robono.server-0.16.0",
|
|
41
41
|
"relationshipType": "DESCRIBES"
|
|
42
42
|
}
|
|
43
43
|
]
|
package/dist/index.d.ts
CHANGED
|
@@ -19,4 +19,9 @@ export { createMessagingTransformBackendAdapter } from './messaging-transforms.j
|
|
|
19
19
|
export { RobonoLocationBackend, createLocationBackendAdapter } from './location.js';
|
|
20
20
|
export type { LocationGrantInput } from './location.js';
|
|
21
21
|
export { RobonoLocationChatBackend } from './location-chat.js';
|
|
22
|
+
export { createRobonoMessengerServer } from './messenger.js';
|
|
23
|
+
export type { RobonoMessengerServerOptions, MessengerAccess } from './messenger.js';
|
|
24
|
+
export * from './messaging-notifications.js';
|
|
25
|
+
export * from './messaging-notification-providers.js';
|
|
26
|
+
export * from './messaging-notification-postgres.js';
|
|
22
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EAAE,2BAA2B,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrI,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC1D,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,yBAAyB,EACzB,WAAW,EACX,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtE,mBAAmB,YAAY,CAAC;AAEhC,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AACvF,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEpF,OAAO,EAAC,kCAAkC,EAAC,MAAM,sBAAsB,CAAC;AACxE,YAAY,EAAC,uBAAuB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,oBAAoB,EAAC,MAAM,sBAAsB,CAAC;AACtI,OAAO,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAC,sCAAsC,EAAC,MAAM,2BAA2B,CAAC;AAEjF,OAAO,EAAC,qBAAqB,EAAC,4BAA4B,EAAC,MAAM,eAAe,CAAC;AACjF,YAAY,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACtD,OAAO,EAAC,yBAAyB,EAAC,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EAAE,2BAA2B,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrI,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC1D,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,yBAAyB,EACzB,WAAW,EACX,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtE,mBAAmB,YAAY,CAAC;AAEhC,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AACvF,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEpF,OAAO,EAAC,kCAAkC,EAAC,MAAM,sBAAsB,CAAC;AACxE,YAAY,EAAC,uBAAuB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,oBAAoB,EAAC,MAAM,sBAAsB,CAAC;AACtI,OAAO,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAC,sCAAsC,EAAC,MAAM,2BAA2B,CAAC;AAEjF,OAAO,EAAC,qBAAqB,EAAC,4BAA4B,EAAC,MAAM,eAAe,CAAC;AACjF,YAAY,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACtD,OAAO,EAAC,yBAAyB,EAAC,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAC,2BAA2B,EAAC,MAAM,gBAAgB,CAAC;AAC3D,YAAY,EAAC,4BAA4B,EAAC,eAAe,EAAC,MAAM,gBAAgB,CAAC;AAEjF,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -11,4 +11,8 @@ export { RobonoManagedMedia } from './managed-media.js';
|
|
|
11
11
|
export { createMessagingTransformBackendAdapter } from './messaging-transforms.js';
|
|
12
12
|
export { RobonoLocationBackend, createLocationBackendAdapter } from './location.js';
|
|
13
13
|
export { RobonoLocationChatBackend } from './location-chat.js';
|
|
14
|
+
export { createRobonoMessengerServer } from './messenger.js';
|
|
15
|
+
export * from './messaging-notifications.js';
|
|
16
|
+
export * from './messaging-notification-providers.js';
|
|
17
|
+
export * from './messaging-notification-postgres.js';
|
|
14
18
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAM1D,OAAO,EACL,yBAAyB,EACzB,WAAW,EACX,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGtE,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAGvF,OAAO,EAAC,kCAAkC,EAAC,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAC,sCAAsC,EAAC,MAAM,2BAA2B,CAAC;AAEjF,OAAO,EAAC,qBAAqB,EAAC,4BAA4B,EAAC,MAAM,eAAe,CAAC;AAEjF,OAAO,EAAC,yBAAyB,EAAC,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAM1D,OAAO,EACL,yBAAyB,EACzB,WAAW,EACX,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGtE,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAGvF,OAAO,EAAC,kCAAkC,EAAC,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAC,sCAAsC,EAAC,MAAM,2BAA2B,CAAC;AAEjF,OAAO,EAAC,qBAAqB,EAAC,4BAA4B,EAAC,MAAM,eAAe,CAAC;AAEjF,OAAO,EAAC,yBAAyB,EAAC,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAC,2BAA2B,EAAC,MAAM,gBAAgB,CAAC;AAG3D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MessagingNotificationStore } from './messaging-notifications.js';
|
|
2
|
+
/** Compatible with pg Pool.query; keep this database connection exclusively on your server. */
|
|
3
|
+
export type MessagingNotificationQuery = (sql: string, parameters: unknown[]) => Promise<{
|
|
4
|
+
rows: Record<string, any>[];
|
|
5
|
+
}>;
|
|
6
|
+
export declare function createPostgresMessagingNotificationStore(query: MessagingNotificationQuery): MessagingNotificationStore;
|
|
7
|
+
//# sourceMappingURL=messaging-notification-postgres.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging-notification-postgres.d.ts","sourceRoot":"","sources":["../src/messaging-notification-postgres.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,0BAA0B,EAAsC,MAAM,8BAA8B,CAAC;AAElH,+FAA+F;AAC/F,MAAM,MAAM,0BAA0B,GAAC,CAAC,GAAG,EAAC,MAAM,EAAC,UAAU,EAAC,OAAO,EAAE,KAAG,OAAO,CAAC;IAAC,IAAI,EAAC,MAAM,CAAC,MAAM,EAAC,GAAG,CAAC,EAAE,CAAA;CAAC,CAAE,CAAC;AAChH,wBAAgB,wCAAwC,CAAC,KAAK,EAAC,0BAA0B,GAAE,0BAA0B,CA8BpH"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function createPostgresMessagingNotificationStore(query) {
|
|
2
|
+
return {
|
|
3
|
+
async register(scope, device) {
|
|
4
|
+
// Serialize registrations for this token; move it away from a previous signed-in account.
|
|
5
|
+
await query(`select robono_notifications.register_device($1,$2,$3,$4,$5)`, [scope, device.id, device.userId, device.provider, device.token]);
|
|
6
|
+
},
|
|
7
|
+
async remove(scope, userId, id, token) { await query('delete from robono_notifications.devices where scope=$1 and user_id=$2 and device_id=$3 and ($4::text is null or token=$4)', [scope, userId, id, token ?? null]); },
|
|
8
|
+
async enqueue(scope, event) {
|
|
9
|
+
await query(`insert into robono_notifications.jobs(scope,event_id,device_id,user_id,provider,token,event)
|
|
10
|
+
select $1,$2,device_id,user_id,provider,token,$4::jsonb from robono_notifications.devices
|
|
11
|
+
where scope=$1 and user_id=$3 and updated_at>now()-interval '90 days'
|
|
12
|
+
on conflict(scope,event_id,device_id,user_id) do nothing`, [scope, event.event_id, event.recipient_external_user_id, JSON.stringify(event)]);
|
|
13
|
+
},
|
|
14
|
+
async claim(scope, limit, lease) {
|
|
15
|
+
const result = await query(`with ready as (
|
|
16
|
+
select id from robono_notifications.jobs where scope=$1 and
|
|
17
|
+
((state='pending' and next_attempt_at<=now()) or (state='running' and lease_until<=now()))
|
|
18
|
+
order by next_attempt_at,id for update skip locked limit $2
|
|
19
|
+
) update robono_notifications.jobs j set state='running',lease=$3,lease_until=now()+interval '10 minutes',attempt=attempt+1
|
|
20
|
+
from ready where j.id=ready.id returning j.*`, [scope, limit, lease]);
|
|
21
|
+
return result.rows.map(row => ({ id: String(row.id), lease, event: row.event, attempt: row.attempt,
|
|
22
|
+
device: { id: row.device_id, userId: row.user_id, provider: row.provider, token: row.token } }));
|
|
23
|
+
},
|
|
24
|
+
async current(scope, device) { return (await query(`select 1 from robono_notifications.devices where scope=$1 and device_id=$2 and user_id=$3 and provider=$4 and token=$5 and updated_at>now()-interval '90 days'`, [scope, device.id, device.userId, device.provider, device.token])).rows.length === 1; },
|
|
25
|
+
async finish(scope, job, result) {
|
|
26
|
+
await query(`update robono_notifications.jobs set state=$4,next_attempt_at=coalesce($5,next_attempt_at),lease=null,lease_until=null,
|
|
27
|
+
last_code=$6,finished_at=case when $4 in ('sent','skipped','failed') then now() else null end
|
|
28
|
+
where scope=$1 and id=$2 and lease=$3 and state='running'`, [scope, job.id, job.lease, result.state === 'retry' ? 'pending' : result.state, result.retryAt ?? null, result.code ?? null]);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=messaging-notification-postgres.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging-notification-postgres.js","sourceRoot":"","sources":["../src/messaging-notification-postgres.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,wCAAwC,CAAC,KAAgC;IACvF,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAC,MAAM;YACzB,0FAA0F;YAC1F,MAAM,KAAK,CAAC,6DAA6D,EAAC,CAAC,KAAK,EAAC,MAAM,CAAC,EAAE,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,QAAQ,EAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1I,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE,EAAC,KAAK,IAAE,MAAM,KAAK,CAAC,4HAA4H,EAAC,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE,EAAC,KAAK,IAAE,IAAI,CAAC,CAAC,CAAC,CAAA,CAAC;QAC7M,KAAK,CAAC,OAAO,CAAC,KAAK,EAAC,KAAK;YACvB,MAAM,KAAK,CAAC;;;iEAG+C,EAAC,CAAC,KAAK,EAAC,KAAK,CAAC,QAAQ,EAAC,KAAK,CAAC,0BAA0B,EAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7I,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,KAAK,EAAC,KAAK,EAAC,KAAK;YAC3B,MAAM,MAAM,GAAC,MAAM,KAAK,CAAC;;;;;qDAKsB,EAAC,CAAC,KAAK,EAAC,KAAK,EAAC,KAAK,CAAC,CAAC,CAAC;YACrE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAA,EAAE,CAAA,CAAC,EAAC,EAAE,EAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAC,KAAK,EAAC,KAAK,EAAC,GAAG,CAAC,KAAK,EAAC,OAAO,EAAC,GAAG,CAAC,OAAO;gBACvF,MAAM,EAAC,EAAC,EAAE,EAAC,GAAG,CAAC,SAAS,EAAC,MAAM,EAAC,GAAG,CAAC,OAAO,EAAC,QAAQ,EAAC,GAAG,CAAC,QAAQ,EAAC,KAAK,EAAC,GAAG,CAAC,KAAK,EAAC,EAAC,CAAC,CAAuB,CAAC;QAChH,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAC,MAAM,IAAE,OAAO,CAAC,MAAM,KAAK,CAAC,gKAAgK,EAAC,CAAC,KAAK,EAAC,MAAM,CAAC,EAAE,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,QAAQ,EAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAG,CAAC,CAAC,CAAA,CAAC;QACjS,KAAK,CAAC,MAAM,CAAC,KAAK,EAAC,GAAG,EAAC,MAAM;YAC3B,MAAM,KAAK,CAAC;;kEAEgD,EAAC,CAAC,KAAK,EAAC,GAAG,CAAC,EAAE,EAAC,GAAG,CAAC,KAAK,EAAC,MAAM,CAAC,KAAK,KAAG,OAAO,CAAA,CAAC,CAAA,SAAS,CAAA,CAAC,CAAA,MAAM,CAAC,KAAK,EAAC,MAAM,CAAC,OAAO,IAAE,IAAI,EAAC,MAAM,CAAC,IAAI,IAAE,IAAI,CAAC,CAAC,CAAC;QAC9K,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { MessagingPushDevice, MessagingPushData, MessagingNotificationOptions } from './messaging-notifications.js';
|
|
2
|
+
export interface AppleMessagingCredentials {
|
|
3
|
+
teamId: string;
|
|
4
|
+
keyId: string;
|
|
5
|
+
privateKey: string;
|
|
6
|
+
bundleId: string;
|
|
7
|
+
sandbox?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface GoogleMessagingCredentials {
|
|
10
|
+
projectId: string;
|
|
11
|
+
clientEmail: string;
|
|
12
|
+
privateKey: string;
|
|
13
|
+
}
|
|
14
|
+
type SendResult = Awaited<ReturnType<MessagingNotificationOptions['send']>>;
|
|
15
|
+
/** Uses only fixed Apple/Google endpoints. Private keys never enter notification payloads. */
|
|
16
|
+
export declare function createMessagingPushSender(options: {
|
|
17
|
+
apple?: AppleMessagingCredentials;
|
|
18
|
+
google?: GoogleMessagingCredentials;
|
|
19
|
+
title?: string;
|
|
20
|
+
fetch?: typeof fetch;
|
|
21
|
+
}): {
|
|
22
|
+
providers: ("apns" | "fcm")[];
|
|
23
|
+
send(device: MessagingPushDevice, data: MessagingPushData): Promise<SendResult>;
|
|
24
|
+
};
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=messaging-notification-providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging-notification-providers.d.ts","sourceRoot":"","sources":["../src/messaging-notification-providers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,mBAAmB,EAAC,iBAAiB,EAAC,4BAA4B,EAAC,MAAM,8BAA8B,CAAC;AAErH,MAAM,WAAW,yBAAyB;IAAE,MAAM,EAAC,MAAM,CAAC;IAAA,KAAK,EAAC,MAAM,CAAC;IAAA,UAAU,EAAC,MAAM,CAAC;IAAA,QAAQ,EAAC,MAAM,CAAC;IAAA,OAAO,CAAC,EAAC,OAAO,CAAA;CAAC;AAC1H,MAAM,WAAW,0BAA0B;IAAE,SAAS,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC,MAAM,CAAC;IAAA,UAAU,EAAC,MAAM,CAAA;CAAC;AACnG,KAAK,UAAU,GAAC,OAAO,CAAC,UAAU,CAAC,4BAA4B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAS1E,8FAA8F;AAC9F,wBAAgB,yBAAyB,CAAC,OAAO,EAAC;IAAC,KAAK,CAAC,EAAC,yBAAyB,CAAC;IAAA,MAAM,CAAC,EAAC,0BAA0B,CAAC;IAAA,KAAK,CAAC,EAAC,MAAM,CAAC;IAAA,KAAK,CAAC,EAAC,OAAO,KAAK,CAAA;CAAC;;iBAsDrI,mBAAmB,QAAM,iBAAiB,GAAE,OAAO,CAAC,UAAU,CAAC;EAKlF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { createHash, createPrivateKey, sign } from 'node:crypto';
|
|
2
|
+
import { connect } from 'node:http2';
|
|
3
|
+
const b64 = (data) => Buffer.from(JSON.stringify(data)).toString('base64url');
|
|
4
|
+
function jwt(header, claims, key, algorithm, p1363 = false) {
|
|
5
|
+
const body = b64(header) + '.' + b64(claims);
|
|
6
|
+
const signature = sign(algorithm, Buffer.from(body), { key: createPrivateKey(key), ...(p1363 ? { dsaEncoding: 'ieee-p1363' } : {}) });
|
|
7
|
+
return body + '.' + signature.toString('base64url');
|
|
8
|
+
}
|
|
9
|
+
function collapse(data) { return createHash('sha256').update(data.accountScope + ':' + data.conversationId).digest('hex'); }
|
|
10
|
+
/** Uses only fixed Apple/Google endpoints. Private keys never enter notification payloads. */
|
|
11
|
+
export function createMessagingPushSender(options) {
|
|
12
|
+
const title = options.title?.trim() || 'New message';
|
|
13
|
+
if (title.length > 80)
|
|
14
|
+
throw Error('Use a notification title of 80 characters or fewer.');
|
|
15
|
+
const apple = options.apple, google = options.google;
|
|
16
|
+
if (apple && (!/^[A-Z\d]{10}$/.test(apple.teamId) || !/^[A-Z\d]{10}$/.test(apple.keyId) || !/^[-\w]+(?:\.[-\w]+)+$/.test(apple.bundleId)))
|
|
17
|
+
throw Error('Check the Apple Team ID, Key ID and app bundle ID.');
|
|
18
|
+
if (google && (!/^[a-z][a-z\d-]{4,61}[a-z\d]$/.test(google.projectId) || !/^[^\s@]+@[^\s@]+\.gserviceaccount\.com$/.test(google.clientEmail)))
|
|
19
|
+
throw Error('Check the Google project ID and service-account email.');
|
|
20
|
+
if (apple && (createPrivateKey(apple.privateKey).asymmetricKeyType !== 'ec' || createPrivateKey(apple.privateKey).asymmetricKeyDetails?.namedCurve !== 'prime256v1'))
|
|
21
|
+
throw Error('Use the Apple APNs .p8 signing key.');
|
|
22
|
+
if (google && createPrivateKey(google.privateKey).asymmetricKeyType !== 'rsa')
|
|
23
|
+
throw Error('Use the Google service-account private key.');
|
|
24
|
+
let appleToken = { value: '', expires: 0 }, googleToken = { value: '', expires: 0 }, googlePending;
|
|
25
|
+
const request = options.fetch ?? fetch;
|
|
26
|
+
async function googleAccess() {
|
|
27
|
+
if (googleToken.expires > Date.now())
|
|
28
|
+
return googleToken.value;
|
|
29
|
+
if (googlePending)
|
|
30
|
+
return googlePending;
|
|
31
|
+
googlePending = (async () => {
|
|
32
|
+
const now = Math.floor(Date.now() / 1000), assertion = jwt({ alg: 'RS256', typ: 'JWT' }, { iss: google.clientEmail, scope: 'https://www.googleapis.com/auth/firebase.messaging', aud: 'https://oauth2.googleapis.com/token', iat: now, exp: now + 3600 }, google.privateKey, 'RSA-SHA256');
|
|
33
|
+
const response = await request('https://oauth2.googleapis.com/token', { method: 'POST', redirect: 'error', signal: AbortSignal.timeout(15000), headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion }) });
|
|
34
|
+
const data = await response.json();
|
|
35
|
+
if (!response.ok || !data.access_token || typeof data.expires_in !== 'number')
|
|
36
|
+
throw Error('Google notification authentication failed.');
|
|
37
|
+
googleToken = { value: data.access_token, expires: Date.now() + Math.max(0, Math.min(data.expires_in, 3600) - 60) * 1000 };
|
|
38
|
+
return data.access_token;
|
|
39
|
+
})();
|
|
40
|
+
try {
|
|
41
|
+
return await googlePending;
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
googlePending = undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function sendApple(device, data) {
|
|
48
|
+
if (!apple)
|
|
49
|
+
return { accepted: false, retryable: false, code: 'apple_credentials_missing' };
|
|
50
|
+
if (!/^[a-f\d]{64,200}$/i.test(device.token))
|
|
51
|
+
return { accepted: false, invalidDevice: true, code: 'invalid_token' };
|
|
52
|
+
if (appleToken.expires <= Date.now())
|
|
53
|
+
appleToken = { value: jwt({ alg: 'ES256', kid: apple.keyId }, { iss: apple.teamId, iat: Math.floor(Date.now() / 1000) }, apple.privateKey, 'sha256', true), expires: Date.now() + 45 * 60000 };
|
|
54
|
+
const payload = JSON.stringify({ aps: { alert: { title, body: 'Open the app to read your message.' }, sound: 'default', 'thread-id': collapse(data) }, body: data });
|
|
55
|
+
return new Promise(resolve => {
|
|
56
|
+
const session = connect(apple.sandbox ? 'https://api.sandbox.push.apple.com' : 'https://api.push.apple.com');
|
|
57
|
+
let finished = false;
|
|
58
|
+
const finish = (result) => { if (finished)
|
|
59
|
+
return; finished = true; clearTimeout(timer); session.destroy(); resolve(result); };
|
|
60
|
+
const timer = setTimeout(() => finish({ accepted: false, retryable: true, code: 'apple_timeout' }), 15000);
|
|
61
|
+
session.on('error', () => finish({ accepted: false, retryable: true, code: 'apple_connection_failed' }));
|
|
62
|
+
const stream = session.request({ ':method': 'POST', ':path': '/3/device/' + device.token, authorization: 'bearer ' + appleToken.value, 'apns-topic': apple.bundleId, 'apns-push-type': 'alert', 'apns-priority': '10', 'apns-expiration': String(Math.floor(Date.now() / 1000) + 3600), 'apns-collapse-id': collapse(data), 'content-type': 'application/json' });
|
|
63
|
+
let status = 0, body = '';
|
|
64
|
+
stream.setEncoding('utf8');
|
|
65
|
+
stream.on('response', headers => { status = Number(headers[':status']); });
|
|
66
|
+
stream.on('data', chunk => { if (body.length < 8192)
|
|
67
|
+
body += chunk; });
|
|
68
|
+
stream.on('error', () => finish({ accepted: false, retryable: true, code: 'apple_connection_failed' }));
|
|
69
|
+
stream.on('end', () => {
|
|
70
|
+
let reason = '';
|
|
71
|
+
try {
|
|
72
|
+
reason = JSON.parse(body).reason;
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
if (status === 403)
|
|
76
|
+
appleToken = { value: '', expires: 0 };
|
|
77
|
+
finish({ accepted: status === 200, invalidDevice: status === 410 || reason === 'BadDeviceToken', retryable: reason === 'ExpiredProviderToken' || status === 429 || status >= 500, code: status === 200 ? 'accepted' : status === 403 ? 'apple_credentials_rejected' : 'apple_rejected' });
|
|
78
|
+
});
|
|
79
|
+
stream.end(payload);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async function sendGoogle(device, data) {
|
|
83
|
+
if (!google)
|
|
84
|
+
return { accepted: false, retryable: false, code: 'google_credentials_missing' };
|
|
85
|
+
const response = await request('https://fcm.googleapis.com/v1/projects/' + encodeURIComponent(google.projectId) + '/messages:send', {
|
|
86
|
+
method: 'POST', redirect: 'error', signal: AbortSignal.timeout(15000), headers: { authorization: 'Bearer ' + await googleAccess(), 'content-type': 'application/json' },
|
|
87
|
+
body: JSON.stringify({ message: { token: device.token, notification: { title, body: 'Open the app to read your message.' }, data,
|
|
88
|
+
android: { priority: 'high', ttl: '3600s', collapse_key: collapse(data), notification: { tag: collapse(data), channel_id: 'robono-messages' } } } }),
|
|
89
|
+
});
|
|
90
|
+
const result = await response.json().catch(() => null);
|
|
91
|
+
if (response.status === 401)
|
|
92
|
+
googleToken = { value: '', expires: 0 };
|
|
93
|
+
return { accepted: response.ok, invalidDevice: result?.error?.details?.some(detail => detail.errorCode === 'UNREGISTERED') ?? false,
|
|
94
|
+
retryable: response.status === 401 || response.status === 429 || response.status >= 500, code: response.ok ? 'accepted' : response.status === 401 || response.status === 403 ? 'google_credentials_rejected' : 'google_rejected' };
|
|
95
|
+
}
|
|
96
|
+
return { providers: [...(apple ? ['apns'] : []), ...(google ? ['fcm'] : [])],
|
|
97
|
+
async send(device, data) {
|
|
98
|
+
try {
|
|
99
|
+
return device.provider === 'apns' ? await sendApple(device, data) : await sendGoogle(device, data);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return { accepted: false, retryable: true, code: 'provider_unavailable' };
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=messaging-notification-providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging-notification-providers.js","sourceRoot":"","sources":["../src/messaging-notification-providers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { MessagingCreatedWebhookEvent } from './types.js';
|
|
2
|
+
export interface MessagingPushData {
|
|
3
|
+
event: 'robono.messaging';
|
|
4
|
+
eventId: string;
|
|
5
|
+
conversationId: string;
|
|
6
|
+
messageId: string;
|
|
7
|
+
accountScope: string;
|
|
8
|
+
}
|
|
9
|
+
export interface MessagingPushDevice {
|
|
10
|
+
id: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
provider: 'apns' | 'fcm';
|
|
13
|
+
token: string;
|
|
14
|
+
}
|
|
15
|
+
export interface MessagingPushJob {
|
|
16
|
+
id: string;
|
|
17
|
+
lease: string;
|
|
18
|
+
event: MessagingCreatedWebhookEvent;
|
|
19
|
+
device: MessagingPushDevice;
|
|
20
|
+
attempt: number;
|
|
21
|
+
}
|
|
22
|
+
export interface MessagingNotificationStore {
|
|
23
|
+
/** Register tokens only for the authenticated user; a token belongs to one account at a time. */
|
|
24
|
+
register(scope: string, device: MessagingPushDevice): Promise<void>;
|
|
25
|
+
remove(scope: string, userId: string, id: string, expectedToken?: string): Promise<void>;
|
|
26
|
+
/** Atomically snapshot this recipient's registered devices; duplicate events do not add jobs. */
|
|
27
|
+
enqueue(scope: string, event: MessagingCreatedWebhookEvent): Promise<void>;
|
|
28
|
+
claim(scope: string, limit: number, lease: string): Promise<MessagingPushJob[]>;
|
|
29
|
+
/** Recheck token ownership after taking a job and immediately before delivery. */
|
|
30
|
+
current(scope: string, device: MessagingPushDevice): Promise<boolean>;
|
|
31
|
+
finish(scope: string, job: MessagingPushJob, result: {
|
|
32
|
+
state: 'sent' | 'skipped' | 'retry' | 'failed';
|
|
33
|
+
retryAt?: Date;
|
|
34
|
+
code?: string;
|
|
35
|
+
}): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export interface MessagingNotificationOptions {
|
|
38
|
+
/** Separate scope and webhook secret for each customer integration and test/live environment. */
|
|
39
|
+
scope: string;
|
|
40
|
+
webhookSecret: string;
|
|
41
|
+
store: MessagingNotificationStore;
|
|
42
|
+
authenticate: (request: Request) => Promise<string | null>;
|
|
43
|
+
/** Required: current account status, conversation access, block/mute state, message existence. */
|
|
44
|
+
mayNotify: (event: MessagingCreatedWebhookEvent) => Promise<boolean>;
|
|
45
|
+
send: (device: MessagingPushDevice, data: MessagingPushData) => Promise<{
|
|
46
|
+
accepted: boolean;
|
|
47
|
+
invalidDevice?: boolean;
|
|
48
|
+
retryable?: boolean;
|
|
49
|
+
code?: string;
|
|
50
|
+
}>;
|
|
51
|
+
/** Only providers with configured server credentials can be registered. */
|
|
52
|
+
providers: readonly ('apns' | 'fcm')[];
|
|
53
|
+
}
|
|
54
|
+
export declare function messagingNotificationAccount(scope: string, userId: string): string;
|
|
55
|
+
/** Durable, content-free notifications. Apple/Google acceptance is not a delivery/read receipt. */
|
|
56
|
+
export declare function createMessagingNotifications(options: MessagingNotificationOptions): {
|
|
57
|
+
devices(request: Request): Promise<Response>;
|
|
58
|
+
webhook(request: Request): Promise<Response>;
|
|
59
|
+
runPending(limit?: number): Promise<{
|
|
60
|
+
sent: number;
|
|
61
|
+
skipped: number;
|
|
62
|
+
retried: number;
|
|
63
|
+
failed: number;
|
|
64
|
+
}>;
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=messaging-notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging-notifications.d.ts","sourceRoot":"","sources":["../src/messaging-notifications.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { verifyRobonoWebhook } from './webhooks.js';
|
|
3
|
+
function id(value, max = 200) { return typeof value === 'string' && value.length > 0 && value.length <= max && value.trim() === value && !/[\u0000-\u001f\u007f]/.test(value); }
|
|
4
|
+
const reply = (data, status = 200) => Response.json(data, { status, headers: { 'cache-control': 'no-store' } });
|
|
5
|
+
export function messagingNotificationAccount(scope, userId) { return createHash('sha256').update(JSON.stringify([scope, userId])).digest('hex'); }
|
|
6
|
+
/** Durable, content-free notifications. Apple/Google acceptance is not a delivery/read receipt. */
|
|
7
|
+
export function createMessagingNotifications(options) {
|
|
8
|
+
if (!id(options.scope) || !options.webhookSecret.trim())
|
|
9
|
+
throw Error('Set a unique notification scope and this integration’s webhook secret.');
|
|
10
|
+
const { scope, store } = options;
|
|
11
|
+
return {
|
|
12
|
+
async devices(request) {
|
|
13
|
+
if (request.method !== 'POST')
|
|
14
|
+
return reply({ error: { code: 'method_not_allowed' } }, 405);
|
|
15
|
+
try {
|
|
16
|
+
const userId = await options.authenticate(request);
|
|
17
|
+
if (!id(userId))
|
|
18
|
+
return reply({ error: { code: 'authentication_required' } }, 401);
|
|
19
|
+
const raw = await request.text();
|
|
20
|
+
if (raw.length > 8192)
|
|
21
|
+
return reply({ error: { code: 'request_too_large' } }, 413);
|
|
22
|
+
let body;
|
|
23
|
+
try {
|
|
24
|
+
body = JSON.parse(raw);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return reply({ error: { code: 'invalid_request' } }, 422);
|
|
28
|
+
}
|
|
29
|
+
const accountScope = messagingNotificationAccount(scope, userId);
|
|
30
|
+
if (body?.operation === 'notification-status')
|
|
31
|
+
return reply({ userId, accountScope, providers: options.providers });
|
|
32
|
+
if (body?.accountScope !== accountScope)
|
|
33
|
+
return reply({ error: { code: 'notification_account_changed' } }, 409);
|
|
34
|
+
if (!body || typeof body !== 'object' || !id(body.deviceId))
|
|
35
|
+
return reply({ error: { code: 'invalid_device' } }, 422);
|
|
36
|
+
if (body.operation === 'remove-device') {
|
|
37
|
+
await store.remove(scope, userId, body.deviceId);
|
|
38
|
+
return reply({ ok: true });
|
|
39
|
+
}
|
|
40
|
+
if (body.operation !== 'register-device' || !['apns', 'fcm'].includes(String(body.provider)) || !id(body.token, 4096))
|
|
41
|
+
return reply({ error: { code: 'invalid_device' } }, 422);
|
|
42
|
+
const provider = body.provider;
|
|
43
|
+
if (!options.providers.includes(provider))
|
|
44
|
+
return reply({ error: { code: 'notification_credentials_missing', message: provider === 'apns' ? 'Your app’s Apple notification credentials have not been connected.' : 'Your app’s Google notification credentials have not been connected.' } }, 409);
|
|
45
|
+
if (provider === 'apns' && !/^[a-f\d]{64,200}$/i.test(body.token))
|
|
46
|
+
return reply({ error: { code: 'invalid_device' } }, 422);
|
|
47
|
+
await store.register(scope, { id: body.deviceId, userId, provider, token: body.token });
|
|
48
|
+
return reply({ ok: true, accountScope: messagingNotificationAccount(scope, userId) });
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return reply({ error: { code: 'notifications_unavailable' } }, 503);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
async webhook(request) {
|
|
55
|
+
if (request.method !== 'POST')
|
|
56
|
+
return reply({ error: { code: 'method_not_allowed' } }, 405);
|
|
57
|
+
const raw = await request.text();
|
|
58
|
+
if (raw.length > 32768)
|
|
59
|
+
return reply({ error: { code: 'request_too_large' } }, 413);
|
|
60
|
+
let event;
|
|
61
|
+
try {
|
|
62
|
+
({ event } = await verifyRobonoWebhook(raw, request.headers, options.webhookSecret));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return reply({ error: { code: 'invalid_webhook' } }, 401);
|
|
66
|
+
}
|
|
67
|
+
if (event.event !== 'messaging.message_created')
|
|
68
|
+
return reply({ ignored: true });
|
|
69
|
+
// Do not acknowledge until the queue insert is durable. Delivery is retried by the worker.
|
|
70
|
+
try {
|
|
71
|
+
await store.enqueue(scope, event);
|
|
72
|
+
return reply({ queued: true }, 202);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return reply({ error: { code: 'notifications_unavailable' } }, 503);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
async runPending(limit = 20) {
|
|
79
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
80
|
+
throw Error('Use a notification batch size from 1 to 100.');
|
|
81
|
+
const result = { sent: 0, skipped: 0, retried: 0, failed: 0 };
|
|
82
|
+
// Small batches avoid unbounded fanout and provider rate spikes.
|
|
83
|
+
for (let index = 0; index < limit; index++) {
|
|
84
|
+
const [job] = await store.claim(scope, 1, randomUUID());
|
|
85
|
+
if (!job)
|
|
86
|
+
break;
|
|
87
|
+
try {
|
|
88
|
+
const event = job.event;
|
|
89
|
+
if (job.device.userId !== event.recipient_external_user_id || event.notification_muted === true ||
|
|
90
|
+
Date.parse(event.created_at) < Date.now() - 86400000 || !await options.mayNotify(event) || !await store.current(scope, job.device)) {
|
|
91
|
+
await store.finish(scope, job, { state: 'skipped' });
|
|
92
|
+
result.skipped++;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const data = { event: 'robono.messaging', eventId: event.event_id,
|
|
96
|
+
conversationId: event.conversation_id, messageId: event.message_id, accountScope: messagingNotificationAccount(scope, job.device.userId) };
|
|
97
|
+
const sent = await options.send(job.device, data);
|
|
98
|
+
if (sent.invalidDevice) {
|
|
99
|
+
await store.remove(scope, job.device.userId, job.device.id, job.device.token);
|
|
100
|
+
await store.finish(scope, job, { state: 'skipped', code: 'device_unregistered' });
|
|
101
|
+
result.skipped++;
|
|
102
|
+
}
|
|
103
|
+
else if (sent.accepted) {
|
|
104
|
+
await store.finish(scope, job, { state: 'sent' });
|
|
105
|
+
result.sent++;
|
|
106
|
+
}
|
|
107
|
+
else if (sent.retryable !== false && job.attempt < 8) {
|
|
108
|
+
await store.finish(scope, job, { state: 'retry', retryAt: new Date(Date.now() + Math.min(3600000, 15000 * 2 ** job.attempt)), code: sent.code ?? 'provider_unavailable' });
|
|
109
|
+
result.retried++;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
await store.finish(scope, job, { state: 'failed', code: sent.code ?? 'provider_rejected' });
|
|
113
|
+
result.failed++;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
await store.finish(scope, job, job.attempt < 8 ? { state: 'retry', retryAt: new Date(Date.now() + Math.min(3600000, 15000 * 2 ** job.attempt)), code: 'delivery_unavailable' } : { state: 'failed', code: 'delivery_unavailable' });
|
|
118
|
+
if (job.attempt < 8)
|
|
119
|
+
result.retried++;
|
|
120
|
+
else
|
|
121
|
+
result.failed++;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=messaging-notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging-notifications.js","sourceRoot":"","sources":["../src/messaging-notifications.ts"],"names":[],"mappings":"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"}
|
package/dist/messaging.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export declare class RobonoMessagingBackend {
|
|
|
40
40
|
revision: number;
|
|
41
41
|
allowed: boolean;
|
|
42
42
|
supergroup?: boolean;
|
|
43
|
+
ownerId?: string;
|
|
43
44
|
members: {
|
|
44
45
|
userId: string;
|
|
45
46
|
canSend: boolean;
|
|
@@ -56,6 +57,12 @@ export declare class RobonoMessagingBackend {
|
|
|
56
57
|
reviewerId: string;
|
|
57
58
|
}): Promise<any>;
|
|
58
59
|
settings(): Promise<any>;
|
|
60
|
+
/** Recheck the live recipient, message, membership, blocks and mute state before an alert. */
|
|
61
|
+
canNotify(input: {
|
|
62
|
+
userId: string;
|
|
63
|
+
conversationId: string;
|
|
64
|
+
messageId: string;
|
|
65
|
+
}): Promise<any>;
|
|
59
66
|
/** Erases this user's hosted conversations. Delete the corresponding private media in your own store too. */
|
|
60
67
|
eraseUser(userId: string): Promise<any>;
|
|
61
68
|
}
|
package/dist/messaging.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messaging.d.ts","sourceRoot":"","sources":["../src/messaging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AACD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAC,MAAM,CAAC;IAAC,cAAc,EAAC,MAAM,CAAC;IAAC,QAAQ,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,OAAO,GAAC,OAAO,CAAC;IAC5E,KAAK,EAAC,OAAO,CAAC;IAAC,MAAM,EAAC,MAAM,CAAC;IAAC,UAAU,EAAC,MAAM,GAAC,IAAI,CAAC;IAAC,WAAW,EAAC,MAAM,GAAC,IAAI,CAAC;IAC9E,WAAW,EAAC;QAAC,YAAY,EAAC,OAAO,CAAC;QAAA,YAAY,EAAC,OAAO,CAAC;QAAA,aAAa,EAAC,OAAO,CAAC;QAAA,aAAa,EAAC,OAAO,CAAA;KAAC,CAAC;CACrG;AACD,0FAA0F;AAC1F,qBAAa,sBAAsB;IAErB,OAAO,CAAC,OAAO;IAD3B,OAAO,CAAC,GAAG,CAAS;gBACA,OAAO,EAAE,uBAAuB;IAU9C,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAAE,OAAO,CAAC,EAAC;QAAC,MAAM,CAAC,EAAC,WAAW,CAAA;KAAC;IA+BpG,eAAe,CACb,KAAK,EAAE;QACL,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB;IAIH,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAC;QAAC,eAAe,EAAC,MAAM,CAAC;QAAA,IAAI,EAAC,MAAM,CAAC;QAAA,QAAQ,EAAC,MAAM,CAAC;QAAA,OAAO,EAAC,OAAO,CAAC;QAAA,UAAU,CAAC,EAAC,OAAO,CAAC;QAAA,OAAO,EAAC;YAAC,MAAM,EAAC,MAAM,CAAC;YAAA,OAAO,EAAC,OAAO,CAAC;YAAA,QAAQ,CAAC,EAAC,OAAO,CAAC,MAAM,CAAC,MAAM,GAAC,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,UAAU,GAAC,MAAM,GAAC,WAAW,EAAC,OAAO,CAAC,CAAC,CAAA;SAAC,EAAE,CAAA;KAAC;
|
|
1
|
+
{"version":3,"file":"messaging.d.ts","sourceRoot":"","sources":["../src/messaging.ts"],"names":[],"mappings":"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"}
|
package/dist/messaging.js
CHANGED
|
@@ -53,6 +53,21 @@ export class RobonoMessagingBackend {
|
|
|
53
53
|
settings() {
|
|
54
54
|
return this.request("settings");
|
|
55
55
|
}
|
|
56
|
+
/** Recheck the live recipient, message, membership, blocks and mute state before an alert. */
|
|
57
|
+
async canNotify(input) {
|
|
58
|
+
try {
|
|
59
|
+
const result = await this.request('list', { actorId: input.userId, conversationId: input.conversationId,
|
|
60
|
+
messageIds: [input.messageId], notificationMessageId: input.messageId });
|
|
61
|
+
if (typeof result.notificationAllowed !== 'boolean')
|
|
62
|
+
throw new RobonoError('Install the notification-access service update before enabling alerts.', { status: 503, code: 'notification_access_unavailable', retryable: true });
|
|
63
|
+
return result.notificationAllowed;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof RobonoError && [401, 403, 404].includes(error.status ?? 0))
|
|
67
|
+
return false;
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
56
71
|
/** Erases this user's hosted conversations. Delete the corresponding private media in your own store too. */
|
|
57
72
|
eraseUser(userId) {
|
|
58
73
|
return this.request("erase-user", { userId });
|
|
@@ -78,7 +93,7 @@ export function createMessagingBackendAdapter(options) {
|
|
|
78
93
|
return respond({ error: { code: "authentication_required" } }, 401);
|
|
79
94
|
}
|
|
80
95
|
const raw = await request.text();
|
|
81
|
-
if (raw.length >
|
|
96
|
+
if (raw.length > 900000) {
|
|
82
97
|
return respond({ error: { code: "request_too_large" } }, 413);
|
|
83
98
|
}
|
|
84
99
|
let body;
|
|
@@ -92,9 +107,15 @@ export function createMessagingBackendAdapter(options) {
|
|
|
92
107
|
return respond({ error: { code: "invalid_request" } }, 422);
|
|
93
108
|
}
|
|
94
109
|
const operation = String(body.operation ?? "");
|
|
95
|
-
if (
|
|
110
|
+
if (raw.length > 20000 && !["group-create", "group-update"].includes(operation))
|
|
111
|
+
return respond({ error: { code: "request_too_large" } }, 413);
|
|
112
|
+
if (!["settings", "send", "edit", "delete", "consume", "conversation-preferences", "conversation-delete", "send-call-message", "call-message-options", "list", "search", "social-preview", "conversations", "seen", "presence-update", "wait", "group-members", "group-create", "group-update", "group-leave", "read", "react", "pin", "vote", "close-poll", "inventory", "safety", "block", "unblock", "report"].includes(operation))
|
|
96
113
|
return respond({ error: { code: "operation_not_allowed" } }, 403);
|
|
97
114
|
const input = { ...body, actorId };
|
|
115
|
+
if (['list', 'conversations', 'group-members'].includes(operation)) {
|
|
116
|
+
input.groupControlsVersion = 1;
|
|
117
|
+
input.discussionVersion = 1;
|
|
118
|
+
}
|
|
98
119
|
delete input.operation;
|
|
99
120
|
if (!await options.authorize({ actorId, operation: operation === 'wait' || operation === 'social-preview' ? 'list' : operation, input, request })) {
|
|
100
121
|
return respond({ error: { code: "operation_not_allowed" } }, 403);
|
|
@@ -143,6 +164,23 @@ export function createMessagingBackendAdapter(options) {
|
|
|
143
164
|
// Check each preview against that customer's current list permission too.
|
|
144
165
|
const allowed = await Promise.all(result.conversations.map(async (row) => typeof row.id === 'string' && await options.authorize({ actorId, operation: 'list', input: { actorId, conversationId: row.id }, request })));
|
|
145
166
|
result.conversations = result.conversations.filter((_row, index) => allowed[index]);
|
|
167
|
+
if (input.query !== undefined) {
|
|
168
|
+
if (result.globalSearchAvailable !== true || !Array.isArray(result.searchResults) || result.searchResults.length > 50)
|
|
169
|
+
return respond({ error: { code: 'search_unavailable' } }, 503);
|
|
170
|
+
const decisions = new Map();
|
|
171
|
+
const searchAllowed = await Promise.all(result.searchResults.map((row) => {
|
|
172
|
+
const id = row.conversation?.id;
|
|
173
|
+
if (typeof id !== 'string' || row.message?.conversationId !== id)
|
|
174
|
+
return false;
|
|
175
|
+
let decision = decisions.get(id);
|
|
176
|
+
if (!decision) {
|
|
177
|
+
decision = options.authorize({ actorId, operation: 'list', input: { actorId, conversationId: id }, request });
|
|
178
|
+
decisions.set(id, decision);
|
|
179
|
+
}
|
|
180
|
+
return decision;
|
|
181
|
+
}));
|
|
182
|
+
result.searchResults = result.searchResults.filter((_row, index) => searchAllowed[index]);
|
|
183
|
+
}
|
|
146
184
|
if (await options.authenticate(request) !== actorId)
|
|
147
185
|
return respond({ error: { code: 'authentication_required' } }, 401);
|
|
148
186
|
}
|
package/dist/messaging.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messaging.js","sourceRoot":"","sources":["../src/messaging.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"messaging.js","sourceRoot":"","sources":["../src/messaging.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { RobonoMessagingBackend } from './messaging.js';
|
|
2
|
+
import { type MessagingPrivateStorage, type MessagingStoredMedia } from './messaging-media.js';
|
|
3
|
+
import { type AppleMessagingCredentials, type GoogleMessagingCredentials } from './messaging-notification-providers.js';
|
|
4
|
+
import { type MessagingNotificationQuery } from './messaging-notification-postgres.js';
|
|
5
|
+
export interface MessengerAccess {
|
|
6
|
+
actorId: string;
|
|
7
|
+
operation: string;
|
|
8
|
+
conversationId?: string;
|
|
9
|
+
uploadId?: string;
|
|
10
|
+
input: Record<string, unknown>;
|
|
11
|
+
request: Request;
|
|
12
|
+
}
|
|
13
|
+
export interface RobonoMessengerServerOptions {
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/** Validate your existing session, including expiry and account suspension. */
|
|
16
|
+
authenticate: (request: Request) => Promise<string | null>;
|
|
17
|
+
/** Your current app permissions; Robono independently enforces membership and feature access. */
|
|
18
|
+
authorize: (access: MessengerAccess) => Promise<boolean>;
|
|
19
|
+
/** Managed private attachments are the default. False deliberately disables them. */
|
|
20
|
+
storage?: (MessagingPrivateStorage & {
|
|
21
|
+
resolve: (input: {
|
|
22
|
+
actorId: string;
|
|
23
|
+
conversationId: string;
|
|
24
|
+
assetId: string;
|
|
25
|
+
}) => Promise<MessagingStoredMedia | null>;
|
|
26
|
+
}) | false;
|
|
27
|
+
messagingUrl?: string;
|
|
28
|
+
mediaUrl?: string;
|
|
29
|
+
fetch?: typeof fetch;
|
|
30
|
+
/** Same-origin cookie sessions must supply their exact allowed origin(s). */
|
|
31
|
+
allowedOrigins?: readonly string[];
|
|
32
|
+
notifications?: {
|
|
33
|
+
scope: string;
|
|
34
|
+
webhookSecret: string;
|
|
35
|
+
workerSecret: string;
|
|
36
|
+
query: MessagingNotificationQuery;
|
|
37
|
+
apple?: AppleMessagingCredentials;
|
|
38
|
+
google?: GoogleMessagingCredentials;
|
|
39
|
+
title?: string;
|
|
40
|
+
/** Current customer account and chat policy, even when the user is not signed in. */
|
|
41
|
+
authorizeRecipient: (input: {
|
|
42
|
+
userId: string;
|
|
43
|
+
conversationId: string;
|
|
44
|
+
}) => Promise<boolean>;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** One authenticated route for messaging and managed media. No account or permission bypass. */
|
|
48
|
+
export declare function createRobonoMessengerServer(options: RobonoMessengerServerOptions): {
|
|
49
|
+
/** Keep relationship and group synchronization on the server. */
|
|
50
|
+
robono: RobonoMessagingBackend;
|
|
51
|
+
handle(request: Request): Promise<Response>;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=messenger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messenger.d.ts","sourceRoot":"","sources":["../src/messenger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAgC,MAAM,gBAAgB,CAAC;AAErF,OAAO,EAAqC,KAAK,uBAAuB,EAAE,KAAK,oBAAoB,EAAC,MAAM,sBAAsB,CAAC;AAGjI,OAAO,EAA2B,KAAK,yBAAyB,EAAC,KAAK,0BAA0B,EAAC,MAAM,uCAAuC,CAAC;AAC/I,OAAO,EAA0C,KAAK,0BAA0B,EAAC,MAAM,sCAAsC,CAAC;AAE9H,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAC,MAAM,CAAC;IACf,SAAS,EAAC,MAAM,CAAC;IACjB,cAAc,CAAC,EAAC,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAC,MAAM,CAAC;IACjB,KAAK,EAAC,MAAM,CAAC,MAAM,EAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,EAAC,OAAO,CAAC;CACjB;AACD,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAC,MAAM,CAAC;IACd,+EAA+E;IAC/E,YAAY,EAAC,CAAC,OAAO,EAAC,OAAO,KAAG,OAAO,CAAC,MAAM,GAAC,IAAI,CAAC,CAAC;IACrD,iGAAiG;IACjG,SAAS,EAAC,CAAC,MAAM,EAAC,eAAe,KAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,qFAAqF;IACrF,OAAO,CAAC,EAAC,CAAC,uBAAuB,GAAG;QAAC,OAAO,EAAC,CAAC,KAAK,EAAC;YAAC,OAAO,EAAC,MAAM,CAAC;YAAA,cAAc,EAAC,MAAM,CAAC;YAAA,OAAO,EAAC,MAAM,CAAA;SAAC,KAAG,OAAO,CAAC,oBAAoB,GAAC,IAAI,CAAC,CAAA;KAAC,CAAC,GAAC,KAAK,CAAC;IACvJ,YAAY,CAAC,EAAC,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAC,MAAM,CAAC;IACjB,KAAK,CAAC,EAAC,OAAO,KAAK,CAAC;IACpB,6EAA6E;IAC7E,cAAc,CAAC,EAAC,SAAS,MAAM,EAAE,CAAC;IAClC,aAAa,CAAC,EAAC;QACb,KAAK,EAAC,MAAM,CAAC;QAAA,aAAa,EAAC,MAAM,CAAC;QAAA,YAAY,EAAC,MAAM,CAAC;QAAA,KAAK,EAAC,0BAA0B,CAAC;QACvF,KAAK,CAAC,EAAC,yBAAyB,CAAC;QAAA,MAAM,CAAC,EAAC,0BAA0B,CAAC;QAAA,KAAK,CAAC,EAAC,MAAM,CAAC;QAClF,qFAAqF;QACrF,kBAAkB,EAAC,CAAC,KAAK,EAAC;YAAC,MAAM,EAAC,MAAM,CAAC;YAAA,cAAc,EAAC,MAAM,CAAA;SAAC,KAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KACpF,CAAC;CACH;AAED,gGAAgG;AAChG,wBAAgB,2BAA2B,CAAC,OAAO,EAAC,4BAA4B;IAoC5E,iEAAiE;;oBAE5C,OAAO,GAAE,OAAO,CAAC,QAAQ,CAAC;EAyBlD"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { RobonoMessagingBackend, createMessagingBackendAdapter } from './messaging.js';
|
|
2
|
+
import { RobonoManagedMedia } from './managed-media.js';
|
|
3
|
+
import { createMessagingMediaBackendAdapter } from './messaging-media.js';
|
|
4
|
+
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
5
|
+
import { createMessagingNotifications } from './messaging-notifications.js';
|
|
6
|
+
import { createMessagingPushSender } from './messaging-notification-providers.js';
|
|
7
|
+
import { createPostgresMessagingNotificationStore } from './messaging-notification-postgres.js';
|
|
8
|
+
/** One authenticated route for messaging and managed media. No account or permission bypass. */
|
|
9
|
+
export function createRobonoMessengerServer(options) {
|
|
10
|
+
if (typeof options.authenticate !== 'function' || typeof options.authorize !== 'function')
|
|
11
|
+
throw Error('Connect your existing sign-in and permission checks. Both are required.');
|
|
12
|
+
const common = { apiKey: options.apiKey, ...(options.fetch ? { fetch: options.fetch } : {}) };
|
|
13
|
+
const robono = new RobonoMessagingBackend({ ...common, ...(options.messagingUrl ? { baseUrl: options.messagingUrl } : {}) });
|
|
14
|
+
const storage = options.storage === false ? null : options.storage ?? new RobonoManagedMedia({ ...common, ...(options.mediaUrl ? { baseUrl: options.mediaUrl } : {}) });
|
|
15
|
+
const origins = new Set((options.allowedOrigins ?? []).map(value => {
|
|
16
|
+
const url = new URL(value);
|
|
17
|
+
if (url.origin !== value || !['https:', 'http:'].includes(url.protocol))
|
|
18
|
+
throw Error('Use exact origins without a path.');
|
|
19
|
+
return url.origin;
|
|
20
|
+
}));
|
|
21
|
+
if (options.notifications && (!options.notifications.workerSecret || options.notifications.workerSecret.length < 32))
|
|
22
|
+
throw Error('Set a separate notification worker secret of at least 32 characters.');
|
|
23
|
+
const authenticate = async (request) => {
|
|
24
|
+
const actor = await options.authenticate(request);
|
|
25
|
+
return typeof actor === 'string' && actor.trim() === actor && actor.length > 0 && actor.length <= 200 && !/[\u0000-\u001f\u007f]/.test(actor) ? actor : null;
|
|
26
|
+
};
|
|
27
|
+
const push = options.notifications ? createMessagingPushSender({ ...options.notifications, ...(options.fetch ? { fetch: options.fetch } : {}) }) : null;
|
|
28
|
+
const notifications = options.notifications && push ? createMessagingNotifications({
|
|
29
|
+
scope: options.notifications.scope, webhookSecret: options.notifications.webhookSecret,
|
|
30
|
+
store: createPostgresMessagingNotificationStore(options.notifications.query), authenticate,
|
|
31
|
+
providers: push.providers, send: push.send,
|
|
32
|
+
mayNotify: async (event) => await options.notifications.authorizeRecipient({ userId: event.recipient_external_user_id, conversationId: event.conversation_id }) &&
|
|
33
|
+
await robono.canNotify({ userId: event.recipient_external_user_id, conversationId: event.conversation_id, messageId: event.message_id }),
|
|
34
|
+
}) : null;
|
|
35
|
+
const messages = createMessagingBackendAdapter({ robono, authenticate,
|
|
36
|
+
authorize: access => options.storage === false && ['send', 'send-call-message', 'edit'].includes(access.operation) && access.input.kind !== undefined && !['text', 'poll'].includes(String(access.input.kind)) ? Promise.resolve(false) : options.authorize({ ...access,
|
|
37
|
+
...(typeof access.input.conversationId === 'string' ? { conversationId: access.input.conversationId } : {}),
|
|
38
|
+
}), ...(storage ? { resolveMedia: (input) => storage.resolve(input) } : {}),
|
|
39
|
+
});
|
|
40
|
+
const media = storage ? createMessagingMediaBackendAdapter({ robono, storage, authenticate,
|
|
41
|
+
authorize: ({ actorId, operation, conversationId, uploadId, request }) => options.authorize({ actorId,
|
|
42
|
+
operation: 'media.' + operation, ...(conversationId ? { conversationId } : {}), ...(uploadId ? { uploadId } : {}),
|
|
43
|
+
input: { ...(conversationId ? { conversationId } : {}), ...(uploadId ? { uploadId } : {}) }, request,
|
|
44
|
+
}),
|
|
45
|
+
}) : null;
|
|
46
|
+
const failure = (code, status) => Response.json({ error: { code } }, { status, headers: { 'cache-control': 'no-store' } });
|
|
47
|
+
return {
|
|
48
|
+
/** Keep relationship and group synchronization on the server. */
|
|
49
|
+
robono,
|
|
50
|
+
async handle(request) {
|
|
51
|
+
if (request.method !== 'POST')
|
|
52
|
+
return failure('method_not_allowed', 405);
|
|
53
|
+
const route = new URL(request.url).searchParams.get('service') ?? 'messages';
|
|
54
|
+
if (route === 'events')
|
|
55
|
+
return notifications ? notifications.webhook(request) : failure('notifications_not_configured', 409);
|
|
56
|
+
if (route === 'notification-worker') {
|
|
57
|
+
if (!notifications)
|
|
58
|
+
return failure('notifications_not_configured', 409);
|
|
59
|
+
const expected = createHash('sha256').update('Bearer ' + options.notifications.workerSecret).digest();
|
|
60
|
+
const received = createHash('sha256').update(request.headers.get('authorization') ?? '').digest();
|
|
61
|
+
if (!timingSafeEqual(expected, received))
|
|
62
|
+
return failure('authentication_required', 401);
|
|
63
|
+
try {
|
|
64
|
+
return Response.json(await notifications.runPending(), { headers: { 'cache-control': 'no-store' } });
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return failure('notification_worker_unavailable', 503);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// The public route is safe with cookies too: require explicit trusted origins.
|
|
71
|
+
// Bearer-only native/server clients do not send an Origin header.
|
|
72
|
+
const origin = request.headers.get('origin');
|
|
73
|
+
if (origin && !origins.has(origin))
|
|
74
|
+
return failure('origin_not_allowed', 403);
|
|
75
|
+
if (!origin && !/^Bearer\s+\S+$/i.test(request.headers.get('authorization') ?? ''))
|
|
76
|
+
return failure('authentication_required', 401);
|
|
77
|
+
if (!request.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase().match(/^application\/json$/))
|
|
78
|
+
return failure('json_required', 415);
|
|
79
|
+
if (route === 'messages')
|
|
80
|
+
return messages(request);
|
|
81
|
+
if (route === 'media')
|
|
82
|
+
return media ? media(request) : failure('attachments_disabled', 403);
|
|
83
|
+
if (route === 'notifications')
|
|
84
|
+
return notifications ? notifications.devices(request) : failure('notifications_not_configured', 409);
|
|
85
|
+
return failure('service_not_found', 404);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=messenger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messenger.js","sourceRoot":"","sources":["../src/messenger.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robono/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Provider-neutral server SDK for the Robono Bridge API.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"robono",
|
|
@@ -46,7 +46,9 @@
|
|
|
46
46
|
"README.md",
|
|
47
47
|
"CHANGELOG.md",
|
|
48
48
|
"LICENSE",
|
|
49
|
-
"SBOM.spdx.json"
|
|
49
|
+
"SBOM.spdx.json",
|
|
50
|
+
"sql",
|
|
51
|
+
"NOTIFICATIONS.md"
|
|
50
52
|
],
|
|
51
53
|
"scripts": {
|
|
52
54
|
"build": "tsc -p tsconfig.json",
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- Apply to the CUSTOMER'S PostgreSQL database with the server's database role.
|
|
2
|
+
-- Do not expose this schema through a public/client database API.
|
|
3
|
+
begin;
|
|
4
|
+
create schema if not exists robono_notifications;
|
|
5
|
+
revoke all on schema robono_notifications from public;
|
|
6
|
+
create table if not exists robono_notifications.devices (
|
|
7
|
+
scope text not null,device_id text not null,user_id text not null,
|
|
8
|
+
provider text not null check(provider in ('apns','fcm')),token text not null,
|
|
9
|
+
updated_at timestamptz not null default now(),
|
|
10
|
+
token_hash bytea not null check(octet_length(token_hash)=32),
|
|
11
|
+
primary key(scope,device_id,user_id),unique(scope,provider,token_hash)
|
|
12
|
+
);
|
|
13
|
+
create table if not exists robono_notifications.jobs (
|
|
14
|
+
id bigint generated always as identity primary key,scope text not null,event_id text not null,
|
|
15
|
+
device_id text not null,user_id text not null,provider text not null,token text not null,event jsonb not null,
|
|
16
|
+
state text not null default 'pending' check(state in ('pending','running','sent','skipped','failed')),
|
|
17
|
+
attempt integer not null default 0,next_attempt_at timestamptz not null default now(),
|
|
18
|
+
lease text,lease_until timestamptz,last_code text,finished_at timestamptz,
|
|
19
|
+
unique(scope,event_id,device_id,user_id)
|
|
20
|
+
);
|
|
21
|
+
create index if not exists jobs_ready on robono_notifications.jobs(scope,state,next_attempt_at);
|
|
22
|
+
alter table robono_notifications.devices enable row level security;
|
|
23
|
+
alter table robono_notifications.jobs enable row level security;
|
|
24
|
+
revoke all on all tables in schema robono_notifications from public;
|
|
25
|
+
revoke all on all sequences in schema robono_notifications from public;
|
|
26
|
+
|
|
27
|
+
create or replace function robono_notifications.register_device(s text,d text,u text,p text,t text)
|
|
28
|
+
returns void language plpgsql set search_path=pg_catalog,robono_notifications as $$
|
|
29
|
+
begin
|
|
30
|
+
perform pg_advisory_xact_lock(hashtextextended('robono-notification:'||s,0));
|
|
31
|
+
delete from robono_notifications.devices where scope=s and provider=p and token=t and (device_id<>d or user_id<>u);
|
|
32
|
+
insert into robono_notifications.devices(scope,device_id,user_id,provider,token,token_hash)
|
|
33
|
+
values(s,d,u,p,t,sha256(convert_to(t,'UTF8'))) on conflict(scope,device_id,user_id) do update set provider=p,token=t,token_hash=excluded.token_hash,updated_at=now();
|
|
34
|
+
end $$;
|
|
35
|
+
revoke all on function robono_notifications.register_device(text,text,text,text,text) from public;
|
|
36
|
+
commit;
|
|
37
|
+
|
|
38
|
+
-- Retain completed job identities for seven days to deduplicate delivery retries.
|
|
39
|
+
-- Schedule this cleanup daily with the same private server role:
|
|
40
|
+
-- delete from robono_notifications.jobs where finished_at < now()-interval '7 days';
|
|
41
|
+
-- delete from robono_notifications.devices where updated_at < now()-interval '90 days';
|