@applica-software-guru/persona-sdk 0.1.83 → 0.1.85
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/README.md +104 -0
- package/dist/bundle.cjs.js +18 -30
- package/dist/bundle.cjs.js.map +1 -1
- package/dist/bundle.es.js +3506 -7033
- package/dist/bundle.es.js.map +1 -1
- package/dist/bundle.iife.js +18 -30
- package/dist/bundle.iife.js.map +1 -1
- package/dist/bundle.umd.js +17 -29
- package/dist/bundle.umd.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/messages.d.ts +2 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/protocol/webrtc.d.ts.map +1 -1
- package/dist/protocol/websocket.d.ts.map +1 -1
- package/dist/runtime/context.d.ts +34 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/handlers.d.ts +21 -0
- package/dist/runtime/handlers.d.ts.map +1 -0
- package/dist/runtime/listeners.d.ts +6 -0
- package/dist/runtime/listeners.d.ts.map +1 -0
- package/dist/runtime/protocols.d.ts +17 -0
- package/dist/runtime/protocols.d.ts.map +1 -0
- package/dist/runtime/threads.d.ts +35 -0
- package/dist/runtime/threads.d.ts.map +1 -0
- package/dist/runtime/utils.d.ts +10 -0
- package/dist/runtime/utils.d.ts.map +1 -0
- package/dist/runtime.d.ts +4 -22
- package/dist/runtime.d.ts.map +1 -1
- package/dist/storage/base.d.ts +19 -0
- package/dist/storage/base.d.ts.map +1 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/persona.d.ts +30 -0
- package/dist/storage/persona.d.ts.map +1 -0
- package/dist/types.d.ts +51 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -10
- package/playground/src/chat.tsx +51 -66
- package/playground/src/components/assistant-ui/thread-list.tsx +45 -12
- package/playground/src/components/assistant-ui/thread.tsx +34 -96
- package/playground/src/components/assistant-ui/threadlist-sidebar.tsx +59 -0
- package/playground/src/components/chat/logging.tsx +53 -0
- package/playground/src/components/ui/input.tsx +21 -0
- package/playground/src/components/ui/separator.tsx +26 -0
- package/playground/src/components/ui/sheet.tsx +139 -0
- package/playground/src/components/ui/sidebar.tsx +619 -0
- package/playground/src/components/ui/skeleton.tsx +13 -0
- package/playground/src/components/ui/tooltip.tsx +0 -2
- package/playground/src/hooks/theme.ts +70 -0
- package/playground/src/hooks/use-mobile.ts +19 -0
- package/src/index.ts +1 -0
- package/src/messages.ts +98 -8
- package/src/protocol/webrtc.ts +1 -0
- package/src/protocol/websocket.ts +5 -2
- package/src/runtime/context.ts +88 -0
- package/src/runtime/handlers.ts +276 -0
- package/src/runtime/index.ts +6 -0
- package/src/runtime/listeners.ts +79 -0
- package/src/runtime/protocols.ts +169 -0
- package/src/runtime/threads.ts +120 -0
- package/src/runtime/utils.ts +46 -0
- package/src/runtime.tsx +226 -326
- package/src/storage/base.ts +21 -0
- package/src/storage/index.ts +2 -0
- package/src/storage/persona.ts +132 -0
- package/src/types.ts +64 -2
- package/vite.config.ts +11 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { PersonaPacket, PersonaMessage, PersonaReasoning, PersonaTransaction, PersonaProtocol, TransformMessages } from '../types';
|
|
2
|
+
import { parseMessages } from '../messages';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates packet listener for a protocol
|
|
6
|
+
*/
|
|
7
|
+
export function createPacketListener(
|
|
8
|
+
protocol: PersonaProtocol,
|
|
9
|
+
setMessages: React.Dispatch<React.SetStateAction<PersonaMessage[]>>,
|
|
10
|
+
setIsRunning: React.Dispatch<React.SetStateAction<boolean>>,
|
|
11
|
+
protocols: PersonaProtocol[],
|
|
12
|
+
transformMessages?: TransformMessages,
|
|
13
|
+
) {
|
|
14
|
+
return (message: PersonaPacket) => {
|
|
15
|
+
if (message.type === 'message') {
|
|
16
|
+
handleMessagePacket(message.payload as PersonaMessage, protocol, setMessages, setIsRunning, transformMessages);
|
|
17
|
+
} else if (message.type === 'reasoning') {
|
|
18
|
+
handleReasoningPacket(message.payload as PersonaReasoning, protocol, setMessages, transformMessages);
|
|
19
|
+
} else if (message.type === 'transaction') {
|
|
20
|
+
handleTransactionPacket(message.payload as PersonaTransaction, protocol, protocols);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function handleMessagePacket(
|
|
26
|
+
personaMessage: PersonaMessage,
|
|
27
|
+
protocol: PersonaProtocol,
|
|
28
|
+
setMessages: React.Dispatch<React.SetStateAction<PersonaMessage[]>>,
|
|
29
|
+
setIsRunning: React.Dispatch<React.SetStateAction<boolean>>,
|
|
30
|
+
transformMessages?: TransformMessages,
|
|
31
|
+
) {
|
|
32
|
+
// Ensure message has proper timestamp
|
|
33
|
+
if (!personaMessage.createdAt) {
|
|
34
|
+
personaMessage.createdAt = new Date();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Handle finish reason and update isRunning state
|
|
38
|
+
if (personaMessage?.finishReason === 'stop' && !personaMessage?.functionResponse && !personaMessage?.thought) {
|
|
39
|
+
setIsRunning(false);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Convert thought to reasoning type
|
|
43
|
+
if (personaMessage.thought) {
|
|
44
|
+
personaMessage.type = 'reasoning';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Add protocol information
|
|
48
|
+
personaMessage.protocol = protocol.getName();
|
|
49
|
+
|
|
50
|
+
setMessages((currentConversation) => {
|
|
51
|
+
const newMessages = parseMessages([...currentConversation, personaMessage]);
|
|
52
|
+
return transformMessages ? transformMessages(newMessages) : newMessages;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function handleReasoningPacket(
|
|
57
|
+
reasoning: PersonaReasoning,
|
|
58
|
+
protocol: PersonaProtocol,
|
|
59
|
+
setMessages: React.Dispatch<React.SetStateAction<PersonaMessage[]>>,
|
|
60
|
+
transformMessages?: TransformMessages,
|
|
61
|
+
) {
|
|
62
|
+
const personaMessage: PersonaMessage = {
|
|
63
|
+
type: 'reasoning',
|
|
64
|
+
text: reasoning.thought,
|
|
65
|
+
role: 'assistant',
|
|
66
|
+
finishReason: 'stop',
|
|
67
|
+
protocol: protocol.getName(),
|
|
68
|
+
createdAt: new Date(),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
setMessages((currentConversation) => {
|
|
72
|
+
const newMessages = parseMessages([...currentConversation, personaMessage]);
|
|
73
|
+
return transformMessages ? transformMessages(newMessages) : newMessages;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function handleTransactionPacket(transaction: PersonaTransaction, currentProtocol: PersonaProtocol, protocols: PersonaProtocol[]) {
|
|
78
|
+
protocols.filter((p) => p !== currentProtocol).forEach((p) => p.onTransaction(transaction));
|
|
79
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { PersonaProtocol, PersonaProtocolBaseConfig, PersonaConfig } from '../types';
|
|
2
|
+
import type { PersonaLogger } from '../logging';
|
|
3
|
+
import {
|
|
4
|
+
PersonaRESTProtocol,
|
|
5
|
+
PersonaRESTProtocolConfig,
|
|
6
|
+
PersonaTransactionProtocol,
|
|
7
|
+
PersonaWebRTCProtocol,
|
|
8
|
+
PersonaWebRTCProtocolConfig,
|
|
9
|
+
PersonaWebSocketProtocol,
|
|
10
|
+
PersonaWebSocketProtocolConfig,
|
|
11
|
+
} from '../protocol';
|
|
12
|
+
|
|
13
|
+
type ProtocolsConfig = PersonaConfig['protocols'];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Initializes protocols based on configuration
|
|
17
|
+
*/
|
|
18
|
+
export function initializeProtocols(
|
|
19
|
+
_protocols: ProtocolsConfig,
|
|
20
|
+
config: {
|
|
21
|
+
dev: boolean;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
apiKey: string;
|
|
24
|
+
agentId: string;
|
|
25
|
+
userId?: string;
|
|
26
|
+
tools?: PersonaConfig['tools'];
|
|
27
|
+
logger?: PersonaLogger;
|
|
28
|
+
},
|
|
29
|
+
): PersonaProtocol[] {
|
|
30
|
+
if (Array.isArray(_protocols)) {
|
|
31
|
+
return _protocols;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeof _protocols === 'object' && _protocols !== null) {
|
|
35
|
+
const baseEndpoint = config.dev ? 'localhost:8000' : config.baseUrl || 'persona.applica.guru/api';
|
|
36
|
+
const baseEndpointProtocol = config.dev ? 'http' : 'https';
|
|
37
|
+
const baseWebSocketProtocol = config.dev ? 'ws' : 'wss';
|
|
38
|
+
|
|
39
|
+
let availableProtocols = Object.keys(_protocols)
|
|
40
|
+
.map((key) => {
|
|
41
|
+
switch (key) {
|
|
42
|
+
case 'rest':
|
|
43
|
+
return createRESTProtocol(_protocols[key], {
|
|
44
|
+
baseEndpointProtocol,
|
|
45
|
+
baseEndpoint,
|
|
46
|
+
apiKey: config.apiKey,
|
|
47
|
+
agentId: config.agentId,
|
|
48
|
+
userId: config.userId,
|
|
49
|
+
logger: config.logger,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
case 'webrtc':
|
|
53
|
+
return createWebRTCProtocol(_protocols[key], {
|
|
54
|
+
baseWebSocketProtocol,
|
|
55
|
+
baseEndpoint,
|
|
56
|
+
apiKey: config.apiKey,
|
|
57
|
+
agentId: config.agentId,
|
|
58
|
+
userId: config.userId,
|
|
59
|
+
logger: config.logger,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
case 'websocket':
|
|
63
|
+
return createWebSocketProtocol(_protocols[key], {
|
|
64
|
+
baseWebSocketProtocol,
|
|
65
|
+
baseEndpoint,
|
|
66
|
+
apiKey: config.apiKey,
|
|
67
|
+
agentId: config.agentId,
|
|
68
|
+
userId: config.userId,
|
|
69
|
+
logger: config.logger,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
default:
|
|
73
|
+
throw new Error(`Unknown protocol: ${key}`);
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
.filter((protocol) => protocol !== null) as PersonaProtocol[];
|
|
77
|
+
|
|
78
|
+
if (config.tools) {
|
|
79
|
+
availableProtocols.push(
|
|
80
|
+
new PersonaTransactionProtocol({
|
|
81
|
+
apiUrl: `${baseEndpointProtocol}://${baseEndpoint}`,
|
|
82
|
+
apiKey: config.apiKey,
|
|
83
|
+
agentId: config.agentId,
|
|
84
|
+
tools: config.tools,
|
|
85
|
+
logger: config.logger,
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return availableProtocols;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw new Error('Invalid protocols configuration');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function createRESTProtocol(
|
|
97
|
+
config: PersonaProtocolBaseConfig | boolean | undefined,
|
|
98
|
+
baseConfig: {
|
|
99
|
+
baseEndpointProtocol: string;
|
|
100
|
+
baseEndpoint: string;
|
|
101
|
+
apiKey: string;
|
|
102
|
+
agentId: string;
|
|
103
|
+
userId?: string;
|
|
104
|
+
logger?: PersonaLogger;
|
|
105
|
+
},
|
|
106
|
+
): PersonaRESTProtocol | null {
|
|
107
|
+
if (config === true) {
|
|
108
|
+
return new PersonaRESTProtocol({
|
|
109
|
+
apiUrl: `${baseConfig.baseEndpointProtocol}://${baseConfig.baseEndpoint}`,
|
|
110
|
+
apiKey: baseConfig.apiKey,
|
|
111
|
+
agentId: baseConfig.agentId,
|
|
112
|
+
userId: baseConfig.userId,
|
|
113
|
+
logger: baseConfig.logger,
|
|
114
|
+
});
|
|
115
|
+
} else if (typeof config === 'object' && config !== null) {
|
|
116
|
+
return new PersonaRESTProtocol(config as PersonaRESTProtocolConfig);
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function createWebRTCProtocol(
|
|
122
|
+
config: PersonaProtocolBaseConfig | boolean | undefined,
|
|
123
|
+
baseConfig: {
|
|
124
|
+
baseWebSocketProtocol: string;
|
|
125
|
+
baseEndpoint: string;
|
|
126
|
+
apiKey: string;
|
|
127
|
+
agentId: string;
|
|
128
|
+
userId?: string;
|
|
129
|
+
logger?: PersonaLogger;
|
|
130
|
+
},
|
|
131
|
+
): PersonaWebRTCProtocol | null {
|
|
132
|
+
if (config === true) {
|
|
133
|
+
return new PersonaWebRTCProtocol({
|
|
134
|
+
webrtcUrl: `${baseConfig.baseWebSocketProtocol}://${baseConfig.baseEndpoint}/webrtc`,
|
|
135
|
+
apiKey: baseConfig.apiKey,
|
|
136
|
+
agentId: baseConfig.agentId,
|
|
137
|
+
userId: baseConfig.userId,
|
|
138
|
+
logger: baseConfig.logger,
|
|
139
|
+
});
|
|
140
|
+
} else if (typeof config === 'object' && config !== null) {
|
|
141
|
+
return new PersonaWebRTCProtocol(config as PersonaWebRTCProtocolConfig);
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function createWebSocketProtocol(
|
|
147
|
+
config: PersonaProtocolBaseConfig | boolean | undefined,
|
|
148
|
+
baseConfig: {
|
|
149
|
+
baseWebSocketProtocol: string;
|
|
150
|
+
baseEndpoint: string;
|
|
151
|
+
apiKey: string;
|
|
152
|
+
agentId: string;
|
|
153
|
+
userId?: string;
|
|
154
|
+
logger?: PersonaLogger;
|
|
155
|
+
},
|
|
156
|
+
): PersonaWebSocketProtocol | null {
|
|
157
|
+
if (config === true) {
|
|
158
|
+
return new PersonaWebSocketProtocol({
|
|
159
|
+
webSocketUrl: `${baseConfig.baseWebSocketProtocol}://${baseConfig.baseEndpoint}/websocket`,
|
|
160
|
+
apiKey: baseConfig.apiKey,
|
|
161
|
+
agentId: baseConfig.agentId,
|
|
162
|
+
userId: baseConfig.userId,
|
|
163
|
+
logger: baseConfig.logger,
|
|
164
|
+
});
|
|
165
|
+
} else if (typeof config === 'object' && config !== null) {
|
|
166
|
+
return new PersonaWebSocketProtocol(config as PersonaWebSocketProtocolConfig);
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { ThreadData } from '../types';
|
|
2
|
+
import type { PersonaLogger } from '../logging';
|
|
3
|
+
import type { SessionStorage } from '../storage';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generates a new session ID
|
|
7
|
+
*/
|
|
8
|
+
export function generateSessionId(): string {
|
|
9
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
10
|
+
let sid = '';
|
|
11
|
+
for (let i = 0; i < 16; i++) {
|
|
12
|
+
sid += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
13
|
+
}
|
|
14
|
+
return sid;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates the thread list adapter for multi-thread support
|
|
19
|
+
*/
|
|
20
|
+
export function createThreadListAdapter(
|
|
21
|
+
currentThreadId: string,
|
|
22
|
+
threadList: ThreadData[],
|
|
23
|
+
setCurrentThreadId: (id: string) => void,
|
|
24
|
+
setThreadList: React.Dispatch<React.SetStateAction<ThreadData[]>>,
|
|
25
|
+
storage: SessionStorage,
|
|
26
|
+
onThreadCreate?: (threadId: string) => void,
|
|
27
|
+
onThreadSwitch?: (threadId: string) => void,
|
|
28
|
+
onThreadArchive?: (threadId: string) => void,
|
|
29
|
+
onThreadUnarchive?: (threadId: string) => void,
|
|
30
|
+
onThreadDelete?: (threadId: string) => void,
|
|
31
|
+
logger?: PersonaLogger,
|
|
32
|
+
) {
|
|
33
|
+
return {
|
|
34
|
+
threadId: currentThreadId,
|
|
35
|
+
threads: threadList
|
|
36
|
+
.filter((t) => t.status === 'regular')
|
|
37
|
+
.map((t) => ({
|
|
38
|
+
id: t.threadId,
|
|
39
|
+
threadId: t.threadId,
|
|
40
|
+
title: t.title || `Chat ${t.threadId}`,
|
|
41
|
+
status: t.status as 'regular',
|
|
42
|
+
})),
|
|
43
|
+
archivedThreads: threadList
|
|
44
|
+
.filter((t) => t.status === 'archived')
|
|
45
|
+
.map((t) => ({
|
|
46
|
+
id: t.threadId,
|
|
47
|
+
threadId: t.threadId,
|
|
48
|
+
title: t.title || `Archived Chat ${t.threadId}`,
|
|
49
|
+
status: t.status as 'archived',
|
|
50
|
+
})),
|
|
51
|
+
|
|
52
|
+
onSwitchToNewThread: () => {
|
|
53
|
+
const newId = generateSessionId();
|
|
54
|
+
logger?.debug('Creating new thread:', newId);
|
|
55
|
+
|
|
56
|
+
const newThread = {
|
|
57
|
+
threadId: newId,
|
|
58
|
+
status: 'regular' as const,
|
|
59
|
+
title: 'New Chat',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
setThreadList((prev) => [newThread, ...prev]);
|
|
63
|
+
setCurrentThreadId(newId);
|
|
64
|
+
|
|
65
|
+
onThreadCreate?.(newId);
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
onSwitchToThread: (threadId: string) => {
|
|
69
|
+
logger?.debug('Switching to thread:', threadId);
|
|
70
|
+
setCurrentThreadId(threadId);
|
|
71
|
+
// Messages will be synced by the useEffect in runtime.tsx
|
|
72
|
+
|
|
73
|
+
onThreadSwitch?.(threadId);
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
onArchive: (threadId: string) => {
|
|
77
|
+
logger?.debug('Archiving thread:', threadId);
|
|
78
|
+
setThreadList((prev) => prev.map((t) => (t.threadId === threadId ? { ...t, status: 'archived' as const } : t)));
|
|
79
|
+
|
|
80
|
+
onThreadArchive?.(threadId);
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
onUnarchive: (threadId: string) => {
|
|
84
|
+
logger?.debug('Unarchiving thread:', threadId);
|
|
85
|
+
setThreadList((prev) => prev.map((t) => (t.threadId === threadId ? { ...t, status: 'regular' as const } : t)));
|
|
86
|
+
|
|
87
|
+
onThreadUnarchive?.(threadId);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
onDelete: async (threadId: string) => {
|
|
91
|
+
logger?.debug('Deleting thread:', threadId);
|
|
92
|
+
|
|
93
|
+
// Remove from list
|
|
94
|
+
setThreadList((prev) => prev.filter((t) => t.threadId !== threadId));
|
|
95
|
+
|
|
96
|
+
// Switch to another thread if deleting current
|
|
97
|
+
if (currentThreadId === threadId) {
|
|
98
|
+
const remaining = threadList.filter((t) => t.threadId !== threadId && t.status === 'regular');
|
|
99
|
+
if (remaining.length > 0) {
|
|
100
|
+
setCurrentThreadId(remaining[0].threadId);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Delete from backend (threadId = sessionId)
|
|
105
|
+
storage
|
|
106
|
+
.remove(threadId)
|
|
107
|
+
.then(() => logger?.debug('Thread deleted from backend'))
|
|
108
|
+
.catch((error) => logger?.error('Failed to delete thread:', error));
|
|
109
|
+
|
|
110
|
+
onThreadDelete?.(threadId);
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Generates a default thread ID
|
|
117
|
+
*/
|
|
118
|
+
export function generateDefaultThreadId(): string {
|
|
119
|
+
return `thread-${Date.now()}`;
|
|
120
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { PersonaProtocol } from '../types';
|
|
2
|
+
import { PersonaRESTProtocol, PersonaWebRTCProtocol, PersonaWebSocketProtocol } from '../protocol';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Converts a File object to a base64 string
|
|
6
|
+
*/
|
|
7
|
+
export function fileToBase64(file: File): Promise<string> {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const reader = new FileReader();
|
|
10
|
+
reader.readAsDataURL(file);
|
|
11
|
+
|
|
12
|
+
reader.onload = () => {
|
|
13
|
+
const base64 = reader.result as string;
|
|
14
|
+
const base64WithoutPrefix = base64.split(';base64,')[1];
|
|
15
|
+
resolve(base64WithoutPrefix);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
reader.onerror = (error) => {
|
|
19
|
+
reject(error);
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Extracts the first available protocol endpoint URL
|
|
26
|
+
*/
|
|
27
|
+
export function getFirstAvailableProtocolEndpoint(protocols: PersonaProtocol[]): string | null {
|
|
28
|
+
const extractors: { [key: string]: (protocol: PersonaProtocol) => string } = {
|
|
29
|
+
rest: (protocol) => (protocol as PersonaRESTProtocol).config.apiUrl,
|
|
30
|
+
webrtc: (protocol) =>
|
|
31
|
+
(protocol as PersonaWebRTCProtocol).config.webrtcUrl.replace('/webrtc', '').replace('ws://', 'http://').replace('wss://', 'https://'),
|
|
32
|
+
websocket: (protocol) =>
|
|
33
|
+
(protocol as PersonaWebSocketProtocol).config.webSocketUrl
|
|
34
|
+
.replace('/websocket', '')
|
|
35
|
+
.replace('ws://', 'http://')
|
|
36
|
+
.replace('wss://', 'https://'),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
for (const protocol of protocols) {
|
|
40
|
+
const extractor = extractors[protocol.getName()];
|
|
41
|
+
if (extractor) {
|
|
42
|
+
return extractor(protocol);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|