@portel/photon 1.0.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.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +952 -0
  3. package/dist/base.d.ts +58 -0
  4. package/dist/base.d.ts.map +1 -0
  5. package/dist/base.js +92 -0
  6. package/dist/base.js.map +1 -0
  7. package/dist/cli.d.ts +8 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +1441 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/dependency-manager.d.ts +49 -0
  12. package/dist/dependency-manager.d.ts.map +1 -0
  13. package/dist/dependency-manager.js +165 -0
  14. package/dist/dependency-manager.js.map +1 -0
  15. package/dist/loader.d.ts +86 -0
  16. package/dist/loader.d.ts.map +1 -0
  17. package/dist/loader.js +612 -0
  18. package/dist/loader.js.map +1 -0
  19. package/dist/marketplace-manager.d.ts +261 -0
  20. package/dist/marketplace-manager.d.ts.map +1 -0
  21. package/dist/marketplace-manager.js +767 -0
  22. package/dist/marketplace-manager.js.map +1 -0
  23. package/dist/path-resolver.d.ts +21 -0
  24. package/dist/path-resolver.d.ts.map +1 -0
  25. package/dist/path-resolver.js +71 -0
  26. package/dist/path-resolver.js.map +1 -0
  27. package/dist/photon-doc-extractor.d.ts +89 -0
  28. package/dist/photon-doc-extractor.d.ts.map +1 -0
  29. package/dist/photon-doc-extractor.js +228 -0
  30. package/dist/photon-doc-extractor.js.map +1 -0
  31. package/dist/readme-syncer.d.ts +33 -0
  32. package/dist/readme-syncer.d.ts.map +1 -0
  33. package/dist/readme-syncer.js +93 -0
  34. package/dist/readme-syncer.js.map +1 -0
  35. package/dist/registry-manager.d.ts +76 -0
  36. package/dist/registry-manager.d.ts.map +1 -0
  37. package/dist/registry-manager.js +220 -0
  38. package/dist/registry-manager.js.map +1 -0
  39. package/dist/schema-extractor.d.ts +83 -0
  40. package/dist/schema-extractor.d.ts.map +1 -0
  41. package/dist/schema-extractor.js +396 -0
  42. package/dist/schema-extractor.js.map +1 -0
  43. package/dist/security-scanner.d.ts +52 -0
  44. package/dist/security-scanner.d.ts.map +1 -0
  45. package/dist/security-scanner.js +172 -0
  46. package/dist/security-scanner.js.map +1 -0
  47. package/dist/server.d.ts +73 -0
  48. package/dist/server.d.ts.map +1 -0
  49. package/dist/server.js +474 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/template-manager.d.ts +56 -0
  52. package/dist/template-manager.d.ts.map +1 -0
  53. package/dist/template-manager.js +509 -0
  54. package/dist/template-manager.js.map +1 -0
  55. package/dist/test-client.d.ts +52 -0
  56. package/dist/test-client.d.ts.map +1 -0
  57. package/dist/test-client.js +168 -0
  58. package/dist/test-client.js.map +1 -0
  59. package/dist/test-marketplace-sources.d.ts +5 -0
  60. package/dist/test-marketplace-sources.d.ts.map +1 -0
  61. package/dist/test-marketplace-sources.js +53 -0
  62. package/dist/test-marketplace-sources.js.map +1 -0
  63. package/dist/types.d.ts +108 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +12 -0
  66. package/dist/types.js.map +1 -0
  67. package/dist/version-checker.d.ts +48 -0
  68. package/dist/version-checker.d.ts.map +1 -0
  69. package/dist/version-checker.js +128 -0
  70. package/dist/version-checker.js.map +1 -0
  71. package/dist/watcher.d.ts +26 -0
  72. package/dist/watcher.d.ts.map +1 -0
  73. package/dist/watcher.js +72 -0
  74. package/dist/watcher.js.map +1 -0
  75. package/package.json +79 -0
  76. package/templates/photon.template.ts +55 -0
@@ -0,0 +1,509 @@
1
+ import { existsSync } from 'fs';
2
+ import * as fs from 'fs/promises';
3
+ import * as path from 'path';
4
+ import * as crypto from 'crypto';
5
+ /**
6
+ * Manages marketplace documentation templates
7
+ *
8
+ * Templates are stored in .marketplace/_templates/ and can be customized by users.
9
+ * Hash-based detection prevents overwriting user customizations.
10
+ */
11
+ export class TemplateManager {
12
+ workingDir;
13
+ marketplaceDir;
14
+ templateDir;
15
+ hashFile;
16
+ // Current template version - increment when templates are updated
17
+ static TEMPLATE_VERSION = '1.0.0';
18
+ constructor(workingDir) {
19
+ this.workingDir = workingDir;
20
+ this.marketplaceDir = path.join(workingDir, '.marketplace');
21
+ this.templateDir = path.join(this.marketplaceDir, '_templates');
22
+ this.hashFile = path.join(this.marketplaceDir, '.template-hashes.json');
23
+ }
24
+ /**
25
+ * Ensure templates directory exists and templates are initialized
26
+ */
27
+ async ensureTemplates() {
28
+ // Create directories
29
+ await fs.mkdir(this.templateDir, { recursive: true });
30
+ // Load or initialize hash tracking
31
+ const hashes = await this.loadHashes();
32
+ // Check and update each template
33
+ await this.ensureTemplate('readme.md', this.getDefaultReadmeTemplate(), hashes);
34
+ await this.ensureTemplate('photon.md', this.getDefaultPhotonTemplate(), hashes);
35
+ // Save updated hashes
36
+ await this.saveHashes(hashes);
37
+ }
38
+ /**
39
+ * Check if a template has been customized by the user
40
+ */
41
+ async isTemplateCustomized(templateName) {
42
+ const hashes = await this.loadHashes();
43
+ return hashes[templateName]?.customized || false;
44
+ }
45
+ /**
46
+ * Render a template with provided data
47
+ */
48
+ async renderTemplate(templateName, data) {
49
+ const templatePath = path.join(this.templateDir, templateName);
50
+ if (!existsSync(templatePath)) {
51
+ throw new Error(`Template not found: ${templateName}`);
52
+ }
53
+ const template = await fs.readFile(templatePath, 'utf-8');
54
+ return this.render(template, data);
55
+ }
56
+ /**
57
+ * Simple template renderer using template literals
58
+ * Safely evaluates ${expression} in templates
59
+ */
60
+ render(template, data) {
61
+ // Helper functions available in templates
62
+ // Using $ prefix to avoid reserved keywords
63
+ const helpers = {
64
+ // Loop over array
65
+ each: (items, fn) => {
66
+ return items.map((item, index) => fn(item, index)).join('');
67
+ },
68
+ // Conditional rendering
69
+ $if: (condition, truthy, falsy = '') => {
70
+ return condition ? truthy : falsy;
71
+ },
72
+ // Default value
73
+ $default: (value, defaultValue) => {
74
+ return value !== undefined && value !== null && value !== '' ? value : defaultValue;
75
+ },
76
+ // Extract proper name from description (before " - ")
77
+ properName: (desc, fallbackName) => {
78
+ if (desc.includes(' - ')) {
79
+ return desc.split(' - ')[0];
80
+ }
81
+ // Fallback: title case the name
82
+ return fallbackName.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
83
+ },
84
+ // Extract description after " - " separator
85
+ cleanDesc: (desc) => {
86
+ return desc.includes(' - ') ? desc.split(' - ').slice(1).join(' - ') : desc;
87
+ },
88
+ };
89
+ try {
90
+ // Create function with data and helpers in scope
91
+ const fn = new Function('data', 'helpers', `
92
+ with (data) {
93
+ const { each, $if, $default, properName, cleanDesc } = helpers;
94
+ return \`${template}\`;
95
+ }
96
+ `);
97
+ return fn(data, helpers);
98
+ }
99
+ catch (error) {
100
+ throw new Error(`Template rendering error: ${error.message}`);
101
+ }
102
+ }
103
+ /**
104
+ * Ensure a single template exists and is up-to-date
105
+ */
106
+ async ensureTemplate(name, defaultContent, hashes) {
107
+ const templatePath = path.join(this.templateDir, name);
108
+ const defaultHash = this.calculateHash(defaultContent);
109
+ if (!existsSync(templatePath)) {
110
+ // Template doesn't exist - create it
111
+ await fs.writeFile(templatePath, defaultContent, 'utf-8');
112
+ hashes[name] = {
113
+ version: TemplateManager.TEMPLATE_VERSION,
114
+ hash: defaultHash,
115
+ customized: false,
116
+ };
117
+ console.error(` ✓ Created template: _templates/${name}`);
118
+ }
119
+ else {
120
+ // Template exists - check if customized
121
+ const currentContent = await fs.readFile(templatePath, 'utf-8');
122
+ const currentHash = this.calculateHash(currentContent);
123
+ const tracked = hashes[name];
124
+ if (!tracked) {
125
+ // Not tracked yet - assume customized
126
+ hashes[name] = {
127
+ version: TemplateManager.TEMPLATE_VERSION,
128
+ hash: currentHash,
129
+ customized: true,
130
+ };
131
+ }
132
+ else if (currentHash === tracked.hash) {
133
+ // Unchanged from last sync
134
+ if (!tracked.customized && defaultHash !== tracked.hash) {
135
+ // Template was default but we have a new version - update it
136
+ await fs.writeFile(templatePath, defaultContent, 'utf-8');
137
+ hashes[name] = {
138
+ version: TemplateManager.TEMPLATE_VERSION,
139
+ hash: defaultHash,
140
+ customized: false,
141
+ };
142
+ console.error(` ✓ Updated template: _templates/${name} (new version)`);
143
+ }
144
+ }
145
+ else {
146
+ // Hash changed - user customized it
147
+ hashes[name] = {
148
+ ...tracked,
149
+ hash: currentHash,
150
+ customized: true,
151
+ };
152
+ }
153
+ }
154
+ }
155
+ /**
156
+ * Load template hashes from file
157
+ */
158
+ async loadHashes() {
159
+ if (!existsSync(this.hashFile)) {
160
+ return {};
161
+ }
162
+ try {
163
+ const content = await fs.readFile(this.hashFile, 'utf-8');
164
+ return JSON.parse(content);
165
+ }
166
+ catch {
167
+ return {};
168
+ }
169
+ }
170
+ /**
171
+ * Save template hashes to file
172
+ */
173
+ async saveHashes(hashes) {
174
+ await fs.writeFile(this.hashFile, JSON.stringify(hashes, null, 2), 'utf-8');
175
+ }
176
+ /**
177
+ * Calculate SHA-256 hash of content
178
+ */
179
+ calculateHash(content) {
180
+ return crypto.createHash('sha256').update(content).digest('hex');
181
+ }
182
+ /**
183
+ * Get default README template
184
+ */
185
+ getDefaultReadmeTemplate() {
186
+ return `# \${marketplaceName}
187
+
188
+ > **Singular focus. Precise target.**
189
+
190
+ \${$if(marketplaceDescription, \`\${marketplaceDescription}\n\n\`, \`Photons are single-file TypeScript classes that run as [MCP servers](https://modelcontextprotocol.io/introduction). Add them to your favorite AI assistant using the [Photon runtime](https://github.com/portel-dev/photon).\n\n\`)}\${$if(marketplaceName === 'photons', \`## 🏛️ Official Marketplace
191
+
192
+ This is the **official Photon marketplace** maintained by Portel. It comes pre-configured with Photon - no manual setup needed.
193
+
194
+ **Already available to you:**
195
+ - ✅ Pre-installed with Photon
196
+ - ✅ Automatically updated
197
+ - ✅ Production-ready photons
198
+ - ✅ Community-maintained
199
+
200
+ **Want to contribute?**
201
+ We welcome contributions! Submit pull requests for:
202
+ - 🐛 Bug fixes to existing photons
203
+ - ✨ Enhancements and new features
204
+ - 📦 New photons to add to the marketplace
205
+ - 📝 Documentation improvements
206
+
207
+ **Repository:** [github.com/portel-dev/photons](https://github.com/portel-dev/photons)
208
+
209
+ \`, '')}## 📦 Available Photons
210
+
211
+ | Photon | Focus | Tools | Details |
212
+ |--------|-------|-------|---------|
213
+ \${each(photons, (p) => \`| **\${properName(p.description, p.name)}** | \${cleanDesc(p.description)} | \${p.tools ? p.tools.length : 0} | [View →](\${p.name}.md) |\n\`)}
214
+
215
+ **Total:** \${photons.length} photons ready to use
216
+
217
+ ---
218
+
219
+ ## 🚀 Quick Start
220
+
221
+ ### 1. Install Photon
222
+
223
+ \\\`\\\`\\\`bash
224
+ npm install -g @portel/photon
225
+ \\\`\\\`\\\`
226
+
227
+ ### 2. Add Any Photon
228
+
229
+ \\\`\\\`\\\`bash
230
+ photon add filesystem
231
+ photon add git
232
+ photon add aws-s3
233
+ \\\`\\\`\\\`
234
+
235
+ ### 3. Use It
236
+
237
+ \\\`\\\`\\\`bash
238
+ # Run as MCP server
239
+ photon mcp filesystem
240
+
241
+ # Get config for your MCP client
242
+ photon get filesystem --mcp
243
+ \\\`\\\`\\\`
244
+
245
+ Output (paste directly into your MCP client config):
246
+ \\\`\\\`\\\`json
247
+ {
248
+ "mcpServers": {
249
+ "filesystem": {
250
+ "command": "photon",
251
+ "args": ["mcp", "filesystem"]
252
+ }
253
+ }
254
+ }
255
+ \\\`\\\`\\\`
256
+
257
+ Add the output to your MCP client's configuration. **Consult your client's documentation** for setup instructions.
258
+
259
+ **That's it!** Your AI assistant now has \${photons.length} focused tools at its fingertips.
260
+
261
+ ## ⚛️ What Are Photons?
262
+
263
+ **Photons** are laser-focused modules - each does ONE thing exceptionally well:
264
+ - 📁 **Filesystem** - File operations
265
+ - 🐙 **Git** - Repository management
266
+ - ☁️ **AWS S3** - Cloud storage
267
+ - 📅 **Google Calendar** - Calendar integration
268
+ - 🕐 **Time** - Timezone operations
269
+ - ... and more
270
+
271
+ Each photon delivers **singular focus** to a **precise target**.
272
+
273
+ **Key Features:**
274
+ - 🎯 Each photon does one thing perfectly
275
+ - 📦 \${photons.length} production-ready photons available
276
+ - ⚡ Auto-installs dependencies
277
+ - 🔧 Works out of the box
278
+ - 📄 Single-file design (easy to fork and customize)
279
+
280
+ ## 🎯 The Value Proposition
281
+
282
+ ### Before Photon
283
+
284
+ For each MCP server:
285
+ 1. Find and clone the repository
286
+ 2. Install dependencies manually
287
+ 3. Configure environment variables
288
+ 4. Write MCP client config JSON by hand
289
+ 5. Repeat for every server
290
+
291
+ ### With Photon
292
+
293
+ \\\`\\\`\\\`bash
294
+ # Install from marketplace
295
+ photon add filesystem
296
+
297
+ # Get MCP config
298
+ photon get filesystem --mcp
299
+ \\\`\\\`\\\`
300
+
301
+ Output (paste directly into your MCP client config):
302
+ \\\`\\\`\\\`json
303
+ {
304
+ "mcpServers": {
305
+ "filesystem": {
306
+ "command": "photon",
307
+ "args": ["mcp", "filesystem"]
308
+ }
309
+ }
310
+ }
311
+ \\\`\\\`\\\`
312
+
313
+ **That's it.** No dependencies, no environment setup, no configuration files.
314
+
315
+ **Difference:**
316
+ - ✅ One CLI, one command
317
+ - ✅ Zero configuration
318
+ - ✅ Instant installation
319
+ - ✅ Auto-dependencies
320
+ - ✅ Consistent experience
321
+
322
+ ## 💡 Use Cases
323
+
324
+ **For Claude Users:**
325
+ \\\`\\\`\\\`bash
326
+ photon add filesystem git github-issues
327
+ photon get --mcp # Get config for all three
328
+ \\\`\\\`\\\`
329
+ Add to Claude Desktop → Now Claude can read files, manage repos, create issues
330
+
331
+ **For Teams:**
332
+ \\\`\\\`\\\`bash
333
+ photon add postgres mongodb redis
334
+ photon get --mcp
335
+ \\\`\\\`\\\`
336
+ Give Claude access to your data infrastructure
337
+
338
+ **For Developers:**
339
+ \\\`\\\`\\\`bash
340
+ photon add docker git slack
341
+ photon get --mcp
342
+ \\\`\\\`\\\`
343
+ Automate your workflow through AI
344
+
345
+ ## 🔍 Browse & Search
346
+
347
+ \\\`\\\`\\\`bash
348
+ # List all photons
349
+ photon get
350
+
351
+ # Search by keyword
352
+ photon search calendar
353
+
354
+ # View details
355
+ photon get google-calendar
356
+
357
+ # Upgrade all
358
+ photon upgrade
359
+ \\\`\\\`\\\`
360
+
361
+ ## 🏢 For Enterprises
362
+
363
+ Create your own marketplace:
364
+
365
+ \\\`\\\`\\\`bash
366
+ # 1. Organize photons
367
+ mkdir company-photons && cd company-photons
368
+
369
+ # 2. Generate marketplace
370
+ photon sync marketplace
371
+
372
+ # 3. Share with team
373
+ git push origin main
374
+
375
+ # Team members use:
376
+ photon marketplace add company/photons
377
+ photon add your-internal-tool
378
+ \\\`\\\`\\\`
379
+
380
+ ---
381
+
382
+ **Built with singular focus. Deployed with precise targeting.**
383
+
384
+ Made with ⚛️ by [Portel](https://github.com/portel-dev)
385
+ `;
386
+ }
387
+ /**
388
+ * Get default Photon documentation template
389
+ */
390
+ getDefaultPhotonTemplate() {
391
+ return `# \${properName(description, name)}
392
+
393
+ \${cleanDesc(description)}
394
+
395
+ ## 📋 Overview
396
+
397
+ **Version:** \${version}
398
+ **Author:** \${author || 'Unknown'}
399
+ **License:** \${license || 'MIT'}\${$if(repository, \` \n**Repository:** \${repository}\`, '')}\${$if(homepage, \` \n**Homepage:** \${homepage}\`, '')}
400
+
401
+ ## ⚙️ Configuration
402
+
403
+ ### Environment Variables
404
+
405
+ \${each(configParams || [], (param) => \`
406
+ - **\\\`\${param.envVar}\\\`** \${param.required ? '[REQUIRED]' : '[OPTIONAL]'}
407
+ - Type: \${param.type}
408
+ - Description: \${param.description}
409
+ \${param.default ? \`- Default: \\\`\${param.default}\\\`\` : ''}
410
+ \`)}
411
+
412
+ \${$if(!configParams || configParams.length === 0, \`
413
+ No configuration required.
414
+ \`)}
415
+
416
+ \${$if(setupInstructions, \`
417
+ ### Setup Instructions
418
+
419
+ \${setupInstructions}
420
+ \`)}
421
+
422
+ ## 🔧 Tools
423
+
424
+ This photon provides **\${tools ? tools.length : 0}** tools:
425
+
426
+ \${each(tools || [], (tool) => \`
427
+ ### \\\`\${tool.name}\\\`
428
+
429
+ \${tool.description || 'No description available'}
430
+
431
+ \${$if(tool.params && tool.params.length > 0, \`
432
+ **Parameters:**
433
+
434
+ \${each(tool.params, (p) => \`
435
+ - **\\\`\${p.name}\\\`** (\${p.type}\${p.optional ? ', optional' : ''}) - \${p.description || 'No description'}
436
+ \`)}
437
+ \`)}
438
+
439
+ \${$if(tool.example, \`
440
+ **Example:**
441
+
442
+ \\\`\\\`\\\`typescript
443
+ \${tool.example}
444
+ \\\`\\\`\\\`
445
+ \`)}
446
+
447
+ ---
448
+
449
+ \`)}
450
+
451
+ \${$if(!tools || tools.length === 0, \`
452
+ No tools defined.
453
+ \`)}
454
+
455
+ ## 📥 Usage
456
+
457
+ ### Install Photon CLI
458
+
459
+ \\\`\\\`\\\`bash
460
+ npm install -g @portel/photon
461
+ \\\`\\\`\\\`
462
+
463
+ ### Run This Photon
464
+
465
+ **Option 1: Run directly from file**
466
+
467
+ \\\`\\\`\\\`bash
468
+ # Clone/download the photon file
469
+ photon mcp ./\${name}.photon.ts
470
+ \\\`\\\`\\\`
471
+
472
+ **Option 2: Install to ~/.photon/ (recommended)**
473
+
474
+ \\\`\\\`\\\`bash
475
+ # Copy to photon directory
476
+ cp \${name}.photon.ts ~/.photon/
477
+
478
+ # Run by name
479
+ photon mcp \${name}
480
+ \\\`\\\`\\\`
481
+
482
+ **Option 3: Use with Claude Desktop**
483
+
484
+ \\\`\\\`\\\`bash
485
+ # Generate MCP configuration
486
+ photon mcp \${name} --config
487
+
488
+ # Add the output to ~/Library/Application Support/Claude/claude_desktop_config.json
489
+ \\\`\\\`\\\`
490
+
491
+ ## 📦 Dependencies
492
+
493
+ \${$if(dependencies, \`
494
+ This photon automatically installs the following dependencies:
495
+
496
+ \\\`\\\`\\\`
497
+ \${dependencies}
498
+ \\\`\\\`\\\`
499
+ \`, \`
500
+ No external dependencies required.
501
+ \`)}
502
+
503
+ ## 📄 License
504
+
505
+ \${license || 'MIT'} • Version \${version}
506
+ `;
507
+ }
508
+ }
509
+ //# sourceMappingURL=template-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-manager.js","sourceRoot":"","sources":["../src/template-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Test Client - Automated testing for Photon MCPs
4
+ *
5
+ * Spawns MCP servers, sends protocol messages, validates responses
6
+ */
7
+ interface MCPResponse {
8
+ jsonrpc: '2.0';
9
+ id: number | string;
10
+ result?: any;
11
+ error?: {
12
+ code: number;
13
+ message: string;
14
+ data?: any;
15
+ };
16
+ }
17
+ interface TestCase {
18
+ name: string;
19
+ method: string;
20
+ params?: any;
21
+ validate: (response: MCPResponse) => boolean | string;
22
+ }
23
+ export declare class MCPTestClient {
24
+ private process?;
25
+ private requestId;
26
+ private pendingRequests;
27
+ start(command: string, args: string[], env?: Record<string, string>): Promise<void>;
28
+ send(method: string, params?: any): Promise<MCPResponse>;
29
+ initialize(serverInfo?: {
30
+ name: string;
31
+ version: string;
32
+ }): Promise<MCPResponse>;
33
+ listTools(): Promise<MCPResponse>;
34
+ callTool(name: string, args?: any): Promise<MCPResponse>;
35
+ runTests(tests: TestCase[]): Promise<{
36
+ passed: number;
37
+ failed: number;
38
+ errors: string[];
39
+ }>;
40
+ shutdown(): Promise<void>;
41
+ }
42
+ export declare const validators: {
43
+ hasResult: (response: MCPResponse) => true | "Response missing result field";
44
+ hasError: (response: MCPResponse) => true | "Response missing error field";
45
+ matchesPattern: (pattern: RegExp, field?: string) => (response: MCPResponse) => string | true;
46
+ hasField: (field: string) => (response: MCPResponse) => string | true;
47
+ equals: (expected: any, field?: string) => (response: MCPResponse) => string | true;
48
+ custom: (fn: (result: any) => boolean | string) => (response: MCPResponse) => string | boolean;
49
+ and: (...validators: Array<(response: MCPResponse) => boolean | string>) => (response: MCPResponse) => string | boolean;
50
+ };
51
+ export {};
52
+ //# sourceMappingURL=test-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-client.d.ts","sourceRoot":"","sources":["../src/test-client.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAYH,UAAU,WAAW;IACnB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,GAAG,CAAC;KACZ,CAAC;CACH;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,QAAQ,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,OAAO,GAAG,MAAM,CAAC;CACvD;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAC,CAAe;IAC/B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,eAAe,CAGlB;IAEC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDnF,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;IA4BxD,UAAU,CAAC,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAQhF,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC;IAIjC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;IAIxD,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA8B1F,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAOhC;AAGD,eAAO,MAAM,UAAU;0BACC,WAAW;yBAGZ,WAAW;8BAGN,MAAM,UAAU,MAAM,MAAM,UAAU,WAAW;sBAOzD,MAAM,MAAM,UAAU,WAAW;uBAYhC,GAAG,UAAU,MAAM,MAAM,UAAU,WAAW;iBAMpD,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,GAAG,MAAM,MAAM,UAAU,WAAW;yBAIpD,KAAK,CAAC,CAAC,QAAQ,EAAE,WAAW,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,UAAU,WAAW;CAOnG,CAAC"}