@memberjunction/livekit-room-server 6.2.0-edge.3 → 6.2.0-edge.5

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.
Files changed (34) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/livekit-agent-room-coordinator.d.ts +120 -10
  6. package/dist/livekit-agent-room-coordinator.d.ts.map +1 -1
  7. package/dist/livekit-agent-room-coordinator.js +312 -68
  8. package/dist/livekit-agent-room-coordinator.js.map +1 -1
  9. package/dist/livekit-native-module.d.ts.map +1 -1
  10. package/dist/livekit-native-module.js +7 -0
  11. package/dist/livekit-native-module.js.map +1 -1
  12. package/dist/livekit-participant-service.d.ts +47 -0
  13. package/dist/livekit-participant-service.d.ts.map +1 -0
  14. package/dist/livekit-participant-service.js +64 -0
  15. package/dist/livekit-participant-service.js.map +1 -0
  16. package/dist/livekit-token-service.d.ts +20 -5
  17. package/dist/livekit-token-service.d.ts.map +1 -1
  18. package/dist/livekit-token-service.js +14 -7
  19. package/dist/livekit-token-service.js.map +1 -1
  20. package/dist/meeting-dial-in-service.d.ts +32 -1
  21. package/dist/meeting-dial-in-service.d.ts.map +1 -1
  22. package/dist/meeting-dial-in-service.js +83 -11
  23. package/dist/meeting-dial-in-service.js.map +1 -1
  24. package/dist/room-handoff/handoff-offer-registry.d.ts +10 -0
  25. package/dist/room-handoff/handoff-offer-registry.d.ts.map +1 -1
  26. package/dist/room-handoff/handoff-offer-registry.js +40 -13
  27. package/dist/room-handoff/handoff-offer-registry.js.map +1 -1
  28. package/dist/room-handoff/handoff-types.d.ts +11 -9
  29. package/dist/room-handoff/handoff-types.d.ts.map +1 -1
  30. package/dist/room-handoff/room-handoff-engine.d.ts +9 -1
  31. package/dist/room-handoff/room-handoff-engine.d.ts.map +1 -1
  32. package/dist/room-handoff/room-handoff-engine.js +40 -7
  33. package/dist/room-handoff/room-handoff-engine.js.map +1 -1
  34. package/package.json +13 -12
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview {@link LiveKitParticipantService} — changes a participant in a live room through LiveKit's
3
+ * `RoomServiceClient` (`livekit-server-sdk`). Today it records whether a person lets agents see their camera and shared
4
+ * screen. A participant's token can't change its own attributes: MJ's tokens carry no `canUpdateOwnMetadata`, because
5
+ * the same right would let anyone rename themselves and rewrite the metadata that carries their role. So the server
6
+ * sets the attribute for them, once MJAPI has worked out who is asking.
7
+ *
8
+ * @module @memberjunction/livekit-room-server
9
+ */
10
+ import { RoomServiceClient, TwirpError } from 'livekit-server-sdk';
11
+ import { AgentVisionAttributes } from '@memberjunction/ai';
12
+ import { LiveKitTokenService } from './livekit-token-service.js';
13
+ import { WsToHttpUrl } from './livekit-egress-service.js';
14
+ /** Changes participants in live LiveKit rooms, on the server's authority. */
15
+ export class LiveKitParticipantService {
16
+ /**
17
+ * @param config Explicit credentials; omitted fields fall back to environment variables (via
18
+ * {@link LiveKitTokenService}). The room service client uses the HTTP(S) form of the server URL.
19
+ * @param client An injectable room service client (primarily for unit testing); defaults to a real
20
+ * `RoomServiceClient` built from the resolved credentials.
21
+ */
22
+ constructor(config, client) {
23
+ const token = new LiveKitTokenService(config);
24
+ this.configured = token.IsConfigured;
25
+ this.client =
26
+ client ?? new RoomServiceClient(WsToHttpUrl(token.ServerUrl), config?.ApiKey ?? process.env.LIVEKIT_API_KEY, config?.ApiSecret ?? process.env.LIVEKIT_API_SECRET);
27
+ }
28
+ /**
29
+ * Records whether a person lets agents see their camera and shared screen: sets their `mj.agentCanSee` attribute to
30
+ * `'true'`, or removes it. The caller must already have established that `identity` is the person asking.
31
+ *
32
+ * @param roomName The room the person is in.
33
+ * @param identity The person's participant identity.
34
+ * @param allow `true` to let agents see, `false` to stop.
35
+ * @returns Whether LiveKit applied it; never throws.
36
+ */
37
+ async SetAgentVision(roomName, identity, allow) {
38
+ return this.updateAttributes(roomName, identity, AgentVisionAttributes(allow));
39
+ }
40
+ /** Sets (or, with `''`, removes) a participant's attributes; reports LiveKit's refusal instead of throwing. */
41
+ async updateAttributes(roomName, identity, attributes) {
42
+ if (!this.configured) {
43
+ return { Success: false, ErrorMessage: 'LiveKit is not configured on this server.' };
44
+ }
45
+ try {
46
+ await this.client.updateParticipant(roomName, identity, { attributes });
47
+ return { Success: true };
48
+ }
49
+ catch (error) {
50
+ if (isNotFound(error)) {
51
+ return { Success: false, NotInRoom: true, ErrorMessage: `${identity} is not in room ${roomName}.` };
52
+ }
53
+ return { Success: false, ErrorMessage: error instanceof Error ? error.message : String(error) };
54
+ }
55
+ }
56
+ }
57
+ /**
58
+ * Whether LiveKit refused because the room or the participant does not exist. Only LiveKit's own `not_found` code
59
+ * counts: a bare HTTP 404 more likely means the server URL is wrong.
60
+ */
61
+ function isNotFound(error) {
62
+ return error instanceof TwirpError && error.code === 'not_found';
63
+ }
64
+ //# sourceMappingURL=livekit-participant-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"livekit-participant-service.js","sourceRoot":"","sources":["../src/livekit-participant-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAA4B,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAevD,6EAA6E;AAC7E,MAAM,OAAO,yBAAyB;IAIpC;;;;;OAKG;IACH,YAAY,MAAqC,EAAE,MAAoC;QACrF,MAAM,KAAK,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,YAAY,CAAC;QACrC,IAAI,CAAC,MAAM;YACT,MAAM,IAAI,IAAI,iBAAiB,CAAC,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACtK,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,QAAgB,EAAE,KAAc;QAC5E,OAAO,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,+GAA+G;IACvG,KAAK,CAAC,gBAAgB,CAAC,QAAgB,EAAE,QAAgB,EAAE,UAAkC;QACnG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,2CAA2C,EAAE,CAAC;QACvF,CAAC;QACD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YACxE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,QAAQ,mBAAmB,QAAQ,GAAG,EAAE,CAAC;YACtG,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAClG,CAAC;IACH,CAAC;CACF;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,KAAK,YAAY,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC;AACnE,CAAC"}
@@ -40,6 +40,16 @@ export interface MintTokenParams {
40
40
  TtlSeconds?: number;
41
41
  /** Extra metadata merged into the participant metadata JSON. */
42
42
  Metadata?: Record<string, unknown>;
43
+ /**
44
+ * LiveKit participant attributes the participant carries from the moment it joins (e.g. `mj.agentWatches` on an
45
+ * agent's bot). Attributes are shared with every participant and announced on change.
46
+ */
47
+ Attributes?: Record<string, string>;
48
+ /**
49
+ * Whether the participant may change its own name, metadata and attributes. Default: false (LiveKit's default). Agent
50
+ * bots get it, so a bot can say when its avatar was taken down (`mj.agentAvatar`).
51
+ */
52
+ CanUpdateOwnMetadata?: boolean;
43
53
  }
44
54
  /** A minted token plus the connection coordinates a client needs to join. */
45
55
  export interface MintedToken {
@@ -89,18 +99,23 @@ export declare class LiveKitTokenService {
89
99
  MintClientToken(roomName: string, identity: string, displayName?: string, ttlSeconds?: number): Promise<MintedToken>;
90
100
  /**
91
101
  * Mints a token for the AGENT bot (publish + subscribe + data, `agent` role metadata so the UI badges
92
- * it correctly). The bridge passes this in its session `Configuration.AccessToken`.
102
+ * it correctly, and leave to update its own attributes, so it can say when its avatar was taken down). The bridge
103
+ * passes this in its session `Configuration.AccessToken`.
93
104
  *
94
105
  * @param roomName The room to join.
95
106
  * @param identity The bot identity.
96
107
  * @param displayName The bot display name.
108
+ * @param attributes Participant attributes the bot carries from the moment it joins (e.g. `mj.agentWatches`).
97
109
  */
98
- MintBotToken(roomName: string, identity: string, displayName?: string): Promise<MintedToken>;
99
- /** Builds the LiveKit video grant from the params (defaults: publish + subscribe + data all on). */
110
+ MintBotToken(roomName: string, identity: string, displayName?: string, attributes?: Record<string, string>): Promise<MintedToken>;
111
+ /** Builds the LiveKit video grant from the params (defaults: publish + subscribe + data all on; own metadata off). */
100
112
  private buildGrant;
101
113
  /** Builds the participant metadata JSON string, always stamping the role for UI resolution. */
102
114
  private buildMetadata;
103
- /** Throws a clear error when credentials are missing. */
104
- private assertConfigured;
115
+ /**
116
+ * Throws a clear error when credentials are missing. Public so a caller that must fail before doing costly work (the
117
+ * room coordinator, before it opens a model session) gets the same error minting would.
118
+ */
119
+ AssertConfigured(): void;
105
120
  }
106
121
  //# sourceMappingURL=livekit-token-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"livekit-token-service.d.ts","sourceRoot":"","sources":["../src/livekit-token-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,iDAAiD;AACjD,MAAM,WAAW,mBAAmB;IAClC,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gGAAgG;AAChG,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,CAAC;AAEhE,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,gEAAgE;IAChE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gFAAgF;IAChF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,yFAAyF;AACzF,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAE7C;;;OAGG;gBACS,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAQjD,qEAAqE;IACrE,IAAW,YAAY,IAAI,OAAO,CAEjC;IAED,iFAAiF;IACjF,IAAW,SAAS,IAAI,MAAM,CAE7B;IAED;;;;;;OAMG;IACU,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAarE;;;;;;;OAOG;IACI,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAI3H;;;;;;;OAOG;IACI,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAInG,oGAAoG;IACpG,OAAO,CAAC,UAAU;IAUlB,+FAA+F;IAC/F,OAAO,CAAC,aAAa;IAIrB,yDAAyD;IACzD,OAAO,CAAC,gBAAgB;CAQzB"}
1
+ {"version":3,"file":"livekit-token-service.d.ts","sourceRoot":"","sources":["../src/livekit-token-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,iDAAiD;AACjD,MAAM,WAAW,mBAAmB;IAClC,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gGAAgG;AAChG,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,CAAC;AAEhE,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,gEAAgE;IAChE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gFAAgF;IAChF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,yFAAyF;AACzF,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAE7C;;;OAGG;gBACS,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAQjD,qEAAqE;IACrE,IAAW,YAAY,IAAI,OAAO,CAEjC;IAED,iFAAiF;IACjF,IAAW,SAAS,IAAI,MAAM,CAE7B;IAED;;;;;;OAMG;IACU,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAcrE;;;;;;;OAOG;IACI,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAI3H;;;;;;;;;OASG;IACI,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAIxI,sHAAsH;IACtH,OAAO,CAAC,UAAU;IAWlB,+FAA+F;IAC/F,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACI,gBAAgB,IAAI,IAAI;CAQhC"}
@@ -47,12 +47,13 @@ export class LiveKitTokenService {
47
47
  * @throws {Error} when credentials are not configured.
48
48
  */
49
49
  async MintToken(params) {
50
- this.assertConfigured();
50
+ this.AssertConfigured();
51
51
  const at = new AccessToken(this.config.ApiKey, this.config.ApiSecret, {
52
52
  identity: params.Identity,
53
53
  name: params.DisplayName,
54
54
  ttl: params.TtlSeconds ?? 3600,
55
55
  metadata: this.buildMetadata(params),
56
+ attributes: params.Attributes,
56
57
  });
57
58
  at.addGrant(this.buildGrant(params));
58
59
  const token = await at.toJwt();
@@ -71,16 +72,18 @@ export class LiveKitTokenService {
71
72
  }
72
73
  /**
73
74
  * Mints a token for the AGENT bot (publish + subscribe + data, `agent` role metadata so the UI badges
74
- * it correctly). The bridge passes this in its session `Configuration.AccessToken`.
75
+ * it correctly, and leave to update its own attributes, so it can say when its avatar was taken down). The bridge
76
+ * passes this in its session `Configuration.AccessToken`.
75
77
  *
76
78
  * @param roomName The room to join.
77
79
  * @param identity The bot identity.
78
80
  * @param displayName The bot display name.
81
+ * @param attributes Participant attributes the bot carries from the moment it joins (e.g. `mj.agentWatches`).
79
82
  */
80
- MintBotToken(roomName, identity, displayName) {
81
- return this.MintToken({ RoomName: roomName, Identity: identity, DisplayName: displayName, Role: 'agent' });
83
+ MintBotToken(roomName, identity, displayName, attributes) {
84
+ return this.MintToken({ RoomName: roomName, Identity: identity, DisplayName: displayName, Role: 'agent', Attributes: attributes, CanUpdateOwnMetadata: true });
82
85
  }
83
- /** Builds the LiveKit video grant from the params (defaults: publish + subscribe + data all on). */
86
+ /** Builds the LiveKit video grant from the params (defaults: publish + subscribe + data all on; own metadata off). */
84
87
  buildGrant(params) {
85
88
  return {
86
89
  roomJoin: true,
@@ -88,14 +91,18 @@ export class LiveKitTokenService {
88
91
  canPublish: params.CanPublish ?? true,
89
92
  canSubscribe: params.CanSubscribe ?? true,
90
93
  canPublishData: params.CanPublishData ?? true,
94
+ ...(params.CanUpdateOwnMetadata ? { canUpdateOwnMetadata: true } : {}),
91
95
  };
92
96
  }
93
97
  /** Builds the participant metadata JSON string, always stamping the role for UI resolution. */
94
98
  buildMetadata(params) {
95
99
  return JSON.stringify({ mjRole: params.Role ?? 'participant', ...(params.Metadata ?? {}) });
96
100
  }
97
- /** Throws a clear error when credentials are missing. */
98
- assertConfigured() {
101
+ /**
102
+ * Throws a clear error when credentials are missing. Public so a caller that must fail before doing costly work (the
103
+ * room coordinator, before it opens a model session) gets the same error minting would.
104
+ */
105
+ AssertConfigured() {
99
106
  if (!this.IsConfigured) {
100
107
  throw new Error('LiveKitTokenService is not configured. Set LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET ' +
101
108
  '(or pass them to the constructor) before minting tokens.');
@@ -1 +1 @@
1
- {"version":3,"file":"livekit-token-service.js","sourceRoot":"","sources":["../src/livekit-token-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"livekit-token-service.js","sourceRoot":"","sources":["../src/livekit-token-service.ts"],"names":[],"mappings":"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"}
@@ -13,20 +13,51 @@
13
13
  */
14
14
  import { BaseSingleton } from '@memberjunction/global';
15
15
  import { type IMetadataProvider, type UserInfo } from '@memberjunction/core';
16
- /** Rate limiter with configurable attempt limits and lockout windows. */
16
+ /**
17
+ * Rate limiter with configurable attempt limits and lockout windows.
18
+ *
19
+ * Keys are caller-supplied (caller and dialed numbers), so the number of tracked keys is capped.
20
+ * Two things keep that cap from becoming a weakness under a flood of distinct keys:
21
+ * - **Constant cost per call.** Expired entries are swept at most once every
22
+ * {@link sweepThreshold} inserts, not on every failure, and enforcing the cap drops one entry.
23
+ * Before, each failure past 1,000 keys walked the whole map, so a flood cost O(n) per attempt.
24
+ * - **Lockouts are evicted last.** Locked-out keys live in their own map, and the cap drops the
25
+ * oldest key that is still only counting attempts. A locked-out caller can no longer flood
26
+ * distinct numbers to push their own lockout out of the map; a lockout is dropped only when
27
+ * every tracked key is locked out.
28
+ */
17
29
  export declare class DialInRateLimiter {
18
30
  private readonly maxAttempts;
19
31
  private readonly windowMs;
20
32
  private readonly lockoutMs;
33
+ /** Keys still counting attempts, oldest first (Map keeps insertion order). */
21
34
  private readonly attempts;
35
+ /** Keys locked out (or whose lockout ended inside their window), oldest lockout first. */
36
+ private readonly lockouts;
37
+ /** New keys inserted since the last sweep of expired entries. */
38
+ private insertsSinceSweep;
22
39
  constructor(maxAttempts?: number, windowMs?: number, lockoutMs?: number);
23
40
  CheckAllowed(key: string): {
24
41
  allowed: boolean;
25
42
  remainingMs?: number;
26
43
  };
44
+ /** Above this many tracked keys, expired entries are swept, at most once per this many new keys. */
45
+ private static readonly sweepThreshold;
46
+ /** Hard ceiling on tracked keys; when a new key would pass it, one entry is dropped (see the class doc). */
47
+ private static readonly maxEntries;
48
+ /** Number of tracked keys (diagnostics/tests). */
49
+ get Size(): number;
27
50
  RecordFailure(key: string): void;
28
51
  RecordSuccess(key: string): void;
29
52
  Clear(): void;
53
+ private entryFor;
54
+ private remove;
55
+ /** Locks the key out from `now`, moving it to the lockout map as its newest entry. */
56
+ private lock;
57
+ /** Called before a new key is inserted: sweeps on the amortized schedule, then enforces the cap. */
58
+ private makeRoomForNewKey;
59
+ /** Removes entries whose window and lockout have both elapsed. */
60
+ private sweepExpired;
30
61
  }
31
62
  /** Input parameters for verifying a dial-in code. */
32
63
  export interface VerifyDialInCodeParams {
@@ -1 +1 @@
1
- {"version":3,"file":"meeting-dial-in-service.d.ts","sourceRoot":"","sources":["../src/meeting-dial-in-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,aAAa,EAAmB,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAqB,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAUhG,yEAAyE;AACzE,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAL5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;gBAG3C,WAAW,GAAE,MAAU,EACvB,QAAQ,GAAE,MAAuB,EACjC,SAAS,GAAE,MAAuB;IAG9C,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;IAoBrE,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAahC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIhC,KAAK,IAAI,IAAI;CAGrB;AAED,qDAAqD;AACrD,MAAM,WAAW,sBAAsB;IACrC,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,2CAA2C;AAC3C,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,aAAa,CAAC,oBAAoB,CAAC;IAE3E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4D;IAE1F,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6D;;IAM3F,WAAkB,QAAQ,IAAI,oBAAoB,CAEjD;IAED;;OAEG;IACI,kBAAkB,IAAI,MAAM;IAInC;;OAEG;IACU,wBAAwB,CACnC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,QAAQ,EACd,QAAQ,CAAC,EAAE,iBAAiB,GAC3B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAqB9B;;;OAGG;IACU,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA0E/F,kDAAkD;IAC3C,yBAAyB,IAAI,IAAI;CAIzC"}
1
+ {"version":3,"file":"meeting-dial-in-service.d.ts","sourceRoot":"","sources":["../src/meeting-dial-in-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,aAAa,EAAmB,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAqB,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAUhG;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAiB;IAS1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAV5B,8EAA8E;IAC9E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,0FAA0F;IAC1F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,iEAAiE;IACjE,OAAO,CAAC,iBAAiB,CAAK;gBAGX,WAAW,GAAE,MAAU,EACvB,QAAQ,GAAE,MAAuB,EACjC,SAAS,GAAE,MAAuB;IAG9C,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;IAoB5E,oGAAoG;IACpG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAQ;IAC9C,4GAA4G;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAS;IAE3C,kDAAkD;IAClD,IAAW,IAAI,IAAI,MAAM,CAExB;IAEM,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAkBhC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIhC,KAAK,IAAI,IAAI;IAMpB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;IAKd,sFAAsF;IACtF,OAAO,CAAC,IAAI;IAOZ,oGAAoG;IACpG,OAAO,CAAC,iBAAiB;IAgBzB,kEAAkE;IAClE,OAAO,CAAC,YAAY;CAUrB;AAED,qDAAqD;AACrD,MAAM,WAAW,sBAAsB;IACrC,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,2CAA2C;AAC3C,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,aAAa,CAAC,oBAAoB,CAAC;IAE3E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4D;IAE1F,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6D;;IAM3F,WAAkB,QAAQ,IAAI,oBAAoB,CAEjD;IAED;;OAEG;IACI,kBAAkB,IAAI,MAAM;IAInC;;OAEG;IACU,wBAAwB,CACnC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,QAAQ,EACd,QAAQ,CAAC,EAAE,iBAAiB,GAC3B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAqB9B;;;OAGG;IACU,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA0E/F,kDAAkD;IAC3C,yBAAyB,IAAI,IAAI;CAIzC"}
@@ -14,16 +14,33 @@
14
14
  import { randomInt } from 'node:crypto';
15
15
  import { BaseSingleton, EscapeSQLString } from '@memberjunction/global';
16
16
  import { LogError, RunView } from '@memberjunction/core';
17
- /** Rate limiter with configurable attempt limits and lockout windows. */
17
+ /**
18
+ * Rate limiter with configurable attempt limits and lockout windows.
19
+ *
20
+ * Keys are caller-supplied (caller and dialed numbers), so the number of tracked keys is capped.
21
+ * Two things keep that cap from becoming a weakness under a flood of distinct keys:
22
+ * - **Constant cost per call.** Expired entries are swept at most once every
23
+ * {@link sweepThreshold} inserts, not on every failure, and enforcing the cap drops one entry.
24
+ * Before, each failure past 1,000 keys walked the whole map, so a flood cost O(n) per attempt.
25
+ * - **Lockouts are evicted last.** Locked-out keys live in their own map, and the cap drops the
26
+ * oldest key that is still only counting attempts. A locked-out caller can no longer flood
27
+ * distinct numbers to push their own lockout out of the map; a lockout is dropped only when
28
+ * every tracked key is locked out.
29
+ */
18
30
  export class DialInRateLimiter {
19
31
  constructor(maxAttempts = 5, windowMs = 15 * 60 * 1000, lockoutMs = 15 * 60 * 1000) {
20
32
  this.maxAttempts = maxAttempts;
21
33
  this.windowMs = windowMs;
22
34
  this.lockoutMs = lockoutMs;
35
+ /** Keys still counting attempts, oldest first (Map keeps insertion order). */
23
36
  this.attempts = new Map();
37
+ /** Keys locked out (or whose lockout ended inside their window), oldest lockout first. */
38
+ this.lockouts = new Map();
39
+ /** New keys inserted since the last sweep of expired entries. */
40
+ this.insertsSinceSweep = 0;
24
41
  }
25
42
  CheckAllowed(key) {
26
- const entry = this.attempts.get(key);
43
+ const entry = this.entryFor(key);
27
44
  if (!entry) {
28
45
  return { allowed: true };
29
46
  }
@@ -32,33 +49,88 @@ export class DialInRateLimiter {
32
49
  return { allowed: false, remainingMs: entry.lockedUntil - now };
33
50
  }
34
51
  if (now - entry.firstAttemptAt > this.windowMs) {
35
- this.attempts.delete(key);
52
+ this.remove(key);
36
53
  return { allowed: true };
37
54
  }
38
55
  if (entry.attempts >= this.maxAttempts) {
39
- entry.lockedUntil = now + this.lockoutMs;
56
+ this.lock(key, entry, now);
40
57
  return { allowed: false, remainingMs: this.lockoutMs };
41
58
  }
42
59
  return { allowed: true };
43
60
  }
61
+ /** Above this many tracked keys, expired entries are swept, at most once per this many new keys. */
62
+ static { this.sweepThreshold = 1000; }
63
+ /** Hard ceiling on tracked keys; when a new key would pass it, one entry is dropped (see the class doc). */
64
+ static { this.maxEntries = 10000; }
65
+ /** Number of tracked keys (diagnostics/tests). */
66
+ get Size() {
67
+ return this.attempts.size + this.lockouts.size;
68
+ }
44
69
  RecordFailure(key) {
45
70
  const now = Date.now();
46
- const entry = this.attempts.get(key);
71
+ const entry = this.entryFor(key);
72
+ if (entry?.lockedUntil && entry.lockedUntil > now) {
73
+ return; // already locked out: a further failure neither extends nor resets the lockout
74
+ }
47
75
  if (!entry || now - entry.firstAttemptAt > this.windowMs) {
76
+ this.remove(key);
77
+ this.makeRoomForNewKey(now);
48
78
  this.attempts.set(key, { attempts: 1, firstAttemptAt: now });
79
+ return;
49
80
  }
50
- else {
51
- entry.attempts++;
52
- if (entry.attempts >= this.maxAttempts) {
53
- entry.lockedUntil = now + this.lockoutMs;
54
- }
81
+ entry.attempts++;
82
+ if (entry.attempts >= this.maxAttempts) {
83
+ this.lock(key, entry, now);
55
84
  }
56
85
  }
57
86
  RecordSuccess(key) {
58
- this.attempts.delete(key);
87
+ this.remove(key);
59
88
  }
60
89
  Clear() {
61
90
  this.attempts.clear();
91
+ this.lockouts.clear();
92
+ this.insertsSinceSweep = 0;
93
+ }
94
+ entryFor(key) {
95
+ return this.attempts.get(key) ?? this.lockouts.get(key);
96
+ }
97
+ remove(key) {
98
+ this.attempts.delete(key);
99
+ this.lockouts.delete(key);
100
+ }
101
+ /** Locks the key out from `now`, moving it to the lockout map as its newest entry. */
102
+ lock(key, entry, now) {
103
+ entry.lockedUntil = now + this.lockoutMs;
104
+ this.attempts.delete(key);
105
+ this.lockouts.delete(key);
106
+ this.lockouts.set(key, entry);
107
+ }
108
+ /** Called before a new key is inserted: sweeps on the amortized schedule, then enforces the cap. */
109
+ makeRoomForNewKey(now) {
110
+ this.insertsSinceSweep++;
111
+ if (this.Size >= DialInRateLimiter.sweepThreshold && this.insertsSinceSweep >= DialInRateLimiter.sweepThreshold) {
112
+ this.sweepExpired(now);
113
+ this.insertsSinceSweep = 0;
114
+ }
115
+ while (this.Size >= DialInRateLimiter.maxEntries) {
116
+ const victims = this.attempts.size > 0 ? this.attempts : this.lockouts;
117
+ const oldest = victims.keys().next();
118
+ if (oldest.done) {
119
+ break;
120
+ }
121
+ victims.delete(oldest.value);
122
+ }
123
+ }
124
+ /** Removes entries whose window and lockout have both elapsed. */
125
+ sweepExpired(now) {
126
+ for (const map of [this.attempts, this.lockouts]) {
127
+ for (const [key, entry] of map) {
128
+ const lockExpired = !entry.lockedUntil || entry.lockedUntil <= now;
129
+ if (lockExpired && now - entry.firstAttemptAt > this.windowMs) {
130
+ map.delete(key);
131
+ }
132
+ }
133
+ }
62
134
  }
63
135
  }
64
136
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"meeting-dial-in-service.js","sourceRoot":"","sources":["../src/meeting-dial-in-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"meeting-dial-in-service.js","sourceRoot":"","sources":["../src/meeting-dial-in-service.ts"],"names":[],"mappings":"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"}
@@ -70,6 +70,11 @@ export declare function ToOfferView(offer: HandoffOfferRecord): HandoffOfferView
70
70
  export interface HandoffOfferRegistryDeps {
71
71
  Provider?: IMetadataProvider;
72
72
  ContextUser?: UserInfo;
73
+ /**
74
+ * Lazily resolves a server identity when no `ContextUser` was given (e.g. the system user, which only exists once the
75
+ * host's user cache has loaded). Consulted on every call, so a late-loading cache is picked up.
76
+ */
77
+ ResolveContextUser?: () => UserInfo | undefined;
73
78
  Publisher?: (event: {
74
79
  UserID: string;
75
80
  Kind: 'offered' | 'updated';
@@ -131,6 +136,11 @@ export declare class HandoffOfferRegistry extends BaseSingleton<HandoffOfferRegi
131
136
  private finish;
132
137
  private entityToRecord;
133
138
  private notifyPublisher;
139
+ private warnedNoUser;
140
+ /** The caller's user, else the configured server identity, else the lazily resolved one. */
141
+ private resolveUser;
142
+ /** Logs once (not per tick) that database queries are being skipped because no user identity is available yet. */
143
+ private noteNoUser;
134
144
  private getProvider;
135
145
  private getRunView;
136
146
  }
@@ -1 +1 @@
1
- {"version":3,"file":"handoff-offer-registry.d.ts","sourceRoot":"","sources":["../../src/room-handoff/handoff-offer-registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"handoff-offer-registry.d.ts","sourceRoot":"","sources":["../../src/room-handoff/handoff-offer-registry.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@
16
16
  * @module @memberjunction/livekit-room-server
17
17
  */
18
18
  import { randomUUID } from 'node:crypto';
19
- import { LogError, Metadata, RunInEntityTransaction, RunView } from '@memberjunction/core';
19
+ import { LogError, LogStatusEx, Metadata, RunInEntityTransaction, RunView } from '@memberjunction/core';
20
20
  import { BaseSingleton, EscapeSQLString, UUIDsEqual } from '@memberjunction/global';
21
21
  /** How long a person has to accept an offer before it expires. */
22
22
  export const HANDOFF_OFFER_TIMEOUT_MS = 45_000;
@@ -56,6 +56,7 @@ export class HandoffOfferRegistry extends BaseSingleton {
56
56
  this.deps = {};
57
57
  this.offers = new Map();
58
58
  this.now = Date.now;
59
+ this.warnedNoUser = false;
59
60
  this.sweepTimer = setInterval(() => {
60
61
  void this.Sweep().catch((e) => {
61
62
  LogError(`[HandoffOfferRegistry] periodic sweep failed: ${e instanceof Error ? e.message : String(e)}`);
@@ -101,7 +102,7 @@ export class HandoffOfferRegistry extends BaseSingleton {
101
102
  const expiresAt = createdAt + timeoutMs;
102
103
  const p = this.getProvider(input.Provider);
103
104
  if (p && typeof p.GetEntityObject === 'function') {
104
- const user = input.ContextUser ?? this.deps.ContextUser;
105
+ const user = this.resolveUser(input.ContextUser);
105
106
  try {
106
107
  let interactionID = input.InteractionID;
107
108
  if (!interactionID) {
@@ -176,7 +177,7 @@ export class HandoffOfferRegistry extends BaseSingleton {
176
177
  const now = this.now();
177
178
  if (p && typeof p.GetEntityObject === 'function') {
178
179
  try {
179
- const user = contextUser ?? this.deps.ContextUser;
180
+ const user = this.resolveUser(contextUser);
180
181
  const entity = await p.GetEntityObject('MJ: Interaction Offers', user);
181
182
  const loaded = await entity.Load(offerID);
182
183
  if (loaded) {
@@ -210,10 +211,13 @@ export class HandoffOfferRegistry extends BaseSingleton {
210
211
  async PendingForUser(userID, contextUser, provider) {
211
212
  const p = this.getProvider(provider);
212
213
  const now = this.now();
213
- if (p && typeof p.GetEntityObject === 'function') {
214
+ const user = this.resolveUser(contextUser);
215
+ if (!user) {
216
+ this.noteNoUser();
217
+ }
218
+ if (p && user && typeof p.GetEntityObject === 'function') {
214
219
  try {
215
220
  const rv = this.getRunView(p);
216
- const user = contextUser ?? this.deps.ContextUser;
217
221
  const result = await rv.RunView({
218
222
  EntityName: 'MJ: Interaction Offers',
219
223
  ExtraFilter: `TargetUserID = '${EscapeSQLString(userID)}' AND Status = 'Pending'`,
@@ -255,11 +259,14 @@ export class HandoffOfferRegistry extends BaseSingleton {
255
259
  await this.sweep(contextUser, provider);
256
260
  const p = this.getProvider(provider);
257
261
  const now = this.now();
258
- if (p && typeof p.GetEntityObject === 'function') {
262
+ const user = this.resolveUser(contextUser);
263
+ if (!user) {
264
+ this.noteNoUser();
265
+ }
266
+ if (p && user && typeof p.GetEntityObject === 'function') {
259
267
  try {
260
268
  const cutoff = new Date(now - HANDOFF_OFFER_RETENTION_MS).toISOString();
261
269
  const rv = this.getRunView(p);
262
- const user = contextUser ?? this.deps.ContextUser;
263
270
  const result = await rv.RunView({
264
271
  EntityName: 'MJ: Interaction Offers',
265
272
  ExtraFilter: `TargetUserID = '${EscapeSQLString(userID)}' AND (Status = 'Pending' OR RespondedAt >= '${cutoff}')`,
@@ -288,10 +295,13 @@ export class HandoffOfferRegistry extends BaseSingleton {
288
295
  async ForRoom(roomName, contextUser, provider) {
289
296
  const key = roomName.trim().toLowerCase();
290
297
  const p = this.getProvider(provider);
291
- if (p && typeof p.GetEntityObject === 'function') {
298
+ const user = this.resolveUser(contextUser);
299
+ if (!user) {
300
+ this.noteNoUser();
301
+ }
302
+ if (p && user && typeof p.GetEntityObject === 'function') {
292
303
  try {
293
304
  const rv = this.getRunView(p);
294
- const user = contextUser ?? this.deps.ContextUser;
295
305
  const result = await rv.RunView({
296
306
  EntityName: 'MJ: Interaction Offers',
297
307
  ExtraFilter: `RoomName = '${EscapeSQLString(roomName.trim())}'`,
@@ -319,7 +329,7 @@ export class HandoffOfferRegistry extends BaseSingleton {
319
329
  async ResolveForUser(offerID, userID, status, contextUser, provider) {
320
330
  const p = this.getProvider(provider);
321
331
  if (p && typeof p.GetEntityObject === 'function') {
322
- const user = contextUser ?? this.deps.ContextUser;
332
+ const user = this.resolveUser(contextUser);
323
333
  try {
324
334
  return await RunInEntityTransaction(asTransactionCapable(p), async () => {
325
335
  const entity = await p.GetEntityObject('MJ: Interaction Offers', user);
@@ -380,7 +390,7 @@ export class HandoffOfferRegistry extends BaseSingleton {
380
390
  async Close(offerID, status, contextUser, provider) {
381
391
  const p = this.getProvider(provider);
382
392
  if (p && typeof p.GetEntityObject === 'function') {
383
- const user = contextUser ?? this.deps.ContextUser;
393
+ const user = this.resolveUser(contextUser);
384
394
  try {
385
395
  return await RunInEntityTransaction(asTransactionCapable(p), async () => {
386
396
  const entity = await p.GetEntityObject('MJ: Interaction Offers', user);
@@ -426,10 +436,13 @@ export class HandoffOfferRegistry extends BaseSingleton {
426
436
  const now = this.now();
427
437
  let swept = 0;
428
438
  const p = this.getProvider(provider);
429
- if (p && typeof p.GetEntityObject === 'function') {
439
+ const user = this.resolveUser(contextUser);
440
+ if (!user) {
441
+ this.noteNoUser();
442
+ }
443
+ if (p && user && typeof p.GetEntityObject === 'function') {
430
444
  try {
431
445
  const rv = this.getRunView(p);
432
- const user = contextUser ?? this.deps.ContextUser;
433
446
  const result = await rv.RunView({
434
447
  EntityName: 'MJ: Interaction Offers',
435
448
  ExtraFilter: `Status = 'Pending' AND ExpiresAt <= '${new Date(now).toISOString()}'`,
@@ -508,6 +521,20 @@ export class HandoffOfferRegistry extends BaseSingleton {
508
521
  LogError(`[HandoffOfferRegistry] publish failed: ${e instanceof Error ? e.message : String(e)}`);
509
522
  }
510
523
  }
524
+ /** The caller's user, else the configured server identity, else the lazily resolved one. */
525
+ resolveUser(contextUser) {
526
+ return contextUser ?? this.deps.ContextUser ?? this.deps.ResolveContextUser?.();
527
+ }
528
+ /** Logs once (not per tick) that database queries are being skipped because no user identity is available yet. */
529
+ noteNoUser() {
530
+ if (!this.warnedNoUser) {
531
+ this.warnedNoUser = true;
532
+ LogStatusEx({
533
+ message: '[HandoffOfferRegistry] no context user configured yet; skipping database queries (in-memory offers still served and expired).',
534
+ verboseOnly: true,
535
+ });
536
+ }
537
+ }
511
538
  getProvider(callProvider) {
512
539
  return callProvider ?? this.deps.Provider ?? Metadata.Provider;
513
540
  }