LCOV - code coverage report
Current view: top level - dashql-app/src/session/persistence - session_script_connections.ts Coverage Total Hit
Test: DashQL 915828b Lines: 100.0 % 44 44
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import type { ConnectionState } from '../../connections/connection_state.js';
       2              : import type { SessionConnection, SessionData, SessionScript } from '../../storage/storage_backend.js';
       3              : import { reconcileSessionScripts, sanitizeSessionFiles, withSessionScripts } from '../../storage/session_files.js';
       4              : 
       5              : /// A script of a session file with the connection it runs on
       6              : export interface ResolvedSessionScript {
       7              :     /// The file name
       8              :     name: string;
       9              :     /// The connection of the app the script runs on
      10              :     connection: ConnectionState;
      11              :     /// The connection that the session file names for the script if the app doesn't know it
      12              :     unresolvedConnectionId?: string;
      13              : }
      14              : 
      15              : /// The scripts of a session file resolved to connections of the app
      16              : export interface ResolvedSessionScripts {
      17              :     /// The scripts in feed order
      18              :     scripts: ResolvedSessionScript[];
      19              :     /// The connection that the first script of a session without scripts runs on, null if the session has scripts
      20              :     pendingConnection: ConnectionState | null;
      21              :     /// The session file that describes the resolved scripts. It differs from the stored one when
      22              :     /// script files were added or removed, connections were consolidated, or the session held
      23              :     /// copies of connections that no script uses.
      24              :     session: SessionData;
      25              : }
      26              : 
      27              : /// Resolve a connection of a session to a connection of the app, null if it is unknown.
      28              : /// `copy` is the copy that the session file holds, null if it holds none. A resolver may register
      29              : /// an unknown connection from its copy.
      30              : export type SessionConnectionResolver = (connectionId: string, copy: SessionConnection | null) => ConnectionState | null;
      31              : 
      32              : /// Resolve the scripts of a session file to the connections of the app.
      33              : ///
      34              : /// Every path that turns a session file into scripts resolves here: the restoration of the app, an
      35              : /// import (through the restoration) and the reload of a native folder that changed on disk.
      36              : /// The session file lists the scripts in feed order with the ids of their connections, script files
      37              : /// without an entry are appended on the connection of the script before them. A script whose
      38              : /// connection can't be resolved runs on the fallback connection, the embedded database, and the
      39              : /// session file keeps its reference. A session without scripts resolves the connection it holds.
      40            1 : export function resolveSessionScripts(
      41            1 :     session: SessionData,
      42            1 :     fileNames: readonly string[],
      43            1 :     fallback: () => ConnectionState,
      44            1 :     resolve: SessionConnectionResolver,
      45            1 :     onUnresolved: (connectionId: string) => void = () => { },
      46            1 : ): ResolvedSessionScripts {
      47            1 :     const copies = new Map(session.connections.map(connection => [connection.connectionId, connection]));
      48            1 :     const resolved = new Map<string, ConnectionState | null>();
      49            1 :     const resolveId = (connectionId: string): ConnectionState | null => {
      50            1 :         if (!resolved.has(connectionId)) {
      51            1 :             const connection = resolve(connectionId, copies.get(connectionId) ?? null);
      52            1 :             if (connection == null) onUnresolved(connectionId);
      53            1 :             resolved.set(connectionId, connection);
      54            1 :         }
      55            1 :         return resolved.get(connectionId) ?? null;
      56            1 :     };
      57            1 :     const scriptOf = (name: string, connectionId: string): ResolvedSessionScript => {
      58            1 :         const connection = resolveId(connectionId);
      59            1 :         return connection != null
      60            1 :             ? { name, connection }
      61            1 :             : { name, connection: fallback(), unresolvedConnectionId: connectionId };
      62            1 :     };
      63            1 :     const firstConnectionId = session.connections[0]?.connectionId ?? null;
      64            1 :     const listed = reconcileSessionScripts(sanitizeSessionFiles(session).scripts, fileNames, firstConnectionId ?? '').scripts;
      65            1 :     const scripts = listed.map(entry => scriptOf(entry.name, entry.connectionId));
      66            1 :     const pendingConnection = scripts.length > 0 ? null
      67            1 :         : (firstConnectionId == null ? null : resolveId(firstConnectionId)) ?? fallback();
      68            1 :     const list: SessionScript[] = scripts.map(script => ({ name: script.name, connectionId: script.unresolvedConnectionId ?? script.connection.connectionId }));
      69            1 :     const used = [...(pendingConnection == null ? [] : [pendingConnection]), ...scripts.map(script => script.connection)]
      70            1 :         .map(connection => ({ connectionId: connection.connectionId, params: connection.params }));
      71            1 :     return {
      72            1 :         scripts,
      73            1 :         pendingConnection,
      74            1 :         session: withSessionScripts(session, list, used),
      75            1 :     };
      76            1 : }
      77              : 
      78              : /// Does a resolved session file differ from the stored one in its scripts or connections?
      79            1 : export function sessionScriptsResolutionChanged(stored: SessionData, resolved: SessionData): boolean {
      80            1 :     const refs = (session: SessionData) => JSON.stringify([
      81            1 :         session.connections.map(connection => connection.connectionId),
      82            1 :         session.scripts ?? [],
      83            1 :     ]);
      84            1 :     return refs(stored) !== refs(resolved);
      85            1 : }
        

Generated by: LCOV version 2.0-1