@mpgd/adapter-devvit 0.14.11 → 0.14.12
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/dist/notifications-backend-client.d.ts +1 -1
- package/dist/notifications-backend-client.js +8 -4
- package/dist/notifications-client.d.ts +1 -1
- package/dist/notifications-client.js +8 -4
- package/dist/server/notifications-backend-bridge.d.ts +1 -1
- package/dist/server/notifications-backend-bridge.js +3 -2
- package/dist/server/notifications-bridge.d.ts +1 -1
- package/dist/server/notifications-bridge.js +2 -1
- package/dist/server/notifications-delivery.js +3 -2
- package/dist/server/redis-notification-store.js +6 -3
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type BridgeNotificationsBackendMethod } from '@mpgd/bridge';
|
|
2
2
|
import type { NotificationRuntimeBackend, NotificationRuntimeSession } from '@mpgd/platform/notifications-runtime';
|
|
3
3
|
/**
|
|
4
4
|
* The webview side of the notifications runtime's backend on Devvit
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isThrownInstance, readThrownField, } from '@mpgd/bridge';
|
|
1
2
|
import { assertBridgeNotificationsBackendPayload, assertBridgeNotificationsBackendResult, notificationsBackendBridgeHostCodes, readBridgeNotificationsHostCode, } from '@mpgd/bridge/notifications';
|
|
2
3
|
import { isNotificationErrorCode, NotificationError, notificationsProtocol, } from '@mpgd/platform/notifications';
|
|
3
4
|
/** The default `timeoutMs`: a request still unanswered after this is no longer awaited. */
|
|
@@ -279,12 +280,15 @@ export function createDevvitNotificationsBackendClient(input) {
|
|
|
279
280
|
};
|
|
280
281
|
}
|
|
281
282
|
function toNotificationError(method, error) {
|
|
282
|
-
if (error
|
|
283
|
+
if (isThrownInstance(error, NotificationError)) {
|
|
283
284
|
return error;
|
|
284
285
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
:
|
|
286
|
+
// Each field read once; one whose getter or Proxy trap throws counts as missing.
|
|
287
|
+
const failure = {
|
|
288
|
+
code: readThrownField(error, 'code'),
|
|
289
|
+
message: readThrownField(error, 'message'),
|
|
290
|
+
retryable: readThrownField(error, 'retryable'),
|
|
291
|
+
};
|
|
288
292
|
const message = typeof failure.message === 'string' ? failure.message : undefined;
|
|
289
293
|
if (backendUnavailableCodes.has(failure.code)) {
|
|
290
294
|
return new NotificationError('NOTIFICATIONS_CONFIGURATION_REQUIRED', {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type BridgeNotificationsV2Method } from '@mpgd/bridge';
|
|
2
2
|
import type { NotificationSubscriptionAdapter } from '@mpgd/platform';
|
|
3
3
|
import { type NotificationProvider } from '@mpgd/platform/notifications';
|
|
4
4
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isThrownInstance, readThrownField } from '@mpgd/bridge';
|
|
1
2
|
import { assertBridgeNotificationsV2Result, readBridgeNotificationsHostCode, } from '@mpgd/bridge/notifications';
|
|
2
3
|
import { isNotificationErrorCode, isValidNotificationTimeZone, NotificationError, notificationsProtocol, toNotificationSubscriptionAdapter, } from '@mpgd/platform/notifications';
|
|
3
4
|
import { devvitNotificationProviderId } from './notifications-contract.js';
|
|
@@ -109,12 +110,15 @@ function defaultLocale() {
|
|
|
109
110
|
return typeof navigatorLike?.language === 'string' ? navigatorLike.language : undefined;
|
|
110
111
|
}
|
|
111
112
|
function toNotificationError(error) {
|
|
112
|
-
if (error
|
|
113
|
+
if (isThrownInstance(error, NotificationError)) {
|
|
113
114
|
return error;
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
:
|
|
116
|
+
// Each field read once; one whose getter or Proxy trap throws counts as missing.
|
|
117
|
+
const failure = {
|
|
118
|
+
code: readThrownField(error, 'code'),
|
|
119
|
+
message: readThrownField(error, 'message'),
|
|
120
|
+
retryable: readThrownField(error, 'retryable'),
|
|
121
|
+
};
|
|
118
122
|
const message = typeof failure.message === 'string' ? failure.message : undefined;
|
|
119
123
|
const explicit = typeof failure.retryable === 'boolean' ? { retryable: failure.retryable } : {};
|
|
120
124
|
if (isNotificationErrorCode(failure.code)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type BridgeRequest, type BridgeResponse } from '@mpgd/bridge';
|
|
2
2
|
import { type NotificationService } from '@mpgd/game-services/notifications';
|
|
3
3
|
import { type DevvitNotificationSessionContext } from './notifications-delivery.js';
|
|
4
4
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isThrownInstance } from '@mpgd/bridge';
|
|
1
2
|
import { createNotificationsBackendBridgeHandler } from '@mpgd/bridge/notifications';
|
|
2
3
|
import { NotificationError } from '@mpgd/platform/notifications';
|
|
3
4
|
import { NotificationConsentRateLimitError, } from '@mpgd/game-services/notifications';
|
|
@@ -65,8 +66,8 @@ function warnBackendFailure(error, context) {
|
|
|
65
66
|
// A throttled consent write is the player's own cap, and an input the
|
|
66
67
|
// service refuses is the caller's: neither is a server failure, and a
|
|
67
68
|
// webview could otherwise fill the log with them.
|
|
68
|
-
if (error
|
|
69
|
-
|| (error
|
|
69
|
+
if (isThrownInstance(error, NotificationConsentRateLimitError)
|
|
70
|
+
|| (isThrownInstance(error, NotificationError) && error.code === 'NOTIFICATIONS_INVALID_INPUT')) {
|
|
70
71
|
return;
|
|
71
72
|
}
|
|
72
73
|
console.warn(`devvit notifications ${context.method} failed`, error);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type BridgeRequest, type BridgeResponse } from '@mpgd/bridge';
|
|
2
2
|
import { type NotificationProvider } from '@mpgd/platform/notifications';
|
|
3
3
|
/**
|
|
4
4
|
* The game-rendered consent of the Devvit profile (notifications v2 RFC,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isThrownInstance } from '@mpgd/bridge';
|
|
1
2
|
import { createNotificationsV2BridgeHandler } from '@mpgd/bridge/notifications';
|
|
2
3
|
import { NotificationError, } from '@mpgd/platform/notifications';
|
|
3
4
|
import { createDevvitNotificationCapabilities, devvitNotificationProviderId, devvitUserIdPattern, } from '../notifications-contract.js';
|
|
@@ -177,7 +178,7 @@ export function createDevvitNotificationsV2BridgeHandler(input) {
|
|
|
177
178
|
// An unexpected failure's text stays on the server.
|
|
178
179
|
unexpectedFailureMessage: (method) => `${method} failed on the Devvit server.`,
|
|
179
180
|
onError: input.onError ?? ((error, context) => {
|
|
180
|
-
if (error
|
|
181
|
+
if (isThrownInstance(error, NotificationError) && error.code === 'NOTIFICATIONS_UNSUPPORTED') {
|
|
181
182
|
return;
|
|
182
183
|
}
|
|
183
184
|
console.warn(`devvit notifications ${context.method} failed`, error);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { thrownMessage } from '@mpgd/bridge';
|
|
1
2
|
import { createNotificationProviderRegistry, createNotificationService, createNotificationServiceCatalog, } from '@mpgd/game-services/notifications';
|
|
2
3
|
import { referenceNotificationProviders, } from '@mpgd/platform/notifications';
|
|
3
4
|
import { devvitNotificationBodyMaxLength, devvitNotificationLinkPattern, devvitNotificationProviderId, devvitNotificationsPerAppPerDay, devvitNotificationsPerUserPerDay, devvitNotificationTarget, devvitNotificationTextLength, devvitNotificationTitleMaxLength, devvitUserIdPattern, } from '../notifications-contract.js';
|
|
@@ -183,7 +184,7 @@ export function createDevvitNotificationDeliveryProvider(input) {
|
|
|
183
184
|
}
|
|
184
185
|
catch (error) {
|
|
185
186
|
// A failing classifier keeps the default answer; the report says so.
|
|
186
|
-
note = ` (classifyEnqueueError threw: ${
|
|
187
|
+
note = ` (classifyEnqueueError threw: ${thrownMessage(error)})`;
|
|
187
188
|
}
|
|
188
189
|
// The provider code follows the final answer, after any override; a
|
|
189
190
|
// thrown call keeps DEVVIT_ENQUEUE_FAILED, which names its source.
|
|
@@ -223,7 +224,7 @@ export function createDevvitNotificationDeliveryProvider(input) {
|
|
|
223
224
|
});
|
|
224
225
|
}
|
|
225
226
|
catch (error) {
|
|
226
|
-
return failure('thrown',
|
|
227
|
+
return failure('thrown', thrownMessage(error), 'ambiguous');
|
|
227
228
|
}
|
|
228
229
|
if (typeof response?.successCount === 'number' && response.successCount > 0) {
|
|
229
230
|
return { status: 'accepted' };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isThrownInstance, readThrownField } from '@mpgd/bridge';
|
|
1
2
|
import { formatNotificationInstant, notificationSendDueAt, } from '@mpgd/game-services/notifications';
|
|
2
3
|
import { createHash } from 'node:crypto';
|
|
3
4
|
export const defaultDevvitNotificationNamespace = 'mpgd:notifications';
|
|
@@ -1084,7 +1085,9 @@ const permanentRedisError = /not allowed|allow-?list|unknown command|WRONGTYPE|u
|
|
|
1084
1085
|
const connectionLoss = /\b(?:econnreset|econnrefused|socket hang up|temporarily unavailable|resource[_ ]exhausted|try again later)\b/iu;
|
|
1085
1086
|
const transactionAbort = /\b(?:timed?\s*out|timeout|deadline exceeded)\b/iu;
|
|
1086
1087
|
function redisThrowKind(error) {
|
|
1087
|
-
if (error
|
|
1088
|
+
if (isThrownInstance(error, TypeError)
|
|
1089
|
+
|| isThrownInstance(error, RangeError)
|
|
1090
|
+
|| isThrownInstance(error, SyntaxError)) {
|
|
1088
1091
|
return 'permanent';
|
|
1089
1092
|
}
|
|
1090
1093
|
const text = redisErrorText(error);
|
|
@@ -1110,8 +1113,8 @@ function redisErrorText(error) {
|
|
|
1110
1113
|
if (typeof error !== 'object' || error === null) {
|
|
1111
1114
|
return '';
|
|
1112
1115
|
}
|
|
1113
|
-
|
|
1114
|
-
return [
|
|
1116
|
+
// A field whose getter or Proxy trap throws counts as missing.
|
|
1117
|
+
return [readThrownField(error, 'message'), readThrownField(error, 'code'), readThrownField(error, 'msg')]
|
|
1115
1118
|
.filter((part) => typeof part === 'string')
|
|
1116
1119
|
.join(' ');
|
|
1117
1120
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpgd/adapter-devvit",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.12",
|
|
4
4
|
"description": "Reddit Devvit Web platform adapter for mpgd games.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
],
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@devvit/web": "0.15.0",
|
|
58
|
-
"@mpgd/
|
|
59
|
-
"@mpgd/game-services": "0.
|
|
60
|
-
"@mpgd/
|
|
58
|
+
"@mpgd/platform": "0.35.1",
|
|
59
|
+
"@mpgd/game-services": "0.34.0",
|
|
60
|
+
"@mpgd/bridge": "0.19.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@types/node": "^24.0.0",
|