@q9labsai/chalk-client 5.1.0 → 5.2.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/dist/chat-files/types.d.ts +3 -0
  3. package/dist/{chunk-RJRSLXVT.js → chunk-BCO3AZUB.js} +647 -221
  4. package/dist/{chunk-K7PNW3KI.js → chunk-D2GXPX2P.js} +143 -13
  5. package/dist/{chunk-KHHULLBZ.js → chunk-DHGAKJXP.js} +1 -1
  6. package/dist/{chunk-3ZN7IXOZ.js → chunk-HO4745TX.js} +250 -2
  7. package/dist/client.d.ts +201 -0
  8. package/dist/connection/dependencies.d.ts +3 -0
  9. package/dist/connection/diagnostics.d.ts +3 -2
  10. package/dist/connection/lifecycle.d.ts +1 -0
  11. package/dist/connection/types.d.ts +2 -0
  12. package/dist/effect.js +62 -4
  13. package/dist/generated/http-api.d.ts +197 -0
  14. package/dist/generated/schemas.d.ts +366 -0
  15. package/dist/generated/sync.d.ts +74 -3
  16. package/dist/generated/whiteboard-v1.d.ts +71 -9
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.js +18 -14
  19. package/dist/public-invites/index.js +2 -2
  20. package/dist/space-client/reload-rejoin.d.ts +1 -1
  21. package/dist/space-client/types.d.ts +8 -1
  22. package/dist/sync/connect-diagnostics.d.ts +10 -0
  23. package/dist/sync/index.js +1 -1
  24. package/dist/sync/types.d.ts +1 -0
  25. package/dist/sync/v1-client.d.ts +2 -0
  26. package/dist/sync/v1-types.d.ts +4 -0
  27. package/dist/whiteboard/index.d.ts +2 -5
  28. package/dist/whiteboard/types.d.ts +26 -3
  29. package/dist/whiteboard/v1-client.d.ts +3 -1
  30. package/dist/whiteboard/v1-codec.d.ts +5 -1
  31. package/dist/whiteboard/v1-multipart.d.ts +1 -1
  32. package/dist/whiteboard/view-bounds.d.ts +5 -0
  33. package/dist/whiteboard/view-versions.d.ts +9 -0
  34. package/package.json +1 -1
@@ -120,7 +120,7 @@ var BrowserSyncSocket = class {
120
120
  this.#socket = socket;
121
121
  this.#socket.addEventListener("open", () => this.onopen?.());
122
122
  this.#socket.addEventListener("message", (event) => this.onmessage?.({ data: event.data }));
123
- this.#socket.addEventListener("close", (event) => this.onclose?.({ code: event.code }));
123
+ this.#socket.addEventListener("close", (event) => this.onclose?.({ code: event.code, reason: event.reason }));
124
124
  this.#socket.addEventListener("error", () => this.onerror?.());
125
125
  }
126
126
  send(data) {
@@ -176,7 +176,7 @@ var ReactNativeSyncSocket = class {
176
176
  this.#socket = socket;
177
177
  this.#socket.onopen = () => this.onopen?.();
178
178
  this.#socket.onmessage = (event) => this.onmessage?.({ data: event.data });
179
- this.#socket.onclose = (event) => this.onclose?.({ code: typeof event.code === "number" ? event.code : 1006 });
179
+ this.#socket.onclose = (event) => this.onclose?.({ code: typeof event.code === "number" ? event.code : 1006, reason: typeof event.reason === "string" ? event.reason : void 0 });
180
180
  this.#socket.onerror = () => this.onerror?.();
181
181
  }
182
182
  send(data) {
@@ -196,7 +196,7 @@ var BrowserFallbackSyncSocket = class {
196
196
  this.#socket = socket;
197
197
  this.#socket.addEventListener("open", () => this.onopen?.());
198
198
  this.#socket.addEventListener("message", (event) => this.onmessage?.({ data: event.data }));
199
- this.#socket.addEventListener("close", (event) => this.onclose?.({ code: event.code }));
199
+ this.#socket.addEventListener("close", (event) => this.onclose?.({ code: event.code, reason: event.reason }));
200
200
  this.#socket.addEventListener("error", () => this.onerror?.());
201
201
  }
202
202
  send(data) {
@@ -217,6 +217,40 @@ function unsubscribe(subscription) {
217
217
  }
218
218
  }
219
219
 
220
+ // src/sync/connect-diagnostics.ts
221
+ var SAFE_REASONS = /* @__PURE__ */ new Set([
222
+ "hello timeout",
223
+ "invalid token",
224
+ "policy violation",
225
+ "dependency unavailable",
226
+ "server draining",
227
+ "heartbeat timeout",
228
+ "normal",
229
+ "transport error",
230
+ "authentication failed",
231
+ "delivery recovery required",
232
+ "space action delivery recovery required",
233
+ "text frames only",
234
+ "unsupported protocol",
235
+ "invalid frame",
236
+ "WebSocket dial timeout",
237
+ "lifecycle transport deadline",
238
+ "lifecycle unavailable",
239
+ "invalid_frame",
240
+ "state_digest_mismatch",
241
+ "state_digest_recovery_failed",
242
+ "terminal event acknowledged",
243
+ "client stopped",
244
+ "participant inactive",
245
+ "terminal recovery"
246
+ ]);
247
+ function safeSyncCloseReason(reason) {
248
+ return reason ? SAFE_REASONS.has(reason) ? reason : "redacted" : null;
249
+ }
250
+ function formatSyncConnectDiagnostic(diagnostic) {
251
+ return `[${diagnostic.stage}; open=${diagnostic.opened ? 1 : 0}; close=${diagnostic.closeCode ?? "none"}; reason=${safeSyncCloseReason(diagnostic.closeReason ?? void 0) ?? "none"}; ${Math.round(diagnostic.durationMs)}ms]`;
252
+ }
253
+
220
254
  // src/sync/v1-health.ts
221
255
  var SYNC_HEALTH_BUDGET = {
222
256
  probeIntervalMs: 500,
@@ -266,7 +300,14 @@ var SyncProtocolMetadata = {
266
300
  field: "protocol",
267
301
  value: 1,
268
302
  transport: "websocket-json-text",
269
- route: "/v1/sync"
303
+ route: "/v1/sync",
304
+ entryGeneration: {
305
+ queryParameter: "entry_generation",
306
+ newEntry: "new",
307
+ resume: "previous welcome entry_generation",
308
+ confirmation: "monotonic compare-and-set",
309
+ scope: "participant"
310
+ }
270
311
  },
271
312
  directions: {
272
313
  clientToServer: "client-to-server",
@@ -290,7 +331,7 @@ var SyncProtocolMetadata = {
290
331
  },
291
332
  {
292
333
  id: "live",
293
- accepts: ["command", "live_target", "directed_request", "delivery_ack", "request_ack", "reaction_send", "chat_send", "chat_page_request", "chat_read_set", "chat_reaction_set", "ping"],
334
+ accepts: ["entered", "command", "live_target", "directed_request", "delivery_ack", "request_ack", "reaction_send", "chat_send", "chat_page_request", "chat_read_set", "chat_reaction_set", "ping"],
294
335
  heartbeat: {
295
336
  intervalMs: 2e4,
296
337
  missedDeadlinesBeforeClose: 2
@@ -570,7 +611,7 @@ var SyncProtocolMetadata = {
570
611
  {
571
612
  code: 1008,
572
613
  connection: "closed",
573
- reasons: ["invalid token", "policy violation"]
614
+ reasons: ["invalid token", "policy violation", "entry timeout"]
574
615
  },
575
616
  {
576
617
  code: 1009,
@@ -742,6 +783,8 @@ function strictClientFrame(value) {
742
783
  return exactObject(value, ["type", "stream", "revision", "state_digest"]);
743
784
  case "recovery_ack":
744
785
  return exactObject(value, ["type", "recovery_id", "revision", "state_digest"]);
786
+ case "entered":
787
+ return exactObject(value, ["type"]);
745
788
  case "ping":
746
789
  return exactObject(value, ["type"]);
747
790
  default:
@@ -824,7 +867,8 @@ function strictWelcome(value) {
824
867
  const base = ["type", "protocol", "participant_id", "participant_generation", "recovery_id", "head", "mode"];
825
868
  const extension = Array.isArray(value.extensions) && value.extensions.length === 1 ? value.extensions[0] : void 0;
826
869
  const extensionValid = isObject(extension) && ["collaboration_v1", "collaboration_v2"].includes(String(extension.name)) && exactObject(extension, ["name", "capabilities", "participant_capabilities", "chat_head_sequence", "retained_floor_sequence", "read_receipts"]) && Array.isArray(extension.read_receipts);
827
- const fields = extensionValid ? [...base, "extensions"] : base;
870
+ if (Object.hasOwn(value, "entry_confirmation") && value.entry_confirmation !== true) return false;
871
+ const fields = [...base, ...extensionValid ? ["extensions"] : [], ...Object.hasOwn(value, "entry_confirmation") ? ["entry_confirmation"] : [], ...Object.hasOwn(value, "entry_generation") ? ["entry_generation"] : []];
828
872
  if (!strictCursor(value.head)) return false;
829
873
  if (value.mode === "snapshot") return exactObjectWithCorrelation(value, [...fields, "snapshot"]) && strictSnapshot(value.snapshot);
830
874
  if (value.mode === "terminal") return exactObjectWithCorrelation(value, [...fields, "reason"]);
@@ -883,6 +927,8 @@ function strictServerFrame(value) {
883
927
  return exactObjectWithCorrelation(value, ["type", "command_id", "code"]);
884
928
  case "error":
885
929
  return exactObjectWithCorrelation(value, ["type", "code", "detail"]);
930
+ case "entered_ack":
931
+ return exactObjectWithCorrelation(value, ["type"]);
886
932
  case "pong":
887
933
  return exactObjectWithCorrelation(value, ["type"]);
888
934
  default:
@@ -1423,7 +1469,16 @@ var CollaborationWelcomeExtensionSchema = Schema.Struct({
1423
1469
  retained_floor_sequence: Schema.NullOr(UnsignedDecimalSchema),
1424
1470
  read_receipts: Schema.Array(ChatReadReceiptSchema).check(Schema.isMaxLength(500))
1425
1471
  }).check(exactKeys(["name", "capabilities", "participant_capabilities", "chat_head_sequence", "retained_floor_sequence", "read_receipts"]));
1426
- var WelcomeBase = { type: Schema.Literal("welcome"), protocol: Schema.Literal(1), participant_id: UuidSchema, participant_generation: PositiveIntegerSchema, recovery_id: UuidSchema, head: ControlCursorSchema };
1472
+ var WelcomeBase = {
1473
+ type: Schema.Literal("welcome"),
1474
+ protocol: Schema.Literal(1),
1475
+ participant_id: UuidSchema,
1476
+ participant_generation: PositiveIntegerSchema,
1477
+ recovery_id: UuidSchema,
1478
+ head: ControlCursorSchema,
1479
+ entry_confirmation: Schema.optionalKey(Schema.Literal(true)),
1480
+ entry_generation: Schema.optionalKey(PositiveIntegerSchema.check(Schema.isLessThanOrEqualTo(9007199254740991)))
1481
+ };
1427
1482
  var ExtendedWelcomeBase = { ...WelcomeBase, extensions: Schema.Tuple([CollaborationWelcomeExtensionSchema]) };
1428
1483
  var WelcomeSnapshotFrameSchema = Schema.Struct({ ...WelcomeBase, mode: Schema.Literal("snapshot"), snapshot: SnapshotSchema, ...ServerCorrelationFields }).check(boundedServerFrame(SyncProtocolLimits.snapshotEncodedBytes));
1429
1484
  var WelcomeReplayFrameSchema = Schema.Struct({ ...WelcomeBase, mode: Schema.Literal("replay"), ...ServerCorrelationFields });
@@ -1599,6 +1654,8 @@ var RejectedChatReadResultFrameSchema = Schema.Struct({ type: Schema.Literal("ch
1599
1654
  var ChatReadResultFrameSchema = Schema.Union([AcceptedChatReadResultFrameSchema, RejectedChatReadResultFrameSchema]);
1600
1655
  var RetryableErrorFrameSchema = Schema.Struct({ type: Schema.Literal("retryable_error"), command_id: CommandIdSchema, code: RetryableErrorCodeSchema, ...ServerCorrelationFields });
1601
1656
  var ErrorFrameSchema = Schema.Struct({ type: Schema.Literal("error"), code: ProtocolErrorCodeSchema, detail: boundedUtf8String(1024), ...ServerCorrelationFields });
1657
+ var EnteredFrameSchema = Schema.Struct({ type: Schema.Literal("entered") });
1658
+ var EnteredAckFrameSchema = Schema.Struct({ type: Schema.Literal("entered_ack"), ...ServerCorrelationFields });
1602
1659
  var PingFrameSchema = Schema.Struct({ type: Schema.Literal("ping") });
1603
1660
  var PongFrameSchema = Schema.Struct({ type: Schema.Literal("pong"), ...ServerCorrelationFields });
1604
1661
  var SyncV1ClientFrameSchema = Schema.Unknown.check(Schema.makeFilter((frame) => strictClientFrame(frame) ? void 0 : { path: [], issue: "must not contain unknown or missing fields" })).pipe(
@@ -1632,6 +1689,7 @@ var SyncV1ClientFrameSchema = Schema.Unknown.check(Schema.makeFilter((frame) =>
1632
1689
  ChatReactionSetFrameSchema,
1633
1690
  DeliveryAckFrameSchema,
1634
1691
  RecoveryAckFrameSchema,
1692
+ EnteredFrameSchema,
1635
1693
  PingFrameSchema
1636
1694
  ])
1637
1695
  )
@@ -1663,6 +1721,7 @@ var SyncV1ServerFrameSchema = Schema.Unknown.check(Schema.makeFilter((frame) =>
1663
1721
  ChatReactionResultFrameSchema,
1664
1722
  RetryableErrorFrameSchema,
1665
1723
  ErrorFrameSchema,
1724
+ EnteredAckFrameSchema,
1666
1725
  PongFrameSchema
1667
1726
  ])
1668
1727
  )
@@ -2939,6 +2998,9 @@ var V1SyncClient = class {
2939
2998
  #snapshotRevision = null;
2940
2999
  #controlEvents = /* @__PURE__ */ new Map();
2941
3000
  #liveTargets;
3001
+ #entryPending = false;
3002
+ // Older Sync rejects new hello fields, so entry confirmation is requested on the URL and granted in welcome.
3003
+ #entryNegotiated = false;
2942
3004
  #requests = /* @__PURE__ */ new Map();
2943
3005
  #mediaEventEvidence = /* @__PURE__ */ new Map();
2944
3006
  #presenceEventEvidence = /* @__PURE__ */ new Map();
@@ -2949,6 +3011,7 @@ var V1SyncClient = class {
2949
3011
  #presence = null;
2950
3012
  #participantId = null;
2951
3013
  #participantGeneration = null;
3014
+ #entryGeneration = null;
2952
3015
  #recovery = null;
2953
3016
  #snapshotRecoveryRequested = false;
2954
3017
  #lastDigestRecoveryAt = null;
@@ -2958,6 +3021,12 @@ var V1SyncClient = class {
2958
3021
  #reconnectTimer;
2959
3022
  #cancelDial;
2960
3023
  #dialTimeoutCount = 0;
3024
+ #connectStartedAt = null;
3025
+ #opened = false;
3026
+ #connectFailure;
3027
+ #connectDiagnostic() {
3028
+ return { stage: this.#opened ? "hello" : "upgrade", opened: this.#opened, closeCode: null, closeReason: null, durationMs: Math.max(0, this.#clock().now() - (this.#connectStartedAt ?? this.#clock().now())) };
3029
+ }
2961
3030
  #reconnectAttempt = 0;
2962
3031
  #heartbeatTimer;
2963
3032
  #missedHeartbeats = 0;
@@ -3036,6 +3105,8 @@ var V1SyncClient = class {
3036
3105
  }
3037
3106
  stop() {
3038
3107
  this.#started = false;
3108
+ this.#entryPending = false;
3109
+ this.#entryGeneration = null;
3039
3110
  this.#startupGeneration += 1;
3040
3111
  this.#unsubscribeLifecycle?.();
3041
3112
  this.#unsubscribeLifecycle = void 0;
@@ -3055,11 +3126,24 @@ var V1SyncClient = class {
3055
3126
  this.#liveTargets.resetLocalMedia();
3056
3127
  this.#emit();
3057
3128
  }
3129
+ /** Announces completed startup; transport recovery resends until acknowledged. */
3130
+ async confirmEntered() {
3131
+ this.#requireLive();
3132
+ this.#entryPending = true;
3133
+ if (!this.#entryNegotiated) return;
3134
+ this.#send({ type: "entered" });
3135
+ }
3058
3136
  getSnapshot() {
3059
3137
  const pendingCommands = this.#commandScheduler.pendingCommands;
3060
3138
  const optimisticControl = this.#control && this.#participantId ? optimisticV1Control(this.#control, this.#participantId, pendingCommands) : this.#control;
3061
3139
  return {
3062
- connection: { ...this.#phase, ...this.#phase.phase === "live" ? { noticeUnresponsive: this.#health.health === "recovering", health: this.#health.health } : {}, ...this.#dialTimeoutCount ? { dialTimeoutCount: this.#dialTimeoutCount } : {} },
3140
+ connection: {
3141
+ ...this.#phase,
3142
+ ...this.#connectStartedAt !== null && (this.#phase.phase === "connecting" || this.#phase.phase === "recovering") ? { connectAttempt: this.#connectDiagnostic() } : {},
3143
+ ...this.#connectFailure && (this.#phase.phase === "connecting" || this.#phase.phase === "recovering") ? { connectFailure: this.#connectFailure } : {},
3144
+ ...this.#phase.phase === "live" ? { noticeUnresponsive: this.#health.health === "recovering", health: this.#health.health } : {},
3145
+ ...this.#dialTimeoutCount ? { dialTimeoutCount: this.#dialTimeoutCount } : {}
3146
+ },
3063
3147
  participantId: this.#participantId,
3064
3148
  participantGeneration: this.#participantGeneration,
3065
3149
  control: this.#control,
@@ -3199,8 +3283,19 @@ var V1SyncClient = class {
3199
3283
  #connect() {
3200
3284
  if (!this.#started || !this.#transportAvailable || this.#socket || this.#phase.phase === "terminal") return;
3201
3285
  this.#phase = { phase: "connecting" };
3286
+ this.#connectStartedAt = this.#clock().now();
3287
+ this.#opened = false;
3288
+ this.#connectFailure = void 0;
3202
3289
  this.#emit();
3203
- const socket = this.#options.webSocket.connect(this.#options.url);
3290
+ this.#entryNegotiated = false;
3291
+ let socket;
3292
+ try {
3293
+ socket = this.#options.webSocket.connect(entryUrl(this.#options.url, this.#entryGeneration, this.#options.entryConfirmation === true));
3294
+ } catch {
3295
+ this.#connectFailure = this.#connectDiagnostic();
3296
+ this.#emit();
3297
+ throw new V1SyncError("Sync WebSocket could not be created", "sync_hello_timeout");
3298
+ }
3204
3299
  const connectionGeneration = ++this.#connectionGeneration;
3205
3300
  this.#socket = socket;
3206
3301
  this.#cancelDial = scheduleSyncDialDeadline(
@@ -3208,6 +3303,7 @@ var V1SyncClient = class {
3208
3303
  () => {
3209
3304
  this.#cancelDial = void 0;
3210
3305
  this.#dialTimeoutCount += 1;
3306
+ this.#connectFailure = this.#connectDiagnostic();
3211
3307
  this.#recover("WebSocket dial timeout");
3212
3308
  },
3213
3309
  this.#options.dialTimeoutMs
@@ -3215,18 +3311,36 @@ var V1SyncClient = class {
3215
3311
  socket.onopen = () => {
3216
3312
  if (socket !== this.#socket) return;
3217
3313
  this.#clearDial();
3314
+ this.#opened = true;
3315
+ this.#connectFailure = void 0;
3218
3316
  void this.#authenticate(socket);
3219
3317
  };
3220
3318
  socket.onmessage = (event) => {
3221
3319
  this.#inbound = this.#inbound.then(() => this.#receive(socket, event.data));
3222
3320
  };
3223
- socket.onclose = () => {
3321
+ socket.onclose = (event) => {
3322
+ if (socket === this.#socket && (this.#phase.phase === "connecting" || this.#phase.phase === "recovering")) {
3323
+ this.#connectFailure = { ...this.#connectDiagnostic(), closeCode: event.code, closeReason: safeSyncCloseReason(event.reason) };
3324
+ this.#emit();
3325
+ }
3224
3326
  this.#clock().setTimeout(() => {
3225
3327
  if (connectionGeneration !== this.#connectionGeneration) return;
3226
- this.#inbound = this.#inbound.then(() => this.#disconnected(socket));
3328
+ this.#inbound = this.#inbound.then(() => {
3329
+ if (socket === this.#socket && event.code === 1008 && (event.reason === "" || event.reason === "invalid token" || event.reason === "policy violation" || event.reason === "entry timeout")) {
3330
+ this.#phase = { phase: "terminal", terminalReason: event.reason === "entry timeout" ? "entry_timeout" : "access_rejected" };
3331
+ this.#emit();
3332
+ }
3333
+ this.#disconnected(socket);
3334
+ });
3227
3335
  }, 0);
3228
3336
  };
3229
- socket.onerror = () => socket.close(CLIENT_RESTART_CLOSE_CODE, "transport error");
3337
+ socket.onerror = () => {
3338
+ if (socket === this.#socket && (this.#phase.phase === "connecting" || this.#phase.phase === "recovering")) {
3339
+ this.#connectFailure = this.#connectDiagnostic();
3340
+ this.#emit();
3341
+ }
3342
+ socket.close(CLIENT_RESTART_CLOSE_CODE, "transport error");
3343
+ };
3230
3344
  }
3231
3345
  async #authenticate(socket) {
3232
3346
  try {
@@ -3355,6 +3469,10 @@ var V1SyncClient = class {
3355
3469
  return;
3356
3470
  case "error":
3357
3471
  throw new V1ReplicaError(frame.code);
3472
+ case "entered_ack":
3473
+ this.#requireLive();
3474
+ this.#entryPending = false;
3475
+ return;
3358
3476
  case "pong": {
3359
3477
  this.#requireLive();
3360
3478
  this.#missedHeartbeats = 0;
@@ -3368,6 +3486,8 @@ var V1SyncClient = class {
3368
3486
  async #welcome(frame) {
3369
3487
  if (this.#phase.phase !== "recovering" || this.#recovery) throw new V1ReplicaError("unexpected welcome");
3370
3488
  this.#collaborationState.acceptWelcome(frame);
3489
+ this.#entryNegotiated = frame.entry_confirmation === true;
3490
+ this.#entryGeneration = frame.entry_generation ?? this.#entryGeneration;
3371
3491
  this.#participantId = frame.participant_id;
3372
3492
  this.#participantGeneration = frame.participant_generation;
3373
3493
  this.#updateLocalMediaStates();
@@ -3486,8 +3606,11 @@ var V1SyncClient = class {
3486
3606
  if (!this.#recovery?.controlComplete || !this.#media || !this.#presence) return;
3487
3607
  this.#recovery = null;
3488
3608
  this.#phase = { phase: "live" };
3609
+ this.#connectStartedAt = null;
3610
+ this.#connectFailure = void 0;
3489
3611
  this.#reconnectAttempt = 0;
3490
3612
  this.#missedHeartbeats = 0;
3613
+ if (this.#entryPending && this.#entryNegotiated) this.#send({ type: "entered" });
3491
3614
  this.#commandScheduler.enterLive();
3492
3615
  this.#liveTargets.enterLive();
3493
3616
  this.#startHeartbeat();
@@ -3746,6 +3869,12 @@ function copyPublication(publication) {
3746
3869
  function validMediaPublication(publication) {
3747
3870
  return typeof publication.participantId === "string" && publication.participantId.length > 0 && (publication.source === "microphone" || publication.source === "camera" || publication.source === "screen" || publication.source === "screen_audio") && typeof publication.enabled === "boolean" && (publication.publicationId === null || typeof publication.publicationId === "string") && (!publication.enabled || publication.publicationId !== null);
3748
3871
  }
3872
+ function entryUrl(value, generation, confirmation) {
3873
+ const url = new URL(value);
3874
+ url.searchParams.set("entry_generation", generation === null ? "new" : String(generation));
3875
+ if (confirmation) url.searchParams.set("entry_confirmation", "1");
3876
+ return url.toString();
3877
+ }
3749
3878
  function assertV1Url(value) {
3750
3879
  const url = new URL(value);
3751
3880
  if (url.pathname !== "/v1/sync") throw new V1SyncError("SyncEngine v1 websocket URL must use /v1/sync", "invalid_url");
@@ -3893,6 +4022,7 @@ function createV1SyncClient(options) {
3893
4022
  }
3894
4023
 
3895
4024
  export {
4025
+ formatSyncConnectDiagnostic,
3896
4026
  UuidSchema,
3897
4027
  ReactionValues,
3898
4028
  ReactionSchema,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createChalkEffectClient,
3
3
  parseAccessGrant
4
- } from "./chunk-3ZN7IXOZ.js";
4
+ } from "./chunk-HO4745TX.js";
5
5
 
6
6
  // src/public-invites/client.ts
7
7
  import { Effect } from "effect";