@casual-simulation/aux-records 3.4.6-alpha.14668890889 → 3.5.0-alpha.15117651144
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/AIController.js +835 -890
- package/AIController.js.map +1 -1
- package/AIHumeInterface.js +43 -54
- package/AIHumeInterface.js.map +1 -1
- package/AIOpenAIRealtimeInterface.js +60 -71
- package/AIOpenAIRealtimeInterface.js.map +1 -1
- package/AnthropicAIChatInterface.js +96 -142
- package/AnthropicAIChatInterface.js.map +1 -1
- package/AuthController.d.ts +3 -2
- package/AuthController.js +1907 -1933
- package/AuthController.js.map +1 -1
- package/AuthStore.d.ts +1 -10
- package/BlockadeLabsGenerateSkyboxInterface.js +57 -72
- package/BlockadeLabsGenerateSkyboxInterface.js.map +1 -1
- package/CachingConfigStore.js +30 -45
- package/CachingConfigStore.js.map +1 -1
- package/CachingPolicyStore.d.ts +8 -2
- package/CachingPolicyStore.js +108 -135
- package/CachingPolicyStore.js.map +1 -1
- package/ComIdConfig.d.ts +18 -18
- package/ComIdConfig.js.map +1 -1
- package/ConsoleAuthMessenger.js +7 -20
- package/ConsoleAuthMessenger.js.map +1 -1
- package/DataRecordsController.d.ts +2 -2
- package/DataRecordsController.js +369 -377
- package/DataRecordsController.js.map +1 -1
- package/DataRecordsStore.d.ts +1 -1
- package/DataRecordsStore.js +1 -1
- package/DataRecordsStore.js.map +1 -1
- package/EventRecordsController.js +226 -240
- package/EventRecordsController.js.map +1 -1
- package/FileRecordsController.d.ts +13 -2
- package/FileRecordsController.js +458 -450
- package/FileRecordsController.js.map +1 -1
- package/GoogleAIChatInterface.js +133 -179
- package/GoogleAIChatInterface.js.map +1 -1
- package/LivekitController.js +43 -54
- package/LivekitController.js.map +1 -1
- package/LoomController.js +64 -75
- package/LoomController.js.map +1 -1
- package/MemoryAuthMessenger.js +10 -23
- package/MemoryAuthMessenger.js.map +1 -1
- package/MemoryCache.js +18 -35
- package/MemoryCache.js.map +1 -1
- package/MemoryFileRecordsLookup.js +105 -125
- package/MemoryFileRecordsLookup.js.map +1 -1
- package/MemoryModerationJobProvider.js +17 -30
- package/MemoryModerationJobProvider.js.map +1 -1
- package/MemoryRateLimiter.js +12 -27
- package/MemoryRateLimiter.js.map +1 -1
- package/MemoryStore.d.ts +18 -6
- package/MemoryStore.js +1879 -1997
- package/MemoryStore.js.map +1 -1
- package/MetricsStore.d.ts +2 -2
- package/ModerationController.js +186 -200
- package/ModerationController.js.map +1 -1
- package/OpenAIChatInterface.js +105 -135
- package/OpenAIChatInterface.js.map +1 -1
- package/OpenAIImageInterface.js +57 -51
- package/OpenAIImageInterface.js.map +1 -1
- package/PolicyController.d.ts +150 -10
- package/PolicyController.js +1546 -1299
- package/PolicyController.js.map +1 -1
- package/PolicyStore.d.ts +110 -2
- package/PolicyStore.js +36 -1
- package/PolicyStore.js.map +1 -1
- package/PrivoClient.js +398 -435
- package/PrivoClient.js.map +1 -1
- package/RateLimitController.js +25 -36
- package/RateLimitController.js.map +1 -1
- package/RecordsClient.js +51 -74
- package/RecordsClient.js.map +1 -1
- package/RecordsController.d.ts +2 -42
- package/RecordsController.js +1026 -1182
- package/RecordsController.js.map +1 -1
- package/RecordsServer.d.ts +196 -27
- package/RecordsServer.js +1701 -1343
- package/RecordsServer.js.map +1 -1
- package/RecordsStore.d.ts +1 -10
- package/RecordsStore.js.map +1 -1
- package/ServerConfig.d.ts +339 -195
- package/ServerConfig.js +13 -0
- package/ServerConfig.js.map +1 -1
- package/SloydInterface.js +62 -75
- package/SloydInterface.js.map +1 -1
- package/StabilityAIImageInterface.js +150 -167
- package/StabilityAIImageInterface.js.map +1 -1
- package/SubscriptionConfigBuilder.d.ts +6 -1
- package/SubscriptionConfigBuilder.js +22 -0
- package/SubscriptionConfigBuilder.js.map +1 -1
- package/SubscriptionConfiguration.d.ts +266 -169
- package/SubscriptionConfiguration.js +101 -79
- package/SubscriptionConfiguration.js.map +1 -1
- package/SubscriptionController.d.ts +2 -1
- package/SubscriptionController.js +643 -650
- package/SubscriptionController.js.map +1 -1
- package/SystemNotificationMessenger.d.ts +21 -4
- package/SystemNotificationMessenger.js +36 -30
- package/SystemNotificationMessenger.js.map +1 -1
- package/TestUtils.d.ts +9 -1
- package/TestUtils.js +105 -129
- package/TestUtils.js.map +1 -1
- package/Utils.d.ts +2 -16
- package/Utils.js +21 -22
- package/Utils.js.map +1 -1
- package/crud/CrudHelpers.js +17 -26
- package/crud/CrudHelpers.js.map +1 -1
- package/crud/CrudRecordsController.d.ts +1 -1
- package/crud/CrudRecordsController.js +259 -267
- package/crud/CrudRecordsController.js.map +1 -1
- package/crud/CrudRecordsControllerTests.js +174 -185
- package/crud/CrudRecordsControllerTests.js.map +1 -1
- package/crud/CrudRecordsStore.d.ts +7 -3
- package/crud/MemoryCrudRecordsStore.d.ts +4 -4
- package/crud/MemoryCrudRecordsStore.js +98 -118
- package/crud/MemoryCrudRecordsStore.js.map +1 -1
- package/crud/sub/MemorySubCrudRecordsStore.d.ts +24 -0
- package/crud/sub/MemorySubCrudRecordsStore.js +146 -0
- package/crud/sub/MemorySubCrudRecordsStore.js.map +1 -0
- package/crud/sub/SubCrudRecordsController.d.ts +182 -0
- package/crud/sub/SubCrudRecordsController.js +360 -0
- package/crud/sub/SubCrudRecordsController.js.map +1 -0
- package/crud/sub/SubCrudRecordsControllerTests.d.ts +39 -0
- package/crud/sub/SubCrudRecordsControllerTests.js +821 -0
- package/crud/sub/SubCrudRecordsControllerTests.js.map +1 -0
- package/crud/sub/SubCrudRecordsStore.d.ts +95 -0
- package/{forms/index.js → crud/sub/SubCrudRecordsStore.js} +2 -2
- package/crud/sub/SubCrudRecordsStore.js.map +1 -0
- package/crud/sub/index.d.ts +3 -0
- package/crud/sub/index.js +20 -0
- package/{forms → crud/sub}/index.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/notifications/MemoryNotificationRecordsStore.js +189 -198
- package/notifications/MemoryNotificationRecordsStore.js.map +1 -1
- package/notifications/NotificationRecordsController.js +438 -460
- package/notifications/NotificationRecordsController.js.map +1 -1
- package/notifications/NotificationRecordsStore.d.ts +2 -1
- package/notifications/WebPushInterface.d.ts +0 -1
- package/notifications/WebPushInterface.js +0 -1
- package/notifications/WebPushInterface.js.map +1 -1
- package/package.json +6 -6
- package/packages/MemoryPackageRecordsStore.d.ts +10 -0
- package/packages/MemoryPackageRecordsStore.js +38 -0
- package/packages/MemoryPackageRecordsStore.js.map +1 -0
- package/packages/PackageRecordsController.d.ts +26 -0
- package/packages/PackageRecordsController.js +49 -0
- package/packages/PackageRecordsController.js.map +1 -0
- package/packages/PackageRecordsStore.d.ts +32 -0
- package/packages/PackageRecordsStore.js +19 -0
- package/packages/PackageRecordsStore.js.map +1 -0
- package/packages/index.d.ts +4 -0
- package/packages/index.js +21 -0
- package/packages/index.js.map +1 -0
- package/packages/version/MemoryPackageVersionRecordsStore.d.ts +21 -0
- package/packages/version/MemoryPackageVersionRecordsStore.js +177 -0
- package/packages/version/MemoryPackageVersionRecordsStore.js.map +1 -0
- package/packages/version/PackageVersionRecordsController.d.ts +144 -0
- package/packages/version/PackageVersionRecordsController.js +656 -0
- package/packages/version/PackageVersionRecordsController.js.map +1 -0
- package/packages/version/PackageVersionRecordsStore.d.ts +342 -0
- package/packages/version/PackageVersionRecordsStore.js +126 -0
- package/packages/version/PackageVersionRecordsStore.js.map +1 -0
- package/packages/version/index.d.ts +4 -0
- package/packages/version/index.js +21 -0
- package/packages/version/index.js.map +1 -0
- package/tracing/TracingDecorators.js +31 -40
- package/tracing/TracingDecorators.js.map +1 -1
- package/webhooks/MemoryWebhookRecordsStore.js +56 -72
- package/webhooks/MemoryWebhookRecordsStore.js.map +1 -1
- package/webhooks/WebhookEnvironment.d.ts +3 -3
- package/webhooks/WebhookRecordsController.d.ts +2 -1
- package/webhooks/WebhookRecordsController.js +389 -382
- package/webhooks/WebhookRecordsController.js.map +1 -1
- package/webhooks/WebhookRecordsStore.d.ts +2 -1
- package/websockets/InstRecordsStore.d.ts +50 -0
- package/websockets/InstRecordsStore.js +17 -0
- package/websockets/InstRecordsStore.js.map +1 -1
- package/websockets/MemoryTempInstRecordsStore.d.ts +5 -0
- package/websockets/MemoryTempInstRecordsStore.js +168 -179
- package/websockets/MemoryTempInstRecordsStore.js.map +1 -1
- package/websockets/MemoryWebsocketConnectionStore.js +98 -135
- package/websockets/MemoryWebsocketConnectionStore.js.map +1 -1
- package/websockets/MemoryWebsocketMessenger.js +29 -48
- package/websockets/MemoryWebsocketMessenger.js.map +1 -1
- package/websockets/SplitInstRecordsStore.d.ts +4 -1
- package/websockets/SplitInstRecordsStore.js +167 -185
- package/websockets/SplitInstRecordsStore.js.map +1 -1
- package/websockets/TemporaryInstRecordsStore.d.ts +19 -1
- package/websockets/TemporaryInstRecordsStore.js +17 -0
- package/websockets/TemporaryInstRecordsStore.js.map +1 -1
- package/websockets/WebsocketController.d.ts +147 -3
- package/websockets/WebsocketController.js +1735 -1391
- package/websockets/WebsocketController.js.map +1 -1
- package/websockets/index.d.ts +0 -1
- package/websockets/index.js +0 -1
- package/websockets/index.js.map +1 -1
- package/AAGUID.d.ts +0 -11
- package/AAGUID.js +0 -116
- package/AAGUID.js.map +0 -1
- package/AuthUtils.d.ts +0 -162
- package/AuthUtils.js +0 -327
- package/AuthUtils.js.map +0 -1
- package/forms/FormError.d.ts +0 -43
- package/forms/FormError.js +0 -56
- package/forms/FormError.js.map +0 -1
- package/forms/index.d.ts +0 -2
- package/websockets/Utils.d.ts +0 -33
- package/websockets/Utils.js +0 -82
- package/websockets/Utils.js.map +0 -1
|
@@ -4,145 +4,135 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
|
|
8
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
import { PRIVATE_MARKER } from '@casual-simulation/aux-common';
|
|
7
|
+
import { PRIVATE_MARKER, SUBSCRIPTION_ID_NAMESPACE, } from '@casual-simulation/aux-common';
|
|
17
8
|
import { CrudRecordsController } from '../crud';
|
|
18
9
|
import { getNotificationFeatures } from '../SubscriptionConfiguration';
|
|
19
10
|
import { traced } from '../tracing/TracingDecorators';
|
|
20
11
|
import { SpanStatusCode, trace } from '@opentelemetry/api';
|
|
21
12
|
import { v7 as uuidv7, v5 as uuidv5 } from 'uuid';
|
|
22
|
-
import { SUBSCRIPTION_ID_NAMESPACE } from './WebPushInterface';
|
|
23
13
|
const TRACE_NAME = 'NotificationRecordsController';
|
|
24
14
|
/**
|
|
25
15
|
* Defines a controller that can be used to interact with NotificationRecords.
|
|
26
16
|
*/
|
|
27
17
|
export class NotificationRecordsController extends CrudRecordsController {
|
|
28
18
|
constructor(config) {
|
|
29
|
-
super(
|
|
19
|
+
super({
|
|
20
|
+
...config,
|
|
21
|
+
name: 'NotificationRecordsController',
|
|
22
|
+
resourceKind: 'notification',
|
|
23
|
+
});
|
|
30
24
|
this._pushInterface = config.pushInterface;
|
|
31
25
|
}
|
|
32
|
-
getApplicationServerKey() {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
});
|
|
26
|
+
async getApplicationServerKey() {
|
|
27
|
+
try {
|
|
28
|
+
const key = this._pushInterface.getServerApplicationKey();
|
|
29
|
+
return {
|
|
30
|
+
success: true,
|
|
31
|
+
key,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
const span = trace.getActiveSpan();
|
|
36
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
37
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
38
|
+
console.error('[NotificationRecordsController] Error subscribing to notification:', err);
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
errorCode: 'server_error',
|
|
42
|
+
errorMessage: 'A server error occurred.',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
53
45
|
}
|
|
54
46
|
/**
|
|
55
47
|
* Subscribes the user to the given notification.
|
|
56
48
|
* Does nothing if the user is already subscribed.
|
|
57
49
|
* @param request The request.
|
|
58
50
|
*/
|
|
59
|
-
subscribeToNotification(request) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return context;
|
|
68
|
-
}
|
|
69
|
-
const recordName = context.context.recordName;
|
|
70
|
-
const userId = context.context.userId;
|
|
71
|
-
const notification = yield this.store.getItemByAddress(recordName, request.address);
|
|
72
|
-
if (!notification) {
|
|
73
|
-
return {
|
|
74
|
-
success: false,
|
|
75
|
-
errorCode: 'data_not_found',
|
|
76
|
-
errorMessage: 'Notification not found.',
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
const authorization = yield this.policies.authorizeUserAndInstances(context.context, {
|
|
80
|
-
action: 'subscribe',
|
|
81
|
-
resourceKind: 'notification',
|
|
82
|
-
resourceId: notification.address,
|
|
83
|
-
markers: notification.markers,
|
|
84
|
-
userId: userId,
|
|
85
|
-
instances: request.instances,
|
|
86
|
-
});
|
|
87
|
-
if (authorization.success === false) {
|
|
88
|
-
return authorization;
|
|
89
|
-
}
|
|
90
|
-
const metrics = yield this._checkSubscriptionMetrics('subscribe', context.context, authorization, notification);
|
|
91
|
-
if (metrics.success === false) {
|
|
92
|
-
return metrics;
|
|
93
|
-
}
|
|
94
|
-
const pushSubscriptionId = this._getPushSubscriptionId(request.pushSubscription.endpoint);
|
|
95
|
-
yield this.store.savePushSubscription({
|
|
96
|
-
id: pushSubscriptionId,
|
|
97
|
-
active: true,
|
|
98
|
-
endpoint: request.pushSubscription.endpoint,
|
|
99
|
-
keys: request.pushSubscription.keys,
|
|
100
|
-
});
|
|
101
|
-
yield this.store.savePushSubscriptionUser({
|
|
102
|
-
pushSubscriptionId: pushSubscriptionId,
|
|
103
|
-
userId: userId,
|
|
104
|
-
});
|
|
105
|
-
let subscriptionId = null;
|
|
106
|
-
if (userId) {
|
|
107
|
-
const sub = yield this.store.getSubscriptionByRecordAddressAndUserId(recordName, notification.address, userId);
|
|
108
|
-
if (sub) {
|
|
109
|
-
subscriptionId = sub.id;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
const sub = yield this.store.getSubscriptionByRecordAddressAndPushSubscriptionId(recordName, notification.address, pushSubscriptionId);
|
|
114
|
-
if (sub) {
|
|
115
|
-
subscriptionId = sub.id;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (!subscriptionId) {
|
|
119
|
-
subscriptionId = uuidv7();
|
|
120
|
-
yield this.store.saveSubscription({
|
|
121
|
-
id: subscriptionId,
|
|
122
|
-
recordName,
|
|
123
|
-
notificationAddress: notification.address,
|
|
124
|
-
userId: userId,
|
|
125
|
-
pushSubscriptionId: !userId ? pushSubscriptionId : null,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
console.log(`[NotificationRecordsController] [userId: ${userId} pushSubscriptionId: ${pushSubscriptionId} subscriptionId: ${subscriptionId}] Subscribed to notification`);
|
|
129
|
-
return {
|
|
130
|
-
success: true,
|
|
131
|
-
subscriptionId,
|
|
132
|
-
};
|
|
51
|
+
async subscribeToNotification(request) {
|
|
52
|
+
try {
|
|
53
|
+
const context = await this.policies.constructAuthorizationContext({
|
|
54
|
+
userId: request.userId,
|
|
55
|
+
recordKeyOrRecordName: request.recordName,
|
|
56
|
+
});
|
|
57
|
+
if (context.success === false) {
|
|
58
|
+
return context;
|
|
133
59
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
console.error('[NotificationRecordsController] Error subscribing to notification:', err);
|
|
60
|
+
const recordName = context.context.recordName;
|
|
61
|
+
const userId = context.context.userId;
|
|
62
|
+
const notification = await this.store.getItemByAddress(recordName, request.address);
|
|
63
|
+
if (!notification) {
|
|
139
64
|
return {
|
|
140
65
|
success: false,
|
|
141
|
-
errorCode: '
|
|
142
|
-
errorMessage: '
|
|
66
|
+
errorCode: 'data_not_found',
|
|
67
|
+
errorMessage: 'Notification not found.',
|
|
143
68
|
};
|
|
144
69
|
}
|
|
145
|
-
|
|
70
|
+
const authorization = await this.policies.authorizeUserAndInstances(context.context, {
|
|
71
|
+
action: 'subscribe',
|
|
72
|
+
resourceKind: 'notification',
|
|
73
|
+
resourceId: notification.address,
|
|
74
|
+
markers: notification.markers,
|
|
75
|
+
userId: userId,
|
|
76
|
+
instances: request.instances,
|
|
77
|
+
});
|
|
78
|
+
if (authorization.success === false) {
|
|
79
|
+
return authorization;
|
|
80
|
+
}
|
|
81
|
+
const metrics = await this._checkSubscriptionMetrics('subscribe', context.context, authorization, notification);
|
|
82
|
+
if (metrics.success === false) {
|
|
83
|
+
return metrics;
|
|
84
|
+
}
|
|
85
|
+
const pushSubscriptionId = this._getPushSubscriptionId(request.pushSubscription.endpoint);
|
|
86
|
+
await this.store.savePushSubscription({
|
|
87
|
+
id: pushSubscriptionId,
|
|
88
|
+
active: true,
|
|
89
|
+
endpoint: request.pushSubscription.endpoint,
|
|
90
|
+
keys: request.pushSubscription.keys,
|
|
91
|
+
});
|
|
92
|
+
await this.store.savePushSubscriptionUser({
|
|
93
|
+
pushSubscriptionId: pushSubscriptionId,
|
|
94
|
+
userId: userId,
|
|
95
|
+
});
|
|
96
|
+
let subscriptionId = null;
|
|
97
|
+
if (userId) {
|
|
98
|
+
const sub = await this.store.getSubscriptionByRecordAddressAndUserId(recordName, notification.address, userId);
|
|
99
|
+
if (sub) {
|
|
100
|
+
subscriptionId = sub.id;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const sub = await this.store.getSubscriptionByRecordAddressAndPushSubscriptionId(recordName, notification.address, pushSubscriptionId);
|
|
105
|
+
if (sub) {
|
|
106
|
+
subscriptionId = sub.id;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!subscriptionId) {
|
|
110
|
+
subscriptionId = uuidv7();
|
|
111
|
+
await this.store.saveSubscription({
|
|
112
|
+
id: subscriptionId,
|
|
113
|
+
recordName,
|
|
114
|
+
notificationAddress: notification.address,
|
|
115
|
+
userId: userId,
|
|
116
|
+
pushSubscriptionId: !userId ? pushSubscriptionId : null,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
console.log(`[NotificationRecordsController] [userId: ${userId} pushSubscriptionId: ${pushSubscriptionId} subscriptionId: ${subscriptionId}] Subscribed to notification`);
|
|
120
|
+
return {
|
|
121
|
+
success: true,
|
|
122
|
+
subscriptionId,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
const span = trace.getActiveSpan();
|
|
127
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
128
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
129
|
+
console.error('[NotificationRecordsController] Error subscribing to notification:', err);
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
errorCode: 'server_error',
|
|
133
|
+
errorMessage: 'A server error occurred.',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
146
136
|
}
|
|
147
137
|
_getPushSubscriptionId(endpoint) {
|
|
148
138
|
return uuidv5(endpoint, SUBSCRIPTION_ID_NAMESPACE);
|
|
@@ -151,144 +141,47 @@ export class NotificationRecordsController extends CrudRecordsController {
|
|
|
151
141
|
* Unsubscribes the user from the given notification.
|
|
152
142
|
* @param request The request.
|
|
153
143
|
*/
|
|
154
|
-
unsubscribeFromNotification(request) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
144
|
+
async unsubscribeFromNotification(request) {
|
|
145
|
+
try {
|
|
146
|
+
const subscription = await this.store.getSubscriptionById(request.subscriptionId);
|
|
147
|
+
if (!subscription) {
|
|
148
|
+
return {
|
|
149
|
+
success: false,
|
|
150
|
+
errorCode: 'data_not_found',
|
|
151
|
+
errorMessage: 'Subscription not found.',
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const context = await this.policies.constructAuthorizationContext({
|
|
155
|
+
userId: request.userId,
|
|
156
|
+
recordKeyOrRecordName: subscription.recordName,
|
|
157
|
+
});
|
|
158
|
+
if (context.success === false) {
|
|
159
|
+
return context;
|
|
160
|
+
}
|
|
161
|
+
let successfulAuthorization = false;
|
|
162
|
+
if (subscription.userId) {
|
|
163
|
+
const userContext = await this.policies.constructAuthorizationContext({
|
|
166
164
|
userId: request.userId,
|
|
167
|
-
recordKeyOrRecordName: subscription.
|
|
165
|
+
recordKeyOrRecordName: subscription.userId,
|
|
168
166
|
});
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
let successfulAuthorization = false;
|
|
173
|
-
if (subscription.userId) {
|
|
174
|
-
const userContext = yield this.policies.constructAuthorizationContext({
|
|
167
|
+
if (userContext.success === true) {
|
|
168
|
+
const userAuthorization = await this.policies.authorizeUserAndInstances(userContext.context, {
|
|
175
169
|
userId: request.userId,
|
|
176
|
-
recordKeyOrRecordName: subscription.userId,
|
|
177
|
-
});
|
|
178
|
-
if (userContext.success === true) {
|
|
179
|
-
const userAuthorization = yield this.policies.authorizeUserAndInstances(userContext.context, {
|
|
180
|
-
userId: request.userId,
|
|
181
|
-
action: 'unsubscribe',
|
|
182
|
-
resourceKind: 'notification',
|
|
183
|
-
resourceId: subscription.id,
|
|
184
|
-
instances: request.instances,
|
|
185
|
-
markers: [PRIVATE_MARKER],
|
|
186
|
-
});
|
|
187
|
-
if (userAuthorization.success === true) {
|
|
188
|
-
successfulAuthorization = true;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
const userId = context.context.userId;
|
|
193
|
-
const recordName = context.context.recordName;
|
|
194
|
-
if (!successfulAuthorization) {
|
|
195
|
-
const notification = yield this.store.getItemByAddress(recordName, subscription.notificationAddress);
|
|
196
|
-
if (!notification) {
|
|
197
|
-
return {
|
|
198
|
-
success: false,
|
|
199
|
-
errorCode: 'data_not_found',
|
|
200
|
-
errorMessage: 'Notification not found.',
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
const authorization = yield this.policies.authorizeUserAndInstances(context.context, {
|
|
204
|
-
userId,
|
|
205
170
|
action: 'unsubscribe',
|
|
206
171
|
resourceKind: 'notification',
|
|
207
|
-
resourceId:
|
|
172
|
+
resourceId: subscription.id,
|
|
208
173
|
instances: request.instances,
|
|
209
|
-
markers:
|
|
174
|
+
markers: [PRIVATE_MARKER],
|
|
210
175
|
});
|
|
211
|
-
if (
|
|
212
|
-
|
|
176
|
+
if (userAuthorization.success === true) {
|
|
177
|
+
successfulAuthorization = true;
|
|
213
178
|
}
|
|
214
179
|
}
|
|
215
|
-
// allowed
|
|
216
|
-
yield this.store.deleteSubscription(request.subscriptionId);
|
|
217
|
-
console.log(`[NotificationRecordsController] [userId: ${userId} subscriptionId: ${request.subscriptionId}] Unsubscribed from notification`);
|
|
218
|
-
return {
|
|
219
|
-
success: true,
|
|
220
|
-
};
|
|
221
180
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
console.error('[NotificationRecordsController] Error subscribing to notification:', err);
|
|
227
|
-
return {
|
|
228
|
-
success: false,
|
|
229
|
-
errorCode: 'server_error',
|
|
230
|
-
errorMessage: 'A server error occurred.',
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Registers a push subscription for the user.
|
|
237
|
-
* This will allow the device to recieve push notifications for the user.
|
|
238
|
-
* @param request The request.
|
|
239
|
-
*/
|
|
240
|
-
registerPushSubscription(request) {
|
|
241
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
242
|
-
try {
|
|
243
|
-
if (!request.userId) {
|
|
244
|
-
return {
|
|
245
|
-
success: false,
|
|
246
|
-
errorCode: 'not_logged_in',
|
|
247
|
-
errorMessage: 'The user must be logged in. Please provide a sessionKey or a recordKey.',
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
const pushSubscriptionId = this._getPushSubscriptionId(request.pushSubscription.endpoint);
|
|
251
|
-
yield this.store.savePushSubscription({
|
|
252
|
-
id: pushSubscriptionId,
|
|
253
|
-
active: true,
|
|
254
|
-
endpoint: request.pushSubscription.endpoint,
|
|
255
|
-
keys: request.pushSubscription.keys,
|
|
256
|
-
});
|
|
257
|
-
yield this.store.savePushSubscriptionUser({
|
|
258
|
-
pushSubscriptionId: pushSubscriptionId,
|
|
259
|
-
userId: request.userId,
|
|
260
|
-
});
|
|
261
|
-
console.log(`[NotificationRecordsController] [userId: ${request.userId} pushSubscriptionId: ${pushSubscriptionId}] Registered push subscription`);
|
|
262
|
-
return {
|
|
263
|
-
success: true,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
catch (err) {
|
|
267
|
-
const span = trace.getActiveSpan();
|
|
268
|
-
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
269
|
-
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
270
|
-
console.error('[NotificationRecordsController] Error registering push subscription:', err);
|
|
271
|
-
return {
|
|
272
|
-
success: false,
|
|
273
|
-
errorCode: 'server_error',
|
|
274
|
-
errorMessage: 'A server error occurred.',
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
sendNotification(request) {
|
|
280
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
281
|
-
try {
|
|
282
|
-
const context = yield this.policies.constructAuthorizationContext({
|
|
283
|
-
userId: request.userId,
|
|
284
|
-
recordKeyOrRecordName: request.recordName,
|
|
285
|
-
});
|
|
286
|
-
if (context.success === false) {
|
|
287
|
-
return context;
|
|
288
|
-
}
|
|
289
|
-
const recordName = context.context.recordName;
|
|
290
|
-
const userId = context.context.userId;
|
|
291
|
-
const notification = yield this.store.getItemByAddress(recordName, request.address);
|
|
181
|
+
const userId = context.context.userId;
|
|
182
|
+
const recordName = context.context.recordName;
|
|
183
|
+
if (!successfulAuthorization) {
|
|
184
|
+
const notification = await this.store.getItemByAddress(recordName, subscription.notificationAddress);
|
|
292
185
|
if (!notification) {
|
|
293
186
|
return {
|
|
294
187
|
success: false,
|
|
@@ -296,264 +189,349 @@ export class NotificationRecordsController extends CrudRecordsController {
|
|
|
296
189
|
errorMessage: 'Notification not found.',
|
|
297
190
|
};
|
|
298
191
|
}
|
|
299
|
-
const authorization =
|
|
300
|
-
|
|
192
|
+
const authorization = await this.policies.authorizeUserAndInstances(context.context, {
|
|
193
|
+
userId,
|
|
194
|
+
action: 'unsubscribe',
|
|
301
195
|
resourceKind: 'notification',
|
|
302
196
|
resourceId: notification.address,
|
|
303
|
-
markers: notification.markers,
|
|
304
|
-
userId: userId,
|
|
305
197
|
instances: request.instances,
|
|
198
|
+
markers: notification.markers,
|
|
306
199
|
});
|
|
307
200
|
if (authorization.success === false) {
|
|
308
201
|
return authorization;
|
|
309
202
|
}
|
|
310
|
-
const metrics = yield this._checkSubscriptionMetrics('send', context.context, authorization, notification);
|
|
311
|
-
if (metrics.success === false) {
|
|
312
|
-
return metrics;
|
|
313
|
-
}
|
|
314
|
-
const pushSubs = yield this.store.listActivePushSubscriptionsForNotification(recordName, notification.address);
|
|
315
|
-
if (typeof metrics.features.maxSentPushNotificationsPerPeriod ===
|
|
316
|
-
'number') {
|
|
317
|
-
if (metrics.metrics.totalSentNotificationsInPeriod +
|
|
318
|
-
pushSubs.length >=
|
|
319
|
-
metrics.features.maxSentPushNotificationsPerPeriod) {
|
|
320
|
-
return {
|
|
321
|
-
success: false,
|
|
322
|
-
errorCode: 'subscription_limit_reached',
|
|
323
|
-
errorMessage: 'The maximum number of sent push notifications has been reached for this period.',
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
let promises = [];
|
|
328
|
-
const sentTimeMs = Date.now();
|
|
329
|
-
for (let push of pushSubs) {
|
|
330
|
-
promises.push(this._pushInterface
|
|
331
|
-
.sendNotification({
|
|
332
|
-
endpoint: push.endpoint,
|
|
333
|
-
keys: push.keys,
|
|
334
|
-
}, request.payload, request.topic)
|
|
335
|
-
.then((result) => {
|
|
336
|
-
return [push, result];
|
|
337
|
-
}));
|
|
338
|
-
}
|
|
339
|
-
const results = yield Promise.allSettled(promises);
|
|
340
|
-
const notificationId = uuidv7();
|
|
341
|
-
yield this.store.saveSentNotification({
|
|
342
|
-
id: notificationId,
|
|
343
|
-
recordName,
|
|
344
|
-
notificationAddress: notification.address,
|
|
345
|
-
title: request.payload.title,
|
|
346
|
-
body: request.payload.body,
|
|
347
|
-
icon: request.payload.icon,
|
|
348
|
-
badge: request.payload.badge,
|
|
349
|
-
defaultAction: request.payload.action,
|
|
350
|
-
actions: request.payload.actions,
|
|
351
|
-
silent: request.payload.silent,
|
|
352
|
-
tag: request.payload.tag,
|
|
353
|
-
timestamp: request.payload.timestamp,
|
|
354
|
-
sentTimeMs: sentTimeMs,
|
|
355
|
-
topic: request.topic,
|
|
356
|
-
});
|
|
357
|
-
let sentPushNotifications = [];
|
|
358
|
-
let failedPushSubscriptions = [];
|
|
359
|
-
for (let promiseResult of results) {
|
|
360
|
-
if (promiseResult.status === 'rejected') {
|
|
361
|
-
console.error('[NotificationRecordsController] Error sending notification:', promiseResult.reason);
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
const [push, result] = promiseResult.value;
|
|
365
|
-
sentPushNotifications.push({
|
|
366
|
-
id: uuidv7(),
|
|
367
|
-
pushSubscriptionId: push.id,
|
|
368
|
-
sentNotificationId: notificationId,
|
|
369
|
-
userId: push.userId,
|
|
370
|
-
subscriptionId: push.subscriptionId,
|
|
371
|
-
success: result.success,
|
|
372
|
-
errorCode: result.success === false ? result.errorCode : null,
|
|
373
|
-
});
|
|
374
|
-
if (result.success === false) {
|
|
375
|
-
console.error(`[NotificationRecordsController] Error sending notification for ${push.id}:`, result.errorCode);
|
|
376
|
-
if (result.errorCode === 'subscription_gone' ||
|
|
377
|
-
result.errorCode === 'subscription_not_found') {
|
|
378
|
-
failedPushSubscriptions.push(push.id);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
if (sentPushNotifications.length > 0) {
|
|
384
|
-
yield this.store.createSentPushNotifications(sentPushNotifications);
|
|
385
|
-
}
|
|
386
|
-
if (failedPushSubscriptions.length > 0) {
|
|
387
|
-
yield this.store.markPushSubscriptionsInactiveAndDeleteUserRelations(failedPushSubscriptions);
|
|
388
|
-
}
|
|
389
|
-
console.log(`[NotificationRecordsController] [userId: ${userId} notificationId: ${notificationId} sent: ${sentPushNotifications.length} failed: ${failedPushSubscriptions.length}] Sent notification`);
|
|
390
|
-
return {
|
|
391
|
-
success: true,
|
|
392
|
-
};
|
|
393
203
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
204
|
+
// allowed
|
|
205
|
+
await this.store.deleteSubscription(request.subscriptionId);
|
|
206
|
+
console.log(`[NotificationRecordsController] [userId: ${userId} subscriptionId: ${request.subscriptionId}] Unsubscribed from notification`);
|
|
207
|
+
return {
|
|
208
|
+
success: true,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
const span = trace.getActiveSpan();
|
|
213
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
214
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
215
|
+
console.error('[NotificationRecordsController] Error subscribing to notification:', err);
|
|
216
|
+
return {
|
|
217
|
+
success: false,
|
|
218
|
+
errorCode: 'server_error',
|
|
219
|
+
errorMessage: 'A server error occurred.',
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Registers a push subscription for the user.
|
|
225
|
+
* This will allow the device to recieve push notifications for the user.
|
|
226
|
+
* @param request The request.
|
|
227
|
+
*/
|
|
228
|
+
async registerPushSubscription(request) {
|
|
229
|
+
try {
|
|
230
|
+
if (!request.userId) {
|
|
399
231
|
return {
|
|
400
232
|
success: false,
|
|
401
|
-
errorCode: '
|
|
402
|
-
errorMessage: '
|
|
233
|
+
errorCode: 'not_logged_in',
|
|
234
|
+
errorMessage: 'The user must be logged in. Please provide a sessionKey or a recordKey.',
|
|
403
235
|
};
|
|
404
236
|
}
|
|
405
|
-
|
|
237
|
+
const pushSubscriptionId = this._getPushSubscriptionId(request.pushSubscription.endpoint);
|
|
238
|
+
await this.store.savePushSubscription({
|
|
239
|
+
id: pushSubscriptionId,
|
|
240
|
+
active: true,
|
|
241
|
+
endpoint: request.pushSubscription.endpoint,
|
|
242
|
+
keys: request.pushSubscription.keys,
|
|
243
|
+
});
|
|
244
|
+
await this.store.savePushSubscriptionUser({
|
|
245
|
+
pushSubscriptionId: pushSubscriptionId,
|
|
246
|
+
userId: request.userId,
|
|
247
|
+
});
|
|
248
|
+
console.log(`[NotificationRecordsController] [userId: ${request.userId} pushSubscriptionId: ${pushSubscriptionId}] Registered push subscription`);
|
|
249
|
+
return {
|
|
250
|
+
success: true,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
const span = trace.getActiveSpan();
|
|
255
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
256
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
257
|
+
console.error('[NotificationRecordsController] Error registering push subscription:', err);
|
|
258
|
+
return {
|
|
259
|
+
success: false,
|
|
260
|
+
errorCode: 'server_error',
|
|
261
|
+
errorMessage: 'A server error occurred.',
|
|
262
|
+
};
|
|
263
|
+
}
|
|
406
264
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
const subscriptions = yield this.store.listSubscriptionsForUser(request.userId);
|
|
418
|
-
return {
|
|
419
|
-
success: true,
|
|
420
|
-
subscriptions: subscriptions.map((sub) => ({
|
|
421
|
-
id: sub.id,
|
|
422
|
-
userId: sub.userId,
|
|
423
|
-
recordName: sub.recordName,
|
|
424
|
-
notificationAddress: sub.notificationAddress,
|
|
425
|
-
pushSubscriptionId: sub.pushSubscriptionId,
|
|
426
|
-
})),
|
|
427
|
-
};
|
|
265
|
+
async sendNotification(request) {
|
|
266
|
+
try {
|
|
267
|
+
const context = await this.policies.constructAuthorizationContext({
|
|
268
|
+
userId: request.userId,
|
|
269
|
+
recordKeyOrRecordName: request.recordName,
|
|
270
|
+
});
|
|
271
|
+
if (context.success === false) {
|
|
272
|
+
return context;
|
|
428
273
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
console.error('[NotificationRecordsController] Error listing subscriptions for user:', err);
|
|
274
|
+
const recordName = context.context.recordName;
|
|
275
|
+
const userId = context.context.userId;
|
|
276
|
+
const notification = await this.store.getItemByAddress(recordName, request.address);
|
|
277
|
+
if (!notification) {
|
|
434
278
|
return {
|
|
435
279
|
success: false,
|
|
436
|
-
errorCode: '
|
|
437
|
-
errorMessage: '
|
|
280
|
+
errorCode: 'data_not_found',
|
|
281
|
+
errorMessage: 'Notification not found.',
|
|
438
282
|
};
|
|
439
283
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
284
|
+
const authorization = await this.policies.authorizeUserAndInstances(context.context, {
|
|
285
|
+
action: 'send',
|
|
286
|
+
resourceKind: 'notification',
|
|
287
|
+
resourceId: notification.address,
|
|
288
|
+
markers: notification.markers,
|
|
289
|
+
userId: userId,
|
|
290
|
+
instances: request.instances,
|
|
291
|
+
});
|
|
292
|
+
if (authorization.success === false) {
|
|
293
|
+
return authorization;
|
|
294
|
+
}
|
|
295
|
+
const metrics = await this._checkSubscriptionMetrics('send', context.context, authorization, notification);
|
|
296
|
+
if (metrics.success === false) {
|
|
297
|
+
return metrics;
|
|
298
|
+
}
|
|
299
|
+
const pushSubs = await this.store.listActivePushSubscriptionsForNotification(recordName, notification.address);
|
|
300
|
+
if (typeof metrics.features.maxSentPushNotificationsPerPeriod ===
|
|
301
|
+
'number') {
|
|
302
|
+
if (metrics.metrics.totalSentNotificationsInPeriod +
|
|
303
|
+
pushSubs.length >=
|
|
304
|
+
metrics.features.maxSentPushNotificationsPerPeriod) {
|
|
446
305
|
return {
|
|
447
306
|
success: false,
|
|
448
|
-
errorCode: '
|
|
449
|
-
errorMessage: 'The
|
|
307
|
+
errorCode: 'subscription_limit_reached',
|
|
308
|
+
errorMessage: 'The maximum number of sent push notifications has been reached for this period.',
|
|
450
309
|
};
|
|
451
310
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
return
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
311
|
+
}
|
|
312
|
+
let promises = [];
|
|
313
|
+
const sentTimeMs = Date.now();
|
|
314
|
+
for (let push of pushSubs) {
|
|
315
|
+
promises.push(this._pushInterface
|
|
316
|
+
.sendNotification({
|
|
317
|
+
endpoint: push.endpoint,
|
|
318
|
+
keys: push.keys,
|
|
319
|
+
}, request.payload, request.topic)
|
|
320
|
+
.then((result) => {
|
|
321
|
+
return [push, result];
|
|
322
|
+
}));
|
|
323
|
+
}
|
|
324
|
+
const results = await Promise.allSettled(promises);
|
|
325
|
+
const notificationId = uuidv7();
|
|
326
|
+
await this.store.saveSentNotification({
|
|
327
|
+
id: notificationId,
|
|
328
|
+
recordName,
|
|
329
|
+
notificationAddress: notification.address,
|
|
330
|
+
title: request.payload.title,
|
|
331
|
+
body: request.payload.body,
|
|
332
|
+
icon: request.payload.icon,
|
|
333
|
+
badge: request.payload.badge,
|
|
334
|
+
defaultAction: request.payload.action,
|
|
335
|
+
actions: request.payload.actions,
|
|
336
|
+
silent: request.payload.silent,
|
|
337
|
+
tag: request.payload.tag,
|
|
338
|
+
timestamp: request.payload.timestamp,
|
|
339
|
+
sentTimeMs: sentTimeMs,
|
|
340
|
+
topic: request.topic,
|
|
341
|
+
});
|
|
342
|
+
let sentPushNotifications = [];
|
|
343
|
+
let failedPushSubscriptions = [];
|
|
344
|
+
for (let promiseResult of results) {
|
|
345
|
+
if (promiseResult.status === 'rejected') {
|
|
346
|
+
console.error('[NotificationRecordsController] Error sending notification:', promiseResult.reason);
|
|
467
347
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
348
|
+
else {
|
|
349
|
+
const [push, result] = promiseResult.value;
|
|
350
|
+
sentPushNotifications.push({
|
|
351
|
+
id: uuidv7(),
|
|
352
|
+
pushSubscriptionId: push.id,
|
|
353
|
+
sentNotificationId: notificationId,
|
|
354
|
+
userId: push.userId,
|
|
355
|
+
subscriptionId: push.subscriptionId,
|
|
356
|
+
success: result.success,
|
|
357
|
+
errorCode: result.success === false ? result.errorCode : null,
|
|
358
|
+
});
|
|
359
|
+
if (result.success === false) {
|
|
360
|
+
console.error(`[NotificationRecordsController] Error sending notification for ${push.id}:`, result.errorCode);
|
|
361
|
+
if (result.errorCode === 'subscription_gone' ||
|
|
362
|
+
result.errorCode === 'subscription_not_found') {
|
|
363
|
+
failedPushSubscriptions.push(push.id);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
478
366
|
}
|
|
479
|
-
const subscriptions = yield this.store.listSubscriptionsForNotification(recordName, request.address);
|
|
480
|
-
return {
|
|
481
|
-
success: true,
|
|
482
|
-
subscriptions: subscriptions.map((sub) => ({
|
|
483
|
-
id: sub.id,
|
|
484
|
-
userId: sub.userId,
|
|
485
|
-
recordName: sub.recordName,
|
|
486
|
-
notificationAddress: sub.notificationAddress,
|
|
487
|
-
pushSubscriptionId: sub.pushSubscriptionId,
|
|
488
|
-
})),
|
|
489
|
-
};
|
|
490
367
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
368
|
+
if (sentPushNotifications.length > 0) {
|
|
369
|
+
await this.store.createSentPushNotifications(sentPushNotifications);
|
|
370
|
+
}
|
|
371
|
+
if (failedPushSubscriptions.length > 0) {
|
|
372
|
+
await this.store.markPushSubscriptionsInactiveAndDeleteUserRelations(failedPushSubscriptions);
|
|
373
|
+
}
|
|
374
|
+
console.log(`[NotificationRecordsController] [userId: ${userId} notificationId: ${notificationId} sent: ${sentPushNotifications.length} failed: ${failedPushSubscriptions.length}] Sent notification`);
|
|
375
|
+
return {
|
|
376
|
+
success: true,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
const span = trace.getActiveSpan();
|
|
381
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
382
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
383
|
+
console.error('[NotificationRecordsController] Error sending notification:', err);
|
|
384
|
+
return {
|
|
385
|
+
success: false,
|
|
386
|
+
errorCode: 'server_error',
|
|
387
|
+
errorMessage: 'A server error occurred.',
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async listSubscriptionsForUser(request) {
|
|
392
|
+
try {
|
|
393
|
+
if (!request.userId) {
|
|
496
394
|
return {
|
|
497
395
|
success: false,
|
|
498
|
-
errorCode: '
|
|
499
|
-
errorMessage: '
|
|
396
|
+
errorCode: 'not_logged_in',
|
|
397
|
+
errorMessage: 'The user must be logged in. Please provide a sessionKey or a recordKey.',
|
|
500
398
|
};
|
|
501
399
|
}
|
|
502
|
-
|
|
400
|
+
const subscriptions = await this.store.listSubscriptionsForUser(request.userId);
|
|
401
|
+
return {
|
|
402
|
+
success: true,
|
|
403
|
+
subscriptions: subscriptions.map((sub) => ({
|
|
404
|
+
id: sub.id,
|
|
405
|
+
userId: sub.userId,
|
|
406
|
+
recordName: sub.recordName,
|
|
407
|
+
notificationAddress: sub.notificationAddress,
|
|
408
|
+
pushSubscriptionId: sub.pushSubscriptionId,
|
|
409
|
+
})),
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
catch (err) {
|
|
413
|
+
const span = trace.getActiveSpan();
|
|
414
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
415
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
416
|
+
console.error('[NotificationRecordsController] Error listing subscriptions for user:', err);
|
|
417
|
+
return {
|
|
418
|
+
success: false,
|
|
419
|
+
errorCode: 'server_error',
|
|
420
|
+
errorMessage: 'A server error occurred.',
|
|
421
|
+
};
|
|
422
|
+
}
|
|
503
423
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const metrics = yield this.store.getSubscriptionMetrics({
|
|
508
|
-
ownerId: context.recordOwnerId,
|
|
509
|
-
studioId: context.recordStudioId,
|
|
510
|
-
});
|
|
511
|
-
const features = getNotificationFeatures(config, metrics.subscriptionStatus, metrics.subscriptionId, metrics.subscriptionType, metrics.currentPeriodStartMs, metrics.currentPeriodEndMs);
|
|
512
|
-
if (!features.allowed) {
|
|
424
|
+
async listSubscriptions(request) {
|
|
425
|
+
try {
|
|
426
|
+
if (!request.userId) {
|
|
513
427
|
return {
|
|
514
428
|
success: false,
|
|
515
|
-
errorCode: '
|
|
516
|
-
errorMessage: '
|
|
429
|
+
errorCode: 'not_logged_in',
|
|
430
|
+
errorMessage: 'The user must be logged in. Please provide a sessionKey or a recordKey.',
|
|
517
431
|
};
|
|
518
432
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
};
|
|
526
|
-
}
|
|
433
|
+
const context = await this.policies.constructAuthorizationContext({
|
|
434
|
+
recordKeyOrRecordName: request.recordName,
|
|
435
|
+
userId: request.userId,
|
|
436
|
+
});
|
|
437
|
+
if (context.success === false) {
|
|
438
|
+
return context;
|
|
527
439
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
};
|
|
537
|
-
}
|
|
440
|
+
const recordName = context.context.recordName;
|
|
441
|
+
const notification = await this.store.getItemByAddress(recordName, request.address);
|
|
442
|
+
if (!notification) {
|
|
443
|
+
return {
|
|
444
|
+
success: false,
|
|
445
|
+
errorCode: 'data_not_found',
|
|
446
|
+
errorMessage: 'Notification not found.',
|
|
447
|
+
};
|
|
538
448
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
449
|
+
const authorization = await this.policies.authorizeUserAndInstances(context.context, {
|
|
450
|
+
userId: request.userId,
|
|
451
|
+
resourceKind: 'notification',
|
|
452
|
+
markers: notification.markers,
|
|
453
|
+
resourceId: notification.address,
|
|
454
|
+
action: 'listSubscriptions',
|
|
455
|
+
instances: request.instances,
|
|
456
|
+
});
|
|
457
|
+
if (authorization.success === false) {
|
|
458
|
+
return authorization;
|
|
549
459
|
}
|
|
460
|
+
const subscriptions = await this.store.listSubscriptionsForNotification(recordName, request.address);
|
|
550
461
|
return {
|
|
551
462
|
success: true,
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
463
|
+
subscriptions: subscriptions.map((sub) => ({
|
|
464
|
+
id: sub.id,
|
|
465
|
+
userId: sub.userId,
|
|
466
|
+
recordName: sub.recordName,
|
|
467
|
+
notificationAddress: sub.notificationAddress,
|
|
468
|
+
pushSubscriptionId: sub.pushSubscriptionId,
|
|
469
|
+
})),
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
catch (err) {
|
|
473
|
+
const span = trace.getActiveSpan();
|
|
474
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
475
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
476
|
+
console.error('[NotificationRecordsController] Error listing subscriptions for notification:', err);
|
|
477
|
+
return {
|
|
478
|
+
success: false,
|
|
479
|
+
errorCode: 'server_error',
|
|
480
|
+
errorMessage: 'A server error occurred.',
|
|
555
481
|
};
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async _checkSubscriptionMetrics(action, context, authorization, item) {
|
|
485
|
+
const config = await this.config.getSubscriptionConfiguration();
|
|
486
|
+
const metrics = await this.store.getSubscriptionMetrics({
|
|
487
|
+
ownerId: context.recordOwnerId,
|
|
488
|
+
studioId: context.recordStudioId,
|
|
556
489
|
});
|
|
490
|
+
const features = getNotificationFeatures(config, metrics.subscriptionStatus, metrics.subscriptionId, metrics.subscriptionType, metrics.currentPeriodStartMs, metrics.currentPeriodEndMs);
|
|
491
|
+
if (!features.allowed) {
|
|
492
|
+
return {
|
|
493
|
+
success: false,
|
|
494
|
+
errorCode: 'not_authorized',
|
|
495
|
+
errorMessage: 'Notifications are not allowed for this subscription.',
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
if (action === 'create' && typeof features.maxItems === 'number') {
|
|
499
|
+
if (metrics.totalItems >= features.maxItems) {
|
|
500
|
+
return {
|
|
501
|
+
success: false,
|
|
502
|
+
errorCode: 'subscription_limit_reached',
|
|
503
|
+
errorMessage: 'The maximum number of notification items has been reached for your subscription.',
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (action === 'subscribe' &&
|
|
508
|
+
typeof features.maxSubscribersPerItem === 'number') {
|
|
509
|
+
const totalSubscriptions = await this.store.countSubscriptionsForNotification(context.recordName, item.address);
|
|
510
|
+
if (totalSubscriptions >= features.maxSubscribersPerItem) {
|
|
511
|
+
return {
|
|
512
|
+
success: false,
|
|
513
|
+
errorCode: 'subscription_limit_reached',
|
|
514
|
+
errorMessage: 'The maximum number of subscriptions has been reached for this notification.',
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (action === 'send') {
|
|
519
|
+
if (typeof features.maxSentNotificationsPerPeriod === 'number' &&
|
|
520
|
+
metrics.totalSentNotificationsInPeriod >=
|
|
521
|
+
features.maxSentNotificationsPerPeriod) {
|
|
522
|
+
return {
|
|
523
|
+
success: false,
|
|
524
|
+
errorCode: 'subscription_limit_reached',
|
|
525
|
+
errorMessage: 'The maximum number of sent notifications has been reached for this period.',
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
success: true,
|
|
531
|
+
config,
|
|
532
|
+
metrics,
|
|
533
|
+
features,
|
|
534
|
+
};
|
|
557
535
|
}
|
|
558
536
|
}
|
|
559
537
|
__decorate([
|