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/CHANGELOG.md +36 -4
- package/README.en.md +82 -14
- package/README.md +84 -22
- package/SECURITY.md +2 -0
- package/docs/SELF_HOSTED_FRP.en.md +75 -0
- package/docs/SELF_HOSTED_FRP.md +3 -1
- package/lib/cli.js +99 -82
- package/lib/cli.js.map +1 -1
- package/lib/client.js +808 -103
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +89 -3
- package/lib/index.mjs +727 -131
- package/lib/index.mjs.map +1 -1
- package/package.json +18 -9
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
|
-
|
|
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
|