@aurabase/realtime 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +61 -19
- package/dist/index.d.cts +22 -13
- package/dist/index.d.ts +22 -13
- package/dist/index.js +61 -19
- package/package.json +13 -12
package/dist/index.cjs
CHANGED
|
@@ -272,10 +272,12 @@ var AuraChannel = class {
|
|
|
272
272
|
constructor(name, projectPrefix, options) {
|
|
273
273
|
this.name = name;
|
|
274
274
|
this._projectPrefix = projectPrefix;
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
this.
|
|
278
|
-
this.
|
|
275
|
+
const bcast = options?.broadcast ?? options?.config?.broadcast;
|
|
276
|
+
const pres = options?.presence ?? options?.config?.presence;
|
|
277
|
+
this._isPrivate = Boolean(options?.private ?? options?.config?.private ?? false);
|
|
278
|
+
this._broadcastAck = Boolean(bcast?.ack ?? false);
|
|
279
|
+
this._broadcastSelf = Boolean(bcast?.self ?? false);
|
|
280
|
+
this._presenceKey = typeof pres?.key === "string" ? pres.key : "";
|
|
279
281
|
}
|
|
280
282
|
/** Génère un ref_id unique pour la corrélation request/response. */
|
|
281
283
|
_nextRef() {
|
|
@@ -308,6 +310,7 @@ var AuraChannel = class {
|
|
|
308
310
|
subscribe(callback, timeoutMs) {
|
|
309
311
|
this._subscribeCallback = callback ?? null;
|
|
310
312
|
this._subscribed = true;
|
|
313
|
+
this._serverState = "pending";
|
|
311
314
|
this._closedEmitted = false;
|
|
312
315
|
if (typeof timeoutMs === "number" && timeoutMs > 0) {
|
|
313
316
|
this._subscribeTimeoutMs = timeoutMs;
|
|
@@ -694,14 +697,32 @@ var AuraChannel = class {
|
|
|
694
697
|
}
|
|
695
698
|
}
|
|
696
699
|
}
|
|
697
|
-
|
|
700
|
+
const cdcPayload = payload && typeof payload === "object" ? payload : {};
|
|
701
|
+
if (cdcPayload.new === void 0 && cdcPayload.record !== void 0) {
|
|
702
|
+
cdcPayload.new = cdcPayload.record;
|
|
703
|
+
}
|
|
704
|
+
if (cdcPayload.old === void 0 && cdcPayload.old_record !== void 0) {
|
|
705
|
+
cdcPayload.old = cdcPayload.old_record;
|
|
706
|
+
}
|
|
707
|
+
if (cdcPayload.eventType === void 0 && cdcPayload.type !== void 0) {
|
|
708
|
+
cdcPayload.eventType = cdcPayload.type;
|
|
709
|
+
}
|
|
710
|
+
const enrichedEvent = Object.assign(Object.create(event), {
|
|
711
|
+
new: cdcPayload.record,
|
|
712
|
+
old: cdcPayload.old_record,
|
|
713
|
+
eventType: cdcPayload.type,
|
|
714
|
+
schema: cdcPayload.schema,
|
|
715
|
+
table: cdcPayload.table
|
|
716
|
+
});
|
|
717
|
+
listener.callback(enrichedEvent);
|
|
698
718
|
}
|
|
699
719
|
}
|
|
700
720
|
} else if (listener.type === "broadcast") {
|
|
701
721
|
if (eventType === "broadcast") {
|
|
702
722
|
const filter = listener.filter;
|
|
703
|
-
const
|
|
704
|
-
|
|
723
|
+
const broadcastPayload = event.payload && typeof event.payload === "object" ? event.payload : void 0;
|
|
724
|
+
const broadcastEvent = broadcastPayload?.event;
|
|
725
|
+
if (!filter.event || filter.event === "*" || broadcastEvent === filter.event) {
|
|
705
726
|
listener.callback(event);
|
|
706
727
|
}
|
|
707
728
|
}
|
|
@@ -926,6 +947,8 @@ var RealtimeService = class _RealtimeService {
|
|
|
926
947
|
_tokenRefreshTimer = null;
|
|
927
948
|
/** Dernier access_token propagé au serveur — évite les pushs redondants (propagation différentielle). */
|
|
928
949
|
_lastSentToken = null;
|
|
950
|
+
/** Token d'authentification explicite passé à setAuth(), prioritaire sur authStore. */
|
|
951
|
+
_customAuthToken = null;
|
|
929
952
|
/** Listeners d'erreurs de transport (handshake refusé, coupure, connexion morte). */
|
|
930
953
|
_errorListeners = /* @__PURE__ */ new Set();
|
|
931
954
|
/**
|
|
@@ -955,6 +978,10 @@ var RealtimeService = class _RealtimeService {
|
|
|
955
978
|
get connectionState() {
|
|
956
979
|
return this._state;
|
|
957
980
|
}
|
|
981
|
+
/** Whether the WebSocket is currently connected. */
|
|
982
|
+
get isConnected() {
|
|
983
|
+
return this._state === "connected";
|
|
984
|
+
}
|
|
958
985
|
/** Listen for connection state changes. */
|
|
959
986
|
onStateChange(callback) {
|
|
960
987
|
this._stateListeners.add(callback);
|
|
@@ -1019,17 +1046,15 @@ var RealtimeService = class _RealtimeService {
|
|
|
1019
1046
|
}
|
|
1020
1047
|
// ─── Préfixe de projet des canaux ───────────────────────────────────────
|
|
1021
1048
|
/**
|
|
1022
|
-
* Préfixe
|
|
1049
|
+
* Préfixe de projet déduit du token courant (`<project_id>:`), vide si aucun token.
|
|
1023
1050
|
*
|
|
1024
|
-
*
|
|
1025
|
-
*
|
|
1026
|
-
*
|
|
1027
|
-
* celui de l'URL — mais le token de session, lui, porte ce claim : on le lit là, dans le
|
|
1028
|
-
* même jeton que celui envoyé au serveur. Sans token (pas encore connecté), il n'y a rien
|
|
1051
|
+
* Utilisé pour normaliser les noms de canaux : le serveur (`aura-realtime`) attend
|
|
1052
|
+
* systématiquement `<project_id>:<canal>` sur le protocole WebSocket et REST, alors que
|
|
1053
|
+
* l'utilisateur passe généralement un nom court (`room-1`). Sans session, aucun préfixe
|
|
1029
1054
|
* à préfixer ; la connexion WS échouerait de toute façon, le serveur exigeant un JWT.
|
|
1030
1055
|
*/
|
|
1031
1056
|
_projectPrefix() {
|
|
1032
|
-
const token = this.client.authStore.token;
|
|
1057
|
+
const token = this._customAuthToken ?? this.client.authStore.token;
|
|
1033
1058
|
if (!token) return "";
|
|
1034
1059
|
const pid = getTokenProjectId(token);
|
|
1035
1060
|
return pid ? `${pid}:` : "";
|
|
@@ -1047,7 +1072,7 @@ var RealtimeService = class _RealtimeService {
|
|
|
1047
1072
|
}
|
|
1048
1073
|
this._intentionalClose = false;
|
|
1049
1074
|
this._setState("connecting");
|
|
1050
|
-
const token = this.client.authStore.token;
|
|
1075
|
+
const token = this._customAuthToken ?? this.client.authStore.token;
|
|
1051
1076
|
const params = new URLSearchParams();
|
|
1052
1077
|
if (token) params.set("token", token);
|
|
1053
1078
|
if (this.client.apiKey) params.set("apikey", this.client.apiKey);
|
|
@@ -1066,6 +1091,9 @@ var RealtimeService = class _RealtimeService {
|
|
|
1066
1091
|
opened = true;
|
|
1067
1092
|
this._reconnectAttempts = 0;
|
|
1068
1093
|
this._setState("connected");
|
|
1094
|
+
if (this._customAuthToken && this._customAuthToken !== this._lastSentToken) {
|
|
1095
|
+
this.refreshToken(this._customAuthToken);
|
|
1096
|
+
}
|
|
1069
1097
|
this._awaitingPong = false;
|
|
1070
1098
|
this._lastServerMessageAt = Date.now();
|
|
1071
1099
|
this._heartbeat.start(() => this._heartbeatTick(ws), HEARTBEAT_INTERVAL_MS);
|
|
@@ -1291,7 +1319,11 @@ var RealtimeService = class _RealtimeService {
|
|
|
1291
1319
|
*/
|
|
1292
1320
|
setAuth(token) {
|
|
1293
1321
|
const resolved = token ?? this.client.authStore.token;
|
|
1294
|
-
|
|
1322
|
+
this._customAuthToken = resolved ?? null;
|
|
1323
|
+
if (resolved == null) {
|
|
1324
|
+
this._lastSentToken = null;
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1295
1327
|
this.refreshToken(resolved);
|
|
1296
1328
|
}
|
|
1297
1329
|
/**
|
|
@@ -1469,8 +1501,9 @@ var RealtimeService = class _RealtimeService {
|
|
|
1469
1501
|
}
|
|
1470
1502
|
return ch;
|
|
1471
1503
|
}
|
|
1472
|
-
/** Remove a channel. */
|
|
1473
|
-
removeChannel(
|
|
1504
|
+
/** Remove a channel by name or by AuraChannel instance. */
|
|
1505
|
+
removeChannel(channel) {
|
|
1506
|
+
const name = typeof channel === "string" ? channel : channel.name;
|
|
1474
1507
|
const ch = this._channels.get(name);
|
|
1475
1508
|
if (ch) {
|
|
1476
1509
|
ch.unsubscribe();
|
|
@@ -1500,8 +1533,17 @@ var RealtimeService = class _RealtimeService {
|
|
|
1500
1533
|
ch._onMessage(msg);
|
|
1501
1534
|
return;
|
|
1502
1535
|
}
|
|
1536
|
+
if (channelFull.includes(":")) {
|
|
1537
|
+
const colonIdx = channelFull.indexOf(":");
|
|
1538
|
+
const relativeName = channelFull.slice(colonIdx + 1);
|
|
1539
|
+
const relCh = this._channels.get(relativeName);
|
|
1540
|
+
if (relCh) {
|
|
1541
|
+
relCh._onMessage(msg);
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1503
1545
|
for (const [, channel] of this._channels) {
|
|
1504
|
-
if (channel.fullName === channelFull || channelFull.startsWith(channel.fullName + ":")) {
|
|
1546
|
+
if (channel.fullName === channelFull || channel.name === channelFull || channelFull.startsWith(channel.fullName + ":") || channelFull.endsWith(`:${channel.name}`)) {
|
|
1505
1547
|
channel._onMessage(msg);
|
|
1506
1548
|
return;
|
|
1507
1549
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import { ChannelConfig, PostgresChangesFilter, RealtimeEvent, BroadcastFilter, PresenceFilter, PresenceState, SubscribeCallback, BroadcastPayload, BroadcastSendStatus, ServerMessage,
|
|
1
|
+
import { ChannelConfig, PostgresChangesFilter, RealtimeEvent, BroadcastFilter, PresenceFilter, PresenceState, SubscribeCallback, BroadcastPayload, BroadcastSendStatus, ServerMessage, AuraClientLike, AuraResponse } from '@aurabase/core';
|
|
2
2
|
|
|
3
|
-
type ListenerCallback = (payload: RealtimeEvent | Record<string, unknown>) => void;
|
|
4
3
|
type ListenerEntry = {
|
|
5
|
-
type:
|
|
6
|
-
filter: PostgresChangesFilter
|
|
7
|
-
callback:
|
|
4
|
+
type: 'postgres_changes';
|
|
5
|
+
filter: PostgresChangesFilter;
|
|
6
|
+
callback: (payload: RealtimeEvent) => void;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'broadcast';
|
|
9
|
+
filter: BroadcastFilter;
|
|
10
|
+
callback: (payload: RealtimeEvent) => void;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'presence';
|
|
13
|
+
filter: PresenceFilter;
|
|
14
|
+
callback: (payload: PresenceState | RealtimeEvent | Record<string, unknown>) => void;
|
|
8
15
|
};
|
|
9
16
|
/**
|
|
10
17
|
* Fonction d'émission fournie par `RealtimeService`.
|
|
@@ -379,6 +386,8 @@ declare class RealtimeService {
|
|
|
379
386
|
private _tokenRefreshTimer;
|
|
380
387
|
/** Dernier access_token propagé au serveur — évite les pushs redondants (propagation différentielle). */
|
|
381
388
|
private _lastSentToken;
|
|
389
|
+
/** Token d'authentification explicite passé à setAuth(), prioritaire sur authStore. */
|
|
390
|
+
private _customAuthToken;
|
|
382
391
|
/** Listeners d'erreurs de transport (handshake refusé, coupure, connexion morte). */
|
|
383
392
|
private _errorListeners;
|
|
384
393
|
/**
|
|
@@ -404,6 +413,8 @@ declare class RealtimeService {
|
|
|
404
413
|
constructor(client: AuraClientLike);
|
|
405
414
|
/** Current connection state. */
|
|
406
415
|
get connectionState(): ConnectionState;
|
|
416
|
+
/** Whether the WebSocket is currently connected. */
|
|
417
|
+
get isConnected(): boolean;
|
|
407
418
|
/** Listen for connection state changes. */
|
|
408
419
|
onStateChange(callback: (state: ConnectionState) => void): () => void;
|
|
409
420
|
private _setState;
|
|
@@ -438,13 +449,11 @@ declare class RealtimeService {
|
|
|
438
449
|
*/
|
|
439
450
|
private _emitError;
|
|
440
451
|
/**
|
|
441
|
-
* Préfixe
|
|
452
|
+
* Préfixe de projet déduit du token courant (`<project_id>:`), vide si aucun token.
|
|
442
453
|
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
* celui de l'URL — mais le token de session, lui, porte ce claim : on le lit là, dans le
|
|
447
|
-
* même jeton que celui envoyé au serveur. Sans token (pas encore connecté), il n'y a rien
|
|
454
|
+
* Utilisé pour normaliser les noms de canaux : le serveur (`aura-realtime`) attend
|
|
455
|
+
* systématiquement `<project_id>:<canal>` sur le protocole WebSocket et REST, alors que
|
|
456
|
+
* l'utilisateur passe généralement un nom court (`room-1`). Sans session, aucun préfixe
|
|
448
457
|
* à préfixer ; la connexion WS échouerait de toute façon, le serveur exigeant un JWT.
|
|
449
458
|
*/
|
|
450
459
|
private _projectPrefix;
|
|
@@ -609,8 +618,8 @@ declare class RealtimeService {
|
|
|
609
618
|
* ```
|
|
610
619
|
*/
|
|
611
620
|
channel(name: string, options?: ChannelConfig): AuraChannel;
|
|
612
|
-
/** Remove a channel. */
|
|
613
|
-
removeChannel(
|
|
621
|
+
/** Remove a channel by name or by AuraChannel instance. */
|
|
622
|
+
removeChannel(channel: string | AuraChannel): void;
|
|
614
623
|
/** List active channels. */
|
|
615
624
|
getChannels(): AuraChannel[];
|
|
616
625
|
/** Remove all channels and subscriptions. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import { ChannelConfig, PostgresChangesFilter, RealtimeEvent, BroadcastFilter, PresenceFilter, PresenceState, SubscribeCallback, BroadcastPayload, BroadcastSendStatus, ServerMessage,
|
|
1
|
+
import { ChannelConfig, PostgresChangesFilter, RealtimeEvent, BroadcastFilter, PresenceFilter, PresenceState, SubscribeCallback, BroadcastPayload, BroadcastSendStatus, ServerMessage, AuraClientLike, AuraResponse } from '@aurabase/core';
|
|
2
2
|
|
|
3
|
-
type ListenerCallback = (payload: RealtimeEvent | Record<string, unknown>) => void;
|
|
4
3
|
type ListenerEntry = {
|
|
5
|
-
type:
|
|
6
|
-
filter: PostgresChangesFilter
|
|
7
|
-
callback:
|
|
4
|
+
type: 'postgres_changes';
|
|
5
|
+
filter: PostgresChangesFilter;
|
|
6
|
+
callback: (payload: RealtimeEvent) => void;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'broadcast';
|
|
9
|
+
filter: BroadcastFilter;
|
|
10
|
+
callback: (payload: RealtimeEvent) => void;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'presence';
|
|
13
|
+
filter: PresenceFilter;
|
|
14
|
+
callback: (payload: PresenceState | RealtimeEvent | Record<string, unknown>) => void;
|
|
8
15
|
};
|
|
9
16
|
/**
|
|
10
17
|
* Fonction d'émission fournie par `RealtimeService`.
|
|
@@ -379,6 +386,8 @@ declare class RealtimeService {
|
|
|
379
386
|
private _tokenRefreshTimer;
|
|
380
387
|
/** Dernier access_token propagé au serveur — évite les pushs redondants (propagation différentielle). */
|
|
381
388
|
private _lastSentToken;
|
|
389
|
+
/** Token d'authentification explicite passé à setAuth(), prioritaire sur authStore. */
|
|
390
|
+
private _customAuthToken;
|
|
382
391
|
/** Listeners d'erreurs de transport (handshake refusé, coupure, connexion morte). */
|
|
383
392
|
private _errorListeners;
|
|
384
393
|
/**
|
|
@@ -404,6 +413,8 @@ declare class RealtimeService {
|
|
|
404
413
|
constructor(client: AuraClientLike);
|
|
405
414
|
/** Current connection state. */
|
|
406
415
|
get connectionState(): ConnectionState;
|
|
416
|
+
/** Whether the WebSocket is currently connected. */
|
|
417
|
+
get isConnected(): boolean;
|
|
407
418
|
/** Listen for connection state changes. */
|
|
408
419
|
onStateChange(callback: (state: ConnectionState) => void): () => void;
|
|
409
420
|
private _setState;
|
|
@@ -438,13 +449,11 @@ declare class RealtimeService {
|
|
|
438
449
|
*/
|
|
439
450
|
private _emitError;
|
|
440
451
|
/**
|
|
441
|
-
* Préfixe
|
|
452
|
+
* Préfixe de projet déduit du token courant (`<project_id>:`), vide si aucun token.
|
|
442
453
|
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
* celui de l'URL — mais le token de session, lui, porte ce claim : on le lit là, dans le
|
|
447
|
-
* même jeton que celui envoyé au serveur. Sans token (pas encore connecté), il n'y a rien
|
|
454
|
+
* Utilisé pour normaliser les noms de canaux : le serveur (`aura-realtime`) attend
|
|
455
|
+
* systématiquement `<project_id>:<canal>` sur le protocole WebSocket et REST, alors que
|
|
456
|
+
* l'utilisateur passe généralement un nom court (`room-1`). Sans session, aucun préfixe
|
|
448
457
|
* à préfixer ; la connexion WS échouerait de toute façon, le serveur exigeant un JWT.
|
|
449
458
|
*/
|
|
450
459
|
private _projectPrefix;
|
|
@@ -609,8 +618,8 @@ declare class RealtimeService {
|
|
|
609
618
|
* ```
|
|
610
619
|
*/
|
|
611
620
|
channel(name: string, options?: ChannelConfig): AuraChannel;
|
|
612
|
-
/** Remove a channel. */
|
|
613
|
-
removeChannel(
|
|
621
|
+
/** Remove a channel by name or by AuraChannel instance. */
|
|
622
|
+
removeChannel(channel: string | AuraChannel): void;
|
|
614
623
|
/** List active channels. */
|
|
615
624
|
getChannels(): AuraChannel[];
|
|
616
625
|
/** Remove all channels and subscriptions. */
|
package/dist/index.js
CHANGED
|
@@ -270,10 +270,12 @@ var AuraChannel = class {
|
|
|
270
270
|
constructor(name, projectPrefix, options) {
|
|
271
271
|
this.name = name;
|
|
272
272
|
this._projectPrefix = projectPrefix;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
this.
|
|
276
|
-
this.
|
|
273
|
+
const bcast = options?.broadcast ?? options?.config?.broadcast;
|
|
274
|
+
const pres = options?.presence ?? options?.config?.presence;
|
|
275
|
+
this._isPrivate = Boolean(options?.private ?? options?.config?.private ?? false);
|
|
276
|
+
this._broadcastAck = Boolean(bcast?.ack ?? false);
|
|
277
|
+
this._broadcastSelf = Boolean(bcast?.self ?? false);
|
|
278
|
+
this._presenceKey = typeof pres?.key === "string" ? pres.key : "";
|
|
277
279
|
}
|
|
278
280
|
/** Génère un ref_id unique pour la corrélation request/response. */
|
|
279
281
|
_nextRef() {
|
|
@@ -306,6 +308,7 @@ var AuraChannel = class {
|
|
|
306
308
|
subscribe(callback, timeoutMs) {
|
|
307
309
|
this._subscribeCallback = callback ?? null;
|
|
308
310
|
this._subscribed = true;
|
|
311
|
+
this._serverState = "pending";
|
|
309
312
|
this._closedEmitted = false;
|
|
310
313
|
if (typeof timeoutMs === "number" && timeoutMs > 0) {
|
|
311
314
|
this._subscribeTimeoutMs = timeoutMs;
|
|
@@ -692,14 +695,32 @@ var AuraChannel = class {
|
|
|
692
695
|
}
|
|
693
696
|
}
|
|
694
697
|
}
|
|
695
|
-
|
|
698
|
+
const cdcPayload = payload && typeof payload === "object" ? payload : {};
|
|
699
|
+
if (cdcPayload.new === void 0 && cdcPayload.record !== void 0) {
|
|
700
|
+
cdcPayload.new = cdcPayload.record;
|
|
701
|
+
}
|
|
702
|
+
if (cdcPayload.old === void 0 && cdcPayload.old_record !== void 0) {
|
|
703
|
+
cdcPayload.old = cdcPayload.old_record;
|
|
704
|
+
}
|
|
705
|
+
if (cdcPayload.eventType === void 0 && cdcPayload.type !== void 0) {
|
|
706
|
+
cdcPayload.eventType = cdcPayload.type;
|
|
707
|
+
}
|
|
708
|
+
const enrichedEvent = Object.assign(Object.create(event), {
|
|
709
|
+
new: cdcPayload.record,
|
|
710
|
+
old: cdcPayload.old_record,
|
|
711
|
+
eventType: cdcPayload.type,
|
|
712
|
+
schema: cdcPayload.schema,
|
|
713
|
+
table: cdcPayload.table
|
|
714
|
+
});
|
|
715
|
+
listener.callback(enrichedEvent);
|
|
696
716
|
}
|
|
697
717
|
}
|
|
698
718
|
} else if (listener.type === "broadcast") {
|
|
699
719
|
if (eventType === "broadcast") {
|
|
700
720
|
const filter = listener.filter;
|
|
701
|
-
const
|
|
702
|
-
|
|
721
|
+
const broadcastPayload = event.payload && typeof event.payload === "object" ? event.payload : void 0;
|
|
722
|
+
const broadcastEvent = broadcastPayload?.event;
|
|
723
|
+
if (!filter.event || filter.event === "*" || broadcastEvent === filter.event) {
|
|
703
724
|
listener.callback(event);
|
|
704
725
|
}
|
|
705
726
|
}
|
|
@@ -924,6 +945,8 @@ var RealtimeService = class _RealtimeService {
|
|
|
924
945
|
_tokenRefreshTimer = null;
|
|
925
946
|
/** Dernier access_token propagé au serveur — évite les pushs redondants (propagation différentielle). */
|
|
926
947
|
_lastSentToken = null;
|
|
948
|
+
/** Token d'authentification explicite passé à setAuth(), prioritaire sur authStore. */
|
|
949
|
+
_customAuthToken = null;
|
|
927
950
|
/** Listeners d'erreurs de transport (handshake refusé, coupure, connexion morte). */
|
|
928
951
|
_errorListeners = /* @__PURE__ */ new Set();
|
|
929
952
|
/**
|
|
@@ -953,6 +976,10 @@ var RealtimeService = class _RealtimeService {
|
|
|
953
976
|
get connectionState() {
|
|
954
977
|
return this._state;
|
|
955
978
|
}
|
|
979
|
+
/** Whether the WebSocket is currently connected. */
|
|
980
|
+
get isConnected() {
|
|
981
|
+
return this._state === "connected";
|
|
982
|
+
}
|
|
956
983
|
/** Listen for connection state changes. */
|
|
957
984
|
onStateChange(callback) {
|
|
958
985
|
this._stateListeners.add(callback);
|
|
@@ -1017,17 +1044,15 @@ var RealtimeService = class _RealtimeService {
|
|
|
1017
1044
|
}
|
|
1018
1045
|
// ─── Préfixe de projet des canaux ───────────────────────────────────────
|
|
1019
1046
|
/**
|
|
1020
|
-
* Préfixe
|
|
1047
|
+
* Préfixe de projet déduit du token courant (`<project_id>:`), vide si aucun token.
|
|
1021
1048
|
*
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
1025
|
-
* celui de l'URL — mais le token de session, lui, porte ce claim : on le lit là, dans le
|
|
1026
|
-
* même jeton que celui envoyé au serveur. Sans token (pas encore connecté), il n'y a rien
|
|
1049
|
+
* Utilisé pour normaliser les noms de canaux : le serveur (`aura-realtime`) attend
|
|
1050
|
+
* systématiquement `<project_id>:<canal>` sur le protocole WebSocket et REST, alors que
|
|
1051
|
+
* l'utilisateur passe généralement un nom court (`room-1`). Sans session, aucun préfixe
|
|
1027
1052
|
* à préfixer ; la connexion WS échouerait de toute façon, le serveur exigeant un JWT.
|
|
1028
1053
|
*/
|
|
1029
1054
|
_projectPrefix() {
|
|
1030
|
-
const token = this.client.authStore.token;
|
|
1055
|
+
const token = this._customAuthToken ?? this.client.authStore.token;
|
|
1031
1056
|
if (!token) return "";
|
|
1032
1057
|
const pid = getTokenProjectId(token);
|
|
1033
1058
|
return pid ? `${pid}:` : "";
|
|
@@ -1045,7 +1070,7 @@ var RealtimeService = class _RealtimeService {
|
|
|
1045
1070
|
}
|
|
1046
1071
|
this._intentionalClose = false;
|
|
1047
1072
|
this._setState("connecting");
|
|
1048
|
-
const token = this.client.authStore.token;
|
|
1073
|
+
const token = this._customAuthToken ?? this.client.authStore.token;
|
|
1049
1074
|
const params = new URLSearchParams();
|
|
1050
1075
|
if (token) params.set("token", token);
|
|
1051
1076
|
if (this.client.apiKey) params.set("apikey", this.client.apiKey);
|
|
@@ -1064,6 +1089,9 @@ var RealtimeService = class _RealtimeService {
|
|
|
1064
1089
|
opened = true;
|
|
1065
1090
|
this._reconnectAttempts = 0;
|
|
1066
1091
|
this._setState("connected");
|
|
1092
|
+
if (this._customAuthToken && this._customAuthToken !== this._lastSentToken) {
|
|
1093
|
+
this.refreshToken(this._customAuthToken);
|
|
1094
|
+
}
|
|
1067
1095
|
this._awaitingPong = false;
|
|
1068
1096
|
this._lastServerMessageAt = Date.now();
|
|
1069
1097
|
this._heartbeat.start(() => this._heartbeatTick(ws), HEARTBEAT_INTERVAL_MS);
|
|
@@ -1289,7 +1317,11 @@ var RealtimeService = class _RealtimeService {
|
|
|
1289
1317
|
*/
|
|
1290
1318
|
setAuth(token) {
|
|
1291
1319
|
const resolved = token ?? this.client.authStore.token;
|
|
1292
|
-
|
|
1320
|
+
this._customAuthToken = resolved ?? null;
|
|
1321
|
+
if (resolved == null) {
|
|
1322
|
+
this._lastSentToken = null;
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1293
1325
|
this.refreshToken(resolved);
|
|
1294
1326
|
}
|
|
1295
1327
|
/**
|
|
@@ -1467,8 +1499,9 @@ var RealtimeService = class _RealtimeService {
|
|
|
1467
1499
|
}
|
|
1468
1500
|
return ch;
|
|
1469
1501
|
}
|
|
1470
|
-
/** Remove a channel. */
|
|
1471
|
-
removeChannel(
|
|
1502
|
+
/** Remove a channel by name or by AuraChannel instance. */
|
|
1503
|
+
removeChannel(channel) {
|
|
1504
|
+
const name = typeof channel === "string" ? channel : channel.name;
|
|
1472
1505
|
const ch = this._channels.get(name);
|
|
1473
1506
|
if (ch) {
|
|
1474
1507
|
ch.unsubscribe();
|
|
@@ -1498,8 +1531,17 @@ var RealtimeService = class _RealtimeService {
|
|
|
1498
1531
|
ch._onMessage(msg);
|
|
1499
1532
|
return;
|
|
1500
1533
|
}
|
|
1534
|
+
if (channelFull.includes(":")) {
|
|
1535
|
+
const colonIdx = channelFull.indexOf(":");
|
|
1536
|
+
const relativeName = channelFull.slice(colonIdx + 1);
|
|
1537
|
+
const relCh = this._channels.get(relativeName);
|
|
1538
|
+
if (relCh) {
|
|
1539
|
+
relCh._onMessage(msg);
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1501
1543
|
for (const [, channel] of this._channels) {
|
|
1502
|
-
if (channel.fullName === channelFull || channelFull.startsWith(channel.fullName + ":")) {
|
|
1544
|
+
if (channel.fullName === channelFull || channel.name === channelFull || channelFull.startsWith(channel.fullName + ":") || channelFull.endsWith(`:${channel.name}`)) {
|
|
1503
1545
|
channel._onMessage(msg);
|
|
1504
1546
|
return;
|
|
1505
1547
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurabase/realtime",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Service temps réel du SDK Aurabase (postgres_changes, broadcast, presence)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"url": "git+https://github.com/daylami555/aurabase.git",
|
|
35
35
|
"directory": "aurabase-js/packages/realtime"
|
|
36
36
|
},
|
|
37
|
-
"homepage": "https://
|
|
37
|
+
"homepage": "https://aurabase.cloud",
|
|
38
38
|
"bugs": {
|
|
39
39
|
"url": "https://github.com/daylami555/aurabase/issues"
|
|
40
40
|
},
|
|
@@ -44,19 +44,20 @@
|
|
|
44
44
|
"sdk",
|
|
45
45
|
"realtime"
|
|
46
46
|
],
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"@aurabase/core": "0.5.0"
|
|
49
|
-
},
|
|
50
|
-
"devDependencies": {
|
|
51
|
-
"@types/node": "20.14.15",
|
|
52
|
-
"tsup": "^8.0.0",
|
|
53
|
-
"typescript": "^5.5.0",
|
|
54
|
-
"vitest": "^4.1.6"
|
|
55
|
-
},
|
|
56
47
|
"scripts": {
|
|
57
48
|
"build": "tsup",
|
|
58
49
|
"test": "vitest run --passWithNoTests",
|
|
59
50
|
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
|
|
51
|
+
"prepack": "pnpm build",
|
|
60
52
|
"typecheck:tests": "tsc --noEmit -p tsconfig.test.json"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@aurabase/core": "workspace:*"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/node": "catalog:",
|
|
59
|
+
"tsup": "catalog:",
|
|
60
|
+
"typescript": "catalog:",
|
|
61
|
+
"vitest": "catalog:"
|
|
61
62
|
}
|
|
62
|
-
}
|
|
63
|
+
}
|