@inditextech/weave-store-azure-web-pubsub 2.0.2 → 2.1.0

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/client.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  import { WeaveStore } from "@inditextech/weave-sdk";
2
- import { WeaveStoreOptions } from "@inditextech/weave-types";
2
+ import { DeepPartial, WeaveStoreOptions } from "@inditextech/weave-types";
3
3
  import ReconnectingWebSocket from "reconnecting-websocket";
4
4
  import { Doc } from "yjs";
5
5
  import Emittery from "emittery";
6
6
  import * as awarenessProtocol from "y-protocols/awareness";
7
7
  import { WebSocket } from "ws";
8
8
  import { TokenCredential } from "@azure/identity";
9
+ import { Encoder } from "lib0/encoding";
10
+ import { Decoder } from "lib0/decoding";
9
11
 
10
12
  //#region src/server/event-handler/cloud-events-protocols.d.ts
11
13
  /**
@@ -80,6 +82,12 @@ interface MqttConnectionContextProperties {
80
82
  * Request for the connect event.
81
83
  */
82
84
  declare const WEAVE_STORE_AZURE_WEB_PUBSUB = "store-azure-web-pubsub";
85
+ declare const WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS: {
86
+ "CONNECTING": string;
87
+ "CONNECTED": string;
88
+ "DISCONNECTED": string;
89
+ "ERROR": string;
90
+ };
83
91
  declare const WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE: {
84
92
  "PUB": string;
85
93
  "SUB": string;
@@ -92,13 +100,13 @@ declare const WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG: {
92
100
  //#region src/types.d.ts
93
101
  type WeaveStoreAzureWebPubsubConfig = {
94
102
  endpoint: string;
103
+ persistIntervalMs?: number;
95
104
  hubName: string;
96
105
  auth?: {
97
106
  key?: string;
98
107
  custom?: TokenCredential;
99
108
  };
100
- connectionHandlers?: Pick<WeaveAzureWebPubsubSyncHandlerOptions, "onConnect" | "onConnected" | "removeConnection" | "getConnectionRoom" | "getRoomConnections">;
101
- persistIntervalMs?: number;
109
+ connectionHandlers?: DeepPartial<WeaveAzureWebPubsubSyncHandlerOptions>;
102
110
  };
103
111
  type WeaveAzureWebPubsubSyncHandlerOptions = {
104
112
  onConnect?: (connectionId: string, queries: Record<string, string[]> | undefined) => Promise<void>;
@@ -161,13 +169,42 @@ type WeaveStoreAzureWebPubsubOnWebsocketErrorEvent = {
161
169
  type WeaveStoreAzureWebPubsubOnWebsocketOnTokenRefreshEvent = {
162
170
  group: string;
163
171
  };
164
-
165
- //#endregion
166
- //#region src/client.d.ts
167
- interface ClientOptions {
172
+ type WeaveStoreAzureWebPubSubSyncHostClientConnectOptions = {
173
+ expirationTimeInMinutes?: number;
174
+ };
175
+ type WeaveStoreAzureWebPubSubSyncClientConnectionStatusKeys = keyof typeof WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS;
176
+ type WeaveStoreAzureWebPubSubSyncClientConnectionStatus = (typeof WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS)[WeaveStoreAzureWebPubSubSyncClientConnectionStatusKeys];
177
+ declare enum MessageType {
178
+ System = "system",
179
+ JoinGroup = "joinGroup",
180
+ SendToGroup = "sendToGroup",
181
+ }
182
+ declare enum MessageDataType {
183
+ Init = "init",
184
+ Sync = "sync",
185
+ Awareness = "awareness",
186
+ }
187
+ interface MessageData {
188
+ group: string;
189
+ t: string;
190
+ f: string;
191
+ c: string;
192
+ }
193
+ interface Message {
194
+ type: string;
195
+ fromUserId: string;
196
+ from: string;
197
+ group: string;
198
+ data: MessageData;
199
+ }
200
+ type MessageHandler = (encoder: Encoder, decoder: Decoder, client: WeaveStoreAzureWebPubSubSyncClient, clientId: string, emitSynced: boolean, messageType: number) => void;
201
+ interface WeaveStoreAzureWebPubSubSyncClientOptions {
168
202
  resyncInterval: number;
169
203
  tokenProvider: Promise<string> | null;
170
204
  }
205
+
206
+ //#endregion
207
+ //#region src/client.d.ts
171
208
  declare class WeaveStoreAzureWebPubSubSyncClient extends Emittery {
172
209
  doc: Doc;
173
210
  topic: string;
@@ -179,6 +216,8 @@ declare class WeaveStoreAzureWebPubSubSyncClient extends Emittery {
179
216
  private _wsConnected;
180
217
  private _synced;
181
218
  private _resyncInterval;
219
+ private _resyncCheckInterval;
220
+ private _lastReceivedSyncResponse;
182
221
  private _connectionRetries;
183
222
  private _uuid;
184
223
  private _awareness;
@@ -193,20 +232,23 @@ declare class WeaveStoreAzureWebPubSubSyncClient extends Emittery {
193
232
  * @param {number} [options.resyncInterval] Request server state every `resyncInterval` milliseconds.
194
233
  * @param {number} [options.tokenProvider] token generator for negotiation.
195
234
  */
196
- constructor(instance: WeaveStoreAzureWebPubsub, url: string, topic: string, doc: Doc, options?: ClientOptions);
235
+ constructor(instance: WeaveStoreAzureWebPubsub, url: string, topic: string, doc: Doc, options?: WeaveStoreAzureWebPubSubSyncClientOptions);
197
236
  get awareness(): awarenessProtocol.Awareness;
198
237
  get synced(): boolean;
199
238
  set synced(state: boolean);
200
239
  get ws(): ReconnectingWebSocket | null;
201
240
  get id(): string;
202
241
  getClientId(): string;
242
+ saveLastSyncResponse(): void;
203
243
  setupResyncInterval(): void;
204
- destroy(): void;
205
- stop(): void;
244
+ cleanupResyncInterval(): void;
245
+ simulateWebsocketError(): void;
246
+ disconnect(): void;
206
247
  setFetchClient(fetchClient?: FetchClient): void;
207
- fetchConnectionUrl(): Promise<string>;
208
- createWebSocket(): Promise<ReconnectingWebSocket>;
209
- start(): Promise<void>;
248
+ fetchConnectionUrl(connectionUrlExtraParams?: Record<string, string>): Promise<string>;
249
+ createWebSocket(connectionUrlExtraParams?: Record<string, string>): Promise<ReconnectingWebSocket>;
250
+ setAndEmitStatusInfo(status: WeaveStoreAzureWebPubSubSyncClientConnectionStatus): void;
251
+ connect(connectionUrlExtraParams?: Record<string, string>): Promise<void>;
210
252
  }
211
253
 
212
254
  //#endregion
@@ -226,11 +268,13 @@ declare class WeaveStoreAzureWebPubsub extends WeaveStore {
226
268
  private init;
227
269
  emitEvent<T>(name: string, payload?: T): void;
228
270
  getClientId(): string | null;
229
- connect(): Promise<void>;
271
+ connect(extraParams?: Record<string, string>): Promise<void>;
230
272
  disconnect(): void;
273
+ simulateWebsocketError(): void;
274
+ destroy(): void;
231
275
  handleAwarenessChange(emit?: boolean): void;
232
276
  setAwarenessInfo<T>(field: string, value: T): void;
233
277
  }
234
278
 
235
279
  //#endregion
236
- export { FetchClient, FetchInitialState, FetchRoom, PersistRoom, WEAVE_STORE_AZURE_WEB_PUBSUB, WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG, WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE, WeaveAzureWebPubsubSyncHandlerOptions, WeaveStoreAzureWebPubsub, WeaveStoreAzureWebPubsubConfig, WeaveStoreAzureWebPubsubEvents, WeaveStoreAzureWebPubsubOnConnectEvent, WeaveStoreAzureWebPubsubOnConnectedEvent, WeaveStoreAzureWebPubsubOnDisconnectedEvent, WeaveStoreAzureWebPubsubOnStoreFetchConnectionUrlEvent, WeaveStoreAzureWebPubsubOnWebsocketCloseEvent, WeaveStoreAzureWebPubsubOnWebsocketErrorEvent, WeaveStoreAzureWebPubsubOnWebsocketJoinGroupEvent, WeaveStoreAzureWebPubsubOnWebsocketMessageEvent, WeaveStoreAzureWebPubsubOnWebsocketOnTokenRefreshEvent, WeaveStoreAzureWebPubsubOnWebsocketOpenEvent, WeaveStoreAzureWebPubsubOptions };
280
+ export { FetchClient, FetchInitialState, FetchRoom, Message, MessageData, MessageDataType, MessageHandler, MessageType, PersistRoom, WEAVE_STORE_AZURE_WEB_PUBSUB, WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS, WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG, WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE, WeaveAzureWebPubsubSyncHandlerOptions, WeaveStoreAzureWebPubSubSyncClientConnectionStatus, WeaveStoreAzureWebPubSubSyncClientConnectionStatusKeys, WeaveStoreAzureWebPubSubSyncClientOptions, WeaveStoreAzureWebPubSubSyncHostClientConnectOptions, WeaveStoreAzureWebPubsub, WeaveStoreAzureWebPubsubConfig, WeaveStoreAzureWebPubsubEvents, WeaveStoreAzureWebPubsubOnConnectEvent, WeaveStoreAzureWebPubsubOnConnectedEvent, WeaveStoreAzureWebPubsubOnDisconnectedEvent, WeaveStoreAzureWebPubsubOnStoreFetchConnectionUrlEvent, WeaveStoreAzureWebPubsubOnWebsocketCloseEvent, WeaveStoreAzureWebPubsubOnWebsocketErrorEvent, WeaveStoreAzureWebPubsubOnWebsocketJoinGroupEvent, WeaveStoreAzureWebPubsubOnWebsocketMessageEvent, WeaveStoreAzureWebPubsubOnWebsocketOnTokenRefreshEvent, WeaveStoreAzureWebPubsubOnWebsocketOpenEvent, WeaveStoreAzureWebPubsubOptions };
package/dist/client.js CHANGED
@@ -3693,11 +3693,7 @@ const applyAwarenessUpdate = (awareness, update, origin) => {
3693
3693
  };
3694
3694
 
3695
3695
  //#endregion
3696
- //#region src/client.ts
3697
- const messageSyncStep1 = 0;
3698
- const messageAwareness = 1;
3699
- const messageQueryAwareness = 3;
3700
- const AzureWebPubSubJsonProtocol = "json.webpubsub.azure.v1";
3696
+ //#region src/types.ts
3701
3697
  let MessageType = /* @__PURE__ */ function(MessageType$1) {
3702
3698
  MessageType$1["System"] = "system";
3703
3699
  MessageType$1["JoinGroup"] = "joinGroup";
@@ -3710,6 +3706,28 @@ let MessageDataType = /* @__PURE__ */ function(MessageDataType$1) {
3710
3706
  MessageDataType$1["Awareness"] = "awareness";
3711
3707
  return MessageDataType$1;
3712
3708
  }({});
3709
+
3710
+ //#endregion
3711
+ //#region src/constants.ts
3712
+ const WEAVE_STORE_AZURE_WEB_PUBSUB = "store-azure-web-pubsub";
3713
+ const WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS = {
3714
+ ["CONNECTING"]: "connecting",
3715
+ ["CONNECTED"]: "connected",
3716
+ ["DISCONNECTED"]: "disconnected",
3717
+ ["ERROR"]: "error"
3718
+ };
3719
+ const WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE = {
3720
+ ["PUB"]: "pub",
3721
+ ["SUB"]: "sub"
3722
+ };
3723
+ const WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG = { resyncIntervalMs: 15e3 };
3724
+
3725
+ //#endregion
3726
+ //#region src/client.ts
3727
+ const messageSyncStep1 = 0;
3728
+ const messageAwareness = 1;
3729
+ const messageQueryAwareness = 3;
3730
+ const AzureWebPubSubJsonProtocol = "json.webpubsub.azure.v1";
3713
3731
  const messageHandlers = [];
3714
3732
  messageHandlers[messageSyncStep1] = (encoder, decoder, client, clientId, emitSynced, messageType) => {
3715
3733
  writeVarUint(encoder, messageType);
@@ -3727,6 +3745,7 @@ const readMessage = (client, buf, emitSynced, clientId) => {
3727
3745
  const decoder = createDecoder(buf);
3728
3746
  const encoder = createEncoder();
3729
3747
  const messageType = readVarUint(decoder);
3748
+ if (messageType === 0) client.saveLastSyncResponse();
3730
3749
  const messageHandler = messageHandlers[messageType];
3731
3750
  if (messageHandler) messageHandler(encoder, decoder, client, clientId, emitSynced, messageType);
3732
3751
  else throw new Error(`unable to handle message with type: ${messageType}`);
@@ -3752,15 +3771,17 @@ var WeaveStoreAzureWebPubSubSyncClient = class extends Emittery {
3752
3771
  this._fetchClient = fetch;
3753
3772
  this._url = url;
3754
3773
  this._uuid = v4();
3755
- this._status = "disconnected";
3774
+ this._status = WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.DISCONNECTED;
3756
3775
  this._wsConnected = false;
3757
3776
  this._initialized = false;
3758
3777
  this._connectionRetries = 0;
3759
3778
  this._synced = false;
3760
3779
  this._ws = null;
3761
- const awareness = new Awareness(doc);
3762
- this._awareness = awareness;
3763
3780
  this._resyncInterval = null;
3781
+ this._resyncCheckInterval = null;
3782
+ this._lastReceivedSyncResponse = null;
3783
+ const awareness = new Awareness(this.doc);
3784
+ this._awareness = awareness;
3764
3785
  this._updateHandler = (update, origin) => {
3765
3786
  if (origin !== this) {
3766
3787
  const encoder = createEncoder();
@@ -3774,10 +3795,10 @@ var WeaveStoreAzureWebPubSubSyncClient = class extends Emittery {
3774
3795
  const changedClients = added.concat(updated).concat(removed);
3775
3796
  const encoder = createEncoder();
3776
3797
  writeVarUint(encoder, messageAwareness);
3777
- writeVarUint8Array(encoder, encodeAwarenessUpdate(awareness, changedClients));
3798
+ writeVarUint8Array(encoder, encodeAwarenessUpdate(this.awareness, changedClients));
3778
3799
  sendToControlGroup(this, topic, MessageDataType.Awareness, toUint8Array(encoder));
3779
3800
  };
3780
- awareness.on("update", this._awarenessUpdateHandler);
3801
+ this._awareness.on("update", this._awarenessUpdateHandler);
3781
3802
  }
3782
3803
  get awareness() {
3783
3804
  return this._awareness;
@@ -3797,38 +3818,80 @@ var WeaveStoreAzureWebPubSubSyncClient = class extends Emittery {
3797
3818
  getClientId() {
3798
3819
  return this.id;
3799
3820
  }
3821
+ saveLastSyncResponse() {
3822
+ const now = new Date();
3823
+ this._lastReceivedSyncResponse = now.getTime();
3824
+ this.instance.emitEvent("onSyncResponse", this._lastReceivedSyncResponse);
3825
+ }
3800
3826
  setupResyncInterval() {
3801
- if (this._options.resyncInterval > 0) this._resyncInterval = setInterval(() => {
3802
- if (this._ws && this._wsConnected) {
3803
- const encoder = createEncoder();
3804
- writeVarUint(encoder, messageSyncStep1);
3805
- writeSyncStep1(encoder, this.doc);
3806
- sendToControlGroup(this, this.topic, MessageDataType.Sync, toUint8Array(encoder));
3807
- }
3808
- }, this._options.resyncInterval);
3827
+ if (this._options.resyncInterval > 0) {
3828
+ this._resyncInterval = setInterval(() => {
3829
+ if (this._ws && this._wsConnected) {
3830
+ const encoder = createEncoder();
3831
+ writeVarUint(encoder, messageSyncStep1);
3832
+ writeSyncStep1(encoder, this.doc);
3833
+ sendToControlGroup(this, this.topic, MessageDataType.Sync, toUint8Array(encoder));
3834
+ }
3835
+ }, this._options.resyncInterval);
3836
+ this._resyncCheckInterval = setInterval(() => {
3837
+ if (!this._lastReceivedSyncResponse) return;
3838
+ const resyncInSeconds = this._options.resyncInterval / 1e3;
3839
+ const resyncLimitInSeconds = resyncInSeconds + 5;
3840
+ const now = new Date();
3841
+ const diffInSeconds = (now.getTime() - this._lastReceivedSyncResponse) / 1e3;
3842
+ if (diffInSeconds > resyncLimitInSeconds && this._ws?.readyState === WebSocket.OPEN) {
3843
+ this._ws.dispatchEvent(new CustomEvent("error", {
3844
+ cancelable: false,
3845
+ bubbles: false,
3846
+ detail: new Error("No sync response")
3847
+ }));
3848
+ this._ws._ws.close();
3849
+ }
3850
+ }, this._options.resyncInterval + 5e3);
3851
+ }
3809
3852
  }
3810
- destroy() {
3811
- if (this._resyncInterval) clearInterval(this._resyncInterval);
3812
- this.stop();
3813
- this.doc.off("update", this._updateHandler);
3853
+ cleanupResyncInterval() {
3854
+ if (this._resyncInterval) {
3855
+ clearInterval(this._resyncInterval);
3856
+ this._resyncInterval = null;
3857
+ }
3858
+ if (this._resyncCheckInterval) {
3859
+ clearInterval(this._resyncCheckInterval);
3860
+ this._resyncCheckInterval = null;
3861
+ }
3862
+ }
3863
+ simulateWebsocketError() {
3864
+ if (this._ws) this._ws._ws.close(4e3, new Error("Simulated error for testing"));
3814
3865
  }
3815
- stop() {
3866
+ disconnect() {
3816
3867
  if (this._ws !== null) {
3817
3868
  const encoder = createEncoder();
3818
3869
  writeVarUint(encoder, messageAwareness);
3819
3870
  writeVarUint8Array(encoder, encodeAwarenessUpdate(this.awareness, [this.doc.clientID], new Map()));
3820
3871
  const u8 = toUint8Array(encoder);
3821
3872
  sendToControlGroup(this, this.topic, MessageDataType.Awareness, u8);
3873
+ removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter((client) => client !== this.doc.clientID), this);
3822
3874
  this._initialized = false;
3823
- if (this._ws.readyState === WebSocket.OPEN) this._ws.close();
3875
+ this._ws.close();
3824
3876
  }
3877
+ this.cleanupResyncInterval();
3878
+ this._wsConnected = false;
3879
+ this._ws = null;
3825
3880
  }
3826
3881
  setFetchClient(fetchClient = window.fetch) {
3827
3882
  this._fetchClient = fetchClient.bind(window);
3828
3883
  }
3829
- async fetchConnectionUrl() {
3884
+ async fetchConnectionUrl(connectionUrlExtraParams) {
3830
3885
  try {
3831
- const res = await this._fetchClient(this._url);
3886
+ const connectionURL = new URL(this._url, isRelativeUrl(this._url) ? window.location.origin : void 0);
3887
+ if (connectionUrlExtraParams) {
3888
+ const extraParamsKeys = Object.keys(connectionUrlExtraParams);
3889
+ for (const key of extraParamsKeys) {
3890
+ if (connectionURL.searchParams.has(key)) connectionURL.searchParams.delete(key);
3891
+ connectionURL.searchParams.append(key, connectionUrlExtraParams[key]);
3892
+ }
3893
+ }
3894
+ const res = await this._fetchClient(connectionURL.toString());
3832
3895
  if (res.ok) {
3833
3896
  const data = await res.json();
3834
3897
  return data.url;
@@ -3837,7 +3900,7 @@ var WeaveStoreAzureWebPubSubSyncClient = class extends Emittery {
3837
3900
  throw new Error(`Failed to fetch connection url from: ${this._url}`);
3838
3901
  }
3839
3902
  }
3840
- async createWebSocket() {
3903
+ async createWebSocket(connectionUrlExtraParams) {
3841
3904
  const websocket = new ReconnectingWebSocket(async () => {
3842
3905
  let url = "https://error";
3843
3906
  let error = null;
@@ -3846,7 +3909,7 @@ var WeaveStoreAzureWebPubSubSyncClient = class extends Emittery {
3846
3909
  loading: true,
3847
3910
  error: null
3848
3911
  });
3849
- url = await this.fetchConnectionUrl();
3912
+ url = await this.fetchConnectionUrl(connectionUrlExtraParams);
3850
3913
  } catch (ex) {
3851
3914
  error = ex;
3852
3915
  } finally {
@@ -3864,14 +3927,12 @@ var WeaveStoreAzureWebPubSubSyncClient = class extends Emittery {
3864
3927
  this._initialized = false;
3865
3928
  this.synced = false;
3866
3929
  websocket.addEventListener("error", (e) => {
3867
- if (e) console.error("Websocket error", e);
3930
+ console.error("WebSocket error", e);
3868
3931
  if (this._initialized && websocket.retryCount > 0) {
3869
- this._status = "connecting";
3870
- this.emit("status", this._status);
3932
+ this.setAndEmitStatusInfo(WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.CONNECTING);
3871
3933
  return;
3872
3934
  }
3873
- this._status = "error";
3874
- this.emit("status", this._status);
3935
+ this.setAndEmitStatusInfo(WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.ERROR);
3875
3936
  });
3876
3937
  websocket.onmessage = (event) => {
3877
3938
  if (event.data === null) return;
@@ -3883,24 +3944,18 @@ var WeaveStoreAzureWebPubSubSyncClient = class extends Emittery {
3883
3944
  const encoder = readMessage(this, buf, true, messageData.f);
3884
3945
  if (length$1(encoder) > 1) sendToControlGroup(this, this.topic, MessageDataType.Sync, toUint8Array(encoder));
3885
3946
  };
3886
- websocket.onclose = (ev) => {
3887
- this._status = "disconnected";
3888
- this.emit("status", this._status);
3947
+ websocket.onclose = () => {
3948
+ if ((this._ws?.retryCount ?? 0) > 0) this.setAndEmitStatusInfo(WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.CONNECTING);
3949
+ else this.setAndEmitStatusInfo(WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.DISCONNECTED);
3889
3950
  if (this._wsConnected) {
3890
- if (this._resyncInterval) clearInterval(this._resyncInterval);
3891
- this._resyncInterval = null;
3951
+ this.cleanupResyncInterval();
3892
3952
  this._wsConnected = false;
3893
3953
  this.synced = false;
3894
3954
  removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter((x) => x !== this.doc.clientID), this);
3895
3955
  }
3896
- if (ev.code === 1008 && websocket.readyState === WebSocket.OPEN) {
3897
- websocket.close();
3898
- this.createWebSocket();
3899
- }
3900
3956
  };
3901
3957
  websocket.onopen = () => {
3902
- this._status = "connected";
3903
- this.emit("status", this._status);
3958
+ this.setAndEmitStatusInfo(WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.CONNECTED);
3904
3959
  this._wsConnected = true;
3905
3960
  this._initialized = true;
3906
3961
  this._connectionRetries = this._connectionRetries++;
@@ -3911,19 +3966,31 @@ var WeaveStoreAzureWebPubSubSyncClient = class extends Emittery {
3911
3966
  writeSyncStep1(encoder, this.doc);
3912
3967
  const u8 = toUint8Array(encoder);
3913
3968
  sendToControlGroup(this, this.topic, MessageDataType.Init, u8);
3969
+ const encoderState = createEncoder();
3970
+ writeVarUint(encoderState, messageSyncStep1);
3971
+ writeSyncStep2(encoderState, this.doc);
3972
+ sendToControlGroup(this, this.topic, MessageDataType.Init, u8);
3973
+ const encoderAwarenessQuery = createEncoder();
3974
+ writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
3975
+ sendToControlGroup(this, this.topic, MessageDataType.Init, u8);
3914
3976
  if (this.awareness.getLocalState() !== null) {
3915
3977
  const encoderAwarenessState = createEncoder();
3916
3978
  writeVarUint(encoderAwarenessState, messageAwareness);
3917
3979
  writeVarUint8Array(encoderAwarenessState, encodeAwarenessUpdate(this.awareness, [this.doc.clientID]));
3918
- const u8$1 = toUint8Array(encoder);
3919
- sendToControlGroup(this, this.topic, MessageDataType.Awareness, u8$1);
3980
+ const u82 = toUint8Array(encoder);
3981
+ sendToControlGroup(this, this.topic, MessageDataType.Awareness, u82);
3920
3982
  }
3921
3983
  };
3984
+ this.setAndEmitStatusInfo(WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.CONNECTING);
3922
3985
  return websocket;
3923
3986
  }
3924
- async start() {
3987
+ setAndEmitStatusInfo(status) {
3988
+ this._status = status;
3989
+ this.emit("status", this._status);
3990
+ }
3991
+ async connect(connectionUrlExtraParams) {
3925
3992
  if (this._wsConnected || this._ws) return;
3926
- await this.createWebSocket();
3993
+ await this.createWebSocket(connectionUrlExtraParams);
3927
3994
  }
3928
3995
  };
3929
3996
  function safeSend(data) {
@@ -3956,15 +4023,9 @@ function sendToControlGroup(client, group, type, u8) {
3956
4023
  if (!safeSend(payload)) return;
3957
4024
  client.ws?.send(payload);
3958
4025
  }
3959
-
3960
- //#endregion
3961
- //#region src/constants.ts
3962
- const WEAVE_STORE_AZURE_WEB_PUBSUB = "store-azure-web-pubsub";
3963
- const WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE = {
3964
- ["PUB"]: "pub",
3965
- ["SUB"]: "sub"
3966
- };
3967
- const WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG = { resyncIntervalMs: 15e3 };
4026
+ function isRelativeUrl(url) {
4027
+ return !/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(url);
4028
+ }
3968
4029
 
3969
4030
  //#endregion
3970
4031
  //#region src/store-azure-web-pubsub.ts
@@ -3995,9 +4056,12 @@ var WeaveStoreAzureWebPubsub = class extends WeaveStore {
3995
4056
  resyncInterval: this.azureWebPubsubOptions.resyncIntervalMs,
3996
4057
  tokenProvider: null
3997
4058
  });
4059
+ const awareness = this.provider.awareness;
4060
+ awareness.on("update", this.handleAwarenessChange.bind(this));
4061
+ awareness.on("change", this.handleAwarenessChange.bind(this));
3998
4062
  window.addEventListener("beforeunload", () => {
3999
- const awareness = this.provider.awareness;
4000
- awareness.destroy();
4063
+ const awareness$1 = this.provider.awareness;
4064
+ if (awareness$1) awareness$1.destroy();
4001
4065
  });
4002
4066
  this.provider.on("error", () => {
4003
4067
  this.handleConnectionStatusChange(WEAVE_STORE_CONNECTION_STATUS.DISCONNECTED);
@@ -4018,22 +4082,20 @@ var WeaveStoreAzureWebPubsub = class extends WeaveStore {
4018
4082
  if (this.provider) return this.provider.getClientId();
4019
4083
  return null;
4020
4084
  }
4021
- async connect() {
4085
+ async connect(extraParams) {
4022
4086
  const { fetchClient } = this.azureWebPubsubOptions;
4023
- const awareness = this.provider.awareness;
4024
- awareness.on("update", this.handleAwarenessChange.bind(this));
4025
- awareness.on("change", this.handleAwarenessChange.bind(this));
4026
4087
  this.provider.setFetchClient(fetchClient ?? window.fetch);
4027
- await this.provider.start();
4088
+ await this.provider.connect(extraParams);
4028
4089
  }
4029
4090
  disconnect() {
4030
- const awareness = this.provider.awareness;
4031
- awareness.destroy();
4032
- awareness.off("update", this.handleAwarenessChange.bind(this));
4033
- awareness.off("change", this.handleAwarenessChange.bind(this));
4034
- this.provider.destroy();
4091
+ this.provider.disconnect();
4092
+ }
4093
+ simulateWebsocketError() {
4094
+ this.provider.simulateWebsocketError();
4035
4095
  }
4096
+ destroy() {}
4036
4097
  handleAwarenessChange(emit = true) {
4098
+ if (!this.instance) return;
4037
4099
  const awareness = this.provider.awareness;
4038
4100
  const values = Array.from(awareness.getStates().values());
4039
4101
  values.splice(awareness.clientID, 1);
@@ -4046,4 +4108,4 @@ var WeaveStoreAzureWebPubsub = class extends WeaveStore {
4046
4108
  };
4047
4109
 
4048
4110
  //#endregion
4049
- export { WEAVE_STORE_AZURE_WEB_PUBSUB, WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG, WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE, WeaveStoreAzureWebPubsub };
4111
+ export { MessageDataType, MessageType, WEAVE_STORE_AZURE_WEB_PUBSUB, WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS, WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG, WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE, WeaveStoreAzureWebPubsub };
package/dist/server.d.ts CHANGED
@@ -5,20 +5,116 @@ import { Doc } from "yjs";
5
5
  import { WebSocket } from "ws";
6
6
  import koa from "koa";
7
7
  import Emittery from "emittery";
8
- import express from "express-serve-static-core";
8
+ import ReconnectingWebSocket from "reconnecting-websocket";
9
+ import * as awarenessProtocol$1 from "y-protocols/awareness";
9
10
  import * as awarenessProtocol from "y-protocols/awareness";
11
+ import { WeaveStore } from "@inditextech/weave-sdk";
12
+ import { DeepPartial, WeaveStoreOptions } from "@inditextech/weave-types";
13
+ import { Encoder } from "lib0/encoding";
14
+ import { Decoder } from "lib0/decoding";
15
+ import express from "express-serve-static-core";
10
16
  import { RequestHandler } from "express";
11
17
 
18
+ //#region src/constants.d.ts
19
+ declare const WEAVE_STORE_AZURE_WEB_PUBSUB = "store-azure-web-pubsub";
20
+ declare const WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS: {
21
+ "CONNECTING": string;
22
+ "CONNECTED": string;
23
+ "DISCONNECTED": string;
24
+ "ERROR": string;
25
+ };
26
+ declare const WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE: {
27
+ "PUB": string;
28
+ "SUB": string;
29
+ };
30
+ declare const WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG: {
31
+ resyncIntervalMs: number;
32
+ };
33
+
34
+ //#endregion
35
+ //#region src/store-azure-web-pubsub.d.ts
36
+ declare class WeaveStoreAzureWebPubsub extends WeaveStore {
37
+ private azureWebPubsubOptions;
38
+ private roomId;
39
+ private started;
40
+ private initialRoomData;
41
+ protected provider: WeaveStoreAzureWebPubSubSyncClient;
42
+ protected name: string;
43
+ protected supportsUndoManager: boolean;
44
+ protected awarenessCallback: (changes: any) => void;
45
+ constructor(initialRoomData: Uint8Array | FetchInitialState | undefined, storeOptions: WeaveStoreOptions, azureWebPubsubOptions: Pick<WeaveStoreAzureWebPubsubOptions, "roomId" | "url"> & Partial<Omit<WeaveStoreAzureWebPubsubOptions, "roomId" | "url">>);
46
+ setup(): void;
47
+ private loadRoomInitialData;
48
+ private init;
49
+ emitEvent<T>(name: string, payload?: T): void;
50
+ getClientId(): string | null;
51
+ connect(extraParams?: Record<string, string>): Promise<void>;
52
+ disconnect(): void;
53
+ simulateWebsocketError(): void;
54
+ destroy(): void;
55
+ handleAwarenessChange(emit?: boolean): void;
56
+ setAwarenessInfo<T>(field: string, value: T): void;
57
+ }
58
+
59
+ //#endregion
60
+ //#region src/client.d.ts
61
+ declare class WeaveStoreAzureWebPubSubSyncClient extends Emittery {
62
+ doc: Doc;
63
+ topic: string;
64
+ private instance;
65
+ private _ws;
66
+ private _url;
67
+ private _fetchClient;
68
+ private _status;
69
+ private _wsConnected;
70
+ private _synced;
71
+ private _resyncInterval;
72
+ private _resyncCheckInterval;
73
+ private _lastReceivedSyncResponse;
74
+ private _connectionRetries;
75
+ private _uuid;
76
+ private _awareness;
77
+ private _options;
78
+ private _initialized;
79
+ private _updateHandler;
80
+ private _awarenessUpdateHandler;
81
+ /**
82
+ * @param {string} url
83
+ * @param {string} topic
84
+ * @param {Doc} doc
85
+ * @param {number} [options.resyncInterval] Request server state every `resyncInterval` milliseconds.
86
+ * @param {number} [options.tokenProvider] token generator for negotiation.
87
+ */
88
+ constructor(instance: WeaveStoreAzureWebPubsub, url: string, topic: string, doc: Doc, options?: WeaveStoreAzureWebPubSubSyncClientOptions);
89
+ get awareness(): awarenessProtocol$1.Awareness;
90
+ get synced(): boolean;
91
+ set synced(state: boolean);
92
+ get ws(): ReconnectingWebSocket | null;
93
+ get id(): string;
94
+ getClientId(): string;
95
+ saveLastSyncResponse(): void;
96
+ setupResyncInterval(): void;
97
+ cleanupResyncInterval(): void;
98
+ simulateWebsocketError(): void;
99
+ disconnect(): void;
100
+ setFetchClient(fetchClient?: FetchClient): void;
101
+ fetchConnectionUrl(connectionUrlExtraParams?: Record<string, string>): Promise<string>;
102
+ createWebSocket(connectionUrlExtraParams?: Record<string, string>): Promise<ReconnectingWebSocket>;
103
+ setAndEmitStatusInfo(status: WeaveStoreAzureWebPubSubSyncClientConnectionStatus): void;
104
+ connect(connectionUrlExtraParams?: Record<string, string>): Promise<void>;
105
+ }
106
+
107
+ //#endregion
12
108
  //#region src/types.d.ts
13
109
  type WeaveStoreAzureWebPubsubConfig = {
14
110
  endpoint: string;
111
+ persistIntervalMs?: number;
15
112
  hubName: string;
16
113
  auth?: {
17
114
  key?: string;
18
115
  custom?: TokenCredential;
19
116
  };
20
- connectionHandlers?: Pick<WeaveAzureWebPubsubSyncHandlerOptions, "onConnect" | "onConnected" | "removeConnection" | "getConnectionRoom" | "getRoomConnections">;
21
- persistIntervalMs?: number;
117
+ connectionHandlers?: DeepPartial<WeaveAzureWebPubsubSyncHandlerOptions>;
22
118
  };
23
119
  type WeaveAzureWebPubsubSyncHandlerOptions = {
24
120
  onConnect?: (connectionId: string, queries: Record<string, string[]> | undefined) => Promise<void>;
@@ -81,6 +177,39 @@ type WeaveStoreAzureWebPubsubOnWebsocketErrorEvent = {
81
177
  type WeaveStoreAzureWebPubsubOnWebsocketOnTokenRefreshEvent = {
82
178
  group: string;
83
179
  };
180
+ type WeaveStoreAzureWebPubSubSyncHostClientConnectOptions = {
181
+ expirationTimeInMinutes?: number;
182
+ };
183
+ type WeaveStoreAzureWebPubSubSyncClientConnectionStatusKeys = keyof typeof WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS;
184
+ type WeaveStoreAzureWebPubSubSyncClientConnectionStatus = (typeof WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS)[WeaveStoreAzureWebPubSubSyncClientConnectionStatusKeys];
185
+ declare enum MessageType {
186
+ System = "system",
187
+ JoinGroup = "joinGroup",
188
+ SendToGroup = "sendToGroup",
189
+ }
190
+ declare enum MessageDataType {
191
+ Init = "init",
192
+ Sync = "sync",
193
+ Awareness = "awareness",
194
+ }
195
+ interface MessageData {
196
+ group: string;
197
+ t: string;
198
+ f: string;
199
+ c: string;
200
+ }
201
+ interface Message {
202
+ type: string;
203
+ fromUserId: string;
204
+ from: string;
205
+ group: string;
206
+ data: MessageData;
207
+ }
208
+ type MessageHandler = (encoder: Encoder, decoder: Decoder, client: WeaveStoreAzureWebPubSubSyncClient, clientId: string, emitSynced: boolean, messageType: number) => void;
209
+ interface WeaveStoreAzureWebPubSubSyncClientOptions {
210
+ resyncInterval: number;
211
+ tokenProvider: Promise<string> | null;
212
+ }
84
213
 
85
214
  //#endregion
86
215
  //#region src/server/event-handler/enum/mqtt-error-codes/mqtt-disconnect-reason-code.d.ts
@@ -407,7 +536,9 @@ declare enum MqttV500ConnectReasonCode {
407
536
  * Description: The connection rate limit has been exceeded.
408
537
  */
409
538
  ConnectionRateExceeded = 159,
410
- } //#endregion
539
+ }
540
+
541
+ //#endregion
411
542
  //#region src/server/event-handler/cloud-events-protocols.d.ts
412
543
  /**
413
544
  * Response of the connect event.
@@ -869,16 +1000,21 @@ declare class WebPubSubEventHandler {
869
1000
  //#region src/server/azure-web-pubsub-host.d.ts
870
1001
  declare class WeaveStoreAzureWebPubSubSyncHost {
871
1002
  private readonly server;
1003
+ private readonly syncHandler;
872
1004
  doc: Y.Doc;
873
1005
  topic: string;
874
1006
  topicAwarenessChannel: string;
875
1007
  private _client;
876
1008
  private _conn;
1009
+ private _reconnectAttempts;
1010
+ private _forceClose;
877
1011
  private _awareness;
878
- constructor(server: WeaveAzureWebPubsubServer, client: WebPubSubServiceClient, topic: string, doc: Y.Doc);
1012
+ private _updateHandler;
1013
+ private _awarenessUpdateHandler;
1014
+ constructor(server: WeaveAzureWebPubsubServer, syncHandler: WeaveAzureWebPubsubSyncHandler, client: WebPubSubServiceClient, topic: string, doc: Y.Doc);
879
1015
  get awareness(): awarenessProtocol.Awareness;
880
1016
  sendInitAwarenessInfo(origin: string): void;
881
- createWebSocket(sleep?: number): Promise<void>;
1017
+ createWebSocket(): Promise<void>;
882
1018
  start(): Promise<void>;
883
1019
  stop(): Promise<void>;
884
1020
  simulateWebsocketError(): void;
@@ -901,17 +1037,19 @@ declare class WeaveAzureWebPubsubSyncHandler extends WebPubSubEventHandler {
901
1037
  private readonly syncOptions?;
902
1038
  private initialState;
903
1039
  private readonly server;
1040
+ private readonly roomsLastState;
904
1041
  constructor(hub: string, server: WeaveAzureWebPubsubServer, client: WebPubSubServiceClient, initialState: FetchInitialState, syncHandlerOptions?: WeaveAzureWebPubsubSyncHandlerOptions, eventHandlerOptions?: WebPubSubEventHandlerOptions);
905
1042
  private getNewYDoc;
906
1043
  private setupRoomInstance;
907
- private persistRoomTask;
1044
+ isPersistingOnInterval(): boolean;
908
1045
  private setupRoomInstancePersistence;
1046
+ persistRoomTask(roomId: string): Promise<void>;
909
1047
  private handleConnectionDisconnection;
910
1048
  destroyRoomInstance(roomId: string): Promise<void>;
911
1049
  private getHostConnection;
912
1050
  getRoomsLoaded(): string[];
913
1051
  getRoomSyncHost(roomId: string): WeaveStoreAzureWebPubSubSyncHost | undefined;
914
- clientConnect(roomId: string): Promise<string>;
1052
+ clientConnect(roomId: string, connectionOptions?: WeaveStoreAzureWebPubSubSyncHostClientConnectOptions): Promise<string>;
915
1053
  }
916
1054
 
917
1055
  //#endregion
@@ -941,19 +1079,8 @@ declare class WeaveAzureWebPubsubServer extends Emittery {
941
1079
  emitEvent<T>(event: string, payload?: T): void;
942
1080
  addEventListener<T>(event: string, callback: (payload: T) => void): void;
943
1081
  removeEventListener<T>(event: string, callback: (payload: T) => void): void;
944
- clientConnect(roomId: string): Promise<string | null>;
1082
+ clientConnect(roomId: string, connectionOptions?: WeaveStoreAzureWebPubSubSyncHostClientConnectOptions): Promise<string | null>;
945
1083
  }
946
1084
 
947
1085
  //#endregion
948
- //#region src/constants.d.ts
949
- declare const WEAVE_STORE_AZURE_WEB_PUBSUB = "store-azure-web-pubsub";
950
- declare const WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE: {
951
- "PUB": string;
952
- "SUB": string;
953
- };
954
- declare const WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG: {
955
- resyncIntervalMs: number;
956
- };
957
-
958
- //#endregion
959
- export { Certificate, ConnectErrorResponse, ConnectRequest, ConnectResponse, ConnectResponseHandler, ConnectedRequest, ConnectionContext, DisconnectedRequest, FetchClient, FetchInitialState, FetchRoom, MqttConnectErrorResponse, MqttConnectErrorResponseProperties, MqttConnectProperties, MqttConnectRequest, MqttConnectResponse, MqttConnectResponseProperties, MqttConnectionContextProperties, MqttDisconnectPacket, MqttDisconnectReasonCode, MqttDisconnectedProperties, MqttDisconnectedRequest, MqttUserProperty, MqttV311ConnectReturnCode, MqttV500ConnectReasonCode, PersistRoom, UserEventRequest, UserEventResponseHandler, WEAVE_STORE_AZURE_WEB_PUBSUB, WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG, WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE, WeaveAzureWebPubsubServer, WeaveAzureWebPubsubSyncHandlerOptions, WeaveStoreAzureWebPubSubSyncHost, WeaveStoreAzureWebPubsubConfig, WeaveStoreAzureWebPubsubEvents, WeaveStoreAzureWebPubsubOnConnectEvent, WeaveStoreAzureWebPubsubOnConnectedEvent, WeaveStoreAzureWebPubsubOnDisconnectedEvent, WeaveStoreAzureWebPubsubOnStoreFetchConnectionUrlEvent, WeaveStoreAzureWebPubsubOnWebsocketCloseEvent, WeaveStoreAzureWebPubsubOnWebsocketErrorEvent, WeaveStoreAzureWebPubsubOnWebsocketJoinGroupEvent, WeaveStoreAzureWebPubsubOnWebsocketMessageEvent, WeaveStoreAzureWebPubsubOnWebsocketOnTokenRefreshEvent, WeaveStoreAzureWebPubsubOnWebsocketOpenEvent, WeaveStoreAzureWebPubsubOptions, WebPubSubClientProtocol, WebPubSubEventHandler, WebPubSubEventHandlerOptions };
1086
+ export { Certificate, ConnectErrorResponse, ConnectRequest, ConnectResponse, ConnectResponseHandler, ConnectedRequest, ConnectionContext, DisconnectedRequest, FetchClient, FetchInitialState, FetchRoom, Message, MessageData, MessageDataType, MessageHandler, MessageType, MqttConnectErrorResponse, MqttConnectErrorResponseProperties, MqttConnectProperties, MqttConnectRequest, MqttConnectResponse, MqttConnectResponseProperties, MqttConnectionContextProperties, MqttDisconnectPacket, MqttDisconnectReasonCode, MqttDisconnectedProperties, MqttDisconnectedRequest, MqttUserProperty, MqttV311ConnectReturnCode, MqttV500ConnectReasonCode, PersistRoom, UserEventRequest, UserEventResponseHandler, WEAVE_STORE_AZURE_WEB_PUBSUB, WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS, WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG, WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE, WeaveAzureWebPubsubServer, WeaveAzureWebPubsubSyncHandlerOptions, WeaveStoreAzureWebPubSubSyncClientConnectionStatus, WeaveStoreAzureWebPubSubSyncClientConnectionStatusKeys, WeaveStoreAzureWebPubSubSyncClientOptions, WeaveStoreAzureWebPubSubSyncHost, WeaveStoreAzureWebPubSubSyncHostClientConnectOptions, WeaveStoreAzureWebPubsubConfig, WeaveStoreAzureWebPubsubEvents, WeaveStoreAzureWebPubsubOnConnectEvent, WeaveStoreAzureWebPubsubOnConnectedEvent, WeaveStoreAzureWebPubsubOnDisconnectedEvent, WeaveStoreAzureWebPubsubOnStoreFetchConnectionUrlEvent, WeaveStoreAzureWebPubsubOnWebsocketCloseEvent, WeaveStoreAzureWebPubsubOnWebsocketErrorEvent, WeaveStoreAzureWebPubsubOnWebsocketJoinGroupEvent, WeaveStoreAzureWebPubsubOnWebsocketMessageEvent, WeaveStoreAzureWebPubsubOnWebsocketOnTokenRefreshEvent, WeaveStoreAzureWebPubsubOnWebsocketOpenEvent, WeaveStoreAzureWebPubsubOptions, WebPubSubClientProtocol, WebPubSubEventHandler, WebPubSubEventHandlerOptions };
package/dist/server.js CHANGED
@@ -8,6 +8,7 @@ import { URL as URL$1 } from "node:url";
8
8
  import { EOL } from "node:os";
9
9
  import process$1 from "node:process";
10
10
  import { WebSocket } from "ws";
11
+ import crypto from "node:crypto";
11
12
  import { defaultInitialState } from "@inditextech/weave-sdk/server";
12
13
 
13
14
  //#region rolldown:runtime
@@ -18609,6 +18610,12 @@ var require_response = __commonJS({ "../../node_modules/koa/lib/response.js"(exp
18609
18610
  set body(val) {
18610
18611
  const original = this._body;
18611
18612
  this._body = val;
18613
+ const cleanupPreviousStream = () => {
18614
+ if (original && isStream$1(original)) {
18615
+ original.once("error", () => {});
18616
+ if (!isStream$1(val)) destroy$1(original);
18617
+ }
18618
+ };
18612
18619
  if (val == null) {
18613
18620
  if (!statuses$3.empty[this.status]) {
18614
18621
  if (this.type === "application/json") {
@@ -18621,6 +18628,7 @@ var require_response = __commonJS({ "../../node_modules/koa/lib/response.js"(exp
18621
18628
  this.remove("Content-Type");
18622
18629
  this.remove("Content-Length");
18623
18630
  this.remove("Transfer-Encoding");
18631
+ cleanupPreviousStream();
18624
18632
  return;
18625
18633
  }
18626
18634
  if (!this._explicitStatus) this.status = 200;
@@ -18628,29 +18636,33 @@ var require_response = __commonJS({ "../../node_modules/koa/lib/response.js"(exp
18628
18636
  if (typeof val === "string") {
18629
18637
  if (setType) this.type = /^\s*</.test(val) ? "html" : "text";
18630
18638
  this.length = Buffer.byteLength(val);
18639
+ cleanupPreviousStream();
18631
18640
  return;
18632
18641
  }
18633
18642
  if (Buffer.isBuffer(val)) {
18634
18643
  if (setType) this.type = "bin";
18635
18644
  this.length = val.length;
18645
+ cleanupPreviousStream();
18636
18646
  return;
18637
18647
  }
18638
18648
  if (isStream$1(val)) {
18639
18649
  onFinish(this.res, destroy$1.bind(null, val));
18640
18650
  if (original !== val) {
18641
- val.once("error", (err) => this.ctx.onerror(err));
18642
18651
  if (original != null) this.remove("Content-Length");
18652
+ cleanupPreviousStream();
18643
18653
  }
18644
18654
  if (setType) this.type = "bin";
18645
18655
  return;
18646
18656
  }
18647
18657
  if (val instanceof ReadableStream) {
18648
18658
  if (setType) this.type = "bin";
18659
+ cleanupPreviousStream();
18649
18660
  return;
18650
18661
  }
18651
18662
  if (val instanceof Blob) {
18652
18663
  if (setType) this.type = "bin";
18653
18664
  this.length = val.size;
18665
+ cleanupPreviousStream();
18654
18666
  return;
18655
18667
  }
18656
18668
  if (val instanceof Response) {
@@ -18658,10 +18670,12 @@ var require_response = __commonJS({ "../../node_modules/koa/lib/response.js"(exp
18658
18670
  if (setType) this.type = "bin";
18659
18671
  const headers = val.headers;
18660
18672
  for (const key of headers.keys()) this.set(key, headers.get(key));
18673
+ cleanupPreviousStream();
18661
18674
  return;
18662
18675
  }
18663
18676
  this.remove("Content-Length");
18664
18677
  if (!this.type || !/\bjson\b/i.test(this.type)) this.type = "json";
18678
+ cleanupPreviousStream();
18665
18679
  },
18666
18680
  set length(n) {
18667
18681
  if (!this.has("Transfer-Encoding")) this.set("Content-Length", n);
@@ -19818,19 +19832,19 @@ var require_delegates = __commonJS({ "../../node_modules/delegates/index.js"(exp
19818
19832
  //#endregion
19819
19833
  //#region ../../node_modules/tsscmp/lib/index.js
19820
19834
  var require_lib = __commonJS({ "../../node_modules/tsscmp/lib/index.js"(exports, module) {
19821
- var crypto$1 = __require("crypto");
19835
+ var crypto$2 = __require("crypto");
19822
19836
  function bufferEqual(a, b) {
19823
19837
  if (a.length !== b.length) return false;
19824
- if (crypto$1.timingSafeEqual) return crypto$1.timingSafeEqual(a, b);
19838
+ if (crypto$2.timingSafeEqual) return crypto$2.timingSafeEqual(a, b);
19825
19839
  for (var i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
19826
19840
  return true;
19827
19841
  }
19828
19842
  function timeSafeCompare(a, b) {
19829
19843
  var sa = String(a);
19830
19844
  var sb = String(b);
19831
- var key = crypto$1.pseudoRandomBytes(32);
19832
- var ah = crypto$1.createHmac("sha256", key).update(sa).digest();
19833
- var bh = crypto$1.createHmac("sha256", key).update(sb).digest();
19845
+ var key = crypto$2.pseudoRandomBytes(32);
19846
+ var ah = crypto$2.createHmac("sha256", key).update(sa).digest();
19847
+ var bh = crypto$2.createHmac("sha256", key).update(sb).digest();
19834
19848
  return bufferEqual(ah, bh) && a === b;
19835
19849
  }
19836
19850
  module.exports = timeSafeCompare;
@@ -19840,14 +19854,14 @@ var require_lib = __commonJS({ "../../node_modules/tsscmp/lib/index.js"(exports,
19840
19854
  //#region ../../node_modules/keygrip/index.js
19841
19855
  var require_keygrip = __commonJS({ "../../node_modules/keygrip/index.js"(exports, module) {
19842
19856
  var compare = require_lib();
19843
- var crypto = __require("crypto");
19857
+ var crypto$1 = __require("crypto");
19844
19858
  function Keygrip$1(keys$1, algorithm, encoding) {
19845
19859
  if (!algorithm) algorithm = "sha1";
19846
19860
  if (!encoding) encoding = "base64";
19847
19861
  if (!(this instanceof Keygrip$1)) return new Keygrip$1(keys$1, algorithm, encoding);
19848
19862
  if (!keys$1 || !(0 in keys$1)) throw new Error("Keys must be provided.");
19849
19863
  function sign(data, key) {
19850
- return crypto.createHmac(algorithm, key).update(data).digest(encoding).replace(/\/|\+|=/g, function(x) {
19864
+ return crypto$1.createHmac(algorithm, key).update(data).digest(encoding).replace(/\/|\+|=/g, function(x) {
19851
19865
  return {
19852
19866
  "/": "_",
19853
19867
  "+": "-",
@@ -20389,10 +20403,14 @@ var require_application = __commonJS({ "../../node_modules/koa/lib/application.j
20389
20403
  }
20390
20404
  if (Buffer.isBuffer(body)) return res.end(body);
20391
20405
  if (typeof body === "string") return res.end(body);
20392
- if (body instanceof Blob) return Stream.Readable.from(body.stream()).pipe(res);
20393
- if (body instanceof ReadableStream) return Stream.Readable.from(body).pipe(res);
20394
- if (body instanceof Response) return Stream.Readable.from(body?.body || "").pipe(res);
20395
- if (isStream(body)) return body.pipe(res);
20406
+ let stream = null;
20407
+ if (body instanceof Blob) stream = Stream.Readable.from(body.stream());
20408
+ else if (body instanceof ReadableStream) stream = Stream.Readable.from(body);
20409
+ else if (body instanceof Response) stream = Stream.Readable.from(body?.body || "");
20410
+ else if (isStream(body)) stream = body;
20411
+ if (stream) return Stream.pipeline(stream, res, (err) => {
20412
+ if (err && ctx.app.listenerCount("error")) ctx.onerror(err);
20413
+ });
20396
20414
  body = JSON.stringify(body);
20397
20415
  if (!res.headersSent) ctx.length = Buffer.byteLength(body);
20398
20416
  res.end(body);
@@ -20769,6 +20787,21 @@ Object.defineProperty(Emittery, "listenerRemoved", {
20769
20787
  configurable: false
20770
20788
  });
20771
20789
 
20790
+ //#endregion
20791
+ //#region src/types.ts
20792
+ let MessageType = /* @__PURE__ */ function(MessageType$2) {
20793
+ MessageType$2["System"] = "system";
20794
+ MessageType$2["JoinGroup"] = "joinGroup";
20795
+ MessageType$2["SendToGroup"] = "sendToGroup";
20796
+ return MessageType$2;
20797
+ }({});
20798
+ let MessageDataType = /* @__PURE__ */ function(MessageDataType$2) {
20799
+ MessageDataType$2["Init"] = "init";
20800
+ MessageDataType$2["Sync"] = "sync";
20801
+ MessageDataType$2["Awareness"] = "awareness";
20802
+ return MessageDataType$2;
20803
+ }({});
20804
+
20772
20805
  //#endregion
20773
20806
  //#region src/yjs.ts
20774
20807
  var yjs_default = Y$1;
@@ -22809,61 +22842,74 @@ const expirationTimeInMinutes = 60;
22809
22842
  const messageSync = 0;
22810
22843
  const messageAwareness = 1;
22811
22844
  const AzureWebPubSubJsonProtocol = "json.webpubsub.azure.v1";
22812
- let MessageType = /* @__PURE__ */ function(MessageType$1) {
22813
- MessageType$1["System"] = "system";
22814
- MessageType$1["JoinGroup"] = "joinGroup";
22815
- MessageType$1["SendToGroup"] = "sendToGroup";
22816
- return MessageType$1;
22845
+ let MessageType$1 = /* @__PURE__ */ function(MessageType$2) {
22846
+ MessageType$2["System"] = "system";
22847
+ MessageType$2["JoinGroup"] = "joinGroup";
22848
+ MessageType$2["SendToGroup"] = "sendToGroup";
22849
+ return MessageType$2;
22817
22850
  }({});
22818
- let MessageDataType = /* @__PURE__ */ function(MessageDataType$1) {
22819
- MessageDataType$1["Init"] = "init";
22820
- MessageDataType$1["Sync"] = "sync";
22821
- MessageDataType$1["Awareness"] = "awareness";
22822
- return MessageDataType$1;
22851
+ let MessageDataType$1 = /* @__PURE__ */ function(MessageDataType$2) {
22852
+ MessageDataType$2["Init"] = "init";
22853
+ MessageDataType$2["Sync"] = "sync";
22854
+ MessageDataType$2["Awareness"] = "awareness";
22855
+ return MessageDataType$2;
22823
22856
  }({});
22824
22857
  const HostUserId = "host";
22825
22858
  var WeaveStoreAzureWebPubSubSyncHost = class {
22826
- constructor(server, client, topic, doc) {
22859
+ _reconnectAttempts = 0;
22860
+ _forceClose = false;
22861
+ constructor(server, syncHandler, client, topic, doc) {
22827
22862
  this.server = server;
22863
+ this.syncHandler = syncHandler;
22828
22864
  this.doc = doc;
22829
22865
  this.topic = topic;
22830
22866
  this.topicAwarenessChannel = `${topic}-awareness`;
22831
22867
  this._client = client;
22832
22868
  this._conn = null;
22833
22869
  this._awareness = new Awareness(this.doc);
22834
- this._awareness.setLocalState(null);
22835
- const awarenessUpdateHandler = ({ added, updated, removed }, origin) => {
22836
- const changedClients = added.concat(added, updated, removed);
22837
- const encoder = createEncoder();
22838
- writeVarUint(encoder, messageAwareness);
22839
- writeVarUint8Array(encoder, encodeAwarenessUpdate(this._awareness, changedClients));
22840
- const u8 = toUint8Array(encoder);
22841
- this.broadcast(this.topic, origin, u8);
22870
+ this._awarenessUpdateHandler = ({ added, updated, removed }, origin) => {
22871
+ try {
22872
+ const changedClients = added.concat(added, updated, removed);
22873
+ const encoder = createEncoder();
22874
+ writeVarUint(encoder, messageAwareness);
22875
+ const payload = encodeAwarenessUpdate(this._awareness, changedClients);
22876
+ writeVarUint8Array(encoder, payload);
22877
+ const u8 = toUint8Array(encoder);
22878
+ this.broadcast(this.topic, origin, u8);
22879
+ } catch (err) {
22880
+ console.error("Error in awareness update handler:", err);
22881
+ }
22842
22882
  };
22843
- this._awareness.on("update", awarenessUpdateHandler);
22844
- const updateHandler = (update, origin) => {
22845
- const encoder = createEncoder();
22846
- writeVarUint(encoder, messageSync);
22847
- writeUpdate(encoder, update);
22848
- const u8 = toUint8Array(encoder);
22849
- this.broadcast(this.topic, origin, u8);
22883
+ this._awareness.on("update", this._awarenessUpdateHandler);
22884
+ this._updateHandler = (update, origin) => {
22885
+ try {
22886
+ const encoder = createEncoder();
22887
+ writeVarUint(encoder, messageSync);
22888
+ writeUpdate(encoder, update);
22889
+ const u8 = toUint8Array(encoder);
22890
+ this.broadcast(this.topic, origin, u8);
22891
+ if (!this.syncHandler.isPersistingOnInterval()) this.syncHandler.persistRoomTask(this.topic);
22892
+ } catch (err) {
22893
+ console.error("Error in document update handler:", err);
22894
+ }
22850
22895
  };
22851
- this.doc.on("update", updateHandler);
22896
+ this.doc.on("update", this._updateHandler);
22852
22897
  }
22853
22898
  get awareness() {
22854
22899
  return this._awareness;
22855
22900
  }
22856
22901
  sendInitAwarenessInfo(origin) {
22902
+ if (!this._awareness) return;
22857
22903
  const encoderAwarenessState = createEncoder();
22858
22904
  writeVarUint(encoderAwarenessState, messageAwareness);
22859
22905
  writeVarUint8Array(encoderAwarenessState, encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
22860
22906
  const u8 = toUint8Array(encoderAwarenessState);
22861
22907
  this.broadcast(this.topic, origin, u8);
22862
22908
  }
22863
- async createWebSocket(sleep = 0) {
22909
+ async createWebSocket() {
22864
22910
  const group = this.topic;
22865
22911
  const { url: url$1 } = await this.negotiate(this.topic);
22866
- if (sleep && sleep > 0) await new Promise((resolve) => setTimeout(resolve, sleep));
22912
+ this._reconnectAttempts++;
22867
22913
  return new Promise((resolve) => {
22868
22914
  const ws = new WebSocket(url$1, AzureWebPubSubJsonProtocol);
22869
22915
  ws.addEventListener("open", (event) => {
@@ -22872,7 +22918,7 @@ var WeaveStoreAzureWebPubSubSyncHost = class {
22872
22918
  event
22873
22919
  });
22874
22920
  ws.send(JSON.stringify({
22875
- type: MessageType.JoinGroup,
22921
+ type: MessageType$1.JoinGroup,
22876
22922
  group: `${group}.host`
22877
22923
  }));
22878
22924
  this.server.emitEvent("onWsJoinGroup", { group: `${group}.host` });
@@ -22886,15 +22932,15 @@ var WeaveStoreAzureWebPubSubSyncHost = class {
22886
22932
  });
22887
22933
  const event = JSON.parse(e.data.toString());
22888
22934
  if (event.type === "message" && event.from === "group") switch (event.data.t) {
22889
- case MessageDataType.Init:
22935
+ case MessageDataType$1.Init:
22890
22936
  this.onClientInit(group, event.data);
22891
22937
  this.onClientSync(group, event.data);
22892
22938
  this.sendInitAwarenessInfo(event.data.f);
22893
22939
  return;
22894
- case MessageDataType.Sync:
22940
+ case MessageDataType$1.Sync:
22895
22941
  this.onClientSync(group, event.data);
22896
22942
  return;
22897
- case MessageDataType.Awareness:
22943
+ case MessageDataType$1.Awareness:
22898
22944
  this.onAwareness(group, event.data);
22899
22945
  return;
22900
22946
  }
@@ -22904,9 +22950,12 @@ var WeaveStoreAzureWebPubSubSyncHost = class {
22904
22950
  group: `${group}.host`,
22905
22951
  event: e
22906
22952
  });
22907
- if (e.code === 1008 && ws.readyState === WebSocket.OPEN) {
22908
- ws.close();
22909
- this.createWebSocket();
22953
+ if (this._forceClose) return;
22954
+ else {
22955
+ const timeout = 1e3 * Math.pow(1.5, this._reconnectAttempts);
22956
+ setTimeout(() => {
22957
+ this.createWebSocket();
22958
+ }, timeout);
22910
22959
  }
22911
22960
  });
22912
22961
  ws.addEventListener("error", (error) => {
@@ -22915,7 +22964,6 @@ var WeaveStoreAzureWebPubSubSyncHost = class {
22915
22964
  error
22916
22965
  });
22917
22966
  if (ws.readyState === WebSocket.OPEN) ws.close();
22918
- this.createWebSocket(2e4);
22919
22967
  });
22920
22968
  setTimeout(() => {
22921
22969
  if (ws.readyState === WebSocket.OPEN) {
@@ -22930,6 +22978,7 @@ var WeaveStoreAzureWebPubSubSyncHost = class {
22930
22978
  await this.createWebSocket();
22931
22979
  }
22932
22980
  async stop() {
22981
+ this._forceClose = true;
22933
22982
  if (this._conn?.readyState === WebSocket.OPEN) {
22934
22983
  this._conn?.close();
22935
22984
  this._conn = null;
@@ -22948,30 +22997,38 @@ var WeaveStoreAzureWebPubSubSyncHost = class {
22948
22997
  return true;
22949
22998
  }
22950
22999
  broadcast(group, from$1, u8) {
22951
- const payload = JSON.stringify({
22952
- type: MessageType.SendToGroup,
22953
- group,
22954
- noEcho: true,
22955
- data: {
22956
- f: from$1,
22957
- c: Buffer.from(u8).toString("base64")
22958
- }
22959
- });
22960
- if (!this.safeSend(payload)) return;
22961
- this._conn?.send?.(payload);
23000
+ try {
23001
+ const payload = JSON.stringify({
23002
+ type: MessageType$1.SendToGroup,
23003
+ group,
23004
+ noEcho: true,
23005
+ data: {
23006
+ f: from$1,
23007
+ c: Buffer.from(u8).toString("base64")
23008
+ }
23009
+ });
23010
+ if (!this.safeSend(payload)) return;
23011
+ this._conn?.send?.(payload);
23012
+ } catch (ex) {
23013
+ console.error("Error broadcasting message:", ex);
23014
+ }
22962
23015
  }
22963
23016
  send(group, to, u8) {
22964
- const payload = JSON.stringify({
22965
- type: MessageType.SendToGroup,
22966
- group,
22967
- noEcho: true,
22968
- data: {
22969
- t: to,
22970
- c: Buffer.from(u8).toString("base64")
22971
- }
22972
- });
22973
- if (!this.safeSend(payload)) return;
22974
- this._conn?.send?.(payload);
23017
+ try {
23018
+ const payload = JSON.stringify({
23019
+ type: MessageType$1.SendToGroup,
23020
+ group,
23021
+ noEcho: true,
23022
+ data: {
23023
+ t: to,
23024
+ c: Buffer.from(u8).toString("base64")
23025
+ }
23026
+ });
23027
+ if (!this.safeSend(payload)) return;
23028
+ this._conn?.send?.(payload);
23029
+ } catch (ex) {
23030
+ console.error("Error sending message:", ex);
23031
+ }
22975
23032
  }
22976
23033
  onClientInit(group, data) {
22977
23034
  const encoder = createEncoder();
@@ -23003,6 +23060,7 @@ var WeaveStoreAzureWebPubSubSyncHost = class {
23003
23060
  const decoder = createDecoder(buf);
23004
23061
  readVarUint(decoder);
23005
23062
  const update = readVarUint8Array(decoder);
23063
+ if (!this._awareness) return;
23006
23064
  applyAwarenessUpdate(this._awareness, update, void 0);
23007
23065
  } catch (err) {
23008
23066
  this.doc.emit("error", [err]);
@@ -23023,12 +23081,27 @@ var WeaveStoreAzureWebPubSubSyncHost = class {
23023
23081
  }
23024
23082
  };
23025
23083
 
23084
+ //#endregion
23085
+ //#region src/server/utils.ts
23086
+ function getStateAsJson(actualState) {
23087
+ const document = new yjs_default.Doc();
23088
+ yjs_default.applyUpdate(document, actualState);
23089
+ const actualStateString = JSON.stringify(document.getMap("weave").toJSON());
23090
+ const actualStateJson = JSON.parse(actualStateString);
23091
+ return actualStateJson;
23092
+ }
23093
+ function hashJson(obj) {
23094
+ const jsonString = JSON.stringify(obj);
23095
+ return crypto.createHash("sha256").update(jsonString).digest("hex");
23096
+ }
23097
+
23026
23098
  //#endregion
23027
23099
  //#region src/server/azure-web-pubsub-sync-handler.ts
23028
23100
  var WeaveAzureWebPubsubSyncHandler = class extends WebPubSubEventHandler {
23029
23101
  _rooms = new Map();
23030
23102
  _roomsSyncHost = new Map();
23031
23103
  _store_persistence = new Map();
23104
+ roomsLastState = new Map();
23032
23105
  constructor(hub, server, client, initialState, syncHandlerOptions, eventHandlerOptions) {
23033
23106
  super(hub, {
23034
23107
  ...eventHandlerOptions,
@@ -23053,6 +23126,7 @@ var WeaveAzureWebPubsubSyncHandler = class extends WebPubSubEventHandler {
23053
23126
  this.server = server;
23054
23127
  this.initialState = initialState;
23055
23128
  this._client = client;
23129
+ if (this.isPersistingOnInterval()) console.warn(`Room persistence defined via interval, be aware that this can lead to data loss. Consider persisting on document updates instead.`);
23056
23130
  }
23057
23131
  getNewYDoc() {
23058
23132
  return new yjs_default.Doc();
@@ -23064,29 +23138,44 @@ var WeaveAzureWebPubsubSyncHandler = class extends WebPubSubEventHandler {
23064
23138
  if (this.server?.fetchRoom) documentData = await this.server.fetchRoom(roomId);
23065
23139
  if (documentData) yjs_default.applyUpdate(doc, documentData);
23066
23140
  else this.initialState(doc);
23067
- this._roomsSyncHost.set(roomId, new WeaveStoreAzureWebPubSubSyncHost(this.server, this._client, roomId, doc));
23141
+ this._roomsSyncHost.set(roomId, new WeaveStoreAzureWebPubSubSyncHost(this.server, this, this._client, roomId, doc));
23068
23142
  const connection = this._roomsSyncHost.get(roomId);
23069
23143
  await connection.start();
23070
- await this.setupRoomInstancePersistence(roomId);
23144
+ if (this.isPersistingOnInterval()) this.setupRoomInstancePersistence(roomId);
23145
+ }
23146
+ isPersistingOnInterval() {
23147
+ return this.syncOptions?.persistIntervalMs !== void 0;
23148
+ }
23149
+ async setupRoomInstancePersistence(roomId) {
23150
+ if (!this._store_persistence.has(roomId)) {
23151
+ const intervalId = setInterval(async () => {
23152
+ await this.persistRoomTask(roomId);
23153
+ }, this.syncOptions?.persistIntervalMs ?? 5e3);
23154
+ this._store_persistence.set(roomId, intervalId);
23155
+ }
23071
23156
  }
23072
23157
  async persistRoomTask(roomId) {
23073
23158
  try {
23074
23159
  const doc = this._rooms.get(roomId);
23075
23160
  if (!doc) return;
23076
23161
  const actualState = yjs_default.encodeStateAsUpdate(doc);
23162
+ if (!this.isPersistingOnInterval()) {
23163
+ const savedRoomData = this.roomsLastState.get(roomId);
23164
+ if (savedRoomData) {
23165
+ const savedStateJson = getStateAsJson(savedRoomData);
23166
+ const savedHash = hashJson(savedStateJson);
23167
+ const actualStateJson = getStateAsJson(actualState);
23168
+ const actualHash = hashJson(actualStateJson);
23169
+ const same = savedHash === actualHash;
23170
+ if (same) return;
23171
+ this.roomsLastState.set(roomId, actualState);
23172
+ }
23173
+ }
23077
23174
  if (this.server?.persistRoom) await this.server.persistRoom(roomId, actualState);
23078
23175
  } catch (ex) {
23079
23176
  console.error(ex);
23080
23177
  }
23081
23178
  }
23082
- async setupRoomInstancePersistence(roomId) {
23083
- if (!this._store_persistence.has(roomId)) {
23084
- const intervalId = setInterval(async () => {
23085
- await this.persistRoomTask(roomId);
23086
- }, this.syncOptions?.persistIntervalMs ?? 5e3);
23087
- this._store_persistence.set(roomId, intervalId);
23088
- }
23089
- }
23090
23179
  async handleConnectionDisconnection(connectionId) {
23091
23180
  const connectionRoom = await this.syncOptions?.getConnectionRoom?.(connectionId);
23092
23181
  if (connectionRoom) await this.syncOptions?.removeConnection?.(connectionId);
@@ -23094,10 +23183,13 @@ var WeaveAzureWebPubsubSyncHandler = class extends WebPubSubEventHandler {
23094
23183
  if (connectionRoom && roomConnections?.length === 0) await this.destroyRoomInstance(connectionRoom);
23095
23184
  }
23096
23185
  async destroyRoomInstance(roomId) {
23097
- const intervalId = this._store_persistence.get(roomId);
23098
- if (intervalId) clearInterval(intervalId);
23099
- this._store_persistence.delete(roomId);
23186
+ if (this.isPersistingOnInterval()) {
23187
+ const intervalId = this._store_persistence.get(roomId);
23188
+ if (intervalId) clearInterval(intervalId);
23189
+ this._store_persistence.delete(roomId);
23190
+ }
23100
23191
  await this.persistRoomTask(roomId);
23192
+ if (!this.isPersistingOnInterval()) this.roomsLastState.delete(roomId);
23101
23193
  const syncHost = this._roomsSyncHost.get(roomId);
23102
23194
  if (syncHost) {
23103
23195
  await syncHost.stop();
@@ -23114,11 +23206,12 @@ var WeaveAzureWebPubsubSyncHandler = class extends WebPubSubEventHandler {
23114
23206
  getRoomSyncHost(roomId) {
23115
23207
  return this._roomsSyncHost.get(roomId);
23116
23208
  }
23117
- async clientConnect(roomId) {
23209
+ async clientConnect(roomId, connectionOptions) {
23118
23210
  await this.getHostConnection(roomId);
23119
23211
  const token = await this._client.getClientAccessToken({
23120
23212
  groups: [roomId],
23121
- roles: [`webpubsub.joinLeaveGroup.${roomId}`, `webpubsub.sendToGroup.${roomId}.host`]
23213
+ roles: [`webpubsub.joinLeaveGroup.${roomId}`, `webpubsub.sendToGroup.${roomId}.host`],
23214
+ ...connectionOptions
23122
23215
  });
23123
23216
  const finalURL = `${token.url}&group=${roomId}`;
23124
23217
  return finalURL;
@@ -23143,7 +23236,7 @@ var WeaveAzureWebPubsubServer = class extends Emittery {
23143
23236
  credentials ??= new DefaultAzureCredential();
23144
23237
  this.syncClient = new WebPubSubServiceClient(pubSubConfig.endpoint, credentials, pubSubConfig.hubName);
23145
23238
  this.syncHandler = new WeaveAzureWebPubsubSyncHandler(pubSubConfig.hubName, this, this.syncClient, initialState, {
23146
- persistIntervalMs: pubSubConfig.persistIntervalMs,
23239
+ ...pubSubConfig.persistIntervalMs && { persistIntervalMs: pubSubConfig.persistIntervalMs },
23147
23240
  ...pubSubConfig.connectionHandlers
23148
23241
  }, eventsHandlerConfig);
23149
23242
  }
@@ -23165,14 +23258,20 @@ var WeaveAzureWebPubsubServer = class extends Emittery {
23165
23258
  removeEventListener(event, callback) {
23166
23259
  this.off(event, callback);
23167
23260
  }
23168
- async clientConnect(roomId) {
23169
- return await this.syncHandler.clientConnect(roomId);
23261
+ async clientConnect(roomId, connectionOptions) {
23262
+ return await this.syncHandler.clientConnect(roomId, connectionOptions);
23170
23263
  }
23171
23264
  };
23172
23265
 
23173
23266
  //#endregion
23174
23267
  //#region src/constants.ts
23175
23268
  const WEAVE_STORE_AZURE_WEB_PUBSUB = "store-azure-web-pubsub";
23269
+ const WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS = {
23270
+ ["CONNECTING"]: "connecting",
23271
+ ["CONNECTED"]: "connected",
23272
+ ["DISCONNECTED"]: "disconnected",
23273
+ ["ERROR"]: "error"
23274
+ };
23176
23275
  const WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE = {
23177
23276
  ["PUB"]: "pub",
23178
23277
  ["SUB"]: "sub"
@@ -23180,4 +23279,4 @@ const WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE = {
23180
23279
  const WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG = { resyncIntervalMs: 15e3 };
23181
23280
 
23182
23281
  //#endregion
23183
- export { MqttDisconnectReasonCode, MqttV311ConnectReturnCode, MqttV500ConnectReasonCode, WEAVE_STORE_AZURE_WEB_PUBSUB, WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG, WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE, WeaveAzureWebPubsubServer, WeaveStoreAzureWebPubSubSyncHost, WebPubSubEventHandler };
23282
+ export { MessageDataType, MessageType, MqttDisconnectReasonCode, MqttV311ConnectReturnCode, MqttV500ConnectReasonCode, WEAVE_STORE_AZURE_WEB_PUBSUB, WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS, WEAVE_STORE_AZURE_WEB_PUBSUB_DEFAULT_CONFIG, WEAVE_STORE_HORIZONTAL_SYNC_HANDLER_CLIENT_TYPE, WeaveAzureWebPubsubServer, WeaveStoreAzureWebPubSubSyncHost, WebPubSubEventHandler };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inditextech/weave-store-azure-web-pubsub",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Jesus Manuel Piñeiro Cid <jesusmpc@inditex.com>",
@@ -57,8 +57,8 @@
57
57
  "dependencies": {
58
58
  "@azure/identity": "4.10.2",
59
59
  "@azure/web-pubsub": "1.2.0",
60
- "@inditextech/weave-types": "2.0.2",
61
- "@inditextech/weave-sdk": "2.0.2",
60
+ "@inditextech/weave-types": "2.1.0",
61
+ "@inditextech/weave-sdk": "2.1.0",
62
62
  "@syncedstore/core": "0.6.0",
63
63
  "buffer": "6.0.3",
64
64
  "reconnecting-websocket": "4.4.0",