@ai-matrx/meet 0.7.2 → 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/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 refusal = await refusalFor(response, operation);
760
- options.store.patch({ noteTakerRefusal: refusal });
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
- refusal.reason,
764
- refusal.remedy
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 refusal = await refusalFor(response, "meet.ai.ask");
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
- refusal.reason,
806
- refusal.remedy
839
+ refusal2.reason,
840
+ refusal2.remedy
807
841
  );
808
842
  }
809
843
  const body = response.body;
@@ -2243,11 +2277,11 @@ function createMeetingSession(options) {
2243
2277
  } catch {
2244
2278
  body = null;
2245
2279
  }
2246
- const refusal = readServerRefusal(body);
2280
+ const refusal2 = readServerRefusal(body);
2247
2281
  throw new MeetError(
2248
2282
  response.status === 403 ? "forbidden" : "transport",
2249
- refusal?.reason ?? `meet.endForEveryone: the server answered ${response.status}`,
2250
- refusal?.remedy !== void 0 && refusal.remedy.length > 0 ? refusal.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."
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."
2251
2285
  );
2252
2286
  }
2253
2287
  let payload = null;
@@ -2290,7 +2324,11 @@ var TABLES = {
2290
2324
  invites: "meet_call_invites",
2291
2325
  recordings: "meet_recordings",
2292
2326
  transcripts: "meet_transcript_segments",
2293
- 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"
2294
2332
  };
2295
2333
  var RPCS = {
2296
2334
  /** Atomic: create the invite row and stamp its expiry in one statement. */
@@ -2306,10 +2344,41 @@ var RPCS = {
2306
2344
  admit: "meet_admit_participant",
2307
2345
  setLock: "meet_set_lock",
2308
2346
  endMeeting: "meet_end_meeting",
2309
- 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"
2310
2378
  };
2311
2379
  var VOID_RPCS = [RPCS.admit, RPCS.recordConsent];
2312
- 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";
2313
2382
  var RECORDING_COLUMNS = "id,meeting_id,state,started_at,ended_at,started_by,file_id,failure_reason";
2314
2383
  var SEGMENT_COLUMNS = "id,meeting_id,identity,speaker,text,started_at,is_final,metadata";
2315
2384
  var NOTE_COLUMNS = "id,meeting_id,text,kind,assignee_user_id,created_at,metadata";
@@ -2407,6 +2476,138 @@ function projectNote(row) {
2407
2476
  source: "record"
2408
2477
  };
2409
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
+ }
2410
2611
  function createMeetRepository(options) {
2411
2612
  const db = options.client.schema(MEET_SCHEMA);
2412
2613
  async function guardVoid(operation, run) {
@@ -2476,7 +2677,16 @@ function createMeetRepository(options) {
2476
2677
  lobbyEnabled: bool(row, "lobby_enabled", true),
2477
2678
  recordingPolicy: policy === "disabled" || policy === "always-on" ? policy : "host-controlled",
2478
2679
  aiEnabled: bool(row, "ai_enabled", true),
2479
- 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
2480
2690
  };
2481
2691
  }
2482
2692
  function projectRecording(row) {
@@ -2563,6 +2773,170 @@ function createMeetRepository(options) {
2563
2773
  projectNote,
2564
2774
  projectRecording,
2565
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
+ },
2566
2940
  async attendees(meetingId) {
2567
2941
  const response = await db.from(TABLES.participants).select(ATTENDEE_COLUMNS).eq("meeting_id", meetingId).order("joined_at", { ascending: true }).order("id", { ascending: true });
2568
2942
  if (response.error !== null) throw normalizeMeetError(response.error, "meet.attendees");
@@ -2990,14 +3364,14 @@ function noteTakerStatus(args) {
2990
3364
  const row = typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
2991
3365
  const recorded = readState(row["state"]);
2992
3366
  const detail = typeof row["reason"] === "string" && row["reason"].length > 0 ? row["reason"] : null;
2993
- const refusal = args.refusal ?? null;
3367
+ const refusal2 = args.refusal ?? null;
2994
3368
  if (recorded === null) {
2995
- return { state: "absent", detail, present, refusal };
3369
+ return { state: "absent", detail, present, refusal: refusal2 };
2996
3370
  }
2997
3371
  if (recorded === "transcribing" && !present) {
2998
- return { state: "handoff_pending", detail, present, refusal };
3372
+ return { state: "handoff_pending", detail, present, refusal: refusal2 };
2999
3373
  }
3000
- return { state: recorded, detail, present, refusal };
3374
+ return { state: recorded, detail, present, refusal: refusal2 };
3001
3375
  }
3002
3376
  function noteTakerLabel(status) {
3003
3377
  switch (status.state) {
@@ -4022,11 +4396,11 @@ function computeStage(args) {
4022
4396
  presenting: sharer !== null
4023
4397
  };
4024
4398
  }
4025
- function gridColumns(count) {
4026
- if (count <= 1) return 1;
4027
- if (count <= 4) return 2;
4028
- if (count <= 9) return 3;
4029
- if (count <= 16) return 4;
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;
4030
4404
  return 5;
4031
4405
  }
4032
4406
 
@@ -4200,7 +4574,7 @@ function meetingWhen(meeting, locale) {
4200
4574
  if (start === null) return "Time not recorded";
4201
4575
  const startedAt = new Date(start);
4202
4576
  if (Number.isNaN(startedAt.getTime())) return "Time not recorded";
4203
- const when = startedAt.toLocaleString(locale, {
4577
+ const when2 = startedAt.toLocaleString(locale, {
4204
4578
  weekday: "long",
4205
4579
  year: "numeric",
4206
4580
  month: "long",
@@ -4208,11 +4582,11 @@ function meetingWhen(meeting, locale) {
4208
4582
  hour: "numeric",
4209
4583
  minute: "2-digit"
4210
4584
  });
4211
- if (meeting.endedAt === null || meeting.startedAt === null) return when;
4585
+ if (meeting.endedAt === null || meeting.startedAt === null) return when2;
4212
4586
  const endedAt = new Date(meeting.endedAt);
4213
- if (Number.isNaN(endedAt.getTime())) return when;
4587
+ if (Number.isNaN(endedAt.getTime())) return when2;
4214
4588
  const elapsedMs = endedAt.getTime() - startedAt.getTime();
4215
- return `${when} \xB7 ${(0, import_format.formatDurationMs)(elapsedMs, { style: "long" })}`;
4589
+ return `${when2} \xB7 ${(0, import_format.formatDurationMs)(elapsedMs, { style: "long" })}`;
4216
4590
  }
4217
4591
  var GUEST_RECORD_ACCESS_LEVELS = [
4218
4592
  "none",
@@ -4319,8 +4693,8 @@ async function loadGuestMeetingRecord(args) {
4319
4693
  );
4320
4694
  }
4321
4695
  if (!response.ok) {
4322
- const refusal = await readRefusal(response);
4323
- return refusedBundle(meeting, refusal.message, refusal.remedy);
4696
+ const refusal2 = await readRefusal(response);
4697
+ return refusedBundle(meeting, refusal2.message, refusal2.remedy);
4324
4698
  }
4325
4699
  const body = await response.json();
4326
4700
  const payload = typeof body["data"] === "object" && body["data"] !== null ? body["data"] : body;
@@ -4411,8 +4785,8 @@ async function setGuestRecordAccess(args) {
4411
4785
  }
4412
4786
  });
4413
4787
  if (!response.ok) {
4414
- const refusal = await readRefusal(response);
4415
- throw new MeetError("forbidden", refusal.message, refusal.remedy);
4788
+ const refusal2 = await readRefusal(response);
4789
+ throw new MeetError("forbidden", refusal2.message, refusal2.remedy);
4416
4790
  }
4417
4791
  const body = await response.json();
4418
4792
  const payload = typeof body["data"] === "object" && body["data"] !== null ? body["data"] : body;
@@ -5079,8 +5453,8 @@ function callStateLabel(state, outgoing) {
5079
5453
  return "Call";
5080
5454
  }
5081
5455
  }
5082
- function countLabel(count, singular, plural = `${singular}s`) {
5083
- return `${count} ${count === 1 ? singular : plural}`;
5456
+ function countLabel(count2, singular, plural = `${singular}s`) {
5457
+ return `${count2} ${count2 === 1 ? singular : plural}`;
5084
5458
  }
5085
5459
 
5086
5460
  // src/react/icons.tsx
@@ -6138,7 +6512,7 @@ function ScheduleMeetingBody({
6138
6512
  host
6139
6513
  }) {
6140
6514
  const [title, setTitle] = (0, import_react4.useState)("");
6141
- const [when, setWhen] = (0, import_react4.useState)("");
6515
+ const [when2, setWhen] = (0, import_react4.useState)("");
6142
6516
  const [kind, setKind] = (0, import_react4.useState)("scheduled");
6143
6517
  const [busy, setBusy] = (0, import_react4.useState)(false);
6144
6518
  const [link, setLink] = (0, import_react4.useState)(null);
@@ -6158,7 +6532,7 @@ function ScheduleMeetingBody({
6158
6532
  hostUserId: host.identity.userId,
6159
6533
  title: title.trim(),
6160
6534
  kind,
6161
- scheduledFor: when.length > 0 ? new Date(when).toISOString() : null
6535
+ scheduledFor: when2.length > 0 ? new Date(when2).toISOString() : null
6162
6536
  }).then((meeting) => {
6163
6537
  setLink(meetingLink(appBaseUrl, meeting.slug));
6164
6538
  onScheduled?.(meeting.slug);
@@ -6188,7 +6562,7 @@ function ScheduleMeetingBody({
6188
6562
  {
6189
6563
  className: "mx-meet__input",
6190
6564
  type: "datetime-local",
6191
- value: when,
6565
+ value: when2,
6192
6566
  onChange: (event) => setWhen(event.target.value)
6193
6567
  }
6194
6568
  )
@@ -6768,4 +7142,55 @@ function createMeetingInviteHandler(options) {
6768
7142
  }
6769
7143
  };
6770
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
+ }
6771
7196
  //# sourceMappingURL=react.cjs.map