@privateconnect/sdk 0.3.0

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 ADDED
@@ -0,0 +1,174 @@
1
+ # Private Connect SDK
2
+
3
+ TypeScript SDK for Private Connect - programmatic access to services and agent orchestration.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @privateconnect/sdk
9
+ # or
10
+ pnpm add @privateconnect/sdk
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import { PrivateConnect, connect } from '@privateconnect/sdk';
17
+
18
+ // Quick connect to a service
19
+ const db = await connect('postgres-prod');
20
+ console.log(db.connectionString); // postgres://localhost:5432/...
21
+
22
+ // Or use the full client
23
+ const pc = new PrivateConnect({
24
+ apiKey: process.env.PRIVATECONNECT_API_KEY
25
+ });
26
+
27
+ // List available services
28
+ const services = await pc.services.list();
29
+
30
+ // Connect to a specific service
31
+ const redis = await pc.connect('redis-cache');
32
+ console.log(redis.connectionString); // redis://localhost:6379
33
+ ```
34
+
35
+ ## Agent Orchestration
36
+
37
+ The SDK enables multi-agent orchestration - coordinating work across agents running on different machines.
38
+
39
+ ### List Agents
40
+
41
+ ```typescript
42
+ // Get all agents in your workspace
43
+ const agents = await pc.agents.list();
44
+
45
+ // Get only online agents
46
+ const online = await pc.agents.list({ onlineOnly: true });
47
+
48
+ // Find agents with specific capabilities
49
+ const gpuAgents = await pc.agents.findByCapability('gpu');
50
+ ```
51
+
52
+ ### Register Capabilities
53
+
54
+ Tell other agents what you can do:
55
+
56
+ ```typescript
57
+ await pc.agents.registerCapabilities([
58
+ { name: 'database', metadata: { type: 'postgres', version: '15' } },
59
+ { name: 'gpu', metadata: { model: 'A100', memory: '80GB' } },
60
+ ]);
61
+ ```
62
+
63
+ ### Agent Messaging
64
+
65
+ Coordinate with other agents:
66
+
67
+ ```typescript
68
+ // Send a message to a specific agent
69
+ await pc.agents.sendMessage(targetAgentId, {
70
+ action: 'run-migration',
71
+ database: 'users',
72
+ });
73
+
74
+ // Broadcast to all agents
75
+ await pc.agents.broadcast({
76
+ type: 'deployment-starting',
77
+ service: 'api',
78
+ });
79
+
80
+ // Get your messages
81
+ const messages = await pc.agents.getMessages({ unreadOnly: true });
82
+ for (const msg of messages) {
83
+ console.log(`From ${msg.from.name}: ${JSON.stringify(msg.payload)}`);
84
+ }
85
+ ```
86
+
87
+ ### Orchestration Sessions
88
+
89
+ Create ephemeral sessions for coordinated workflows:
90
+
91
+ ```typescript
92
+ // Create a session
93
+ const session = await pc.sessions.create('deploy-v2.1', {
94
+ ttlMinutes: 30,
95
+ metadata: { version: '2.1.0' },
96
+ });
97
+
98
+ // ... coordinate agents ...
99
+
100
+ // End the session
101
+ await pc.sessions.end(session.id);
102
+ ```
103
+
104
+ ## Connection Strings
105
+
106
+ Get properly formatted connection strings for common services:
107
+
108
+ ```typescript
109
+ const db = await pc.connect('postgres-prod');
110
+ // db.connectionString = 'postgres://localhost:5432/postgres'
111
+ // db.envVar = 'DATABASE_URL'
112
+
113
+ const cache = await pc.connect('redis-cache');
114
+ // cache.connectionString = 'redis://localhost:6379'
115
+ // cache.envVar = 'REDIS_URL'
116
+
117
+ const api = await pc.connect('internal-api');
118
+ // api.connectionString = 'http://localhost:8080'
119
+ // api.envVar = 'API_URL'
120
+ ```
121
+
122
+ ## Environment Variables
123
+
124
+ The SDK can read configuration from environment variables:
125
+
126
+ ```bash
127
+ export PRIVATECONNECT_API_KEY=your-api-key
128
+ ```
129
+
130
+ ```typescript
131
+ // API key automatically read from env
132
+ const connection = await connect('my-service');
133
+ ```
134
+
135
+ ## API Reference
136
+
137
+ ### `PrivateConnect`
138
+
139
+ Main client class.
140
+
141
+ ```typescript
142
+ const pc = new PrivateConnect({
143
+ apiKey: string, // Required: Your API key
144
+ hubUrl?: string, // Optional: Hub URL (default: https://api.privateconnect.co)
145
+ agentId?: string, // Optional: Agent ID (auto-detected)
146
+ });
147
+ ```
148
+
149
+ ### `pc.services`
150
+
151
+ - `list()` - List all services
152
+ - `get(name)` - Get a service by name
153
+ - `getConnection(name)` - Get connection details for a service
154
+
155
+ ### `pc.agents`
156
+
157
+ - `list(options?)` - List all agents
158
+ - `findByCapability(capability)` - Find agents by capability
159
+ - `registerCapabilities(capabilities)` - Register this agent's capabilities
160
+ - `sendMessage(toAgentId, payload, options?)` - Send a message
161
+ - `broadcast(payload, options?)` - Broadcast to all agents
162
+ - `getMessages(options?)` - Get received messages
163
+ - `markRead(messageIds)` - Mark messages as read
164
+
165
+ ### `pc.sessions`
166
+
167
+ - `create(name, options?)` - Create an orchestration session
168
+ - `end(sessionId)` - End a session
169
+ - `getActive()` - Get active sessions
170
+
171
+ ## License
172
+
173
+ [FSL-1.1-MIT](LICENSE)
174
+
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Private Connect SDK
3
+ *
4
+ * Programmatic access to Private Connect services and agent orchestration.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { PrivateConnect } from '@privateconnect/sdk';
9
+ *
10
+ * const pc = new PrivateConnect({ apiKey: 'your-api-key' });
11
+ *
12
+ * // Connect to a service
13
+ * const db = await pc.connect('postgres-prod');
14
+ * console.log(db.connectionString); // postgres://localhost:5432/...
15
+ *
16
+ * // List all agents
17
+ * const agents = await pc.agents.list();
18
+ *
19
+ * // Send message to another agent
20
+ * await pc.agents.sendMessage(targetAgentId, { action: 'deploy' });
21
+ * ```
22
+ */
23
+ export interface PrivateConnectConfig {
24
+ /** API key for authentication */
25
+ apiKey: string;
26
+ /** Hub URL (default: https://api.privateconnect.co) */
27
+ hubUrl?: string;
28
+ /** Agent ID (auto-detected from config if not provided) */
29
+ agentId?: string;
30
+ }
31
+ export interface Service {
32
+ id: string;
33
+ name: string;
34
+ targetHost: string;
35
+ targetPort: number;
36
+ tunnelPort?: number;
37
+ protocol: string;
38
+ status: string;
39
+ agentLabel?: string;
40
+ }
41
+ export interface Agent {
42
+ id: string;
43
+ name?: string;
44
+ label: string;
45
+ isOnline: boolean;
46
+ lastSeenAt: string;
47
+ capabilities: string[];
48
+ services: string[];
49
+ }
50
+ export interface Connection {
51
+ service: string;
52
+ host: string;
53
+ port: number;
54
+ connectionString: string;
55
+ envVar: string;
56
+ }
57
+ export interface Message {
58
+ id: string;
59
+ from: {
60
+ id: string;
61
+ name?: string;
62
+ label?: string;
63
+ };
64
+ channel: string;
65
+ type: string;
66
+ payload: Record<string, unknown>;
67
+ createdAt: string;
68
+ isRead: boolean;
69
+ }
70
+ export interface Session {
71
+ id: string;
72
+ name: string;
73
+ createdBy: string;
74
+ createdAt: string;
75
+ expiresAt: string;
76
+ metadata?: Record<string, unknown>;
77
+ }
78
+ /**
79
+ * Agents API for discovery and orchestration
80
+ */
81
+ export declare class AgentsAPI {
82
+ private client;
83
+ constructor(client: PrivateConnect);
84
+ /**
85
+ * List all agents in the workspace
86
+ */
87
+ list(options?: {
88
+ onlineOnly?: boolean;
89
+ }): Promise<Agent[]>;
90
+ /**
91
+ * Find agents by capability
92
+ */
93
+ findByCapability(capability: string): Promise<Agent[]>;
94
+ /**
95
+ * Register capabilities for this agent
96
+ */
97
+ registerCapabilities(capabilities: Array<{
98
+ name: string;
99
+ metadata?: Record<string, unknown>;
100
+ }>): Promise<void>;
101
+ /**
102
+ * Send a message to another agent
103
+ */
104
+ sendMessage(toAgentId: string, payload: Record<string, unknown>, options?: {
105
+ channel?: string;
106
+ type?: 'request' | 'response' | 'event';
107
+ }): Promise<{
108
+ messageId: string;
109
+ }>;
110
+ /**
111
+ * Broadcast a message to all online agents
112
+ */
113
+ broadcast(payload: Record<string, unknown>, options?: {
114
+ channel?: string;
115
+ }): Promise<{
116
+ sent: number;
117
+ }>;
118
+ /**
119
+ * Get messages for this agent
120
+ */
121
+ getMessages(options?: {
122
+ channel?: string;
123
+ unreadOnly?: boolean;
124
+ limit?: number;
125
+ }): Promise<Message[]>;
126
+ /**
127
+ * Mark messages as read
128
+ */
129
+ markRead(messageIds: string[]): Promise<void>;
130
+ }
131
+ /**
132
+ * Services API for connecting to and managing services
133
+ */
134
+ export declare class ServicesAPI {
135
+ private client;
136
+ constructor(client: PrivateConnect);
137
+ /**
138
+ * List all services
139
+ */
140
+ list(): Promise<Service[]>;
141
+ /**
142
+ * Get a specific service by name
143
+ */
144
+ get(name: string): Promise<Service | null>;
145
+ /**
146
+ * Get connection details for a service
147
+ */
148
+ getConnection(serviceName: string): Promise<Connection>;
149
+ }
150
+ /**
151
+ * Sessions API for ephemeral orchestration sessions
152
+ */
153
+ export declare class SessionsAPI {
154
+ private client;
155
+ private activeSessions;
156
+ constructor(client: PrivateConnect);
157
+ /**
158
+ * Create an orchestration session
159
+ */
160
+ create(name: string, options?: {
161
+ ttlMinutes?: number;
162
+ metadata?: Record<string, unknown>;
163
+ }): Promise<Session>;
164
+ /**
165
+ * End an orchestration session
166
+ */
167
+ end(sessionId: string): Promise<void>;
168
+ /**
169
+ * Get active sessions
170
+ */
171
+ getActive(): Session[];
172
+ }
173
+ /**
174
+ * Main Private Connect SDK client
175
+ */
176
+ export declare class PrivateConnect {
177
+ private config;
178
+ /** Agents API for discovery and orchestration */
179
+ agents: AgentsAPI;
180
+ /** Services API for connecting to services */
181
+ services: ServicesAPI;
182
+ /** Sessions API for ephemeral orchestration */
183
+ sessions: SessionsAPI;
184
+ constructor(config: PrivateConnectConfig);
185
+ /**
186
+ * Get the agent ID
187
+ */
188
+ get agentId(): string | undefined;
189
+ /**
190
+ * Connect to a service and get connection details
191
+ */
192
+ connect(serviceName: string): Promise<Connection>;
193
+ /**
194
+ * Internal fetch helper
195
+ */
196
+ fetch(path: string, options?: RequestInit): Promise<Response>;
197
+ /**
198
+ * Try to detect agent ID from local config
199
+ */
200
+ private detectAgentId;
201
+ }
202
+ export default PrivateConnect;
203
+ export declare function connect(serviceName: string, config?: PrivateConnectConfig): Promise<Connection>;
package/dist/index.js ADDED
@@ -0,0 +1,309 @@
1
+ "use strict";
2
+ /**
3
+ * Private Connect SDK
4
+ *
5
+ * Programmatic access to Private Connect services and agent orchestration.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { PrivateConnect } from '@privateconnect/sdk';
10
+ *
11
+ * const pc = new PrivateConnect({ apiKey: 'your-api-key' });
12
+ *
13
+ * // Connect to a service
14
+ * const db = await pc.connect('postgres-prod');
15
+ * console.log(db.connectionString); // postgres://localhost:5432/...
16
+ *
17
+ * // List all agents
18
+ * const agents = await pc.agents.list();
19
+ *
20
+ * // Send message to another agent
21
+ * await pc.agents.sendMessage(targetAgentId, { action: 'deploy' });
22
+ * ```
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.PrivateConnect = exports.SessionsAPI = exports.ServicesAPI = exports.AgentsAPI = void 0;
26
+ exports.connect = connect;
27
+ /**
28
+ * Agents API for discovery and orchestration
29
+ */
30
+ class AgentsAPI {
31
+ constructor(client) {
32
+ this.client = client;
33
+ }
34
+ /**
35
+ * List all agents in the workspace
36
+ */
37
+ async list(options) {
38
+ const response = await this.client.fetch('/v1/agents/orchestration');
39
+ const data = await response.json();
40
+ let agents = data.agents || [];
41
+ if (options?.onlineOnly) {
42
+ agents = agents.filter((a) => a.isOnline);
43
+ }
44
+ return agents.map((a) => ({
45
+ id: a.id,
46
+ name: a.name,
47
+ label: a.label,
48
+ isOnline: a.isOnline,
49
+ lastSeenAt: a.lastSeenAt,
50
+ capabilities: a.capabilities?.map((c) => c.name) || [],
51
+ services: a.services?.map((s) => s.name) || [],
52
+ }));
53
+ }
54
+ /**
55
+ * Find agents by capability
56
+ */
57
+ async findByCapability(capability) {
58
+ const response = await this.client.fetch(`/v1/agents/by-capability/${encodeURIComponent(capability)}`);
59
+ const data = await response.json();
60
+ return data.agents || [];
61
+ }
62
+ /**
63
+ * Register capabilities for this agent
64
+ */
65
+ async registerCapabilities(capabilities) {
66
+ await this.client.fetch(`/v1/agents/${this.client.agentId}/capabilities`, {
67
+ method: 'POST',
68
+ body: JSON.stringify({ capabilities }),
69
+ });
70
+ }
71
+ /**
72
+ * Send a message to another agent
73
+ */
74
+ async sendMessage(toAgentId, payload, options) {
75
+ const response = await this.client.fetch(`/v1/agents/${this.client.agentId}/messages/send`, {
76
+ method: 'POST',
77
+ body: JSON.stringify({ toAgentId, payload, ...options }),
78
+ });
79
+ return response.json();
80
+ }
81
+ /**
82
+ * Broadcast a message to all online agents
83
+ */
84
+ async broadcast(payload, options) {
85
+ const response = await this.client.fetch(`/v1/agents/${this.client.agentId}/messages/broadcast`, {
86
+ method: 'POST',
87
+ body: JSON.stringify({ payload, ...options }),
88
+ });
89
+ return response.json();
90
+ }
91
+ /**
92
+ * Get messages for this agent
93
+ */
94
+ async getMessages(options) {
95
+ const params = new URLSearchParams();
96
+ if (options?.channel)
97
+ params.set('channel', options.channel);
98
+ if (options?.unreadOnly !== undefined)
99
+ params.set('unreadOnly', String(options.unreadOnly));
100
+ if (options?.limit)
101
+ params.set('limit', String(options.limit));
102
+ const response = await this.client.fetch(`/v1/agents/${this.client.agentId}/messages?${params}`);
103
+ const data = await response.json();
104
+ return data.messages || [];
105
+ }
106
+ /**
107
+ * Mark messages as read
108
+ */
109
+ async markRead(messageIds) {
110
+ await this.client.fetch(`/v1/agents/${this.client.agentId}/messages/read`, {
111
+ method: 'POST',
112
+ body: JSON.stringify({ messageIds }),
113
+ });
114
+ }
115
+ }
116
+ exports.AgentsAPI = AgentsAPI;
117
+ /**
118
+ * Services API for connecting to and managing services
119
+ */
120
+ class ServicesAPI {
121
+ constructor(client) {
122
+ this.client = client;
123
+ }
124
+ /**
125
+ * List all services
126
+ */
127
+ async list() {
128
+ const response = await this.client.fetch('/v1/services');
129
+ return response.json();
130
+ }
131
+ /**
132
+ * Get a specific service by name
133
+ */
134
+ async get(name) {
135
+ const services = await this.list();
136
+ return services.find(s => s.name.toLowerCase() === name.toLowerCase()) || null;
137
+ }
138
+ /**
139
+ * Get connection details for a service
140
+ */
141
+ async getConnection(serviceName) {
142
+ const service = await this.get(serviceName);
143
+ if (!service) {
144
+ throw new Error(`Service "${serviceName}" not found`);
145
+ }
146
+ const port = service.tunnelPort || service.targetPort;
147
+ const host = 'localhost';
148
+ let connectionString = '';
149
+ let envVar = 'SERVICE_URL';
150
+ if (service.targetPort === 5432 || service.protocol === 'postgres') {
151
+ connectionString = `postgres://${host}:${port}/postgres`;
152
+ envVar = 'DATABASE_URL';
153
+ }
154
+ else if (service.targetPort === 3306 || service.protocol === 'mysql') {
155
+ connectionString = `mysql://${host}:${port}`;
156
+ envVar = 'DATABASE_URL';
157
+ }
158
+ else if (service.targetPort === 6379 || service.protocol === 'redis') {
159
+ connectionString = `redis://${host}:${port}`;
160
+ envVar = 'REDIS_URL';
161
+ }
162
+ else if (service.targetPort === 27017 || service.protocol === 'mongodb') {
163
+ connectionString = `mongodb://${host}:${port}`;
164
+ envVar = 'MONGODB_URI';
165
+ }
166
+ else if (service.protocol === 'http' || service.protocol === 'https') {
167
+ connectionString = `http://${host}:${port}`;
168
+ envVar = 'API_URL';
169
+ }
170
+ else {
171
+ connectionString = `tcp://${host}:${port}`;
172
+ envVar = `${serviceName.toUpperCase().replace(/-/g, '_')}_URL`;
173
+ }
174
+ return {
175
+ service: serviceName,
176
+ host,
177
+ port,
178
+ connectionString,
179
+ envVar,
180
+ };
181
+ }
182
+ }
183
+ exports.ServicesAPI = ServicesAPI;
184
+ /**
185
+ * Sessions API for ephemeral orchestration sessions
186
+ */
187
+ class SessionsAPI {
188
+ constructor(client) {
189
+ this.client = client;
190
+ this.activeSessions = new Map();
191
+ }
192
+ /**
193
+ * Create an orchestration session
194
+ */
195
+ async create(name, options) {
196
+ const ttlMinutes = options?.ttlMinutes || 60;
197
+ const sessionId = `${this.client.agentId}-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
198
+ const expiresAt = new Date(Date.now() + ttlMinutes * 60 * 1000);
199
+ const session = {
200
+ id: sessionId,
201
+ name,
202
+ createdBy: this.client.agentId,
203
+ createdAt: new Date().toISOString(),
204
+ expiresAt: expiresAt.toISOString(),
205
+ metadata: options?.metadata,
206
+ };
207
+ this.activeSessions.set(sessionId, session);
208
+ // Broadcast session creation
209
+ await this.client.agents.broadcast({ type: 'session:created', session }, { channel: 'orchestration' });
210
+ return session;
211
+ }
212
+ /**
213
+ * End an orchestration session
214
+ */
215
+ async end(sessionId) {
216
+ this.activeSessions.delete(sessionId);
217
+ // Broadcast session end
218
+ await this.client.agents.broadcast({
219
+ type: 'session:ended',
220
+ sessionId,
221
+ endedBy: this.client.agentId,
222
+ endedAt: new Date().toISOString(),
223
+ }, { channel: 'orchestration' });
224
+ }
225
+ /**
226
+ * Get active sessions
227
+ */
228
+ getActive() {
229
+ const now = new Date();
230
+ const active = [];
231
+ for (const [id, session] of this.activeSessions) {
232
+ if (new Date(session.expiresAt) > now) {
233
+ active.push(session);
234
+ }
235
+ else {
236
+ this.activeSessions.delete(id);
237
+ }
238
+ }
239
+ return active;
240
+ }
241
+ }
242
+ exports.SessionsAPI = SessionsAPI;
243
+ /**
244
+ * Main Private Connect SDK client
245
+ */
246
+ class PrivateConnect {
247
+ constructor(config) {
248
+ this.config = {
249
+ apiKey: config.apiKey,
250
+ hubUrl: config.hubUrl || 'https://api.privateconnect.co',
251
+ agentId: config.agentId || this.detectAgentId(),
252
+ };
253
+ this.agents = new AgentsAPI(this);
254
+ this.services = new ServicesAPI(this);
255
+ this.sessions = new SessionsAPI(this);
256
+ }
257
+ /**
258
+ * Get the agent ID
259
+ */
260
+ get agentId() {
261
+ return this.config.agentId;
262
+ }
263
+ /**
264
+ * Connect to a service and get connection details
265
+ */
266
+ async connect(serviceName) {
267
+ return this.services.getConnection(serviceName);
268
+ }
269
+ /**
270
+ * Internal fetch helper
271
+ */
272
+ async fetch(path, options) {
273
+ const url = `${this.config.hubUrl}${path}`;
274
+ const response = await fetch(url, {
275
+ ...options,
276
+ headers: {
277
+ 'x-api-key': this.config.apiKey,
278
+ 'Content-Type': 'application/json',
279
+ ...options?.headers,
280
+ },
281
+ });
282
+ if (!response.ok) {
283
+ const error = await response.json().catch(() => ({ message: 'Unknown error' }));
284
+ throw new Error(error.message || `Request failed: ${response.status}`);
285
+ }
286
+ return response;
287
+ }
288
+ /**
289
+ * Try to detect agent ID from local config
290
+ */
291
+ detectAgentId() {
292
+ // In a real implementation, this would read from ~/.connect/config.json
293
+ // For now, generate a default ID
294
+ return `sdk-${Date.now()}`;
295
+ }
296
+ }
297
+ exports.PrivateConnect = PrivateConnect;
298
+ // Default export
299
+ exports.default = PrivateConnect;
300
+ // Convenience function
301
+ async function connect(serviceName, config) {
302
+ const apiKey = config?.apiKey || process.env.PRIVATECONNECT_API_KEY;
303
+ if (!apiKey) {
304
+ throw new Error('API key required. Set PRIVATECONNECT_API_KEY or pass config.apiKey');
305
+ }
306
+ const client = new PrivateConnect({ ...config, apiKey });
307
+ return client.connect(serviceName);
308
+ }
309
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7OztBQTBYSCwwQkFRQztBQXZVRDs7R0FFRztBQUNILE1BQWEsU0FBUztJQUNwQixZQUFvQixNQUFzQjtRQUF0QixXQUFNLEdBQU4sTUFBTSxDQUFnQjtJQUFHLENBQUM7SUFFOUM7O09BRUc7SUFDSCxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQWtDO1FBQzNDLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUNyRSxNQUFNLElBQUksR0FBRyxNQUFNLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNuQyxJQUFJLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUUvQixJQUFJLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQztZQUN4QixNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2pELENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDN0IsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFO1lBQ1IsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJO1lBQ1osS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLO1lBQ2QsUUFBUSxFQUFFLENBQUMsQ0FBQyxRQUFRO1lBQ3BCLFVBQVUsRUFBRSxDQUFDLENBQUMsVUFBVTtZQUN4QixZQUFZLEVBQUUsQ0FBQyxDQUFDLFlBQVksRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO1lBQzNELFFB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QUFjLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELE9BQU8sTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUNyQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQcml2YXRlIENvbm5lY3QgU0RLXG4gKiBcbiAqIFByb2dyYW1tYXRpYyBhY2Nlc3MgdG8gUHJpdmF0ZSBDb25uZWN0IHNlcnZpY2VzIGFuZCBhZ2VudCBvcmNoZXN0cmF0aW9uLlxuICogXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgUHJpdmF0ZUNvbm5lY3QgfSBmcm9tICdAcHJpdmF0ZWNvbm5lY3Qvc2RrJztcbiAqIFxuICogY29uc3QgcGMgPSBuZXcgUHJpdmF0ZUNvbm5lY3QoeyBhcGlLZXk6ICd5b3VyLWFwaS1rZXknIH0pO1xuICogXG4gKiAvLyBDb25uZWN0IHRvIGEgc2VydmljZVxuICogY29uc3QgZGIgPSBhd2FpdCBwYy5jb25uZWN0KCdwb3N0Z3Jlcy1wcm9kJyk7XG4gKiBjb25zb2xlLmxvZyhkYi5jb25uZWN0aW9uU3RyaW5nKTsgLy8gcG9zdGdyZXM6Ly9sb2NhbGhvc3Q6NTQzMi8uLi5cbiAqIFxuICogLy8gTGlzdCBhbGwgYWdlbnRzXG4gKiBjb25zdCBhZ2VudHMgPSBhd2FpdCBwYy5hZ2VudHMubGlzdCgpO1xuICogXG4gKiAvLyBTZW5kIG1lc3NhZ2UgdG8gYW5vdGhlciBhZ2VudFxuICogYXdhaXQgcGMuYWdlbnRzLnNlbmRNZXNzYWdlKHRhcmdldEFnZW50SWQsIHsgYWN0aW9uOiAnZGVwbG95JyB9KTtcbiAqIGBgYFxuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgUHJpdmF0ZUNvbm5lY3RDb25maWcge1xuICAvKiogQVBJIGtleSBmb3IgYXV0aGVudGljYXRpb24gKi9cbiAgYXBpS2V5OiBzdHJpbmc7XG4gIC8qKiBIdWIgVVJMIChkZWZhdWx0OiBodHRwczovL2FwaS5wcml2YXRlY29ubmVjdC5jbykgKi9cbiAgaHViVXJsPzogc3RyaW5nO1xuICAvKiogQWdlbnQgSUQgKGF1dG8tZGV0ZWN0ZWQgZnJvbSBjb25maWcgaWYgbm90IHByb3ZpZGVkKSAqL1xuICBhZ2VudElkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZpY2Uge1xuICBpZDogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIHRhcmdldEhvc3Q6IHN0cmluZztcbiAgdGFyZ2V0UG9ydDogbnVtYmVyO1xuICB0dW5uZWxQb3J0PzogbnVtYmVyO1xuICBwcm90b2NvbDogc3RyaW5nO1xuICBzdGF0dXM6IHN0cmluZztcbiAgYWdlbnRMYWJlbD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBZ2VudCB7XG4gIGlkOiBzdHJpbmc7XG4gIG5hbWU/OiBzdHJpbmc7XG4gIGxhYmVsOiBzdHJpbmc7XG4gIGlzT25saW5lOiBib29sZWFuO1xuICBsYXN0U2VlbkF0OiBzdHJpbmc7XG4gIGNhcGFiaWxpdGllczogc3RyaW5nW107XG4gIHNlcnZpY2VzOiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb25uZWN0aW9uIHtcbiAgc2VydmljZTogc3RyaW5nO1xuICBob3N0OiBzdHJpbmc7XG4gIHBvcnQ6IG51bWJlcjtcbiAgY29ubmVjdGlvblN0cmluZzogc3RyaW5nO1xuICBlbnZWYXI6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNZXNzYWdlIHtcbiAgaWQ6IHN0cmluZztcbiAgZnJvbTogeyBpZDogc3RyaW5nOyBuYW1lPzogc3RyaW5nOyBsYWJlbD86IHN0cmluZyB9O1xuICBjaGFubmVsOiBzdHJpbmc7XG4gIHR5cGU6IHN0cmluZztcbiAgcGF5bG9hZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xuICBpc1JlYWQ6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2Vzc2lvbiB7XG4gIGlkOiBzdHJpbmc7XG4gIG5hbWU6IHN0cmluZztcbiAgY3JlYXRlZEJ5OiBzdHJpbmc7XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xuICBleHBpcmVzQXQ6IHN0cmluZztcbiAgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuLyoqXG4gKiBBZ2VudHMgQVBJIGZvciBkaXNjb3ZlcnkgYW5kIG9yY2hlc3RyYXRpb25cbiAqL1xuZXhwb3J0IGNsYXNzIEFnZW50c0FQSSB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2xpZW50OiBQcml2YXRlQ29ubmVjdCkge31cblxuICAvKipcbiAgICogTGlzdCBhbGwgYWdlbnRzIGluIHRoZSB3b3Jrc3BhY2VcbiAgICovXG4gIGFzeW5jIGxpc3Qob3B0aW9ucz86IHsgb25saW5lT25seT86IGJvb2xlYW4gfSk6IFByb21pc2U8QWdlbnRbXT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5jbGllbnQuZmV0Y2goJy92MS9hZ2VudHMvb3JjaGVzdHJhdGlvbicpO1xuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG4gICAgbGV0IGFnZW50cyA9IGRhdGEuYWdlbnRzIHx8IFtdO1xuICAgIFxuICAgIGlmIChvcHRpb25zPy5vbmxpbmVPbmx5KSB7XG4gICAgICBhZ2VudHMgPSBhZ2VudHMuZmlsdGVyKChhOiBhbnkpID0+IGEuaXNPbmxpbmUpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gYWdlbnRzLm1hcCgoYTogYW55KSA9PiAoe1xuICAgICAgaWQ6IGEuaWQsXG4gICAgICBuYW1lOiBhLm5hbWUsXG4gICAgICBsYWJlbDogYS5sYWJlbCxcbiAgICAgIGlzT25saW5lOiBhLmlzT25saW5lLFxuICAgICAgbGFzdFNlZW5BdDogYS5sYXN0U2VlbkF0LFxuICAgICAgY2FwYWJpbGl0aWVzOiBhLmNhcGFiaWxpdGllcz8ubWFwKChjOiBhbnkpID0+IGMubmFtZSkgfHwgW10sXG4gICAgICBzZXJ2aWNlczogYS5zZXJ2aWNlcz8ubWFwKChzOiBhbnkpID0+IHMubmFtZSkgfHwgW10sXG4gICAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmQgYWdlbnRzIGJ5IGNhcGFiaWxpdHlcbiAgICovXG4gIGFzeW5jIGZpbmRCeUNhcGFiaWxpdHkoY2FwYWJpbGl0eTogc3RyaW5nKTogUHJvbWlzZTxBZ2VudFtdPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmNsaWVudC5mZXRjaChgL3YxL2FnZW50cy9ieS1jYXBhYmlsaXR5LyR7ZW5jb2RlVVJJQ29tcG9uZW50KGNhcGFiaWxpdHkpfWApO1xuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG4gICAgcmV0dXJuIGRhdGEuYWdlbnRzIHx8IFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVyIGNhcGFiaWxpdGllcyBmb3IgdGhpcyBhZ2VudFxuICAgKi9cbiAgYXN5bmMgcmVnaXN0ZXJDYXBhYmlsaXRpZXMoY2FwYWJpbGl0aWVzOiBBcnJheTx7IG5hbWU6IHN0cmluZzsgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9Pik6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuY2xpZW50LmZldGNoKGAvdjEvYWdlbnRzLyR7dGhpcy5jbGllbnQuYWdlbnRJZH0vY2FwYWJpbGl0aWVzYCwge1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7IGNhcGFiaWxpdGllcyB9KSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kIGEgbWVzc2FnZSB0byBhbm90aGVyIGFnZW50XG4gICAqL1xuICBhc3luYyBzZW5kTWVzc2FnZShcbiAgICB0b0FnZW50SWQ6IHN0cmluZyxcbiAgICBwYXlsb2FkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBvcHRpb25zPzogeyBjaGFubmVsPzogc3RyaW5nOyB0eXBlPzogJ3JlcXVlc3QnIHwgJ3Jlc3BvbnNlJyB8ICdldmVudCcgfVxuICApOiBQcm9taXNlPHsgbWVzc2FnZUlkOiBzdHJpbmcgfT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5jbGllbnQuZmV0Y2goYC92MS9hZ2VudHMvJHt0aGlzLmNsaWVudC5hZ2VudElkfS9tZXNzYWdlcy9zZW5kYCwge1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7IHRvQWdlbnRJZCwgcGF5bG9hZCwgLi4ub3B0aW9ucyB9KSxcbiAgICB9KTtcbiAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJyb2FkY2FzdCBhIG1lc3NhZ2UgdG8gYWxsIG9ubGluZSBhZ2VudHNcbiAgICovXG4gIGFzeW5jIGJyb2FkY2FzdChcbiAgICBwYXlsb2FkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBvcHRpb25zPzogeyBjaGFubmVsPzogc3RyaW5nIH1cbiAgKTogUHJvbWlzZTx7IHNlbnQ6IG51bWJlciB9PiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmNsaWVudC5mZXRjaChgL3YxL2FnZW50cy8ke3RoaXMuY2xpZW50LmFnZW50SWR9L21lc3NhZ2VzL2Jyb2FkY2FzdGAsIHtcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBwYXlsb2FkLCAuLi5vcHRpb25zIH0pLFxuICAgIH0pO1xuICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IG1lc3NhZ2VzIGZvciB0aGlzIGFnZW50XG4gICAqL1xuICBhc3luYyBnZXRNZXNzYWdlcyhvcHRpb25zPzogeyBjaGFubmVsPzogc3RyaW5nOyB1bnJlYWRPbmx5PzogYm9vbGVhbjsgbGltaXQ/OiBudW1iZXIgfSk6IFByb21pc2U8TWVzc2FnZVtdPiB7XG4gICAgY29uc3QgcGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcygpO1xuICAgIGlmIChvcHRpb25zPy5jaGFubmVsKSBwYXJhbXMuc2V0KCdjaGFubmVsJywgb3B0aW9ucy5jaGFubmVsKTtcbiAgICBpZiAob3B0aW9ucz8udW5yZWFkT25seSAhPT0gdW5kZWZpbmVkKSBwYXJhbXMuc2V0KCd1bnJlYWRPbmx5JywgU3RyaW5nKG9wdGlvbnMudW5yZWFkT25seSkpO1xuICAgIGlmIChvcHRpb25zPy5saW1pdCkgcGFyYW1zLnNldCgnbGltaXQnLCBTdHJpbmcob3B0aW9ucy5saW1pdCkpO1xuICAgIFxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5jbGllbnQuZmV0Y2goYC92MS9hZ2VudHMvJHt0aGlzLmNsaWVudC5hZ2VudElkfS9tZXNzYWdlcz8ke3BhcmFtc31gKTtcbiAgICBjb25zdCBkYXRhID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICAgIHJldHVybiBkYXRhLm1lc3NhZ2VzIHx8IFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIE1hcmsgbWVzc2FnZXMgYXMgcmVhZFxuICAgKi9cbiAgYXN5bmMgbWFya1JlYWQobWVzc2FnZUlkczogc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmNsaWVudC5mZXRjaChgL3YxL2FnZW50cy8ke3RoaXMuY2xpZW50LmFnZW50SWR9L21lc3NhZ2VzL3JlYWRgLCB7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgbWVzc2FnZUlkcyB9KSxcbiAgICB9KTtcbiAgfVxufVxuXG4vKipcbiAqIFNlcnZpY2VzIEFQSSBmb3IgY29ubmVjdGluZyB0byBhbmQgbWFuYWdpbmcgc2VydmljZXNcbiAqL1xuZXhwb3J0IGNsYXNzIFNlcnZpY2VzQVBJIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjbGllbnQ6IFByaXZhdGVDb25uZWN0KSB7fVxuXG4gIC8qKlxuICAgKiBMaXN0IGFsbCBzZXJ2aWNlc1xuICAgKi9cbiAgYXN5bmMgbGlzdCgpOiBQcm9taXNlPFNlcnZpY2VbXT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5jbGllbnQuZmV0Y2goJy92MS9zZXJ2aWNlcycpO1xuICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgc3BlY2lmaWMgc2VydmljZSBieSBuYW1lXG4gICAqL1xuICBhc3luYyBnZXQobmFtZTogc3RyaW5nKTogUHJvbWlzZTxTZXJ2aWNlIHwgbnVsbD4ge1xuICAgIGNvbnN0IHNlcnZpY2VzID0gYXdhaXQgdGhpcy5saXN0KCk7XG4gICAgcmV0dXJuIHNlcnZpY2VzLmZpbmQocyA9PiBzLm5hbWUudG9Mb3dlckNhc2UoKSA9PT0gbmFtZS50b0xvd2VyQ2FzZSgpKSB8fCBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjb25uZWN0aW9uIGRldGFpbHMgZm9yIGEgc2VydmljZVxuICAgKi9cbiAgYXN5bmMgZ2V0Q29ubmVjdGlvbihzZXJ2aWNlTmFtZTogc3RyaW5nKTogUHJvbWlzZTxDb25uZWN0aW9uPiB7XG4gICAgY29uc3Qgc2VydmljZSA9IGF3YWl0IHRoaXMuZ2V0KHNlcnZpY2VOYW1lKTtcbiAgICBpZiAoIXNlcnZpY2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgU2VydmljZSBcIiR7c2VydmljZU5hbWV9XCIgbm90IGZvdW5kYCk7XG4gICAgfVxuXG4gICAgY29uc3QgcG9ydCA9IHNlcnZpY2UudHVubmVsUG9ydCB8fCBzZXJ2aWNlLnRhcmdldFBvcnQ7XG4gICAgY29uc3QgaG9zdCA9ICdsb2NhbGhvc3QnO1xuICAgIFxuICAgIGxldCBjb25uZWN0aW9uU3RyaW5nID0gJyc7XG4gICAgbGV0IGVudlZhciA9ICdTRVJWSUNFX1VSTCc7XG4gICAgXG4gICAgaWYgKHNlcnZpY2UudGFyZ2V0UG9ydCA9PT0gNTQzMiB8fCBzZXJ2aWNlLnByb3RvY29sID09PSAncG9zdGdyZXMnKSB7XG4gICAgICBjb25uZWN0aW9uU3RyaW5nID0gYHBvc3RncmVzOi8vJHtob3N0fToke3BvcnR9L3Bvc3RncmVzYDtcbiAgICAgIGVudlZhciA9ICdEQVRBQkFTRV9VUkwnO1xuICAgIH0gZWxzZSBpZiAoc2VydmljZS50YXJnZXRQb3J0ID09PSAzMzA2IHx8IHNlcnZpY2UucHJvdG9jb2wgPT09ICdteXNxbCcpIHtcbiAgICAgIGNvbm5lY3Rpb25TdHJpbmcgPSBgbXlzcWw6Ly8ke2hvc3R9OiR7cG9ydH1gO1xuICAgICAgZW52VmFyID0gJ0RBVEFCQVNFX1VSTCc7XG4gICAgfSBlbHNlIGlmIChzZXJ2aWNlLnRhcmdldFBvcnQgPT09IDYzNzkgfHwgc2VydmljZS5wcm90b2NvbCA9PT0gJ3JlZGlzJykge1xuICAgICAgY29ubmVjdGlvblN0cmluZyA9IGByZWRpczovLyR7aG9zdH06JHtwb3J0fWA7XG4gICAgICBlbnZWYXIgPSAnUkVESVNfVVJMJztcbiAgICB9IGVsc2UgaWYgKHNlcnZpY2UudGFyZ2V0UG9ydCA9PT0gMjcwMTcgfHwgc2VydmljZS5wcm90b2NvbCA9PT0gJ21vbmdvZGInKSB7XG4gICAgICBjb25uZWN0aW9uU3RyaW5nID0gYG1vbmdvZGI6Ly8ke2hvc3R9OiR7cG9ydH1gO1xuICAgICAgZW52VmFyID0gJ01PTkdPREJfVVJJJztcbiAgICB9IGVsc2UgaWYgKHNlcnZpY2UucHJvdG9jb2wgPT09ICdodHRwJyB8fCBzZXJ2aWNlLnByb3RvY29sID09PSAnaHR0cHMnKSB7XG4gICAgICBjb25uZWN0aW9uU3RyaW5nID0gYGh0dHA6Ly8ke2hvc3R9OiR7cG9ydH1gO1xuICAgICAgZW52VmFyID0gJ0FQSV9VUkwnO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25uZWN0aW9uU3RyaW5nID0gYHRjcDovLyR7aG9zdH06JHtwb3J0fWA7XG4gICAgICBlbnZWYXIgPSBgJHtzZXJ2aWNlTmFtZS50b1VwcGVyQ2FzZSgpLnJlcGxhY2UoLy0vZywgJ18nKX1fVVJMYDtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgc2VydmljZTogc2VydmljZU5hbWUsXG4gICAgICBob3N0LFxuICAgICAgcG9ydCxcbiAgICAgIGNvbm5lY3Rpb25TdHJpbmcsXG4gICAgICBlbnZWYXIsXG4gICAgfTtcbiAgfVxufVxuXG4vKipcbiAqIFNlc3Npb25zIEFQSSBmb3IgZXBoZW1lcmFsIG9yY2hlc3RyYXRpb24gc2Vzc2lvbnNcbiAqL1xuZXhwb3J0IGNsYXNzIFNlc3Npb25zQVBJIHtcbiAgcHJpdmF0ZSBhY3RpdmVTZXNzaW9ucyA9IG5ldyBNYXA8c3RyaW5nLCBTZXNzaW9uPigpO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2xpZW50OiBQcml2YXRlQ29ubmVjdCkge31cblxuICAvKipcbiAgICogQ3JlYXRlIGFuIG9yY2hlc3RyYXRpb24gc2Vzc2lvblxuICAgKi9cbiAgYXN5bmMgY3JlYXRlKG5hbWU6IHN0cmluZywgb3B0aW9ucz86IHsgdHRsTWludXRlcz86IG51bWJlcjsgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9KTogUHJvbWlzZTxTZXNzaW9uPiB7XG4gICAgY29uc3QgdHRsTWludXRlcyA9IG9wdGlvbnM/LnR0bE1pbnV0ZXMgfHwgNjA7XG4gICAgY29uc3Qgc2Vzc2lvbklkID0gYCR7dGhpcy5jbGllbnQuYWdlbnRJZH0tJHtEYXRlLm5vdygpfS0ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZygyLCA4KX1gO1xuICAgIGNvbnN0IGV4cGlyZXNBdCA9IG5ldyBEYXRlKERhdGUubm93KCkgKyB0dGxNaW51dGVzICogNjAgKiAxMDAwKTtcblxuICAgIGNvbnN0IHNlc3Npb246IFNlc3Npb24gPSB7XG4gICAgICBpZDogc2Vzc2lvbklkLFxuICAgICAgbmFtZSxcbiAgICAgIGNyZWF0ZWRCeTogdGhpcy5jbGllbnQuYWdlbnRJZCEsXG4gICAgICBjcmVhdGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgIGV4cGlyZXNBdDogZXhwaXJlc0F0LnRvSVNPU3RyaW5nKCksXG4gICAgICBtZXRhZGF0YTogb3B0aW9ucz8ubWV0YWRhdGEsXG4gICAgfTtcblxuICAgIHRoaXMuYWN0aXZlU2Vzc2lvbnMuc2V0KHNlc3Npb25JZCwgc2Vzc2lvbik7XG5cbiAgICAvLyBCcm9hZGNhc3Qgc2Vzc2lvbiBjcmVhdGlvblxuICAgIGF3YWl0IHRoaXMuY2xpZW50LmFnZW50cy5icm9hZGNhc3QoXG4gICAgICB7IHR5cGU6ICdzZXNzaW9uOmNyZWF0ZWQnLCBzZXNzaW9uIH0sXG4gICAgICB7IGNoYW5uZWw6ICdvcmNoZXN0cmF0aW9uJyB9XG4gICAgKTtcblxuICAgIHJldHVybiBzZXNzaW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuZCBhbiBvcmNoZXN0cmF0aW9uIHNlc3Npb25cbiAgICovXG4gIGFzeW5jIGVuZChzZXNzaW9uSWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuYWN0aXZlU2Vzc2lvbnMuZGVsZXRlKHNlc3Npb25JZCk7XG5cbiAgICAvLyBCcm9hZGNhc3Qgc2Vzc2lvbiBlbmRcbiAgICBhd2FpdCB0aGlzLmNsaWVudC5hZ2VudHMuYnJvYWRjYXN0KFxuICAgICAge1xuICAgICAgICB0eXBlOiAnc2Vzc2lvbjplbmRlZCcsXG4gICAgICAgIHNlc3Npb25JZCxcbiAgICAgICAgZW5kZWRCeTogdGhpcy5jbGllbnQuYWdlbnRJZCxcbiAgICAgICAgZW5kZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgfSxcbiAgICAgIHsgY2hhbm5lbDogJ29yY2hlc3RyYXRpb24nIH1cbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhY3RpdmUgc2Vzc2lvbnNcbiAgICovXG4gIGdldEFjdGl2ZSgpOiBTZXNzaW9uW10ge1xuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgY29uc3QgYWN0aXZlOiBTZXNzaW9uW10gPSBbXTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IFtpZCwgc2Vzc2lvbl0gb2YgdGhpcy5hY3RpdmVTZXNzaW9ucykge1xuICAgICAgaWYgKG5ldyBEYXRlKHNlc3Npb24uZXhwaXJlc0F0KSA+IG5vdykge1xuICAgICAgICBhY3RpdmUucHVzaChzZXNzaW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYWN0aXZlU2Vzc2lvbnMuZGVsZXRlKGlkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGFjdGl2ZTtcbiAgfVxufVxuXG4vKipcbiAqIE1haW4gUHJpdmF0ZSBDb25uZWN0IFNESyBjbGllbnRcbiAqL1xuZXhwb3J0IGNsYXNzIFByaXZhdGVDb25uZWN0IHtcbiAgcHJpdmF0ZSBjb25maWc6IFJlcXVpcmVkPFByaXZhdGVDb25uZWN0Q29uZmlnPjtcbiAgXG4gIC8qKiBBZ2VudHMgQVBJIGZvciBkaXNjb3ZlcnkgYW5kIG9yY2hlc3RyYXRpb24gKi9cbiAgcHVibGljIGFnZW50czogQWdlbnRzQVBJO1xuICBcbiAgLyoqIFNlcnZpY2VzIEFQSSBmb3IgY29ubmVjdGluZyB0byBzZXJ2aWNlcyAqL1xuICBwdWJsaWMgc2VydmljZXM6IFNlcnZpY2VzQVBJO1xuICBcbiAgLyoqIFNlc3Npb25zIEFQSSBmb3IgZXBoZW1lcmFsIG9yY2hlc3RyYXRpb24gKi9cbiAgcHVibGljIHNlc3Npb25zOiBTZXNzaW9uc0FQSTtcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IFByaXZhdGVDb25uZWN0Q29uZmlnKSB7XG4gICAgdGhpcy5jb25maWcgPSB7XG4gICAgICBhcGlLZXk6IGNvbmZpZy5hcGlLZXksXG4gICAgICBodWJVcmw6IGNvbmZpZy5odWJVcmwgfHwgJ2h0dHBzOi8vYXBpLnByaXZhdGVjb25uZWN0LmNvJyxcbiAgICAgIGFnZW50SWQ6IGNvbmZpZy5hZ2VudElkIHx8IHRoaXMuZGV0ZWN0QWdlbnRJZCgpLFxuICAgIH07XG5cbiAgICB0aGlzLmFnZW50cyA9IG5ldyBBZ2VudHNBUEkodGhpcyk7XG4gICAgdGhpcy5zZXJ2aWNlcyA9IG5ldyBTZXJ2aWNlc0FQSSh0aGlzKTtcbiAgICB0aGlzLnNlc3Npb25zID0gbmV3IFNlc3Npb25zQVBJKHRoaXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgYWdlbnQgSURcbiAgICovXG4gIGdldCBhZ2VudElkKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmFnZW50SWQ7XG4gIH1cblxuICAvKipcbiAgICogQ29ubmVjdCB0byBhIHNlcnZpY2UgYW5kIGdldCBjb25uZWN0aW9uIGRldGFpbHNcbiAgICovXG4gIGFzeW5jIGNvbm5lY3Qoc2VydmljZU5hbWU6IHN0cmluZyk6IFByb21pc2U8Q29ubmVjdGlvbj4ge1xuICAgIHJldHVybiB0aGlzLnNlcnZpY2VzLmdldENvbm5lY3Rpb24oc2VydmljZU5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEludGVybmFsIGZldGNoIGhlbHBlclxuICAgKi9cbiAgYXN5bmMgZmV0Y2gocGF0aDogc3RyaW5nLCBvcHRpb25zPzogUmVxdWVzdEluaXQpOiBQcm9taXNlPFJlc3BvbnNlPiB7XG4gICAgY29uc3QgdXJsID0gYCR7dGhpcy5jb25maWcuaHViVXJsfSR7cGF0aH1gO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICAuLi5vcHRpb25zLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAneC1hcGkta2V5JzogdGhpcy5jb25maWcuYXBpS2V5LFxuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAuLi5vcHRpb25zPy5oZWFkZXJzLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgIGNvbnN0IGVycm9yID0gYXdhaXQgcmVzcG9uc2UuanNvbigpLmNhdGNoKCgpID0+ICh7IG1lc3NhZ2U6ICdVbmtub3duIGVycm9yJyB9KSk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3IubWVzc2FnZSB8fCBgUmVxdWVzdCBmYWlsZWQ6ICR7cmVzcG9uc2Uuc3RhdHVzfWApO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcnkgdG8gZGV0ZWN0IGFnZW50IElEIGZyb20gbG9jYWwgY29uZmlnXG4gICAqL1xuICBwcml2YXRlIGRldGVjdEFnZW50SWQoKTogc3RyaW5nIHtcbiAgICAvLyBJbiBhIHJlYWwgaW1wbGVtZW50YXRpb24sIHRoaXMgd291bGQgcmVhZCBmcm9tIH4vLmNvbm5lY3QvY29uZmlnLmpzb25cbiAgICAvLyBGb3Igbm93LCBnZW5lcmF0ZSBhIGRlZmF1bHQgSURcbiAgICByZXR1cm4gYHNkay0ke0RhdGUubm93KCl9YDtcbiAgfVxufVxuXG4vLyBEZWZhdWx0IGV4cG9ydFxuZXhwb3J0IGRlZmF1bHQgUHJpdmF0ZUNvbm5lY3Q7XG5cbi8vIENvbnZlbmllbmNlIGZ1bmN0aW9uXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29ubmVjdChzZXJ2aWNlTmFtZTogc3RyaW5nLCBjb25maWc/OiBQcml2YXRlQ29ubmVjdENvbmZpZyk6IFByb21pc2U8Q29ubmVjdGlvbj4ge1xuICBjb25zdCBhcGlLZXkgPSBjb25maWc/LmFwaUtleSB8fCBwcm9jZXNzLmVudi5QUklWQVRFQ09OTkVDVF9BUElfS0VZO1xuICBpZiAoIWFwaUtleSkge1xuICAgIHRocm93IG5ldyBFcnJvcignQVBJIGtleSByZXF1aXJlZC4gU2V0IFBSSVZBVEVDT05ORUNUX0FQSV9LRVkgb3IgcGFzcyBjb25maWcuYXBpS2V5Jyk7XG4gIH1cbiAgXG4gIGNvbnN0IGNsaWVudCA9IG5ldyBQcml2YXRlQ29ubmVjdCh7IC4uLmNvbmZpZywgYXBpS2V5IH0pO1xuICByZXR1cm4gY2xpZW50LmNvbm5lY3Qoc2VydmljZU5hbWUpO1xufVxuXG4iXX0=
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@privateconnect/sdk",
3
+ "version": "0.3.0",
4
+ "description": "TypeScript SDK for Private Connect - programmatic access to services and agent orchestration",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc -w",
13
+ "clean": "rm -rf dist"
14
+ },
15
+ "keywords": [
16
+ "private-connect",
17
+ "tunnel",
18
+ "networking",
19
+ "orchestration",
20
+ "agent"
21
+ ],
22
+ "license": "FSL-1.1-MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/treadiehq/private-connect.git",
26
+ "directory": "packages/sdk"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^20.0.0",
30
+ "typescript": "^5.0.0"
31
+ }
32
+ }
33
+