dsh-mobile 0.3.16 → 0.4.1

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/lib/index.d.mts CHANGED
@@ -85,6 +85,13 @@ interface SessionAuthorization {
85
85
  readonly deviceId: string;
86
86
  readonly expiresAt: number;
87
87
  }
88
+ /** Result of a persistent-device reachability check without opening a Session. */
89
+ interface DeviceProbeResult {
90
+ readonly deviceId: string;
91
+ readonly deviceExpiresAt: number;
92
+ }
93
+ /** Why a short-lived Session ended; only device revocation is sent to clients. */
94
+ type SessionEndReason = 'logout' | 'expired' | 'evicted' | 'revoked';
88
95
  /** Safe device metadata returned by the loopback administration API. */
89
96
  interface DeviceSummary {
90
97
  readonly id: string;
@@ -139,6 +146,8 @@ declare class AccessController {
139
146
  pair(sourceKey: string, token: string, label?: string): Promise<PairingResult>;
140
147
  /** Exchange a valid persistent device credential for a new short Session. */
141
148
  renew(deviceToken: string): Promise<RenewalResult>;
149
+ /** Validate a persistent device credential without consuming a Session slot. */
150
+ probe(deviceToken: string): Promise<DeviceProbeResult>;
142
151
  /** Resolve a short Session Cookie without revealing whether device or Session failed. */
143
152
  authorizeSession(sessionToken: string): SessionAuthorization;
144
153
  /** Require the Session-bound anti-CSRF value for an authenticated mutation. */
@@ -157,7 +166,7 @@ declare class AccessController {
157
166
  expiresAt?: number;
158
167
  };
159
168
  /** Subscribe gateway resources to Session logout, expiry, eviction, and device revocation. */
160
- onSessionEnded(listener: (authorization: SessionAuthorization) => void): () => void;
169
+ onSessionEnded(listener: (authorization: SessionAuthorization, reason: SessionEndReason) => void): () => void;
161
170
  /** Stop new operations, drain durable mutations, then clear volatile credentials. */
162
171
  close(): Promise<void>;
163
172
  private finishClose;
@@ -427,8 +436,10 @@ declare class MobileExtensionError extends Error {
427
436
  constructor(code: string, message: string, status?: number);
428
437
  }
429
438
  /** One host-side action exposed by an extension. */
439
+ type CallableActionInput = (value?: never, options?: never) => unknown;
430
440
  interface MobileHostAction {
431
- readonly input?: {
441
+ /** A callable Schemastery schema or an adapter exposing parse(). */
442
+ readonly input?: CallableActionInput | {
432
443
  parse(value: unknown): unknown;
433
444
  };
434
445
  readonly run: (context: MobileActionContext, input: unknown) => unknown | Promise<unknown>;
@@ -598,6 +609,9 @@ declare class MobileAccessGateway {
598
609
  private readonly mobileBootBatches;
599
610
  private readonly extensionEventListeners;
600
611
  private extensionEventRevision;
612
+ private readonly taskEventListeners;
613
+ private readonly deviceEventListeners;
614
+ private readonly pendingDeviceRevocations;
601
615
  private extensionChangeTimer;
602
616
  private extensionChangeTask;
603
617
  private legacyCustomDigest;
@@ -612,6 +626,7 @@ declare class MobileAccessGateway {
612
626
  private readonly removeSessionListener;
613
627
  private readonly removeExtensionContentListener;
614
628
  private readonly renewLimiter;
629
+ private readonly probeLimiter;
615
630
  constructor(config: ResolvedGatewayConfig, store: DeviceStore, extensions?: MobileAccessService | undefined, upstreamAuthenticatedUrl?: string | undefined, extraWebSocketPaths?: {
616
631
  has(pathname: string): boolean;
617
632
  } | undefined, blockedUpgradeLog?: BlockedUpgradePathLog | undefined);
@@ -635,6 +650,7 @@ declare class MobileAccessGateway {
635
650
  private handleRenew;
636
651
  private handleNativePair;
637
652
  private handleNativeRenew;
653
+ private handleNativeProbe;
638
654
  private handleLogout;
639
655
  private handleExternalRequest;
640
656
  private handleExtensionRequest;
@@ -664,6 +680,13 @@ declare class MobileAccessGateway {
664
680
  private proxyHttp;
665
681
  private abortSessionResources;
666
682
  private broadcastExtensionChange;
683
+ /** Fan a completed task to every phone holding this gateway's event stream. */
684
+ broadcastTaskEvent(event: {
685
+ readonly sessionId: string;
686
+ readonly turn: number;
687
+ }): void;
688
+ /** Notify only the device whose persistent credential was revoked by the Host. */
689
+ private broadcastDeviceRevoked;
667
690
  private pollLegacyCustomChanges;
668
691
  private openExtensionEventStream;
669
692
  private readUpgradeResponse;
@@ -934,6 +957,69 @@ declare class FrpController implements RemoteProviderController {
934
957
  private stopProcessAndGateway;
935
958
  }
936
959
  //#endregion
960
+ //#region src/task-events.d.ts
961
+ /**
962
+ * Host-side task-completion fan-out for phone notifications.
963
+ *
964
+ * The exact moment a run ends is known only on the Host (the phone page can
965
+ * merely infer it from UI state), so this module watches the public
966
+ * `session/event` bus for completed root turns and hands them to a hub that
967
+ * fans out to every live mobile gateway. Phones render the text locally, so
968
+ * no user content crosses this boundary — only opaque session and turn ids.
969
+ */
970
+ /** A completed root turn worth announcing on paired phones. */
971
+ interface TaskCompletionEvent {
972
+ readonly sessionId: string;
973
+ readonly turn: number;
974
+ }
975
+ /** Minimal session shape read off the `session/event` bus. */
976
+ interface TaskEventSession {
977
+ readonly id: unknown;
978
+ readonly header?: {
979
+ readonly parentSession?: unknown;
980
+ } | null | undefined;
981
+ }
982
+ /**
983
+ * Minimal turn event shape read off the `session/event` bus. Fields stay
984
+ * unknown here and are validated at runtime below so this module never
985
+ * depends on the harness session packages.
986
+ */
987
+ interface TaskTurnEvent {
988
+ readonly type: string;
989
+ readonly data?: unknown;
990
+ }
991
+ /** Structural slice of the Host context this module needs (keeps tests cordis-free). */
992
+ interface TaskEventContext {
993
+ on(event: 'session/event', handler: (session: TaskEventSession, event: TaskTurnEvent) => void): () => void;
994
+ }
995
+ interface TaskEventWatcherOptions {
996
+ /** Trailing debounce per session that merges turn-boundary bursts. */
997
+ readonly debounceMs?: number;
998
+ readonly onTaskCompleted: (event: TaskCompletionEvent) => void;
999
+ readonly log?: (event: string, fields: Readonly<Record<string, string | number | boolean>>) => void;
1000
+ }
1001
+ declare const TASK_EVENT_DEBOUNCE_MS = 1000;
1002
+ /**
1003
+ * Subscribe to completed root turns. Subagent turns are skipped so one task
1004
+ * announces once, and rapid turn boundaries collapse into a single event.
1005
+ * Returns a disposer that also drops pending debounces.
1006
+ */
1007
+ declare function watchTaskCompletions(ctx: TaskEventContext, options: TaskEventWatcherOptions): () => void;
1008
+ /** Receives fanned-out completion events (normally a mobile gateway). */
1009
+ interface TaskEventSink {
1010
+ broadcastTaskEvent(event: TaskCompletionEvent): void;
1011
+ }
1012
+ /** One subscription feeding every live gateway; gateways register on start. */
1013
+ declare class TaskEventHub {
1014
+ private readonly sinks;
1015
+ /** Register a sink; returns its disposer. */
1016
+ add(sink: TaskEventSink): () => void;
1017
+ /** Fan out to a snapshot so a failing sink cannot break its siblings. */
1018
+ broadcast(event: TaskCompletionEvent): void;
1019
+ /** Visible for tests. */
1020
+ get size(): number;
1021
+ }
1022
+ //#endregion
937
1023
  //#region src/plugin.d.ts
938
1024
  /** Stable Cordis plugin name. */
939
1025
  declare const name = "dsh-mobile";
@@ -942,5 +1028,5 @@ declare const inject: string[];
942
1028
  /** Mount the resident control route and its optional authenticated LAN gateway. */
943
1029
  declare function apply(ctx: Context, config: PluginConfig): Promise<void>;
944
1030
  //#endregion
945
- export { AUTH_PREFIX, AccessController, type AccessControllerOptions, AccessError, type AuthoritySpec, type BlockedUpgradePathEntry, BlockedUpgradePathLog, BoundedRateLimiter, CSRF_COOKIE, CSRF_HEADER, Config, FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT, FRP_VHOST_HTTP_PORT, DEVICE_COOKIE, type DeviceSnapshot, type DeviceStore, type DeviceSummary, type DisabledTlsConfig, EXTENSION_LIMITS, FRP_CADDY_IMPORT_LINE, FRP_CADDY_SNIPPET_MARKER, FRP_CADDY_SNIPPET_PATH, FRP_COMPONENT_RELEASES, FrpComponentManager, type FrpComponentStatus, FrpConfigStore, type FrpConfigurationStatus, FrpController, type FrpControllerOptions, type FrpSettings, type FrpState, type FrpStatus, JsonDeviceStore, JsonMobileAccessControlStore, JsonRemoteProviderStore, LOCAL_ADMIN_PREFIX, type LocalExtensionManifest, MAX_BLOCKED_UPGRADE_PATHS, MAX_EXTRA_WEBSOCKET_PATHS, MAX_WEBSOCKET_PATH_LENGTH, MemoryDeviceStore, type MobileAccessControlState, type MobileAccessControlStore, MobileAccessGateway, MobileAccessGatewayController, type MobileAccessService as MobileAccessRegistry, MobileAccessService, type MobileAccessRuntime, type MobileActionContext, type MobileExtensionClientEntry, type MobileExtensionDefinition, MobileExtensionError, type MobileExtensionManifest, type MobileExtensionStatus, type MobileHostAction, type MobileHostRoute, type MobileRouteRequest, type MobileRouteResponse, type PairingResult, type ParsedCidr, type PluginConfig, type ProvidedTlsConfig, type RemoteProvider, type RemoteProviderController, type RemoteProviderState, type RemoteProviderStatus, type RenewalResult, RequestTrustPolicy, type ResolvedGatewayConfig, SESSION_COOKIE, type SessionAuthorization, type StoredDevice, type TlsConfig, WS_PATHS, WebSocketPathStore, addressAllowed, apply, assertExtensionId, configuredRemoteProvider, createCaddySite, createFrpServerTemplate, createFrpcToml, createMobileAccessService, createRestrictedFrpServerTemplate, inject, isGloballyRoutableIpv4, isLoopbackAddress, mergeSavedFrpSettings, mergeSavedFrpTarget, name, normalizeWebSocketPaths, parseAuthority, parseCidr, parseControlFile, parseDeviceSnapshot, parseExtensionManifest, parseFrpSettings, parseGatewayConfig, parseMobileAccessControlState, parseRemoteProviderState, resolveAuthority, rewriteMobileIndex, validateFrpPublicOrigin, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, validateWebSocketPath };
1031
+ export { AUTH_PREFIX, AccessController, type AccessControllerOptions, AccessError, type AuthoritySpec, type BlockedUpgradePathEntry, BlockedUpgradePathLog, BoundedRateLimiter, CSRF_COOKIE, CSRF_HEADER, Config, FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT, FRP_VHOST_HTTP_PORT, DEVICE_COOKIE, type DeviceProbeResult, type DeviceSnapshot, type DeviceStore, type DeviceSummary, type DisabledTlsConfig, EXTENSION_LIMITS, FRP_CADDY_IMPORT_LINE, FRP_CADDY_SNIPPET_MARKER, FRP_CADDY_SNIPPET_PATH, FRP_COMPONENT_RELEASES, FrpComponentManager, type FrpComponentStatus, FrpConfigStore, type FrpConfigurationStatus, FrpController, type FrpControllerOptions, type FrpSettings, type FrpState, type FrpStatus, JsonDeviceStore, JsonMobileAccessControlStore, JsonRemoteProviderStore, LOCAL_ADMIN_PREFIX, type LocalExtensionManifest, MAX_BLOCKED_UPGRADE_PATHS, MAX_EXTRA_WEBSOCKET_PATHS, MAX_WEBSOCKET_PATH_LENGTH, MemoryDeviceStore, type MobileAccessControlState, type MobileAccessControlStore, MobileAccessGateway, MobileAccessGatewayController, type MobileAccessService as MobileAccessRegistry, MobileAccessService, type MobileAccessRuntime, type MobileActionContext, type MobileExtensionClientEntry, type MobileExtensionDefinition, MobileExtensionError, type MobileExtensionManifest, type MobileExtensionStatus, type MobileHostAction, type MobileHostRoute, type MobileRouteRequest, type MobileRouteResponse, type PairingResult, type ParsedCidr, type PluginConfig, type ProvidedTlsConfig, type RemoteProvider, type RemoteProviderController, type RemoteProviderState, type RemoteProviderStatus, type RenewalResult, RequestTrustPolicy, type ResolvedGatewayConfig, SESSION_COOKIE, type SessionAuthorization, type SessionEndReason, type StoredDevice, TASK_EVENT_DEBOUNCE_MS, type TaskCompletionEvent, type TaskEventContext, TaskEventHub, type TaskEventSession, type TaskEventSink, type TaskEventWatcherOptions, type TaskTurnEvent, type TlsConfig, WS_PATHS, WebSocketPathStore, addressAllowed, apply, assertExtensionId, configuredRemoteProvider, createCaddySite, createFrpServerTemplate, createFrpcToml, createMobileAccessService, createRestrictedFrpServerTemplate, inject, isGloballyRoutableIpv4, isLoopbackAddress, mergeSavedFrpSettings, mergeSavedFrpTarget, name, normalizeWebSocketPaths, parseAuthority, parseCidr, parseControlFile, parseDeviceSnapshot, parseExtensionManifest, parseFrpSettings, parseGatewayConfig, parseMobileAccessControlState, parseRemoteProviderState, resolveAuthority, rewriteMobileIndex, validateFrpPublicOrigin, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, validateWebSocketPath, watchTaskCompletions };
946
1032
  //# sourceMappingURL=index.d.mts.map