@wix/realtime 1.0.46 → 1.0.48
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/cjs/build/index.d.ts +2 -2
- package/cjs/build/publisher/publisher.public.d.ts +2 -2
- package/cjs/build/subscriber/errors.d.ts +7 -4
- package/cjs/build/subscriber/errors.js +24 -1
- package/cjs/build/subscriber/subscriber.context.d.ts +2 -2
- package/cjs/build/subscriber/subscriber.context.js +2 -2
- package/cjs/build/subscriber/subscriber.public.d.ts +2 -2
- package/cjs/build/subscriber/subscriber.public.js +84 -36
- package/cjs/build/subscriber/subscription-manager.d.ts +9 -7
- package/cjs/build/subscriber/subscription-manager.js +21 -18
- package/cjs/build/types.d.ts +1 -1
- package/dist/statics/docs-ts-model.json +286 -124
- package/es/build/index.d.ts +2 -2
- package/es/build/publisher/publisher.public.d.ts +2 -2
- package/es/build/subscriber/errors.d.ts +7 -4
- package/es/build/subscriber/errors.js +21 -1
- package/es/build/subscriber/subscriber.context.d.ts +2 -2
- package/es/build/subscriber/subscriber.context.js +2 -2
- package/es/build/subscriber/subscriber.public.d.ts +2 -2
- package/es/build/subscriber/subscriber.public.js +85 -37
- package/es/build/subscriber/subscription-manager.d.ts +9 -7
- package/es/build/subscriber/subscription-manager.js +21 -18
- package/es/build/types.d.ts +1 -1
- package/package.json +4 -4
package/cjs/build/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * as site from '@wix/sdk_realtime_site';
|
|
2
2
|
export * as publisher from './publisher/publisher.context.js';
|
|
3
3
|
export * as subscriber from './subscriber/subscriber.context.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { PublishChannel, SubscribeChannel, Message, MessageHandler, Publisher, SubscriptionErrorHandler, SubscriptionHandler, SubscriptionOptions, UnsubscribeOptions } from './types.js';
|
|
5
5
|
import { RealtimeError, RealtimeErrorCode } from './types.js';
|
|
6
|
-
export type {
|
|
6
|
+
export type { PublishChannel, SubscribeChannel, Message, MessageHandler, Publisher, SubscriptionErrorHandler, SubscriptionHandler, SubscriptionOptions, UnsubscribeOptions, };
|
|
7
7
|
export { RealtimeError, RealtimeErrorCode };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PublishChannel } from '@wix/realtime-common/types';
|
|
2
2
|
import type { HttpClient } from '@wix/sdk-types';
|
|
3
3
|
interface PublishSignature {
|
|
4
|
-
(channel:
|
|
4
|
+
(channel: PublishChannel, payload: Record<string, any>): Promise<void>;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Publish a message to a channel.
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import { RealtimeError, type Channel } from '@wix/realtime-common/types';
|
|
1
|
+
import { RealtimeError, type PublishChannel, type Channel, type SubscribeChannel } from '@wix/realtime-common/types';
|
|
2
2
|
export declare function missingChannelOrSubscriptionId(): RealtimeError;
|
|
3
3
|
export declare function channelMismatch(): RealtimeError;
|
|
4
|
+
export declare function channelAppIdMismatch(passedAppId: string, subscribedAppId: string): RealtimeError;
|
|
5
|
+
export declare function unsubscribeRequiresAppId(channel: PublishChannel, crossAppIds: string[]): RealtimeError;
|
|
6
|
+
export declare function unknownChannelAppId(channel: SubscribeChannel, existingAppIds: string[]): RealtimeError;
|
|
4
7
|
export declare function invalidChannel(channel: Channel): RealtimeError;
|
|
5
8
|
export declare function validateChannel(channel: Channel): void;
|
|
6
9
|
export declare function disconnectedError(recoverable?: boolean, message?: string): RealtimeError;
|
|
7
10
|
export declare function connectError(recoverable?: boolean, message?: string): RealtimeError;
|
|
8
|
-
export declare function subscribeFailed(channel:
|
|
11
|
+
export declare function subscribeFailed(channel: SubscribeChannel, payload?: {
|
|
9
12
|
status?: number;
|
|
10
13
|
message?: string;
|
|
11
14
|
}): RealtimeError;
|
|
12
|
-
export declare function resubscribeFailed(channel:
|
|
15
|
+
export declare function resubscribeFailed(channel: SubscribeChannel, payload?: {
|
|
13
16
|
status?: number;
|
|
14
17
|
message?: string;
|
|
15
18
|
}): RealtimeError;
|
|
16
|
-
export declare function subscribeError(error: unknown, channel:
|
|
19
|
+
export declare function subscribeError(error: unknown, channel: SubscribeChannel): RealtimeError;
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.missingChannelOrSubscriptionId = missingChannelOrSubscriptionId;
|
|
4
4
|
exports.channelMismatch = channelMismatch;
|
|
5
|
+
exports.channelAppIdMismatch = channelAppIdMismatch;
|
|
6
|
+
exports.unsubscribeRequiresAppId = unsubscribeRequiresAppId;
|
|
7
|
+
exports.unknownChannelAppId = unknownChannelAppId;
|
|
5
8
|
exports.invalidChannel = invalidChannel;
|
|
6
9
|
exports.validateChannel = validateChannel;
|
|
7
10
|
exports.disconnectedError = disconnectedError;
|
|
@@ -10,13 +13,33 @@ exports.subscribeFailed = subscribeFailed;
|
|
|
10
13
|
exports.resubscribeFailed = resubscribeFailed;
|
|
11
14
|
exports.subscribeError = subscribeError;
|
|
12
15
|
const types_1 = require("@wix/realtime-common/types");
|
|
16
|
+
const realtime_common_1 = require("@wix/realtime-common");
|
|
13
17
|
function missingChannelOrSubscriptionId() {
|
|
14
18
|
return new types_1.RealtimeError(types_1.RealtimeErrorCode.BadInput, 'channel or subscriptionId is required');
|
|
15
19
|
}
|
|
16
20
|
function channelMismatch() {
|
|
17
21
|
return new types_1.RealtimeError(types_1.RealtimeErrorCode.BadInput, 'channel does not match subscriptionId');
|
|
18
22
|
}
|
|
19
|
-
|
|
23
|
+
function channelAppIdMismatch(passedAppId, subscribedAppId) {
|
|
24
|
+
return new types_1.RealtimeError(types_1.RealtimeErrorCode.BadInput, `channel.appId "${passedAppId}" does not match subscription (subscribed with appId "${subscribedAppId}")`);
|
|
25
|
+
}
|
|
26
|
+
function unsubscribeRequiresAppId(channel, crossAppIds) {
|
|
27
|
+
const target = channel.resourceId
|
|
28
|
+
? `"${channel.name}" / "${channel.resourceId}"`
|
|
29
|
+
: `"${channel.name}"`;
|
|
30
|
+
return new types_1.RealtimeError(types_1.RealtimeErrorCode.BadInput, `Unsubscribe on ${target} requires channel.appId because the matching subscription(s) were opened cross-app to ${crossAppIds
|
|
31
|
+
.map((id) => `"${id}"`)
|
|
32
|
+
.join(', ')}. Pass channel.appId to scope the removal.`);
|
|
33
|
+
}
|
|
34
|
+
function unknownChannelAppId(channel, existingAppIds) {
|
|
35
|
+
const target = channel.resourceId
|
|
36
|
+
? `"${channel.name}" / "${channel.resourceId}"`
|
|
37
|
+
: `"${channel.name}"`;
|
|
38
|
+
const knownAppIds = existingAppIds.length
|
|
39
|
+
? existingAppIds.map((id) => `"${id}"`).join(', ')
|
|
40
|
+
: '(none)';
|
|
41
|
+
return new types_1.RealtimeError(types_1.RealtimeErrorCode.BadInput, `No subscription on ${target} matches channel.appId "${channel.appId}". Existing subscriptions on this channel are scoped to ${knownAppIds}.`);
|
|
42
|
+
}
|
|
20
43
|
function invalidChannel(channel) {
|
|
21
44
|
const { name, resourceId } = channel;
|
|
22
45
|
const reasons = [];
|
|
@@ -7,7 +7,7 @@ import type { BuildRESTFunction, MaybeContext } from '@wix/sdk-types';
|
|
|
7
7
|
*
|
|
8
8
|
* Use the `options` parameter to register handlers that run whenever the subscription succeeds or generates an error. For some errors, the subscription is re-attempted automatically. The `onSubscribed()` handler runs on every successful re-subscription.
|
|
9
9
|
*
|
|
10
|
-
* Learn more about the [subscription lifecycle](https://dev.wix.com/docs/sdk/
|
|
10
|
+
* Learn more about the [subscription lifecycle](https://dev.wix.com/docs/sdk/core-modules/realtime/realtime/subscriber/introduction#core-modules_realtime_realtime_subscriber_subscription-lifecycle).
|
|
11
11
|
*
|
|
12
12
|
* @example Subscribe to a channel
|
|
13
13
|
* ```ts
|
|
@@ -50,7 +50,7 @@ import type { BuildRESTFunction, MaybeContext } from '@wix/sdk-types';
|
|
|
50
50
|
* @requiredField channel
|
|
51
51
|
* @param messageHandler - Handler that runs whenever a message is published to the channel or resource.
|
|
52
52
|
* @requiredField messageHandler
|
|
53
|
-
* @param options - [Lifecycle handlers](https://dev.wix.com/docs/sdk/
|
|
53
|
+
* @param options - [Lifecycle handlers](https://dev.wix.com/docs/sdk/core-modules/realtime/realtime/subscriber/introduction#core-modules_realtime_realtime_subscriber_subscription-lifecycle) for subscription events.
|
|
54
54
|
*/
|
|
55
55
|
export declare const subscribe: MaybeContext<BuildRESTFunction<typeof publicSubscribe> & typeof publicSubscribe>;
|
|
56
56
|
/**
|
|
@@ -10,7 +10,7 @@ const rest_modules_1 = require("@wix/sdk-runtime/rest-modules");
|
|
|
10
10
|
*
|
|
11
11
|
* Use the `options` parameter to register handlers that run whenever the subscription succeeds or generates an error. For some errors, the subscription is re-attempted automatically. The `onSubscribed()` handler runs on every successful re-subscription.
|
|
12
12
|
*
|
|
13
|
-
* Learn more about the [subscription lifecycle](https://dev.wix.com/docs/sdk/
|
|
13
|
+
* Learn more about the [subscription lifecycle](https://dev.wix.com/docs/sdk/core-modules/realtime/realtime/subscriber/introduction#core-modules_realtime_realtime_subscriber_subscription-lifecycle).
|
|
14
14
|
*
|
|
15
15
|
* @example Subscribe to a channel
|
|
16
16
|
* ```ts
|
|
@@ -53,7 +53,7 @@ const rest_modules_1 = require("@wix/sdk-runtime/rest-modules");
|
|
|
53
53
|
* @requiredField channel
|
|
54
54
|
* @param messageHandler - Handler that runs whenever a message is published to the channel or resource.
|
|
55
55
|
* @requiredField messageHandler
|
|
56
|
-
* @param options - [Lifecycle handlers](https://dev.wix.com/docs/sdk/
|
|
56
|
+
* @param options - [Lifecycle handlers](https://dev.wix.com/docs/sdk/core-modules/realtime/realtime/subscriber/introduction#core-modules_realtime_realtime_subscriber_subscription-lifecycle) for subscription events.
|
|
57
57
|
*/
|
|
58
58
|
exports.subscribe = (0, rest_modules_1.createRESTModule)(subscriber_public_js_1.subscribe);
|
|
59
59
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type SubscribeChannel, type MessageHandler, type SubscriptionOptions, type UnsubscribeOptions } from '@wix/realtime-common/types';
|
|
2
2
|
import type { HttpClient } from '@wix/sdk-types';
|
|
3
3
|
interface SubscribeSignature {
|
|
4
|
-
(channel:
|
|
4
|
+
(channel: SubscribeChannel, messageHandler: MessageHandler, options?: SubscriptionOptions): string;
|
|
5
5
|
}
|
|
6
6
|
export declare function subscribe(httpClient: HttpClient): SubscribeSignature;
|
|
7
7
|
interface UnsubscribeSignature {
|
|
@@ -10,6 +10,9 @@ const channel_utils_js_1 = require("../channel-utils.js");
|
|
|
10
10
|
const constants_js_1 = require("../constants.js");
|
|
11
11
|
const errors_js_1 = require("./errors.js");
|
|
12
12
|
const subscription_manager_js_1 = require("./subscription-manager.js");
|
|
13
|
+
function socketKey(socketAppId, siteId) {
|
|
14
|
+
return `${socketAppId}:${siteId}`;
|
|
15
|
+
}
|
|
13
16
|
const instanceConnections = new Map();
|
|
14
17
|
const subscriptionManager = new subscription_manager_js_1.SubscriptionManager();
|
|
15
18
|
function subscribe(httpClient) {
|
|
@@ -19,6 +22,8 @@ function subscribe(httpClient) {
|
|
|
19
22
|
subscriptionManager.set(subscriptionId, {
|
|
20
23
|
channelName: channel.name,
|
|
21
24
|
channelResourceId: channel.resourceId,
|
|
25
|
+
maybeCrossAppId: channel.appId,
|
|
26
|
+
socketAppId: channel.appId,
|
|
22
27
|
removeListeners: () => { },
|
|
23
28
|
onSubscribed: options?.onSubscribed,
|
|
24
29
|
onSubscriptionError: options?.onSubscriptionError,
|
|
@@ -55,57 +60,92 @@ function unsubscribeById(subscriptionId, channel) {
|
|
|
55
60
|
if (!subscription) {
|
|
56
61
|
return;
|
|
57
62
|
}
|
|
58
|
-
if (channel
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
if (channel) {
|
|
64
|
+
const channelNameMismatch = channel.name !== undefined && channel.name !== subscription.channelName;
|
|
65
|
+
const channelResourceIdMismatch = channel.resourceId !== undefined &&
|
|
66
|
+
channel.resourceId !== subscription.channelResourceId;
|
|
67
|
+
if (channelNameMismatch || channelResourceIdMismatch) {
|
|
68
|
+
throw (0, errors_js_1.channelMismatch)();
|
|
69
|
+
}
|
|
70
|
+
const appIdMismatch = channel.appId !== undefined &&
|
|
71
|
+
subscription.socketAppId !== undefined &&
|
|
72
|
+
channel.appId !== subscription.socketAppId;
|
|
73
|
+
if (appIdMismatch) {
|
|
74
|
+
throw (0, errors_js_1.channelAppIdMismatch)(channel.appId, subscription.socketAppId);
|
|
75
|
+
}
|
|
62
76
|
}
|
|
63
77
|
subscription.removeListeners();
|
|
64
|
-
const { channelName, channelResourceId,
|
|
65
|
-
|
|
66
|
-
// cancelled so the in-flight setupSubscription knows to bail out.
|
|
67
|
-
if (!channelEmitter || !instanceId) {
|
|
78
|
+
const { channelName, channelResourceId, socketAppId, siteId, channelEmitter, } = subscription;
|
|
79
|
+
if (!channelEmitter || !socketAppId || !siteId) {
|
|
68
80
|
subscription.cancelled = true;
|
|
69
81
|
subscriptionManager.delete(subscriptionId);
|
|
70
|
-
if (
|
|
71
|
-
cleanupConnectionIfIdle(
|
|
82
|
+
if (socketAppId && siteId) {
|
|
83
|
+
cleanupConnectionIfIdle(socketAppId, siteId);
|
|
72
84
|
}
|
|
73
85
|
return;
|
|
74
86
|
}
|
|
75
87
|
// If no other subscriptions remain on this channel, fire-and-forget
|
|
76
88
|
// the duplexer unsubscribe.
|
|
77
|
-
const hasOtherSubscriptionsOnChannel = subscriptionManager.deleteAndStillHasRemainingOnChannel(
|
|
89
|
+
const hasOtherSubscriptionsOnChannel = subscriptionManager.deleteAndStillHasRemainingOnChannel(socketAppId, siteId, subscriptionId, channelName, channelResourceId);
|
|
78
90
|
if (!hasOtherSubscriptionsOnChannel) {
|
|
79
|
-
const conn = instanceConnections.get(
|
|
91
|
+
const conn = instanceConnections.get(socketKey(socketAppId, siteId));
|
|
80
92
|
if (conn) {
|
|
81
93
|
conn.socket.unsubscribe(channelName, channelResourceId);
|
|
82
94
|
}
|
|
83
95
|
}
|
|
84
|
-
cleanupConnectionIfIdle(
|
|
96
|
+
cleanupConnectionIfIdle(socketAppId, siteId);
|
|
97
|
+
}
|
|
98
|
+
function distinctDefined(items, pickItemFunction) {
|
|
99
|
+
const out = new Set();
|
|
100
|
+
for (const item of items) {
|
|
101
|
+
const v = pickItemFunction(item);
|
|
102
|
+
if (v !== undefined)
|
|
103
|
+
out.add(v);
|
|
104
|
+
}
|
|
105
|
+
return [...out];
|
|
85
106
|
}
|
|
86
107
|
function unsubscribeByChannel(channel) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
108
|
+
const matches = subscriptionManager.findByChannel(channel.name, channel.resourceId);
|
|
109
|
+
if (matches.length === 0) {
|
|
110
|
+
return;
|
|
90
111
|
}
|
|
112
|
+
if (channel.appId === undefined) {
|
|
113
|
+
const sameAppMatches = matches.filter(([, sub]) => sub.maybeCrossAppId === undefined);
|
|
114
|
+
if (sameAppMatches.length === 0) {
|
|
115
|
+
const crossAppIds = distinctDefined(matches, ([, sub]) => sub.maybeCrossAppId);
|
|
116
|
+
throw (0, errors_js_1.unsubscribeRequiresAppId)(channel, crossAppIds);
|
|
117
|
+
}
|
|
118
|
+
for (const [id] of sameAppMatches)
|
|
119
|
+
unsubscribeById(id);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// appId passed: scope to subs whose socket lives in that namespace.
|
|
123
|
+
const scoped = matches.filter(([, sub]) => sub.socketAppId === channel.appId);
|
|
124
|
+
if (scoped.length === 0) {
|
|
125
|
+
const existingAppIds = distinctDefined(matches, ([, sub]) => sub.socketAppId);
|
|
126
|
+
throw (0, errors_js_1.unknownChannelAppId)(channel, existingAppIds);
|
|
127
|
+
}
|
|
128
|
+
for (const [id] of scoped)
|
|
129
|
+
unsubscribeById(id);
|
|
91
130
|
}
|
|
92
|
-
function closeConnection(
|
|
93
|
-
const
|
|
131
|
+
function closeConnection(socketAppId, siteId) {
|
|
132
|
+
const key = socketKey(socketAppId, siteId);
|
|
133
|
+
const conn = instanceConnections.get(key);
|
|
94
134
|
if (conn) {
|
|
95
135
|
conn.socket.removeAllListeners();
|
|
96
136
|
conn.socket.disconnect();
|
|
97
137
|
conn.duplexer.close();
|
|
98
|
-
instanceConnections.delete(
|
|
138
|
+
instanceConnections.delete(key);
|
|
99
139
|
}
|
|
100
140
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
closeConnection(instanceId);
|
|
141
|
+
function cleanupConnectionIfIdle(socketAppId, siteId) {
|
|
142
|
+
if (!subscriptionManager.hasSubscriptionsForSocket(socketAppId, siteId)) {
|
|
143
|
+
closeConnection(socketAppId, siteId);
|
|
105
144
|
}
|
|
106
145
|
}
|
|
107
|
-
function getOrCreateConnection(httpClient,
|
|
108
|
-
const
|
|
146
|
+
function getOrCreateConnection(httpClient, socketAppId, siteId) {
|
|
147
|
+
const key = socketKey(socketAppId, siteId);
|
|
148
|
+
const existing = instanceConnections.get(key);
|
|
109
149
|
if (existing) {
|
|
110
150
|
return existing;
|
|
111
151
|
}
|
|
@@ -115,10 +155,10 @@ function getOrCreateConnection(httpClient, appId, instanceId) {
|
|
|
115
155
|
},
|
|
116
156
|
});
|
|
117
157
|
const socket = duplexer.connect({
|
|
118
|
-
appDefId:
|
|
158
|
+
appDefId: socketAppId,
|
|
119
159
|
});
|
|
120
160
|
const notifySubscriptionError = (realtimeError) => {
|
|
121
|
-
for (const subId of subscriptionManager.
|
|
161
|
+
for (const subId of subscriptionManager.getSubscriptionIdsBySocket(socketAppId, siteId)) {
|
|
122
162
|
subscriptionManager
|
|
123
163
|
.get(subId)
|
|
124
164
|
?.onSubscriptionError?.(realtimeError, subId);
|
|
@@ -131,15 +171,21 @@ function getOrCreateConnection(httpClient, appId, instanceId) {
|
|
|
131
171
|
notifySubscriptionError((0, errors_js_1.connectError)(error?.recoverable, error?.message));
|
|
132
172
|
});
|
|
133
173
|
const connection = { duplexer, socket };
|
|
134
|
-
instanceConnections.set(
|
|
174
|
+
instanceConnections.set(key, connection);
|
|
135
175
|
return connection;
|
|
136
176
|
}
|
|
137
177
|
async function setupSubscription(httpClient, subscriptionId, channel, messageHandler) {
|
|
138
178
|
try {
|
|
139
|
-
const [{ appId,
|
|
179
|
+
const [{ appId: callerAppId, siteId }, duplexerChannelName] = await Promise.all([
|
|
140
180
|
(0, realtime_common_1.getAppInfoFromAuthToken)(httpClient),
|
|
141
181
|
(0, channel_utils_js_1.resolveDuplexerChannelName)(channel),
|
|
142
182
|
]);
|
|
183
|
+
const socketAppId = channel.appId ?? callerAppId;
|
|
184
|
+
const maybeCrossAppId = channel.appId === callerAppId ? undefined : channel.appId;
|
|
185
|
+
channel = {
|
|
186
|
+
...channel,
|
|
187
|
+
appId: socketAppId,
|
|
188
|
+
};
|
|
143
189
|
const subscriptionEntry = subscriptionManager.get(subscriptionId);
|
|
144
190
|
// Entry was already deleted (e.g., unsubscribe called during the await)
|
|
145
191
|
// or explicitly cancelled — bail out.
|
|
@@ -147,13 +193,13 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
147
193
|
subscriptionManager.delete(subscriptionId);
|
|
148
194
|
return;
|
|
149
195
|
}
|
|
150
|
-
// Index the subscription by instanceId now so cleanupConnectionIfIdle
|
|
151
|
-
// correctly counts it while the duplexer subscription is being set up.
|
|
152
196
|
subscriptionManager.set(subscriptionId, {
|
|
153
197
|
...subscriptionEntry,
|
|
154
|
-
|
|
198
|
+
maybeCrossAppId,
|
|
199
|
+
socketAppId,
|
|
200
|
+
siteId,
|
|
155
201
|
});
|
|
156
|
-
const { socket } = getOrCreateConnection(httpClient,
|
|
202
|
+
const { socket } = getOrCreateConnection(httpClient, socketAppId, siteId);
|
|
157
203
|
const onMessageCallback = (payload, { publisher }) => {
|
|
158
204
|
messageHandler({
|
|
159
205
|
payload,
|
|
@@ -168,7 +214,7 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
168
214
|
// server-side subscription leak.
|
|
169
215
|
if (!subscriptionManager.get(subscriptionId)) {
|
|
170
216
|
socket.unsubscribe(duplexerChannelName, channel.resourceId);
|
|
171
|
-
cleanupConnectionIfIdle(
|
|
217
|
+
cleanupConnectionIfIdle(socketAppId, siteId);
|
|
172
218
|
return;
|
|
173
219
|
}
|
|
174
220
|
subscribedChannel.on(realtime_common_1.MESSAGE_EVENT_NAME, onMessageCallback);
|
|
@@ -196,7 +242,9 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
196
242
|
subscriptionManager.set(subscriptionId, {
|
|
197
243
|
channelName: channel.name,
|
|
198
244
|
channelResourceId: channel.resourceId,
|
|
199
|
-
|
|
245
|
+
maybeCrossAppId,
|
|
246
|
+
socketAppId,
|
|
247
|
+
siteId,
|
|
200
248
|
channelEmitter: subscribedChannel,
|
|
201
249
|
onSubscribed: currentEntry?.onSubscribed,
|
|
202
250
|
onSubscriptionError: currentEntry?.onSubscriptionError,
|
|
@@ -212,7 +260,7 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
212
260
|
const failedEntry = subscriptionManager.get(subscriptionId);
|
|
213
261
|
subscriptionManager.delete(subscriptionId);
|
|
214
262
|
failedEntry?.onSubscriptionError?.((0, errors_js_1.subscribeFailed)(channel, payload), subscriptionId);
|
|
215
|
-
cleanupConnectionIfIdle(
|
|
263
|
+
cleanupConnectionIfIdle(socketAppId, siteId);
|
|
216
264
|
}
|
|
217
265
|
// Subscribe to the duplexer channel and register lifecycle listeners
|
|
218
266
|
// in the same synchronous block so no events can be missed.
|
|
@@ -3,7 +3,9 @@ import type { SubscriptionHandler, SubscriptionErrorHandler } from '@wix/realtim
|
|
|
3
3
|
export interface SubscriptionEntry {
|
|
4
4
|
channelName: string;
|
|
5
5
|
channelResourceId?: string;
|
|
6
|
-
|
|
6
|
+
maybeCrossAppId?: string;
|
|
7
|
+
siteId?: string;
|
|
8
|
+
socketAppId?: string;
|
|
7
9
|
channelEmitter?: ReturnType<ReturnType<Duplexer['connect']>['subscribe']>;
|
|
8
10
|
removeListeners: () => void;
|
|
9
11
|
cancelled?: boolean;
|
|
@@ -12,15 +14,15 @@ export interface SubscriptionEntry {
|
|
|
12
14
|
}
|
|
13
15
|
export declare class SubscriptionManager {
|
|
14
16
|
private subscriptionsBySubId;
|
|
15
|
-
private
|
|
17
|
+
private socketKeyToSubscriptionIds;
|
|
16
18
|
set(id: string, entry: SubscriptionEntry): void;
|
|
17
19
|
get(id: string): SubscriptionEntry | undefined;
|
|
18
20
|
delete(id: string): void;
|
|
19
21
|
findByChannel(channelName: string, channelResourceId?: string): [string, SubscriptionEntry][];
|
|
20
|
-
deleteAndStillHasRemainingOnChannel(
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
deleteAndStillHasRemainingOnChannel(socketAppId: string, siteId: string, subscriptionIdToDelete: string, channelName: string, resourceId?: string): boolean;
|
|
23
|
+
hasSubscriptionsForSocket(socketAppId: string, siteId: string): boolean;
|
|
24
|
+
getSubscriptionIdsBySocket(socketAppId: string, siteId: string): string[];
|
|
23
25
|
removeAll(): void;
|
|
24
|
-
private
|
|
25
|
-
private
|
|
26
|
+
private addToSocketIndex;
|
|
27
|
+
private removeFromSocketIndex;
|
|
26
28
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SubscriptionManager = void 0;
|
|
4
|
+
function socketKey(socketAppId, siteId) {
|
|
5
|
+
return `${socketAppId}:${siteId}`;
|
|
6
|
+
}
|
|
4
7
|
class SubscriptionManager {
|
|
5
8
|
subscriptionsBySubId = new Map();
|
|
6
|
-
|
|
9
|
+
socketKeyToSubscriptionIds = new Map();
|
|
7
10
|
set(id, entry) {
|
|
8
11
|
this.subscriptionsBySubId.set(id, entry);
|
|
9
|
-
if (entry.
|
|
10
|
-
this.
|
|
12
|
+
if (entry.socketAppId && entry.siteId) {
|
|
13
|
+
this.addToSocketIndex(socketKey(entry.socketAppId, entry.siteId), id);
|
|
11
14
|
}
|
|
12
15
|
}
|
|
13
16
|
get(id) {
|
|
@@ -15,8 +18,8 @@ class SubscriptionManager {
|
|
|
15
18
|
}
|
|
16
19
|
delete(id) {
|
|
17
20
|
const entry = this.subscriptionsBySubId.get(id);
|
|
18
|
-
if (entry?.
|
|
19
|
-
this.
|
|
21
|
+
if (entry?.socketAppId && entry.siteId) {
|
|
22
|
+
this.removeFromSocketIndex(socketKey(entry.socketAppId, entry.siteId), id);
|
|
20
23
|
}
|
|
21
24
|
this.subscriptionsBySubId.delete(id);
|
|
22
25
|
}
|
|
@@ -24,9 +27,9 @@ class SubscriptionManager {
|
|
|
24
27
|
return [...this.subscriptionsBySubId.entries()].filter(([, sub]) => sub.channelName === channelName &&
|
|
25
28
|
sub.channelResourceId === channelResourceId);
|
|
26
29
|
}
|
|
27
|
-
deleteAndStillHasRemainingOnChannel(
|
|
30
|
+
deleteAndStillHasRemainingOnChannel(socketAppId, siteId, subscriptionIdToDelete, channelName, resourceId) {
|
|
28
31
|
this.delete(subscriptionIdToDelete);
|
|
29
|
-
const candidateIds = this.
|
|
32
|
+
const candidateIds = this.socketKeyToSubscriptionIds.get(socketKey(socketAppId, siteId));
|
|
30
33
|
if (!candidateIds)
|
|
31
34
|
return false;
|
|
32
35
|
for (const id of candidateIds) {
|
|
@@ -39,12 +42,12 @@ class SubscriptionManager {
|
|
|
39
42
|
}
|
|
40
43
|
return false;
|
|
41
44
|
}
|
|
42
|
-
|
|
43
|
-
const ids = this.
|
|
45
|
+
hasSubscriptionsForSocket(socketAppId, siteId) {
|
|
46
|
+
const ids = this.socketKeyToSubscriptionIds.get(socketKey(socketAppId, siteId));
|
|
44
47
|
return !!ids && ids.size > 0;
|
|
45
48
|
}
|
|
46
|
-
|
|
47
|
-
const ids = this.
|
|
49
|
+
getSubscriptionIdsBySocket(socketAppId, siteId) {
|
|
50
|
+
const ids = this.socketKeyToSubscriptionIds.get(socketKey(socketAppId, siteId));
|
|
48
51
|
return ids ? [...ids] : [];
|
|
49
52
|
}
|
|
50
53
|
removeAll() {
|
|
@@ -52,22 +55,22 @@ class SubscriptionManager {
|
|
|
52
55
|
sub.removeListeners();
|
|
53
56
|
}
|
|
54
57
|
this.subscriptionsBySubId.clear();
|
|
55
|
-
this.
|
|
58
|
+
this.socketKeyToSubscriptionIds.clear();
|
|
56
59
|
}
|
|
57
|
-
|
|
58
|
-
let ids = this.
|
|
60
|
+
addToSocketIndex(key, id) {
|
|
61
|
+
let ids = this.socketKeyToSubscriptionIds.get(key);
|
|
59
62
|
if (!ids) {
|
|
60
63
|
ids = new Set();
|
|
61
|
-
this.
|
|
64
|
+
this.socketKeyToSubscriptionIds.set(key, ids);
|
|
62
65
|
}
|
|
63
66
|
ids.add(id);
|
|
64
67
|
}
|
|
65
|
-
|
|
66
|
-
const ids = this.
|
|
68
|
+
removeFromSocketIndex(key, id) {
|
|
69
|
+
const ids = this.socketKeyToSubscriptionIds.get(key);
|
|
67
70
|
if (ids) {
|
|
68
71
|
ids.delete(id);
|
|
69
72
|
if (ids.size === 0) {
|
|
70
|
-
this.
|
|
73
|
+
this.socketKeyToSubscriptionIds.delete(key);
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
}
|
package/cjs/build/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { RealtimeErrorCode, RealtimeError, type
|
|
1
|
+
export { RealtimeErrorCode, RealtimeError, type PublishChannel, type SubscribeChannel, type Publisher, type Message, type MessageHandler, type SubscriptionHandler, type SubscriptionErrorHandler, type SubscriptionOptions, type UnsubscribeOptions, } from '@wix/realtime-common/types';
|