@q9labsai/chalk-client 5.2.2 → 5.2.4

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
@@ -1761,6 +1761,66 @@ export declare const createChalkEffectClient: (options: ChalkEffectClientOptions
1761
1761
  readonly message: import("effect/Schema").String;
1762
1762
  }>;
1763
1763
  }>, never, never>>, never, never>, never, never>;
1764
+ readonly reportConnectionFailure: HttpApiClient.Client.Method<import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"reportConnectionFailure", "POST", "/v1/tenants/:tenant_id/connection-reports", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
1765
+ readonly tenant_id: import("effect/Schema").brand<import("effect/Schema").String, "TenantId">;
1766
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
1767
+ readonly events: import("effect/Schema").$Array<import("effect/Schema").Struct<{
1768
+ readonly attempt: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1769
+ readonly close_code: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1770
+ readonly code: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["invalid_state", "invalid_access", "access_unavailable", "permission_denied", "device_not_found", "device_busy", "device_constraint_invalid", "media_capture_failed", "sync_start_failed", "state_digest_recovery_failed", "sync_hello_timeout", "media_start_failed", "join_cleanup_unconfirmed", "sync_recovery_exhausted", "media_recovery_exhausted", "command_rejected", "leave_unconfirmed", "episode_ended", "unsupported_environment", "internal_error", "collaboration_unavailable", "chat_cursor_reset_required", "rate_limited", "invalid_payload"]>>;
1771
+ readonly duration_ms: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1772
+ readonly elapsed_ms: import("effect/Schema").Number;
1773
+ readonly event: import("effect/Schema").Literals<readonly ["space_join_span", "state_changed", "connection_failed", "sync_connect_failed", "sync_dial_timeout", "access_refreshed", "access_refresh_failed", "recovery_attempt", "recovery_succeeded", "recovery_exhausted", "cleanup_completed", "cleanup_unconfirmed", "sync_socket_open", "sync_socket_close", "sync_heartbeat_gap", "media_state", "media_http_error"]>;
1774
+ readonly heartbeat_gap_ms: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1775
+ readonly http_status: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1776
+ readonly outcome: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["started", "succeeded", "failed", "cancelled"]>>;
1777
+ readonly phase: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["idle", "connecting", "live", "recovering", "failed", "stopped", "new", "connected", "disconnected", "closed"]>>;
1778
+ readonly state: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["idle", "joining", "live", "reconnecting", "leaving", "left", "failed"]>>;
1779
+ readonly step: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["join", "acquire_initial_media", "access_initialize", "create_media_client", "create_sync_client", "start_media", "start_sync", "wait_for_sync_live", "confirm_entered"]>>;
1780
+ }>>;
1781
+ readonly trigger: import("effect/Schema").Literals<readonly ["join_failed", "connection_lost", "recovery_exhausted"]>;
1782
+ readonly version: import("effect/Schema").Literal<1>;
1783
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Void>, import("effect/Schema").toCodecJson<import("effect/Schema").decodeTo<typeof import("./effect").AccessForbiddenError, import("effect/Schema").Struct<{
1784
+ readonly error: import("effect/Schema").Struct<{
1785
+ readonly code: import("effect/Schema").Literal<"access.forbidden">;
1786
+ readonly message: import("effect/Schema").String;
1787
+ }>;
1788
+ }>, never, never> | import("effect/Schema").decodeTo<typeof import("./effect").AccessUnauthenticatedError, import("effect/Schema").Struct<{
1789
+ readonly error: import("effect/Schema").Struct<{
1790
+ readonly code: import("effect/Schema").Literal<"access.unauthenticated">;
1791
+ readonly message: import("effect/Schema").String;
1792
+ }>;
1793
+ }>, never, never> | import("effect/Schema").decodeTo<typeof import("./effect").RequestInvalidError, import("effect/Schema").Struct<{
1794
+ readonly error: import("effect/Schema").Struct<{
1795
+ readonly code: import("effect/Schema").Literal<"request.invalid">;
1796
+ readonly message: import("effect/Schema").String;
1797
+ }>;
1798
+ }>, never, never> | import("effect/Schema").decodeTo<typeof import("./effect").RequestPayloadTooLargeError, import("effect/Schema").Struct<{
1799
+ readonly error: import("effect/Schema").Struct<{
1800
+ readonly code: import("effect/Schema").Literal<"request.payload_too_large">;
1801
+ readonly message: import("effect/Schema").String;
1802
+ }>;
1803
+ }>, never, never> | import("effect/Schema").decodeTo<typeof import("./effect").RequestRateLimitedError, import("effect/Schema").Struct<{
1804
+ readonly error: import("effect/Schema").Struct<{
1805
+ readonly code: import("effect/Schema").Literal<"request.rate_limited">;
1806
+ readonly message: import("effect/Schema").String;
1807
+ }>;
1808
+ }>, never, never> | import("effect/Schema").decodeTo<typeof import("./effect").ServiceInternalError, import("effect/Schema").Struct<{
1809
+ readonly error: import("effect/Schema").Struct<{
1810
+ readonly code: import("effect/Schema").Literal<"service.internal_error">;
1811
+ readonly message: import("effect/Schema").String;
1812
+ }>;
1813
+ }>, never, never> | import("effect/Schema").decodeTo<typeof import("./effect").ServiceUnavailableError, import("effect/Schema").Struct<{
1814
+ readonly error: import("effect/Schema").Struct<{
1815
+ readonly code: import("effect/Schema").Literal<"service.unavailable">;
1816
+ readonly message: import("effect/Schema").String;
1817
+ }>;
1818
+ }>, never, never> | import("effect/Schema").decodeTo<typeof import("./effect").TenantInvalidIdError, import("effect/Schema").Struct<{
1819
+ readonly error: import("effect/Schema").Struct<{
1820
+ readonly code: import("effect/Schema").Literal<"tenant.invalid_id">;
1821
+ readonly message: import("effect/Schema").String;
1822
+ }>;
1823
+ }>, never, never>>, never, never>, never, never>;
1764
1824
  readonly revokeAPIKey: HttpApiClient.Client.Method<import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"revokeAPIKey", "DELETE", "/v1/tenants/:tenant_id/api-keys/:api_key_id", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
1765
1825
  readonly api_key_id: import("effect/Schema").brand<import("effect/Schema").String, "UUID">;
1766
1826
  readonly tenant_id: import("effect/Schema").brand<import("effect/Schema").String, "TenantId">;
@@ -1,3 +1,4 @@
1
+ import type { ConnectionReporter, ConnectionReportTransportEvent } from "./report";
1
2
  import type { ClientMediaPlane, CloudflareSFUBootstrap, ConnectionMediaSnapshot } from "../media";
2
3
  import type { ChalkChatFileTransport } from "../chat-files";
3
4
  import type { V1AdmissionTarget, V1AssignableRole, V1CommandResult, V1EpisodeSnapshot, V1SelfMediaTargetResult } from "../sync";
@@ -79,6 +80,8 @@ export type ConnectionMediaFactoryInput = {
79
80
  readonly access: ParsedAccessGrant;
80
81
  readonly credential: () => Promise<string>;
81
82
  readonly replaceMediaConnection?: () => Promise<ParticipantMediaAccess>;
83
+ readonly traceparent?: string;
84
+ readonly onTransportDiagnostic?: (event: ConnectionReportTransportEvent) => void;
82
85
  readonly onFailure: (error: unknown) => void;
83
86
  readonly onScreenEnded: () => void;
84
87
  };
@@ -86,6 +89,8 @@ export type ConnectionSyncFactoryInput = {
86
89
  readonly access: ParsedAccessGrant;
87
90
  readonly token: () => Promise<string>;
88
91
  readonly media: ConnectionMediaClient;
92
+ readonly traceparent?: string;
93
+ readonly onTransportDiagnostic?: (event: ConnectionReportTransportEvent) => void;
89
94
  };
90
95
  export type ConnectionWhiteboardFactoryInput = {
91
96
  readonly onWatchdogReplacement?: ChalkWhiteboardV1ClientOptions["onWatchdogReplacement"];
@@ -97,6 +102,7 @@ export type ConnectionChatFileFactoryInput = {
97
102
  };
98
103
  export type ConnectionDependencies = {
99
104
  readonly clock: ConnectionClock;
105
+ readonly createConnectionReporter?: (access: () => ParsedAccessGrant | null) => ConnectionReporter | undefined;
100
106
  readonly cancelPendingAdmission?: (access: ParsedAccessGrant, signal: AbortSignal) => Promise<boolean>;
101
107
  readonly mediaDevices: ConnectionMediaDevices;
102
108
  readonly createMediaClient: (input: ConnectionMediaFactoryInput) => ConnectionMediaClient;
@@ -32,6 +32,13 @@ export type ConnectionDiagnostic = {
32
32
  readonly outcome?: ConnectionJoinTraceOutcome;
33
33
  readonly durationMs?: number;
34
34
  readonly sync?: import("../sync/connect-diagnostics").SyncConnectDiagnostic;
35
+ readonly recovery?: {
36
+ readonly reference: "connection.sync_recovery_exhausted" | "connection.media_recovery_exhausted";
37
+ readonly attempts: number;
38
+ readonly transport: import("../sync/connect-diagnostics").SyncRecoveryDiagnostic | null;
39
+ readonly lastHeartbeatReplyAgoMs: number | null;
40
+ readonly visibilityState: DocumentVisibilityState | null;
41
+ };
35
42
  };
36
43
  export declare class ConnectionDiagnostics {
37
44
  #private;
@@ -41,6 +48,13 @@ export declare class ConnectionDiagnostics {
41
48
  readonly onEvent?: (event: ConnectionDiagnostic) => void;
42
49
  });
43
50
  record(input: Omit<ConnectionDiagnostic, "timestamp">): void;
51
+ recordRecoveryExhausted(input: {
52
+ readonly state: ConnectionState;
53
+ readonly epoch: number;
54
+ readonly code: "sync_recovery_exhausted" | "media_recovery_exhausted";
55
+ readonly attempts: number;
56
+ readonly transport: import("../sync/connect-diagnostics").SyncRecoveryDiagnostic | null;
57
+ }): void;
44
58
  snapshot(): readonly ConnectionDiagnostic[];
45
59
  startSpan(input: {
46
60
  readonly step: ConnectionJoinTraceStep;
@@ -0,0 +1,21 @@
1
+ import type { ParsedAccessGrant } from "../access/grant";
2
+ import type { ConnectionDiagnostic } from "./diagnostics";
3
+ import type { ConnectionReport, ConnectionReportTransportEvent } from "../transport-diagnostics";
4
+ export type { ConnectionReport, ConnectionReportTransportEvent } from "../transport-diagnostics";
5
+ type ReporterOptions = {
6
+ readonly traceparent: string;
7
+ readonly now: () => number;
8
+ readonly access: () => ParsedAccessGrant | null;
9
+ readonly send: (access: ParsedAccessGrant, report: ConnectionReport, signal: AbortSignal, traceparent: string) => Promise<void>;
10
+ readonly online: () => boolean;
11
+ readonly subscribeOnline: (listener: () => void) => () => void;
12
+ };
13
+ /** Only SDK-owned enums and numeric facts enter this buffer. No generic logging. */
14
+ export declare class ConnectionReporter {
15
+ #private;
16
+ constructor(options: ReporterOptions);
17
+ recordDiagnostic(diagnostic: ConnectionDiagnostic): void;
18
+ recordTransport(event: ConnectionReportTransportEvent): void;
19
+ dispose(): void;
20
+ get traceparent(): string;
21
+ }
package/dist/effect.js CHANGED
@@ -17,8 +17,8 @@ import {
17
17
  makeSpaceClientCoreLayer,
18
18
  makeSpaceClientCoreLayerFromServices,
19
19
  makeSpaceStoreLayer
20
- } from "./chunk-XPW3OCPO.js";
21
- import "./chunk-DWKTGBHR.js";
20
+ } from "./chunk-LDPC2JZB.js";
21
+ import "./chunk-3ASKGMD3.js";
22
22
  import {
23
23
  APIKeyListSchema,
24
24
  APIKeyWithSecretSchema,
@@ -139,6 +139,7 @@ import {
139
139
  CloudflareSFURenegotiateResponseSchema,
140
140
  CloudflareSFUTracksAPIResponseSchema,
141
141
  CloudflareSFUTracksRequestSchema,
142
+ ConnectionReportRequestSchema,
142
143
  CreateAPIKey429ResponseHeadersSchema,
143
144
  CreateAPIKeyErrorSchema,
144
145
  CreateAPIKeyPathParamsSchema,
@@ -548,6 +549,10 @@ import {
548
549
  RenegotiateCloudflareSFUPathParamsSchema,
549
550
  RenegotiateCloudflareSFURequestBodySchema,
550
551
  RenegotiateCloudflareSFUResponseSchema,
552
+ ReportConnectionFailure429ResponseHeadersSchema,
553
+ ReportConnectionFailureErrorSchema,
554
+ ReportConnectionFailurePathParamsSchema,
555
+ ReportConnectionFailureRequestBodySchema,
551
556
  ReportsDeliveryFailedError,
552
557
  ReportsDeliveryFailedErrorSchema,
553
558
  ReportsDeliveryFailedErrorWireSchema,
@@ -828,8 +833,8 @@ import {
828
833
  WhiteboardStorageUnavailableErrorSchema,
829
834
  WhiteboardStorageUnavailableErrorWireSchema,
830
835
  createChalkEffectClient
831
- } from "./chunk-GA3JDPFI.js";
832
- import "./chunk-AIJ5Z6HA.js";
836
+ } from "./chunk-AZONR3Q3.js";
837
+ import "./chunk-5YPQNMJE.js";
833
838
 
834
839
  // src/space-client/effect.ts
835
840
  import { Context, Effect, Exit, Layer, Scope } from "effect";
@@ -990,6 +995,7 @@ export {
990
995
  ConnectionAccessService,
991
996
  ConnectionLifecycleService,
992
997
  ConnectionPlatformService,
998
+ ConnectionReportRequestSchema,
993
999
  CreateAPIKey429ResponseHeadersSchema,
994
1000
  CreateAPIKeyErrorSchema,
995
1001
  CreateAPIKeyPathParamsSchema,
@@ -1399,6 +1405,10 @@ export {
1399
1405
  RenegotiateCloudflareSFUPathParamsSchema,
1400
1406
  RenegotiateCloudflareSFURequestBodySchema,
1401
1407
  RenegotiateCloudflareSFUResponseSchema,
1408
+ ReportConnectionFailure429ResponseHeadersSchema,
1409
+ ReportConnectionFailureErrorSchema,
1410
+ ReportConnectionFailurePathParamsSchema,
1411
+ ReportConnectionFailureRequestBodySchema,
1402
1412
  ReportsDeliveryFailedError,
1403
1413
  ReportsDeliveryFailedErrorSchema,
1404
1414
  ReportsDeliveryFailedErrorWireSchema,
@@ -1726,6 +1726,65 @@ declare const ChalkApi_base: HttpApi.HttpApi<"ChalkApi", HttpApiGroup.HttpApiGro
1726
1726
  readonly code: import("effect/Schema").Literal<"tenant.invalid_id">;
1727
1727
  readonly message: import("effect/Schema").String;
1728
1728
  }>;
1729
+ }>, never, never>>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"reportConnectionFailure", "POST", "/v1/tenants/:tenant_id/connection-reports", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
1730
+ readonly tenant_id: import("effect/Schema").brand<import("effect/Schema").String, "TenantId">;
1731
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
1732
+ readonly events: import("effect/Schema").$Array<import("effect/Schema").Struct<{
1733
+ readonly attempt: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1734
+ readonly close_code: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1735
+ readonly code: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["invalid_state", "invalid_access", "access_unavailable", "permission_denied", "device_not_found", "device_busy", "device_constraint_invalid", "media_capture_failed", "sync_start_failed", "state_digest_recovery_failed", "sync_hello_timeout", "media_start_failed", "join_cleanup_unconfirmed", "sync_recovery_exhausted", "media_recovery_exhausted", "command_rejected", "leave_unconfirmed", "episode_ended", "unsupported_environment", "internal_error", "collaboration_unavailable", "chat_cursor_reset_required", "rate_limited", "invalid_payload"]>>;
1736
+ readonly duration_ms: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1737
+ readonly elapsed_ms: import("effect/Schema").Number;
1738
+ readonly event: import("effect/Schema").Literals<readonly ["space_join_span", "state_changed", "connection_failed", "sync_connect_failed", "sync_dial_timeout", "access_refreshed", "access_refresh_failed", "recovery_attempt", "recovery_succeeded", "recovery_exhausted", "cleanup_completed", "cleanup_unconfirmed", "sync_socket_open", "sync_socket_close", "sync_heartbeat_gap", "media_state", "media_http_error"]>;
1739
+ readonly heartbeat_gap_ms: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1740
+ readonly http_status: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Number>>;
1741
+ readonly outcome: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["started", "succeeded", "failed", "cancelled"]>>;
1742
+ readonly phase: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["idle", "connecting", "live", "recovering", "failed", "stopped", "new", "connected", "disconnected", "closed"]>>;
1743
+ readonly state: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["idle", "joining", "live", "reconnecting", "leaving", "left", "failed"]>>;
1744
+ readonly step: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["join", "acquire_initial_media", "access_initialize", "create_media_client", "create_sync_client", "start_media", "start_sync", "wait_for_sync_live", "confirm_entered"]>>;
1745
+ }>>;
1746
+ readonly trigger: import("effect/Schema").Literals<readonly ["join_failed", "connection_lost", "recovery_exhausted"]>;
1747
+ readonly version: import("effect/Schema").Literal<1>;
1748
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Void>, import("effect/Schema").toCodecJson<import("effect/Schema").decodeTo<typeof S.AccessForbiddenError, import("effect/Schema").Struct<{
1749
+ readonly error: import("effect/Schema").Struct<{
1750
+ readonly code: import("effect/Schema").Literal<"access.forbidden">;
1751
+ readonly message: import("effect/Schema").String;
1752
+ }>;
1753
+ }>, never, never> | import("effect/Schema").decodeTo<typeof S.AccessUnauthenticatedError, import("effect/Schema").Struct<{
1754
+ readonly error: import("effect/Schema").Struct<{
1755
+ readonly code: import("effect/Schema").Literal<"access.unauthenticated">;
1756
+ readonly message: import("effect/Schema").String;
1757
+ }>;
1758
+ }>, never, never> | import("effect/Schema").decodeTo<typeof S.RequestInvalidError, import("effect/Schema").Struct<{
1759
+ readonly error: import("effect/Schema").Struct<{
1760
+ readonly code: import("effect/Schema").Literal<"request.invalid">;
1761
+ readonly message: import("effect/Schema").String;
1762
+ }>;
1763
+ }>, never, never> | import("effect/Schema").decodeTo<typeof S.RequestPayloadTooLargeError, import("effect/Schema").Struct<{
1764
+ readonly error: import("effect/Schema").Struct<{
1765
+ readonly code: import("effect/Schema").Literal<"request.payload_too_large">;
1766
+ readonly message: import("effect/Schema").String;
1767
+ }>;
1768
+ }>, never, never> | import("effect/Schema").decodeTo<typeof S.RequestRateLimitedError, import("effect/Schema").Struct<{
1769
+ readonly error: import("effect/Schema").Struct<{
1770
+ readonly code: import("effect/Schema").Literal<"request.rate_limited">;
1771
+ readonly message: import("effect/Schema").String;
1772
+ }>;
1773
+ }>, never, never> | import("effect/Schema").decodeTo<typeof S.ServiceInternalError, import("effect/Schema").Struct<{
1774
+ readonly error: import("effect/Schema").Struct<{
1775
+ readonly code: import("effect/Schema").Literal<"service.internal_error">;
1776
+ readonly message: import("effect/Schema").String;
1777
+ }>;
1778
+ }>, never, never> | import("effect/Schema").decodeTo<typeof S.ServiceUnavailableError, import("effect/Schema").Struct<{
1779
+ readonly error: import("effect/Schema").Struct<{
1780
+ readonly code: import("effect/Schema").Literal<"service.unavailable">;
1781
+ readonly message: import("effect/Schema").String;
1782
+ }>;
1783
+ }>, never, never> | import("effect/Schema").decodeTo<typeof S.TenantInvalidIdError, import("effect/Schema").Struct<{
1784
+ readonly error: import("effect/Schema").Struct<{
1785
+ readonly code: import("effect/Schema").Literal<"tenant.invalid_id">;
1786
+ readonly message: import("effect/Schema").String;
1787
+ }>;
1729
1788
  }>, never, never>>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"revokeAPIKey", "DELETE", "/v1/tenants/:tenant_id/api-keys/:api_key_id", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
1730
1789
  readonly api_key_id: import("effect/Schema").brand<import("effect/Schema").String, "UUID">;
1731
1790
  readonly tenant_id: import("effect/Schema").brand<import("effect/Schema").String, "TenantId">;
@@ -219,6 +219,25 @@ export declare const CloudflareSFUTracksRequestSchema: Schema.Struct<{
219
219
  }>>;
220
220
  }>;
221
221
  export type CloudflareSFUTracksRequest = typeof CloudflareSFUTracksRequestSchema.Type;
222
+ export declare const ConnectionReportRequestSchema: Schema.Struct<{
223
+ readonly events: Schema.$Array<Schema.Struct<{
224
+ readonly attempt: Schema.optional<Schema.NullOr<Schema.Number>>;
225
+ readonly close_code: Schema.optional<Schema.NullOr<Schema.Number>>;
226
+ readonly code: Schema.optional<Schema.Literals<readonly ["invalid_state", "invalid_access", "access_unavailable", "permission_denied", "device_not_found", "device_busy", "device_constraint_invalid", "media_capture_failed", "sync_start_failed", "state_digest_recovery_failed", "sync_hello_timeout", "media_start_failed", "join_cleanup_unconfirmed", "sync_recovery_exhausted", "media_recovery_exhausted", "command_rejected", "leave_unconfirmed", "episode_ended", "unsupported_environment", "internal_error", "collaboration_unavailable", "chat_cursor_reset_required", "rate_limited", "invalid_payload"]>>;
227
+ readonly duration_ms: Schema.optional<Schema.NullOr<Schema.Number>>;
228
+ readonly elapsed_ms: Schema.Number;
229
+ readonly event: Schema.Literals<readonly ["space_join_span", "state_changed", "connection_failed", "sync_connect_failed", "sync_dial_timeout", "access_refreshed", "access_refresh_failed", "recovery_attempt", "recovery_succeeded", "recovery_exhausted", "cleanup_completed", "cleanup_unconfirmed", "sync_socket_open", "sync_socket_close", "sync_heartbeat_gap", "media_state", "media_http_error"]>;
230
+ readonly heartbeat_gap_ms: Schema.optional<Schema.NullOr<Schema.Number>>;
231
+ readonly http_status: Schema.optional<Schema.NullOr<Schema.Number>>;
232
+ readonly outcome: Schema.optional<Schema.Literals<readonly ["started", "succeeded", "failed", "cancelled"]>>;
233
+ readonly phase: Schema.optional<Schema.Literals<readonly ["idle", "connecting", "live", "recovering", "failed", "stopped", "new", "connected", "disconnected", "closed"]>>;
234
+ readonly state: Schema.optional<Schema.Literals<readonly ["idle", "joining", "live", "reconnecting", "leaving", "left", "failed"]>>;
235
+ readonly step: Schema.optional<Schema.Literals<readonly ["join", "acquire_initial_media", "access_initialize", "create_media_client", "create_sync_client", "start_media", "start_sync", "wait_for_sync_live", "confirm_entered"]>>;
236
+ }>>;
237
+ readonly trigger: Schema.Literals<readonly ["join_failed", "connection_lost", "recovery_exhausted"]>;
238
+ readonly version: Schema.Literal<1>;
239
+ }>;
240
+ export type ConnectionReportRequest = typeof ConnectionReportRequestSchema.Type;
222
241
  export declare const CreateAPIKeyRequestSchema: Schema.Struct<{
223
242
  readonly expires_at: Schema.brand<Schema.String, "DateTimeString">;
224
243
  readonly name: Schema.String;
@@ -3284,6 +3303,35 @@ export declare const RenegotiateCloudflareSFU429ResponseHeadersSchema: Schema.St
3284
3303
  readonly "X-RateLimit-Remaining": Schema.NumberFromString;
3285
3304
  }>;
3286
3305
  export type RenegotiateCloudflareSFU429ResponseHeaders = typeof RenegotiateCloudflareSFU429ResponseHeadersSchema.Type;
3306
+ export declare const ReportConnectionFailurePathParamsSchema: Schema.Struct<{
3307
+ readonly tenant_id: Schema.brand<Schema.String, "TenantId">;
3308
+ }>;
3309
+ export type ReportConnectionFailurePathParams = typeof ReportConnectionFailurePathParamsSchema.Type;
3310
+ export declare const ReportConnectionFailureRequestBodySchema: Schema.Struct<{
3311
+ readonly events: Schema.$Array<Schema.Struct<{
3312
+ readonly attempt: Schema.optional<Schema.NullOr<Schema.Number>>;
3313
+ readonly close_code: Schema.optional<Schema.NullOr<Schema.Number>>;
3314
+ readonly code: Schema.optional<Schema.Literals<readonly ["invalid_state", "invalid_access", "access_unavailable", "permission_denied", "device_not_found", "device_busy", "device_constraint_invalid", "media_capture_failed", "sync_start_failed", "state_digest_recovery_failed", "sync_hello_timeout", "media_start_failed", "join_cleanup_unconfirmed", "sync_recovery_exhausted", "media_recovery_exhausted", "command_rejected", "leave_unconfirmed", "episode_ended", "unsupported_environment", "internal_error", "collaboration_unavailable", "chat_cursor_reset_required", "rate_limited", "invalid_payload"]>>;
3315
+ readonly duration_ms: Schema.optional<Schema.NullOr<Schema.Number>>;
3316
+ readonly elapsed_ms: Schema.Number;
3317
+ readonly event: Schema.Literals<readonly ["space_join_span", "state_changed", "connection_failed", "sync_connect_failed", "sync_dial_timeout", "access_refreshed", "access_refresh_failed", "recovery_attempt", "recovery_succeeded", "recovery_exhausted", "cleanup_completed", "cleanup_unconfirmed", "sync_socket_open", "sync_socket_close", "sync_heartbeat_gap", "media_state", "media_http_error"]>;
3318
+ readonly heartbeat_gap_ms: Schema.optional<Schema.NullOr<Schema.Number>>;
3319
+ readonly http_status: Schema.optional<Schema.NullOr<Schema.Number>>;
3320
+ readonly outcome: Schema.optional<Schema.Literals<readonly ["started", "succeeded", "failed", "cancelled"]>>;
3321
+ readonly phase: Schema.optional<Schema.Literals<readonly ["idle", "connecting", "live", "recovering", "failed", "stopped", "new", "connected", "disconnected", "closed"]>>;
3322
+ readonly state: Schema.optional<Schema.Literals<readonly ["idle", "joining", "live", "reconnecting", "leaving", "left", "failed"]>>;
3323
+ readonly step: Schema.optional<Schema.Literals<readonly ["join", "acquire_initial_media", "access_initialize", "create_media_client", "create_sync_client", "start_media", "start_sync", "wait_for_sync_live", "confirm_entered"]>>;
3324
+ }>>;
3325
+ readonly trigger: Schema.Literals<readonly ["join_failed", "connection_lost", "recovery_exhausted"]>;
3326
+ readonly version: Schema.Literal<1>;
3327
+ }>;
3328
+ export type ReportConnectionFailureRequestBody = typeof ReportConnectionFailureRequestBodySchema.Type;
3329
+ export declare const ReportConnectionFailure429ResponseHeadersSchema: Schema.Struct<{
3330
+ readonly "Retry-After": Schema.NumberFromString;
3331
+ readonly "X-RateLimit-Limit": Schema.NumberFromString;
3332
+ readonly "X-RateLimit-Remaining": Schema.NumberFromString;
3333
+ }>;
3334
+ export type ReportConnectionFailure429ResponseHeaders = typeof ReportConnectionFailure429ResponseHeadersSchema.Type;
3287
3335
  export declare const RequestRecordingExportPathParamsSchema: Schema.Struct<{
3288
3336
  readonly recording_id: Schema.brand<Schema.String, "RecordingId">;
3289
3337
  readonly tenant_id: Schema.brand<Schema.String, "TenantId">;
@@ -9843,6 +9891,48 @@ export declare const RenegotiateCloudflareSFUErrorSchema: Schema.Union<readonly
9843
9891
  }>;
9844
9892
  }>, never, never>]>;
9845
9893
  export type RenegotiateCloudflareSFUError = typeof RenegotiateCloudflareSFUErrorSchema.Type;
9894
+ export declare const ReportConnectionFailureErrorSchema: Schema.Union<readonly [Schema.decodeTo<typeof AccessForbiddenError, Schema.Struct<{
9895
+ readonly error: Schema.Struct<{
9896
+ readonly code: Schema.Literal<"access.forbidden">;
9897
+ readonly message: Schema.String;
9898
+ }>;
9899
+ }>, never, never>, Schema.decodeTo<typeof AccessUnauthenticatedError, Schema.Struct<{
9900
+ readonly error: Schema.Struct<{
9901
+ readonly code: Schema.Literal<"access.unauthenticated">;
9902
+ readonly message: Schema.String;
9903
+ }>;
9904
+ }>, never, never>, Schema.decodeTo<typeof RequestInvalidError, Schema.Struct<{
9905
+ readonly error: Schema.Struct<{
9906
+ readonly code: Schema.Literal<"request.invalid">;
9907
+ readonly message: Schema.String;
9908
+ }>;
9909
+ }>, never, never>, Schema.decodeTo<typeof RequestPayloadTooLargeError, Schema.Struct<{
9910
+ readonly error: Schema.Struct<{
9911
+ readonly code: Schema.Literal<"request.payload_too_large">;
9912
+ readonly message: Schema.String;
9913
+ }>;
9914
+ }>, never, never>, Schema.decodeTo<typeof RequestRateLimitedError, Schema.Struct<{
9915
+ readonly error: Schema.Struct<{
9916
+ readonly code: Schema.Literal<"request.rate_limited">;
9917
+ readonly message: Schema.String;
9918
+ }>;
9919
+ }>, never, never>, Schema.decodeTo<typeof ServiceInternalError, Schema.Struct<{
9920
+ readonly error: Schema.Struct<{
9921
+ readonly code: Schema.Literal<"service.internal_error">;
9922
+ readonly message: Schema.String;
9923
+ }>;
9924
+ }>, never, never>, Schema.decodeTo<typeof ServiceUnavailableError, Schema.Struct<{
9925
+ readonly error: Schema.Struct<{
9926
+ readonly code: Schema.Literal<"service.unavailable">;
9927
+ readonly message: Schema.String;
9928
+ }>;
9929
+ }>, never, never>, Schema.decodeTo<typeof TenantInvalidIdError, Schema.Struct<{
9930
+ readonly error: Schema.Struct<{
9931
+ readonly code: Schema.Literal<"tenant.invalid_id">;
9932
+ readonly message: Schema.String;
9933
+ }>;
9934
+ }>, never, never>]>;
9935
+ export type ReportConnectionFailureError = typeof ReportConnectionFailureErrorSchema.Type;
9846
9936
  export declare const RequestRecordingExportErrorSchema: Schema.Union<readonly [Schema.decodeTo<typeof AccessForbiddenError, Schema.Struct<{
9847
9937
  readonly error: Schema.Struct<{
9848
9938
  readonly code: Schema.Literal<"access.forbidden">;
@@ -11346,6 +11436,14 @@ export declare const ChalkOperationPolicies: {
11346
11436
  readonly windowSeconds: 60;
11347
11437
  };
11348
11438
  };
11439
+ readonly reportConnectionFailure: {
11440
+ readonly maxBodyBytes: 32768;
11441
+ readonly rateLimit: {
11442
+ readonly limit: 6;
11443
+ readonly policy: "connection_reports.participant";
11444
+ readonly windowSeconds: 600;
11445
+ };
11446
+ };
11349
11447
  readonly requestRecordingExport: {
11350
11448
  readonly maxBodyBytes: 1048576;
11351
11449
  readonly rateLimit: {
@@ -37,7 +37,7 @@ export declare const SyncProtocolMetadata: {
37
37
  readonly accepts: readonly ["entered", "command", "live_target", "directed_request", "delivery_ack", "request_ack", "reaction_send", "chat_send", "chat_page_request", "chat_read_set", "chat_reaction_set", "ping"];
38
38
  readonly heartbeat: {
39
39
  readonly intervalMs: 20000;
40
- readonly missedDeadlinesBeforeClose: 2;
40
+ readonly missedDeadlinesBeforeClose: 5;
41
41
  };
42
42
  }, {
43
43
  readonly id: "terminal";
@@ -11,6 +11,7 @@ export declare const WhiteboardV1ProtocolMetadata: {
11
11
  readonly presentation: {
12
12
  readonly name: "presentation_v1";
13
13
  readonly exactFields: readonly ["name"];
14
+ readonly presenterExactFields: readonly ["name", "presenter"];
14
15
  };
15
16
  readonly view: {
16
17
  readonly name: "view_v1";
@@ -258,6 +259,7 @@ export type WhiteboardV1SharedAppState = {
258
259
  } | null;
259
260
  export type WhiteboardV1PresentationExtension = {
260
261
  readonly name: "presentation_v1";
262
+ readonly presenter?: true;
261
263
  };
262
264
  export type WhiteboardV1ViewExtension = {
263
265
  readonly name: "view_v1";
@@ -388,6 +390,7 @@ export type WhiteboardV1ServerFrame = {
388
390
  readonly revision: string;
389
391
  readonly can_draw: boolean;
390
392
  readonly presenting: boolean;
393
+ readonly presenter_id?: string | null;
391
394
  readonly view_owner_id?: string;
392
395
  } | {
393
396
  readonly type: "snapshot_page";
@@ -451,6 +454,7 @@ export type WhiteboardV1ServerFrame = {
451
454
  readonly scene_id: string;
452
455
  readonly revision: string;
453
456
  readonly presenting: boolean;
457
+ readonly presenter_id?: string | null;
454
458
  } | {
455
459
  readonly type: "reset_required";
456
460
  readonly scene_id: string;
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  createSpaceClient,
16
16
  decodeWhiteboardV1ServerFrame,
17
17
  encodeWhiteboardV1ClientFrame
18
- } from "./chunk-XPW3OCPO.js";
18
+ } from "./chunk-LDPC2JZB.js";
19
19
  import {
20
20
  CloudflareSFUClient,
21
21
  CloudflareSFUError,
@@ -28,19 +28,19 @@ import {
28
28
  requireSFUDescription,
29
29
  validatePublicationSnapshot,
30
30
  waitFor
31
- } from "./chunk-DWKTGBHR.js";
31
+ } from "./chunk-3ASKGMD3.js";
32
32
  import {
33
33
  createChalkPublicClient,
34
34
  createChalkPublicInviteClient,
35
35
  parseInviteCode
36
- } from "./chunk-6LNRDKJF.js";
36
+ } from "./chunk-SYUGRHZ5.js";
37
37
  import {
38
38
  ArrivalInvalidHandleError,
39
39
  ArrivalUnavailableError,
40
40
  SpacePublicInviteUnavailableError,
41
41
  parseParsedAccessGrant,
42
42
  requireAccessGrant
43
- } from "./chunk-GA3JDPFI.js";
43
+ } from "./chunk-AZONR3Q3.js";
44
44
  import {
45
45
  AsyncStorageV1PendingTargetStore,
46
46
  InMemoryV1PendingTargetStore,
@@ -69,7 +69,7 @@ import {
69
69
  optimisticV1Control,
70
70
  reactionFromFrame,
71
71
  restoreV1Snapshot
72
- } from "./chunk-AIJ5Z6HA.js";
72
+ } from "./chunk-5YPQNMJE.js";
73
73
 
74
74
  // src/space-client/reload-rejoin.ts
75
75
  import { Schema } from "effect";
@@ -123,7 +123,7 @@ var FAILURE_DETAILS = {
123
123
  "access.unavailable": "Couldn\u2019t get access to the call. Try again.",
124
124
  "connection.sync_start_failed": "Couldn\u2019t reach the call service. Try again.",
125
125
  "connection.sync_hello_timeout": "The call service did not respond in time. Try again.",
126
- "connection.sync_recovery_exhausted": "The call connection could not recover. Try again.",
126
+ "connection.sync_recovery_exhausted": "You\u2019re disconnected from the call. Rejoin to continue.",
127
127
  "connection.media_start_failed": "Audio and video could not connect. Try again.",
128
128
  "connection.media_recovery_exhausted": "Audio and video could not reconnect. Try again.",
129
129
  "environment.unsupported": "This device cannot start the call. Use an up-to-date browser over HTTPS, or update the app."
@@ -10,7 +10,7 @@ import {
10
10
  requireSFUDescription,
11
11
  validatePublicationSnapshot,
12
12
  waitFor
13
- } from "../chunk-DWKTGBHR.js";
13
+ } from "../chunk-3ASKGMD3.js";
14
14
  export {
15
15
  CloudflareSFUClient,
16
16
  CloudflareSFUError,
@@ -1,3 +1,4 @@
1
+ import type { ConnectionReportTransportEvent } from "../transport-diagnostics";
1
2
  import type { MediaPublication, MediaPublicationSource } from "./plane";
2
3
  export type CloudflareSFUBootstrap = {
3
4
  readonly connectionId: string;
@@ -108,6 +109,8 @@ export type CloudflareSFURestartOptions = {
108
109
  };
109
110
  export type CloudflareSFUCredentialProvider = (signal?: AbortSignal) => string | Promise<string>;
110
111
  export type CloudflareSFUHTTPTransportOptions = {
112
+ readonly traceparent?: string;
113
+ readonly onDiagnostic?: (event: ConnectionReportTransportEvent) => void;
111
114
  readonly apiBaseURL: string;
112
115
  readonly credential?: CloudflareSFUCredentialProvider;
113
116
  /** @deprecated Use credential so refreshed media access is read before every request. */
@@ -2,12 +2,12 @@ import {
2
2
  createChalkPublicClient,
3
3
  createChalkPublicInviteClient,
4
4
  parseInviteCode
5
- } from "../chunk-6LNRDKJF.js";
5
+ } from "../chunk-SYUGRHZ5.js";
6
6
  import {
7
7
  ArrivalInvalidHandleError,
8
8
  ArrivalUnavailableError,
9
9
  SpacePublicInviteUnavailableError
10
- } from "../chunk-GA3JDPFI.js";
10
+ } from "../chunk-AZONR3Q3.js";
11
11
  export {
12
12
  ArrivalInvalidHandleError,
13
13
  ArrivalUnavailableError,
@@ -203,6 +203,7 @@ export type WhiteboardSlice = {
203
203
  readonly sceneId: string | null;
204
204
  readonly revision: string | null;
205
205
  readonly presenting: boolean;
206
+ readonly presenterId?: string | null;
206
207
  readonly error: ChalkWhiteboardV1Failure | null;
207
208
  };
208
209
  /** Who can draw, as Sync last told this person. `canDraw` is false until the board subscription is live. */
@@ -1,3 +1,13 @@
1
+ /** Transport facts only. No URLs, close reasons, payloads, or identities. */
2
+ export type SyncRecoveryDiagnostic = {
3
+ readonly socketAttempts: number;
4
+ readonly socketCloses: readonly {
5
+ readonly code: number;
6
+ readonly wasClean: boolean | null;
7
+ }[];
8
+ readonly omittedSocketCloses: number;
9
+ readonly lastHeartbeatReplyAt: number | null;
10
+ };
1
11
  /** Browsers expose only upgrade/open and hello, never DNS/TCP/TLS progress. */
2
12
  export type SyncConnectDiagnostic = {
3
13
  readonly stage: "upgrade" | "hello";
@@ -22,7 +22,7 @@ import {
22
22
  encodeV1ClientFrame,
23
23
  optimisticV1Control,
24
24
  restoreV1Snapshot
25
- } from "../chunk-AIJ5Z6HA.js";
25
+ } from "../chunk-5YPQNMJE.js";
26
26
  export {
27
27
  AsyncStorageV1PendingTargetStore,
28
28
  InMemoryV1PendingTargetStore,
@@ -7,6 +7,7 @@ export type ReactNativeAsyncStorage = {
7
7
  export type ReactNativeWebSocketCloseEvent = {
8
8
  readonly code?: unknown;
9
9
  readonly reason?: unknown;
10
+ readonly wasClean?: unknown;
10
11
  };
11
12
  export type ReactNativeWebSocket = {
12
13
  onopen: ((event: unknown) => void) | null;
@@ -10,6 +10,7 @@ export type SyncSocket = {
10
10
  onclose: ((event: {
11
11
  readonly code: number;
12
12
  readonly reason?: string;
13
+ readonly wasClean?: boolean;
13
14
  }) => void) | null;
14
15
  onerror: (() => void) | null;
15
16
  send(data: string): void;
@@ -1,3 +1,4 @@
1
+ import type { ConnectionReportTransportEvent } from "../transport-diagnostics";
1
2
  import type { SetAdmissionPolicyCommandFrame, SyncV1ServerFrame } from "../generated/sync";
2
3
  import type { ClientMediaPlane, MediaPlaneOutcome, MediaPlaneResult, MediaPlaneTarget, MediaPublication, MediaSource } from "../media/plane";
3
4
  import type { ChalkChatReactionInput, ChalkChatReactions, ChalkChatMessage, ChalkChatPageResult, ChalkChatReadReceipt, ChalkReaction, ChalkReactionEvent, ChalkSendChatMessageInput, ChalkSyncV1CollaborationCapability } from "../collaboration/types";
@@ -81,6 +82,7 @@ export type V1EpisodeSnapshot = {
81
82
  readonly dialTimeoutCount?: number;
82
83
  readonly connectAttempt?: import("./connect-diagnostics").SyncConnectDiagnostic;
83
84
  readonly connectFailure?: import("./connect-diagnostics").SyncConnectDiagnostic;
85
+ readonly recoveryDiagnostic?: import("./connect-diagnostics").SyncRecoveryDiagnostic;
84
86
  };
85
87
  readonly participantId: string | null;
86
88
  readonly participantGeneration: number | null;
@@ -188,6 +190,8 @@ export type V1CollaborationClient = {
188
190
  }) => Promise<ChalkChatPageResult>;
189
191
  };
190
192
  export type V1SyncClientOptions = {
193
+ readonly traceparent?: string;
194
+ readonly onDiagnostic?: (event: ConnectionReportTransportEvent) => void;
191
195
  readonly url: string;
192
196
  readonly token: () => Promise<string>;
193
197
  readonly webSocket: SyncWebSocketFactory;
@@ -0,0 +1,3 @@
1
+ import type { components } from "./generated/openapi-types";
2
+ export type ConnectionReport = components["schemas"]["ConnectionReportRequest"];
3
+ export type ConnectionReportTransportEvent = Pick<ConnectionReport["events"][number], "event" | "phase" | "attempt" | "duration_ms" | "heartbeat_gap_ms" | "close_code" | "http_status">;