@elizaos/plugin-ngrok 2.0.0-beta.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/README.md +325 -0
- package/dist/__tests__/NgrokTestSuite.d.ts +6 -0
- package/dist/__tests__/NgrokTestSuite.d.ts.map +1 -0
- package/dist/__tests__/NgrokTestSuite.js +92 -0
- package/dist/__tests__/NgrokTestSuite.js.map +1 -0
- package/dist/actions/get-tunnel-status.d.ts +4 -0
- package/dist/actions/get-tunnel-status.d.ts.map +1 -0
- package/dist/actions/get-tunnel-status.js +186 -0
- package/dist/actions/get-tunnel-status.js.map +1 -0
- package/dist/actions/start-tunnel.d.ts +4 -0
- package/dist/actions/start-tunnel.d.ts.map +1 -0
- package/dist/actions/start-tunnel.js +221 -0
- package/dist/actions/start-tunnel.js.map +1 -0
- package/dist/actions/stop-tunnel.d.ts +4 -0
- package/dist/actions/stop-tunnel.d.ts.map +1 -0
- package/dist/actions/stop-tunnel.js +174 -0
- package/dist/actions/stop-tunnel.js.map +1 -0
- package/dist/environment.d.ts +12 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +68 -0
- package/dist/environment.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/services/NgrokService.d.ts +30 -0
- package/dist/services/NgrokService.d.ts.map +1 -0
- package/dist/services/NgrokService.js +333 -0
- package/dist/services/NgrokService.js.map +1 -0
- package/package.json +63 -0
- package/src/__tests__/NgrokTestSuite.ts +110 -0
- package/src/__tests__/debug-mock.test.ts +15 -0
- package/src/__tests__/e2e/real-ngrok.test.ts +543 -0
- package/src/__tests__/integration/webhook-scenarios.test.ts +463 -0
- package/src/__tests__/mocks/NgrokServiceMock.ts +76 -0
- package/src/__tests__/ngrok-integration.test.ts +521 -0
- package/src/__tests__/test-config.ts +83 -0
- package/src/__tests__/test-helpers.ts +43 -0
- package/src/__tests__/test-setup.ts +174 -0
- package/src/__tests__/test-utils.ts +155 -0
- package/src/__tests__/unit/actions.test.ts +402 -0
- package/src/__tests__/unit/environment.test.ts +352 -0
- package/src/actions/get-tunnel-status.ts +218 -0
- package/src/actions/start-tunnel.ts +255 -0
- package/src/actions/stop-tunnel.ts +203 -0
- package/src/environment.ts +75 -0
- package/src/index.ts +33 -0
- package/src/services/NgrokService.ts +401 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { elizaLogger, ModelType, } from '@elizaos/core';
|
|
2
|
+
import { getTunnelService } from '@elizaos/plugin-tunnel';
|
|
3
|
+
const startTunnelTemplate = `
|
|
4
|
+
Respond with a JSON object containing the port number to start the ngrok tunnel on.
|
|
5
|
+
The user said: "{{userMessage}}"
|
|
6
|
+
|
|
7
|
+
Extract the port number from their message, or use the default port 3000 if not specified.
|
|
8
|
+
|
|
9
|
+
Response format:
|
|
10
|
+
\`\`\`json
|
|
11
|
+
{
|
|
12
|
+
"port": 3000
|
|
13
|
+
}
|
|
14
|
+
\`\`\`
|
|
15
|
+
`;
|
|
16
|
+
export const startTunnelAction = {
|
|
17
|
+
name: 'START_TUNNEL',
|
|
18
|
+
similes: ['OPEN_TUNNEL', 'CREATE_TUNNEL', 'NGROK_START', 'TUNNEL_UP'],
|
|
19
|
+
description: 'Start an ngrok tunnel to expose a local port to the internet. Supports action chaining by providing tunnel metadata that can be used for webhook configuration, API testing, or remote access workflows.',
|
|
20
|
+
validate: async (runtime, _message) => {
|
|
21
|
+
const tunnelService = getTunnelService(runtime);
|
|
22
|
+
if (!tunnelService) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
// Check if tunnel is already active
|
|
26
|
+
if (tunnelService.isActive()) {
|
|
27
|
+
elizaLogger.warn('Tunnel is already active');
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
},
|
|
32
|
+
handler: async (runtime, message, _state, _options, callback) => {
|
|
33
|
+
const tunnelService = getTunnelService(runtime);
|
|
34
|
+
if (!tunnelService) {
|
|
35
|
+
elizaLogger.error('Tunnel service is not available');
|
|
36
|
+
if (callback) {
|
|
37
|
+
await callback({
|
|
38
|
+
text: 'Tunnel service is not available. Please ensure the ngrok plugin is properly configured.',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
success: false,
|
|
43
|
+
text: 'Tunnel service is not available. Please ensure the ngrok plugin is properly configured.',
|
|
44
|
+
values: { success: false, error: 'service_unavailable' },
|
|
45
|
+
data: { action: 'START_TUNNEL' },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (tunnelService.isActive()) {
|
|
49
|
+
elizaLogger.warn('Tunnel is already active');
|
|
50
|
+
if (callback) {
|
|
51
|
+
await callback({
|
|
52
|
+
text: 'Tunnel is already active. Please stop the existing tunnel before starting a new one.',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
text: 'Tunnel is already active. Please stop the existing tunnel before starting a new one.',
|
|
58
|
+
values: { success: false, error: 'tunnel_already_active' },
|
|
59
|
+
data: { action: 'START_TUNNEL' },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
elizaLogger.info('Starting ngrok tunnel...');
|
|
63
|
+
try {
|
|
64
|
+
// Extract port from message — inline the user message into the prompt
|
|
65
|
+
// (TEXT_SMALL no longer accepts a separate `context` param).
|
|
66
|
+
const userMessage = message.content.text ?? '';
|
|
67
|
+
const prompt = startTunnelTemplate.replace('{{userMessage}}', userMessage);
|
|
68
|
+
const portResponse = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
69
|
+
prompt,
|
|
70
|
+
temperature: 0.3,
|
|
71
|
+
});
|
|
72
|
+
let port = 3000; // default
|
|
73
|
+
try {
|
|
74
|
+
const parsed = JSON.parse(portResponse);
|
|
75
|
+
if (parsed.port) {
|
|
76
|
+
// Handle both number and string port values
|
|
77
|
+
const portNum = typeof parsed.port === 'string' ? parseInt(parsed.port, 10) : parsed.port;
|
|
78
|
+
if (!Number.isNaN(portNum) && portNum > 0 && portNum <= 65535) {
|
|
79
|
+
port = portNum;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Try to extract port from plain text response
|
|
85
|
+
const portMatch = portResponse.match(/\b(\d{1,5})\b/);
|
|
86
|
+
if (portMatch) {
|
|
87
|
+
const portNum = parseInt(portMatch[1], 10);
|
|
88
|
+
if (!Number.isNaN(portNum) && portNum > 0 && portNum <= 65535) {
|
|
89
|
+
port = portNum;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
elizaLogger.warn('Failed to parse port from response, using default 3000');
|
|
93
|
+
}
|
|
94
|
+
const url = await tunnelService.startTunnel(port);
|
|
95
|
+
const responseText = `✅ Ngrok tunnel started successfully!\n\n🌐 Public URL: ${url}\n🔌 Local Port: ${port}\n\nYour local service is now accessible from the internet.`;
|
|
96
|
+
if (callback) {
|
|
97
|
+
await callback({
|
|
98
|
+
text: responseText,
|
|
99
|
+
metadata: {
|
|
100
|
+
tunnelUrl: url,
|
|
101
|
+
port,
|
|
102
|
+
action: 'tunnel_started',
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
success: true,
|
|
108
|
+
text: responseText,
|
|
109
|
+
values: {
|
|
110
|
+
success: true,
|
|
111
|
+
tunnelUrl: url ?? null,
|
|
112
|
+
port,
|
|
113
|
+
isActive: true,
|
|
114
|
+
},
|
|
115
|
+
data: {
|
|
116
|
+
action: 'START_TUNNEL',
|
|
117
|
+
tunnelMetadata: {
|
|
118
|
+
url: url ?? null,
|
|
119
|
+
port,
|
|
120
|
+
startedAt: new Date().toISOString(),
|
|
121
|
+
provider: 'ngrok',
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
128
|
+
const stack = error instanceof Error ? (error.stack ?? null) : null;
|
|
129
|
+
elizaLogger.error(`Failed to start tunnel: ${message}`);
|
|
130
|
+
if (callback) {
|
|
131
|
+
await callback({
|
|
132
|
+
text: `❌ Failed to start ngrok tunnel: ${message}\n\nPlease make sure ngrok is installed and configured properly.`,
|
|
133
|
+
metadata: {
|
|
134
|
+
error: message,
|
|
135
|
+
action: 'tunnel_failed',
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
success: false,
|
|
141
|
+
text: `❌ Failed to start ngrok tunnel: ${message}\n\nPlease make sure ngrok is installed and configured properly.`,
|
|
142
|
+
values: {
|
|
143
|
+
success: false,
|
|
144
|
+
error: message,
|
|
145
|
+
},
|
|
146
|
+
data: {
|
|
147
|
+
action: 'START_TUNNEL',
|
|
148
|
+
errorType: 'tunnel_start_failed',
|
|
149
|
+
errorDetails: stack,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
examples: [
|
|
155
|
+
[
|
|
156
|
+
{
|
|
157
|
+
name: '{{user}}',
|
|
158
|
+
content: {
|
|
159
|
+
text: 'Start an ngrok tunnel on port 8080',
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: '{{agent}}',
|
|
164
|
+
content: {
|
|
165
|
+
text: '✅ Ngrok tunnel started successfully!\n\n🌐 Public URL: https://abc123.ngrok.io\n🔌 Local Port: 8080\n\nYour local service is now accessible from the internet.',
|
|
166
|
+
actions: ['START_TUNNEL'],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
{
|
|
172
|
+
name: '{{user}}',
|
|
173
|
+
content: {
|
|
174
|
+
text: 'Create a tunnel for my API server and then test the webhook endpoint',
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: '{{agent}}',
|
|
179
|
+
content: {
|
|
180
|
+
text: "I'll start an ngrok tunnel for your API server and then test the webhook endpoint.",
|
|
181
|
+
thought: 'User wants to expose their API server and test webhooks - I should create the tunnel first, then use the public URL for webhook testing.',
|
|
182
|
+
actions: ['START_TUNNEL'],
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: '{{agent}}',
|
|
187
|
+
content: {
|
|
188
|
+
text: '✅ Ngrok tunnel started successfully!\n\n🌐 Public URL: https://xyz789.ngrok.io\n🔌 Local Port: 3000\n\nNow testing the webhook endpoint...',
|
|
189
|
+
thought: 'Tunnel is active and I have the public URL. I can now test the webhook endpoint using this external URL.',
|
|
190
|
+
actions: ['TEST_WEBHOOK'],
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
[
|
|
195
|
+
{
|
|
196
|
+
name: '{{user}}',
|
|
197
|
+
content: {
|
|
198
|
+
text: 'Start tunnel on port 4000 and share the link in our team chat',
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: '{{agent}}',
|
|
203
|
+
content: {
|
|
204
|
+
text: "I'll start the ngrok tunnel on port 4000 and then share the public URL with your team.",
|
|
205
|
+
thought: 'User wants to expose their local service and share the link - I need to start the tunnel first, then send a message with the URL.',
|
|
206
|
+
actions: ['START_TUNNEL'],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: '{{agent}}',
|
|
211
|
+
content: {
|
|
212
|
+
text: '✅ Ngrok tunnel started successfully on port 4000! Now sharing the link with your team.',
|
|
213
|
+
thought: 'Tunnel is up and running. I can now send a message to the team chat with the public URL.',
|
|
214
|
+
actions: ['SEND_MESSAGE'],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
],
|
|
219
|
+
};
|
|
220
|
+
export default startTunnelAction;
|
|
221
|
+
//# sourceMappingURL=start-tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-tunnel.js","sourceRoot":"","sources":["../../src/actions/start-tunnel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-tunnel.d.ts","sourceRoot":"","sources":["../../src/actions/stop-tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EAQZ,MAAM,eAAe,CAAC;AAGvB,eAAO,MAAM,gBAAgB,EAAE,MA4L9B,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { elizaLogger, } from '@elizaos/core';
|
|
2
|
+
import { getTunnelService } from '@elizaos/plugin-tunnel';
|
|
3
|
+
export const stopTunnelAction = {
|
|
4
|
+
name: 'STOP_TUNNEL',
|
|
5
|
+
similes: ['CLOSE_TUNNEL', 'SHUTDOWN_TUNNEL', 'NGROK_STOP', 'TUNNEL_DOWN'],
|
|
6
|
+
description: 'Stop the running ngrok tunnel and clean up resources. Can be chained with START_TUNNEL actions for tunnel rotation workflows or combined with deployment actions for automated service management.',
|
|
7
|
+
validate: async (runtime, _message) => {
|
|
8
|
+
return !!getTunnelService(runtime);
|
|
9
|
+
},
|
|
10
|
+
handler: async (runtime, _message, _state, _options, callback) => {
|
|
11
|
+
const tunnelService = getTunnelService(runtime);
|
|
12
|
+
if (!tunnelService) {
|
|
13
|
+
elizaLogger.error('Tunnel service is not available');
|
|
14
|
+
if (callback) {
|
|
15
|
+
await callback({
|
|
16
|
+
text: 'Tunnel service is not available. Please ensure the ngrok plugin is properly configured.',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
text: 'Tunnel service is not available. Please ensure the ngrok plugin is properly configured.',
|
|
22
|
+
values: { success: false, error: 'service_unavailable' },
|
|
23
|
+
data: { action: 'STOP_TUNNEL' },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (!tunnelService.isActive()) {
|
|
27
|
+
elizaLogger.warn('No active tunnel to stop');
|
|
28
|
+
if (callback) {
|
|
29
|
+
await callback({
|
|
30
|
+
text: 'No tunnel is currently running.',
|
|
31
|
+
metadata: {
|
|
32
|
+
action: 'tunnel_not_active',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
success: true,
|
|
38
|
+
text: 'No tunnel is currently running.',
|
|
39
|
+
values: { success: true, wasActive: false },
|
|
40
|
+
data: { action: 'STOP_TUNNEL', status: 'already_stopped' },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
elizaLogger.info('Stopping ngrok tunnel...');
|
|
44
|
+
try {
|
|
45
|
+
const status = tunnelService.getStatus();
|
|
46
|
+
const previousUrl = status.url;
|
|
47
|
+
const previousPort = status.port;
|
|
48
|
+
await tunnelService.stopTunnel();
|
|
49
|
+
const responseText = `✅ Ngrok tunnel stopped successfully!\n\n🔌 Was running on port: ${previousPort}\n🌐 Previous URL: ${previousUrl}\n\nThe tunnel has been closed and is no longer accessible.`;
|
|
50
|
+
if (callback) {
|
|
51
|
+
await callback({
|
|
52
|
+
text: responseText,
|
|
53
|
+
metadata: {
|
|
54
|
+
previousUrl,
|
|
55
|
+
previousPort,
|
|
56
|
+
action: 'tunnel_stopped',
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
success: true,
|
|
62
|
+
text: responseText,
|
|
63
|
+
values: {
|
|
64
|
+
success: true,
|
|
65
|
+
wasActive: true,
|
|
66
|
+
previousUrl,
|
|
67
|
+
previousPort,
|
|
68
|
+
},
|
|
69
|
+
data: {
|
|
70
|
+
action: 'STOP_TUNNEL',
|
|
71
|
+
previousTunnelMetadata: {
|
|
72
|
+
url: previousUrl,
|
|
73
|
+
port: previousPort,
|
|
74
|
+
stoppedAt: new Date().toISOString(),
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
81
|
+
const stack = error instanceof Error ? (error.stack ?? null) : null;
|
|
82
|
+
elizaLogger.error(`Failed to stop tunnel: ${message}`);
|
|
83
|
+
if (callback) {
|
|
84
|
+
await callback({
|
|
85
|
+
text: `❌ Failed to stop ngrok tunnel: ${message}`,
|
|
86
|
+
metadata: {
|
|
87
|
+
error: message,
|
|
88
|
+
action: 'tunnel_stop_failed',
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
text: `❌ Failed to stop ngrok tunnel: ${message}`,
|
|
95
|
+
values: {
|
|
96
|
+
success: false,
|
|
97
|
+
error: message,
|
|
98
|
+
},
|
|
99
|
+
data: {
|
|
100
|
+
action: 'STOP_TUNNEL',
|
|
101
|
+
errorType: 'tunnel_stop_failed',
|
|
102
|
+
errorDetails: stack,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
examples: [
|
|
108
|
+
[
|
|
109
|
+
{
|
|
110
|
+
name: '{{user}}',
|
|
111
|
+
content: {
|
|
112
|
+
text: 'Stop the ngrok tunnel',
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: '{{agent}}',
|
|
117
|
+
content: {
|
|
118
|
+
text: '✅ Ngrok tunnel stopped successfully!\n\n🔌 Was running on port: 3000\n🌐 Previous URL: https://abc123.ngrok.io\n\nThe tunnel has been closed and is no longer accessible.',
|
|
119
|
+
actions: ['STOP_TUNNEL'],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
{
|
|
125
|
+
name: '{{user}}',
|
|
126
|
+
content: {
|
|
127
|
+
text: 'Stop the current tunnel and start a new one on port 8080',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: '{{agent}}',
|
|
132
|
+
content: {
|
|
133
|
+
text: "I'll stop the current tunnel and then start a new one on port 8080.",
|
|
134
|
+
thought: 'User wants to switch tunnels - I need to stop the current one first, then start a new tunnel on the specified port.',
|
|
135
|
+
actions: ['STOP_TUNNEL'],
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: '{{agent}}',
|
|
140
|
+
content: {
|
|
141
|
+
text: '✅ Tunnel stopped successfully! Now starting new tunnel on port 8080...',
|
|
142
|
+
thought: 'Current tunnel is closed. Now I can start the new tunnel on port 8080 as requested.',
|
|
143
|
+
actions: ['START_TUNNEL'],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
[
|
|
148
|
+
{
|
|
149
|
+
name: '{{user}}',
|
|
150
|
+
content: {
|
|
151
|
+
text: 'Close the tunnel and deploy to production',
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: '{{agent}}',
|
|
156
|
+
content: {
|
|
157
|
+
text: "I'll stop the development tunnel and then proceed with the production deployment.",
|
|
158
|
+
thought: 'User is ready to move from development to production - I should close the ngrok tunnel first, then handle the deployment process.',
|
|
159
|
+
actions: ['STOP_TUNNEL'],
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: '{{agent}}',
|
|
164
|
+
content: {
|
|
165
|
+
text: 'Development tunnel closed successfully. Now initiating production deployment...',
|
|
166
|
+
thought: 'Tunnel is down, development phase is complete. I can now proceed with the production deployment workflow.',
|
|
167
|
+
actions: ['DEPLOY_PRODUCTION'],
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
export default stopTunnelAction;
|
|
174
|
+
//# sourceMappingURL=stop-tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-tunnel.js","sourceRoot":"","sources":["../../src/actions/stop-tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,WAAW,GAKZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,MAAM,CAAC,MAAM,gBAAgB,GAAW;IACtC,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,CAAC,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,CAAC;IACzE,WAAW,EACT,oMAAoM;IACtM,QAAQ,EAAE,KAAK,EAAE,OAAsB,EAAE,QAAgB,EAAE,EAAE;QAC3D,OAAO,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,EAAE,KAAK,EACZ,OAAsB,EACtB,QAAgB,EAChB,MAAc,EACd,QAAkB,EAClB,QAA0B,EACH,EAAE;QACzB,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,WAAW,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACrD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,QAAQ,CAAC;oBACb,IAAI,EAAE,yFAAyF;iBAChG,CAAC,CAAC;YACL,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,yFAAyF;gBAC/F,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE;gBACxD,IAAI,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE;aAChC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC9B,WAAW,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YAC7C,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,QAAQ,CAAC;oBACb,IAAI,EAAE,iCAAiC;oBACvC,QAAQ,EAAE;wBACR,MAAM,EAAE,mBAAmB;qBAC5B;iBACF,CAAC,CAAC;YACL,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,iCAAiC;gBACvC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;gBAC3C,IAAI,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,EAAE;aAC3D,CAAC;QACJ,CAAC;QAED,WAAW,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAE7C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE,CAAC;YACzC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC;YAC/B,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;YAEjC,MAAM,aAAa,CAAC,UAAU,EAAE,CAAC;YAEjC,MAAM,YAAY,GAAG,mEAAmE,YAAY,sBAAsB,WAAW,6DAA6D,CAAC;YAEnM,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,QAAQ,CAAC;oBACb,IAAI,EAAE,YAAY;oBAClB,QAAQ,EAAE;wBACR,WAAW;wBACX,YAAY;wBACZ,MAAM,EAAE,gBAAgB;qBACzB;iBACF,CAAC,CAAC;YACL,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE;oBACN,OAAO,EAAE,IAAI;oBACb,SAAS,EAAE,IAAI;oBACf,WAAW;oBACX,YAAY;iBACb;gBACD,IAAI,EAAE;oBACJ,MAAM,EAAE,aAAa;oBACrB,sBAAsB,EAAE;wBACtB,GAAG,EAAE,WAAW;wBAChB,IAAI,EAAE,YAAY;wBAClB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;qBACpC;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,MAAM,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACpE,WAAW,CAAC,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;YAEvD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,QAAQ,CAAC;oBACb,IAAI,EAAE,kCAAkC,OAAO,EAAE;oBACjD,QAAQ,EAAE;wBACR,KAAK,EAAE,OAAO;wBACd,MAAM,EAAE,oBAAoB;qBAC7B;iBACF,CAAC,CAAC;YACL,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,kCAAkC,OAAO,EAAE;gBACjD,MAAM,EAAE;oBACN,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,OAAO;iBACf;gBACD,IAAI,EAAE;oBACJ,MAAM,EAAE,aAAa;oBACrB,SAAS,EAAE,oBAAoB;oBAC/B,YAAY,EAAE,KAAK;iBACpB;aACF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,QAAQ,EAAE;QACR;YACE;gBACE,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE;oBACP,IAAI,EAAE,uBAAuB;iBAC9B;aACF;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE;oBACP,IAAI,EAAE,2KAA2K;oBACjL,OAAO,EAAE,CAAC,aAAa,CAAC;iBACzB;aACF;SACF;QACD;YACE;gBACE,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE;oBACP,IAAI,EAAE,0DAA0D;iBACjE;aACF;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE;oBACP,IAAI,EAAE,qEAAqE;oBAC3E,OAAO,EACL,qHAAqH;oBACvH,OAAO,EAAE,CAAC,aAAa,CAAC;iBACzB;aACF;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE;oBACP,IAAI,EAAE,wEAAwE;oBAC9E,OAAO,EACL,qFAAqF;oBACvF,OAAO,EAAE,CAAC,cAAc,CAAC;iBAC1B;aACF;SACF;QACD;YACE;gBACE,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE;oBACP,IAAI,EAAE,2CAA2C;iBAClD;aACF;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE;oBACP,IAAI,EAAE,mFAAmF;oBACzF,OAAO,EACL,mIAAmI;oBACrI,OAAO,EAAE,CAAC,aAAa,CAAC;iBACzB;aACF;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE;oBACP,IAAI,EAAE,iFAAiF;oBACvF,OAAO,EACL,2GAA2G;oBAC7G,OAAO,EAAE,CAAC,mBAAmB,CAAC;iBAC/B;aACF;SACF;KACmB;CACvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IAgentRuntime } from '@elizaos/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const ngrokEnvSchema: z.ZodObject<{
|
|
4
|
+
NGROK_AUTH_TOKEN: z.ZodOptional<z.ZodString>;
|
|
5
|
+
NGROK_REGION: z.ZodDefault<z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>, z.ZodTransform<string, string | number | undefined>>>;
|
|
6
|
+
NGROK_SUBDOMAIN: z.ZodOptional<z.ZodString>;
|
|
7
|
+
NGROK_DOMAIN: z.ZodOptional<z.ZodString>;
|
|
8
|
+
NGROK_DEFAULT_PORT: z.ZodDefault<z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>, z.ZodTransform<number, string | number | undefined>>>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export type NgrokConfig = z.infer<typeof ngrokEnvSchema>;
|
|
11
|
+
export declare function validateNgrokConfig(runtime: IAgentRuntime): Promise<NgrokConfig>;
|
|
12
|
+
//# sourceMappingURL=environment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;;;;iBA6BzB,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAWzD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CA4BtF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { elizaLogger } from '@elizaos/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export const ngrokEnvSchema = z.object({
|
|
4
|
+
NGROK_AUTH_TOKEN: z.string().optional(),
|
|
5
|
+
NGROK_REGION: z
|
|
6
|
+
.union([z.string(), z.number()])
|
|
7
|
+
.optional()
|
|
8
|
+
.transform((val) => {
|
|
9
|
+
if (val === undefined || val === null) {
|
|
10
|
+
return 'us';
|
|
11
|
+
}
|
|
12
|
+
return String(val);
|
|
13
|
+
})
|
|
14
|
+
.default('us'),
|
|
15
|
+
NGROK_SUBDOMAIN: z.string().optional(),
|
|
16
|
+
NGROK_DOMAIN: z.string().optional(),
|
|
17
|
+
NGROK_DEFAULT_PORT: z
|
|
18
|
+
.union([z.string(), z.number()])
|
|
19
|
+
.optional()
|
|
20
|
+
.transform((val) => {
|
|
21
|
+
if (val === undefined || val === '') {
|
|
22
|
+
return 3000;
|
|
23
|
+
}
|
|
24
|
+
const num = typeof val === 'string' ? parseInt(val, 10) : val;
|
|
25
|
+
// If port is 0 or invalid, use default
|
|
26
|
+
if (Number.isNaN(num) || num <= 0 || num > 65535) {
|
|
27
|
+
return 3000;
|
|
28
|
+
}
|
|
29
|
+
return num;
|
|
30
|
+
})
|
|
31
|
+
.default(3000),
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Coerce a runtime setting (string | number | boolean | null) to a string suitable
|
|
35
|
+
* for schema parsing. Null/undefined return undefined so optional schema fields work.
|
|
36
|
+
*/
|
|
37
|
+
function settingToString(value) {
|
|
38
|
+
if (value === null || value === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
return String(value);
|
|
41
|
+
}
|
|
42
|
+
export async function validateNgrokConfig(runtime) {
|
|
43
|
+
try {
|
|
44
|
+
elizaLogger.debug('Validating Ngrok configuration with runtime settings');
|
|
45
|
+
const config = {
|
|
46
|
+
NGROK_AUTH_TOKEN: settingToString(runtime.getSetting('NGROK_AUTH_TOKEN')) ?? process.env.NGROK_AUTH_TOKEN,
|
|
47
|
+
NGROK_REGION: settingToString(runtime.getSetting('NGROK_REGION')) ?? process.env.NGROK_REGION,
|
|
48
|
+
NGROK_SUBDOMAIN: settingToString(runtime.getSetting('NGROK_SUBDOMAIN')) ?? process.env.NGROK_SUBDOMAIN,
|
|
49
|
+
NGROK_DOMAIN: settingToString(runtime.getSetting('NGROK_DOMAIN')) ?? process.env.NGROK_DOMAIN,
|
|
50
|
+
NGROK_DEFAULT_PORT: settingToString(runtime.getSetting('NGROK_DEFAULT_PORT')) ??
|
|
51
|
+
process.env.NGROK_DEFAULT_PORT ??
|
|
52
|
+
process.env.NGROK_TUNNEL_PORT,
|
|
53
|
+
};
|
|
54
|
+
elizaLogger.debug({ config }, 'Parsing configuration with schema');
|
|
55
|
+
const validated = ngrokEnvSchema.parse(config);
|
|
56
|
+
elizaLogger.debug('Configuration validated successfully');
|
|
57
|
+
return validated;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (error instanceof z.ZodError) {
|
|
61
|
+
const errorMessages = error.issues.map((e) => `${e.path.join('.')}: ${e.message}`).join('\n');
|
|
62
|
+
elizaLogger.error(`Configuration validation failed: ${errorMessages}`);
|
|
63
|
+
throw new Error(`Ngrok configuration validation failed:\n${errorMessages}`);
|
|
64
|
+
}
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=environment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.js","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Plugin } from '@elizaos/core';
|
|
2
|
+
/**
|
|
3
|
+
* Ngrok tunnel plugin.
|
|
4
|
+
*
|
|
5
|
+
* Implements the `ITunnelService` contract from `@elizaos/plugin-tunnel`.
|
|
6
|
+
* Registers `serviceType="tunnel"` only when no other tunnel service has
|
|
7
|
+
* already claimed the slot (first-active-wins coordination across
|
|
8
|
+
* plugin-tunnel, plugin-elizacloud's CloudTunnelService, and this plugin).
|
|
9
|
+
*/
|
|
10
|
+
export declare const ngrokPlugin: Plugin;
|
|
11
|
+
export default ngrokPlugin;
|
|
12
|
+
export * from './services/NgrokService';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAKzD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,EAAE,MAezB,CAAC;AAEF,eAAe,WAAW,CAAC;AAE3B,cAAc,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { elizaLogger } from '@elizaos/core';
|
|
2
|
+
import { tunnelSlotIsFree } from '@elizaos/plugin-tunnel';
|
|
3
|
+
import { NgrokTestSuite } from './__tests__/NgrokTestSuite';
|
|
4
|
+
import { NgrokService } from './services/NgrokService';
|
|
5
|
+
/**
|
|
6
|
+
* Ngrok tunnel plugin.
|
|
7
|
+
*
|
|
8
|
+
* Implements the `ITunnelService` contract from `@elizaos/plugin-tunnel`.
|
|
9
|
+
* Registers `serviceType="tunnel"` only when no other tunnel service has
|
|
10
|
+
* already claimed the slot (first-active-wins coordination across
|
|
11
|
+
* plugin-tunnel, plugin-elizacloud's CloudTunnelService, and this plugin).
|
|
12
|
+
*/
|
|
13
|
+
export const ngrokPlugin = {
|
|
14
|
+
name: 'ngrok',
|
|
15
|
+
description: 'Ngrok tunnel backend. Coexists with plugin-tunnel via first-active-wins.',
|
|
16
|
+
actions: [],
|
|
17
|
+
tests: [new NgrokTestSuite()],
|
|
18
|
+
init: async (_config, runtime) => {
|
|
19
|
+
if (!tunnelSlotIsFree(runtime)) {
|
|
20
|
+
elizaLogger.info('[plugin-ngrok] another tunnel service already registered — skipping NgrokService');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
elizaLogger.info('[plugin-ngrok] registering NgrokService for serviceType="tunnel"');
|
|
24
|
+
await runtime.registerService(NgrokService);
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
export default ngrokPlugin;
|
|
28
|
+
export * from './services/NgrokService';
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAW;IACjC,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,0EAA0E;IACvF,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,CAAC,IAAI,cAAc,EAAE,CAAC;IAC7B,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QAC/B,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,WAAW,CAAC,IAAI,CACd,kFAAkF,CACnF,CAAC;YACF,OAAO;QACT,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;QACrF,MAAM,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IAC9C,CAAC;CACF,CAAC;AAEF,eAAe,WAAW,CAAC;AAE3B,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type IAgentRuntime, Service } from '@elizaos/core';
|
|
2
|
+
import type { ITunnelService, TunnelStatus } from '@elizaos/plugin-tunnel';
|
|
3
|
+
export declare class NgrokService extends Service implements ITunnelService {
|
|
4
|
+
static serviceType: string;
|
|
5
|
+
readonly capabilityDescription = "Provides secure tunnel functionality using ngrok for exposing local services to the internet";
|
|
6
|
+
private static readonly MIN_TUNNEL_INTERVAL;
|
|
7
|
+
private ngrokProcess;
|
|
8
|
+
private tunnelUrl;
|
|
9
|
+
private tunnelPort;
|
|
10
|
+
private startedAt;
|
|
11
|
+
private lastStartTime;
|
|
12
|
+
private tunnelConfig;
|
|
13
|
+
constructor(runtime?: IAgentRuntime);
|
|
14
|
+
initialize(): Promise<void>;
|
|
15
|
+
static start(runtime: IAgentRuntime): Promise<Service>;
|
|
16
|
+
start(): Promise<void>;
|
|
17
|
+
stop(): Promise<void>;
|
|
18
|
+
startTunnel(port?: number): Promise<string | undefined>;
|
|
19
|
+
private attemptStartTunnel;
|
|
20
|
+
private startTunnelInternal;
|
|
21
|
+
stopTunnel(): Promise<void>;
|
|
22
|
+
getUrl(): string | null;
|
|
23
|
+
isActive(): boolean;
|
|
24
|
+
getStatus(): TunnelStatus;
|
|
25
|
+
private cleanup;
|
|
26
|
+
private checkNgrokInstalled;
|
|
27
|
+
private setAuthToken;
|
|
28
|
+
private fetchTunnelUrl;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=NgrokService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NgrokService.d.ts","sourceRoot":"","sources":["../../src/services/NgrokService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,aAAa,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAgC3E,qBAAa,YAAa,SAAQ,OAAQ,YAAW,cAAc;IACjE,MAAM,CAAC,WAAW,SAAY;IAC9B,QAAQ,CAAC,qBAAqB,kGACmE;IAEjG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IAEnD,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,YAAY,CAAe;gBAEvB,OAAO,CAAC,EAAE,aAAa;IAS7B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;WAsBX,KAAK,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAO/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAKrB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;YA4C/C,kBAAkB;YAmClB,mBAAmB;IA2H3B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA2BjC,MAAM,IAAI,MAAM,GAAG,IAAI;IAIvB,QAAQ,IAAI,OAAO;IAInB,SAAS,IAAI,YAAY;IAUzB,OAAO,CAAC,OAAO;YAOD,mBAAmB;YAQnB,YAAY;YAeZ,cAAc;CA6B7B"}
|