Member Junction
    Preparing search index...

    Interface RealtimeRecordingRouterDeps

    Dependencies of CreateRealtimeRecordingRouter; injectable so the routes can be tested without a database.

    interface RealtimeRecordingRouterDeps {
        AuthorizeSession: (
            session: MJAIAgentSessionEntity,
            contextUser: UserInfo,
            provider: IMetadataProvider,
        ) => Promise<SessionAccessDecision>;
        GraceMs: () => number;
        LoadOwnedSession: (
            agentSessionId: string,
            contextUser: UserInfo,
            provider: IMetadataProvider,
        ) => Promise<MJAIAgentSessionEntity>;
        Scheduler: IRecordingAssemblyScheduler;
        SystemUser: () => UserInfo;
        CreateLedger(
            provider: DatabaseProviderBase,
            contextUser: UserInfo,
        ): IRealtimeRecordingLedger;
        ResolveCaller(req: Request): RealtimeRecordingCaller;
    }
    Index

    Properties

    AuthorizeSession: (
        session: MJAIAgentSessionEntity,
        contextUser: UserInfo,
        provider: IMetadataProvider,
    ) => Promise<SessionAccessDecision>

    The per-session scope rule of the access decision, applied to the session LoadOwnedSession returned.

    Type Declaration

      • (
            session: MJAIAgentSessionEntity,
            contextUser: UserInfo,
            provider: IMetadataProvider,
        ): Promise<SessionAccessDecision>
      • Decides whether contextUser may address an already-loaded session: the AuthorizeSessionAccess decision, reading the session's conversation only when that decision needs it.

        AuthorizeSessionAccess decides a principal without a scope identity — a named user with no magic-link scope, the usual signed-in caller — from the owner check alone, and refuses a non-owner before it looks at anything else, so neither needs the conversation read. This function and that one encode the same rule on purpose and live together for that reason: change the rule there, change the read here. The AuthorizeLoadedSession table test in sessionAccess.test.ts fails if the two ever disagree.

        Parameters

        • session: MJAIAgentSessionEntity

          the session, loaded through the caller's own gate

        • contextUser: UserInfo

          the authenticated caller; the conversation, when read, is read as this user (RLS applies)

        • provider: IMetadataProvider

          the request-scoped provider

        Returns Promise<SessionAccessDecision>

    GraceMs: () => number

    Grace before an incomplete recording is assembled as Partial.

    LoadOwnedSession: (
        agentSessionId: string,
        contextUser: UserInfo,
        provider: IMetadataProvider,
    ) => Promise<MJAIAgentSessionEntity>

    Type Declaration

      • (
            agentSessionId: string,
            contextUser: UserInfo,
            provider: IMetadataProvider,
        ): Promise<MJAIAgentSessionEntity>
      • Loads a session under the caller's identity and enforces ownership: UserID === contextUser.ID, then the scope rule of AuthorizeSessionAccess (every anonymous visitor shares one Anonymous user, so the session's conversation ExternalID must equal the caller's scope identity). It deliberately does NOT reject Closed sessions: the final channel-state flush and the recording terminal signal legitimately arrive after the session closed. Loading as the caller also applies the entity's row-level security.

        Parameters

        Returns Promise<MJAIAgentSessionEntity>

        RealtimeSessionNotFoundError when the row does not load

        RealtimeSessionOwnershipError when another user owns the session (logged with both user ids) or the scope rule refuses the caller (logged with the refusal reason)

    SystemUser: () => UserInfo

    The server's system user, or null when it is not available. Deciding whether a recording is ready reads the shard entity, which callers (UI users, widget guests) deliberately cannot read; that read is the server's own scheduling decision, made after the caller was authorized, so it runs as this user. With none, nothing is scheduled and the session janitor assembles the recording.

    Methods