@ai-matrx/meet 0.11.44 → 0.11.45

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/index.cjs CHANGED
@@ -607,7 +607,8 @@ function createWebResumeStorage() {
607
607
  }
608
608
  };
609
609
  }
610
- var CLEARS_RESUME = (phase) => phase === "left" || phase === "removed" || phase === "superseded" || phase === "inactive" || phase === "ended" || phase === "record" || phase === "prejoin" || phase.startsWith("refused:") || phase.startsWith("waiting:");
610
+ var CLEARS_RESUME = (phase) => phase === "left" || phase === "removed" || phase === "superseded" || phase === "inactive" || phase === "ended" || phase === "record" || phase === "prejoin" || phase === "denied" || phase === "knock_expired" || phase.startsWith("refused:");
611
+ var WAITING_RESUMES = (phase) => phase.startsWith("waiting:");
611
612
  function autoRejoinDelayMs(attempt, random = Math.random) {
612
613
  const base = Math.min(15e3, 1e3 * 2 ** Math.max(0, attempt));
613
614
  return Math.round(base * (0.5 + random()));
@@ -739,6 +740,10 @@ function createConnectionSupervisor(options) {
739
740
  rejoinAttempts = 0;
740
741
  stopRejoin();
741
742
  saveMarker(true);
743
+ } else if (WAITING_RESUMES(phase)) {
744
+ stopRejoin();
745
+ driverRegion = null;
746
+ saveMarker(true);
742
747
  } else if (phase === "disconnected") {
743
748
  driverRegion = null;
744
749
  saveMarker(true);
@@ -1042,6 +1047,7 @@ function parseRoomToken(body, roomName) {
1042
1047
  connectionIdentity: readString(payload, "connection_identity") ?? personKey,
1043
1048
  connectionKind: readString(payload, "connection_kind") === "companion" ? "companion" : "main",
1044
1049
  secondDeviceChoice,
1050
+ secondDeviceRule: readString(payload, "second_device_rule"),
1045
1051
  displayName: readString(payload, "display_name") ?? readString(payload, "displayName") ?? identity,
1046
1052
  expiresAt,
1047
1053
  canPublish: readBoolean(payload, "can_publish", true),
@@ -1780,6 +1786,12 @@ var JOINABLE_FROM = /* @__PURE__ */ new Set([
1780
1786
  // allows the press; the server's gate decides whether it knocks or is refused again.
1781
1787
  "refused:lobby_rejects"
1782
1788
  ]);
1789
+ var RETRYABLE_REFUSALS = /* @__PURE__ */ new Set([
1790
+ "refused:locked",
1791
+ "refused:too_early",
1792
+ "refused:meeting_full",
1793
+ "refused:platform_capacity"
1794
+ ]);
1783
1795
  var NOT_ENDABLE = /* @__PURE__ */ new Set([
1784
1796
  "ended",
1785
1797
  "record",
@@ -1845,7 +1857,7 @@ function nextPhase(from, event) {
1845
1857
  case "link_state":
1846
1858
  return from === "resolving" && event.reason !== null && isJoinRefusalReason(event.reason) ? refusalPhase(event.reason) : null;
1847
1859
  case "join":
1848
- return JOINABLE_FROM.has(from) ? "joining" : null;
1860
+ return JOINABLE_FROM.has(from) || RETRYABLE_REFUSALS.has(from) ? "joining" : null;
1849
1861
  case "auto_rejoin":
1850
1862
  return from === "disconnected" ? "joining" : null;
1851
1863
  case "resumed":
@@ -2270,6 +2282,10 @@ var RPCS = {
2270
2282
  admitAll: "meet_admit_all",
2271
2283
  setLock: "meet_set_lock",
2272
2284
  recordConsent: "meet_record_consent",
2285
+ /** One meeting rule as the gate obeys it (the knob ladder, this meeting's rung included). */
2286
+ meetingRule: "meet_policy",
2287
+ /** A host sets one rule for THIS meeting (the `meet_meeting` rung); refusals come back as `{ok:false}`. */
2288
+ setMeetingRule: "meet_policy_set",
2273
2289
  /*
2274
2290
  * ── MEET WAVE 1 — management (0.8). Every write is a SECURITY DEFINER door
2275
2291
  * authorized by the meeting's host or a real iam grant (editor to change,
@@ -2316,7 +2332,7 @@ var INVITEE_COLUMNS = "id,meeting_id,invitee_user_id,email,display_name,role,rsv
2316
2332
  var RECORDING_COLUMNS = "id,meeting_id,state,started_at,ended_at,started_by,file_id,failure_reason";
2317
2333
  var SEGMENT_COLUMNS = "id,meeting_id,identity,speaker,text,started_at,is_final,metadata";
2318
2334
  var NOTE_COLUMNS = "id,meeting_id,text,kind,assignee_user_id,created_at,metadata";
2319
- var ATTENDEE_COLUMNS = "id,meeting_id,identity,participant_user_id,display_name,avatar_url,role,admission_state,knocked_at,knock_expires_at,is_agent,joined_at,left_at,sessions:metadata->sessions";
2335
+ var ATTENDEE_COLUMNS = "id,meeting_id,identity,participant_user_id,display_name,avatar_url,role,admission_state,knocked_at,knock_expires_at,is_agent,joined_at,left_at,sessions:metadata->sessions,knock_flag:metadata->>knock_flag";
2320
2336
  function projectStays(value) {
2321
2337
  if (!Array.isArray(value)) return [];
2322
2338
  const stays = [];
@@ -2716,6 +2732,8 @@ function createMeetRepository(options) {
2716
2732
  admissionState: states.includes(admission) ? admission : "admitted",
2717
2733
  knockedAt: text(row, "knocked_at"),
2718
2734
  knockExpiresAt: text(row, "knock_expires_at"),
2735
+ // The list read selects `metadata->>knock_flag`; a Postgres Changes row carries `metadata`.
2736
+ knockFlag: text(row, "knock_flag") ?? (typeof row["metadata"] === "object" && row["metadata"] !== null ? text(row["metadata"], "knock_flag") : null),
2719
2737
  isAgent: bool(row, "is_agent", false),
2720
2738
  joinedAt: text(row, "joined_at"),
2721
2739
  leftAt: text(row, "left_at"),
@@ -3039,6 +3057,25 @@ function createMeetRepository(options) {
3039
3057
  );
3040
3058
  return projectMeeting(row);
3041
3059
  },
3060
+ async meetingRule(meetingId, key) {
3061
+ const response = await db.rpc(RPCS.meetingRule, { p_meeting_id: meetingId, p_key: key });
3062
+ if (response.error !== null) throw normalizeMeetError(response.error, "meet.meetingRule");
3063
+ return response.data;
3064
+ },
3065
+ async setMeetingRule(meetingId, key, value) {
3066
+ const response = await db.rpc(RPCS.setMeetingRule, { p_meeting_id: meetingId, p_key: key, p_value: value });
3067
+ if (response.error !== null) throw normalizeMeetError(response.error, "meet.setMeetingRule");
3068
+ const answer = response.data ?? {};
3069
+ if (answer["ok"] !== true) {
3070
+ throw new MeetError(
3071
+ "forbidden",
3072
+ typeof answer["detail"] === "string" ? answer["detail"] : "This meeting's rule was not changed.",
3073
+ "Only the meeting's host or a co-host sets its rules; an organization can lock a rule for everyone.",
3074
+ answer
3075
+ );
3076
+ }
3077
+ return answer["effective_value"];
3078
+ },
3042
3079
  async transcript(meetingId, limit = 1e3) {
3043
3080
  const response = await db.from(TABLES.transcripts).select(SEGMENT_COLUMNS).eq("meeting_id", meetingId).order("started_at", { ascending: true }).order("id", { ascending: true }).limit(limit);
3044
3081
  if (response.error !== null) throw normalizeMeetError(response.error, "meet.transcript");
@@ -5204,7 +5241,8 @@ function lobbyEntryFrom(attendee, now = Date.now()) {
5204
5241
  knockedAt: attendee.knockedAt ?? attendee.joinedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
5205
5242
  knockExpiresAt: attendee.knockExpiresAt ?? null,
5206
5243
  decidedAt: null,
5207
- decidedBy: null
5244
+ decidedBy: null,
5245
+ flag: attendee.knockFlag ?? null
5208
5246
  };
5209
5247
  }
5210
5248
  function deniedEntryFrom(attendee) {
@@ -5736,6 +5774,17 @@ function createMeetingSession(options) {
5736
5774
  async askAgain() {
5737
5775
  await options.rejoin?.();
5738
5776
  },
5777
+ async meetingRule(key) {
5778
+ const meeting = requireMeeting("meet.meetingRule");
5779
+ return repository.meetingRule(meeting.id, key);
5780
+ },
5781
+ async setMeetingRule(key, value) {
5782
+ requireHostUser("meet.setMeetingRule");
5783
+ const meeting = requireMeeting("meet.setMeetingRule");
5784
+ const effective = await repository.setMeetingRule(meeting.id, key, value);
5785
+ hint();
5786
+ return effective;
5787
+ },
5739
5788
  async setLock(locked) {
5740
5789
  const by = requireHostUser("meet.setLock");
5741
5790
  const meeting = requireMeeting("meet.setLock");
@@ -7127,7 +7176,7 @@ function createRoomEngine(options) {
7127
7176
  const { secondDevice: _answered, ...rest } = lastRequest;
7128
7177
  lastRequest = rest;
7129
7178
  }
7130
- options.tabClaim?.inRoom(String(request.roomName), String(token.identity));
7179
+ options.tabClaim?.inRoom(String(request.roomName), String(token.identity), token.secondDeviceRule ?? null);
7131
7180
  current = token;
7132
7181
  lastServerUrl = token.serverUrl;
7133
7182
  connectionPolicy = token.connectionPolicy ?? DEFAULT_CONNECTION_POLICY;
@@ -7439,10 +7488,12 @@ function createRoomEngine(options) {
7439
7488
  if (claim === void 0 || userId === null) return false;
7440
7489
  const before = store.snapshot();
7441
7490
  if (before.phase !== "prejoin" || before.secondDevice !== null) return false;
7442
- if (!await claim.presentElsewhere(String(roomName), `user:${String(userId)}`)) return false;
7491
+ const person = `user:${String(userId)}`;
7492
+ const found = claim.presenceElsewhere !== void 0 ? await claim.presenceElsewhere(String(roomName), person) : await claim.presentElsewhere(String(roomName), person) ? { rule: null } : null;
7493
+ if (found === null || found.rule === "allow_both") return false;
7443
7494
  const now2 = store.snapshot();
7444
7495
  if (now2.phase !== "prejoin" || now2.secondDevice !== null) return false;
7445
- store.patch({ secondDevice: { rule: "ask_switch_or_join" } });
7496
+ store.patch({ secondDevice: { rule: found.rule ?? "ask_switch_or_join" } });
7446
7497
  report("info", "meet: this browser already has you in this meeting \u2014 offering the choice before Join");
7447
7498
  return true;
7448
7499
  },