@ai-matrx/meet 0.7.77 → 0.7.79

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/react.js CHANGED
@@ -1901,13 +1901,13 @@ function mergeCaption(list, caption) {
1901
1901
  return list.map((entry, position) => position === index ? caption : entry);
1902
1902
  }
1903
1903
  function mergeRecord(list, record) {
1904
- const byId = list.findIndex((entry) => entry.source === "record" && entry.id === record.id);
1905
- if (byId !== -1) {
1906
- const existing = list[byId];
1904
+ const byId2 = list.findIndex((entry) => entry.source === "record" && entry.id === record.id);
1905
+ if (byId2 !== -1) {
1906
+ const existing = list[byId2];
1907
1907
  if (existing !== void 0 && existing.text === record.text && existing.final === record.final) {
1908
1908
  return list;
1909
1909
  }
1910
- return list.map((entry, position) => position === byId ? record : entry);
1910
+ return list.map((entry, position) => position === byId2 ? record : entry);
1911
1911
  }
1912
1912
  const captionIndex = list.findIndex((entry) => supersedes(record, entry));
1913
1913
  if (captionIndex === -1) return [...list, record];
@@ -5481,50 +5481,8 @@ function useLocalUserId() {
5481
5481
  }
5482
5482
 
5483
5483
  // src/react/hooks.ts
5484
- import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
5485
-
5486
- // src/core/layout.ts
5487
- var DEFAULT_PAGE_SIZE = 12;
5488
- function orderParticipants(participants, activeSpeakers) {
5489
- const speakerRank = /* @__PURE__ */ new Map();
5490
- activeSpeakers.forEach((identity, index) => speakerRank.set(identity, index));
5491
- return [...participants].sort((a, b) => {
5492
- const speakerA = speakerRank.get(a.identity) ?? Number.MAX_SAFE_INTEGER;
5493
- const speakerB = speakerRank.get(b.identity) ?? Number.MAX_SAFE_INTEGER;
5494
- if (speakerA !== speakerB) return speakerA - speakerB;
5495
- if (a.handRaised !== b.handRaised) return a.handRaised ? -1 : 1;
5496
- if (a.cameraEnabled !== b.cameraEnabled) return a.cameraEnabled ? -1 : 1;
5497
- if (a.joinedAt !== b.joinedAt) return a.joinedAt < b.joinedAt ? -1 : 1;
5498
- return a.identity < b.identity ? -1 : 1;
5499
- });
5500
- }
5501
- function computeStage(args) {
5502
- const pageSize = Math.max(1, args.pageSize ?? DEFAULT_PAGE_SIZE);
5503
- const ordered = orderParticipants(args.participants, args.activeSpeakers);
5504
- const sharer = ordered.find((participant) => participant.screenSharing) ?? null;
5505
- const pinnedParticipant = args.pinned === null ? null : ordered.find((participant) => participant.identity === args.pinned) ?? null;
5506
- const spotlit = args.spotlight == null ? null : ordered.find((participant) => participant.identity === args.spotlight) ?? null;
5507
- const feature = sharer !== null ? sharer : pinnedParticipant !== null && args.layout !== "grid" ? pinnedParticipant : spotlit !== null ? spotlit : args.layout === "grid" ? null : ordered[0] ?? null;
5508
- const rest = feature === null ? ordered : ordered.filter((participant) => participant.identity !== feature.identity);
5509
- const pageCount = Math.max(1, Math.ceil(rest.length / pageSize));
5510
- const page = Math.min(Math.max(0, args.page ?? 0), pageCount - 1);
5511
- const tiles = rest.slice(page * pageSize, page * pageSize + pageSize);
5512
- return {
5513
- feature,
5514
- tiles,
5515
- overflow: rest.length - tiles.length,
5516
- page,
5517
- pageCount,
5518
- presenting: sharer !== null
5519
- };
5520
- }
5521
- function gridColumns(count2) {
5522
- if (count2 <= 1) return 1;
5523
- if (count2 <= 4) return 2;
5524
- if (count2 <= 9) return 3;
5525
- if (count2 <= 16) return 4;
5526
- return 5;
5527
- }
5484
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2, useSyncExternalStore as useSyncExternalStore2 } from "react";
5485
+ import { useRealtimeManager as useRealtimeManager2 } from "@ai-matrx/realtime/react";
5528
5486
 
5529
5487
  // src/core/record.ts
5530
5488
  import { formatDurationMs } from "@ai-matrx/kit/format";
@@ -5548,6 +5506,9 @@ function restrictionFor(part, error) {
5548
5506
  };
5549
5507
  }
5550
5508
  async function loadMeetingRecord(repository, meetingId, meeting, reader = { userId: null }) {
5509
+ return assembleMeetingRecord(meeting, await loadMeetingRecordParts(repository, meetingId, reader));
5510
+ }
5511
+ async function loadMeetingRecordParts(repository, meetingId, reader = { userId: null }) {
5551
5512
  const restrictions = [];
5552
5513
  async function attempt(part, run, empty) {
5553
5514
  if (reader.userId === null) {
@@ -5575,6 +5536,10 @@ async function loadMeetingRecord(repository, meetingId, meeting, reader = { user
5575
5536
  []
5576
5537
  )
5577
5538
  ]);
5539
+ return { attendees, notes, transcript, recordings, restrictions };
5540
+ }
5541
+ function assembleMeetingRecord(meeting, parts) {
5542
+ const { attendees, notes, transcript, recordings, restrictions } = parts;
5578
5543
  return {
5579
5544
  meeting,
5580
5545
  attendees,
@@ -5920,6 +5885,253 @@ async function setGuestRecordAccess(args) {
5920
5885
  }
5921
5886
  var GUEST_RECORD_NOT_SHARED = NOT_SHARED;
5922
5887
 
5888
+ // src/core/record-cache.ts
5889
+ var MEETING_RECORD_GRACE_MS = 6e4;
5890
+ var INITIAL = { loading: true, record: null, failure: null };
5891
+ function upsert2(rows, row, removedId, order) {
5892
+ const id = row?.id ?? removedId;
5893
+ if (id === void 0) return rows;
5894
+ const rest = rows.filter((existing) => existing.id !== id);
5895
+ return row === null ? rest : [...rest, row].sort(order);
5896
+ }
5897
+ var byId = (a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
5898
+ var ascending = (a, b) => a === b ? 0 : a === null ? 1 : b === null ? -1 : a < b ? -1 : 1;
5899
+ function createMeetingRecordCache(options = {}) {
5900
+ const graceMs = options.graceMs ?? MEETING_RECORD_GRACE_MS;
5901
+ const entries = /* @__PURE__ */ new Map();
5902
+ const listeners = /* @__PURE__ */ new Set();
5903
+ const notify = () => {
5904
+ for (const listener of listeners) listener();
5905
+ };
5906
+ const entryOf = (key) => {
5907
+ let entry = entries.get(key);
5908
+ if (!entry) {
5909
+ entry = {
5910
+ state: INITIAL,
5911
+ meeting: null,
5912
+ parts: null,
5913
+ fresh: false,
5914
+ seq: 0,
5915
+ inflight: null,
5916
+ holders: 0,
5917
+ close: null,
5918
+ owner: null,
5919
+ grace: null
5920
+ };
5921
+ entries.set(key, entry);
5922
+ }
5923
+ return entry;
5924
+ };
5925
+ const assemble = (entry) => {
5926
+ if (entry.meeting === null || entry.parts === null) return;
5927
+ entry.state = { loading: false, failure: null, record: assembleMeetingRecord(entry.meeting, entry.parts) };
5928
+ notify();
5929
+ };
5930
+ return {
5931
+ state: (key) => key === null ? INITIAL : entries.get(key)?.state ?? INITIAL,
5932
+ subscribe(listener) {
5933
+ listeners.add(listener);
5934
+ return () => {
5935
+ listeners.delete(listener);
5936
+ };
5937
+ },
5938
+ ensure(key, read, { force = false } = {}) {
5939
+ const entry = entryOf(key);
5940
+ if (!force) {
5941
+ if (entry.inflight !== null) return entry.inflight;
5942
+ if (entry.fresh) return Promise.resolve();
5943
+ }
5944
+ const seq = ++entry.seq;
5945
+ if (entry.state.failure !== null) {
5946
+ entry.state = { ...entry.state, loading: true, failure: null };
5947
+ notify();
5948
+ }
5949
+ const request = read().then(
5950
+ (answer) => {
5951
+ if (seq !== entry.seq) return;
5952
+ entry.fresh = true;
5953
+ if (answer.kind === "parts") {
5954
+ entry.meeting = answer.meeting;
5955
+ entry.parts = answer.parts;
5956
+ assemble(entry);
5957
+ } else {
5958
+ entry.meeting = answer.bundle.meeting;
5959
+ entry.parts = null;
5960
+ entry.state = { loading: false, failure: null, record: answer.bundle };
5961
+ notify();
5962
+ }
5963
+ },
5964
+ (thrown) => {
5965
+ if (seq !== entry.seq) return;
5966
+ entry.fresh = false;
5967
+ entry.state = {
5968
+ loading: false,
5969
+ record: entry.state.record,
5970
+ failure: {
5971
+ message: thrown?.message ?? String(thrown),
5972
+ remedy: thrown?.remedy ?? "The meeting record could not be read. Reload the page; nothing was changed."
5973
+ }
5974
+ };
5975
+ notify();
5976
+ }
5977
+ );
5978
+ const tracked = request.finally(() => {
5979
+ if (entry.inflight === tracked) entry.inflight = null;
5980
+ });
5981
+ entry.inflight = tracked;
5982
+ return tracked;
5983
+ },
5984
+ setMeeting(key, meeting) {
5985
+ const entry = entries.get(key);
5986
+ if (!entry || entry.meeting === meeting) return;
5987
+ if (entry.parts !== null) {
5988
+ entry.meeting = meeting;
5989
+ assemble(entry);
5990
+ } else if (entry.state.record !== null) {
5991
+ entry.meeting = meeting;
5992
+ entry.state = { ...entry.state, record: { ...entry.state.record, meeting } };
5993
+ notify();
5994
+ }
5995
+ },
5996
+ apply(key, change) {
5997
+ const entry = entries.get(key);
5998
+ const parts = entry?.parts;
5999
+ if (!entry || !parts) return;
6000
+ const refused = parts.restrictions.some((r) => r.part === change.part);
6001
+ if (refused) return;
6002
+ switch (change.part) {
6003
+ case "transcript":
6004
+ entry.parts = {
6005
+ ...parts,
6006
+ transcript: upsert2(
6007
+ parts.transcript,
6008
+ change.row,
6009
+ change.removedId,
6010
+ (a, b) => ascending(a.startedAt, b.startedAt) || byId(a, b)
6011
+ )
6012
+ };
6013
+ break;
6014
+ case "notes":
6015
+ entry.parts = {
6016
+ ...parts,
6017
+ notes: upsert2(
6018
+ parts.notes,
6019
+ change.row,
6020
+ change.removedId,
6021
+ (a, b) => ascending(a.createdAt, b.createdAt) || byId(a, b)
6022
+ )
6023
+ };
6024
+ break;
6025
+ case "attendance":
6026
+ entry.parts = {
6027
+ ...parts,
6028
+ attendees: upsert2(
6029
+ parts.attendees,
6030
+ change.row,
6031
+ change.removedId,
6032
+ (a, b) => ascending(a.joinedAt, b.joinedAt) || byId(a, b)
6033
+ )
6034
+ };
6035
+ break;
6036
+ case "recording":
6037
+ entry.parts = {
6038
+ ...parts,
6039
+ // Newest first, as the read orders them.
6040
+ recordings: upsert2(
6041
+ parts.recordings,
6042
+ change.row,
6043
+ change.removedId,
6044
+ (a, b) => ascending(b.startedAt, a.startedAt) || byId(a, b)
6045
+ )
6046
+ };
6047
+ break;
6048
+ }
6049
+ assemble(entry);
6050
+ },
6051
+ hold(key, open, owner = null) {
6052
+ const entry = entryOf(key);
6053
+ if (entry.grace !== null) {
6054
+ clearTimeout(entry.grace);
6055
+ entry.grace = null;
6056
+ }
6057
+ if (entry.close !== null && entry.owner !== owner) {
6058
+ entry.close();
6059
+ entry.close = null;
6060
+ }
6061
+ if (entry.close === null) {
6062
+ entry.close = open();
6063
+ entry.owner = owner;
6064
+ }
6065
+ entry.holders += 1;
6066
+ let released = false;
6067
+ return () => {
6068
+ if (released) return;
6069
+ released = true;
6070
+ entry.holders -= 1;
6071
+ if (entry.holders > 0) return;
6072
+ entry.grace = setTimeout(() => {
6073
+ entry.grace = null;
6074
+ if (entry.holders > 0) return;
6075
+ entry.close?.();
6076
+ entry.close = null;
6077
+ entry.fresh = false;
6078
+ }, graceMs);
6079
+ };
6080
+ },
6081
+ reset() {
6082
+ for (const entry of entries.values()) {
6083
+ if (entry.grace !== null) clearTimeout(entry.grace);
6084
+ entry.close?.();
6085
+ }
6086
+ entries.clear();
6087
+ notify();
6088
+ }
6089
+ };
6090
+ }
6091
+
6092
+ // src/core/layout.ts
6093
+ var DEFAULT_PAGE_SIZE = 12;
6094
+ function orderParticipants(participants, activeSpeakers) {
6095
+ const speakerRank = /* @__PURE__ */ new Map();
6096
+ activeSpeakers.forEach((identity, index) => speakerRank.set(identity, index));
6097
+ return [...participants].sort((a, b) => {
6098
+ const speakerA = speakerRank.get(a.identity) ?? Number.MAX_SAFE_INTEGER;
6099
+ const speakerB = speakerRank.get(b.identity) ?? Number.MAX_SAFE_INTEGER;
6100
+ if (speakerA !== speakerB) return speakerA - speakerB;
6101
+ if (a.handRaised !== b.handRaised) return a.handRaised ? -1 : 1;
6102
+ if (a.cameraEnabled !== b.cameraEnabled) return a.cameraEnabled ? -1 : 1;
6103
+ if (a.joinedAt !== b.joinedAt) return a.joinedAt < b.joinedAt ? -1 : 1;
6104
+ return a.identity < b.identity ? -1 : 1;
6105
+ });
6106
+ }
6107
+ function computeStage(args) {
6108
+ const pageSize = Math.max(1, args.pageSize ?? DEFAULT_PAGE_SIZE);
6109
+ const ordered = orderParticipants(args.participants, args.activeSpeakers);
6110
+ const sharer = ordered.find((participant) => participant.screenSharing) ?? null;
6111
+ const pinnedParticipant = args.pinned === null ? null : ordered.find((participant) => participant.identity === args.pinned) ?? null;
6112
+ const spotlit = args.spotlight == null ? null : ordered.find((participant) => participant.identity === args.spotlight) ?? null;
6113
+ const feature = sharer !== null ? sharer : pinnedParticipant !== null && args.layout !== "grid" ? pinnedParticipant : spotlit !== null ? spotlit : args.layout === "grid" ? null : ordered[0] ?? null;
6114
+ const rest = feature === null ? ordered : ordered.filter((participant) => participant.identity !== feature.identity);
6115
+ const pageCount = Math.max(1, Math.ceil(rest.length / pageSize));
6116
+ const page = Math.min(Math.max(0, args.page ?? 0), pageCount - 1);
6117
+ const tiles = rest.slice(page * pageSize, page * pageSize + pageSize);
6118
+ return {
6119
+ feature,
6120
+ tiles,
6121
+ overflow: rest.length - tiles.length,
6122
+ page,
6123
+ pageCount,
6124
+ presenting: sharer !== null
6125
+ };
6126
+ }
6127
+ function gridColumns(count2) {
6128
+ if (count2 <= 1) return 1;
6129
+ if (count2 <= 4) return 2;
6130
+ if (count2 <= 9) return 3;
6131
+ if (count2 <= 16) return 4;
6132
+ return 5;
6133
+ }
6134
+
5923
6135
  // src/react/hooks.ts
5924
6136
  var EMPTY_NAMES = {};
5925
6137
  var NO_RUNTIME_REMEDY = "Render this inside a <MeetProvider> that has a Supabase client, an organization id and an identity (userId or guestName). The provider stays inert until all three are real, and while it is inert this package's components render nothing rather than a dead control.";
@@ -6505,16 +6717,22 @@ function useMeeting() {
6505
6717
  function useMeetingId() {
6506
6718
  return useMeetSnapshot()?.meeting?.id ?? null;
6507
6719
  }
6720
+ var RECORD_CACHE_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/meet/meeting-record-cache");
6721
+ function meetingRecordCache() {
6722
+ const holder = globalThis;
6723
+ let cache = holder[RECORD_CACHE_KEY];
6724
+ if (cache === void 0) {
6725
+ cache = createMeetingRecordCache();
6726
+ holder[RECORD_CACHE_KEY] = cache;
6727
+ }
6728
+ return cache;
6729
+ }
6730
+ var rowIdOf = (row) => typeof row["id"] === "string" ? row["id"] : void 0;
6508
6731
  function useMeetingRecord(meeting) {
6509
6732
  const host = useMeetHost();
6510
6733
  const repository = host?.repository ?? null;
6511
6734
  const ai = host?.ai ?? null;
6512
6735
  const readerId = host?.identity.userId ?? null;
6513
- const [recordReaderId, setRecordReaderId] = useState2(readerId);
6514
- const [record, setRecord] = useState2(null);
6515
- const [loading, setLoading] = useState2(true);
6516
- const [failure, setFailure] = useState2(null);
6517
- const [nonce, setNonce] = useState2(0);
6518
6736
  const [asking, setAsking] = useState2(false);
6519
6737
  const [answer, setAnswer] = useState2(null);
6520
6738
  const [coverage, setCoverage] = useState2(null);
@@ -6523,57 +6741,107 @@ function useMeetingRecord(meeting) {
6523
6741
  const api = host?.api ?? null;
6524
6742
  const tokens = host?.tokens ?? null;
6525
6743
  const roomName = meeting?.roomName ?? null;
6526
- useEffect2(() => {
6527
- if (repository === null || meeting === null || meetingId === null) return void 0;
6528
- let live = true;
6529
- setLoading(true);
6530
- setFailure(null);
6531
- setRecord(null);
6532
- const load = readerId === null && api !== null && tokens !== null && roomName !== null ? loadGuestMeetingRecord({
6533
- api,
6534
- repository,
6535
- meetingId,
6536
- meeting,
6537
- roomToken: tokens.remembered(roomName)
6538
- }) : loadMeetingRecord(repository, meetingId, meeting, { userId: readerId }).then(
6539
- (direct) => (
6540
- // A SIGNED-IN OUTSIDER IS NOT A STRANGER (2026-10-01). The database
6541
- // answers members and invitees; a person from another organization
6542
- // the host admitted — or a guest who later made an account — reads
6543
- // the guest share through the server, with their session as the pass.
6544
- api !== null && direct.restrictions.some((part) => part.part === "notes") ? loadGuestMeetingRecord({
6744
+ const manager = useRealtimeManager2();
6745
+ const cache = meetingRecordCache();
6746
+ const key = repository !== null && meetingId !== null ? `${readerId ?? `guest:${roomName ?? "-"}`}|${meetingId}` : null;
6747
+ const state = useSyncExternalStore2(
6748
+ cache.subscribe,
6749
+ () => cache.state(key),
6750
+ () => cache.state(null)
6751
+ );
6752
+ const readRef = useRef2(() => Promise.reject(new Error("not ready")));
6753
+ readRef.current = async () => {
6754
+ if (repository === null || meeting === null || meetingId === null) throw new Error("No meeting to read.");
6755
+ if (readerId === null && api !== null && tokens !== null && roomName !== null) {
6756
+ return {
6757
+ kind: "bundle",
6758
+ bundle: await loadGuestMeetingRecord({
6545
6759
  api,
6546
6760
  repository,
6547
6761
  meetingId,
6548
6762
  meeting,
6549
- roomToken: null,
6550
- session: true
6551
- }).then(
6552
- (viaServer) => viaServer.restrictions.length < direct.restrictions.length ? viaServer : direct
6553
- ) : direct
6554
- )
6555
- );
6556
- void load.then((bundle) => {
6557
- if (!live) return;
6558
- setRecordReaderId(readerId);
6559
- setRecord(bundle);
6560
- setLoading(false);
6561
- }).catch((thrown) => {
6562
- if (!live) return;
6563
- setFailure({
6564
- message: thrown.message,
6565
- remedy: thrown.remedy ?? "The meeting record could not be read. Reload the page; nothing was changed."
6763
+ roomToken: tokens.remembered(roomName)
6764
+ })
6765
+ };
6766
+ }
6767
+ const parts = await loadMeetingRecordParts(repository, meetingId, { userId: readerId });
6768
+ if (api !== null && parts.restrictions.some((part) => part.part === "notes")) {
6769
+ const viaServer = await loadGuestMeetingRecord({
6770
+ api,
6771
+ repository,
6772
+ meetingId,
6773
+ meeting,
6774
+ roomToken: null,
6775
+ session: true
6566
6776
  });
6567
- setLoading(false);
6777
+ if (viaServer.restrictions.length < parts.restrictions.length) return { kind: "bundle", bundle: viaServer };
6778
+ }
6779
+ return { kind: "parts", meeting, parts };
6780
+ };
6781
+ useEffect2(() => {
6782
+ if (key === null) return;
6783
+ void cache.ensure(key, () => readRef.current());
6784
+ }, [cache, key]);
6785
+ useEffect2(() => {
6786
+ if (key !== null && meeting !== null) cache.setMeeting(key, meeting);
6787
+ }, [cache, key, meeting]);
6788
+ useEffect2(() => {
6789
+ if (key === null || manager === null || repository === null || meetingId === null || readerId === null) {
6790
+ return void 0;
6791
+ }
6792
+ const repo = repository;
6793
+ const binding = (table, apply) => ({
6794
+ event: "*",
6795
+ schema: repo.schema,
6796
+ table,
6797
+ filter: `meeting_id=eq.${meetingId}`,
6798
+ rowId: rowIdOf,
6799
+ onChange: ({ row, payload }) => {
6800
+ if (row === null) return;
6801
+ const gone = payload.eventType === "DELETE";
6802
+ apply(gone ? null : row, gone ? rowIdOf(row) : void 0);
6803
+ }
6568
6804
  });
6569
- return () => {
6570
- live = false;
6571
- };
6572
- }, [repository, meeting, meetingId, readerId, api, tokens, roomName, nonce]);
6805
+ return cache.hold(
6806
+ key,
6807
+ () => {
6808
+ const handle = manager.open({
6809
+ topic: meetingTopic(meetingId),
6810
+ postgresChanges: [
6811
+ binding(
6812
+ repo.tables.notes,
6813
+ (row, removedId) => cache.apply(key, { part: "notes", row: row && repo.projectNote(row), removedId })
6814
+ ),
6815
+ binding(
6816
+ repo.tables.transcripts,
6817
+ (row, removedId) => cache.apply(key, { part: "transcript", row: row && repo.projectSegment(row), removedId })
6818
+ ),
6819
+ binding(
6820
+ repo.tables.participants,
6821
+ (row, removedId) => cache.apply(key, { part: "attendance", row: row && repo.projectAttendee(row), removedId })
6822
+ ),
6823
+ binding(
6824
+ repo.tables.recordings,
6825
+ (row, removedId) => (
6826
+ // An archived recording is off the record (the read filters it the same way).
6827
+ row !== null && row["deleted_at"] != null ? cache.apply(key, { part: "recording", row: null, removedId: rowIdOf(row) }) : cache.apply(key, { part: "recording", row: row && repo.projectRecording(row), removedId })
6828
+ )
6829
+ )
6830
+ ],
6831
+ // Realtime has no replay: a socket that blipped reads the record again.
6832
+ onBackfill: async () => {
6833
+ await cache.ensure(key, () => readRef.current(), { force: true });
6834
+ }
6835
+ });
6836
+ return () => handle.close();
6837
+ },
6838
+ manager
6839
+ );
6840
+ }, [cache, key, manager, repository, meetingId, readerId]);
6573
6841
  return {
6574
- loading: loading && failure === null,
6575
- record: recordReaderId === readerId ? record : null,
6576
- failure,
6842
+ loading: state.loading && state.failure === null,
6843
+ record: state.record,
6844
+ failure: state.failure,
6577
6845
  asking,
6578
6846
  answer,
6579
6847
  coverage,
@@ -6604,7 +6872,9 @@ function useMeetingRecord(meeting) {
6604
6872
  },
6605
6873
  [ai, meetingId]
6606
6874
  ),
6607
- reload: useCallback2(() => setNonce((value) => value + 1), [])
6875
+ reload: useCallback2(() => {
6876
+ if (key !== null) void cache.ensure(key, () => readRef.current(), { force: true });
6877
+ }, [cache, key])
6608
6878
  };
6609
6879
  }
6610
6880
  function useMeetings(limit = 25, organizationFilter = null) {
@@ -11051,6 +11321,7 @@ export {
11051
11321
  LockIcon,
11052
11322
  MEETING_INVITE_KIND,
11053
11323
  MEETING_INVITE_VERSION,
11324
+ MEETING_RECORD_GRACE_MS,
11054
11325
  MEET_ANSWER_CONTEXT_EVENT,
11055
11326
  MEET_ANSWER_EVENTS,
11056
11327
  MEET_EVENTS,
@@ -11128,6 +11399,7 @@ export {
11128
11399
  asParticipantIdentity,
11129
11400
  asRoomName,
11130
11401
  asUserId,
11402
+ assembleMeetingRecord,
11131
11403
  assignedRoom,
11132
11404
  attendanceCsv,
11133
11405
  attendanceReport,
@@ -11157,6 +11429,7 @@ export {
11157
11429
  createMeetRepository,
11158
11430
  createMeetStore,
11159
11431
  createMeetingInviteHandler,
11432
+ createMeetingRecordCache,
11160
11433
  createMeetingSession,
11161
11434
  createMemoryDeviceStorage,
11162
11435
  createRecordingController,
@@ -11191,12 +11464,14 @@ export {
11191
11464
  loadMeetingActivities,
11192
11465
  loadMeetingChat,
11193
11466
  loadMeetingRecord,
11467
+ loadMeetingRecordParts,
11194
11468
  mapConnectionState,
11195
11469
  mapQuality,
11196
11470
  meetingInviteAction,
11197
11471
  meetingLength,
11198
11472
  meetingLink,
11199
11473
  meetingPath,
11474
+ meetingRecordCache,
11200
11475
  meetingSlug,
11201
11476
  meetingTopic,
11202
11477
  meetingWhen,