@loro-dev/streams-crdt 0.12.2 → 0.12.3

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/flock.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as InMemoryRemoteCursorStore, c as EphemeralStreamCrdt, i as StreamsCrdt, l as PayloadProtectionError, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-D-UirMkk.js";
1
+ import { a as InMemoryRemoteCursorStore, c as EphemeralStreamCrdt, i as StreamsCrdt, l as PayloadProtectionError, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-BZhLwAOj.js";
2
2
  import { Flock } from "@loro-dev/flock-wasm";
3
3
  //#region src/flock.ts
4
4
  function isAfter(entry, current) {
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as InMemoryRemoteCursorStore, c as EphemeralStreamCrdt, i as StreamsCrdt, l as PayloadProtectionError, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-D-UirMkk.js";
1
+ import { a as InMemoryRemoteCursorStore, c as EphemeralStreamCrdt, i as StreamsCrdt, l as PayloadProtectionError, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-BZhLwAOj.js";
2
2
  export { PayloadProtectionError as E2eeError, PayloadProtectionError, EphemeralStreamCrdt, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, StreamsCrdt, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
package/dist/loro.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as InMemoryRemoteCursorStore, c as EphemeralStreamCrdt, i as StreamsCrdt, l as PayloadProtectionError, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-D-UirMkk.js";
1
+ import { a as InMemoryRemoteCursorStore, c as EphemeralStreamCrdt, i as StreamsCrdt, l as PayloadProtectionError, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-BZhLwAOj.js";
2
2
  import { LoroDoc, VersionVector, decodeImportBlobMeta } from "loro-crdt";
3
3
  //#region src/loro.ts
4
4
  function batchImportUpdates(doc, updates) {
@@ -1177,7 +1177,7 @@ var StreamsTransportClient = class {
1177
1177
  * the first event must be `bootstrap`, and all following events must be live
1178
1178
  * `data` updates.
1179
1179
  */
1180
- async readEphemeralSse(onBootstrap, onData, signal) {
1180
+ async readEphemeralSse(onBootstrap, onData, signal, onActivity) {
1181
1181
  const requestUrl = this.ephemeralReadEndpoint();
1182
1182
  const response = await this.fetchAuthorized(requestUrl, {
1183
1183
  method: "GET",
@@ -1198,7 +1198,7 @@ var StreamsTransportClient = class {
1198
1198
  const dataEncoding = response.headers.get("Stream-SSE-Data-Encoding") ?? void 0;
1199
1199
  const consume = async () => {
1200
1200
  let sawBootstrap = false;
1201
- for await (const event of readSseEvents(response.body)) {
1201
+ for await (const event of readSseEvents(response.body, { onActivity })) {
1202
1202
  if (!sawBootstrap) {
1203
1203
  if (event.event !== "bootstrap") throw new ProtocolError(`ephemeral sse must start with bootstrap, got '${event.event}'`);
1204
1204
  await onBootstrap(decodeSsePayload(event.data, dataEncoding));
@@ -1689,15 +1689,35 @@ var EphemeralStreamCrdt = class {
1689
1689
  state.requestController ??= new AbortController();
1690
1690
  const capturedController = state.requestController;
1691
1691
  let sseOpenedAtMs = 0;
1692
+ let inactivityTimer = null;
1693
+ let inactivityTriggered = false;
1694
+ const clearInactivity = () => {
1695
+ if (inactivityTimer != null) {
1696
+ clearTimeout(inactivityTimer);
1697
+ inactivityTimer = null;
1698
+ }
1699
+ };
1700
+ const resetInactivity = () => {
1701
+ clearInactivity();
1702
+ const timeoutMs = this.reconnectConfig.liveInactivityTimeoutMs;
1703
+ if (timeoutMs != null && timeoutMs > 0 && !state.closed) inactivityTimer = setTimeout(() => {
1704
+ inactivityTriggered = true;
1705
+ capturedController.abort();
1706
+ }, timeoutMs);
1707
+ };
1692
1708
  try {
1709
+ resetInactivity();
1693
1710
  const result = await this.client.readEphemeralSse(async (bootstrap) => {
1711
+ resetInactivity();
1694
1712
  if (bootstrap.byteLength > 0) await this.adaptor.applyRemoteUpdates([bootstrap]);
1695
1713
  sseOpenedAtMs = Date.now();
1696
1714
  this.setReadStatus(state, "ok");
1697
1715
  this.resolveFirstOpen(state);
1698
1716
  }, async (update) => {
1717
+ resetInactivity();
1699
1718
  if (update.byteLength > 0) await this.adaptor.applyRemoteUpdates([update]);
1700
- }, capturedController.signal);
1719
+ }, capturedController.signal, resetInactivity);
1720
+ clearInactivity();
1701
1721
  if (state.closed) return;
1702
1722
  if (result.kind === "ok") {
1703
1723
  state.retryAttempt = 0;
@@ -1708,10 +1728,25 @@ var EphemeralStreamCrdt = class {
1708
1728
  if (result.kind === "unsupported") throw new Error("ephemeral stream requires SSE support");
1709
1729
  if (result.kind === "not-found") throw new HttpError("ephemeral stream not found", 404);
1710
1730
  } catch (error) {
1731
+ clearInactivity();
1711
1732
  if (state.closed) return;
1712
1733
  if (capturedController.signal.aborted) {
1713
1734
  state.requestController = new AbortController();
1714
1735
  this.setReadStatus(state, "reconnecting");
1736
+ if (!inactivityTriggered) continue;
1737
+ if (sseOpenedAtMs > 0 && Date.now() - sseOpenedAtMs >= 5e3) state.retryAttempt = 0;
1738
+ if (state.retryAttempt >= this.reconnectConfig.maxAttempts) {
1739
+ this.logError("ephemeral live reconnect exhausted (inactivity)", error, {
1740
+ streamUrl: this.streamUrl,
1741
+ attempts: state.retryAttempt
1742
+ });
1743
+ this.setReadStatus(state, "disconnected");
1744
+ this.rejectFirstOpen(state, toError(error));
1745
+ return;
1746
+ }
1747
+ const delay = computeRetryDelay(state.retryAttempt, this.reconnectConfig);
1748
+ state.retryAttempt += 1;
1749
+ await sleep(delay, state.retrySleepController.signal);
1715
1750
  continue;
1716
1751
  }
1717
1752
  const classified = classifyFetchError(error);
@@ -3692,4 +3727,4 @@ function createStreamUrl(input) {
3692
3727
  //#endregion
3693
3728
  export { InMemoryRemoteCursorStore as a, EphemeralStreamCrdt as c, StreamsCrdt as i, PayloadProtectionError as l, isValidBucketId as n, IndexedDbRemoteCursorStore as o, isValidRillId as r, createInitialRemoteCursor as s, createStreamUrl as t };
3694
3729
 
3695
- //# sourceMappingURL=stream-id-D-UirMkk.js.map
3730
+ //# sourceMappingURL=stream-id-BZhLwAOj.js.map