@q9labsai/chalk-client 5.2.0 → 5.2.2
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/chunk-6LNRDKJF.js +162 -0
- package/dist/{chunk-D2GXPX2P.js → chunk-AIJ5Z6HA.js} +42 -10
- package/dist/{chunk-HO4745TX.js → chunk-GA3JDPFI.js} +2 -0
- package/dist/{chunk-BCO3AZUB.js → chunk-XPW3OCPO.js} +130 -53
- package/dist/client.d.ts +4 -0
- package/dist/connection/index.d.ts +1 -0
- package/dist/effect.js +3 -3
- package/dist/generated/http-api.d.ts +4 -0
- package/dist/generated/schemas.d.ts +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +25 -5
- package/dist/public-invites/code.d.ts +1 -0
- package/dist/public-invites/index.d.ts +1 -0
- package/dist/public-invites/index.js +6 -4
- package/dist/public-invites/words.d.ts +2 -0
- package/dist/space-client/failure-detail.d.ts +6 -0
- package/dist/space-client/types.d.ts +2 -0
- package/dist/sync/connect-diagnostics.d.ts +6 -0
- package/dist/sync/index.js +1 -1
- package/dist/sync/v1-types.d.ts +4 -0
- package/package.json +1 -1
- package/dist/chunk-DHGAKJXP.js +0 -142
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createChalkEffectClient,
|
|
3
|
+
parseAccessGrant
|
|
4
|
+
} from "./chunk-GA3JDPFI.js";
|
|
5
|
+
|
|
6
|
+
// src/public-invites/client.ts
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
function createChalkPublicClient(options) {
|
|
9
|
+
const baseClientOptions = {
|
|
10
|
+
baseUrl: options.baseUrl,
|
|
11
|
+
credentials: options.credentials ?? (options.runtime === "react-native" ? void 0 : "include"),
|
|
12
|
+
fetch: options.fetch
|
|
13
|
+
};
|
|
14
|
+
const createClient = (guestCredential, requestInit) => createChalkEffectClient({
|
|
15
|
+
...baseClientOptions,
|
|
16
|
+
...requestInit ? { fetch: requestInitFetch(options.fetch, requestInit) } : {},
|
|
17
|
+
headers: requestHeaders(options, guestCredential)
|
|
18
|
+
});
|
|
19
|
+
const createPublicSpace = async (input, idempotency) => {
|
|
20
|
+
const client = await Effect.runPromise(createClient(void 0));
|
|
21
|
+
const response = await Effect.runPromise(
|
|
22
|
+
client.spaces.createPublicSpace({
|
|
23
|
+
headers: { "Idempotency-Key": idempotencyKey(idempotency) },
|
|
24
|
+
payload: { display_name: required(input.displayName, "displayName") }
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
return publicSpaceCreated(response);
|
|
28
|
+
};
|
|
29
|
+
const arriveBySpacePublicInvite = async (input, arrival) => {
|
|
30
|
+
const client = await Effect.runPromise(createClient(arrival?.guestCredential ?? options.guestCredential));
|
|
31
|
+
const response = await Effect.runPromise(
|
|
32
|
+
client.spaces.arriveBySpacePublicInvite({
|
|
33
|
+
headers: {
|
|
34
|
+
"Idempotency-Key": idempotencyKey(arrival),
|
|
35
|
+
...arrival?.arrivalHandle === void 0 ? {} : { "X-Chalk-Arrival-Handle": required(arrival.arrivalHandle, "arrivalHandle") }
|
|
36
|
+
},
|
|
37
|
+
payload: {
|
|
38
|
+
display_name: required(input.displayName, "displayName"),
|
|
39
|
+
space_invite_token: required(input.spaceInviteToken, "spaceInviteToken")
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
return publicSpaceArrival(response);
|
|
44
|
+
};
|
|
45
|
+
const getSpacePublicInviteArrival = async (reference) => {
|
|
46
|
+
const normalized = arrivalReference(reference);
|
|
47
|
+
const client = await Effect.runPromise(createClient(normalized.guestCredential ?? options.guestCredential));
|
|
48
|
+
const response = await Effect.runPromise(
|
|
49
|
+
client.spaces.getSpacePublicInviteArrival({
|
|
50
|
+
headers: { "X-Chalk-Arrival-Handle": normalized.arrivalHandle }
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
return publicSpaceArrival(response);
|
|
54
|
+
};
|
|
55
|
+
const refreshSpacePublicInviteAccess = async (input, arrival) => {
|
|
56
|
+
const normalized = refreshInput(input, arrival);
|
|
57
|
+
const client = await Effect.runPromise(createClient(normalized.guestCredential ?? options.guestCredential, normalized.signal ? { signal: normalized.signal } : void 0));
|
|
58
|
+
const response = await Effect.runPromise(
|
|
59
|
+
client.spaces.refreshSpacePublicInviteAccess({
|
|
60
|
+
headers: { "X-Chalk-Arrival-Handle": normalized.arrivalHandle },
|
|
61
|
+
payload: { media_proof: required(normalized.mediaProof, "mediaProof"), replace_media_connection: normalized.replaceMediaConnection ?? false }
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
return parseAccessGrant(response);
|
|
65
|
+
};
|
|
66
|
+
const leaveSpacePublicInviteArrival = async (reference, leaveOptions) => {
|
|
67
|
+
const normalized = arrivalReference(reference);
|
|
68
|
+
const client = await Effect.runPromise(createClient(normalized.guestCredential ?? options.guestCredential, requestInitForLeave(leaveOptions)));
|
|
69
|
+
await Effect.runPromise(
|
|
70
|
+
client.spaces.leaveSpacePublicInviteArrival({
|
|
71
|
+
headers: { "X-Chalk-Arrival-Handle": normalized.arrivalHandle }
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
prepareSpaceEntrance: async (spaceInviteToken) => {
|
|
77
|
+
const client = await Effect.runPromise(createClient(void 0));
|
|
78
|
+
await Effect.runPromise(client.spaces.preparePublicSpaceEntrance({ payload: { space_invite_token: required(spaceInviteToken, "spaceInviteToken") } }));
|
|
79
|
+
},
|
|
80
|
+
arrive: arriveBySpacePublicInvite,
|
|
81
|
+
arriveBySpacePublicInvite,
|
|
82
|
+
create: createPublicSpace,
|
|
83
|
+
createPublicSpace,
|
|
84
|
+
getSpacePublicInviteArrival,
|
|
85
|
+
leave: leaveSpacePublicInviteArrival,
|
|
86
|
+
leaveSpacePublicInviteArrival,
|
|
87
|
+
refresh: refreshSpacePublicInviteAccess,
|
|
88
|
+
refreshSpacePublicInviteAccess,
|
|
89
|
+
status: getSpacePublicInviteArrival
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
var createChalkPublicInviteClient = createChalkPublicClient;
|
|
93
|
+
function requestHeaders(options, guestCredential) {
|
|
94
|
+
const headers = { ...options.headers };
|
|
95
|
+
if (options.runtime === "react-native") {
|
|
96
|
+
headers["X-Chalk-Client"] = "react-native";
|
|
97
|
+
const credential = guestCredential ?? options.guestCredential;
|
|
98
|
+
if (credential !== void 0) headers.Authorization = `ChalkGuest ${required(credential, "guestCredential")}`;
|
|
99
|
+
}
|
|
100
|
+
return headers;
|
|
101
|
+
}
|
|
102
|
+
function idempotencyKey(options) {
|
|
103
|
+
return options?.idempotencyKey === void 0 ? globalThis.crypto.randomUUID() : required(options.idempotencyKey, "idempotencyKey");
|
|
104
|
+
}
|
|
105
|
+
function arrivalReference(reference) {
|
|
106
|
+
if (typeof reference === "string") return { arrivalHandle: required(reference, "arrivalHandle") };
|
|
107
|
+
return { arrivalHandle: required(reference.arrivalHandle, "arrivalHandle"), guestCredential: reference.guestCredential };
|
|
108
|
+
}
|
|
109
|
+
function refreshInput(input, arrival) {
|
|
110
|
+
const values = typeof input === "string" ? { arrivalHandle: arrival?.arrivalHandle, guestCredential: arrival?.guestCredential, mediaProof: input } : { arrivalHandle: input.arrivalHandle ?? arrival?.arrivalHandle, guestCredential: input.guestCredential ?? arrival?.guestCredential, mediaProof: input.mediaProof, replaceMediaConnection: input.replaceMediaConnection, signal: input.signal };
|
|
111
|
+
return {
|
|
112
|
+
...values,
|
|
113
|
+
arrivalHandle: required(values.arrivalHandle ?? "", "arrivalHandle")
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function requestInitForLeave(options) {
|
|
117
|
+
if (options?.keepalive === void 0) return void 0;
|
|
118
|
+
return { keepalive: options.keepalive };
|
|
119
|
+
}
|
|
120
|
+
function requestInitFetch(fetchImplementation, requestInit) {
|
|
121
|
+
const implementation = fetchImplementation ?? globalThis.fetch;
|
|
122
|
+
return (input, init) => implementation(input, { ...init, ...requestInit });
|
|
123
|
+
}
|
|
124
|
+
function publicSpaceCreated(value) {
|
|
125
|
+
const { arrival, ...created } = value;
|
|
126
|
+
return { ...created, arrival: publicSpaceArrival(arrival) };
|
|
127
|
+
}
|
|
128
|
+
function publicSpaceArrival(value) {
|
|
129
|
+
const { access, ...arrival } = value;
|
|
130
|
+
if (access === void 0) return arrival;
|
|
131
|
+
return { ...arrival, access: access === null ? null : parseAccessGrant(access) };
|
|
132
|
+
}
|
|
133
|
+
function required(value, name) {
|
|
134
|
+
const normalized = value.trim();
|
|
135
|
+
if (!normalized) throw new TypeError(`${name} is required`);
|
|
136
|
+
return normalized;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/public-invites/words.ts
|
|
140
|
+
var INVITE_WORD_COUNT = 4;
|
|
141
|
+
var INVITE_WORDS = new Set(
|
|
142
|
+
"abacus able accent acorn acoustic acre acrobat active actor adore aerial agenda agent agile ahead aim airport album alike alive almond aloe aloha alone alpaca alto alumni amber amend ample amuse anchor angle animal anthem antique anvil apple april apron aqua arcade arctic area arena arise aroma array art artist aspire astute atlas atom attach attain attic audio autumn avenue avocado awake award awning bacon badge bagel baked baker bakery bamboo banana banjo banner barge barn basil basket batch baton beacon beetle blank blanket blaze blend blink blog blossom bluebird boat bobcat bolt bonsai bonus book booth boots boss botany both bottle boulder bounce bowler branch breeze brick bright brim bring brisk broil bronze brook broom brush bubble bucket budget buffalo builder bulb bulk bunch bundle bunny busy butter button buzz cabana cable cactus cake calm cameo camera camper campus canal canary candle candy canopy canyon cape captain carbon card cargo carrot carry cartoon case castle catalog cedar celery chair charm cheer cheese chef cherry chess chief chill chip chunk churn cinema circle circus citrus city civic civil claim clamp clap clasp class clay clean clear clever click cling clip cloak clock clone closet cloth cloud clover clump coach coast coat cobalt cocoa coconut coffee coil cola cold colony comfy comic compass concert condor cone cookie cope copper copy coral cork corner cosmic cost cotton couch cover craft crane crate crave crawl crayon create cricket crisp crop crowd crown crumb crust crystal cub cube cupcake curl curry cursor curve cut cycle daffodil daily daisy dance dash date dawn deal debug decaf deck decor delta deluxe denim depth desk device dial diary dice dig dime diner dinner disco dish dock doing doll dolphin domain dome donut dot down dragon dragonfly drama draw drawing dress dried drift drill drive drizzle drove drum dry duck duke duo dusk dust duty eagle early earth easel east echo eclipse edge editor eel effort elder elf elk elm email ember emblem emboss emerald encore energy engine enrich enter entry equal equator eraser errand even evolve exact exit expert fable fabric fact factory falcon fall fame family fancy feast feather feed fence fern ferry fetch fiber fiddle figure film filter final finale finch firefly fit five flag flame flap flick flight flip float flock flower foam fog foil folk font food forest fossil found fountain fox frame fresh fridge friend from front frost fruit gala galaxy game gap garage garden garlic gave gazebo gear gecko gem gerbil giant gift gig ginger giraffe glacier glad glass glide glitter glory gloss glove glow glue goal going golden golf good gown grab grain granite grant grape graph grasp grass gravy green greet grew grid grill grip groom groove guide guitar gulf gummy gush habit half hamster happy harvest hatch haven hazel hazy heap heat hedge helium helmet help heron hickory holiday honey horizon hub hula hull human humid hurry hut ice iceberg icing icon igloo image insect iron island item ivory ivy jacket jaguar jam jasmine jazz jelly jersey jet jigsaw job jog jolly jolt journal joy judge juice juicy july jumbo jump jungle keep kettle kilt king kite kitten kiwi koala ladder lady lagoon lake lamp land lantern laptop large latch laurel lavender leaflet legend lemon length lens leopard letter lettuce level lever library lid life lift lilac lily limit line linen lint lion liquid list little lively lizard lobster locket lotus luggage lumber lunar lunch lyric magnet maker mango manor many map maple marble marine market mascot mash match math meadow melon mercury meteor mitten mocha monkey mop mosaic motor motto mount mouse move movie mud muffin mug mural muse museum mushroom music nacho nail name nap napkin nature neat nectar neon nest net next nickel noodle nugget nutmeg nylon oak oasis oat oatmeal ocean octagon octopus oil olive onion opal open opera orchid origami otter outdoor outer oval oven owl oxygen oyster ozone pace packet pager palace palm panda panther pantry pants papaya paper parade parcel park parrot parsley party pasta pastel patch path patio pebble pecan pelican pencil penguin penny pepper perch petal photo picnic pigeon pillow plank plant plaza plenty pluck plug plus pod poem poet point polar polka polo pond pony poppy portal poster pouch pound power press print prism prize proof pug pull pulp pulse puma pupil puppet puppy purse push puzzle quiet quilt quota quote race rack radar radio radish raft rail rake rally ramp ranch range ranger rank raven reach react recap relax relay relic remix repay reply rerun reset rhyme ribbon rice rich ride rinse ripple rise river robe robin rock rocket rope rover royal ruby rug rule rush safari sage salad salon salsa salt sample sandy satin say scale scan scarf scoop scoot scope score scout scrap screen script scrub scuba scuff sedan send serve seven shack shade shaky shape shed sheep shelf shell shine shiny ship shirt shop shore sift silk silly silver simple single sip size skate sketch skid skip skirt sky slab slack slate sled sleek sleep slice slick sling slip slush small smile snack snap snowy speak speed spend spent spill spiny spoke sponge spool spoon sport spot spout spray spring sprint sprout spruce spur squad squid stack staff stage stall stamp stand staple start state statue steam steep stem step stereo stew stick sting stir stock stool stop storm stove straw stream street strut stuck studio stuff stump stunt subway sugar surf sushi swan sway sweep swell swim swing swipe swirl swoop syrup tablet taco tag take tall task taste tasty thaw theme think thread thumb tiara tidal tidy tiger tile tilt tint tiny trace track trade train travel tray treat tree trek trend trial trick trio trophy trout truck trunk try tug tulip turf turtle tutor tweak tweet twice twins twirl twist uncle undo unify unit untie update upper urban user valley value velvet venue verify verse vest video view violet vista vocal voice volt vowel voyage wafer wagon wake walk walnut wand watch water wavy wheat whoop widen width willow wing wink wipe wise wish wizard wok wolf wool word work woven yam yard year yelp yield yoga yogurt yummy zebra zero zesty zippy zone zoom".split(
|
|
143
|
+
" "
|
|
144
|
+
)
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
// src/public-invites/code.ts
|
|
148
|
+
var INVITE_CODE_PATTERN = /^(?:[a-z]{10}|[a-z]{3}-[a-z]{4}-[a-z]{3})$/;
|
|
149
|
+
function parseInviteCode(value) {
|
|
150
|
+
const normalized = value.trim().toLowerCase();
|
|
151
|
+
const words = normalized.split(/[-.\s]+/u);
|
|
152
|
+
if (words.length === INVITE_WORD_COUNT && words.every((word) => INVITE_WORDS.has(word))) return words.join("-");
|
|
153
|
+
if (!INVITE_CODE_PATTERN.test(normalized)) return void 0;
|
|
154
|
+
const code = normalized.replaceAll("-", "");
|
|
155
|
+
return `${code.slice(0, 3)}-${code.slice(3, 7)}-${code.slice(7)}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
createChalkPublicClient,
|
|
160
|
+
createChalkPublicInviteClient,
|
|
161
|
+
parseInviteCode
|
|
162
|
+
};
|
|
@@ -154,7 +154,9 @@ function createReactNativeWebSocketFactory(WebSocketConstructor) {
|
|
|
154
154
|
function createReactNativeSyncLifecycle(environment) {
|
|
155
155
|
return {
|
|
156
156
|
subscribe(listener) {
|
|
157
|
-
const appState = environment.appState.addEventListener("change", (state) =>
|
|
157
|
+
const appState = environment.appState.addEventListener("change", (state) => {
|
|
158
|
+
if (state !== "inactive") listener(state === "active" ? "active" : "inactive");
|
|
159
|
+
});
|
|
158
160
|
const network = environment.networkInfo?.addEventListener((state) => listener(isNetworkOnline(state) ? "online" : "offline"));
|
|
159
161
|
listener(environment.appState.currentState === "active" ? "active" : "inactive");
|
|
160
162
|
return () => {
|
|
@@ -247,8 +249,11 @@ var SAFE_REASONS = /* @__PURE__ */ new Set([
|
|
|
247
249
|
function safeSyncCloseReason(reason) {
|
|
248
250
|
return reason ? SAFE_REASONS.has(reason) ? reason : "redacted" : null;
|
|
249
251
|
}
|
|
252
|
+
function syncConnectFailureCode(diagnostic) {
|
|
253
|
+
return diagnostic?.stage === "upgrade" ? "sync_start_failed" : "sync_hello_timeout";
|
|
254
|
+
}
|
|
250
255
|
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]`;
|
|
256
|
+
return `[${diagnostic.stage}; open=${diagnostic.opened ? 1 : 0}; close=${diagnostic.closeCode ?? "none"}; reason=${safeSyncCloseReason(diagnostic.closeReason ?? void 0) ?? "none"}; ${diagnostic.stage === "upgrade" && diagnostic.closeCode !== null ? "cause=closed_before_open; " : ""}${diagnostic.attempt === void 0 ? "" : `attempt=${diagnostic.attempt}; `}${diagnostic.attempts === void 0 ? "" : `attempts=${diagnostic.attempts}; `}${Math.round(diagnostic.durationMs)}ms]`;
|
|
252
257
|
}
|
|
253
258
|
|
|
254
259
|
// src/sync/v1-health.ts
|
|
@@ -1956,7 +1961,7 @@ function reduceEvent(state, event) {
|
|
|
1956
1961
|
case "episode_started":
|
|
1957
1962
|
return state;
|
|
1958
1963
|
case "episode_ended":
|
|
1959
|
-
return { ...state, status: "ended", participants: [], admissionRequests: [], recording: null };
|
|
1964
|
+
return { ...state, status: "ended", endReason: event.payload.reason, participants: [], admissionRequests: [], recording: null };
|
|
1960
1965
|
case "hand_raised":
|
|
1961
1966
|
case "hand_lowered":
|
|
1962
1967
|
return updateParticipant(state, event.payload.participant_id, (participant) => ({ ...participant, handRaised: event.name === "hand_raised" }));
|
|
@@ -3022,12 +3027,14 @@ var V1SyncClient = class {
|
|
|
3022
3027
|
#cancelDial;
|
|
3023
3028
|
#dialTimeoutCount = 0;
|
|
3024
3029
|
#connectStartedAt = null;
|
|
3030
|
+
#connectAttemptCount = 0;
|
|
3025
3031
|
#opened = false;
|
|
3026
3032
|
#connectFailure;
|
|
3027
3033
|
#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())) };
|
|
3034
|
+
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())), attempt: this.#connectAttemptCount };
|
|
3029
3035
|
}
|
|
3030
3036
|
#reconnectAttempt = 0;
|
|
3037
|
+
#episodeEndTimer;
|
|
3031
3038
|
#heartbeatTimer;
|
|
3032
3039
|
#missedHeartbeats = 0;
|
|
3033
3040
|
#noticeTimer;
|
|
@@ -3087,6 +3094,8 @@ var V1SyncClient = class {
|
|
|
3087
3094
|
async start() {
|
|
3088
3095
|
if (this.#started) return;
|
|
3089
3096
|
this.#started = true;
|
|
3097
|
+
this.#connectAttemptCount = 0;
|
|
3098
|
+
this.#connectFailure = void 0;
|
|
3090
3099
|
const startupGeneration = ++this.#startupGeneration;
|
|
3091
3100
|
let stored;
|
|
3092
3101
|
try {
|
|
@@ -3112,6 +3121,8 @@ var V1SyncClient = class {
|
|
|
3112
3121
|
this.#unsubscribeLifecycle = void 0;
|
|
3113
3122
|
this.#clearReconnect();
|
|
3114
3123
|
this.#clearDial();
|
|
3124
|
+
this.#clock().clearTimeout(this.#episodeEndTimer);
|
|
3125
|
+
this.#episodeEndTimer = void 0;
|
|
3115
3126
|
this.#clearHeartbeat();
|
|
3116
3127
|
this.#clearNoticeProbe();
|
|
3117
3128
|
this.#commandScheduler.stop("client_stopped");
|
|
@@ -3283,9 +3294,10 @@ var V1SyncClient = class {
|
|
|
3283
3294
|
#connect() {
|
|
3284
3295
|
if (!this.#started || !this.#transportAvailable || this.#socket || this.#phase.phase === "terminal") return;
|
|
3285
3296
|
this.#phase = { phase: "connecting" };
|
|
3297
|
+
this.#connectAttemptCount += 1;
|
|
3286
3298
|
this.#connectStartedAt = this.#clock().now();
|
|
3287
3299
|
this.#opened = false;
|
|
3288
|
-
this.#connectFailure = void 0;
|
|
3300
|
+
if (this.#connectFailure?.opened) this.#connectFailure = void 0;
|
|
3289
3301
|
this.#emit();
|
|
3290
3302
|
this.#entryNegotiated = false;
|
|
3291
3303
|
let socket;
|
|
@@ -3294,7 +3306,7 @@ var V1SyncClient = class {
|
|
|
3294
3306
|
} catch {
|
|
3295
3307
|
this.#connectFailure = this.#connectDiagnostic();
|
|
3296
3308
|
this.#emit();
|
|
3297
|
-
throw new V1SyncError("Sync WebSocket could not be created", "
|
|
3309
|
+
throw new V1SyncError("Sync WebSocket could not be created", "sync_start_failed");
|
|
3298
3310
|
}
|
|
3299
3311
|
const connectionGeneration = ++this.#connectionGeneration;
|
|
3300
3312
|
this.#socket = socket;
|
|
@@ -3336,7 +3348,7 @@ var V1SyncClient = class {
|
|
|
3336
3348
|
};
|
|
3337
3349
|
socket.onerror = () => {
|
|
3338
3350
|
if (socket === this.#socket && (this.#phase.phase === "connecting" || this.#phase.phase === "recovering")) {
|
|
3339
|
-
this.#connectFailure
|
|
3351
|
+
this.#connectFailure ??= this.#connectDiagnostic();
|
|
3340
3352
|
this.#emit();
|
|
3341
3353
|
}
|
|
3342
3354
|
socket.close(CLIENT_RESTART_CLOSE_CODE, "transport error");
|
|
@@ -3423,6 +3435,19 @@ var V1SyncClient = class {
|
|
|
3423
3435
|
case "ack":
|
|
3424
3436
|
this.#requireLive();
|
|
3425
3437
|
await this.#commandScheduler.acknowledge(frame);
|
|
3438
|
+
if (frame.outcome === "rejected" && frame.reason === "episode_ended") {
|
|
3439
|
+
if (this.#episodeEndTimer === void 0) {
|
|
3440
|
+
this.#episodeEndTimer = this.#clock().setTimeout(() => {
|
|
3441
|
+
this.#episodeEndTimer = void 0;
|
|
3442
|
+
if (this.#control?.status === "ended" || this.#phase.phase === "terminal") return;
|
|
3443
|
+
this.#phase = { phase: "terminal", terminalReason: "episode_ended" };
|
|
3444
|
+
this.#clearReconnect();
|
|
3445
|
+
this.#socket?.close(1e3, "episode ended");
|
|
3446
|
+
this.#emit();
|
|
3447
|
+
}, 5e3);
|
|
3448
|
+
}
|
|
3449
|
+
this.#recover("episode ended");
|
|
3450
|
+
}
|
|
3426
3451
|
return;
|
|
3427
3452
|
case "retryable_error":
|
|
3428
3453
|
this.#requireLive();
|
|
@@ -3652,9 +3677,10 @@ var V1SyncClient = class {
|
|
|
3652
3677
|
this.#presence = null;
|
|
3653
3678
|
this.#rejectRequests("disconnected_before_delivery");
|
|
3654
3679
|
this.#collaborationState.disconnect("disconnected_before_delivery");
|
|
3655
|
-
if (!this.#started ||
|
|
3680
|
+
if (!this.#started || this.#phase.phase === "terminal") return;
|
|
3656
3681
|
this.#phase = { phase: "connecting" };
|
|
3657
3682
|
this.#emit();
|
|
3683
|
+
if (!this.#transportAvailable) return;
|
|
3658
3684
|
this.#clearReconnect();
|
|
3659
3685
|
const configuredDelay = this.#options.reconnectDelayMs;
|
|
3660
3686
|
const exponentialAttempt = configuredDelay === void 0 ? Math.max(0, this.#reconnectAttempt - FAST_RECONNECT_ATTEMPTS + 1) : this.#reconnectAttempt;
|
|
@@ -3699,8 +3725,13 @@ var V1SyncClient = class {
|
|
|
3699
3725
|
if (event === "online" || event === "offline") this.#online = event === "online";
|
|
3700
3726
|
else this.#active = event === "active";
|
|
3701
3727
|
this.#transportAvailable = this.#online && this.#active;
|
|
3702
|
-
if (!this.#transportAvailable)
|
|
3703
|
-
|
|
3728
|
+
if (!this.#transportAvailable) {
|
|
3729
|
+
const socket = this.#socket;
|
|
3730
|
+
if (socket) {
|
|
3731
|
+
socket.close(CLIENT_RESTART_CLOSE_CODE, "lifecycle unavailable");
|
|
3732
|
+
this.#disconnected(socket);
|
|
3733
|
+
}
|
|
3734
|
+
} else this.#connect();
|
|
3704
3735
|
}
|
|
3705
3736
|
#rejectEphemeral(code) {
|
|
3706
3737
|
this.#rejectRequests(code);
|
|
@@ -4022,6 +4053,7 @@ function createV1SyncClient(options) {
|
|
|
4022
4053
|
}
|
|
4023
4054
|
|
|
4024
4055
|
export {
|
|
4056
|
+
syncConnectFailureCode,
|
|
4025
4057
|
formatSyncConnectDiagnostic,
|
|
4026
4058
|
UuidSchema,
|
|
4027
4059
|
ReactionValues,
|
|
@@ -532,6 +532,7 @@ var PublicSpaceArrivalSchema = Schema.Struct({
|
|
|
532
532
|
Schema.NullOr(
|
|
533
533
|
Schema.Struct({
|
|
534
534
|
admission_mode: Schema.String,
|
|
535
|
+
maximum_episode_duration_seconds: Schema.optional(Schema.Number),
|
|
535
536
|
name: Schema.String,
|
|
536
537
|
slug: Schema.String
|
|
537
538
|
})
|
|
@@ -546,6 +547,7 @@ var PublicSpaceCreatedSchema = Schema.Struct({
|
|
|
546
547
|
lifecycle_until: DateTimeStringSchema,
|
|
547
548
|
space: Schema.Struct({
|
|
548
549
|
admission_mode: Schema.String,
|
|
550
|
+
maximum_episode_duration_seconds: Schema.optional(Schema.Number),
|
|
549
551
|
name: Schema.String,
|
|
550
552
|
slug: Schema.String
|
|
551
553
|
})
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
AccessGrantError,
|
|
8
8
|
requireParsedAccessGrant
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GA3JDPFI.js";
|
|
10
10
|
import {
|
|
11
11
|
ChatAttachmentMimeTypeSchema,
|
|
12
12
|
ChatReactionSetFrameSchema,
|
|
@@ -18,8 +18,9 @@ import {
|
|
|
18
18
|
createBrowserWebSocketFactory,
|
|
19
19
|
createV1SyncClient,
|
|
20
20
|
formatSyncConnectDiagnostic,
|
|
21
|
-
scheduleSyncDialDeadline
|
|
22
|
-
|
|
21
|
+
scheduleSyncDialDeadline,
|
|
22
|
+
syncConnectFailureCode
|
|
23
|
+
} from "./chunk-AIJ5Z6HA.js";
|
|
23
24
|
|
|
24
25
|
// src/access/manager.ts
|
|
25
26
|
import { Clock, Context, Data, Effect, Layer, SynchronizedRef } from "effect";
|
|
@@ -2551,7 +2552,7 @@ var ConnectionDiagnostics = class {
|
|
|
2551
2552
|
|
|
2552
2553
|
// src/connection/lifecycle.ts
|
|
2553
2554
|
var MEDIA_RECOVERY_TIMEOUT_MS = 6e4;
|
|
2554
|
-
var START_TIMEOUT_MS =
|
|
2555
|
+
var START_TIMEOUT_MS = 3e4;
|
|
2555
2556
|
var LEAVE_TIMEOUT_MS = 5e3;
|
|
2556
2557
|
var RECOVERY_BUDGET_MS = 1e4;
|
|
2557
2558
|
var MAX_RECOVERY_ATTEMPTS = 3;
|
|
@@ -2621,6 +2622,7 @@ var makeConnectionLifecycleLayerFromServices = (options) => Layer3.effect(
|
|
|
2621
2622
|
initialMediaIntent: null,
|
|
2622
2623
|
intent: { microphone: options.initialMicrophoneEnabled ?? true, camera: options.initialCameraEnabled ?? true },
|
|
2623
2624
|
episodeEndConfirmed: false,
|
|
2625
|
+
episodeEndReason: void 0,
|
|
2624
2626
|
removedByHost: false,
|
|
2625
2627
|
activeScope: null,
|
|
2626
2628
|
syncBindingCleanup: null,
|
|
@@ -2767,7 +2769,7 @@ var makeConnectionLifecycleLayerFromServices = (options) => Layer3.effect(
|
|
|
2767
2769
|
const failure2 = snapshot.connection.connectFailure;
|
|
2768
2770
|
if (failure2 && failure2 !== observedConnectFailure) {
|
|
2769
2771
|
observedConnectFailure = failure2;
|
|
2770
|
-
diagnostics.record({ event: "sync_connect_failed", state: model.state, epoch: model.epoch, code:
|
|
2772
|
+
diagnostics.record({ event: "sync_connect_failed", state: model.state, epoch: model.epoch, code: syncConnectFailureCode(failure2), sync: failure2 });
|
|
2771
2773
|
}
|
|
2772
2774
|
const count = snapshot.connection.dialTimeoutCount ?? 0;
|
|
2773
2775
|
if (count > observedDialTimeouts) {
|
|
@@ -2843,7 +2845,7 @@ var makeConnectionLifecycleLayerFromServices = (options) => Layer3.effect(
|
|
|
2843
2845
|
const span = diagnostics.startSpan({ step, state: model.state, epoch: model.epoch });
|
|
2844
2846
|
return effect.pipe(
|
|
2845
2847
|
Effect2.tap(() => Effect2.sync(() => span.end({ state: model.state, epoch: model.epoch, outcome: "succeeded" }))),
|
|
2846
|
-
Effect2.tapError(() => Effect2.sync(() => span.end({ state: model.state, epoch: model.epoch, outcome: "failed" })))
|
|
2848
|
+
Effect2.tapError((cause) => Effect2.sync(() => span.end({ state: model.state, epoch: model.epoch, outcome: "failed", code: failureFromCause(cause, "internal_error", "Connection step failed").code })))
|
|
2847
2849
|
);
|
|
2848
2850
|
};
|
|
2849
2851
|
const confirmSyncEntry = (sync) => {
|
|
@@ -2856,6 +2858,7 @@ var makeConnectionLifecycleLayerFromServices = (options) => Layer3.effect(
|
|
|
2856
2858
|
model.epoch += 1;
|
|
2857
2859
|
model.failure = null;
|
|
2858
2860
|
model.episodeEndConfirmed = false;
|
|
2861
|
+
model.episodeEndReason = void 0;
|
|
2859
2862
|
model.removedByHost = false;
|
|
2860
2863
|
yield* transition("joining");
|
|
2861
2864
|
const span = diagnostics.startSpan({ step: "join", state: model.state, epoch: model.epoch });
|
|
@@ -2919,7 +2922,7 @@ var makeConnectionLifecycleLayerFromServices = (options) => Layer3.effect(
|
|
|
2919
2922
|
Effect2.matchEffect({
|
|
2920
2923
|
onFailure: (cause) => Effect2.gen(function* () {
|
|
2921
2924
|
stopStream(stream);
|
|
2922
|
-
const failure2 = failureFromCause(cause, "
|
|
2925
|
+
const failure2 = failureFromCause(cause, "internal_error", "The Connection could not start");
|
|
2923
2926
|
model.failure = toFailure(failure2);
|
|
2924
2927
|
if (model.joinCancelled) {
|
|
2925
2928
|
span.end({ state: model.state, epoch: model.epoch, outcome: "cancelled", code: "invalid_state" });
|
|
@@ -3265,7 +3268,10 @@ var makeConnectionLifecycleLayerFromServices = (options) => Layer3.effect(
|
|
|
3265
3268
|
const ended = episodeEnded(snapshot);
|
|
3266
3269
|
const removed = snapshot.connection.terminalReason === "participant_removed";
|
|
3267
3270
|
if (ended || removed || snapshot.connection.terminalReason === "participant_inactive") {
|
|
3268
|
-
if (ended)
|
|
3271
|
+
if (ended) {
|
|
3272
|
+
model.episodeEndConfirmed = true;
|
|
3273
|
+
model.episodeEndReason = snapshot.control?.endReason;
|
|
3274
|
+
}
|
|
3269
3275
|
if (removed) model.removedByHost = true;
|
|
3270
3276
|
yield* finishTerminalSnapshot();
|
|
3271
3277
|
return true;
|
|
@@ -3454,6 +3460,7 @@ function snapshotFor(model, access) {
|
|
|
3454
3460
|
connection: Object.freeze({ syncHealth: model.syncSnapshot?.connection.health, sync: model.syncSnapshot?.connection.phase === "live" && model.syncNoticeUnresponsive ? "unresponsive" : syncPhase(model.syncSnapshot?.connection.phase), media: mediaPhase(model.mediaSnapshot?.connection.phase) }),
|
|
3455
3461
|
failure: model.failure ? Object.freeze({ ...model.failure }) : null,
|
|
3456
3462
|
episodeEnded: model.episodeEndConfirmed,
|
|
3463
|
+
episodeEndReason: model.episodeEndReason,
|
|
3457
3464
|
removedByHost: model.removedByHost
|
|
3458
3465
|
});
|
|
3459
3466
|
}
|
|
@@ -3578,9 +3585,11 @@ function syncTerminalFailure(snapshot) {
|
|
|
3578
3585
|
return lifecycleFailure("sync_start_failed", true, "The Sync transport needs recovery");
|
|
3579
3586
|
}
|
|
3580
3587
|
function syncStartupFailure(snapshot) {
|
|
3581
|
-
const
|
|
3588
|
+
const evidence = snapshot.connection.connectFailure ?? snapshot.connection.connectAttempt;
|
|
3589
|
+
const attempts = snapshot.connection.connectAttempt?.attempt;
|
|
3590
|
+
const sync = evidence ? { ...evidence, ...attempts === void 0 ? {} : { attempts } } : void 0;
|
|
3582
3591
|
const message = sync?.opened === false ? "Sync could not reach the call service" : "Sync could not connect";
|
|
3583
|
-
return new ConnectionLifecycleFailure({ code:
|
|
3592
|
+
return new ConnectionLifecycleFailure({ code: syncConnectFailureCode(sync), recoverable: true, message: `${message}${sync ? ` ${formatSyncConnectDiagnostic(sync)}` : " before the startup deadline"}`, ...sync ? { sync: Object.freeze({ ...sync }) } : {} });
|
|
3584
3593
|
}
|
|
3585
3594
|
function syncAutoRecoverable(snapshot, failure2) {
|
|
3586
3595
|
return failure2.recoverable && snapshot.connection.terminalReason !== "entry_timeout";
|
|
@@ -3625,6 +3634,7 @@ var INVALID_PAYLOAD_CODE_BY_ACTION = /* @__PURE__ */ new Map([
|
|
|
3625
3634
|
]);
|
|
3626
3635
|
var MEDIA_TIMEOUT_FAILURE = { code: "media.timeout", recoverable: true, message: "Media did not respond in time. Try again." };
|
|
3627
3636
|
var SYNC_FAILURES = /* @__PURE__ */ new Map([
|
|
3637
|
+
["sync_start_failed", { failure: { code: "connection.sync_start_failed", recoverable: true, message: "A connection to the call service could not be opened. Try again." } }],
|
|
3628
3638
|
["sync_hello_timeout", { failure: { code: "connection.sync_hello_timeout", recoverable: true, message: "Sync could not reach the call service. Try again." } }],
|
|
3629
3639
|
["not_live", { failure: { code: "connection.invalid_state", recoverable: true, message: "Wait for the call to connect, then try again." } }],
|
|
3630
3640
|
["signaling_timeout", { failure: MEDIA_TIMEOUT_FAILURE }],
|
|
@@ -3732,6 +3742,7 @@ var SpaceStore = class _SpaceStore {
|
|
|
3732
3742
|
episode: snapshot.episode,
|
|
3733
3743
|
lastError: sameError(current.lastError, error2) ? current.lastError : error2,
|
|
3734
3744
|
episodeEnded: snapshot.episodeEnded ?? false,
|
|
3745
|
+
episodeEndReason: snapshot.episodeEndReason,
|
|
3735
3746
|
removedByHost: snapshot.removedByHost ?? false
|
|
3736
3747
|
};
|
|
3737
3748
|
if (sameConnection(current, next)) return;
|
|
@@ -3790,7 +3801,7 @@ function connectionStatus(snapshot) {
|
|
|
3790
3801
|
return snapshot.state === "live" && interrupted ? "reconnecting" : snapshot.state;
|
|
3791
3802
|
}
|
|
3792
3803
|
function sameConnection(left, right) {
|
|
3793
|
-
return left.status === right.status && left.syncHealth === right.syncHealth && sameEpisode(left.episode, right.episode) && left.lastError === right.lastError && left.episodeEnded === right.episodeEnded && left.removedByHost === right.removedByHost;
|
|
3804
|
+
return left.status === right.status && left.syncHealth === right.syncHealth && sameEpisode(left.episode, right.episode) && left.lastError === right.lastError && left.episodeEnded === right.episodeEnded && left.episodeEndReason === right.episodeEndReason && left.removedByHost === right.removedByHost;
|
|
3794
3805
|
}
|
|
3795
3806
|
function sameEpisode(left, right) {
|
|
3796
3807
|
if (left === right) return true;
|
|
@@ -4348,6 +4359,7 @@ function chatError(message) {
|
|
|
4348
4359
|
// src/space-client/media-controller.ts
|
|
4349
4360
|
import { Clock as Clock3, Context as Context6, Deferred as Deferred2, Effect as Effect5, Exit as Exit2, Layer as Layer6, Semaphore } from "effect";
|
|
4350
4361
|
var MEDIA_SOURCES = ["microphone", "camera", "screen"];
|
|
4362
|
+
var MEDIA_READY_TIMEOUT_MS = 1e4;
|
|
4351
4363
|
function sourceWorker(enabled) {
|
|
4352
4364
|
return { desired: { enabled, revision: 0, previousEnabled: enabled }, result: { revision: 0, status: "confirmed" }, sentRevision: 0, initialRevision: 0, localEnabled: enabled, pause: null, serverSequence: -1, forcedRevision: null };
|
|
4353
4365
|
}
|
|
@@ -4392,8 +4404,9 @@ var MediaControllerRuntime = class {
|
|
|
4392
4404
|
#tracks = /* @__PURE__ */ new Map();
|
|
4393
4405
|
#sources = { microphone: sourceWorker(true), camera: sourceWorker(true), screen: sourceWorker(false) };
|
|
4394
4406
|
#syncLive = false;
|
|
4395
|
-
#pendingSources = /* @__PURE__ */ new
|
|
4407
|
+
#pendingSources = /* @__PURE__ */ new Map();
|
|
4396
4408
|
#pendingCaptures = /* @__PURE__ */ new Set();
|
|
4409
|
+
#readinessChecks = /* @__PURE__ */ new Set();
|
|
4397
4410
|
#requestGenerations = /* @__PURE__ */ new Map();
|
|
4398
4411
|
#camera = { status: "idle" };
|
|
4399
4412
|
#requests = Object.freeze([]);
|
|
@@ -4421,8 +4434,8 @@ var MediaControllerRuntime = class {
|
|
|
4421
4434
|
if (intent.microphone !== void 0) this.#recordIntent("microphone", intent.microphone);
|
|
4422
4435
|
if (intent.camera !== void 0) this.#recordIntent("camera", intent.camera);
|
|
4423
4436
|
}
|
|
4424
|
-
setMicrophoneEnabled = (enabled) => this.#
|
|
4425
|
-
setCameraEnabled = (enabled) => this.#
|
|
4437
|
+
setMicrophoneEnabled = (enabled) => this.#set("microphone", enabled);
|
|
4438
|
+
setCameraEnabled = (enabled) => this.#set("camera", enabled);
|
|
4426
4439
|
captureCameraPreview = () => this.#cameraSource("preview").pipe(Effect5.mapError(normalizeMediaError));
|
|
4427
4440
|
setScreenShareEnabled = (enabled, options) => enabled ? this.#mediaAction(true, this.#startScreen(options)) : this.#stopScreen();
|
|
4428
4441
|
selectMicrophone = (deviceId) => Effect5.sync(() => {
|
|
@@ -4516,6 +4529,7 @@ var MediaControllerRuntime = class {
|
|
|
4516
4529
|
this.#fork(this.#refreshDevices().pipe(Effect5.ignore));
|
|
4517
4530
|
}
|
|
4518
4531
|
dispose() {
|
|
4532
|
+
for (const check of this.#readinessChecks) check(normalizeMediaError(cancelledCaptureError()));
|
|
4519
4533
|
this.#cancelCaptures();
|
|
4520
4534
|
for (const unsubscribe of [this.#unsubscribeMedia, this.#unsubscribeRequests, this.#unsubscribePause, this.#unsubscribeSync]) unsubscribe?.();
|
|
4521
4535
|
this.#unsubscribeConnection?.();
|
|
@@ -4540,8 +4554,37 @@ var MediaControllerRuntime = class {
|
|
|
4540
4554
|
#mediaAction(enabling, operation) {
|
|
4541
4555
|
return Effect5.suspend(() => !enabling || this.#store.getSnapshot().connection.status === "live" ? operation : Effect5.fail(normalizeMediaError(new V1SyncError("Media enable requires a live call", "not_live"))));
|
|
4542
4556
|
}
|
|
4557
|
+
#waitForLive(source, revision, ports) {
|
|
4558
|
+
return Effect5.suspend(() => {
|
|
4559
|
+
let cleanup = () => {
|
|
4560
|
+
};
|
|
4561
|
+
return Effect5.callback((resume) => {
|
|
4562
|
+
const check = (failure2) => {
|
|
4563
|
+
if (failure2) return resume(Effect5.fail(failure2));
|
|
4564
|
+
if (this.#sources[source].desired.revision !== revision) return resume(Effect5.void);
|
|
4565
|
+
if (ports && (this.#ports?.sync !== ports.sync || this.#ports.media !== ports.media)) return resume(Effect5.fail(normalizeMediaError(cancelledCaptureError())));
|
|
4566
|
+
const state = this.#connection.getSnapshot().state;
|
|
4567
|
+
if (state === "live" && this.#ports?.sync.getSnapshot().connection.phase === "live" && this.#store.getSnapshot().connection.status === "live") return resume(Effect5.void);
|
|
4568
|
+
if (state !== "joining" && state !== "reconnecting" && state !== "live") resume(Effect5.fail(normalizeMediaError(new V1SyncError("Media enable requires a live call", "not_live"))));
|
|
4569
|
+
};
|
|
4570
|
+
this.#readinessChecks.add(check);
|
|
4571
|
+
const unsubscribe = this.#connection.subscribe(() => check());
|
|
4572
|
+
const unsubscribeStore = this.#store.subscribe(() => check());
|
|
4573
|
+
const unsubscribePorts = this.#connection.subscribePorts(() => check());
|
|
4574
|
+
const timer = this.#connection.scheduleUnsafe(() => check(new SpaceClientError({ code: "media.timeout", recoverable: true, message: "The call did not connect in time. Try again." })), MEDIA_READY_TIMEOUT_MS);
|
|
4575
|
+
cleanup = () => {
|
|
4576
|
+
this.#readinessChecks.delete(check);
|
|
4577
|
+
unsubscribe();
|
|
4578
|
+
unsubscribeStore();
|
|
4579
|
+
unsubscribePorts();
|
|
4580
|
+
this.#connection.cancelScheduleUnsafe(timer);
|
|
4581
|
+
};
|
|
4582
|
+
check();
|
|
4583
|
+
}).pipe(Effect5.ensuring(Effect5.sync(() => cleanup())));
|
|
4584
|
+
});
|
|
4585
|
+
}
|
|
4543
4586
|
#set(source, enabled) {
|
|
4544
|
-
return this.#act(source, enabled);
|
|
4587
|
+
return Effect5.suspend(() => this.#store.getSnapshot().connection.status === "joining" ? this.#act(source, enabled) : this.#mediaAction(enabled, this.#act(source, enabled)));
|
|
4545
4588
|
}
|
|
4546
4589
|
#startScreen(options) {
|
|
4547
4590
|
return this.#act("screen", true, options);
|
|
@@ -4576,19 +4619,41 @@ var MediaControllerRuntime = class {
|
|
|
4576
4619
|
void state.pause.catch(() => void 0);
|
|
4577
4620
|
}
|
|
4578
4621
|
}
|
|
4622
|
+
for (const check of this.#readinessChecks) check();
|
|
4579
4623
|
return desired;
|
|
4580
4624
|
}
|
|
4581
4625
|
#act(source, enabled, options) {
|
|
4582
4626
|
return Effect5.suspend(() => {
|
|
4583
4627
|
const desired = this.#recordIntent(source, enabled, options);
|
|
4584
|
-
|
|
4585
|
-
Effect5.
|
|
4586
|
-
Effect5.
|
|
4587
|
-
if (
|
|
4588
|
-
|
|
4589
|
-
|
|
4628
|
+
const ready = enabled && source !== "screen" && this.#store.getSnapshot().connection.status !== "live" ? this.#waitForLive(source, desired.revision).pipe(
|
|
4629
|
+
Effect5.tapError(
|
|
4630
|
+
(cause) => Effect5.sync(() => {
|
|
4631
|
+
if (this.#sources[source].desired.revision === desired.revision) {
|
|
4632
|
+
const cancelled = this.#recordIntent(source, false);
|
|
4633
|
+
this.#sources[source].result = { revision: cancelled.revision, status: "failed", cause, cleanup: false };
|
|
4634
|
+
}
|
|
4590
4635
|
})
|
|
4591
4636
|
)
|
|
4637
|
+
) : Effect5.void;
|
|
4638
|
+
return this.#pending(
|
|
4639
|
+
source,
|
|
4640
|
+
ready.pipe(
|
|
4641
|
+
Effect5.andThen(
|
|
4642
|
+
Effect5.suspend(() => {
|
|
4643
|
+
if (this.#sources[source].desired.revision !== desired.revision) return Effect5.void;
|
|
4644
|
+
return this.#serialize(source, this.#work(source)).pipe(
|
|
4645
|
+
Effect5.andThen(
|
|
4646
|
+
Effect5.suspend(() => {
|
|
4647
|
+
const result = this.#sources[source].result;
|
|
4648
|
+
if (result.revision === desired.revision && result.status === "failed") return Effect5.fail(result.cause);
|
|
4649
|
+
if (enabled && (source === "screen" || this.#sources[source].desired.enabled) && this.#store.getSnapshot().connection.status !== "live") return this.#mediaAction(true, Effect5.void);
|
|
4650
|
+
return Effect5.void;
|
|
4651
|
+
})
|
|
4652
|
+
)
|
|
4653
|
+
);
|
|
4654
|
+
})
|
|
4655
|
+
)
|
|
4656
|
+
)
|
|
4592
4657
|
);
|
|
4593
4658
|
}).pipe(Effect5.mapError(normalizeMediaError));
|
|
4594
4659
|
}
|
|
@@ -4663,18 +4728,24 @@ var MediaControllerRuntime = class {
|
|
|
4663
4728
|
return source === "camera" && !intent.previousEnabled || !this.#hasTrack(source) ? this.#captureForPublish(
|
|
4664
4729
|
source,
|
|
4665
4730
|
ports.media,
|
|
4666
|
-
(track) => Effect5.
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4731
|
+
(track) => Effect5.sync(() => {
|
|
4732
|
+
captured = track;
|
|
4733
|
+
}).pipe(
|
|
4734
|
+
Effect5.andThen(this.#waitForLive(source, intent.revision, ports)),
|
|
4735
|
+
Effect5.andThen(
|
|
4736
|
+
Effect5.try({
|
|
4737
|
+
try: () => {
|
|
4738
|
+
this.#assertActivePorts(ports, action);
|
|
4739
|
+
this.#assertCurrentIntent(source, intent.revision);
|
|
4740
|
+
this.#setTrack(source, track);
|
|
4741
|
+
ports.media.prepareLocalTrack(source, track);
|
|
4742
|
+
prepared = true;
|
|
4743
|
+
this.#publish();
|
|
4744
|
+
},
|
|
4745
|
+
catch: (cause) => cause
|
|
4746
|
+
})
|
|
4747
|
+
)
|
|
4748
|
+
)
|
|
4678
4749
|
) : Effect5.void;
|
|
4679
4750
|
});
|
|
4680
4751
|
return retire.pipe(Effect5.andThen(acquire), Effect5.andThen(this.#send(ports, source, intent, true)));
|
|
@@ -4790,7 +4861,7 @@ var MediaControllerRuntime = class {
|
|
|
4790
4861
|
return this.#serialize("microphone", this.#serialize("camera", publish));
|
|
4791
4862
|
}
|
|
4792
4863
|
#send(ports, source, intent, enabled) {
|
|
4793
|
-
|
|
4864
|
+
const command = this.#mediaAction(
|
|
4794
4865
|
enabled,
|
|
4795
4866
|
foreign2(async () => {
|
|
4796
4867
|
this.#assertCurrentIntent(source, intent.revision);
|
|
@@ -4798,9 +4869,12 @@ var MediaControllerRuntime = class {
|
|
|
4798
4869
|
const state = this.#sources[source];
|
|
4799
4870
|
state.sentRevision = intent.revision;
|
|
4800
4871
|
await (source === "microphone" ? ports.sync.setMicrophoneEnabled(enabled) : source === "camera" ? ports.sync.setCameraEnabled(enabled) : ports.sync.setScreenShareEnabled(enabled));
|
|
4801
|
-
|
|
4802
|
-
|
|
4872
|
+
}).pipe(
|
|
4873
|
+
Effect5.andThen(enabled && source !== "screen" ? this.#waitForLive(source, intent.revision, ports) : Effect5.void),
|
|
4874
|
+
Effect5.tap(() => Effect5.try({ try: () => this.#assertActivePorts(ports, source === "screen" ? "startScreenShare" : source === "camera" ? "setCameraEnabled" : "setMicrophoneEnabled"), catch: (cause) => cause }))
|
|
4875
|
+
)
|
|
4803
4876
|
);
|
|
4877
|
+
return enabled && source !== "screen" ? this.#waitForLive(source, intent.revision, ports).pipe(Effect5.andThen(command)) : command;
|
|
4804
4878
|
}
|
|
4805
4879
|
#reconcileIntents() {
|
|
4806
4880
|
const live = this.#connection.getSnapshot().state === "live" && this.#ports?.sync.getSnapshot().connection.phase === "live";
|
|
@@ -4825,18 +4899,21 @@ var MediaControllerRuntime = class {
|
|
|
4825
4899
|
return pause;
|
|
4826
4900
|
}
|
|
4827
4901
|
#serialize(source, effect) {
|
|
4828
|
-
return this.#gates.get(source).withPermit(
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4902
|
+
return this.#gates.get(source).withPermit(this.#pending(source, effect));
|
|
4903
|
+
}
|
|
4904
|
+
#pending(source, effect) {
|
|
4905
|
+
return Effect5.sync(() => {
|
|
4906
|
+
this.#pendingSources.set(source, (this.#pendingSources.get(source) ?? 0) + 1);
|
|
4907
|
+
this.#publish();
|
|
4908
|
+
}).pipe(
|
|
4909
|
+
Effect5.andThen(effect),
|
|
4910
|
+
Effect5.ensuring(
|
|
4911
|
+
Effect5.sync(() => {
|
|
4912
|
+
const remaining = this.#pendingSources.get(source) - 1;
|
|
4913
|
+
if (remaining === 0) this.#pendingSources.delete(source);
|
|
4914
|
+
else this.#pendingSources.set(source, remaining);
|
|
4915
|
+
this.#publish();
|
|
4916
|
+
})
|
|
4840
4917
|
)
|
|
4841
4918
|
);
|
|
4842
4919
|
}
|
|
@@ -5279,9 +5356,9 @@ var MediaControllerRuntime = class {
|
|
|
5279
5356
|
const snapshot = this.#ports?.media.getSnapshot();
|
|
5280
5357
|
const state = this.#connection.getSnapshot().state;
|
|
5281
5358
|
const local = Object.freeze({
|
|
5282
|
-
microphone: localMedia("microphone", this.#localTracks(), snapshot, this.#sources.microphone.localEnabled, state, this.#pendingSources.has("microphone")),
|
|
5283
|
-
camera: localMedia("camera", this.#localTracks(), snapshot, this.#sources.camera.localEnabled, state, this.#pendingSources.has("camera")),
|
|
5284
|
-
screen: localMedia("screen", this.#localTracks(), snapshot, false, state, this.#pendingSources.has("screen"))
|
|
5359
|
+
microphone: localMedia("microphone", this.#localTracks(), snapshot, this.#sources.microphone.localEnabled, state, this.#pendingSources.has("microphone") && this.#sources.microphone.desired.enabled),
|
|
5360
|
+
camera: localMedia("camera", this.#localTracks(), snapshot, this.#sources.camera.localEnabled, state, this.#pendingSources.has("camera") && this.#sources.camera.desired.enabled),
|
|
5361
|
+
screen: localMedia("screen", this.#localTracks(), snapshot, false, state, this.#pendingSources.has("screen") && this.#sources.screen.desired.enabled)
|
|
5285
5362
|
});
|
|
5286
5363
|
const remote = Object.freeze((snapshot?.remoteTracks ?? []).map((track) => Object.freeze({ participantId: track.participantId, source: track.source, publicationId: track.publicationId, track: track.track })));
|
|
5287
5364
|
const media = Object.freeze({
|
|
@@ -5335,8 +5412,8 @@ function initialTrackEntries(microphone, camera) {
|
|
|
5335
5412
|
function localMedia(source, tracks, snapshot, intended, connectionState, pending) {
|
|
5336
5413
|
const track = tracks.get(source) ?? null;
|
|
5337
5414
|
const publication = snapshot?.localTracks.find((candidate) => candidate.source === source);
|
|
5338
|
-
if (locallyMuted(intended, track, publication)) return Object.freeze({ source, state: "disabled", track });
|
|
5339
5415
|
if (pending) return Object.freeze({ source, state: "requesting", track });
|
|
5416
|
+
if (locallyMuted(intended, track, publication)) return Object.freeze({ source, state: "disabled", track });
|
|
5340
5417
|
if (publication?.enabled) return Object.freeze({ source, state: "enabled", track });
|
|
5341
5418
|
if (publication && connectionState === "live") return Object.freeze({ source, state: "disabled", track });
|
|
5342
5419
|
return Object.freeze({ source, state: localMediaState(source, track, intended, connectionState), track });
|
|
@@ -6338,7 +6415,7 @@ var SpaceClientCore = class {
|
|
|
6338
6415
|
this.#store.updateConnection(snapshot);
|
|
6339
6416
|
const newlyEnded = snapshot.episodeEnded && !this.#episodeEnded;
|
|
6340
6417
|
this.#episodeEnded = snapshot.episodeEnded ?? false;
|
|
6341
|
-
if (newlyEnded) this.#emit("episodeEnded", { episode });
|
|
6418
|
+
if (newlyEnded) this.#emit("episodeEnded", { episode, reason: snapshot.episodeEndReason });
|
|
6342
6419
|
});
|
|
6343
6420
|
}
|
|
6344
6421
|
getSnapshot = () => this.#store.getSnapshot();
|
package/dist/client.d.ts
CHANGED
|
@@ -4063,6 +4063,7 @@ export declare const createChalkEffectClient: (options: ChalkEffectClientOptions
|
|
|
4063
4063
|
readonly retry_after: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4064
4064
|
readonly space: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Struct<{
|
|
4065
4065
|
readonly admission_mode: import("effect/Schema").String;
|
|
4066
|
+
readonly maximum_episode_duration_seconds: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4066
4067
|
readonly name: import("effect/Schema").String;
|
|
4067
4068
|
readonly slug: import("effect/Schema").String;
|
|
4068
4069
|
}>>>;
|
|
@@ -4236,6 +4237,7 @@ export declare const createChalkEffectClient: (options: ChalkEffectClientOptions
|
|
|
4236
4237
|
readonly retry_after: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4237
4238
|
readonly space: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Struct<{
|
|
4238
4239
|
readonly admission_mode: import("effect/Schema").String;
|
|
4240
|
+
readonly maximum_episode_duration_seconds: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4239
4241
|
readonly name: import("effect/Schema").String;
|
|
4240
4242
|
readonly slug: import("effect/Schema").String;
|
|
4241
4243
|
}>>>;
|
|
@@ -4246,6 +4248,7 @@ export declare const createChalkEffectClient: (options: ChalkEffectClientOptions
|
|
|
4246
4248
|
readonly lifecycle_until: import("effect/Schema").brand<import("effect/Schema").String, "DateTimeString">;
|
|
4247
4249
|
readonly space: import("effect/Schema").Struct<{
|
|
4248
4250
|
readonly admission_mode: import("effect/Schema").String;
|
|
4251
|
+
readonly maximum_episode_duration_seconds: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4249
4252
|
readonly name: import("effect/Schema").String;
|
|
4250
4253
|
readonly slug: import("effect/Schema").String;
|
|
4251
4254
|
}>;
|
|
@@ -4665,6 +4668,7 @@ export declare const createChalkEffectClient: (options: ChalkEffectClientOptions
|
|
|
4665
4668
|
readonly retry_after: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4666
4669
|
readonly space: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Struct<{
|
|
4667
4670
|
readonly admission_mode: import("effect/Schema").String;
|
|
4671
|
+
readonly maximum_episode_duration_seconds: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4668
4672
|
readonly name: import("effect/Schema").String;
|
|
4669
4673
|
readonly slug: import("effect/Schema").String;
|
|
4670
4674
|
}>>>;
|
|
@@ -18,6 +18,7 @@ export type ConnectionLifecycleSnapshot = {
|
|
|
18
18
|
};
|
|
19
19
|
readonly failure: ConnectionFailure | null;
|
|
20
20
|
readonly episodeEnded?: boolean;
|
|
21
|
+
readonly episodeEndReason?: import("../sync/v1-types").V1ControlState["endReason"];
|
|
21
22
|
readonly removedByHost?: boolean;
|
|
22
23
|
};
|
|
23
24
|
export type ConnectionPorts = {
|
package/dist/effect.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
makeSpaceClientCoreLayer,
|
|
18
18
|
makeSpaceClientCoreLayerFromServices,
|
|
19
19
|
makeSpaceStoreLayer
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-XPW3OCPO.js";
|
|
21
21
|
import "./chunk-DWKTGBHR.js";
|
|
22
22
|
import {
|
|
23
23
|
APIKeyListSchema,
|
|
@@ -828,8 +828,8 @@ import {
|
|
|
828
828
|
WhiteboardStorageUnavailableErrorSchema,
|
|
829
829
|
WhiteboardStorageUnavailableErrorWireSchema,
|
|
830
830
|
createChalkEffectClient
|
|
831
|
-
} from "./chunk-
|
|
832
|
-
import "./chunk-
|
|
831
|
+
} from "./chunk-GA3JDPFI.js";
|
|
832
|
+
import "./chunk-AIJ5Z6HA.js";
|
|
833
833
|
|
|
834
834
|
// src/space-client/effect.ts
|
|
835
835
|
import { Context, Effect, Exit, Layer, Scope } from "effect";
|
|
@@ -3994,6 +3994,7 @@ declare const ChalkApi_base: HttpApi.HttpApi<"ChalkApi", HttpApiGroup.HttpApiGro
|
|
|
3994
3994
|
readonly retry_after: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
3995
3995
|
readonly space: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Struct<{
|
|
3996
3996
|
readonly admission_mode: import("effect/Schema").String;
|
|
3997
|
+
readonly maximum_episode_duration_seconds: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
3997
3998
|
readonly name: import("effect/Schema").String;
|
|
3998
3999
|
readonly slug: import("effect/Schema").String;
|
|
3999
4000
|
}>>>;
|
|
@@ -4165,6 +4166,7 @@ declare const ChalkApi_base: HttpApi.HttpApi<"ChalkApi", HttpApiGroup.HttpApiGro
|
|
|
4165
4166
|
readonly retry_after: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4166
4167
|
readonly space: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Struct<{
|
|
4167
4168
|
readonly admission_mode: import("effect/Schema").String;
|
|
4169
|
+
readonly maximum_episode_duration_seconds: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4168
4170
|
readonly name: import("effect/Schema").String;
|
|
4169
4171
|
readonly slug: import("effect/Schema").String;
|
|
4170
4172
|
}>>>;
|
|
@@ -4175,6 +4177,7 @@ declare const ChalkApi_base: HttpApi.HttpApi<"ChalkApi", HttpApiGroup.HttpApiGro
|
|
|
4175
4177
|
readonly lifecycle_until: import("effect/Schema").brand<import("effect/Schema").String, "DateTimeString">;
|
|
4176
4178
|
readonly space: import("effect/Schema").Struct<{
|
|
4177
4179
|
readonly admission_mode: import("effect/Schema").String;
|
|
4180
|
+
readonly maximum_episode_duration_seconds: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4178
4181
|
readonly name: import("effect/Schema").String;
|
|
4179
4182
|
readonly slug: import("effect/Schema").String;
|
|
4180
4183
|
}>;
|
|
@@ -4589,6 +4592,7 @@ declare const ChalkApi_base: HttpApi.HttpApi<"ChalkApi", HttpApiGroup.HttpApiGro
|
|
|
4589
4592
|
readonly retry_after: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4590
4593
|
readonly space: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").Struct<{
|
|
4591
4594
|
readonly admission_mode: import("effect/Schema").String;
|
|
4595
|
+
readonly maximum_episode_duration_seconds: import("effect/Schema").optional<import("effect/Schema").Number>;
|
|
4592
4596
|
readonly name: import("effect/Schema").String;
|
|
4593
4597
|
readonly slug: import("effect/Schema").String;
|
|
4594
4598
|
}>>>;
|
|
@@ -608,6 +608,7 @@ export declare const PublicSpaceArrivalSchema: Schema.Struct<{
|
|
|
608
608
|
readonly retry_after: Schema.optional<Schema.Number>;
|
|
609
609
|
readonly space: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
610
610
|
readonly admission_mode: Schema.String;
|
|
611
|
+
readonly maximum_episode_duration_seconds: Schema.optional<Schema.Number>;
|
|
611
612
|
readonly name: Schema.String;
|
|
612
613
|
readonly slug: Schema.String;
|
|
613
614
|
}>>>;
|
|
@@ -642,6 +643,7 @@ export declare const PublicSpaceCreatedSchema: Schema.Struct<{
|
|
|
642
643
|
readonly retry_after: Schema.optional<Schema.Number>;
|
|
643
644
|
readonly space: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
644
645
|
readonly admission_mode: Schema.String;
|
|
646
|
+
readonly maximum_episode_duration_seconds: Schema.optional<Schema.Number>;
|
|
645
647
|
readonly name: Schema.String;
|
|
646
648
|
readonly slug: Schema.String;
|
|
647
649
|
}>>>;
|
|
@@ -652,6 +654,7 @@ export declare const PublicSpaceCreatedSchema: Schema.Struct<{
|
|
|
652
654
|
readonly lifecycle_until: Schema.brand<Schema.String, "DateTimeString">;
|
|
653
655
|
readonly space: Schema.Struct<{
|
|
654
656
|
readonly admission_mode: Schema.String;
|
|
657
|
+
readonly maximum_episode_duration_seconds: Schema.optional<Schema.Number>;
|
|
655
658
|
readonly name: Schema.String;
|
|
656
659
|
readonly slug: Schema.String;
|
|
657
660
|
}>;
|
|
@@ -1558,6 +1561,7 @@ export declare const ArriveBySpacePublicInviteResponseSchema: Schema.Struct<{
|
|
|
1558
1561
|
readonly retry_after: Schema.optional<Schema.Number>;
|
|
1559
1562
|
readonly space: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
1560
1563
|
readonly admission_mode: Schema.String;
|
|
1564
|
+
readonly maximum_episode_duration_seconds: Schema.optional<Schema.Number>;
|
|
1561
1565
|
readonly name: Schema.String;
|
|
1562
1566
|
readonly slug: Schema.String;
|
|
1563
1567
|
}>>>;
|
|
@@ -1790,6 +1794,7 @@ export declare const CreatePublicSpaceResponseSchema: Schema.Struct<{
|
|
|
1790
1794
|
readonly retry_after: Schema.optional<Schema.Number>;
|
|
1791
1795
|
readonly space: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
1792
1796
|
readonly admission_mode: Schema.String;
|
|
1797
|
+
readonly maximum_episode_duration_seconds: Schema.optional<Schema.Number>;
|
|
1793
1798
|
readonly name: Schema.String;
|
|
1794
1799
|
readonly slug: Schema.String;
|
|
1795
1800
|
}>>>;
|
|
@@ -1800,6 +1805,7 @@ export declare const CreatePublicSpaceResponseSchema: Schema.Struct<{
|
|
|
1800
1805
|
readonly lifecycle_until: Schema.brand<Schema.String, "DateTimeString">;
|
|
1801
1806
|
readonly space: Schema.Struct<{
|
|
1802
1807
|
readonly admission_mode: Schema.String;
|
|
1808
|
+
readonly maximum_episode_duration_seconds: Schema.optional<Schema.Number>;
|
|
1803
1809
|
readonly name: Schema.String;
|
|
1804
1810
|
readonly slug: Schema.String;
|
|
1805
1811
|
}>;
|
|
@@ -2343,6 +2349,7 @@ export declare const GetSpacePublicInviteArrivalResponseSchema: Schema.Struct<{
|
|
|
2343
2349
|
readonly retry_after: Schema.optional<Schema.Number>;
|
|
2344
2350
|
readonly space: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
2345
2351
|
readonly admission_mode: Schema.String;
|
|
2352
|
+
readonly maximum_episode_duration_seconds: Schema.optional<Schema.Number>;
|
|
2346
2353
|
readonly name: Schema.String;
|
|
2347
2354
|
readonly slug: Schema.String;
|
|
2348
2355
|
}>>>;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
createSpaceClient,
|
|
16
16
|
decodeWhiteboardV1ServerFrame,
|
|
17
17
|
encodeWhiteboardV1ClientFrame
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-XPW3OCPO.js";
|
|
19
19
|
import {
|
|
20
20
|
CloudflareSFUClient,
|
|
21
21
|
CloudflareSFUError,
|
|
@@ -31,15 +31,16 @@ import {
|
|
|
31
31
|
} from "./chunk-DWKTGBHR.js";
|
|
32
32
|
import {
|
|
33
33
|
createChalkPublicClient,
|
|
34
|
-
createChalkPublicInviteClient
|
|
35
|
-
|
|
34
|
+
createChalkPublicInviteClient,
|
|
35
|
+
parseInviteCode
|
|
36
|
+
} from "./chunk-6LNRDKJF.js";
|
|
36
37
|
import {
|
|
37
38
|
ArrivalInvalidHandleError,
|
|
38
39
|
ArrivalUnavailableError,
|
|
39
40
|
SpacePublicInviteUnavailableError,
|
|
40
41
|
parseParsedAccessGrant,
|
|
41
42
|
requireAccessGrant
|
|
42
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-GA3JDPFI.js";
|
|
43
44
|
import {
|
|
44
45
|
AsyncStorageV1PendingTargetStore,
|
|
45
46
|
InMemoryV1PendingTargetStore,
|
|
@@ -68,7 +69,7 @@ import {
|
|
|
68
69
|
optimisticV1Control,
|
|
69
70
|
reactionFromFrame,
|
|
70
71
|
restoreV1Snapshot
|
|
71
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-AIJ5Z6HA.js";
|
|
72
73
|
|
|
73
74
|
// src/space-client/reload-rejoin.ts
|
|
74
75
|
import { Schema } from "effect";
|
|
@@ -114,6 +115,23 @@ function reloadRejoinAccess(access) {
|
|
|
114
115
|
const parsed = parseParsedAccessGrant(access);
|
|
115
116
|
return { tenantId: parsed.subject.tenantId, episodeId: parsed.subject.episodeId, participantId: parsed.subject.participantId, participantGeneration: parsed.subject.participantGeneration, mediaProof: parsed.media.token };
|
|
116
117
|
}
|
|
118
|
+
|
|
119
|
+
// src/space-client/failure-detail.ts
|
|
120
|
+
var DEFAULT_FAILURE_DETAIL = "Something went wrong while joining. Try again.";
|
|
121
|
+
var FAILURE_DETAILS = {
|
|
122
|
+
"access.invalid": "Access to this call was rejected. Refresh the page and try again.",
|
|
123
|
+
"access.unavailable": "Couldn\u2019t get access to the call. Try again.",
|
|
124
|
+
"connection.sync_start_failed": "Couldn\u2019t reach the call service. Try again.",
|
|
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.",
|
|
127
|
+
"connection.media_start_failed": "Audio and video could not connect. Try again.",
|
|
128
|
+
"connection.media_recovery_exhausted": "Audio and video could not reconnect. Try again.",
|
|
129
|
+
"environment.unsupported": "This device cannot start the call. Use an up-to-date browser over HTTPS, or update the app."
|
|
130
|
+
};
|
|
131
|
+
function getConnectionFailureDetail({ code, sync }) {
|
|
132
|
+
if (sync?.stage === "upgrade") return sync.closeCode !== null ? "The connection closed before the call service could be reached. Try again." : "A connection to the call service could not be opened. Try again.";
|
|
133
|
+
return (code && FAILURE_DETAILS[code]) ?? DEFAULT_FAILURE_DETAIL;
|
|
134
|
+
}
|
|
117
135
|
export {
|
|
118
136
|
ArrivalInvalidHandleError,
|
|
119
137
|
ArrivalUnavailableError,
|
|
@@ -165,8 +183,10 @@ export {
|
|
|
165
183
|
encodeV1ClientFrame,
|
|
166
184
|
encodeWhiteboardV1ClientFrame,
|
|
167
185
|
formatSyncConnectDiagnostic,
|
|
186
|
+
getConnectionFailureDetail,
|
|
168
187
|
optimisticV1Control,
|
|
169
188
|
parseCloudflareSFUPublicationID,
|
|
189
|
+
parseInviteCode,
|
|
170
190
|
publicationKey,
|
|
171
191
|
reactionFromFrame,
|
|
172
192
|
readReloadRejoin,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseInviteCode(value: string): string | undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createChalkPublicClient, createChalkPublicInviteClient } from "./client.js";
|
|
2
|
+
export { parseInviteCode } from "./code.js";
|
|
2
3
|
export type { ArriveBySpacePublicInviteInput, ChalkPublicClient, ChalkPublicClientOptions, ChalkPublicClientRuntime, ChalkPublicIdempotencyOptions, ChalkPublicInviteError, CreatePublicSpace, CreatePublicSpaceInput, ArriveBySpacePublicInvite, GetSpacePublicInviteArrival, LeaveSpacePublicInviteArrival, PublicArrivalOptions, PublicArrivalReference, PublicRefreshAccessInput, PublicLeaveOptions, PublicSpaceArrival, PublicSpaceArrivalAccess, PublicSpaceCreated, RefreshSpacePublicInviteAccess, } from "./types.js";
|
|
3
4
|
export { ArrivalInvalidHandleError, ArrivalUnavailableError, SpacePublicInviteUnavailableError } from "../generated/schemas.js";
|
|
4
5
|
export type { ApproveSpacePublicAdmissionRequestError, ArriveBySpacePublicInviteError, CreatePublicSpaceError, DenySpacePublicAdmissionRequestError, GetSpacePublicInviteArrivalError, LeaveSpacePublicInviteArrivalError, RefreshSpacePublicInviteAccessError } from "../generated/schemas.js";
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createChalkPublicClient,
|
|
3
|
-
createChalkPublicInviteClient
|
|
4
|
-
|
|
3
|
+
createChalkPublicInviteClient,
|
|
4
|
+
parseInviteCode
|
|
5
|
+
} from "../chunk-6LNRDKJF.js";
|
|
5
6
|
import {
|
|
6
7
|
ArrivalInvalidHandleError,
|
|
7
8
|
ArrivalUnavailableError,
|
|
8
9
|
SpacePublicInviteUnavailableError
|
|
9
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-GA3JDPFI.js";
|
|
10
11
|
export {
|
|
11
12
|
ArrivalInvalidHandleError,
|
|
12
13
|
ArrivalUnavailableError,
|
|
13
14
|
SpacePublicInviteUnavailableError,
|
|
14
15
|
createChalkPublicClient,
|
|
15
|
-
createChalkPublicInviteClient
|
|
16
|
+
createChalkPublicInviteClient,
|
|
17
|
+
parseInviteCode
|
|
16
18
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ClientFailure, ErrorCode } from "./types";
|
|
2
|
+
/** Safe, actionable failure copy shared by web and native call screens. */
|
|
3
|
+
export declare function getConnectionFailureDetail({ code, sync }: {
|
|
4
|
+
readonly code?: ErrorCode;
|
|
5
|
+
readonly sync?: ClientFailure["sync"];
|
|
6
|
+
}): string;
|
|
@@ -67,6 +67,7 @@ export type ConnectionSlice = {
|
|
|
67
67
|
readonly lastError: ClientFailure | null;
|
|
68
68
|
/** The Episode ended while this person was in it. */
|
|
69
69
|
readonly episodeEnded: boolean;
|
|
70
|
+
readonly episodeEndReason?: import("../sync/v1-types").V1ControlState["endReason"];
|
|
70
71
|
/** The server removed this person from the call; a person's own leave never sets this. */
|
|
71
72
|
readonly removedByHost: boolean;
|
|
72
73
|
};
|
|
@@ -260,6 +261,7 @@ export type ClientEventMap = {
|
|
|
260
261
|
};
|
|
261
262
|
readonly episodeEnded: {
|
|
262
263
|
readonly episode: EpisodeSummary | null;
|
|
264
|
+
readonly reason?: ConnectionSlice["episodeEndReason"];
|
|
263
265
|
};
|
|
264
266
|
readonly screenShareStarted: {
|
|
265
267
|
readonly participantId: string;
|
|
@@ -5,6 +5,12 @@ export type SyncConnectDiagnostic = {
|
|
|
5
5
|
readonly closeCode: number | null;
|
|
6
6
|
readonly closeReason: string | null;
|
|
7
7
|
readonly durationMs: number;
|
|
8
|
+
/** One-based socket attempt since Sync start; absent in older SDK evidence. */
|
|
9
|
+
readonly attempt?: number;
|
|
10
|
+
/** Total sockets started when the join failed, including a pending replacement. */
|
|
11
|
+
readonly attempts?: number;
|
|
8
12
|
};
|
|
9
13
|
export declare function safeSyncCloseReason(reason: string | undefined): string | null;
|
|
14
|
+
/** Keep published error codes stable while separating upgrade from hello failures. */
|
|
15
|
+
export declare function syncConnectFailureCode(diagnostic: SyncConnectDiagnostic | undefined): "sync_start_failed" | "sync_hello_timeout";
|
|
10
16
|
export declare function formatSyncConnectDiagnostic(diagnostic: SyncConnectDiagnostic): string;
|
package/dist/sync/index.js
CHANGED
package/dist/sync/v1-types.d.ts
CHANGED
|
@@ -37,6 +37,10 @@ export type V1ControlState = {
|
|
|
37
37
|
readonly stateSchemaVersion: number;
|
|
38
38
|
readonly stateDigest: string;
|
|
39
39
|
readonly status: "active" | "ended";
|
|
40
|
+
readonly endReason?: Extract<SyncV1ServerFrame, {
|
|
41
|
+
readonly type: "event";
|
|
42
|
+
readonly name: "episode_ended";
|
|
43
|
+
}>["payload"]["reason"];
|
|
40
44
|
readonly admissionPolicy: V1AdmissionPolicy;
|
|
41
45
|
readonly deadlineAtMs: number;
|
|
42
46
|
readonly deadlineGeneration: number;
|
package/package.json
CHANGED
package/dist/chunk-DHGAKJXP.js
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createChalkEffectClient,
|
|
3
|
-
parseAccessGrant
|
|
4
|
-
} from "./chunk-HO4745TX.js";
|
|
5
|
-
|
|
6
|
-
// src/public-invites/client.ts
|
|
7
|
-
import { Effect } from "effect";
|
|
8
|
-
function createChalkPublicClient(options) {
|
|
9
|
-
const baseClientOptions = {
|
|
10
|
-
baseUrl: options.baseUrl,
|
|
11
|
-
credentials: options.credentials ?? (options.runtime === "react-native" ? void 0 : "include"),
|
|
12
|
-
fetch: options.fetch
|
|
13
|
-
};
|
|
14
|
-
const createClient = (guestCredential, requestInit) => createChalkEffectClient({
|
|
15
|
-
...baseClientOptions,
|
|
16
|
-
...requestInit ? { fetch: requestInitFetch(options.fetch, requestInit) } : {},
|
|
17
|
-
headers: requestHeaders(options, guestCredential)
|
|
18
|
-
});
|
|
19
|
-
const createPublicSpace = async (input, idempotency) => {
|
|
20
|
-
const client = await Effect.runPromise(createClient(void 0));
|
|
21
|
-
const response = await Effect.runPromise(
|
|
22
|
-
client.spaces.createPublicSpace({
|
|
23
|
-
headers: { "Idempotency-Key": idempotencyKey(idempotency) },
|
|
24
|
-
payload: { display_name: required(input.displayName, "displayName") }
|
|
25
|
-
})
|
|
26
|
-
);
|
|
27
|
-
return publicSpaceCreated(response);
|
|
28
|
-
};
|
|
29
|
-
const arriveBySpacePublicInvite = async (input, arrival) => {
|
|
30
|
-
const client = await Effect.runPromise(createClient(arrival?.guestCredential ?? options.guestCredential));
|
|
31
|
-
const response = await Effect.runPromise(
|
|
32
|
-
client.spaces.arriveBySpacePublicInvite({
|
|
33
|
-
headers: {
|
|
34
|
-
"Idempotency-Key": idempotencyKey(arrival),
|
|
35
|
-
...arrival?.arrivalHandle === void 0 ? {} : { "X-Chalk-Arrival-Handle": required(arrival.arrivalHandle, "arrivalHandle") }
|
|
36
|
-
},
|
|
37
|
-
payload: {
|
|
38
|
-
display_name: required(input.displayName, "displayName"),
|
|
39
|
-
space_invite_token: required(input.spaceInviteToken, "spaceInviteToken")
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
);
|
|
43
|
-
return publicSpaceArrival(response);
|
|
44
|
-
};
|
|
45
|
-
const getSpacePublicInviteArrival = async (reference) => {
|
|
46
|
-
const normalized = arrivalReference(reference);
|
|
47
|
-
const client = await Effect.runPromise(createClient(normalized.guestCredential ?? options.guestCredential));
|
|
48
|
-
const response = await Effect.runPromise(
|
|
49
|
-
client.spaces.getSpacePublicInviteArrival({
|
|
50
|
-
headers: { "X-Chalk-Arrival-Handle": normalized.arrivalHandle }
|
|
51
|
-
})
|
|
52
|
-
);
|
|
53
|
-
return publicSpaceArrival(response);
|
|
54
|
-
};
|
|
55
|
-
const refreshSpacePublicInviteAccess = async (input, arrival) => {
|
|
56
|
-
const normalized = refreshInput(input, arrival);
|
|
57
|
-
const client = await Effect.runPromise(createClient(normalized.guestCredential ?? options.guestCredential, normalized.signal ? { signal: normalized.signal } : void 0));
|
|
58
|
-
const response = await Effect.runPromise(
|
|
59
|
-
client.spaces.refreshSpacePublicInviteAccess({
|
|
60
|
-
headers: { "X-Chalk-Arrival-Handle": normalized.arrivalHandle },
|
|
61
|
-
payload: { media_proof: required(normalized.mediaProof, "mediaProof"), replace_media_connection: normalized.replaceMediaConnection ?? false }
|
|
62
|
-
})
|
|
63
|
-
);
|
|
64
|
-
return parseAccessGrant(response);
|
|
65
|
-
};
|
|
66
|
-
const leaveSpacePublicInviteArrival = async (reference, leaveOptions) => {
|
|
67
|
-
const normalized = arrivalReference(reference);
|
|
68
|
-
const client = await Effect.runPromise(createClient(normalized.guestCredential ?? options.guestCredential, requestInitForLeave(leaveOptions)));
|
|
69
|
-
await Effect.runPromise(
|
|
70
|
-
client.spaces.leaveSpacePublicInviteArrival({
|
|
71
|
-
headers: { "X-Chalk-Arrival-Handle": normalized.arrivalHandle }
|
|
72
|
-
})
|
|
73
|
-
);
|
|
74
|
-
};
|
|
75
|
-
return {
|
|
76
|
-
prepareSpaceEntrance: async (spaceInviteToken) => {
|
|
77
|
-
const client = await Effect.runPromise(createClient(void 0));
|
|
78
|
-
await Effect.runPromise(client.spaces.preparePublicSpaceEntrance({ payload: { space_invite_token: required(spaceInviteToken, "spaceInviteToken") } }));
|
|
79
|
-
},
|
|
80
|
-
arrive: arriveBySpacePublicInvite,
|
|
81
|
-
arriveBySpacePublicInvite,
|
|
82
|
-
create: createPublicSpace,
|
|
83
|
-
createPublicSpace,
|
|
84
|
-
getSpacePublicInviteArrival,
|
|
85
|
-
leave: leaveSpacePublicInviteArrival,
|
|
86
|
-
leaveSpacePublicInviteArrival,
|
|
87
|
-
refresh: refreshSpacePublicInviteAccess,
|
|
88
|
-
refreshSpacePublicInviteAccess,
|
|
89
|
-
status: getSpacePublicInviteArrival
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
var createChalkPublicInviteClient = createChalkPublicClient;
|
|
93
|
-
function requestHeaders(options, guestCredential) {
|
|
94
|
-
const headers = { ...options.headers };
|
|
95
|
-
if (options.runtime === "react-native") {
|
|
96
|
-
headers["X-Chalk-Client"] = "react-native";
|
|
97
|
-
const credential = guestCredential ?? options.guestCredential;
|
|
98
|
-
if (credential !== void 0) headers.Authorization = `ChalkGuest ${required(credential, "guestCredential")}`;
|
|
99
|
-
}
|
|
100
|
-
return headers;
|
|
101
|
-
}
|
|
102
|
-
function idempotencyKey(options) {
|
|
103
|
-
return options?.idempotencyKey === void 0 ? globalThis.crypto.randomUUID() : required(options.idempotencyKey, "idempotencyKey");
|
|
104
|
-
}
|
|
105
|
-
function arrivalReference(reference) {
|
|
106
|
-
if (typeof reference === "string") return { arrivalHandle: required(reference, "arrivalHandle") };
|
|
107
|
-
return { arrivalHandle: required(reference.arrivalHandle, "arrivalHandle"), guestCredential: reference.guestCredential };
|
|
108
|
-
}
|
|
109
|
-
function refreshInput(input, arrival) {
|
|
110
|
-
const values = typeof input === "string" ? { arrivalHandle: arrival?.arrivalHandle, guestCredential: arrival?.guestCredential, mediaProof: input } : { arrivalHandle: input.arrivalHandle ?? arrival?.arrivalHandle, guestCredential: input.guestCredential ?? arrival?.guestCredential, mediaProof: input.mediaProof, replaceMediaConnection: input.replaceMediaConnection, signal: input.signal };
|
|
111
|
-
return {
|
|
112
|
-
...values,
|
|
113
|
-
arrivalHandle: required(values.arrivalHandle ?? "", "arrivalHandle")
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
function requestInitForLeave(options) {
|
|
117
|
-
if (options?.keepalive === void 0) return void 0;
|
|
118
|
-
return { keepalive: options.keepalive };
|
|
119
|
-
}
|
|
120
|
-
function requestInitFetch(fetchImplementation, requestInit) {
|
|
121
|
-
const implementation = fetchImplementation ?? globalThis.fetch;
|
|
122
|
-
return (input, init) => implementation(input, { ...init, ...requestInit });
|
|
123
|
-
}
|
|
124
|
-
function publicSpaceCreated(value) {
|
|
125
|
-
const { arrival, ...created } = value;
|
|
126
|
-
return { ...created, arrival: publicSpaceArrival(arrival) };
|
|
127
|
-
}
|
|
128
|
-
function publicSpaceArrival(value) {
|
|
129
|
-
const { access, ...arrival } = value;
|
|
130
|
-
if (access === void 0) return arrival;
|
|
131
|
-
return { ...arrival, access: access === null ? null : parseAccessGrant(access) };
|
|
132
|
-
}
|
|
133
|
-
function required(value, name) {
|
|
134
|
-
const normalized = value.trim();
|
|
135
|
-
if (!normalized) throw new TypeError(`${name} is required`);
|
|
136
|
-
return normalized;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export {
|
|
140
|
-
createChalkPublicClient,
|
|
141
|
-
createChalkPublicInviteClient
|
|
142
|
-
};
|