@wix/realtime 1.0.58 → 1.0.60
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/publisher/publisher.context.d.ts +3 -2
- package/cjs/build/publisher/publisher.context.js +3 -2
- package/cjs/build/subscriber/errors.d.ts +1 -0
- package/cjs/build/subscriber/errors.js +10 -0
- package/cjs/build/subscriber/subscriber.public.js +14 -0
- package/dist/statics/docs-ts-model.json +4 -4
- package/es/build/publisher/publisher.context.d.ts +3 -2
- package/es/build/publisher/publisher.context.js +3 -2
- package/es/build/subscriber/errors.d.ts +1 -0
- package/es/build/subscriber/errors.js +9 -0
- package/es/build/subscriber/subscriber.public.js +15 -1
- package/package.json +3 -3
|
@@ -17,7 +17,8 @@ export type { PublishChannel } from '@wix/realtime-common/types';
|
|
|
17
17
|
* import { publisher } from '@wix/realtime';
|
|
18
18
|
* import { elevate } from '@wix/sdk/context';
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* const elevatedPublish = elevate(publisher.publish);
|
|
21
|
+
* await elevatedPublish({ name: 'my-channel' }, { text: 'hello' });
|
|
21
22
|
* ```
|
|
22
23
|
*
|
|
23
24
|
* @example Publish a message to the specified channel: Self-hosted
|
|
@@ -33,7 +34,7 @@ export type { PublishChannel } from '@wix/realtime-common/types';
|
|
|
33
34
|
* // Include the auth strategy and host as relevant
|
|
34
35
|
* });
|
|
35
36
|
*
|
|
36
|
-
* await client.publisher.publish({ name: 'my-channel' }, {
|
|
37
|
+
* await client.publisher.publish({ name: 'my-channel' }, { text: 'hello' });
|
|
37
38
|
* ```
|
|
38
39
|
*
|
|
39
40
|
* @param channel - Channel and resource to publish to.
|
|
@@ -19,7 +19,8 @@ const rest_modules_1 = require("@wix/sdk-runtime/rest-modules");
|
|
|
19
19
|
* import { publisher } from '@wix/realtime';
|
|
20
20
|
* import { elevate } from '@wix/sdk/context';
|
|
21
21
|
*
|
|
22
|
-
*
|
|
22
|
+
* const elevatedPublish = elevate(publisher.publish);
|
|
23
|
+
* await elevatedPublish({ name: 'my-channel' }, { text: 'hello' });
|
|
23
24
|
* ```
|
|
24
25
|
*
|
|
25
26
|
* @example Publish a message to the specified channel: Self-hosted
|
|
@@ -35,7 +36,7 @@ const rest_modules_1 = require("@wix/sdk-runtime/rest-modules");
|
|
|
35
36
|
* // Include the auth strategy and host as relevant
|
|
36
37
|
* });
|
|
37
38
|
*
|
|
38
|
-
* await client.publisher.publish({ name: 'my-channel' }, {
|
|
39
|
+
* await client.publisher.publish({ name: 'my-channel' }, { text: 'hello' });
|
|
39
40
|
* ```
|
|
40
41
|
*
|
|
41
42
|
* @param channel - Channel and resource to publish to.
|
|
@@ -8,6 +8,7 @@ export declare function invalidChannel(channel: Channel): RealtimeError;
|
|
|
8
8
|
export declare function validateChannel(channel: Channel): void;
|
|
9
9
|
export declare function disconnectedError(recoverable?: boolean, message?: string): RealtimeError;
|
|
10
10
|
export declare function connectError(recoverable?: boolean, message?: string): RealtimeError;
|
|
11
|
+
export declare function subscribeTimedOut(channel: SubscribeChannel, timeoutMs: number): RealtimeError;
|
|
11
12
|
export declare function subscribeFailed(channel: SubscribeChannel, payload?: {
|
|
12
13
|
status?: number;
|
|
13
14
|
message?: string;
|
|
@@ -9,6 +9,7 @@ exports.invalidChannel = invalidChannel;
|
|
|
9
9
|
exports.validateChannel = validateChannel;
|
|
10
10
|
exports.disconnectedError = disconnectedError;
|
|
11
11
|
exports.connectError = connectError;
|
|
12
|
+
exports.subscribeTimedOut = subscribeTimedOut;
|
|
12
13
|
exports.subscribeFailed = subscribeFailed;
|
|
13
14
|
exports.resubscribeFailed = resubscribeFailed;
|
|
14
15
|
exports.subscribeError = subscribeError;
|
|
@@ -72,6 +73,15 @@ function disconnectedError(recoverable, message) {
|
|
|
72
73
|
function connectError(recoverable, message) {
|
|
73
74
|
return new types_1.RealtimeError(types_1.RealtimeErrorCode.ConnectionError, message || 'connection error', { recoverable });
|
|
74
75
|
}
|
|
76
|
+
function subscribeTimedOut(channel, timeoutMs) {
|
|
77
|
+
const target = channel.resourceId
|
|
78
|
+
? `"${channel.name}" / "${channel.resourceId}"`
|
|
79
|
+
: `"${channel.name}"`;
|
|
80
|
+
return new types_1.RealtimeError(types_1.RealtimeErrorCode.ConnectionError, `Subscription to ${target} did not connect within ${timeoutMs}ms. The realtime ` +
|
|
81
|
+
`socket has not been established — commonly a page served over http:// dialing ` +
|
|
82
|
+
`ws:// to a TLS-only host, or a blocked/offline network. The client keeps retrying, ` +
|
|
83
|
+
`so this may still succeed.`, { channel, recoverable: true });
|
|
84
|
+
}
|
|
75
85
|
function subscriptionFailed(prefix, channel, payload) {
|
|
76
86
|
let msg = `${prefix} failed`;
|
|
77
87
|
if (payload?.message) {
|
|
@@ -143,6 +143,8 @@ function cleanupConnectionIfIdle(socketAppId, siteId) {
|
|
|
143
143
|
closeConnection(socketAppId, siteId);
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
+
// Surface a stalled initial subscription after this long, via onSubscriptionError.
|
|
147
|
+
const SUBSCRIBE_TIMEOUT_MS = 10_000;
|
|
146
148
|
function getOrCreateConnection(httpClient, socketAppId, siteId) {
|
|
147
149
|
const key = socketKey(socketAppId, siteId);
|
|
148
150
|
const existing = instanceConnections.get(key);
|
|
@@ -206,8 +208,11 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
206
208
|
publisher: publisher?.uid ? { id: publisher.uid } : undefined,
|
|
207
209
|
}, channel);
|
|
208
210
|
};
|
|
211
|
+
// Cleared on subscribe success/failure; armed just after subscribe below.
|
|
212
|
+
let subscribeTimeout;
|
|
209
213
|
// --- callback definitions (hoisted above subscribe for #6 race fix) ---
|
|
210
214
|
function onSubscribeSucceeded(payload) {
|
|
215
|
+
clearTimeout(subscribeTimeout);
|
|
211
216
|
subscribedChannel.off(realtime_common_1.DUPLEXER_EVENTS.subscriptionFailed, onSubscribeFailed);
|
|
212
217
|
// If the subscription was removed (via unsubscribe) while waiting for
|
|
213
218
|
// the duplexer to confirm, clean up the duplexer channel to avoid a
|
|
@@ -256,6 +261,7 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
256
261
|
});
|
|
257
262
|
}
|
|
258
263
|
function onSubscribeFailed(payload) {
|
|
264
|
+
clearTimeout(subscribeTimeout);
|
|
259
265
|
subscribedChannel.off(realtime_common_1.DUPLEXER_EVENTS.subscriptionSucceeded, onSubscribeSucceeded);
|
|
260
266
|
const failedEntry = subscriptionManager.get(subscriptionId);
|
|
261
267
|
subscriptionManager.delete(subscriptionId);
|
|
@@ -269,6 +275,14 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
269
275
|
});
|
|
270
276
|
subscribedChannel.once(realtime_common_1.DUPLEXER_EVENTS.subscriptionSucceeded, onSubscribeSucceeded);
|
|
271
277
|
subscribedChannel.once(realtime_common_1.DUPLEXER_EVENTS.subscriptionFailed, onSubscribeFailed);
|
|
278
|
+
// If neither success nor failure fires in time, report a recoverable timeout
|
|
279
|
+
// but keep the subscription alive so a late connect can still succeed.
|
|
280
|
+
subscribeTimeout = setTimeout(() => {
|
|
281
|
+
const entry = subscriptionManager.get(subscriptionId);
|
|
282
|
+
if (entry && !entry.channelEmitter) {
|
|
283
|
+
entry.onSubscriptionError?.((0, errors_js_1.subscribeTimedOut)(channel, SUBSCRIBE_TIMEOUT_MS), subscriptionId);
|
|
284
|
+
}
|
|
285
|
+
}, SUBSCRIBE_TIMEOUT_MS);
|
|
272
286
|
}
|
|
273
287
|
catch (error) {
|
|
274
288
|
const sub = subscriptionManager.get(subscriptionId);
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"kind": "code",
|
|
128
|
-
"text": "```ts\nimport { publisher } from '@wix/realtime';\nimport { elevate } from '@wix/sdk/context';\n\
|
|
128
|
+
"text": "```ts\nimport { publisher } from '@wix/realtime';\nimport { elevate } from '@wix/sdk/context';\n\nconst elevatedPublish = elevate(publisher.publish);\nawait elevatedPublish({ name: 'my-channel' }, { text: 'hello' });\n```"
|
|
129
129
|
}
|
|
130
130
|
]
|
|
131
131
|
},
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"kind": "code",
|
|
141
|
-
"text": "```ts\nimport { publisher } from '@wix/realtime';\nimport { createClient } from '@wix/sdk';\n\n// Import the auth strategy for the relevant access type\n// Import the relevant host module if needed\n\nconst client = createClient({\n modules: { publisher },\n // Include the auth strategy and host as relevant\n});\n\nawait client.publisher.publish({ name: 'my-channel' }, {
|
|
141
|
+
"text": "```ts\nimport { publisher } from '@wix/realtime';\nimport { createClient } from '@wix/sdk';\n\n// Import the auth strategy for the relevant access type\n// Import the relevant host module if needed\n\nconst client = createClient({\n modules: { publisher },\n // Include the auth strategy and host as relevant\n});\n\nawait client.publisher.publish({ name: 'my-channel' }, { text: 'hello' });\n```"
|
|
142
142
|
}
|
|
143
143
|
]
|
|
144
144
|
},
|
|
@@ -285,7 +285,7 @@
|
|
|
285
285
|
},
|
|
286
286
|
{
|
|
287
287
|
"kind": "code",
|
|
288
|
-
"text": "```ts\nimport { publisher } from '@wix/realtime';\nimport { elevate } from '@wix/sdk/context';\n\
|
|
288
|
+
"text": "```ts\nimport { publisher } from '@wix/realtime';\nimport { elevate } from '@wix/sdk/context';\n\nconst elevatedPublish = elevate(publisher.publish);\nawait elevatedPublish({ name: 'my-channel' }, { text: 'hello' });\n```"
|
|
289
289
|
}
|
|
290
290
|
]
|
|
291
291
|
},
|
|
@@ -298,7 +298,7 @@
|
|
|
298
298
|
},
|
|
299
299
|
{
|
|
300
300
|
"kind": "code",
|
|
301
|
-
"text": "```ts\nimport { publisher } from '@wix/realtime';\nimport { createClient } from '@wix/sdk';\n\n// Import the auth strategy for the relevant access type\n// Import the relevant host module if needed\n\nconst client = createClient({\n modules: { publisher },\n // Include the auth strategy and host as relevant\n});\n\nawait client.publisher.publish({ name: 'my-channel' }, {
|
|
301
|
+
"text": "```ts\nimport { publisher } from '@wix/realtime';\nimport { createClient } from '@wix/sdk';\n\n// Import the auth strategy for the relevant access type\n// Import the relevant host module if needed\n\nconst client = createClient({\n modules: { publisher },\n // Include the auth strategy and host as relevant\n});\n\nawait client.publisher.publish({ name: 'my-channel' }, { text: 'hello' });\n```"
|
|
302
302
|
}
|
|
303
303
|
]
|
|
304
304
|
},
|
|
@@ -17,7 +17,8 @@ export type { PublishChannel } from '@wix/realtime-common/types';
|
|
|
17
17
|
* import { publisher } from '@wix/realtime';
|
|
18
18
|
* import { elevate } from '@wix/sdk/context';
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* const elevatedPublish = elevate(publisher.publish);
|
|
21
|
+
* await elevatedPublish({ name: 'my-channel' }, { text: 'hello' });
|
|
21
22
|
* ```
|
|
22
23
|
*
|
|
23
24
|
* @example Publish a message to the specified channel: Self-hosted
|
|
@@ -33,7 +34,7 @@ export type { PublishChannel } from '@wix/realtime-common/types';
|
|
|
33
34
|
* // Include the auth strategy and host as relevant
|
|
34
35
|
* });
|
|
35
36
|
*
|
|
36
|
-
* await client.publisher.publish({ name: 'my-channel' }, {
|
|
37
|
+
* await client.publisher.publish({ name: 'my-channel' }, { text: 'hello' });
|
|
37
38
|
* ```
|
|
38
39
|
*
|
|
39
40
|
* @param channel - Channel and resource to publish to.
|
|
@@ -16,7 +16,8 @@ import { createRESTModule } from '@wix/sdk-runtime/rest-modules';
|
|
|
16
16
|
* import { publisher } from '@wix/realtime';
|
|
17
17
|
* import { elevate } from '@wix/sdk/context';
|
|
18
18
|
*
|
|
19
|
-
*
|
|
19
|
+
* const elevatedPublish = elevate(publisher.publish);
|
|
20
|
+
* await elevatedPublish({ name: 'my-channel' }, { text: 'hello' });
|
|
20
21
|
* ```
|
|
21
22
|
*
|
|
22
23
|
* @example Publish a message to the specified channel: Self-hosted
|
|
@@ -32,7 +33,7 @@ import { createRESTModule } from '@wix/sdk-runtime/rest-modules';
|
|
|
32
33
|
* // Include the auth strategy and host as relevant
|
|
33
34
|
* });
|
|
34
35
|
*
|
|
35
|
-
* await client.publisher.publish({ name: 'my-channel' }, {
|
|
36
|
+
* await client.publisher.publish({ name: 'my-channel' }, { text: 'hello' });
|
|
36
37
|
* ```
|
|
37
38
|
*
|
|
38
39
|
* @param channel - Channel and resource to publish to.
|
|
@@ -8,6 +8,7 @@ export declare function invalidChannel(channel: Channel): RealtimeError;
|
|
|
8
8
|
export declare function validateChannel(channel: Channel): void;
|
|
9
9
|
export declare function disconnectedError(recoverable?: boolean, message?: string): RealtimeError;
|
|
10
10
|
export declare function connectError(recoverable?: boolean, message?: string): RealtimeError;
|
|
11
|
+
export declare function subscribeTimedOut(channel: SubscribeChannel, timeoutMs: number): RealtimeError;
|
|
11
12
|
export declare function subscribeFailed(channel: SubscribeChannel, payload?: {
|
|
12
13
|
status?: number;
|
|
13
14
|
message?: string;
|
|
@@ -58,6 +58,15 @@ export function disconnectedError(recoverable, message) {
|
|
|
58
58
|
export function connectError(recoverable, message) {
|
|
59
59
|
return new RealtimeError(RealtimeErrorCode.ConnectionError, message || 'connection error', { recoverable });
|
|
60
60
|
}
|
|
61
|
+
export function subscribeTimedOut(channel, timeoutMs) {
|
|
62
|
+
const target = channel.resourceId
|
|
63
|
+
? `"${channel.name}" / "${channel.resourceId}"`
|
|
64
|
+
: `"${channel.name}"`;
|
|
65
|
+
return new RealtimeError(RealtimeErrorCode.ConnectionError, `Subscription to ${target} did not connect within ${timeoutMs}ms. The realtime ` +
|
|
66
|
+
`socket has not been established — commonly a page served over http:// dialing ` +
|
|
67
|
+
`ws:// to a TLS-only host, or a blocked/offline network. The client keeps retrying, ` +
|
|
68
|
+
`so this may still succeed.`, { channel, recoverable: true });
|
|
69
|
+
}
|
|
61
70
|
function subscriptionFailed(prefix, channel, payload) {
|
|
62
71
|
let msg = `${prefix} failed`;
|
|
63
72
|
if (payload?.message) {
|
|
@@ -3,7 +3,7 @@ import { DUPLEXER_EVENTS, MESSAGE_EVENT_NAME, getAppInfoFromAuthToken, tokenToAp
|
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
4
|
import { resolveDuplexerChannelName } from '../channel-utils.js';
|
|
5
5
|
import { DUPLEXER_HOST_URL } from '../constants.js';
|
|
6
|
-
import { missingChannelOrSubscriptionId, channelMismatch, channelAppIdMismatch, unsubscribeRequiresAppId, unknownChannelAppId, disconnectedError, connectError, subscribeFailed, resubscribeFailed, subscribeError, validateChannel, } from './errors.js';
|
|
6
|
+
import { missingChannelOrSubscriptionId, channelMismatch, channelAppIdMismatch, unsubscribeRequiresAppId, unknownChannelAppId, disconnectedError, connectError, subscribeFailed, resubscribeFailed, subscribeError, subscribeTimedOut, validateChannel, } from './errors.js';
|
|
7
7
|
import { SubscriptionManager } from './subscription-manager.js';
|
|
8
8
|
function socketKey(socketAppId, siteId) {
|
|
9
9
|
return `${socketAppId}:${siteId}`;
|
|
@@ -138,6 +138,8 @@ function cleanupConnectionIfIdle(socketAppId, siteId) {
|
|
|
138
138
|
closeConnection(socketAppId, siteId);
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
+
// Surface a stalled initial subscription after this long, via onSubscriptionError.
|
|
142
|
+
const SUBSCRIBE_TIMEOUT_MS = 10_000;
|
|
141
143
|
function getOrCreateConnection(httpClient, socketAppId, siteId) {
|
|
142
144
|
const key = socketKey(socketAppId, siteId);
|
|
143
145
|
const existing = instanceConnections.get(key);
|
|
@@ -201,8 +203,11 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
201
203
|
publisher: publisher?.uid ? { id: publisher.uid } : undefined,
|
|
202
204
|
}, channel);
|
|
203
205
|
};
|
|
206
|
+
// Cleared on subscribe success/failure; armed just after subscribe below.
|
|
207
|
+
let subscribeTimeout;
|
|
204
208
|
// --- callback definitions (hoisted above subscribe for #6 race fix) ---
|
|
205
209
|
function onSubscribeSucceeded(payload) {
|
|
210
|
+
clearTimeout(subscribeTimeout);
|
|
206
211
|
subscribedChannel.off(DUPLEXER_EVENTS.subscriptionFailed, onSubscribeFailed);
|
|
207
212
|
// If the subscription was removed (via unsubscribe) while waiting for
|
|
208
213
|
// the duplexer to confirm, clean up the duplexer channel to avoid a
|
|
@@ -251,6 +256,7 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
251
256
|
});
|
|
252
257
|
}
|
|
253
258
|
function onSubscribeFailed(payload) {
|
|
259
|
+
clearTimeout(subscribeTimeout);
|
|
254
260
|
subscribedChannel.off(DUPLEXER_EVENTS.subscriptionSucceeded, onSubscribeSucceeded);
|
|
255
261
|
const failedEntry = subscriptionManager.get(subscriptionId);
|
|
256
262
|
subscriptionManager.delete(subscriptionId);
|
|
@@ -264,6 +270,14 @@ async function setupSubscription(httpClient, subscriptionId, channel, messageHan
|
|
|
264
270
|
});
|
|
265
271
|
subscribedChannel.once(DUPLEXER_EVENTS.subscriptionSucceeded, onSubscribeSucceeded);
|
|
266
272
|
subscribedChannel.once(DUPLEXER_EVENTS.subscriptionFailed, onSubscribeFailed);
|
|
273
|
+
// If neither success nor failure fires in time, report a recoverable timeout
|
|
274
|
+
// but keep the subscription alive so a late connect can still succeed.
|
|
275
|
+
subscribeTimeout = setTimeout(() => {
|
|
276
|
+
const entry = subscriptionManager.get(subscriptionId);
|
|
277
|
+
if (entry && !entry.channelEmitter) {
|
|
278
|
+
entry.onSubscriptionError?.(subscribeTimedOut(channel, SUBSCRIBE_TIMEOUT_MS), subscriptionId);
|
|
279
|
+
}
|
|
280
|
+
}, SUBSCRIBE_TIMEOUT_MS);
|
|
267
281
|
}
|
|
268
282
|
catch (error) {
|
|
269
283
|
const sub = subscriptionManager.get(subscriptionId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/realtime",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.60",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@wix/auto_sdk_duplexer_publisher": "^1.0.10",
|
|
45
45
|
"@wix/auto_sdk_duplexer_realtime-permissions-provider": "^1.0.3",
|
|
46
|
-
"@wix/duplexer-js": "^2.0.
|
|
46
|
+
"@wix/duplexer-js": "^2.0.11",
|
|
47
47
|
"@wix/realtime-common": "1.0.21",
|
|
48
48
|
"@wix/sdk": "^1.21.4",
|
|
49
49
|
"@wix/sdk-runtime": "^1.0.9",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"isRootPublicSdk": true
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"falconPackageHash": "
|
|
75
|
+
"falconPackageHash": "f348b697ba9d7cf1e635ee58ddc37776af77932d9faee97e4b637d5d"
|
|
76
76
|
}
|