@bodhiapp/setup-modal-types 0.0.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/extension.ts ADDED
@@ -0,0 +1,31 @@
1
+ // Extension error codes
2
+ export type ExtensionErrorCode = 'ext-not-installed' | 'ext-connection-failed' | 'ext-unsupported-version';
3
+
4
+ // Extension error code constants
5
+ export const EXT_NOT_INSTALLED: ExtensionErrorCode = 'ext-not-installed';
6
+ export const EXT_CONNECTION_FAILED: ExtensionErrorCode = 'ext-connection-failed';
7
+ export const EXT_UNSUPPORTED_VERSION: ExtensionErrorCode = 'ext-unsupported-version';
8
+
9
+ // Extension state interfaces
10
+ export interface ExtensionStateReady {
11
+ /** Current extension status */
12
+ status: 'ready';
13
+ /** Extension version */
14
+ version: string;
15
+ /** Extension ID (always present when ready) */
16
+ id: string;
17
+ }
18
+
19
+ export interface ExtensionStateNotReady {
20
+ /** Current extension status */
21
+ status: 'unreachable' | 'not-installed' | 'unsupported';
22
+ /** Error details */
23
+ error: {
24
+ /** Error message */
25
+ message: string;
26
+ /** Error code */
27
+ code: ExtensionErrorCode;
28
+ };
29
+ }
30
+
31
+ export type ExtensionState = ExtensionStateReady | ExtensionStateNotReady;
package/index.ts ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Consolidated types for setup-modal
3
+ *
4
+ * This folder contains all domain and protocol types organized by domain.
5
+ * It is designed to be independent and copyable to other packages.
6
+ */
7
+
8
+ // Platform types
9
+ export type { BrowserType, OSType, EnvState, SupportedBrowser, NotSupportedBrowser, Browser, SupportedOS, NotSupportedOS, OS } from './platform';
10
+
11
+ // Extension types
12
+ export type { ExtensionErrorCode, ExtensionStateReady, ExtensionStateNotReady, ExtensionState } from './extension';
13
+ export { EXT_NOT_INSTALLED, EXT_CONNECTION_FAILED, EXT_UNSUPPORTED_VERSION } from './extension';
14
+
15
+ // Server types
16
+ export type { ServerErrorCode, ServerStateReady, ServerStateReachable, ServerStatePending, ServerStateUnreachable, ServerStateError, ServerState } from './server';
17
+ export {
18
+ SERVER_PENDING_EXT_READY,
19
+ SERVER_CONN_REFUSED,
20
+ SERVER_CONN_TIMEOUT,
21
+ SERVER_NOT_FOUND,
22
+ SERVER_NETWORK_UNREACHABLE,
23
+ SERVER_SERVICE_UNAVAILABLE,
24
+ SERVER_UNEXPECTED_ERROR,
25
+ SERVER_IN_SETUP_STATUS,
26
+ SERVER_IN_ADMIN_STATUS,
27
+ } from './server';
28
+
29
+ // LNA types
30
+ export type {
31
+ LnaErrorCode,
32
+ LnaStatePrompt,
33
+ LnaStateSkipped,
34
+ LnaStateGranted,
35
+ LnaStateUnreachable,
36
+ LnaStateDenied,
37
+ LnaStateUnsupported,
38
+ LnaState,
39
+ LnaServerStatePending,
40
+ LnaServerStateReady,
41
+ LnaServerStateSetup,
42
+ LnaServerStateResourceAdmin,
43
+ LnaServerStateError,
44
+ LnaServerState,
45
+ } from './lna';
46
+ export { LNA_UNREACHABLE, LNA_PERMISSION_DENIED } from './lna';
47
+
48
+ // State types
49
+ export { SetupStep, DEFAULT_USER_CONFIRMATIONS, DEFAULT_SETUP_STATE } from './state';
50
+ export type { SelectedConnection, UserConfirmations, SetupState } from './state';
51
+
52
+ // Protocol types
53
+ export type { RequestId, MessageKind, RequestMessage, ResponseMessage, ErrorMessage, EventMessage, ProtocolMessage } from './protocol';
54
+ export { isRequestMessage, isResponseMessage, isErrorMessage, isEventMessage } from './protocol';
55
+
56
+ // Message types
57
+ export type { MessageTypeRegistry, MessageType, RequestPayload, ResponsePayload, RequestHandlers } from './message-types';
58
+ export { MSG, isMessageType } from './message-types';
59
+
60
+ // Type guards
61
+ export {
62
+ isExtensionStateReady,
63
+ isExtensionStateNotReady,
64
+ isServerStateReady,
65
+ isServerStateReachable,
66
+ isServerStatePending,
67
+ isServerStateUnreachable,
68
+ isServerStateError,
69
+ isLnaStatePrompt,
70
+ isLnaStateSkipped,
71
+ isLnaStateGranted,
72
+ isLnaStateUnreachable,
73
+ isLnaStateDenied,
74
+ isLnaStateUnsupported,
75
+ isLnaServerStatePending,
76
+ isLnaServerStateReady,
77
+ isLnaServerStateSetup,
78
+ isLnaServerStateResourceAdmin,
79
+ isLnaServerStateError,
80
+ isSupportedBrowser,
81
+ isNotSupportedBrowser,
82
+ isSupportedOS,
83
+ isNotSupportedOS,
84
+ } from './type-guards';
package/lna.ts ADDED
@@ -0,0 +1,75 @@
1
+ // LNA error codes
2
+ export type LnaErrorCode = 'lna-unreachable' | 'lna-permission-denied';
3
+
4
+ // LNA error code constants
5
+ export const LNA_UNREACHABLE: LnaErrorCode = 'lna-unreachable';
6
+ export const LNA_PERMISSION_DENIED: LnaErrorCode = 'lna-permission-denied';
7
+
8
+ // LNA (Local Network Access) state interfaces
9
+ // Aligned with browser permission API states: prompt, granted, denied
10
+ export interface LnaStatePrompt {
11
+ status: 'prompt';
12
+ serverUrl?: string; // For URL input default from localStorage
13
+ }
14
+
15
+ export interface LnaStateSkipped {
16
+ status: 'skipped';
17
+ serverUrl?: string; // For URL input default from localStorage
18
+ }
19
+
20
+ export interface LnaStateGranted {
21
+ status: 'granted';
22
+ serverUrl: string;
23
+ }
24
+
25
+ export interface LnaStateUnreachable {
26
+ status: 'unreachable';
27
+ serverUrl: string;
28
+ error: {
29
+ message: string;
30
+ code: LnaErrorCode;
31
+ };
32
+ }
33
+
34
+ export interface LnaStateDenied {
35
+ status: 'denied';
36
+ error: {
37
+ message: string;
38
+ code: LnaErrorCode;
39
+ };
40
+ }
41
+
42
+ export interface LnaStateUnsupported {
43
+ status: 'unsupported';
44
+ }
45
+
46
+ export type LnaState = LnaStatePrompt | LnaStateSkipped | LnaStateGranted | LnaStateUnreachable | LnaStateDenied | LnaStateUnsupported;
47
+
48
+ // LNA Server state interfaces
49
+ export interface LnaServerStatePending {
50
+ status: 'pending-lna-ready';
51
+ }
52
+
53
+ export interface LnaServerStateReady {
54
+ status: 'ready';
55
+ version: string;
56
+ }
57
+
58
+ export interface LnaServerStateSetup {
59
+ status: 'setup';
60
+ version: string;
61
+ }
62
+
63
+ export interface LnaServerStateResourceAdmin {
64
+ status: 'resource-admin';
65
+ version: string;
66
+ }
67
+
68
+ export interface LnaServerStateError {
69
+ status: 'error';
70
+ error: {
71
+ message: string;
72
+ };
73
+ }
74
+
75
+ export type LnaServerState = LnaServerStatePending | LnaServerStateReady | LnaServerStateSetup | LnaServerStateResourceAdmin | LnaServerStateError;
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Message Type Registry - Single source of truth for all protocol message types
3
+ *
4
+ * This registry maps message type strings to their payload/response shapes.
5
+ * All other types (RequestPayload, ResponsePayload, etc.) are derived from this registry.
6
+ *
7
+ * Design: Each entry defines:
8
+ * - request: The payload type sent with the request
9
+ * - response: The payload type expected in the response
10
+ *
11
+ * For events (one-way messages), response is void.
12
+ */
13
+
14
+ import type { SetupState } from './state';
15
+
16
+ /**
17
+ * Central registry mapping message types to their payload/response shapes
18
+ * Single source of truth - everything else is inferred!
19
+ */
20
+ export interface MessageTypeRegistry {
21
+ // === Modal → Parent (Commands) ===
22
+
23
+ /**
24
+ * Modal is ready and requesting initial state
25
+ * Sent on modal mount
26
+ */
27
+ 'modal:ready': {
28
+ request: void;
29
+ response: { setupState: SetupState };
30
+ };
31
+
32
+ /**
33
+ * User requested to refresh platform detection
34
+ * Triggers re-detection of browser, OS, extension, server
35
+ */
36
+ 'modal:refresh': {
37
+ request: void;
38
+ response: { setupState: SetupState };
39
+ };
40
+
41
+ /**
42
+ * User requested to close the modal
43
+ * Parent should hide/destroy modal
44
+ */
45
+ 'modal:close': {
46
+ request: void;
47
+ response: void;
48
+ };
49
+
50
+ /**
51
+ * Setup completed successfully
52
+ * Signals parent that user has finished setup
53
+ */
54
+ 'modal:complete': {
55
+ request: void;
56
+ response: void;
57
+ };
58
+
59
+ /**
60
+ * User requested LNA connection to specific server URL
61
+ * Triggers LNA permission request and connection attempt
62
+ */
63
+ 'modal:lna:connect': {
64
+ request: { serverUrl: string };
65
+ response: { success: boolean };
66
+ };
67
+
68
+ /**
69
+ * User chose to skip LNA setup
70
+ * Falls back to extension-only mode
71
+ */
72
+ 'modal:lna:skip': {
73
+ request: void;
74
+ response: { success: boolean };
75
+ };
76
+
77
+ /**
78
+ * User confirmed server installation status
79
+ * Used when server needs to be installed
80
+ */
81
+ 'modal:confirm-server-install': {
82
+ request: { confirmed: boolean };
83
+ response: { success: boolean };
84
+ };
85
+
86
+ /**
87
+ * User selected preferred connection method
88
+ * Allows choosing between LNA and Extension paths
89
+ */
90
+ 'modal:select-connection': {
91
+ request: { connection: 'lna' | 'extension' };
92
+ response: { success: boolean };
93
+ };
94
+
95
+ // === Parent → Modal (Events) ===
96
+
97
+ /**
98
+ * Parent sending updated state to modal
99
+ * Fired when platform detection results change
100
+ */
101
+ 'parent:state-update': {
102
+ request: { setupState: SetupState };
103
+ response: void;
104
+ };
105
+ }
106
+
107
+ // === Derived Types with Full Inference ===
108
+
109
+ /**
110
+ * Union of all valid message type strings
111
+ * Derived from MessageTypeRegistry keys
112
+ */
113
+ export type MessageType = keyof MessageTypeRegistry;
114
+
115
+ /**
116
+ * Extract request payload type for a given message type
117
+ * Returns the 'request' field from the registry entry
118
+ */
119
+ export type RequestPayload<T extends MessageType> = MessageTypeRegistry[T]['request'];
120
+
121
+ /**
122
+ * Extract response payload type for a given message type
123
+ * Returns the 'response' field from the registry entry
124
+ */
125
+ export type ResponsePayload<T extends MessageType> = MessageTypeRegistry[T]['response'];
126
+
127
+ /**
128
+ * Message type constants - Type-safe identifiers
129
+ *
130
+ * @example
131
+ * switch (message.type) {
132
+ * case MSG.MODAL_READY:
133
+ * // Type-safe constant, no typos possible
134
+ * break;
135
+ * }
136
+ */
137
+ export const MSG = {
138
+ // Modal lifecycle
139
+ MODAL_READY: 'modal:ready',
140
+ MODAL_REFRESH: 'modal:refresh',
141
+ MODAL_CLOSE: 'modal:close',
142
+ MODAL_COMPLETE: 'modal:complete',
143
+
144
+ // LNA actions
145
+ MODAL_LNA_CONNECT: 'modal:lna:connect',
146
+ MODAL_LNA_SKIP: 'modal:lna:skip',
147
+
148
+ // Server confirmation
149
+ MODAL_CONFIRM_SERVER_INSTALL: 'modal:confirm-server-install',
150
+
151
+ // Connection selection
152
+ MODAL_SELECT_CONNECTION: 'modal:select-connection',
153
+
154
+ // Parent → Modal events
155
+ PARENT_STATE_UPDATE: 'parent:state-update',
156
+ } as const;
157
+
158
+ /**
159
+ * Type guard that narrows RequestMessage to specific type WITH payload typing
160
+ *
161
+ * Use this for full type safety when you need access to typed payload fields.
162
+ * The guard narrows the generic RequestMessage to RequestMessage<T> where T
163
+ * determines the payload type.
164
+ *
165
+ * @example
166
+ * if (isMessageType(msg, MSG.MODAL_LNA_CONNECT)) {
167
+ * // msg.payload is { serverUrl: string } - fully typed!
168
+ * console.log(msg.payload.serverUrl); // Autocomplete works!
169
+ * }
170
+ */
171
+ export function isMessageType<T extends MessageType>(msg: { type: string }, type: T): msg is { type: T } {
172
+ return msg.type === type;
173
+ }
174
+
175
+ /**
176
+ * Type-safe request handler map
177
+ * Enforces correct payload access AND correct return type for each message
178
+ *
179
+ * Each handler receives a RequestMessage<K> where K is the specific message type,
180
+ * providing full type safety for payload access. The handler must return the
181
+ * correct ResponsePayload<K> type.
182
+ */
183
+ export type RequestHandlers = {
184
+ [K in MessageType]?: (msg: { type: K; requestId: string; payload: RequestPayload<K> }) => ResponsePayload<K>;
185
+ };
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@bodhiapp/setup-modal-types",
3
+ "version": "0.0.1",
4
+ "description": "TypeScript types for Bodhi Setup Modal",
5
+ "type": "module",
6
+ "main": "index.ts",
7
+ "types": "index.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./index.ts",
11
+ "import": "./index.ts",
12
+ "require": "./index.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "*.ts"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/BodhiSearch/bodhi-browser.git",
21
+ "directory": "setup-modal/src/types"
22
+ },
23
+ "license": "MIT",
24
+ "author": "BodhiSearch",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ }
28
+ }
package/platform.ts ADDED
@@ -0,0 +1,43 @@
1
+ // Browser and OS type definitions
2
+ export type BrowserType = 'chrome' | 'edge' | 'firefox' | 'safari' | 'unknown';
3
+ export type OSType = 'macos' | 'windows' | 'linux' | 'unknown';
4
+
5
+ // Environment state interface
6
+ export interface EnvState {
7
+ os: OSType;
8
+ browser: BrowserType;
9
+ }
10
+
11
+ // Browser platform definitions
12
+ export interface SupportedBrowser {
13
+ id: BrowserType;
14
+ status: 'supported';
15
+ name: string;
16
+ extension_url: string;
17
+ }
18
+
19
+ export interface NotSupportedBrowser {
20
+ id: BrowserType;
21
+ status: 'not-supported';
22
+ name: string;
23
+ github_issue_url?: string;
24
+ }
25
+
26
+ export type Browser = SupportedBrowser | NotSupportedBrowser;
27
+
28
+ // OS platform definitions
29
+ export interface SupportedOS {
30
+ id: OSType;
31
+ status: 'supported';
32
+ name: string;
33
+ download_url: string;
34
+ }
35
+
36
+ export interface NotSupportedOS {
37
+ id: OSType;
38
+ status: 'not-supported';
39
+ name: string;
40
+ github_issue_url?: string;
41
+ }
42
+
43
+ export type OS = SupportedOS | NotSupportedOS;
package/protocol.ts ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Core protocol types for setup-modal ↔ parent communication
3
+ *
4
+ * Design principles:
5
+ * - Type-safe request/response correlation
6
+ * - Discriminated unions for message kinds
7
+ * - Branded types for ID safety
8
+ * - Full TypeScript inference from MessageTypeRegistry
9
+ */
10
+
11
+ import type { MessageType, RequestPayload, ResponsePayload } from './message-types';
12
+
13
+ /** Branded type for type-safe request IDs */
14
+ export type RequestId = string & { readonly __brand: 'RequestId' };
15
+
16
+ /** Message kind discriminator */
17
+ export type MessageKind = 'request' | 'response' | 'error' | 'event';
18
+
19
+ /**
20
+ * Request message - expects a response
21
+ * Sent by either modal or parent to request an action
22
+ */
23
+ export interface RequestMessage<T extends MessageType = MessageType> {
24
+ readonly kind: 'request';
25
+ readonly type: T;
26
+ readonly requestId: RequestId;
27
+ readonly payload: RequestPayload<T>;
28
+ }
29
+
30
+ /**
31
+ * Response message - correlates to a request
32
+ * Sent in response to a RequestMessage with matching requestId
33
+ */
34
+ export interface ResponseMessage<T extends MessageType = MessageType> {
35
+ readonly kind: 'response';
36
+ readonly type: T;
37
+ readonly requestId: RequestId;
38
+ readonly payload: ResponsePayload<T>;
39
+ }
40
+
41
+ /**
42
+ * Error response - indicates request failure
43
+ * Sent instead of ResponseMessage when request cannot be fulfilled
44
+ */
45
+ export interface ErrorMessage {
46
+ readonly kind: 'error';
47
+ readonly requestId: RequestId;
48
+ readonly error: {
49
+ code: string;
50
+ message: string;
51
+ details?: unknown;
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Event message - fire-and-forget notification
57
+ * No response expected, used for one-way state updates
58
+ */
59
+ export interface EventMessage<T extends MessageType = MessageType> {
60
+ readonly kind: 'event';
61
+ readonly type: T;
62
+ readonly payload: RequestPayload<T>;
63
+ }
64
+
65
+ /**
66
+ * Union of all protocol messages
67
+ * Discriminated by 'kind' field for type narrowing
68
+ */
69
+ export type ProtocolMessage = RequestMessage | ResponseMessage | ErrorMessage | EventMessage;
70
+
71
+ /**
72
+ * Type guard to check if message is a request
73
+ */
74
+ export function isRequestMessage(msg: ProtocolMessage): msg is RequestMessage {
75
+ return msg.kind === 'request';
76
+ }
77
+
78
+ /**
79
+ * Type guard to check if message is a response
80
+ */
81
+ export function isResponseMessage(msg: ProtocolMessage): msg is ResponseMessage {
82
+ return msg.kind === 'response';
83
+ }
84
+
85
+ /**
86
+ * Type guard to check if message is an error
87
+ */
88
+ export function isErrorMessage(msg: ProtocolMessage): msg is ErrorMessage {
89
+ return msg.kind === 'error';
90
+ }
91
+
92
+ /**
93
+ * Type guard to check if message is an event
94
+ */
95
+ export function isEventMessage(msg: ProtocolMessage): msg is EventMessage {
96
+ return msg.kind === 'event';
97
+ }
package/server.ts ADDED
@@ -0,0 +1,82 @@
1
+ // Server error codes
2
+ export type ServerErrorCode =
3
+ | 'server-pending-ext-ready'
4
+ | 'server-conn-refused'
5
+ | 'server-conn-timeout'
6
+ | 'server-not-found'
7
+ | 'server-network-unreachable'
8
+ | 'server-service-unavailable'
9
+ | 'server-unexpected-error'
10
+ | 'server-in-setup-status'
11
+ | 'server-in-admin-status';
12
+
13
+ // Server error code constants
14
+ export const SERVER_PENDING_EXT_READY: ServerErrorCode = 'server-pending-ext-ready';
15
+ export const SERVER_CONN_REFUSED: ServerErrorCode = 'server-conn-refused';
16
+ export const SERVER_CONN_TIMEOUT: ServerErrorCode = 'server-conn-timeout';
17
+ export const SERVER_NOT_FOUND: ServerErrorCode = 'server-not-found';
18
+ export const SERVER_NETWORK_UNREACHABLE: ServerErrorCode = 'server-network-unreachable';
19
+ export const SERVER_SERVICE_UNAVAILABLE: ServerErrorCode = 'server-service-unavailable';
20
+ export const SERVER_UNEXPECTED_ERROR: ServerErrorCode = 'server-unexpected-error';
21
+ export const SERVER_IN_SETUP_STATUS: ServerErrorCode = 'server-in-setup-status';
22
+ export const SERVER_IN_ADMIN_STATUS: ServerErrorCode = 'server-in-admin-status';
23
+
24
+ // Server state interfaces
25
+ export interface ServerStateReady {
26
+ /** Current server status */
27
+ status: 'ready';
28
+ /** Server version */
29
+ version: string;
30
+ }
31
+
32
+ export interface ServerStateReachable {
33
+ /** Current server status */
34
+ status: 'setup' | 'resource-admin';
35
+ /** Server version */
36
+ version: string;
37
+ /** Error details */
38
+ error: {
39
+ /** Error message */
40
+ message: string;
41
+ /** Error code */
42
+ code: ServerErrorCode;
43
+ };
44
+ }
45
+
46
+ export interface ServerStatePending {
47
+ /** Current server status */
48
+ status: 'pending-extension-ready';
49
+ /** Error details */
50
+ error: {
51
+ /** Error message */
52
+ message: string;
53
+ /** Error code */
54
+ code: ServerErrorCode;
55
+ };
56
+ }
57
+
58
+ export interface ServerStateUnreachable {
59
+ /** Current server status */
60
+ status: 'unreachable';
61
+ /** Error details */
62
+ error: {
63
+ /** Error message */
64
+ message: string;
65
+ /** Error code */
66
+ code: ServerErrorCode;
67
+ };
68
+ }
69
+
70
+ export interface ServerStateError {
71
+ /** Current server status */
72
+ status: 'error';
73
+ /** Error details */
74
+ error: {
75
+ /** Error message */
76
+ message: string;
77
+ /** Error code */
78
+ code: ServerErrorCode;
79
+ };
80
+ }
81
+
82
+ export type ServerState = ServerStateReady | ServerStateReachable | ServerStatePending | ServerStateUnreachable | ServerStateError;
package/state.ts ADDED
@@ -0,0 +1,65 @@
1
+ import type { Browser, EnvState, OS } from './platform';
2
+ import type { ExtensionState } from './extension';
3
+ import type { ServerState } from './server';
4
+ import type { LnaServerState, LnaState } from './lna';
5
+
6
+ // Step enum for navigation
7
+ export enum SetupStep {
8
+ PLATFORM_CHECK = 'platform-check',
9
+ SERVER_SETUP = 'server-setup',
10
+ LNA_SETUP = 'lna-setup',
11
+ EXTENSION_SETUP = 'extension-setup',
12
+ COMPLETE = 'complete',
13
+ }
14
+
15
+ // Selected connection type for user preference
16
+ export type SelectedConnection = 'lna' | 'extension' | null;
17
+
18
+ // User confirmations interface for manual confirmation states
19
+ export interface UserConfirmations {
20
+ /** Whether user has confirmed server installation */
21
+ serverInstall: boolean;
22
+ }
23
+
24
+ // Default user confirmations
25
+ export const DEFAULT_USER_CONFIRMATIONS: UserConfirmations = {
26
+ serverInstall: false,
27
+ };
28
+
29
+ // Main setup state interface
30
+ export interface SetupState {
31
+ /** Extension state details */
32
+ extension: ExtensionState;
33
+ /** Server state details (via extension) */
34
+ server: ServerState;
35
+ /** LNA connection state */
36
+ lna: LnaState;
37
+ /** Server state details (via LNA) */
38
+ lnaServer: LnaServerState;
39
+ /** Environment detection */
40
+ env: EnvState;
41
+ /** Browser platforms list */
42
+ browsers: Browser[];
43
+ /** Operating systems list */
44
+ os: OS[];
45
+ /** User confirmations for manual steps */
46
+ userConfirmations: UserConfirmations;
47
+ /** User's preferred connection method (null = auto-select based on priority) */
48
+ selectedConnection: SelectedConnection;
49
+ }
50
+
51
+ /**
52
+ * Default setup state used during initialization before parent sends real state
53
+ * Represents "loading" state - unknown platform, no extension, no server
54
+ */
55
+ export const DEFAULT_SETUP_STATE: SetupState = {
56
+ extension: { status: 'not-installed', error: { message: 'Loading...', code: 'ext-not-installed' } },
57
+ server: { status: 'pending-extension-ready', error: { message: 'Loading...', code: 'server-pending-ext-ready' } },
58
+ lna: { status: 'prompt' },
59
+ lnaServer: { status: 'pending-lna-ready' },
60
+ env: { browser: 'unknown', os: 'unknown' },
61
+ browsers: [],
62
+ os: [],
63
+ userConfirmations: DEFAULT_USER_CONFIRMATIONS,
64
+ selectedConnection: null,
65
+ };
package/type-guards.ts ADDED
@@ -0,0 +1,126 @@
1
+ import type { ExtensionState, ExtensionStateNotReady, ExtensionStateReady } from './extension';
2
+ import type { ServerState, ServerStateError, ServerStatePending, ServerStateReachable, ServerStateReady, ServerStateUnreachable } from './server';
3
+ import type {
4
+ LnaServerState,
5
+ LnaServerStateError,
6
+ LnaServerStatePending,
7
+ LnaServerStateReady,
8
+ LnaServerStateResourceAdmin,
9
+ LnaServerStateSetup,
10
+ LnaState,
11
+ LnaStateDenied,
12
+ LnaStateGranted,
13
+ LnaStatePrompt,
14
+ LnaStateSkipped,
15
+ LnaStateUnreachable,
16
+ LnaStateUnsupported,
17
+ } from './lna';
18
+ import type { Browser, NotSupportedBrowser, NotSupportedOS, OS, SupportedBrowser, SupportedOS } from './platform';
19
+
20
+ // ============================================
21
+ // Extension Type Guards
22
+ // ============================================
23
+
24
+ export function isExtensionStateReady(ext: ExtensionState): ext is ExtensionStateReady {
25
+ return ext.status === 'ready';
26
+ }
27
+
28
+ export function isExtensionStateNotReady(ext: ExtensionState): ext is ExtensionStateNotReady {
29
+ return ext.status !== 'ready';
30
+ }
31
+
32
+ // ============================================
33
+ // Server Type Guards
34
+ // ============================================
35
+
36
+ export function isServerStateReady(server: ServerState): server is ServerStateReady {
37
+ return server.status === 'ready';
38
+ }
39
+
40
+ export function isServerStateReachable(server: ServerState): server is ServerStateReachable {
41
+ return server.status === 'setup' || server.status === 'resource-admin';
42
+ }
43
+
44
+ export function isServerStatePending(server: ServerState): server is ServerStatePending {
45
+ return server.status === 'pending-extension-ready';
46
+ }
47
+
48
+ export function isServerStateUnreachable(server: ServerState): server is ServerStateUnreachable {
49
+ return server.status === 'unreachable';
50
+ }
51
+
52
+ export function isServerStateError(server: ServerState): server is ServerStateError {
53
+ return server.status === 'error';
54
+ }
55
+
56
+ // ============================================
57
+ // LNA Type Guards
58
+ // ============================================
59
+
60
+ export function isLnaStatePrompt(lna: LnaState): lna is LnaStatePrompt {
61
+ return lna.status === 'prompt';
62
+ }
63
+
64
+ export function isLnaStateSkipped(lna: LnaState): lna is LnaStateSkipped {
65
+ return lna.status === 'skipped';
66
+ }
67
+
68
+ export function isLnaStateGranted(lna: LnaState): lna is LnaStateGranted {
69
+ return lna.status === 'granted';
70
+ }
71
+
72
+ export function isLnaStateUnreachable(lna: LnaState): lna is LnaStateUnreachable {
73
+ return lna.status === 'unreachable';
74
+ }
75
+
76
+ export function isLnaStateDenied(lna: LnaState): lna is LnaStateDenied {
77
+ return lna.status === 'denied';
78
+ }
79
+
80
+ export function isLnaStateUnsupported(lna: LnaState): lna is LnaStateUnsupported {
81
+ return lna.status === 'unsupported';
82
+ }
83
+
84
+ // ============================================
85
+ // LNA Server Type Guards
86
+ // ============================================
87
+
88
+ export function isLnaServerStatePending(server: LnaServerState): server is LnaServerStatePending {
89
+ return server.status === 'pending-lna-ready';
90
+ }
91
+
92
+ export function isLnaServerStateReady(server: LnaServerState): server is LnaServerStateReady {
93
+ return server.status === 'ready';
94
+ }
95
+
96
+ export function isLnaServerStateSetup(server: LnaServerState): server is LnaServerStateSetup {
97
+ return server.status === 'setup';
98
+ }
99
+
100
+ export function isLnaServerStateResourceAdmin(server: LnaServerState): server is LnaServerStateResourceAdmin {
101
+ return server.status === 'resource-admin';
102
+ }
103
+
104
+ export function isLnaServerStateError(server: LnaServerState): server is LnaServerStateError {
105
+ return server.status === 'error';
106
+ }
107
+
108
+ // ============================================
109
+ // Browser/OS Type Guards
110
+ // ============================================
111
+
112
+ export function isSupportedBrowser(browser: Browser): browser is SupportedBrowser {
113
+ return browser.status === 'supported';
114
+ }
115
+
116
+ export function isNotSupportedBrowser(browser: Browser): browser is NotSupportedBrowser {
117
+ return browser.status === 'not-supported';
118
+ }
119
+
120
+ export function isSupportedOS(os: OS): os is SupportedOS {
121
+ return os.status === 'supported';
122
+ }
123
+
124
+ export function isNotSupportedOS(os: OS): os is NotSupportedOS {
125
+ return os.status === 'not-supported';
126
+ }