@ai-matrx/meet 0.7.1 → 0.7.3
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 +30 -0
- package/dist/index.cjs +471 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +268 -3
- package/dist/index.d.ts +268 -3
- package/dist/index.js +471 -37
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +474 -40
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +474 -40
- package/dist/react.js.map +1 -1
- package/package.json +4 -4
package/dist/react.cjs
CHANGED
|
@@ -116,6 +116,7 @@ __export(react_exports, {
|
|
|
116
116
|
TRANSCRIPTION_TOPIC: () => TRANSCRIPTION_TOPIC,
|
|
117
117
|
WifiLowIcon: () => WifiLowIcon,
|
|
118
118
|
absenceSentence: () => absenceSentence,
|
|
119
|
+
announceMeeting: () => announceMeeting,
|
|
119
120
|
applyRoomEvent: () => applyRoomEvent,
|
|
120
121
|
asCallId: () => asCallId,
|
|
121
122
|
asMeetingId: () => asMeetingId,
|
|
@@ -130,6 +131,7 @@ __export(react_exports, {
|
|
|
130
131
|
canModerateParticipant: () => canModerateParticipant,
|
|
131
132
|
canTransition: () => canTransition,
|
|
132
133
|
captionSegment: () => captionSegment,
|
|
134
|
+
changesPatch: () => changesPatch,
|
|
133
135
|
computeStage: () => computeStage,
|
|
134
136
|
countLabel: () => countLabel,
|
|
135
137
|
createCallCenter: () => createCallCenter,
|
|
@@ -174,6 +176,7 @@ __export(react_exports, {
|
|
|
174
176
|
mapQuality: () => mapQuality,
|
|
175
177
|
meetingInviteAction: () => meetingInviteAction,
|
|
176
178
|
meetingLink: () => meetingLink,
|
|
179
|
+
meetingPath: () => meetingPath,
|
|
177
180
|
meetingSlug: () => meetingSlug,
|
|
178
181
|
meetingTopic: () => meetingTopic,
|
|
179
182
|
meetingWhen: () => meetingWhen,
|
|
@@ -190,9 +193,15 @@ __export(react_exports, {
|
|
|
190
193
|
parseRoomToken: () => parseRoomToken,
|
|
191
194
|
participantSummary: () => participantSummary,
|
|
192
195
|
playableRecordingFileId: () => playableRecordingFileId,
|
|
196
|
+
projectInvitee: () => projectInvitee,
|
|
193
197
|
projectNote: () => projectNote,
|
|
198
|
+
projectOccurrence: () => projectOccurrence,
|
|
199
|
+
projectOverride: () => projectOverride,
|
|
194
200
|
projectParticipant: () => projectParticipant,
|
|
201
|
+
projectRsvpInvitation: () => projectRsvpInvitation,
|
|
195
202
|
projectSegment: () => projectSegment,
|
|
203
|
+
projectUpcoming: () => projectUpcoming,
|
|
204
|
+
pushMeetingToGoogleCalendar: () => pushMeetingToGoogleCalendar,
|
|
196
205
|
readServerRefusal: () => readServerRefusal,
|
|
197
206
|
readableTranscript: () => readableTranscript,
|
|
198
207
|
recordingLabel: () => recordingLabel,
|
|
@@ -200,6 +209,7 @@ __export(react_exports, {
|
|
|
200
209
|
roleOf: () => roleOf,
|
|
201
210
|
roomTopic: () => roomTopic,
|
|
202
211
|
setGuestRecordAccess: () => setGuestRecordAccess,
|
|
212
|
+
settingsPatch: () => settingsPatch,
|
|
203
213
|
snapshotParticipant: () => snapshotParticipant,
|
|
204
214
|
unavailableFrom: () => unavailableFrom,
|
|
205
215
|
useCalls: () => useCalls,
|
|
@@ -266,7 +276,7 @@ var MeetError = class extends Error {
|
|
|
266
276
|
};
|
|
267
277
|
var FORBIDDEN_CODES = /* @__PURE__ */ new Set(["42501", "PGRST301", "PGRST302"]);
|
|
268
278
|
var NOT_FOUND_CODES = /* @__PURE__ */ new Set(["PGRST116", "PGRST205"]);
|
|
269
|
-
var CONFLICT_CODES = /* @__PURE__ */ new Set(["23505"]);
|
|
279
|
+
var CONFLICT_CODES = /* @__PURE__ */ new Set(["23505", "40001", "55000"]);
|
|
270
280
|
var SESSION_MARKERS = [
|
|
271
281
|
"auth session missing",
|
|
272
282
|
"jwt expired",
|
|
@@ -424,8 +434,19 @@ var MEET_ROUTES = {
|
|
|
424
434
|
*/
|
|
425
435
|
record: "/api/v1/meet/record",
|
|
426
436
|
/** A host chooses what guests may read of ONE meeting (MRF-1). */
|
|
427
|
-
recordAccess: "/api/v1/meet/record/access"
|
|
437
|
+
recordAccess: "/api/v1/meet/record/access",
|
|
438
|
+
/**
|
|
439
|
+
* Meet wave 1 (0.8): bring every invitee up to date after a write — sends the
|
|
440
|
+
* invitation / update / cancellation emails with their `.ics` and re-queues
|
|
441
|
+
* reminders. Idempotent. `{meeting_id}` is substituted by `meetingPath`.
|
|
442
|
+
*/
|
|
443
|
+
meetingAnnounce: "/api/v1/meet/meetings/{meeting_id}/announce",
|
|
444
|
+
/** Put a one-off meeting on the caller's own Google Calendar (gated by the server). */
|
|
445
|
+
meetingGoogleCalendar: "/api/v1/meet/meetings/{meeting_id}/google-calendar"
|
|
428
446
|
};
|
|
447
|
+
function meetingPath(template, meetingId) {
|
|
448
|
+
return template.replace("{meeting_id}", encodeURIComponent(meetingId));
|
|
449
|
+
}
|
|
429
450
|
var ROOM_TOKEN_HEADER = "x-meet-room-token";
|
|
430
451
|
var REFRESH_RATIO = 0.8;
|
|
431
452
|
function readString(source, key) {
|
|
@@ -555,6 +576,19 @@ function createTokenClient(options) {
|
|
|
555
576
|
"The link is wrong or the meeting was deleted. Show the 'meeting not found' screen; a durable link that 404s is never a retry."
|
|
556
577
|
);
|
|
557
578
|
}
|
|
579
|
+
if (response.status === 410) {
|
|
580
|
+
let reason = "This meeting was cancelled.";
|
|
581
|
+
try {
|
|
582
|
+
const body = await response.json();
|
|
583
|
+
if (typeof body?.detail?.message === "string") reason = body.detail.message;
|
|
584
|
+
} catch {
|
|
585
|
+
}
|
|
586
|
+
throw new MeetError(
|
|
587
|
+
"cancelled",
|
|
588
|
+
reason,
|
|
589
|
+
"Nobody can join a cancelled meeting. Show the cancelled screen with this sentence; ask the host to schedule a new one."
|
|
590
|
+
);
|
|
591
|
+
}
|
|
558
592
|
if (response.status === 423) {
|
|
559
593
|
throw new MeetError(
|
|
560
594
|
"room-locked",
|
|
@@ -756,12 +790,12 @@ function createMeetAi(options) {
|
|
|
756
790
|
async function dispatch(route, body, operation) {
|
|
757
791
|
const response = await send({ path: route, body, operation, requireAuth: true });
|
|
758
792
|
if (!response.ok) {
|
|
759
|
-
const
|
|
760
|
-
options.store.patch({ noteTakerRefusal:
|
|
793
|
+
const refusal2 = await refusalFor(response, operation);
|
|
794
|
+
options.store.patch({ noteTakerRefusal: refusal2 });
|
|
761
795
|
throw new MeetError(
|
|
762
796
|
response.status === 403 ? "forbidden" : "transport",
|
|
763
|
-
|
|
764
|
-
|
|
797
|
+
refusal2.reason,
|
|
798
|
+
refusal2.remedy
|
|
765
799
|
);
|
|
766
800
|
}
|
|
767
801
|
options.store.patch({ noteTakerRefusal: null });
|
|
@@ -799,11 +833,11 @@ function createMeetAi(options) {
|
|
|
799
833
|
...signal !== void 0 ? { signal } : {}
|
|
800
834
|
});
|
|
801
835
|
if (!response.ok) {
|
|
802
|
-
const
|
|
836
|
+
const refusal2 = await refusalFor(response, "meet.ai.ask");
|
|
803
837
|
throw new MeetError(
|
|
804
838
|
response.status === 403 || response.status === 401 ? "forbidden" : response.status === 404 ? "not-found" : "transport",
|
|
805
|
-
|
|
806
|
-
|
|
839
|
+
refusal2.reason,
|
|
840
|
+
refusal2.remedy
|
|
807
841
|
);
|
|
808
842
|
}
|
|
809
843
|
const body = response.body;
|
|
@@ -1947,6 +1981,15 @@ function createMeetingSession(options) {
|
|
|
1947
1981
|
const { manager, repository, store, identity } = options;
|
|
1948
1982
|
let channel = null;
|
|
1949
1983
|
let meetingChannel = null;
|
|
1984
|
+
async function readMeeting(meetingId) {
|
|
1985
|
+
try {
|
|
1986
|
+
return await repository.meeting(meetingId);
|
|
1987
|
+
} catch (error) {
|
|
1988
|
+
const slug = store.snapshot().meeting?.slug;
|
|
1989
|
+
if (slug === void 0) throw error;
|
|
1990
|
+
return repository.meetingBySlug(slug);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1950
1993
|
function requireHostUser(operation) {
|
|
1951
1994
|
if (identity.userId === null || !isHostRole(effectiveRole(store.snapshot()))) {
|
|
1952
1995
|
throw new MeetError(
|
|
@@ -2027,7 +2070,7 @@ function createMeetingSession(options) {
|
|
|
2027
2070
|
onBackfill: async () => {
|
|
2028
2071
|
const meeting = store.snapshot().meeting;
|
|
2029
2072
|
if (meeting === null) return;
|
|
2030
|
-
const fresh = isGuest(identity) ? await repository.meetingBySlug(meeting.slug) : await
|
|
2073
|
+
const fresh = isGuest(identity) ? await repository.meetingBySlug(meeting.slug) : await readMeeting(meeting.id);
|
|
2031
2074
|
store.patch({ meeting: fresh, locked: fresh.locked });
|
|
2032
2075
|
}
|
|
2033
2076
|
});
|
|
@@ -2122,7 +2165,7 @@ function createMeetingSession(options) {
|
|
|
2122
2165
|
// a recovered surface from looking healthy and being wrong.
|
|
2123
2166
|
onBackfill: async () => {
|
|
2124
2167
|
const [meeting, transcript, notes, recordings, attendees] = await Promise.all([
|
|
2125
|
-
|
|
2168
|
+
readMeeting(meetingId),
|
|
2126
2169
|
repository.transcript(meetingId),
|
|
2127
2170
|
repository.notes(meetingId),
|
|
2128
2171
|
repository.recordings(meetingId),
|
|
@@ -2234,11 +2277,11 @@ function createMeetingSession(options) {
|
|
|
2234
2277
|
} catch {
|
|
2235
2278
|
body = null;
|
|
2236
2279
|
}
|
|
2237
|
-
const
|
|
2280
|
+
const refusal2 = readServerRefusal(body);
|
|
2238
2281
|
throw new MeetError(
|
|
2239
2282
|
response.status === 403 ? "forbidden" : "transport",
|
|
2240
|
-
|
|
2241
|
-
|
|
2283
|
+
refusal2?.reason ?? `meet.endForEveryone: the server answered ${response.status}`,
|
|
2284
|
+
refusal2?.remedy !== void 0 && refusal2.remedy.length > 0 ? refusal2.remedy : "The meeting is still running. Only a host may end it, and the server re-checks that \u2014 being a host on this screen is not the decision."
|
|
2242
2285
|
);
|
|
2243
2286
|
}
|
|
2244
2287
|
let payload = null;
|
|
@@ -2281,7 +2324,11 @@ var TABLES = {
|
|
|
2281
2324
|
invites: "meet_call_invites",
|
|
2282
2325
|
recordings: "meet_recordings",
|
|
2283
2326
|
transcripts: "meet_transcript_segments",
|
|
2284
|
-
notes: "meet_notes"
|
|
2327
|
+
notes: "meet_notes",
|
|
2328
|
+
/** Wave 1 (0.8): who a meeting was sent to, and what they answered. */
|
|
2329
|
+
invitees: "meet_invitees",
|
|
2330
|
+
/** Wave 1 (0.8): one occurrence of a series cancelled or moved. */
|
|
2331
|
+
occurrenceOverrides: "meet_occurrence_overrides"
|
|
2285
2332
|
};
|
|
2286
2333
|
var RPCS = {
|
|
2287
2334
|
/** Atomic: create the invite row and stamp its expiry in one statement. */
|
|
@@ -2297,10 +2344,41 @@ var RPCS = {
|
|
|
2297
2344
|
admit: "meet_admit_participant",
|
|
2298
2345
|
setLock: "meet_set_lock",
|
|
2299
2346
|
endMeeting: "meet_end_meeting",
|
|
2300
|
-
recordConsent: "meet_record_consent"
|
|
2347
|
+
recordConsent: "meet_record_consent",
|
|
2348
|
+
/*
|
|
2349
|
+
* ── MEET WAVE 1 — management (0.8). Every write is a SECURITY DEFINER door
|
|
2350
|
+
* authorized by the meeting's host or a real iam grant (editor to change,
|
|
2351
|
+
* admin = co-host to archive or name a co-host) — never an organization
|
|
2352
|
+
* match. After any of these writes, call `announceMeeting` so the server
|
|
2353
|
+
* sends invitations / updates / cancellations and re-queues reminders.
|
|
2354
|
+
*/
|
|
2355
|
+
/** Schedule with every setting at create; unset settings come from the knobs. */
|
|
2356
|
+
scheduleMeeting: "meet_schedule_meeting",
|
|
2357
|
+
/** Edit / reschedule — a JSON patch with a version compare-and-swap. */
|
|
2358
|
+
updateMeeting: "meet_update_meeting",
|
|
2359
|
+
/** Cancel is a state (`cancelled_at`); the link keeps resolving. */
|
|
2360
|
+
cancelMeeting: "meet_cancel_meeting",
|
|
2361
|
+
/** Archive (soft delete) — the invitations and exceptions cascade. */
|
|
2362
|
+
archiveMeeting: "meet_archive_meeting",
|
|
2363
|
+
restoreMeeting: "meet_restore_meeting",
|
|
2364
|
+
/** Cancel, move or restore ONE occurrence of a series by its original start. */
|
|
2365
|
+
setOccurrence: "meet_set_occurrence",
|
|
2366
|
+
addInvitees: "meet_add_invitees",
|
|
2367
|
+
setInviteeRole: "meet_set_invitee_role",
|
|
2368
|
+
removeInvitee: "meet_remove_invitee",
|
|
2369
|
+
/** A signed-in invitee answers for themselves. */
|
|
2370
|
+
respond: "meet_respond",
|
|
2371
|
+
/** The emailed RSVP link (no account): read and answer. */
|
|
2372
|
+
invitationByToken: "meet_invitation_by_token",
|
|
2373
|
+
respondByToken: "meet_respond_by_token",
|
|
2374
|
+
/** One meeting's occurrences between two instants (INVOKER — the reader's RLS). */
|
|
2375
|
+
meetingOccurrences: "meet_meeting_occurrences",
|
|
2376
|
+
/** Every occurrence the reader can see between two instants — the Upcoming list. */
|
|
2377
|
+
occurrencesBetween: "meet_occurrences_between"
|
|
2301
2378
|
};
|
|
2302
2379
|
var VOID_RPCS = [RPCS.admit, RPCS.recordConsent];
|
|
2303
|
-
var MEETING_COLUMNS = "id,organization_id,room_name,slug,title,kind,host_user_id,scheduled_for,scheduled_duration_minutes,started_at,ended_at,locked,lobby_enabled,recording_policy,ai_enabled,metadata";
|
|
2380
|
+
var MEETING_COLUMNS = "id,organization_id,room_name,slug,title,kind,host_user_id,scheduled_for,scheduled_duration_minutes,started_at,ended_at,locked,lobby_enabled,recording_policy,ai_enabled,metadata,time_zone,agenda,recurrence_rule,join_before_host,cancelled_at,cancellation_reason,deleted_at,calendar_sequence,version";
|
|
2381
|
+
var INVITEE_COLUMNS = "id,meeting_id,invitee_user_id,email,display_name,role,rsvp_state,responded_at,rsvp_note,last_sent_sequence,last_sent_at";
|
|
2304
2382
|
var RECORDING_COLUMNS = "id,meeting_id,state,started_at,ended_at,started_by,file_id,failure_reason";
|
|
2305
2383
|
var SEGMENT_COLUMNS = "id,meeting_id,identity,speaker,text,started_at,is_final,metadata";
|
|
2306
2384
|
var NOTE_COLUMNS = "id,meeting_id,text,kind,assignee_user_id,created_at,metadata";
|
|
@@ -2398,6 +2476,138 @@ function projectNote(row) {
|
|
|
2398
2476
|
source: "record"
|
|
2399
2477
|
};
|
|
2400
2478
|
}
|
|
2479
|
+
var RSVP_STATES = ["needs_action", "accepted", "declined", "tentative"];
|
|
2480
|
+
var OCCURRENCE_STATES = ["scheduled", "moved", "cancelled"];
|
|
2481
|
+
function rsvpState(value) {
|
|
2482
|
+
return RSVP_STATES.includes(value) ? value : "needs_action";
|
|
2483
|
+
}
|
|
2484
|
+
function num(row, key) {
|
|
2485
|
+
const value = row[key];
|
|
2486
|
+
return typeof value === "number" ? value : null;
|
|
2487
|
+
}
|
|
2488
|
+
function when(row, key) {
|
|
2489
|
+
const value = row[key];
|
|
2490
|
+
if (value instanceof Date) return value.toISOString();
|
|
2491
|
+
return text(row, key);
|
|
2492
|
+
}
|
|
2493
|
+
function projectInvitee(row) {
|
|
2494
|
+
const operation = "meet.projectInvitee";
|
|
2495
|
+
const userId = text(row, "invitee_user_id");
|
|
2496
|
+
return {
|
|
2497
|
+
id: requireText(row, "id", operation),
|
|
2498
|
+
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
2499
|
+
userId: userId === null ? null : asUserId(userId),
|
|
2500
|
+
email: text(row, "email"),
|
|
2501
|
+
displayName: text(row, "display_name"),
|
|
2502
|
+
role: text(row, "role") === "cohost" ? "cohost" : "invitee",
|
|
2503
|
+
rsvpState: rsvpState(text(row, "rsvp_state")),
|
|
2504
|
+
respondedAt: when(row, "responded_at"),
|
|
2505
|
+
rsvpNote: text(row, "rsvp_note"),
|
|
2506
|
+
lastSentSequence: num(row, "last_sent_sequence"),
|
|
2507
|
+
lastSentAt: when(row, "last_sent_at")
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
function projectOccurrence(row) {
|
|
2511
|
+
const operation = "meet.projectOccurrence";
|
|
2512
|
+
const state = text(row, "state");
|
|
2513
|
+
return {
|
|
2514
|
+
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
2515
|
+
originalStart: when(row, "original_start") ?? requireText(row, "original_start", operation),
|
|
2516
|
+
occurrenceStart: when(row, "occurrence_start") ?? requireText(row, "occurrence_start", operation),
|
|
2517
|
+
durationMinutes: num(row, "duration_minutes"),
|
|
2518
|
+
// An unknown state is shown as scheduled, never dropped: the row is real.
|
|
2519
|
+
state: OCCURRENCE_STATES.includes(state) ? state : "scheduled",
|
|
2520
|
+
sequence: num(row, "sequence") ?? 0
|
|
2521
|
+
};
|
|
2522
|
+
}
|
|
2523
|
+
function projectUpcoming(row) {
|
|
2524
|
+
const operation = "meet.projectUpcoming";
|
|
2525
|
+
const kind = text(row, "kind");
|
|
2526
|
+
const myRole = text(row, "my_role");
|
|
2527
|
+
const myRsvp = text(row, "my_rsvp");
|
|
2528
|
+
return {
|
|
2529
|
+
...projectOccurrence(row),
|
|
2530
|
+
organizationId: asOrganizationId(requireText(row, "organization_id", operation)),
|
|
2531
|
+
title: text(row, "title") ?? "Meeting",
|
|
2532
|
+
slug: requireText(row, "slug", operation),
|
|
2533
|
+
kind: kind === "scheduled" || kind === "recurring" ? kind : "instant",
|
|
2534
|
+
hostUserId: asUserId(requireText(row, "host_user_id", operation)),
|
|
2535
|
+
timeZone: text(row, "time_zone") ?? "UTC",
|
|
2536
|
+
meetingCancelled: bool(row, "meeting_cancelled", false),
|
|
2537
|
+
myRsvp: myRsvp === null ? null : rsvpState(myRsvp),
|
|
2538
|
+
myRole: myRole === "host" || myRole === "cohost" || myRole === "invitee" ? myRole : null
|
|
2539
|
+
};
|
|
2540
|
+
}
|
|
2541
|
+
function projectOverride(row) {
|
|
2542
|
+
const operation = "meet.projectOverride";
|
|
2543
|
+
return {
|
|
2544
|
+
id: requireText(row, "id", operation),
|
|
2545
|
+
meetingId: asMeetingId(requireText(row, "meeting_id", operation)),
|
|
2546
|
+
originalStart: when(row, "original_start") ?? requireText(row, "original_start", operation),
|
|
2547
|
+
state: text(row, "state") === "moved" ? "moved" : "cancelled",
|
|
2548
|
+
newStart: when(row, "new_start"),
|
|
2549
|
+
newDurationMinutes: num(row, "new_duration_minutes"),
|
|
2550
|
+
reason: text(row, "reason"),
|
|
2551
|
+
calendarSequence: num(row, "calendar_sequence") ?? 0,
|
|
2552
|
+
deletedAt: when(row, "deleted_at")
|
|
2553
|
+
};
|
|
2554
|
+
}
|
|
2555
|
+
function projectRsvpInvitation(body) {
|
|
2556
|
+
const operation = "meet.projectRsvpInvitation";
|
|
2557
|
+
if (typeof body !== "object" || body === null) {
|
|
2558
|
+
throw invalidResponse(operation, "the RSVP door returned no object");
|
|
2559
|
+
}
|
|
2560
|
+
const row = body;
|
|
2561
|
+
if (row["ok"] !== true) {
|
|
2562
|
+
return {
|
|
2563
|
+
ok: false,
|
|
2564
|
+
message: text(row, "message") ?? "This invitation link is no longer valid \u2014 ask the host to send it again."
|
|
2565
|
+
};
|
|
2566
|
+
}
|
|
2567
|
+
const meeting = row["meeting"] ?? {};
|
|
2568
|
+
const invitee = row["invitee"] ?? {};
|
|
2569
|
+
return {
|
|
2570
|
+
ok: true,
|
|
2571
|
+
meeting: {
|
|
2572
|
+
title: text(meeting, "title") ?? "Meeting",
|
|
2573
|
+
slug: requireText(meeting, "slug", operation),
|
|
2574
|
+
scheduledFor: when(meeting, "scheduled_for"),
|
|
2575
|
+
durationMinutes: num(meeting, "duration_minutes"),
|
|
2576
|
+
timeZone: text(meeting, "time_zone") ?? "UTC",
|
|
2577
|
+
agenda: text(meeting, "agenda"),
|
|
2578
|
+
recurrenceRule: text(meeting, "recurrence_rule"),
|
|
2579
|
+
cancelledAt: when(meeting, "cancelled_at"),
|
|
2580
|
+
cancellationReason: text(meeting, "cancellation_reason"),
|
|
2581
|
+
endedAt: when(meeting, "ended_at")
|
|
2582
|
+
},
|
|
2583
|
+
invitee: {
|
|
2584
|
+
displayName: text(invitee, "display_name"),
|
|
2585
|
+
email: text(invitee, "email"),
|
|
2586
|
+
rsvpState: rsvpState(text(invitee, "rsvp_state")),
|
|
2587
|
+
respondedAt: when(invitee, "responded_at")
|
|
2588
|
+
}
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2591
|
+
function settingsPatch(settings) {
|
|
2592
|
+
const patch = {};
|
|
2593
|
+
if (settings.lobbyEnabled !== void 0) patch["lobby_enabled"] = settings.lobbyEnabled;
|
|
2594
|
+
if (settings.recordingPolicy !== void 0) patch["recording_policy"] = settings.recordingPolicy;
|
|
2595
|
+
if (settings.aiEnabled !== void 0) patch["ai_enabled"] = settings.aiEnabled;
|
|
2596
|
+
if (settings.joinBeforeHost !== void 0) patch["join_before_host"] = settings.joinBeforeHost;
|
|
2597
|
+
return patch;
|
|
2598
|
+
}
|
|
2599
|
+
function changesPatch(changes) {
|
|
2600
|
+
const patch = settingsPatch(changes);
|
|
2601
|
+
if (changes.title !== void 0) patch["title"] = changes.title;
|
|
2602
|
+
if (changes.agenda !== void 0) patch["agenda"] = changes.agenda;
|
|
2603
|
+
if (changes.timeZone !== void 0) patch["time_zone"] = changes.timeZone;
|
|
2604
|
+
if (changes.scheduledFor !== void 0) patch["scheduled_for"] = changes.scheduledFor;
|
|
2605
|
+
if (changes.scheduledDurationMinutes !== void 0) {
|
|
2606
|
+
patch["scheduled_duration_minutes"] = changes.scheduledDurationMinutes;
|
|
2607
|
+
}
|
|
2608
|
+
if (changes.recurrenceRule !== void 0) patch["recurrence_rule"] = changes.recurrenceRule;
|
|
2609
|
+
return patch;
|
|
2610
|
+
}
|
|
2401
2611
|
function createMeetRepository(options) {
|
|
2402
2612
|
const db = options.client.schema(MEET_SCHEMA);
|
|
2403
2613
|
async function guardVoid(operation, run) {
|
|
@@ -2467,7 +2677,16 @@ function createMeetRepository(options) {
|
|
|
2467
2677
|
lobbyEnabled: bool(row, "lobby_enabled", true),
|
|
2468
2678
|
recordingPolicy: policy === "disabled" || policy === "always-on" ? policy : "host-controlled",
|
|
2469
2679
|
aiEnabled: bool(row, "ai_enabled", true),
|
|
2470
|
-
metadata: typeof metadata === "object" && metadata !== null && !Array.isArray(metadata) ? metadata : {}
|
|
2680
|
+
metadata: typeof metadata === "object" && metadata !== null && !Array.isArray(metadata) ? metadata : {},
|
|
2681
|
+
timeZone: text(row, "time_zone") ?? "UTC",
|
|
2682
|
+
agenda: text(row, "agenda"),
|
|
2683
|
+
recurrenceRule: text(row, "recurrence_rule"),
|
|
2684
|
+
joinBeforeHost: bool(row, "join_before_host", true),
|
|
2685
|
+
cancelledAt: text(row, "cancelled_at"),
|
|
2686
|
+
cancellationReason: text(row, "cancellation_reason"),
|
|
2687
|
+
deletedAt: text(row, "deleted_at"),
|
|
2688
|
+
calendarSequence: typeof row["calendar_sequence"] === "number" ? row["calendar_sequence"] : 0,
|
|
2689
|
+
version: typeof row["version"] === "number" ? row["version"] : 1
|
|
2471
2690
|
};
|
|
2472
2691
|
}
|
|
2473
2692
|
function projectRecording(row) {
|
|
@@ -2554,6 +2773,170 @@ function createMeetRepository(options) {
|
|
|
2554
2773
|
projectNote,
|
|
2555
2774
|
projectRecording,
|
|
2556
2775
|
projectAttendee,
|
|
2776
|
+
projectInvitee,
|
|
2777
|
+
async scheduleMeeting(input) {
|
|
2778
|
+
requireOrg(input.organizationId, "meet.scheduleMeeting");
|
|
2779
|
+
const row = await guard(
|
|
2780
|
+
"meet.scheduleMeeting",
|
|
2781
|
+
() => db.rpc(RPCS.scheduleMeeting, {
|
|
2782
|
+
p_organization_id: input.organizationId,
|
|
2783
|
+
p_host_user_id: input.hostUserId,
|
|
2784
|
+
p_title: input.title,
|
|
2785
|
+
p_scheduled_for: input.scheduledFor,
|
|
2786
|
+
p_time_zone: input.timeZone,
|
|
2787
|
+
p_duration_minutes: input.durationMinutes ?? null,
|
|
2788
|
+
p_agenda: input.agenda ?? null,
|
|
2789
|
+
p_recurrence_rule: input.recurrenceRule ?? null,
|
|
2790
|
+
p_settings: settingsPatch(input.settings ?? {})
|
|
2791
|
+
})
|
|
2792
|
+
);
|
|
2793
|
+
return projectMeeting(row);
|
|
2794
|
+
},
|
|
2795
|
+
async updateMeeting(meetingId, changes, options2 = {}) {
|
|
2796
|
+
const row = await guard(
|
|
2797
|
+
"meet.updateMeeting",
|
|
2798
|
+
() => db.rpc(RPCS.updateMeeting, {
|
|
2799
|
+
p_meeting_id: meetingId,
|
|
2800
|
+
p_changes: changesPatch(changes),
|
|
2801
|
+
p_expected_version: options2.expectedVersion ?? null,
|
|
2802
|
+
p_by_user_id: options2.byUserId ?? null
|
|
2803
|
+
})
|
|
2804
|
+
);
|
|
2805
|
+
return projectMeeting(row);
|
|
2806
|
+
},
|
|
2807
|
+
async cancelMeeting(meetingId, reason, byUserId = null) {
|
|
2808
|
+
const row = await guard(
|
|
2809
|
+
"meet.cancelMeeting",
|
|
2810
|
+
() => db.rpc(RPCS.cancelMeeting, {
|
|
2811
|
+
p_meeting_id: meetingId,
|
|
2812
|
+
p_reason: reason,
|
|
2813
|
+
p_by_user_id: byUserId
|
|
2814
|
+
})
|
|
2815
|
+
);
|
|
2816
|
+
return projectMeeting(row);
|
|
2817
|
+
},
|
|
2818
|
+
async archiveMeeting(meetingId, byUserId = null) {
|
|
2819
|
+
const row = await guard(
|
|
2820
|
+
"meet.archiveMeeting",
|
|
2821
|
+
() => db.rpc(RPCS.archiveMeeting, { p_meeting_id: meetingId, p_by_user_id: byUserId })
|
|
2822
|
+
);
|
|
2823
|
+
return projectMeeting(row);
|
|
2824
|
+
},
|
|
2825
|
+
async restoreMeeting(meetingId, byUserId = null) {
|
|
2826
|
+
const row = await guard(
|
|
2827
|
+
"meet.restoreMeeting",
|
|
2828
|
+
() => db.rpc(RPCS.restoreMeeting, { p_meeting_id: meetingId, p_by_user_id: byUserId })
|
|
2829
|
+
);
|
|
2830
|
+
return projectMeeting(row);
|
|
2831
|
+
},
|
|
2832
|
+
async setOccurrence(args) {
|
|
2833
|
+
const row = await guard(
|
|
2834
|
+
"meet.setOccurrence",
|
|
2835
|
+
() => db.rpc(RPCS.setOccurrence, {
|
|
2836
|
+
p_meeting_id: args.meetingId,
|
|
2837
|
+
p_original_start: args.originalStart,
|
|
2838
|
+
p_action: args.action,
|
|
2839
|
+
p_new_start: args.newStart ?? null,
|
|
2840
|
+
p_new_duration_minutes: args.newDurationMinutes ?? null,
|
|
2841
|
+
p_reason: args.reason ?? null,
|
|
2842
|
+
p_by_user_id: args.byUserId ?? null
|
|
2843
|
+
})
|
|
2844
|
+
);
|
|
2845
|
+
return projectOverride(row);
|
|
2846
|
+
},
|
|
2847
|
+
async meetingOccurrences(meetingId, { from, to, limit = 200 }) {
|
|
2848
|
+
const rows = await guard(
|
|
2849
|
+
"meet.meetingOccurrences",
|
|
2850
|
+
() => db.rpc(RPCS.meetingOccurrences, {
|
|
2851
|
+
p_meeting_id: meetingId,
|
|
2852
|
+
p_from: from,
|
|
2853
|
+
p_to: to,
|
|
2854
|
+
p_limit: limit
|
|
2855
|
+
})
|
|
2856
|
+
);
|
|
2857
|
+
return rows.map(projectOccurrence);
|
|
2858
|
+
},
|
|
2859
|
+
async occurrencesBetween({ from, to, organizationId = null, limit = 500 }) {
|
|
2860
|
+
const rows = await guard(
|
|
2861
|
+
"meet.occurrencesBetween",
|
|
2862
|
+
() => db.rpc(RPCS.occurrencesBetween, {
|
|
2863
|
+
p_from: from,
|
|
2864
|
+
p_to: to,
|
|
2865
|
+
p_organization_id: organizationId,
|
|
2866
|
+
p_limit: limit
|
|
2867
|
+
})
|
|
2868
|
+
);
|
|
2869
|
+
return rows.map(projectUpcoming);
|
|
2870
|
+
},
|
|
2871
|
+
async invitees(meetingId) {
|
|
2872
|
+
const response = await db.from(TABLES.invitees).select(INVITEE_COLUMNS).eq("meeting_id", meetingId).is("deleted_at", null).order("created_at", { ascending: true }).order("id", { ascending: true });
|
|
2873
|
+
if (response.error !== null) throw normalizeMeetError(response.error, "meet.invitees");
|
|
2874
|
+
return (response.data ?? []).map(projectInvitee);
|
|
2875
|
+
},
|
|
2876
|
+
async addInvitees(meetingId, people, byUserId = null) {
|
|
2877
|
+
const rows = await guard(
|
|
2878
|
+
"meet.addInvitees",
|
|
2879
|
+
() => db.rpc(RPCS.addInvitees, {
|
|
2880
|
+
p_meeting_id: meetingId,
|
|
2881
|
+
p_invitees: people.map((person) => ({
|
|
2882
|
+
...person.userId !== void 0 ? { user_id: person.userId } : {},
|
|
2883
|
+
...person.email !== void 0 ? { email: person.email } : {},
|
|
2884
|
+
...person.displayName !== void 0 ? { display_name: person.displayName } : {},
|
|
2885
|
+
...person.role !== void 0 ? { role: person.role } : {}
|
|
2886
|
+
})),
|
|
2887
|
+
p_by_user_id: byUserId
|
|
2888
|
+
})
|
|
2889
|
+
);
|
|
2890
|
+
return rows.map(projectInvitee);
|
|
2891
|
+
},
|
|
2892
|
+
async setInviteeRole(inviteeId, role, byUserId = null) {
|
|
2893
|
+
const row = await guard(
|
|
2894
|
+
"meet.setInviteeRole",
|
|
2895
|
+
() => db.rpc(RPCS.setInviteeRole, {
|
|
2896
|
+
p_invitee_id: inviteeId,
|
|
2897
|
+
p_role: role,
|
|
2898
|
+
p_by_user_id: byUserId
|
|
2899
|
+
})
|
|
2900
|
+
);
|
|
2901
|
+
return projectInvitee(row);
|
|
2902
|
+
},
|
|
2903
|
+
async removeInvitee(inviteeId, byUserId = null) {
|
|
2904
|
+
const row = await guard(
|
|
2905
|
+
"meet.removeInvitee",
|
|
2906
|
+
() => db.rpc(RPCS.removeInvitee, { p_invitee_id: inviteeId, p_by_user_id: byUserId })
|
|
2907
|
+
);
|
|
2908
|
+
return projectInvitee(row);
|
|
2909
|
+
},
|
|
2910
|
+
async respond(meetingId, answer, note = null) {
|
|
2911
|
+
const row = await guard(
|
|
2912
|
+
"meet.respond",
|
|
2913
|
+
() => db.rpc(RPCS.respond, {
|
|
2914
|
+
p_meeting_id: meetingId,
|
|
2915
|
+
p_response: answer,
|
|
2916
|
+
p_note: note,
|
|
2917
|
+
p_by_user_id: null
|
|
2918
|
+
})
|
|
2919
|
+
);
|
|
2920
|
+
return projectInvitee(row);
|
|
2921
|
+
},
|
|
2922
|
+
async invitationByToken(secret) {
|
|
2923
|
+
const body = await guard(
|
|
2924
|
+
"meet.invitationByToken",
|
|
2925
|
+
() => db.rpc(RPCS.invitationByToken, { p_secret: secret })
|
|
2926
|
+
);
|
|
2927
|
+
return projectRsvpInvitation(body);
|
|
2928
|
+
},
|
|
2929
|
+
async respondByToken(secret, answer, note = null) {
|
|
2930
|
+
const body = await guard(
|
|
2931
|
+
"meet.respondByToken",
|
|
2932
|
+
() => db.rpc(RPCS.respondByToken, {
|
|
2933
|
+
p_secret: secret,
|
|
2934
|
+
p_response: answer,
|
|
2935
|
+
p_note: note
|
|
2936
|
+
})
|
|
2937
|
+
);
|
|
2938
|
+
return projectRsvpInvitation(body);
|
|
2939
|
+
},
|
|
2557
2940
|
async attendees(meetingId) {
|
|
2558
2941
|
const response = await db.from(TABLES.participants).select(ATTENDEE_COLUMNS).eq("meeting_id", meetingId).order("joined_at", { ascending: true }).order("id", { ascending: true });
|
|
2559
2942
|
if (response.error !== null) throw normalizeMeetError(response.error, "meet.attendees");
|
|
@@ -2981,14 +3364,14 @@ function noteTakerStatus(args) {
|
|
|
2981
3364
|
const row = typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
|
|
2982
3365
|
const recorded = readState(row["state"]);
|
|
2983
3366
|
const detail = typeof row["reason"] === "string" && row["reason"].length > 0 ? row["reason"] : null;
|
|
2984
|
-
const
|
|
3367
|
+
const refusal2 = args.refusal ?? null;
|
|
2985
3368
|
if (recorded === null) {
|
|
2986
|
-
return { state: "absent", detail, present, refusal };
|
|
3369
|
+
return { state: "absent", detail, present, refusal: refusal2 };
|
|
2987
3370
|
}
|
|
2988
3371
|
if (recorded === "transcribing" && !present) {
|
|
2989
|
-
return { state: "handoff_pending", detail, present, refusal };
|
|
3372
|
+
return { state: "handoff_pending", detail, present, refusal: refusal2 };
|
|
2990
3373
|
}
|
|
2991
|
-
return { state: recorded, detail, present, refusal };
|
|
3374
|
+
return { state: recorded, detail, present, refusal: refusal2 };
|
|
2992
3375
|
}
|
|
2993
3376
|
function noteTakerLabel(status) {
|
|
2994
3377
|
switch (status.state) {
|
|
@@ -4013,11 +4396,11 @@ function computeStage(args) {
|
|
|
4013
4396
|
presenting: sharer !== null
|
|
4014
4397
|
};
|
|
4015
4398
|
}
|
|
4016
|
-
function gridColumns(
|
|
4017
|
-
if (
|
|
4018
|
-
if (
|
|
4019
|
-
if (
|
|
4020
|
-
if (
|
|
4399
|
+
function gridColumns(count2) {
|
|
4400
|
+
if (count2 <= 1) return 1;
|
|
4401
|
+
if (count2 <= 4) return 2;
|
|
4402
|
+
if (count2 <= 9) return 3;
|
|
4403
|
+
if (count2 <= 16) return 4;
|
|
4021
4404
|
return 5;
|
|
4022
4405
|
}
|
|
4023
4406
|
|
|
@@ -4191,7 +4574,7 @@ function meetingWhen(meeting, locale) {
|
|
|
4191
4574
|
if (start === null) return "Time not recorded";
|
|
4192
4575
|
const startedAt = new Date(start);
|
|
4193
4576
|
if (Number.isNaN(startedAt.getTime())) return "Time not recorded";
|
|
4194
|
-
const
|
|
4577
|
+
const when2 = startedAt.toLocaleString(locale, {
|
|
4195
4578
|
weekday: "long",
|
|
4196
4579
|
year: "numeric",
|
|
4197
4580
|
month: "long",
|
|
@@ -4199,11 +4582,11 @@ function meetingWhen(meeting, locale) {
|
|
|
4199
4582
|
hour: "numeric",
|
|
4200
4583
|
minute: "2-digit"
|
|
4201
4584
|
});
|
|
4202
|
-
if (meeting.endedAt === null || meeting.startedAt === null) return
|
|
4585
|
+
if (meeting.endedAt === null || meeting.startedAt === null) return when2;
|
|
4203
4586
|
const endedAt = new Date(meeting.endedAt);
|
|
4204
|
-
if (Number.isNaN(endedAt.getTime())) return
|
|
4587
|
+
if (Number.isNaN(endedAt.getTime())) return when2;
|
|
4205
4588
|
const elapsedMs = endedAt.getTime() - startedAt.getTime();
|
|
4206
|
-
return `${
|
|
4589
|
+
return `${when2} \xB7 ${(0, import_format.formatDurationMs)(elapsedMs, { style: "long" })}`;
|
|
4207
4590
|
}
|
|
4208
4591
|
var GUEST_RECORD_ACCESS_LEVELS = [
|
|
4209
4592
|
"none",
|
|
@@ -4310,8 +4693,8 @@ async function loadGuestMeetingRecord(args) {
|
|
|
4310
4693
|
);
|
|
4311
4694
|
}
|
|
4312
4695
|
if (!response.ok) {
|
|
4313
|
-
const
|
|
4314
|
-
return refusedBundle(meeting,
|
|
4696
|
+
const refusal2 = await readRefusal(response);
|
|
4697
|
+
return refusedBundle(meeting, refusal2.message, refusal2.remedy);
|
|
4315
4698
|
}
|
|
4316
4699
|
const body = await response.json();
|
|
4317
4700
|
const payload = typeof body["data"] === "object" && body["data"] !== null ? body["data"] : body;
|
|
@@ -4402,8 +4785,8 @@ async function setGuestRecordAccess(args) {
|
|
|
4402
4785
|
}
|
|
4403
4786
|
});
|
|
4404
4787
|
if (!response.ok) {
|
|
4405
|
-
const
|
|
4406
|
-
throw new MeetError("forbidden",
|
|
4788
|
+
const refusal2 = await readRefusal(response);
|
|
4789
|
+
throw new MeetError("forbidden", refusal2.message, refusal2.remedy);
|
|
4407
4790
|
}
|
|
4408
4791
|
const body = await response.json();
|
|
4409
4792
|
const payload = typeof body["data"] === "object" && body["data"] !== null ? body["data"] : body;
|
|
@@ -5070,8 +5453,8 @@ function callStateLabel(state, outgoing) {
|
|
|
5070
5453
|
return "Call";
|
|
5071
5454
|
}
|
|
5072
5455
|
}
|
|
5073
|
-
function countLabel(
|
|
5074
|
-
return `${
|
|
5456
|
+
function countLabel(count2, singular, plural = `${singular}s`) {
|
|
5457
|
+
return `${count2} ${count2 === 1 ? singular : plural}`;
|
|
5075
5458
|
}
|
|
5076
5459
|
|
|
5077
5460
|
// src/react/icons.tsx
|
|
@@ -6129,7 +6512,7 @@ function ScheduleMeetingBody({
|
|
|
6129
6512
|
host
|
|
6130
6513
|
}) {
|
|
6131
6514
|
const [title, setTitle] = (0, import_react4.useState)("");
|
|
6132
|
-
const [
|
|
6515
|
+
const [when2, setWhen] = (0, import_react4.useState)("");
|
|
6133
6516
|
const [kind, setKind] = (0, import_react4.useState)("scheduled");
|
|
6134
6517
|
const [busy, setBusy] = (0, import_react4.useState)(false);
|
|
6135
6518
|
const [link, setLink] = (0, import_react4.useState)(null);
|
|
@@ -6149,7 +6532,7 @@ function ScheduleMeetingBody({
|
|
|
6149
6532
|
hostUserId: host.identity.userId,
|
|
6150
6533
|
title: title.trim(),
|
|
6151
6534
|
kind,
|
|
6152
|
-
scheduledFor:
|
|
6535
|
+
scheduledFor: when2.length > 0 ? new Date(when2).toISOString() : null
|
|
6153
6536
|
}).then((meeting) => {
|
|
6154
6537
|
setLink(meetingLink(appBaseUrl, meeting.slug));
|
|
6155
6538
|
onScheduled?.(meeting.slug);
|
|
@@ -6179,7 +6562,7 @@ function ScheduleMeetingBody({
|
|
|
6179
6562
|
{
|
|
6180
6563
|
className: "mx-meet__input",
|
|
6181
6564
|
type: "datetime-local",
|
|
6182
|
-
value:
|
|
6565
|
+
value: when2,
|
|
6183
6566
|
onChange: (event) => setWhen(event.target.value)
|
|
6184
6567
|
}
|
|
6185
6568
|
)
|
|
@@ -6759,4 +7142,55 @@ function createMeetingInviteHandler(options) {
|
|
|
6759
7142
|
}
|
|
6760
7143
|
};
|
|
6761
7144
|
}
|
|
7145
|
+
|
|
7146
|
+
// src/core/management.ts
|
|
7147
|
+
async function refusal(response, operation) {
|
|
7148
|
+
let body = null;
|
|
7149
|
+
try {
|
|
7150
|
+
body = await response.json();
|
|
7151
|
+
} catch {
|
|
7152
|
+
body = null;
|
|
7153
|
+
}
|
|
7154
|
+
const said = readServerRefusal(body);
|
|
7155
|
+
return new MeetError(
|
|
7156
|
+
response.status === 403 || response.status === 401 ? "forbidden" : response.status === 404 ? "not-found" : response.status === 409 ? "conflict" : "transport",
|
|
7157
|
+
`${operation}: ${said?.reason ?? `the server answered ${response.status}`}`,
|
|
7158
|
+
said?.remedy || "The meeting itself is saved \u2014 only the telling failed. Try again; the call is idempotent."
|
|
7159
|
+
);
|
|
7160
|
+
}
|
|
7161
|
+
function count(body, key) {
|
|
7162
|
+
const value = body[key];
|
|
7163
|
+
return typeof value === "number" ? value : 0;
|
|
7164
|
+
}
|
|
7165
|
+
async function announceMeeting(api, meetingId) {
|
|
7166
|
+
const operation = "meet.announceMeeting";
|
|
7167
|
+
const response = await api.request({
|
|
7168
|
+
path: meetingPath(MEET_ROUTES.meetingAnnounce, meetingId),
|
|
7169
|
+
method: "POST",
|
|
7170
|
+
requireAuth: true,
|
|
7171
|
+
operation
|
|
7172
|
+
});
|
|
7173
|
+
if (!response.ok) throw await refusal(response, operation);
|
|
7174
|
+
const body = await response.json();
|
|
7175
|
+
return {
|
|
7176
|
+
invitations: count(body, "invitations"),
|
|
7177
|
+
updates: count(body, "updates"),
|
|
7178
|
+
cancellations: count(body, "cancellations"),
|
|
7179
|
+
alreadyCurrent: count(body, "already_current"),
|
|
7180
|
+
remindersQueued: count(body, "reminders_queued"),
|
|
7181
|
+
remindersCancelled: count(body, "reminders_cancelled")
|
|
7182
|
+
};
|
|
7183
|
+
}
|
|
7184
|
+
async function pushMeetingToGoogleCalendar(api, meetingId, target) {
|
|
7185
|
+
const operation = "meet.pushMeetingToGoogleCalendar";
|
|
7186
|
+
const response = await api.request({
|
|
7187
|
+
path: meetingPath(MEET_ROUTES.meetingGoogleCalendar, meetingId),
|
|
7188
|
+
method: "POST",
|
|
7189
|
+
requireAuth: true,
|
|
7190
|
+
operation,
|
|
7191
|
+
body: { connection_id: target.connectionId, calendar_id: target.calendarId ?? "primary" }
|
|
7192
|
+
});
|
|
7193
|
+
if (!response.ok) throw await refusal(response, operation);
|
|
7194
|
+
return await response.json();
|
|
7195
|
+
}
|
|
6762
7196
|
//# sourceMappingURL=react.cjs.map
|