@yorkie-js/sdk 0.7.9 → 0.7.10-rc

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.
@@ -106,9 +106,10 @@ export declare interface AttachChannelOptions {
106
106
  */
107
107
  syncMode?: SyncMode;
108
108
  /**
109
- * `channelHeartbeatInterval` overrides the heartbeat interval (ms) for this
110
- * attachment. If unset, mode-specific defaults apply: Polling=3000,
111
- * Realtime=30000.
109
+ * `channelHeartbeatInterval` overrides the heartbeat interval (ms) for
110
+ * this attachment. If unset, the client-level default
111
+ * (`ClientOptions.channelHeartbeatInterval`, default 5000 ms) applies
112
+ * to both Realtime and Polling modes.
112
113
  */
113
114
  channelHeartbeatInterval?: number;
114
115
  }
@@ -801,6 +802,12 @@ export declare class Channel implements Observable_2<ChannelEvent>, Attachable {
801
802
  * The callback will be called when an authentication error occurs.
802
803
  */
803
804
  subscribe(type: 'auth-error', next: ChannelEventCallbackMap['auth-error']): Unsubscribe;
805
+ /**
806
+ * `subscribe` registers a callback to subscribe to non-recoverable sync
807
+ * (RefreshChannel) errors. Subsequent successful events on the channel
808
+ * imply recovery — there is no separate "recovered" event.
809
+ */
810
+ subscribe(type: 'sync-error', next: ChannelEventCallbackMap['sync-error']): Unsubscribe;
804
811
  /**
805
812
  * `subscribe` registers a callback to subscribe to presence events on the channel.
806
813
  * The callback will be called when the presence count changes.
@@ -834,7 +841,7 @@ export declare class Channel implements Observable_2<ChannelEvent>, Attachable {
834
841
  /**
835
842
  * `ChannelEvent` represents an event that occurs in the channel.
836
843
  */
837
- export declare type ChannelEvent = PresenceEvent_3 | BroadcastEvent | LocalBroadcastEvent | AuthErrorEvent_3;
844
+ export declare type ChannelEvent = PresenceEvent_3 | BroadcastEvent | LocalBroadcastEvent | AuthErrorEvent_3 | SyncErrorEvent;
838
845
 
839
846
  /**
840
847
  * `ChannelEventCallbackMap` represents a map of event types to callbacks.
@@ -843,6 +850,7 @@ declare type ChannelEventCallbackMap = {
843
850
  broadcast: NextFn<BroadcastEvent>;
844
851
  'local-broadcast': NextFn<LocalBroadcastEvent>;
845
852
  'auth-error': NextFn<AuthErrorEvent_3>;
853
+ 'sync-error': NextFn<SyncErrorEvent>;
846
854
  presence: NextFn<PresenceEvent_3>;
847
855
  all: NextFn<ChannelEvent>;
848
856
  };
@@ -870,7 +878,15 @@ export declare enum ChannelEventType {
870
878
  /**
871
879
  * `AuthError` means that an authentication error has occurred.
872
880
  */
873
- AuthError = "auth-error"
881
+ AuthError = "auth-error",
882
+ /**
883
+ * `SyncError` means that a non-recoverable sync (RefreshChannel) error
884
+ * occurred. Subscribers can use this to render an error state in the UI
885
+ * without polling internal SDK state. The SDK still retries via its sync
886
+ * loop, so subsequent successful events (PresenceChanged/Initialized) can
887
+ * be treated as recovery.
888
+ */
889
+ SyncError = "sync-error"
874
890
  }
875
891
 
876
892
  /**
@@ -1010,8 +1026,9 @@ export declare class Client {
1010
1026
  */
1011
1027
  attach<R, P extends Indexable>(resource: Document_2<R, P>, opts?: AttachOptions<R, P>): Promise<Document_2<R, P>>;
1012
1028
  /**
1013
- * `attach` attaches the given channel to this client. It tells the server that
1014
- * this client will track the channel.
1029
+ * `attach` attaches the given channel to this client. The channel is
1030
+ * registered locally and the server is notified on the next RefreshChannel
1031
+ * heartbeat.
1015
1032
  */
1016
1033
  attach(resource: Channel, opts?: AttachChannelOptions): Promise<Channel>;
1017
1034
  /**
@@ -1027,8 +1044,9 @@ export declare class Client {
1027
1044
  keepalive?: boolean;
1028
1045
  }): Promise<Document_2<R, P>>;
1029
1046
  /**
1030
- * `detach` detaches the given channel from this client.
1031
- * It tells the server that this client will no longer track the channel.
1047
+ * `detach` detaches the given channel from this client. The detach is a
1048
+ * local cleanup; the server reclaims the session via TTL when heartbeats
1049
+ * stop.
1032
1050
  */
1033
1051
  detach(resource: Channel): Promise<Channel>;
1034
1052
  /**
@@ -1041,13 +1059,15 @@ export declare class Client {
1041
1059
  */
1042
1060
  private detachDocument;
1043
1061
  /**
1044
- * `attach` attaches the given channel to this client.
1045
- * It tells the server that this client will track the channel.
1062
+ * `attachChannel` attaches the given channel to this client. The channel is
1063
+ * registered locally and the server is notified on the next RefreshChannel
1064
+ * heartbeat.
1046
1065
  */
1047
1066
  attachChannel(channel: Channel, opts?: AttachChannelOptions): Promise<Channel>;
1048
1067
  /**
1049
- * `detachChannel` detaches the given channel from this client.
1050
- * It tells the server that this client will no longer track the channel.
1068
+ * `detachChannel` detaches the given channel from this client. The detach
1069
+ * is a local cleanup; the server reclaims the session via TTL when
1070
+ * heartbeats stop.
1051
1071
  */
1052
1072
  detachChannel(channel: Channel): Promise<Channel>;
1053
1073
  /**
@@ -1241,9 +1261,11 @@ export declare interface ClientOptions {
1241
1261
  */
1242
1262
  reconnectStreamDelay?: number;
1243
1263
  /**
1244
- * `channelHeartbeatInterval` is the interval of the channel heartbeat.
1245
- * The client sends a heartbeat to the server to refresh the channel TTL.
1246
- * The default value is `30000`(ms).
1264
+ * `channelHeartbeatInterval` is the interval of the channel heartbeat (ms).
1265
+ * The client sends a `RefreshChannel` heartbeat to refresh the channel
1266
+ * session TTL. The default value is `5000` (ms) — co-tuned to the server's
1267
+ * `ChannelSessionTTL` (15 s) at TTL/3. Values larger than the server TTL
1268
+ * risk premature session expiry.
1247
1269
  */
1248
1270
  channelHeartbeatInterval?: number;
1249
1271
  /**
@@ -6062,6 +6084,26 @@ declare interface SubscribeFn<T> {
6062
6084
  (observer: Observer<T>): Unsubscribe;
6063
6085
  }
6064
6086
 
6087
+ /**
6088
+ * `SyncErrorEvent` represents a non-recoverable sync (RefreshChannel) error.
6089
+ * It carries the underlying error object so subscribers can inspect codes
6090
+ * (e.g. via `isErrorCode`) without losing the original Error.
6091
+ */
6092
+ declare interface SyncErrorEvent {
6093
+ /**
6094
+ * `type` is the type of the event.
6095
+ */
6096
+ type: ChannelEventType.SyncError;
6097
+ /**
6098
+ * `error` is the underlying error thrown by the RPC call.
6099
+ */
6100
+ error: unknown;
6101
+ /**
6102
+ * `method` is the RPC method that failed (e.g. `RefreshChannel`).
6103
+ */
6104
+ method: string;
6105
+ }
6106
+
6065
6107
  /**
6066
6108
  * `SyncMode` defines synchronization modes for the PushPullChanges API
6067
6109
  * (documents) and the RefreshChannel heartbeat (channels).
@@ -5865,7 +5865,7 @@ var DocEventType$1 = /* @__PURE__ */ ((DocEventType2) => {
5865
5865
  DocEventType2[DocEventType2["DOCUMENT_BROADCAST"] = 3] = "DOCUMENT_BROADCAST";
5866
5866
  return DocEventType2;
5867
5867
  })(DocEventType$1 || {});
5868
- const file_yorkie_v1_yorkie = /* @__PURE__ */ fileDesc("ChZ5b3JraWUvdjEveW9ya2llLnByb3RvEgl5b3JraWUudjEingEKFUFjdGl2YXRlQ2xpZW50UmVxdWVzdBISCgpjbGllbnRfa2V5GAEgASgJEkAKCG1ldGFkYXRhGAIgAygLMi4ueW9ya2llLnYxLkFjdGl2YXRlQ2xpZW50UmVxdWVzdC5NZXRhZGF0YUVudHJ5Gi8KDU1ldGFkYXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASIrChZBY3RpdmF0ZUNsaWVudFJlc3BvbnNlEhEKCWNsaWVudF9pZBgBIAEoCSJBChdEZWFjdGl2YXRlQ2xpZW50UmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSEwoLc3luY2hyb25vdXMYAiABKAgiGgoYRGVhY3RpdmF0ZUNsaWVudFJlc3BvbnNlImoKFUF0dGFjaERvY3VtZW50UmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSKgoLY2hhbmdlX3BhY2sYAiABKAsyFS55b3JraWUudjEuQ2hhbmdlUGFjaxISCgpzY2hlbWFfa2V5GAMgASgJIp8BChZBdHRhY2hEb2N1bWVudFJlc3BvbnNlEhMKC2RvY3VtZW50X2lkGAEgASgJEioKC2NoYW5nZV9wYWNrGAIgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2sSHQoVbWF4X3NpemVfcGVyX2RvY3VtZW50GAMgASgFEiUKDHNjaGVtYV9ydWxlcxgEIAMoCzIPLnlvcmtpZS52MS5SdWxlIosBChVEZXRhY2hEb2N1bWVudFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJEioKC2NoYW5nZV9wYWNrGAMgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2sSHgoWcmVtb3ZlX2lmX25vdF9hdHRhY2hlZBgEIAEoCCJEChZEZXRhY2hEb2N1bWVudFJlc3BvbnNlEioKC2NoYW5nZV9wYWNrGAIgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2siUwoMV2F0Y2hSZXF1ZXN0EhEKCWNsaWVudF9pZBgBIAEoCRIwCglyZXNvdXJjZXMYAiADKAsyHS55b3JraWUudjEuUmVzb3VyY2VEZXNjcmlwdG9yIoQBChJSZXNvdXJjZURlc2NyaXB0b3ISMQoIZG9jdW1lbnQYASABKAsyHS55b3JraWUudjEuRG9jdW1lbnREZXNjcmlwdG9ySAASLwoHY2hhbm5lbBgCIAEoCzIcLnlvcmtpZS52MS5DaGFubmVsRGVzY3JpcHRvckgAQgoKCHJlc291cmNlIikKEkRvY3VtZW50RGVzY3JpcHRvchITCgtkb2N1bWVudF9pZBgBIAEoCSIoChFDaGFubmVsRGVzY3JpcHRvchITCgtjaGFubmVsX2tleRgBIAEoCSJ5Cg1XYXRjaFJlc3BvbnNlEjgKDmluaXRpYWxpemF0aW9uGAEgASgLMh4ueW9ya2llLnYxLldhdGNoSW5pdGlhbGl6YXRpb25IABImCgVldmVudBgCIAEoCzIVLnlvcmtpZS52MS5XYXRjaEV2ZW50SABCBgoEYm9keSJGChNXYXRjaEluaXRpYWxpemF0aW9uEi8KDnJlc291cmNlX2luaXRzGAEgAygLMhcueW9ya2llLnYxLlJlc291cmNlSW5pdCJ4CgxSZXNvdXJjZUluaXQSMAoNZG9jdW1lbnRfaW5pdBgBIAEoCzIXLnlvcmtpZS52MS5Eb2N1bWVudEluaXRIABIuCgxjaGFubmVsX2luaXQYAiABKAsyFi55b3JraWUudjEuQ2hhbm5lbEluaXRIAEIGCgRpbml0IjcKDERvY3VtZW50SW5pdBITCgtkb2N1bWVudF9pZBgBIAEoCRISCgpjbGllbnRfaWRzGAIgAygJIkYKC0NoYW5uZWxJbml0EhMKC2NoYW5uZWxfa2V5GAEgASgJEhUKDXNlc3Npb25fY291bnQYAiABKAMSCwoDc2VxGAMgASgDInsKCldhdGNoRXZlbnQSLQoJZG9jX2V2ZW50GAEgASgLMhgueW9ya2llLnYxLkRvY1dhdGNoRXZlbnRIABI1Cg1jaGFubmVsX2V2ZW50GAIgASgLMhwueW9ya2llLnYxLkNoYW5uZWxXYXRjaEV2ZW50SABCBwoFZXZlbnQiSAoNRG9jV2F0Y2hFdmVudBITCgtkb2N1bWVudF9pZBgBIAEoCRIiCgVldmVudBgCIAEoCzITLnlvcmtpZS52MS5Eb2NFdmVudCJQChFDaGFubmVsV2F0Y2hFdmVudBITCgtjaGFubmVsX2tleRgBIAEoCRImCgVldmVudBgCIAEoCzIXLnlvcmtpZS52MS5DaGFubmVsRXZlbnQiPgoUV2F0Y2hEb2N1bWVudFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJIrYBChVXYXRjaERvY3VtZW50UmVzcG9uc2USSQoOaW5pdGlhbGl6YXRpb24YASABKAsyLy55b3JraWUudjEuV2F0Y2hEb2N1bWVudFJlc3BvbnNlLkluaXRpYWxpemF0aW9uSAASJAoFZXZlbnQYAiABKAsyEy55b3JraWUudjEuRG9jRXZlbnRIABokCg5Jbml0aWFsaXphdGlvbhISCgpjbGllbnRfaWRzGAEgAygJQgYKBGJvZHkiPQoTV2F0Y2hDaGFubmVsUmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSEwoLY2hhbm5lbF9rZXkYAiABKAkigwEKFFdhdGNoQ2hhbm5lbFJlc3BvbnNlEjkKC2luaXRpYWxpemVkGAEgASgLMiIueW9ya2llLnYxLldhdGNoQ2hhbm5lbEluaXRpYWxpemVkSAASKAoFZXZlbnQYAiABKAsyFy55b3JraWUudjEuQ2hhbm5lbEV2ZW50SABCBgoEYm9keSI9ChdXYXRjaENoYW5uZWxJbml0aWFsaXplZBIVCg1zZXNzaW9uX2NvdW50GAEgASgDEgsKA3NlcRgCIAEoAyJrChVSZW1vdmVEb2N1bWVudFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJEioKC2NoYW5nZV9wYWNrGAMgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2siRAoWUmVtb3ZlRG9jdW1lbnRSZXNwb25zZRIqCgtjaGFuZ2VfcGFjaxgBIAEoCzIVLnlvcmtpZS52MS5DaGFuZ2VQYWNrIn8KFlB1c2hQdWxsQ2hhbmdlc1JlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJEioKC2NoYW5nZV9wYWNrGAMgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2sSEQoJcHVzaF9vbmx5GAQgASgIIkUKF1B1c2hQdWxsQ2hhbmdlc1Jlc3BvbnNlEioKC2NoYW5nZV9wYWNrGAEgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2siYwoVQ3JlYXRlUmV2aXNpb25SZXF1ZXN0EhEKCWNsaWVudF9pZBgBIAEoCRITCgtkb2N1bWVudF9pZBgCIAEoCRINCgVsYWJlbBgDIAEoCRITCgtkZXNjcmlwdGlvbhgEIAEoCSJGChZDcmVhdGVSZXZpc2lvblJlc3BvbnNlEiwKCHJldmlzaW9uGAEgASgLMhoueW9ya2llLnYxLlJldmlzaW9uU3VtbWFyeSJRChJHZXRSZXZpc2lvblJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJEhMKC3JldmlzaW9uX2lkGAMgASgJIkMKE0dldFJldmlzaW9uUmVzcG9uc2USLAoIcmV2aXNpb24YASABKAsyGi55b3JraWUudjEuUmV2aXNpb25TdW1tYXJ5InUKFExpc3RSZXZpc2lvbnNSZXF1ZXN0EhEKCWNsaWVudF9pZBgBIAEoCRITCgtkb2N1bWVudF9pZBgCIAEoCRIRCglwYWdlX3NpemUYAyABKAUSDgoGb2Zmc2V0GAQgASgFEhIKCmlzX2ZvcndhcmQYBSABKAgiRgoVTGlzdFJldmlzaW9uc1Jlc3BvbnNlEi0KCXJldmlzaW9ucxgBIAMoCzIaLnlvcmtpZS52MS5SZXZpc2lvblN1bW1hcnkiVQoWUmVzdG9yZVJldmlzaW9uUmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSEwoLZG9jdW1lbnRfaWQYAiABKAkSEwoLcmV2aXNpb25faWQYBCABKAkiGQoXUmVzdG9yZVJldmlzaW9uUmVzcG9uc2UiPgoUQXR0YWNoQ2hhbm5lbFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2NoYW5uZWxfa2V5GAIgASgJIkIKFUF0dGFjaENoYW5uZWxSZXNwb25zZRISCgpzZXNzaW9uX2lkGAEgASgJEhUKDXNlc3Npb25fY291bnQYAiABKAMiUgoURGV0YWNoQ2hhbm5lbFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2NoYW5uZWxfa2V5GAIgASgJEhIKCnNlc3Npb25faWQYAyABKAkiLgoVRGV0YWNoQ2hhbm5lbFJlc3BvbnNlEhUKDXNlc3Npb25fY291bnQYASABKAMiUwoVUmVmcmVzaENoYW5uZWxSZXF1ZXN0EhEKCWNsaWVudF9pZBgBIAEoCRITCgtjaGFubmVsX2tleRgCIAEoCRISCgpzZXNzaW9uX2lkGAMgASgJIi8KFlJlZnJlc2hDaGFubmVsUmVzcG9uc2USFQoNc2Vzc2lvbl9jb3VudBgBIAEoAyIpChJQZWVrQ2hhbm5lbFJlcXVlc3QSEwoLY2hhbm5lbF9rZXkYASABKAkiLAoTUGVla0NoYW5uZWxSZXNwb25zZRIVCg1zZXNzaW9uX2NvdW50GAEgASgDIloKEEJyb2FkY2FzdFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2NoYW5uZWxfa2V5GAIgASgJEg0KBXRvcGljGAMgASgJEg8KB3BheWxvYWQYBCABKAwiEwoRQnJvYWRjYXN0UmVzcG9uc2UylQwKDVlvcmtpZVNlcnZpY2USVwoOQWN0aXZhdGVDbGllbnQSIC55b3JraWUudjEuQWN0aXZhdGVDbGllbnRSZXF1ZXN0GiEueW9ya2llLnYxLkFjdGl2YXRlQ2xpZW50UmVzcG9uc2UiABJdChBEZWFjdGl2YXRlQ2xpZW50EiIueW9ya2llLnYxLkRlYWN0aXZhdGVDbGllbnRSZXF1ZXN0GiMueW9ya2llLnYxLkRlYWN0aXZhdGVDbGllbnRSZXNwb25zZSIAElcKDkF0dGFjaERvY3VtZW50EiAueW9ya2llLnYxLkF0dGFjaERvY3VtZW50UmVxdWVzdBohLnlvcmtpZS52MS5BdHRhY2hEb2N1bWVudFJlc3BvbnNlIgASVwoORGV0YWNoRG9jdW1lbnQSIC55b3JraWUudjEuRGV0YWNoRG9jdW1lbnRSZXF1ZXN0GiEueW9ya2llLnYxLkRldGFjaERvY3VtZW50UmVzcG9uc2UiABJXCg5SZW1vdmVEb2N1bWVudBIgLnlvcmtpZS52MS5SZW1vdmVEb2N1bWVudFJlcXVlc3QaIS55b3JraWUudjEuUmVtb3ZlRG9jdW1lbnRSZXNwb25zZSIAEloKD1B1c2hQdWxsQ2hhbmdlcxIhLnlvcmtpZS52MS5QdXNoUHVsbENoYW5nZXNSZXF1ZXN0GiIueW9ya2llLnYxLlB1c2hQdWxsQ2hhbmdlc1Jlc3BvbnNlIgASPgoFV2F0Y2gSFy55b3JraWUudjEuV2F0Y2hSZXF1ZXN0GhgueW9ya2llLnYxLldhdGNoUmVzcG9uc2UiADABElYKDVdhdGNoRG9jdW1lbnQSHy55b3JraWUudjEuV2F0Y2hEb2N1bWVudFJlcXVlc3QaIC55b3JraWUudjEuV2F0Y2hEb2N1bWVudFJlc3BvbnNlIgAwARJTCgxXYXRjaENoYW5uZWwSHi55b3JraWUudjEuV2F0Y2hDaGFubmVsUmVxdWVzdBofLnlvcmtpZS52MS5XYXRjaENoYW5uZWxSZXNwb25zZSIAMAESVwoOQ3JlYXRlUmV2aXNpb24SIC55b3JraWUudjEuQ3JlYXRlUmV2aXNpb25SZXF1ZXN0GiEueW9ya2llLnYxLkNyZWF0ZVJldmlzaW9uUmVzcG9uc2UiABJOCgtHZXRSZXZpc2lvbhIdLnlvcmtpZS52MS5HZXRSZXZpc2lvblJlcXVlc3QaHi55b3JraWUudjEuR2V0UmV2aXNpb25SZXNwb25zZSIAElQKDUxpc3RSZXZpc2lvbnMSHy55b3JraWUudjEuTGlzdFJldmlzaW9uc1JlcXVlc3QaIC55b3JraWUudjEuTGlzdFJldmlzaW9uc1Jlc3BvbnNlIgASWgoPUmVzdG9yZVJldmlzaW9uEiEueW9ya2llLnYxLlJlc3RvcmVSZXZpc2lvblJlcXVlc3QaIi55b3JraWUudjEuUmVzdG9yZVJldmlzaW9uUmVzcG9uc2UiABJUCg1BdHRhY2hDaGFubmVsEh8ueW9ya2llLnYxLkF0dGFjaENoYW5uZWxSZXF1ZXN0GiAueW9ya2llLnYxLkF0dGFjaENoYW5uZWxSZXNwb25zZSIAElQKDURldGFjaENoYW5uZWwSHy55b3JraWUudjEuRGV0YWNoQ2hhbm5lbFJlcXVlc3QaIC55b3JraWUudjEuRGV0YWNoQ2hhbm5lbFJlc3BvbnNlIgASVwoOUmVmcmVzaENoYW5uZWwSIC55b3JraWUudjEuUmVmcmVzaENoYW5uZWxSZXF1ZXN0GiEueW9ya2llLnYxLlJlZnJlc2hDaGFubmVsUmVzcG9uc2UiABJOCgtQZWVrQ2hhbm5lbBIdLnlvcmtpZS52MS5QZWVrQ2hhbm5lbFJlcXVlc3QaHi55b3JraWUudjEuUGVla0NoYW5uZWxSZXNwb25zZSIAEkgKCUJyb2FkY2FzdBIbLnlvcmtpZS52MS5Ccm9hZGNhc3RSZXF1ZXN0GhwueW9ya2llLnYxLkJyb2FkY2FzdFJlc3BvbnNlIgBCRQoRZGV2LnlvcmtpZS5hcGkudjFQAVouZ2l0aHViLmNvbS95b3JraWUtdGVhbS95b3JraWUvYXBpL3lvcmtpZS92MTt2MWIGcHJvdG8z", [file_yorkie_v1_resources]);
5868
+ const file_yorkie_v1_yorkie = /* @__PURE__ */ fileDesc("ChZ5b3JraWUvdjEveW9ya2llLnByb3RvEgl5b3JraWUudjEingEKFUFjdGl2YXRlQ2xpZW50UmVxdWVzdBISCgpjbGllbnRfa2V5GAEgASgJEkAKCG1ldGFkYXRhGAIgAygLMi4ueW9ya2llLnYxLkFjdGl2YXRlQ2xpZW50UmVxdWVzdC5NZXRhZGF0YUVudHJ5Gi8KDU1ldGFkYXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASIrChZBY3RpdmF0ZUNsaWVudFJlc3BvbnNlEhEKCWNsaWVudF9pZBgBIAEoCSJBChdEZWFjdGl2YXRlQ2xpZW50UmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSEwoLc3luY2hyb25vdXMYAiABKAgiGgoYRGVhY3RpdmF0ZUNsaWVudFJlc3BvbnNlImoKFUF0dGFjaERvY3VtZW50UmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSKgoLY2hhbmdlX3BhY2sYAiABKAsyFS55b3JraWUudjEuQ2hhbmdlUGFjaxISCgpzY2hlbWFfa2V5GAMgASgJIp8BChZBdHRhY2hEb2N1bWVudFJlc3BvbnNlEhMKC2RvY3VtZW50X2lkGAEgASgJEioKC2NoYW5nZV9wYWNrGAIgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2sSHQoVbWF4X3NpemVfcGVyX2RvY3VtZW50GAMgASgFEiUKDHNjaGVtYV9ydWxlcxgEIAMoCzIPLnlvcmtpZS52MS5SdWxlIosBChVEZXRhY2hEb2N1bWVudFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJEioKC2NoYW5nZV9wYWNrGAMgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2sSHgoWcmVtb3ZlX2lmX25vdF9hdHRhY2hlZBgEIAEoCCJEChZEZXRhY2hEb2N1bWVudFJlc3BvbnNlEioKC2NoYW5nZV9wYWNrGAIgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2siUwoMV2F0Y2hSZXF1ZXN0EhEKCWNsaWVudF9pZBgBIAEoCRIwCglyZXNvdXJjZXMYAiADKAsyHS55b3JraWUudjEuUmVzb3VyY2VEZXNjcmlwdG9yIoQBChJSZXNvdXJjZURlc2NyaXB0b3ISMQoIZG9jdW1lbnQYASABKAsyHS55b3JraWUudjEuRG9jdW1lbnREZXNjcmlwdG9ySAASLwoHY2hhbm5lbBgCIAEoCzIcLnlvcmtpZS52MS5DaGFubmVsRGVzY3JpcHRvckgAQgoKCHJlc291cmNlIikKEkRvY3VtZW50RGVzY3JpcHRvchITCgtkb2N1bWVudF9pZBgBIAEoCSIoChFDaGFubmVsRGVzY3JpcHRvchITCgtjaGFubmVsX2tleRgBIAEoCSJ5Cg1XYXRjaFJlc3BvbnNlEjgKDmluaXRpYWxpemF0aW9uGAEgASgLMh4ueW9ya2llLnYxLldhdGNoSW5pdGlhbGl6YXRpb25IABImCgVldmVudBgCIAEoCzIVLnlvcmtpZS52MS5XYXRjaEV2ZW50SABCBgoEYm9keSJGChNXYXRjaEluaXRpYWxpemF0aW9uEi8KDnJlc291cmNlX2luaXRzGAEgAygLMhcueW9ya2llLnYxLlJlc291cmNlSW5pdCJ4CgxSZXNvdXJjZUluaXQSMAoNZG9jdW1lbnRfaW5pdBgBIAEoCzIXLnlvcmtpZS52MS5Eb2N1bWVudEluaXRIABIuCgxjaGFubmVsX2luaXQYAiABKAsyFi55b3JraWUudjEuQ2hhbm5lbEluaXRIAEIGCgRpbml0IjcKDERvY3VtZW50SW5pdBITCgtkb2N1bWVudF9pZBgBIAEoCRISCgpjbGllbnRfaWRzGAIgAygJIkYKC0NoYW5uZWxJbml0EhMKC2NoYW5uZWxfa2V5GAEgASgJEhUKDXNlc3Npb25fY291bnQYAiABKAMSCwoDc2VxGAMgASgDInsKCldhdGNoRXZlbnQSLQoJZG9jX2V2ZW50GAEgASgLMhgueW9ya2llLnYxLkRvY1dhdGNoRXZlbnRIABI1Cg1jaGFubmVsX2V2ZW50GAIgASgLMhwueW9ya2llLnYxLkNoYW5uZWxXYXRjaEV2ZW50SABCBwoFZXZlbnQiSAoNRG9jV2F0Y2hFdmVudBITCgtkb2N1bWVudF9pZBgBIAEoCRIiCgVldmVudBgCIAEoCzITLnlvcmtpZS52MS5Eb2NFdmVudCJQChFDaGFubmVsV2F0Y2hFdmVudBITCgtjaGFubmVsX2tleRgBIAEoCRImCgVldmVudBgCIAEoCzIXLnlvcmtpZS52MS5DaGFubmVsRXZlbnQiPgoUV2F0Y2hEb2N1bWVudFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJIrYBChVXYXRjaERvY3VtZW50UmVzcG9uc2USSQoOaW5pdGlhbGl6YXRpb24YASABKAsyLy55b3JraWUudjEuV2F0Y2hEb2N1bWVudFJlc3BvbnNlLkluaXRpYWxpemF0aW9uSAASJAoFZXZlbnQYAiABKAsyEy55b3JraWUudjEuRG9jRXZlbnRIABokCg5Jbml0aWFsaXphdGlvbhISCgpjbGllbnRfaWRzGAEgAygJQgYKBGJvZHkiPQoTV2F0Y2hDaGFubmVsUmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSEwoLY2hhbm5lbF9rZXkYAiABKAkigwEKFFdhdGNoQ2hhbm5lbFJlc3BvbnNlEjkKC2luaXRpYWxpemVkGAEgASgLMiIueW9ya2llLnYxLldhdGNoQ2hhbm5lbEluaXRpYWxpemVkSAASKAoFZXZlbnQYAiABKAsyFy55b3JraWUudjEuQ2hhbm5lbEV2ZW50SABCBgoEYm9keSI9ChdXYXRjaENoYW5uZWxJbml0aWFsaXplZBIVCg1zZXNzaW9uX2NvdW50GAEgASgDEgsKA3NlcRgCIAEoAyJrChVSZW1vdmVEb2N1bWVudFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJEioKC2NoYW5nZV9wYWNrGAMgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2siRAoWUmVtb3ZlRG9jdW1lbnRSZXNwb25zZRIqCgtjaGFuZ2VfcGFjaxgBIAEoCzIVLnlvcmtpZS52MS5DaGFuZ2VQYWNrIn8KFlB1c2hQdWxsQ2hhbmdlc1JlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJEioKC2NoYW5nZV9wYWNrGAMgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2sSEQoJcHVzaF9vbmx5GAQgASgIIkUKF1B1c2hQdWxsQ2hhbmdlc1Jlc3BvbnNlEioKC2NoYW5nZV9wYWNrGAEgASgLMhUueW9ya2llLnYxLkNoYW5nZVBhY2siYwoVQ3JlYXRlUmV2aXNpb25SZXF1ZXN0EhEKCWNsaWVudF9pZBgBIAEoCRITCgtkb2N1bWVudF9pZBgCIAEoCRINCgVsYWJlbBgDIAEoCRITCgtkZXNjcmlwdGlvbhgEIAEoCSJGChZDcmVhdGVSZXZpc2lvblJlc3BvbnNlEiwKCHJldmlzaW9uGAEgASgLMhoueW9ya2llLnYxLlJldmlzaW9uU3VtbWFyeSJRChJHZXRSZXZpc2lvblJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2RvY3VtZW50X2lkGAIgASgJEhMKC3JldmlzaW9uX2lkGAMgASgJIkMKE0dldFJldmlzaW9uUmVzcG9uc2USLAoIcmV2aXNpb24YASABKAsyGi55b3JraWUudjEuUmV2aXNpb25TdW1tYXJ5InUKFExpc3RSZXZpc2lvbnNSZXF1ZXN0EhEKCWNsaWVudF9pZBgBIAEoCRITCgtkb2N1bWVudF9pZBgCIAEoCRIRCglwYWdlX3NpemUYAyABKAUSDgoGb2Zmc2V0GAQgASgFEhIKCmlzX2ZvcndhcmQYBSABKAgiRgoVTGlzdFJldmlzaW9uc1Jlc3BvbnNlEi0KCXJldmlzaW9ucxgBIAMoCzIaLnlvcmtpZS52MS5SZXZpc2lvblN1bW1hcnkiVQoWUmVzdG9yZVJldmlzaW9uUmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSEwoLZG9jdW1lbnRfaWQYAiABKAkSEwoLcmV2aXNpb25faWQYBCABKAkiGQoXUmVzdG9yZVJldmlzaW9uUmVzcG9uc2UiPgoUQXR0YWNoQ2hhbm5lbFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2NoYW5uZWxfa2V5GAIgASgJIkIKFUF0dGFjaENoYW5uZWxSZXNwb25zZRISCgpzZXNzaW9uX2lkGAEgASgJEhUKDXNlc3Npb25fY291bnQYAiABKAMiUgoURGV0YWNoQ2hhbm5lbFJlcXVlc3QSEQoJY2xpZW50X2lkGAEgASgJEhMKC2NoYW5uZWxfa2V5GAIgASgJEhIKCnNlc3Npb25faWQYAyABKAkiLgoVRGV0YWNoQ2hhbm5lbFJlc3BvbnNlEhUKDXNlc3Npb25fY291bnQYASABKAMi2gEKFVJlZnJlc2hDaGFubmVsUmVxdWVzdBIRCgljbGllbnRfaWQYASABKAkSEwoLY2hhbm5lbF9rZXkYAiABKAkSEgoKc2Vzc2lvbl9pZBgDIAEoCRISCgpjbGllbnRfa2V5GAQgASgJEkAKCG1ldGFkYXRhGAUgAygLMi4ueW9ya2llLnYxLlJlZnJlc2hDaGFubmVsUmVxdWVzdC5NZXRhZGF0YUVudHJ5Gi8KDU1ldGFkYXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJWChZSZWZyZXNoQ2hhbm5lbFJlc3BvbnNlEhUKDXNlc3Npb25fY291bnQYASABKAMSEQoJY2xpZW50X2lkGAIgASgJEhIKCnNlc3Npb25faWQYAyABKAkiKQoSUGVla0NoYW5uZWxSZXF1ZXN0EhMKC2NoYW5uZWxfa2V5GAEgASgJIiwKE1BlZWtDaGFubmVsUmVzcG9uc2USFQoNc2Vzc2lvbl9jb3VudBgBIAEoAyJaChBCcm9hZGNhc3RSZXF1ZXN0EhEKCWNsaWVudF9pZBgBIAEoCRITCgtjaGFubmVsX2tleRgCIAEoCRINCgV0b3BpYxgDIAEoCRIPCgdwYXlsb2FkGAQgASgMIhMKEUJyb2FkY2FzdFJlc3BvbnNlMpUMCg1Zb3JraWVTZXJ2aWNlElcKDkFjdGl2YXRlQ2xpZW50EiAueW9ya2llLnYxLkFjdGl2YXRlQ2xpZW50UmVxdWVzdBohLnlvcmtpZS52MS5BY3RpdmF0ZUNsaWVudFJlc3BvbnNlIgASXQoQRGVhY3RpdmF0ZUNsaWVudBIiLnlvcmtpZS52MS5EZWFjdGl2YXRlQ2xpZW50UmVxdWVzdBojLnlvcmtpZS52MS5EZWFjdGl2YXRlQ2xpZW50UmVzcG9uc2UiABJXCg5BdHRhY2hEb2N1bWVudBIgLnlvcmtpZS52MS5BdHRhY2hEb2N1bWVudFJlcXVlc3QaIS55b3JraWUudjEuQXR0YWNoRG9jdW1lbnRSZXNwb25zZSIAElcKDkRldGFjaERvY3VtZW50EiAueW9ya2llLnYxLkRldGFjaERvY3VtZW50UmVxdWVzdBohLnlvcmtpZS52MS5EZXRhY2hEb2N1bWVudFJlc3BvbnNlIgASVwoOUmVtb3ZlRG9jdW1lbnQSIC55b3JraWUudjEuUmVtb3ZlRG9jdW1lbnRSZXF1ZXN0GiEueW9ya2llLnYxLlJlbW92ZURvY3VtZW50UmVzcG9uc2UiABJaCg9QdXNoUHVsbENoYW5nZXMSIS55b3JraWUudjEuUHVzaFB1bGxDaGFuZ2VzUmVxdWVzdBoiLnlvcmtpZS52MS5QdXNoUHVsbENoYW5nZXNSZXNwb25zZSIAEj4KBVdhdGNoEhcueW9ya2llLnYxLldhdGNoUmVxdWVzdBoYLnlvcmtpZS52MS5XYXRjaFJlc3BvbnNlIgAwARJWCg1XYXRjaERvY3VtZW50Eh8ueW9ya2llLnYxLldhdGNoRG9jdW1lbnRSZXF1ZXN0GiAueW9ya2llLnYxLldhdGNoRG9jdW1lbnRSZXNwb25zZSIAMAESUwoMV2F0Y2hDaGFubmVsEh4ueW9ya2llLnYxLldhdGNoQ2hhbm5lbFJlcXVlc3QaHy55b3JraWUudjEuV2F0Y2hDaGFubmVsUmVzcG9uc2UiADABElcKDkNyZWF0ZVJldmlzaW9uEiAueW9ya2llLnYxLkNyZWF0ZVJldmlzaW9uUmVxdWVzdBohLnlvcmtpZS52MS5DcmVhdGVSZXZpc2lvblJlc3BvbnNlIgASTgoLR2V0UmV2aXNpb24SHS55b3JraWUudjEuR2V0UmV2aXNpb25SZXF1ZXN0Gh4ueW9ya2llLnYxLkdldFJldmlzaW9uUmVzcG9uc2UiABJUCg1MaXN0UmV2aXNpb25zEh8ueW9ya2llLnYxLkxpc3RSZXZpc2lvbnNSZXF1ZXN0GiAueW9ya2llLnYxLkxpc3RSZXZpc2lvbnNSZXNwb25zZSIAEloKD1Jlc3RvcmVSZXZpc2lvbhIhLnlvcmtpZS52MS5SZXN0b3JlUmV2aXNpb25SZXF1ZXN0GiIueW9ya2llLnYxLlJlc3RvcmVSZXZpc2lvblJlc3BvbnNlIgASVAoNQXR0YWNoQ2hhbm5lbBIfLnlvcmtpZS52MS5BdHRhY2hDaGFubmVsUmVxdWVzdBogLnlvcmtpZS52MS5BdHRhY2hDaGFubmVsUmVzcG9uc2UiABJUCg1EZXRhY2hDaGFubmVsEh8ueW9ya2llLnYxLkRldGFjaENoYW5uZWxSZXF1ZXN0GiAueW9ya2llLnYxLkRldGFjaENoYW5uZWxSZXNwb25zZSIAElcKDlJlZnJlc2hDaGFubmVsEiAueW9ya2llLnYxLlJlZnJlc2hDaGFubmVsUmVxdWVzdBohLnlvcmtpZS52MS5SZWZyZXNoQ2hhbm5lbFJlc3BvbnNlIgASTgoLUGVla0NoYW5uZWwSHS55b3JraWUudjEuUGVla0NoYW5uZWxSZXF1ZXN0Gh4ueW9ya2llLnYxLlBlZWtDaGFubmVsUmVzcG9uc2UiABJICglCcm9hZGNhc3QSGy55b3JraWUudjEuQnJvYWRjYXN0UmVxdWVzdBocLnlvcmtpZS52MS5Ccm9hZGNhc3RSZXNwb25zZSIAQkUKEWRldi55b3JraWUuYXBpLnYxUAFaLmdpdGh1Yi5jb20veW9ya2llLXRlYW0veW9ya2llL2FwaS95b3JraWUvdjE7djFiBnByb3RvMw", [file_yorkie_v1_resources]);
5869
5869
  const YorkieService = /* @__PURE__ */ serviceDesc(file_yorkie_v1_yorkie, 0);
5870
5870
  const file_google_rpc_error_details = /* @__PURE__ */ fileDesc("Ch5nb29nbGUvcnBjL2Vycm9yX2RldGFpbHMucHJvdG8SCmdvb2dsZS5ycGMikwEKCUVycm9ySW5mbxIOCgZyZWFzb24YASABKAkSDgoGZG9tYWluGAIgASgJEjUKCG1ldGFkYXRhGAMgAygLMiMuZ29vZ2xlLnJwYy5FcnJvckluZm8uTWV0YWRhdGFFbnRyeRovCg1NZXRhZGF0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiOwoJUmV0cnlJbmZvEi4KC3JldHJ5X2RlbGF5GAEgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uIjIKCURlYnVnSW5mbxIVCg1zdGFja19lbnRyaWVzGAEgAygJEg4KBmRldGFpbBgCIAEoCSKPAwoMUXVvdGFGYWlsdXJlEjYKCnZpb2xhdGlvbnMYASADKAsyIi5nb29nbGUucnBjLlF1b3RhRmFpbHVyZS5WaW9sYXRpb24axgIKCVZpb2xhdGlvbhIPCgdzdWJqZWN0GAEgASgJEhMKC2Rlc2NyaXB0aW9uGAIgASgJEhMKC2FwaV9zZXJ2aWNlGAMgASgJEhQKDHF1b3RhX21ldHJpYxgEIAEoCRIQCghxdW90YV9pZBgFIAEoCRJRChBxdW90YV9kaW1lbnNpb25zGAYgAygLMjcuZ29vZ2xlLnJwYy5RdW90YUZhaWx1cmUuVmlvbGF0aW9uLlF1b3RhRGltZW5zaW9uc0VudHJ5EhMKC3F1b3RhX3ZhbHVlGAcgASgDEh8KEmZ1dHVyZV9xdW90YV92YWx1ZRgIIAEoA0gAiAEBGjYKFFF1b3RhRGltZW5zaW9uc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAFCFQoTX2Z1dHVyZV9xdW90YV92YWx1ZSKVAQoTUHJlY29uZGl0aW9uRmFpbHVyZRI9Cgp2aW9sYXRpb25zGAEgAygLMikuZ29vZ2xlLnJwYy5QcmVjb25kaXRpb25GYWlsdXJlLlZpb2xhdGlvbho/CglWaW9sYXRpb24SDAoEdHlwZRgBIAEoCRIPCgdzdWJqZWN0GAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJIswBCgpCYWRSZXF1ZXN0Ej8KEGZpZWxkX3Zpb2xhdGlvbnMYASADKAsyJS5nb29nbGUucnBjLkJhZFJlcXVlc3QuRmllbGRWaW9sYXRpb24afQoORmllbGRWaW9sYXRpb24SDQoFZmllbGQYASABKAkSEwoLZGVzY3JpcHRpb24YAiABKAkSDgoGcmVhc29uGAMgASgJEjcKEWxvY2FsaXplZF9tZXNzYWdlGAQgASgLMhwuZ29vZ2xlLnJwYy5Mb2NhbGl6ZWRNZXNzYWdlIjcKC1JlcXVlc3RJbmZvEhIKCnJlcXVlc3RfaWQYASABKAkSFAoMc2VydmluZ19kYXRhGAIgASgJImAKDFJlc291cmNlSW5mbxIVCg1yZXNvdXJjZV90eXBlGAEgASgJEhUKDXJlc291cmNlX25hbWUYAiABKAkSDQoFb3duZXIYAyABKAkSEwoLZGVzY3JpcHRpb24YBCABKAkiVgoESGVscBIkCgVsaW5rcxgBIAMoCzIVLmdvb2dsZS5ycGMuSGVscC5MaW5rGigKBExpbmsSEwoLZGVzY3JpcHRpb24YASABKAkSCwoDdXJsGAIgASgJIjMKEExvY2FsaXplZE1lc3NhZ2USDgoGbG9jYWxlGAEgASgJEg8KB21lc3NhZ2UYAiABKAlCbAoOY29tLmdvb2dsZS5ycGNCEUVycm9yRGV0YWlsc1Byb3RvUAFaP2dvb2dsZS5nb2xhbmcub3JnL2dlbnByb3RvL2dvb2dsZWFwaXMvcnBjL2VycmRldGFpbHM7ZXJyZGV0YWlsc6ICA1JQQ2IGcHJvdG8z", [file_google_protobuf_duration]);
5871
5871
  const ErrorInfoSchema = /* @__PURE__ */ messageDesc(file_google_rpc_error_details, 0);
@@ -5878,6 +5878,7 @@ var Code = /* @__PURE__ */ ((Code2) => {
5878
5878
  Code2["ErrDummy"] = "ErrDummy";
5879
5879
  Code2["ErrNotAttached"] = "ErrNotAttached";
5880
5880
  Code2["ErrNotDetached"] = "ErrNotDetached";
5881
+ Code2["ErrSessionNotFound"] = "ErrSessionNotFound";
5881
5882
  Code2["ErrDocumentRemoved"] = "ErrDocumentRemoved";
5882
5883
  Code2["ErrDocumentSizeExceedsLimit"] = "ErrDocumentSizeExceedsLimit";
5883
5884
  Code2["ErrDocumentSchemaValidationFailed"] = "ErrDocumentSchemaValidationFailed";
@@ -20781,12 +20782,25 @@ class Document {
20781
20782
  }
20782
20783
  class Attachment {
20783
20784
  resource;
20785
+ /**
20786
+ * For Documents: the document's resourceID, available at attach time.
20787
+ * For Channels: the server-issued session_id. Starts empty and is
20788
+ * populated after the first `RefreshChannel` first-call response.
20789
+ */
20784
20790
  resourceID;
20785
20791
  syncMode;
20786
20792
  changeEventReceived;
20787
20793
  lastHeartbeatTime;
20788
20794
  pollInterval;
20789
20795
  pollIntervalPinned;
20796
+ /**
20797
+ * `unsubscribeLocalBroadcast` is set by `attachChannel` when it forwards
20798
+ * a Channel's `local-broadcast` events to the RPC client, and consumed
20799
+ * by `detachInternal` so the subscription does not survive a detach.
20800
+ * Without this, re-attaching a channel accumulates duplicate handlers
20801
+ * on each attach cycle.
20802
+ */
20803
+ unsubscribeLocalBroadcast;
20790
20804
  reconnectStreamDelay;
20791
20805
  cancelled;
20792
20806
  watchStream;
@@ -20794,13 +20808,13 @@ class Attachment {
20794
20808
  watchAbortController;
20795
20809
  syncPromise;
20796
20810
  _detaching = false;
20797
- constructor(reconnectStreamDelay, resource, resourceID, syncMode, pollInterval = 0, pollIntervalPinned = false) {
20811
+ constructor(reconnectStreamDelay, resource, resourceID = "", syncMode, pollInterval = 0, pollIntervalPinned = false) {
20798
20812
  this.reconnectStreamDelay = reconnectStreamDelay;
20799
20813
  this.resource = resource;
20800
20814
  this.resourceID = resourceID;
20801
20815
  this.syncMode = syncMode;
20802
20816
  this.changeEventReceived = syncMode !== void 0 ? false : void 0;
20803
- this.lastHeartbeatTime = Date.now();
20817
+ this.lastHeartbeatTime = 0;
20804
20818
  this.pollInterval = pollInterval;
20805
20819
  this.pollIntervalPinned = pollIntervalPinned;
20806
20820
  this.cancelled = false;
@@ -20962,7 +20976,7 @@ function createAuthInterceptor(apiKey, token) {
20962
20976
  };
20963
20977
  }
20964
20978
  const name = "@yorkie-js/sdk";
20965
- const version = "0.7.9";
20979
+ const version = "0.7.10-rc";
20966
20980
  const pkg = {
20967
20981
  name,
20968
20982
  version
@@ -21000,6 +21014,7 @@ var ChannelEventType = /* @__PURE__ */ ((ChannelEventType2) => {
21000
21014
  ChannelEventType2["Broadcast"] = "broadcast";
21001
21015
  ChannelEventType2["LocalBroadcast"] = "local-broadcast";
21002
21016
  ChannelEventType2["AuthError"] = "auth-error";
21017
+ ChannelEventType2["SyncError"] = "sync-error";
21003
21018
  return ChannelEventType2;
21004
21019
  })(ChannelEventType || {});
21005
21020
  const KeyPathSeparator = ".";
@@ -21139,6 +21154,13 @@ class Channel2 {
21139
21154
  }
21140
21155
  });
21141
21156
  }
21157
+ if (typeOrTopic === "sync-error") {
21158
+ return this.eventStream.subscribe((event) => {
21159
+ if (event.type === "sync-error") {
21160
+ callback(event);
21161
+ }
21162
+ });
21163
+ }
21142
21164
  if (typeOrTopic === "presence") {
21143
21165
  return this.eventStream.subscribe((event) => {
21144
21166
  if (event.type === "presence-changed" || event.type === "initialized") {
@@ -21258,13 +21280,14 @@ var ClientCondition = /* @__PURE__ */ ((ClientCondition2) => {
21258
21280
  ClientCondition2["WatchLoop"] = "WatchLoop";
21259
21281
  return ClientCondition2;
21260
21282
  })(ClientCondition || {});
21261
- const DefaultPollingIntervalMs = 3e3;
21283
+ const DefaultDocumentPollIntervalMs = 3e3;
21284
+ const DefaultChannelHeartbeatMs = 5e3;
21262
21285
  const DefaultClientOptions = {
21263
21286
  rpcAddr: "https://api.yorkie.dev",
21264
21287
  syncLoopDuration: 50,
21265
21288
  retrySyncLoopDelay: 1e3,
21266
21289
  reconnectStreamDelay: 1e3,
21267
- channelHeartbeatInterval: 3e4
21290
+ channelHeartbeatInterval: DefaultChannelHeartbeatMs
21268
21291
  };
21269
21292
  const DefaultBroadcastOptions = {
21270
21293
  maxRetries: Infinity,
@@ -21461,7 +21484,7 @@ class Client {
21461
21484
  );
21462
21485
  }
21463
21486
  const pollIntervalPinned = opts.documentPollInterval !== void 0;
21464
- const pollInterval = pollIntervalPinned ? opts.documentPollInterval : syncMode === "polling" ? DefaultPollingIntervalMs : 0;
21487
+ const pollInterval = pollIntervalPinned ? opts.documentPollInterval : syncMode === "polling" ? DefaultDocumentPollIntervalMs : 0;
21465
21488
  return this.enqueueTask(async () => {
21466
21489
  try {
21467
21490
  const res = await this.rpcClient.attachDocument(
@@ -21590,127 +21613,88 @@ class Client {
21590
21613
  return this.enqueueTask(task);
21591
21614
  }
21592
21615
  /**
21593
- * `attach` attaches the given channel to this client.
21594
- * It tells the server that this client will track the channel.
21616
+ * `attachChannel` attaches the given channel to this client. The channel is
21617
+ * registered locally and the server is notified on the next RefreshChannel
21618
+ * heartbeat.
21595
21619
  */
21596
21620
  async attachChannel(channel, opts = {}) {
21597
- if (!this.isActive()) {
21598
- throw new YorkieError(
21599
- Code.ErrClientNotActivated,
21600
- `${this.key} is not active`
21601
- );
21602
- }
21603
21621
  if (channel.getStatus() !== ChannelStatus.Detached) {
21604
21622
  throw new YorkieError(
21605
21623
  Code.ErrNotDetached,
21606
21624
  `${channel.getKey()} is not detached`
21607
21625
  );
21608
21626
  }
21609
- channel.setActor(this.id);
21627
+ const syncMode = opts.syncMode ?? "realtime";
21628
+ this.assertValidChannelSyncMode(syncMode);
21629
+ if (opts.channelHeartbeatInterval !== void 0 && opts.channelHeartbeatInterval <= 0) {
21630
+ throw new YorkieError(
21631
+ Code.ErrInvalidArgument,
21632
+ "channelHeartbeatInterval must be greater than 0"
21633
+ );
21634
+ }
21635
+ const pollIntervalPinned = opts.channelHeartbeatInterval !== void 0;
21636
+ const pollInterval = opts.channelHeartbeatInterval ?? this.channelHeartbeatInterval;
21610
21637
  const task = async () => {
21611
- try {
21612
- const res = await this.rpcClient.attachChannel(
21613
- {
21614
- clientId: this.id,
21615
- channelKey: channel.getKey()
21616
- },
21617
- {
21618
- headers: {
21619
- "x-shard-key": `${this.apiKey}/${channel.getFirstKeyPath()}`
21620
- }
21621
- }
21622
- );
21623
- channel.setSessionID(res.sessionId);
21624
- channel.updateSessionCount(Number(res.sessionCount), 0);
21625
- channel.applyStatus(ChannelStatus.Attached);
21626
- const syncMode = opts.syncMode ?? "realtime";
21627
- this.assertValidChannelSyncMode(syncMode);
21628
- if (opts.channelHeartbeatInterval !== void 0 && opts.channelHeartbeatInterval <= 0) {
21629
- throw new YorkieError(
21630
- Code.ErrInvalidArgument,
21631
- "channelHeartbeatInterval must be greater than 0"
21632
- );
21633
- }
21634
- const pollIntervalPinned = opts.channelHeartbeatInterval !== void 0;
21635
- const pollInterval = pollIntervalPinned ? opts.channelHeartbeatInterval : syncMode === "polling" ? DefaultPollingIntervalMs : this.channelHeartbeatInterval;
21636
- const attachment = new Attachment(
21637
- this.reconnectStreamDelay,
21638
- channel,
21639
- res.sessionId,
21640
- syncMode,
21641
- pollInterval,
21642
- pollIntervalPinned
21643
- );
21644
- channel.subscribe("local-broadcast", (event) => {
21638
+ if (this.id) {
21639
+ channel.setActor(this.id);
21640
+ }
21641
+ const attachment = new Attachment(
21642
+ this.reconnectStreamDelay,
21643
+ channel,
21644
+ "",
21645
+ // sessionID populated on first refresh response
21646
+ syncMode,
21647
+ pollInterval,
21648
+ pollIntervalPinned
21649
+ );
21650
+ attachment.unsubscribeLocalBroadcast = channel.subscribe(
21651
+ "local-broadcast",
21652
+ (event) => {
21645
21653
  const { topic, payload, options } = event;
21646
21654
  this.broadcast(channel.getKey(), topic, payload, options).catch(
21647
21655
  (error) => {
21648
- if (options?.error) {
21649
- options.error(error);
21650
- }
21656
+ if (options?.error) options.error(error);
21651
21657
  logger.error(`[BC] c:"${this.getKey()}" failed: ${error}`);
21652
21658
  }
21653
21659
  );
21654
- });
21655
- this.attachmentMap.set(channel.getKey(), attachment);
21656
- if (syncMode === "realtime") {
21657
- await this.runWatchLoop(channel.getKey());
21658
21660
  }
21659
- logger.info(
21660
- `[AP] c:"${this.getKey()}" attaches p:"${channel.getKey()}" mode:${syncMode} count:${channel.getSessionCount()}`
21661
- );
21662
- return channel;
21663
- } catch (err) {
21664
- logger.error(`[AP] c:"${this.getKey()}" err :`, err);
21665
- await this.handleConnectError(err);
21666
- throw err;
21661
+ );
21662
+ this.attachmentMap.set(channel.getKey(), attachment);
21663
+ if (!this.conditions[
21664
+ "SyncLoop"
21665
+ /* SyncLoop */
21666
+ ]) {
21667
+ this.runSyncLoop();
21667
21668
  }
21669
+ logger.info(
21670
+ `[AP] c:"${this.getKey()}" attaches p:"${channel.getKey()}" mode:${syncMode}`
21671
+ );
21672
+ return channel;
21668
21673
  };
21669
21674
  return this.enqueueTask(task);
21670
21675
  }
21671
21676
  /**
21672
- * `detachChannel` detaches the given channel from this client.
21673
- * It tells the server that this client will no longer track the channel.
21677
+ * `detachChannel` detaches the given channel from this client. The detach
21678
+ * is a local cleanup; the server reclaims the session via TTL when
21679
+ * heartbeats stop.
21674
21680
  */
21675
21681
  async detachChannel(channel) {
21676
- if (!this.isActive()) {
21677
- throw new YorkieError(
21678
- Code.ErrClientNotActivated,
21679
- `${this.key} is not active`
21680
- );
21681
- }
21682
- if (!this.attachmentMap.has(channel.getKey())) {
21682
+ const attachment = this.attachmentMap.get(channel.getKey());
21683
+ if (!attachment) {
21683
21684
  throw new YorkieError(
21684
21685
  Code.ErrNotAttached,
21685
21686
  `${channel.getKey()} is not attached`
21686
21687
  );
21687
21688
  }
21689
+ attachment.markDetaching();
21690
+ await attachment.waitForSyncComplete();
21688
21691
  const task = async () => {
21689
- try {
21690
- const res = await this.rpcClient.detachChannel(
21691
- {
21692
- clientId: this.id,
21693
- channelKey: channel.getKey(),
21694
- sessionId: channel.getSessionID()
21695
- },
21696
- {
21697
- headers: {
21698
- "x-shard-key": `${this.apiKey}/${channel.getFirstKeyPath()}`
21699
- }
21700
- }
21701
- );
21702
- channel.updateSessionCount(Number(res.sessionCount), 0);
21703
- channel.applyStatus(ChannelStatus.Detached);
21704
- this.detachInternal(channel.getKey());
21705
- logger.info(
21706
- `[DP] c:"${this.getKey()}" detaches p:"${channel.getKey()}" count:${channel.getSessionCount()}`
21707
- );
21708
- return channel;
21709
- } catch (err) {
21710
- logger.error(`[DP] c:"${this.getKey()}" err :`, err);
21711
- await this.handleConnectError(err);
21712
- throw err;
21713
- }
21692
+ channel.applyStatus(ChannelStatus.Detached);
21693
+ this.detachInternal(channel.getKey());
21694
+ logger.info(
21695
+ `[DP] c:"${this.getKey()}" detaches p:"${channel.getKey()}" (local)`
21696
+ );
21697
+ return channel;
21714
21698
  };
21715
21699
  return this.enqueueTask(task);
21716
21700
  }
@@ -21751,7 +21735,7 @@ class Client {
21751
21735
  attachment.changeEventReceived = true;
21752
21736
  }
21753
21737
  if (!attachment.pollIntervalPinned) {
21754
- attachment.pollInterval = syncMode === "polling" ? DefaultPollingIntervalMs : 0;
21738
+ attachment.pollInterval = syncMode === "polling" ? DefaultDocumentPollIntervalMs : 0;
21755
21739
  }
21756
21740
  if ((prevSyncMode === "manual" || prevSyncMode === "polling") && syncMode !== "manual" && syncMode !== "polling") {
21757
21741
  attachment.resetCancelled();
@@ -21772,12 +21756,6 @@ class Client {
21772
21756
  }
21773
21757
  }
21774
21758
  async changeChannelSyncMode(channel, syncMode) {
21775
- if (!this.isActive()) {
21776
- throw new YorkieError(
21777
- Code.ErrClientNotActivated,
21778
- `${this.key} is not active`
21779
- );
21780
- }
21781
21759
  const attachment = this.attachmentMap.get(channel.getKey());
21782
21760
  if (!attachment) {
21783
21761
  throw new YorkieError(
@@ -21795,7 +21773,7 @@ class Client {
21795
21773
  }
21796
21774
  attachment.changeSyncMode(syncMode);
21797
21775
  if (!attachment.pollIntervalPinned) {
21798
- attachment.pollInterval = syncMode === "polling" ? DefaultPollingIntervalMs : syncMode === "realtime" ? this.channelHeartbeatInterval : 0;
21776
+ attachment.pollInterval = syncMode === "manual" ? 0 : this.channelHeartbeatInterval;
21799
21777
  }
21800
21778
  if (syncMode === "realtime") {
21801
21779
  attachment.resetCancelled();
@@ -21807,7 +21785,7 @@ class Client {
21807
21785
  * `sync` implementation that handles both Document and Channel.
21808
21786
  */
21809
21787
  sync(resource) {
21810
- if (!this.isActive()) {
21788
+ if (!(resource instanceof Channel2) && !this.isActive()) {
21811
21789
  throw new YorkieError(
21812
21790
  Code.ErrClientNotActivated,
21813
21791
  `${this.key} is not active`
@@ -22134,12 +22112,6 @@ class Client {
22134
22112
  * subscribe to channel events. Polling is the caller's responsibility.
22135
22113
  */
22136
22114
  async peekChannel(channelKey) {
22137
- if (!this.isActive()) {
22138
- throw new YorkieError(
22139
- Code.ErrClientNotActivated,
22140
- `${this.key} is not active`
22141
- );
22142
- }
22143
22115
  return this.enqueueTask(async () => {
22144
22116
  const firstKeyPath = channelKey.split(".")[0];
22145
22117
  const res = await this.rpcClient.peekChannel(
@@ -22157,12 +22129,6 @@ class Client {
22157
22129
  * `broadcast` broadcasts the given payload to the given topic.
22158
22130
  */
22159
22131
  async broadcast(key, topic, payload, options) {
22160
- if (!this.isActive()) {
22161
- throw new YorkieError(
22162
- Code.ErrClientNotActivated,
22163
- `${this.key} is not active`
22164
- );
22165
- }
22166
22132
  const attachment = this.attachmentMap.get(key);
22167
22133
  if (!attachment) {
22168
22134
  throw new YorkieError(Code.ErrNotAttached, `${key} is not attached`);
@@ -22239,8 +22205,16 @@ class Client {
22239
22205
  */
22240
22206
  runSyncLoop() {
22241
22207
  const doLoop = async () => {
22242
- if (!this.isActive() || this.deactivating) {
22243
- logger.debug(`[SL] c:"${this.getKey()}" exit sync loop`);
22208
+ if (this.deactivating) {
22209
+ logger.debug(`[SL] c:"${this.getKey()}" exit sync loop (deactivating)`);
22210
+ this.conditions[
22211
+ "SyncLoop"
22212
+ /* SyncLoop */
22213
+ ] = false;
22214
+ return;
22215
+ }
22216
+ if (!this.isActive() && this.attachmentMap.size === 0) {
22217
+ logger.debug(`[SL] c:"${this.getKey()}" exit sync loop (idle)`);
22244
22218
  this.conditions[
22245
22219
  "SyncLoop"
22246
22220
  /* SyncLoop */
@@ -22626,6 +22600,10 @@ class Client {
22626
22600
  return;
22627
22601
  }
22628
22602
  attachment.cancelWatchStream();
22603
+ if (attachment.unsubscribeLocalBroadcast) {
22604
+ attachment.unsubscribeLocalBroadcast();
22605
+ attachment.unsubscribeLocalBroadcast = void 0;
22606
+ }
22629
22607
  if (attachment.resource instanceof Document) {
22630
22608
  attachment.resource.resetOnlineClients();
22631
22609
  }
@@ -22634,12 +22612,17 @@ class Client {
22634
22612
  async syncInternal(attachment, syncMode) {
22635
22613
  const { resource } = attachment;
22636
22614
  if (resource instanceof Channel2) {
22615
+ const isFirstCall = !resource.getSessionID();
22637
22616
  try {
22638
22617
  const res = await this.rpcClient.refreshChannel(
22639
22618
  {
22640
- clientId: this.id,
22619
+ clientId: this.id ?? "",
22641
22620
  channelKey: resource.getKey(),
22642
- sessionId: resource.getSessionID()
22621
+ sessionId: resource.getSessionID() ?? "",
22622
+ // First-call only — these fields are ignored by the server
22623
+ // once a session_id is established.
22624
+ clientKey: isFirstCall ? this.key : "",
22625
+ metadata: isFirstCall ? this.metadata : {}
22643
22626
  },
22644
22627
  {
22645
22628
  headers: {
@@ -22647,6 +22630,31 @@ class Client {
22647
22630
  }
22648
22631
  }
22649
22632
  );
22633
+ if (isFirstCall) {
22634
+ if (this.deactivating || attachment.isDetaching()) {
22635
+ return resource;
22636
+ }
22637
+ if (res.clientId && !this.id) {
22638
+ this.id = res.clientId;
22639
+ this.status = "activated";
22640
+ resource.setActor(res.clientId);
22641
+ } else if (this.id) {
22642
+ resource.setActor(this.id);
22643
+ }
22644
+ if (res.sessionId) {
22645
+ resource.setSessionID(res.sessionId);
22646
+ attachment.resourceID = res.sessionId;
22647
+ resource.applyStatus(ChannelStatus.Attached);
22648
+ }
22649
+ if (attachment.syncMode === "realtime") {
22650
+ this.runWatchLoop(resource.getKey()).catch((err) => {
22651
+ logger.error(
22652
+ `[WP] c:"${this.getKey()}" failed to start watch for p:"${resource.getKey()}":`,
22653
+ err
22654
+ );
22655
+ });
22656
+ }
22657
+ }
22650
22658
  const prevCount = resource.getSessionCount();
22651
22659
  if (resource.updateSessionCount(Number(res.sessionCount), 0)) {
22652
22660
  if (resource.getSessionCount() !== prevCount) {
@@ -22661,6 +22669,21 @@ class Client {
22661
22669
  `[RP] c:"${this.getKey()}" refreshes p:"${resource.getKey()}" mode:${attachment.syncMode}`
22662
22670
  );
22663
22671
  } catch (err) {
22672
+ if (isErrorCode(err, Code.ErrSessionNotFound)) {
22673
+ logger.info(
22674
+ `[RP] c:"${this.getKey()}" session expired for p:"${resource.getKey()}", re-attaching`
22675
+ );
22676
+ resource.setSessionID("");
22677
+ attachment.resourceID = "";
22678
+ return resource;
22679
+ }
22680
+ if (!this.deactivating && !attachment.isDetaching()) {
22681
+ resource.publish({
22682
+ type: ChannelEventType.SyncError,
22683
+ error: err,
22684
+ method: "RefreshChannel"
22685
+ });
22686
+ }
22664
22687
  logger.error(`[RP] c:"${this.getKey()}" err :`, err);
22665
22688
  throw err;
22666
22689
  }