farvex 1.0.0 → 1.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # farvex
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix host client disposal, expire stale incoming invites, and export host start input types for frontend integrations.
8
+
3
9
  ## 1.0.0
4
10
 
5
11
  ### Major Changes
package/dist/index.cjs CHANGED
@@ -1065,6 +1065,7 @@ var createSessionStore = (userId) => {
1065
1065
  let listCache = [];
1066
1066
  let invitesCache = [];
1067
1067
  let inviteKey = "";
1068
+ let inviteExpiryTimer = null;
1068
1069
  const emit = (topic) => {
1069
1070
  const fns = subscribers.get(topic);
1070
1071
  if (!fns) {
@@ -1103,7 +1104,9 @@ var createSessionStore = (userId) => {
1103
1104
  }
1104
1105
  };
1105
1106
  const refreshInvites = () => {
1106
- const invites = listCache.map((session) => inviteFrom(session, userId)).filter((invite) => invite !== null);
1107
+ const now = Date.now();
1108
+ const invites = listCache.map((session) => inviteFrom(session, userId, now)).filter((invite) => invite !== null);
1109
+ scheduleInviteExpiry(invites, now);
1107
1110
  const nextKey = invites.map(
1108
1111
  (invite) => `${invite.session.id}:${invite.participant.id}:${invite.participant.state}:${invite.participant.inviteExpiresAt ?? ""}`
1109
1112
  ).join("|");
@@ -1115,6 +1118,34 @@ var createSessionStore = (userId) => {
1115
1118
  invitesCache = invites;
1116
1119
  return true;
1117
1120
  };
1121
+ const clearInviteExpiryTimer = () => {
1122
+ if (inviteExpiryTimer) {
1123
+ globalThis.clearTimeout(inviteExpiryTimer);
1124
+ inviteExpiryTimer = null;
1125
+ }
1126
+ };
1127
+ const scheduleInviteExpiry = (invites, now) => {
1128
+ clearInviteExpiryTimer();
1129
+ const nextExpiry = invites.reduce((min, invite) => {
1130
+ const expiresAt = inviteExpiryMs(invite.participant);
1131
+ if (expiresAt === null) {
1132
+ return min;
1133
+ }
1134
+ return min === null ? expiresAt : Math.min(min, expiresAt);
1135
+ }, null);
1136
+ if (nextExpiry === null) {
1137
+ return;
1138
+ }
1139
+ inviteExpiryTimer = globalThis.setTimeout(
1140
+ () => {
1141
+ inviteExpiryTimer = null;
1142
+ if (refreshInvites()) {
1143
+ emit("invites");
1144
+ }
1145
+ },
1146
+ Math.max(0, nextExpiry - now)
1147
+ );
1148
+ };
1118
1149
  const notifySessionChange = (sessionId) => {
1119
1150
  refresh();
1120
1151
  const invitesChanged = refreshInvites();
@@ -1201,13 +1232,17 @@ var createSessionStore = (userId) => {
1201
1232
  return next;
1202
1233
  },
1203
1234
  can: (session, action) => can(session, userId, action),
1235
+ dispose: () => {
1236
+ clearInviteExpiryTimer();
1237
+ subscribers.clear();
1238
+ },
1204
1239
  subscribe
1205
1240
  };
1206
1241
  };
1207
1242
  var selfParticipant = (session, userId) => session.participants.find((participant) => participant.userId === userId) ?? null;
1208
- var inviteFrom = (session, userId) => {
1243
+ var inviteFrom = (session, userId, now) => {
1209
1244
  const participant = selfParticipant(session, userId);
1210
- if (!participant || participant.state !== "invited") {
1245
+ if (!participant || session.state === "ended" || !isActiveInvite(participant, now)) {
1211
1246
  return null;
1212
1247
  }
1213
1248
  return { session, participant };
@@ -1220,7 +1255,7 @@ var can = (session, userId, action) => {
1220
1255
  switch (action) {
1221
1256
  case "accept":
1222
1257
  case "reject":
1223
- return self.state === "invited";
1258
+ return isActiveInvite(self);
1224
1259
  case "join":
1225
1260
  return self.transport === "webrtc" && (self.state === "accepted" || self.state === "joined");
1226
1261
  case "leave":
@@ -1235,6 +1270,17 @@ var can = (session, userId, action) => {
1235
1270
  return isHost(self) && session.recording.status === "recording";
1236
1271
  }
1237
1272
  };
1273
+ var isActiveInvite = (participant, now = Date.now()) => {
1274
+ const expiresAt = inviteExpiryMs(participant);
1275
+ return participant.state === "invited" && expiresAt !== null && expiresAt > now;
1276
+ };
1277
+ var inviteExpiryMs = (participant) => {
1278
+ if (!participant.inviteExpiresAt) {
1279
+ return null;
1280
+ }
1281
+ const expiresAt = Date.parse(participant.inviteExpiresAt);
1282
+ return Number.isFinite(expiresAt) ? expiresAt : null;
1283
+ };
1238
1284
  var isHost = (participant) => participant.role === "host" && (participant.kind === "agent" || participant.kind === "vendor_user");
1239
1285
 
1240
1286
  // src/core/client.ts
@@ -1255,7 +1301,7 @@ var createSessionClient = (config) => {
1255
1301
  },
1256
1302
  connect: core.connect,
1257
1303
  disconnect: core.realtime.disconnect,
1258
- dispose: core.realtime.dispose,
1304
+ dispose: core.dispose,
1259
1305
  on: core.emitter.on,
1260
1306
  subscribe: core.store.subscribe
1261
1307
  };
@@ -1279,7 +1325,7 @@ var createHostClient = (config) => {
1279
1325
  host: createHostControls(core),
1280
1326
  connect: core.connect,
1281
1327
  disconnect: core.realtime.disconnect,
1282
- dispose: core.realtime.dispose,
1328
+ dispose: core.dispose,
1283
1329
  on: core.emitter.on,
1284
1330
  subscribe: core.store.subscribe
1285
1331
  };
@@ -1318,6 +1364,10 @@ var createCore = (config) => {
1318
1364
  throw err;
1319
1365
  }
1320
1366
  };
1367
+ const dispose = async () => {
1368
+ await realtime.dispose();
1369
+ store.dispose();
1370
+ };
1321
1371
  return {
1322
1372
  api,
1323
1373
  auth: config.auth,
@@ -1325,6 +1375,7 @@ var createCore = (config) => {
1325
1375
  emitter,
1326
1376
  realtime,
1327
1377
  connect,
1378
+ dispose,
1328
1379
  applySession,
1329
1380
  applyStarted,
1330
1381
  patchRecording