@proxygate/cli 0.1.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 (249) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +311 -0
  3. package/dist/commands/apis.d.ts +3 -0
  4. package/dist/commands/apis.d.ts.map +1 -0
  5. package/dist/commands/apis.js +68 -0
  6. package/dist/commands/apis.js.map +1 -0
  7. package/dist/commands/apis.test.d.ts +2 -0
  8. package/dist/commands/apis.test.d.ts.map +1 -0
  9. package/dist/commands/apis.test.js +103 -0
  10. package/dist/commands/apis.test.js.map +1 -0
  11. package/dist/commands/balance.d.ts +9 -0
  12. package/dist/commands/balance.d.ts.map +1 -0
  13. package/dist/commands/balance.js +50 -0
  14. package/dist/commands/balance.js.map +1 -0
  15. package/dist/commands/balance.test.d.ts +2 -0
  16. package/dist/commands/balance.test.d.ts.map +1 -0
  17. package/dist/commands/balance.test.js +106 -0
  18. package/dist/commands/balance.test.js.map +1 -0
  19. package/dist/commands/categories.d.ts +3 -0
  20. package/dist/commands/categories.d.ts.map +1 -0
  21. package/dist/commands/categories.js +45 -0
  22. package/dist/commands/categories.js.map +1 -0
  23. package/dist/commands/categories.test.d.ts +2 -0
  24. package/dist/commands/categories.test.d.ts.map +1 -0
  25. package/dist/commands/categories.test.js +84 -0
  26. package/dist/commands/categories.test.js.map +1 -0
  27. package/dist/commands/create.d.ts +3 -0
  28. package/dist/commands/create.d.ts.map +1 -0
  29. package/dist/commands/create.js +136 -0
  30. package/dist/commands/create.js.map +1 -0
  31. package/dist/commands/create.test.d.ts +2 -0
  32. package/dist/commands/create.test.d.ts.map +1 -0
  33. package/dist/commands/create.test.js +95 -0
  34. package/dist/commands/create.test.js.map +1 -0
  35. package/dist/commands/deposit.d.ts +9 -0
  36. package/dist/commands/deposit.d.ts.map +1 -0
  37. package/dist/commands/deposit.js +78 -0
  38. package/dist/commands/deposit.js.map +1 -0
  39. package/dist/commands/deposit.test.d.ts +2 -0
  40. package/dist/commands/deposit.test.d.ts.map +1 -0
  41. package/dist/commands/deposit.test.js +93 -0
  42. package/dist/commands/deposit.test.js.map +1 -0
  43. package/dist/commands/dev.d.ts +3 -0
  44. package/dist/commands/dev.d.ts.map +1 -0
  45. package/dist/commands/dev.js +188 -0
  46. package/dist/commands/dev.js.map +1 -0
  47. package/dist/commands/dev.test.d.ts +2 -0
  48. package/dist/commands/dev.test.d.ts.map +1 -0
  49. package/dist/commands/dev.test.js +89 -0
  50. package/dist/commands/dev.test.js.map +1 -0
  51. package/dist/commands/getting-started-steps.d.ts +12 -0
  52. package/dist/commands/getting-started-steps.d.ts.map +1 -0
  53. package/dist/commands/getting-started-steps.js +163 -0
  54. package/dist/commands/getting-started-steps.js.map +1 -0
  55. package/dist/commands/getting-started.d.ts +9 -0
  56. package/dist/commands/getting-started.d.ts.map +1 -0
  57. package/dist/commands/getting-started.js +44 -0
  58. package/dist/commands/getting-started.js.map +1 -0
  59. package/dist/commands/init.d.ts +9 -0
  60. package/dist/commands/init.d.ts.map +1 -0
  61. package/dist/commands/init.js +74 -0
  62. package/dist/commands/init.js.map +1 -0
  63. package/dist/commands/init.test.d.ts +2 -0
  64. package/dist/commands/init.test.d.ts.map +1 -0
  65. package/dist/commands/init.test.js +115 -0
  66. package/dist/commands/init.test.js.map +1 -0
  67. package/dist/commands/jobs.d.ts +11 -0
  68. package/dist/commands/jobs.d.ts.map +1 -0
  69. package/dist/commands/jobs.js +370 -0
  70. package/dist/commands/jobs.js.map +1 -0
  71. package/dist/commands/listings/create.d.ts +4 -0
  72. package/dist/commands/listings/create.d.ts.map +1 -0
  73. package/dist/commands/listings/create.js +133 -0
  74. package/dist/commands/listings/create.js.map +1 -0
  75. package/dist/commands/listings/delete.d.ts +4 -0
  76. package/dist/commands/listings/delete.d.ts.map +1 -0
  77. package/dist/commands/listings/delete.js +32 -0
  78. package/dist/commands/listings/delete.js.map +1 -0
  79. package/dist/commands/listings/docs.d.ts +4 -0
  80. package/dist/commands/listings/docs.d.ts.map +1 -0
  81. package/dist/commands/listings/docs.js +48 -0
  82. package/dist/commands/listings/docs.js.map +1 -0
  83. package/dist/commands/listings/headers.d.ts +4 -0
  84. package/dist/commands/listings/headers.d.ts.map +1 -0
  85. package/dist/commands/listings/headers.js +78 -0
  86. package/dist/commands/listings/headers.js.map +1 -0
  87. package/dist/commands/listings/helpers.d.ts +10 -0
  88. package/dist/commands/listings/helpers.d.ts.map +1 -0
  89. package/dist/commands/listings/helpers.js +64 -0
  90. package/dist/commands/listings/helpers.js.map +1 -0
  91. package/dist/commands/listings/index.d.ts +11 -0
  92. package/dist/commands/listings/index.d.ts.map +1 -0
  93. package/dist/commands/listings/index.js +46 -0
  94. package/dist/commands/listings/index.js.map +1 -0
  95. package/dist/commands/listings/list.d.ts +4 -0
  96. package/dist/commands/listings/list.d.ts.map +1 -0
  97. package/dist/commands/listings/list.js +42 -0
  98. package/dist/commands/listings/list.js.map +1 -0
  99. package/dist/commands/listings/pause-unpause.d.ts +6 -0
  100. package/dist/commands/listings/pause-unpause.d.ts.map +1 -0
  101. package/dist/commands/listings/pause-unpause.js +37 -0
  102. package/dist/commands/listings/pause-unpause.js.map +1 -0
  103. package/dist/commands/listings/rotate-key.d.ts +4 -0
  104. package/dist/commands/listings/rotate-key.d.ts.map +1 -0
  105. package/dist/commands/listings/rotate-key.js +62 -0
  106. package/dist/commands/listings/rotate-key.js.map +1 -0
  107. package/dist/commands/listings/update.d.ts +4 -0
  108. package/dist/commands/listings/update.d.ts.map +1 -0
  109. package/dist/commands/listings/update.js +57 -0
  110. package/dist/commands/listings/update.js.map +1 -0
  111. package/dist/commands/listings.d.ts +2 -0
  112. package/dist/commands/listings.d.ts.map +1 -0
  113. package/dist/commands/listings.js +3 -0
  114. package/dist/commands/listings.js.map +1 -0
  115. package/dist/commands/listings.test.d.ts +2 -0
  116. package/dist/commands/listings.test.d.ts.map +1 -0
  117. package/dist/commands/listings.test.js +166 -0
  118. package/dist/commands/listings.test.js.map +1 -0
  119. package/dist/commands/pricing.d.ts +9 -0
  120. package/dist/commands/pricing.d.ts.map +1 -0
  121. package/dist/commands/pricing.js +67 -0
  122. package/dist/commands/pricing.js.map +1 -0
  123. package/dist/commands/pricing.test.d.ts +2 -0
  124. package/dist/commands/pricing.test.d.ts.map +1 -0
  125. package/dist/commands/pricing.test.js +87 -0
  126. package/dist/commands/pricing.test.js.map +1 -0
  127. package/dist/commands/proxy.d.ts +14 -0
  128. package/dist/commands/proxy.d.ts.map +1 -0
  129. package/dist/commands/proxy.js +138 -0
  130. package/dist/commands/proxy.js.map +1 -0
  131. package/dist/commands/proxy.test.d.ts +2 -0
  132. package/dist/commands/proxy.test.d.ts.map +1 -0
  133. package/dist/commands/proxy.test.js +235 -0
  134. package/dist/commands/proxy.test.js.map +1 -0
  135. package/dist/commands/rate.d.ts +3 -0
  136. package/dist/commands/rate.d.ts.map +1 -0
  137. package/dist/commands/rate.js +46 -0
  138. package/dist/commands/rate.js.map +1 -0
  139. package/dist/commands/rate.test.d.ts +2 -0
  140. package/dist/commands/rate.test.d.ts.map +1 -0
  141. package/dist/commands/rate.test.js +74 -0
  142. package/dist/commands/rate.test.js.map +1 -0
  143. package/dist/commands/services.d.ts +3 -0
  144. package/dist/commands/services.d.ts.map +1 -0
  145. package/dist/commands/services.js +48 -0
  146. package/dist/commands/services.js.map +1 -0
  147. package/dist/commands/services.test.d.ts +2 -0
  148. package/dist/commands/services.test.d.ts.map +1 -0
  149. package/dist/commands/services.test.js +87 -0
  150. package/dist/commands/services.test.js.map +1 -0
  151. package/dist/commands/settlements.d.ts +3 -0
  152. package/dist/commands/settlements.d.ts.map +1 -0
  153. package/dist/commands/settlements.js +79 -0
  154. package/dist/commands/settlements.js.map +1 -0
  155. package/dist/commands/settlements.test.d.ts +2 -0
  156. package/dist/commands/settlements.test.d.ts.map +1 -0
  157. package/dist/commands/settlements.test.js +98 -0
  158. package/dist/commands/settlements.test.js.map +1 -0
  159. package/dist/commands/skills.d.ts +3 -0
  160. package/dist/commands/skills.d.ts.map +1 -0
  161. package/dist/commands/skills.js +96 -0
  162. package/dist/commands/skills.js.map +1 -0
  163. package/dist/commands/skills.test.d.ts +2 -0
  164. package/dist/commands/skills.test.d.ts.map +1 -0
  165. package/dist/commands/skills.test.js +89 -0
  166. package/dist/commands/skills.test.js.map +1 -0
  167. package/dist/commands/test-service.d.ts +3 -0
  168. package/dist/commands/test-service.d.ts.map +1 -0
  169. package/dist/commands/test-service.js +200 -0
  170. package/dist/commands/test-service.js.map +1 -0
  171. package/dist/commands/test-service.test.d.ts +2 -0
  172. package/dist/commands/test-service.test.d.ts.map +1 -0
  173. package/dist/commands/test-service.test.js +119 -0
  174. package/dist/commands/test-service.test.js.map +1 -0
  175. package/dist/commands/tunnel-handlers.d.ts +19 -0
  176. package/dist/commands/tunnel-handlers.d.ts.map +1 -0
  177. package/dist/commands/tunnel-handlers.js +103 -0
  178. package/dist/commands/tunnel-handlers.js.map +1 -0
  179. package/dist/commands/tunnel.d.ts +7 -0
  180. package/dist/commands/tunnel.d.ts.map +1 -0
  181. package/dist/commands/tunnel.js +184 -0
  182. package/dist/commands/tunnel.js.map +1 -0
  183. package/dist/commands/usage.d.ts +9 -0
  184. package/dist/commands/usage.d.ts.map +1 -0
  185. package/dist/commands/usage.js +78 -0
  186. package/dist/commands/usage.js.map +1 -0
  187. package/dist/commands/usage.test.d.ts +2 -0
  188. package/dist/commands/usage.test.d.ts.map +1 -0
  189. package/dist/commands/usage.test.js +102 -0
  190. package/dist/commands/usage.test.js.map +1 -0
  191. package/dist/commands/withdraw-confirm.d.ts +10 -0
  192. package/dist/commands/withdraw-confirm.d.ts.map +1 -0
  193. package/dist/commands/withdraw-confirm.js +51 -0
  194. package/dist/commands/withdraw-confirm.js.map +1 -0
  195. package/dist/commands/withdraw-confirm.test.d.ts +2 -0
  196. package/dist/commands/withdraw-confirm.test.d.ts.map +1 -0
  197. package/dist/commands/withdraw-confirm.test.js +75 -0
  198. package/dist/commands/withdraw-confirm.test.js.map +1 -0
  199. package/dist/commands/withdraw.d.ts +9 -0
  200. package/dist/commands/withdraw.d.ts.map +1 -0
  201. package/dist/commands/withdraw.js +78 -0
  202. package/dist/commands/withdraw.js.map +1 -0
  203. package/dist/commands/withdraw.test.d.ts +2 -0
  204. package/dist/commands/withdraw.test.d.ts.map +1 -0
  205. package/dist/commands/withdraw.test.js +96 -0
  206. package/dist/commands/withdraw.test.js.map +1 -0
  207. package/dist/config.d.ts +20 -0
  208. package/dist/config.d.ts.map +1 -0
  209. package/dist/config.js +38 -0
  210. package/dist/config.js.map +1 -0
  211. package/dist/config.test.d.ts +2 -0
  212. package/dist/config.test.d.ts.map +1 -0
  213. package/dist/config.test.js +54 -0
  214. package/dist/config.test.js.map +1 -0
  215. package/dist/format.d.ts +46 -0
  216. package/dist/format.d.ts.map +1 -0
  217. package/dist/format.js +101 -0
  218. package/dist/format.js.map +1 -0
  219. package/dist/format.test.d.ts +2 -0
  220. package/dist/format.test.d.ts.map +1 -0
  221. package/dist/format.test.js +85 -0
  222. package/dist/format.test.js.map +1 -0
  223. package/dist/generated/skills.d.ts +2 -0
  224. package/dist/generated/skills.d.ts.map +1 -0
  225. package/dist/generated/skills.js +23 -0
  226. package/dist/generated/skills.js.map +1 -0
  227. package/dist/helpers.d.ts +12 -0
  228. package/dist/helpers.d.ts.map +1 -0
  229. package/dist/helpers.js +21 -0
  230. package/dist/helpers.js.map +1 -0
  231. package/dist/helpers.test.d.ts +2 -0
  232. package/dist/helpers.test.d.ts.map +1 -0
  233. package/dist/helpers.test.js +59 -0
  234. package/dist/helpers.test.js.map +1 -0
  235. package/dist/index.d.ts +3 -0
  236. package/dist/index.d.ts.map +1 -0
  237. package/dist/index.js +70 -0
  238. package/dist/index.js.map +1 -0
  239. package/package.json +61 -0
  240. package/templates/http-api/README.md +20 -0
  241. package/templates/http-api/package.json +21 -0
  242. package/templates/http-api/proxygate.tunnel.yaml +9 -0
  243. package/templates/http-api/src/index.ts +77 -0
  244. package/templates/http-api/tsconfig.json +14 -0
  245. package/templates/llm-agent/README.md +23 -0
  246. package/templates/llm-agent/package.json +22 -0
  247. package/templates/llm-agent/proxygate.tunnel.yaml +13 -0
  248. package/templates/llm-agent/src/index.ts +142 -0
  249. package/templates/llm-agent/tsconfig.json +14 -0
@@ -0,0 +1,235 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { Command } from 'commander';
3
+ import { registerProxyCommand } from './proxy.js';
4
+ const mockProxy = vi.fn();
5
+ vi.mock('@proxygate/sdk', () => ({
6
+ ProxyGateClient: {
7
+ create: vi.fn().mockResolvedValue({
8
+ proxy: (...args) => mockProxy(...args),
9
+ }),
10
+ },
11
+ ProxyGateError: class ProxyGateError extends Error {
12
+ code;
13
+ action;
14
+ constructor(gatewayError, _statusCode) {
15
+ super(gatewayError.message);
16
+ this.code = gatewayError.error;
17
+ this.action = gatewayError.action;
18
+ }
19
+ },
20
+ parseSSE: vi.fn(),
21
+ parseShieldInfo: vi.fn().mockReturnValue(null),
22
+ }));
23
+ vi.mock('../config.js', () => ({
24
+ loadConfig: vi.fn().mockResolvedValue({
25
+ gatewayUrl: 'http://localhost:3001',
26
+ keypairPath: '/tmp/test-key.json',
27
+ }),
28
+ }));
29
+ describe('proxy command', () => {
30
+ let logSpy;
31
+ let errorSpy;
32
+ let stdoutSpy;
33
+ beforeEach(() => {
34
+ vi.clearAllMocks();
35
+ logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
36
+ errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
37
+ stdoutSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
38
+ });
39
+ afterEach(() => {
40
+ vi.restoreAllMocks();
41
+ });
42
+ const runProxy = async (...args) => {
43
+ const program = new Command('proxygate');
44
+ program
45
+ .option('--gateway <url>', 'Override gateway URL')
46
+ .option('--keypair <path>', 'Override keypair path')
47
+ .option('--json', 'Output raw JSON');
48
+ registerProxyCommand(program);
49
+ await program.parseAsync(['node', 'proxygate', 'proxy', ...args]);
50
+ };
51
+ it('sends a basic GET request when no --data is provided', async () => {
52
+ mockProxy.mockResolvedValue(new Response(JSON.stringify({ result: 'ok' }), {
53
+ status: 200,
54
+ headers: { 'Content-Type': 'application/json' },
55
+ }));
56
+ await runProxy('abc-123', '/v1/models');
57
+ expect(mockProxy).toHaveBeenCalledWith('abc-123', '/v1/models', undefined, {
58
+ method: 'GET',
59
+ shield: undefined,
60
+ });
61
+ });
62
+ it('sends POST with parsed JSON body when --data is provided', async () => {
63
+ const body = { model: 'gpt-4', messages: [{ role: 'user', content: 'hi' }] };
64
+ mockProxy.mockResolvedValue(new Response(JSON.stringify({ id: 'chatcmpl-1' }), {
65
+ status: 200,
66
+ headers: { 'Content-Type': 'application/json' },
67
+ }));
68
+ await runProxy('abc-123', '/v1/chat/completions', '-d', JSON.stringify(body));
69
+ expect(mockProxy).toHaveBeenCalledWith('abc-123', '/v1/chat/completions', body, {
70
+ method: 'POST',
71
+ shield: undefined,
72
+ });
73
+ });
74
+ it('uses explicit method override with -X flag', async () => {
75
+ mockProxy.mockResolvedValue(new Response(JSON.stringify({ updated: true }), {
76
+ status: 200,
77
+ headers: { 'Content-Type': 'application/json' },
78
+ }));
79
+ await runProxy('abc-123', '/v1/resource', '-d', '{"key":"val"}', '-X', 'PUT');
80
+ expect(mockProxy).toHaveBeenCalledWith('abc-123', '/v1/resource', { key: 'val' }, { method: 'PUT', shield: undefined });
81
+ });
82
+ it('exits with error for invalid JSON in --data', async () => {
83
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
84
+ throw new Error('process.exit');
85
+ });
86
+ await expect(runProxy('abc-123', '/v1/models', '-d', 'not-json')).rejects.toThrow('process.exit');
87
+ const errOutput = errorSpy.mock.calls
88
+ .map((c) => c[0])
89
+ .join('\n');
90
+ expect(errOutput).toContain('Invalid JSON');
91
+ mockExit.mockRestore();
92
+ });
93
+ it('outputs pretty-printed JSON for JSON responses', async () => {
94
+ const payload = { id: 'chatcmpl-1', choices: [{ text: 'Hello' }] };
95
+ mockProxy.mockResolvedValue(new Response(JSON.stringify(payload), {
96
+ status: 200,
97
+ headers: { 'Content-Type': 'application/json' },
98
+ }));
99
+ await runProxy('abc-123', '/v1/chat/completions');
100
+ expect(logSpy).toHaveBeenCalledWith(JSON.stringify(payload, null, 2));
101
+ });
102
+ it('outputs plain text for non-JSON responses', async () => {
103
+ mockProxy.mockResolvedValue(new Response('plain text response', {
104
+ status: 200,
105
+ headers: { 'Content-Type': 'text/plain' },
106
+ }));
107
+ await runProxy('abc-123', '/v1/health');
108
+ expect(logSpy).toHaveBeenCalledWith('plain text response');
109
+ });
110
+ it('prints status to stderr for non-200 responses', async () => {
111
+ mockProxy.mockResolvedValue(new Response(JSON.stringify({ error: 'not found' }), {
112
+ status: 404,
113
+ headers: { 'Content-Type': 'application/json' },
114
+ }));
115
+ await runProxy('abc-123', '/v1/missing');
116
+ const errOutput = errorSpy.mock.calls
117
+ .map((c) => c[0])
118
+ .join('\n');
119
+ expect(errOutput).toContain('Status: 404');
120
+ });
121
+ it('catches ProxyGateError and formats error with code and action', async () => {
122
+ const { ProxyGateError } = await import('@proxygate/sdk');
123
+ mockProxy.mockRejectedValue(new ProxyGateError({ error: 'CREDITS_EXHAUSTED', message: 'Insufficient credits', action: 'Deposit more USDC' }, 402));
124
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
125
+ throw new Error('process.exit');
126
+ });
127
+ await expect(runProxy('abc-123', '/v1/chat/completions')).rejects.toThrow('process.exit');
128
+ const errOutput = errorSpy.mock.calls
129
+ .map((c) => c[0])
130
+ .join('\n');
131
+ expect(errOutput).toContain('CREDITS_EXHAUSTED');
132
+ expect(errOutput).toContain('Insufficient credits');
133
+ expect(errOutput).toContain('Deposit more USDC');
134
+ mockExit.mockRestore();
135
+ });
136
+ it('streams SSE events with --stream flag', async () => {
137
+ const { parseSSE } = await import('@proxygate/sdk');
138
+ const events = [{ data: '{"chunk":1}' }, { data: '{"chunk":2}' }, { data: '[DONE]' }];
139
+ mockProxy.mockResolvedValue(new Response('stream body', {
140
+ status: 200,
141
+ headers: { 'Content-Type': 'text/event-stream' },
142
+ }));
143
+ vi.mocked(parseSSE).mockReturnValue((async function* () {
144
+ for (const e of events) {
145
+ yield e;
146
+ }
147
+ })());
148
+ await runProxy('abc-123', '/v1/chat/completions', '-d', '{"model":"gpt-4"}', '--stream');
149
+ // Should write chunk 1 and chunk 2 but stop at [DONE]
150
+ expect(stdoutSpy).toHaveBeenCalledWith('{"chunk":1}\n');
151
+ expect(stdoutSpy).toHaveBeenCalledWith('{"chunk":2}\n');
152
+ // [DONE] should NOT be written
153
+ expect(stdoutSpy).not.toHaveBeenCalledWith('[DONE]\n');
154
+ });
155
+ it('passes --shield mode to proxy options', async () => {
156
+ mockProxy.mockResolvedValue(new Response(JSON.stringify({ result: 'ok' }), {
157
+ status: 200,
158
+ headers: { 'Content-Type': 'application/json' },
159
+ }));
160
+ await runProxy('abc-123', '/v1/models', '--shield', 'strict');
161
+ expect(mockProxy).toHaveBeenCalledWith('abc-123', '/v1/models', undefined, {
162
+ method: 'GET',
163
+ shield: 'strict',
164
+ });
165
+ });
166
+ it('exits with error for invalid shield mode', async () => {
167
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
168
+ throw new Error('process.exit');
169
+ });
170
+ await expect(runProxy('abc-123', '/v1/models', '--shield', 'invalid')).rejects.toThrow('process.exit');
171
+ const errOutput = errorSpy.mock.calls
172
+ .map((c) => c[0])
173
+ .join('\n');
174
+ expect(errOutput).toContain('Invalid shield mode');
175
+ mockExit.mockRestore();
176
+ });
177
+ it('handles shield blocked response (422)', async () => {
178
+ mockProxy.mockResolvedValue(new Response(JSON.stringify({
179
+ error: 'response_blocked',
180
+ code: 'shield_blocked',
181
+ shield_score: 0.89,
182
+ shield_flags: ['pi_and_jailbreak', 'malicious_uris'],
183
+ refunded: true,
184
+ message: 'Response blocked by Shield',
185
+ }), { status: 422, headers: { 'Content-Type': 'application/json' } }));
186
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
187
+ throw new Error('process.exit');
188
+ });
189
+ await expect(runProxy('abc-123', '/v1/chat/completions', '--shield', 'strict')).rejects.toThrow('process.exit');
190
+ const errOutput = errorSpy.mock.calls
191
+ .map((c) => c[0])
192
+ .join('\n');
193
+ expect(errOutput).toContain('Shield blocked');
194
+ expect(errOutput).toContain('0.89');
195
+ expect(errOutput).toContain('Credits refunded');
196
+ mockExit.mockRestore();
197
+ });
198
+ it('displays shield info from response headers', async () => {
199
+ const { parseShieldInfo } = await import('@proxygate/sdk');
200
+ vi.mocked(parseShieldInfo).mockReturnValue({
201
+ mode: 'monitored',
202
+ score: 0.12,
203
+ flags: 'none',
204
+ });
205
+ mockProxy.mockResolvedValue(new Response(JSON.stringify({ result: 'ok' }), {
206
+ status: 200,
207
+ headers: {
208
+ 'Content-Type': 'application/json',
209
+ 'X-ProxyGate-Shield': 'monitored',
210
+ 'X-ProxyGate-Shield-Score': '0.12',
211
+ 'X-ProxyGate-Shield-Flags': 'none',
212
+ },
213
+ }));
214
+ await runProxy('abc-123', '/v1/models', '--shield', 'monitor');
215
+ const errOutput = errorSpy.mock.calls
216
+ .map((c) => c[0])
217
+ .join('\n');
218
+ expect(errOutput).toContain('Shield: monitored');
219
+ });
220
+ it('exits with error when streaming with no response body', async () => {
221
+ mockProxy.mockResolvedValue(new Response(null, {
222
+ status: 200,
223
+ }));
224
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
225
+ throw new Error('process.exit');
226
+ });
227
+ await expect(runProxy('abc-123', '/v1/chat/completions', '--stream')).rejects.toThrow('process.exit');
228
+ const errOutput = errorSpy.mock.calls
229
+ .map((c) => c[0])
230
+ .join('\n');
231
+ expect(errOutput).toContain('No response body');
232
+ mockExit.mockRestore();
233
+ });
234
+ });
235
+ //# sourceMappingURL=proxy.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.test.js","sourceRoot":"","sources":["../../src/commands/proxy.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerRateCommand(program: Command): void;
3
+ //# sourceMappingURL=rate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate.d.ts","sourceRoot":"","sources":["../../src/commands/rate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8C1D"}
@@ -0,0 +1,46 @@
1
+ import { ProxyGateError } from '@proxygate/sdk';
2
+ import { getClient } from '../helpers.js';
3
+ import { bold, green, red, dim } from '../format.js';
4
+ export function registerRateCommand(program) {
5
+ program
6
+ .command('rate')
7
+ .description('Rate a seller after a proxy request')
8
+ .requiredOption('--request-id <id>', 'Request ID from the proxy response receipt')
9
+ .option('--up', 'Positive rating (thumbs up)')
10
+ .option('--down', 'Negative rating (thumbs down)')
11
+ .addHelpText('after', '\nExamples:\n' +
12
+ ' $ proxygate rate --request-id abc-123 --up\n' +
13
+ ' $ proxygate rate --request-id abc-123 --down')
14
+ .action(async (opts) => {
15
+ const parentOpts = program.opts();
16
+ try {
17
+ if (!opts.up && !opts.down) {
18
+ console.error(red('Error: specify --up or --down'));
19
+ process.exit(1);
20
+ }
21
+ const client = await getClient(parentOpts);
22
+ const result = await client.rate({
23
+ request_id: opts.requestId,
24
+ is_positive: !!opts.up,
25
+ });
26
+ if (parentOpts.json) {
27
+ console.log(JSON.stringify(result, null, 2));
28
+ return;
29
+ }
30
+ console.log(bold('Rating Submitted'));
31
+ console.log();
32
+ console.log(` ${green('Status:')} ${result.status}`);
33
+ console.log(` ${dim('Message:')} ${result.message}`);
34
+ }
35
+ catch (err) {
36
+ if (err instanceof ProxyGateError) {
37
+ console.error(red(`Error [${err.code}]: ${err.message}`));
38
+ if (err.action)
39
+ console.error(dim(`Suggestion: ${err.action}`));
40
+ process.exit(1);
41
+ }
42
+ throw err;
43
+ }
44
+ });
45
+ }
46
+ //# sourceMappingURL=rate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate.js","sourceRoot":"","sources":["../../src/commands/rate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,qCAAqC,CAAC;SAClD,cAAc,CAAC,mBAAmB,EAAE,4CAA4C,CAAC;SACjF,MAAM,CAAC,MAAM,EAAE,6BAA6B,CAAC;SAC7C,MAAM,CAAC,QAAQ,EAAE,+BAA+B,CAAC;SACjD,WAAW,CACV,OAAO,EACP,eAAe;QACb,gDAAgD;QAChD,gDAAgD,CACnD;SACA,MAAM,CAAC,KAAK,EAAE,IAAyD,EAAE,EAAE;QAC1E,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAA0D,CAAC;QAE1F,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC3B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;gBACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;gBAC/B,UAAU,EAAE,IAAI,CAAC,SAAS;gBAC1B,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE;aACvB,CAAC,CAAC;YAEH,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7C,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACtC,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;gBAClC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBAC1D,IAAI,GAAG,CAAC,MAAM;oBAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate.test.d.ts","sourceRoot":"","sources":["../../src/commands/rate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { Command } from 'commander';
3
+ import { registerRateCommand } from './rate.js';
4
+ const mockRate = vi.fn();
5
+ vi.mock('@proxygate/sdk', () => ({
6
+ ProxyGateClient: {
7
+ create: vi.fn().mockResolvedValue({
8
+ rate: (...args) => mockRate(...args),
9
+ }),
10
+ },
11
+ ProxyGateError: class extends Error {
12
+ code;
13
+ action;
14
+ constructor(msg, code) {
15
+ super(msg);
16
+ this.code = code;
17
+ }
18
+ },
19
+ }));
20
+ vi.mock('../config.js', () => ({
21
+ loadConfig: vi.fn().mockResolvedValue({
22
+ gatewayUrl: 'http://localhost:3001',
23
+ keypairPath: '/tmp/key.json',
24
+ }),
25
+ }));
26
+ describe('rate command', () => {
27
+ let logSpy;
28
+ beforeEach(() => {
29
+ vi.clearAllMocks();
30
+ logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
31
+ vi.spyOn(console, 'error').mockImplementation(() => { });
32
+ });
33
+ afterEach(() => {
34
+ vi.restoreAllMocks();
35
+ });
36
+ const run = async (...args) => {
37
+ const program = new Command('proxygate');
38
+ program
39
+ .option('--gateway <url>')
40
+ .option('--keypair <path>')
41
+ .option('--json', 'Output raw JSON');
42
+ registerRateCommand(program);
43
+ await program.parseAsync(['node', 'proxygate', 'rate', ...args]);
44
+ };
45
+ it('submits a positive rating with --up', async () => {
46
+ mockRate.mockResolvedValue({ status: 'ok', message: 'Rating submitted' });
47
+ await run('--request-id', 'req-abc-123', '--up');
48
+ expect(mockRate).toHaveBeenCalledWith({ request_id: 'req-abc-123', is_positive: true });
49
+ const output = logSpy.mock.calls.map((c) => c[0]).join('\n');
50
+ expect(output).toContain('Rating Submitted');
51
+ expect(output).toContain('ok');
52
+ });
53
+ it('submits a negative rating with --down', async () => {
54
+ mockRate.mockResolvedValue({ status: 'ok', message: 'Rating submitted' });
55
+ await run('--request-id', 'req-abc-123', '--down');
56
+ expect(mockRate).toHaveBeenCalledWith({ request_id: 'req-abc-123', is_positive: false });
57
+ });
58
+ it('exits with error when neither --up nor --down provided', async () => {
59
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
60
+ throw new Error('process.exit');
61
+ });
62
+ await expect(run('--request-id', 'req-abc-123')).rejects.toThrow('process.exit');
63
+ mockExit.mockRestore();
64
+ });
65
+ it('outputs raw JSON with --json flag', async () => {
66
+ const result = { status: 'ok', message: 'Rating submitted' };
67
+ mockRate.mockResolvedValue(result);
68
+ await run('--request-id', 'req-abc-123', '--up', '--json');
69
+ expect(logSpy).toHaveBeenCalledTimes(1);
70
+ const parsed = JSON.parse(logSpy.mock.calls[0][0]);
71
+ expect(parsed).toEqual(result);
72
+ });
73
+ });
74
+ //# sourceMappingURL=rate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate.test.js","sourceRoot":"","sources":["../../src/commands/rate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerServicesCommand(program: Command): void;
3
+ //# sourceMappingURL=services.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/commands/services.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkD9D"}
@@ -0,0 +1,48 @@
1
+ import { ProxyGateError } from '@proxygate/sdk';
2
+ import { getClient } from '../helpers.js';
3
+ import { bold, red, dim, cyan, formatTable } from '../format.js';
4
+ export function registerServicesCommand(program) {
5
+ program
6
+ .command('services')
7
+ .description('View aggregated service stats (no auth required)')
8
+ .addHelpText('after', '\nExamples:\n' +
9
+ ' $ proxygate services\n' +
10
+ ' $ proxygate services --json')
11
+ .action(async () => {
12
+ const parentOpts = program.opts();
13
+ try {
14
+ const client = await getClient(parentOpts);
15
+ const result = await client.services();
16
+ if (parentOpts.json) {
17
+ console.log(JSON.stringify(result, null, 2));
18
+ return;
19
+ }
20
+ if (result.services.length === 0) {
21
+ console.log(dim('No services available.'));
22
+ return;
23
+ }
24
+ console.log(bold(`Services (${result.count})`));
25
+ console.log();
26
+ const headers = ['Service', 'Cheapest', 'Avg Latency', 'Sellers', 'RPM', 'Rating'];
27
+ const rows = result.services.map((s) => [
28
+ `${bold(cyan(s.service_name))} ${dim(`(${s.service})`)}`,
29
+ `$${s.cheapest_price_usdc}`,
30
+ `${s.avg_latency_ms}ms`,
31
+ String(s.active_seller_count),
32
+ String(s.total_capacity_rpm),
33
+ s.avg_rating > 0 ? s.avg_rating.toFixed(1) : dim('n/a'),
34
+ ]);
35
+ console.log(formatTable(headers, rows));
36
+ }
37
+ catch (err) {
38
+ if (err instanceof ProxyGateError) {
39
+ console.error(red(`Error [${err.code}]: ${err.message}`));
40
+ if (err.action)
41
+ console.error(dim(`Suggestion: ${err.action}`));
42
+ process.exit(1);
43
+ }
44
+ throw err;
45
+ }
46
+ });
47
+ }
48
+ //# sourceMappingURL=services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/commands/services.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAS,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAgB,MAAM,cAAc,CAAC;AAEtF,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,kDAAkD,CAAC;SAC/D,WAAW,CACV,OAAO,EACP,eAAe;QACb,0BAA0B;QAC1B,+BAA+B,CAClC;SACA,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAA0D,CAAC;QAE1F,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;YAEvC,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7C,OAAO;YACT,CAAC;YAED,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAChD,OAAO,CAAC,GAAG,EAAE,CAAC;YAEd,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;YACnF,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;gBACtC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,EAAE;gBACxD,IAAI,CAAC,CAAC,mBAAmB,EAAE;gBAC3B,GAAG,CAAC,CAAC,cAAc,IAAI;gBACvB,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC;gBAC7B,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC;gBAC5B,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;aACxD,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;gBAClC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBAC1D,IAAI,GAAG,CAAC,MAAM;oBAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=services.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.test.d.ts","sourceRoot":"","sources":["../../src/commands/services.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,87 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { Command } from 'commander';
3
+ import { registerServicesCommand } from './services.js';
4
+ const mockServices = vi.fn();
5
+ vi.mock('@proxygate/sdk', () => ({
6
+ ProxyGateClient: {
7
+ create: vi.fn().mockResolvedValue({
8
+ services: (...args) => mockServices(...args),
9
+ }),
10
+ },
11
+ ProxyGateError: class extends Error {
12
+ code;
13
+ constructor(msg, code) {
14
+ super(msg);
15
+ this.code = code;
16
+ }
17
+ },
18
+ }));
19
+ vi.mock('../config.js', () => ({
20
+ loadConfig: vi.fn().mockResolvedValue({
21
+ gatewayUrl: 'http://localhost:3001',
22
+ keypairPath: '/tmp/key.json',
23
+ }),
24
+ }));
25
+ const SERVICES_RESULT = {
26
+ services: [
27
+ {
28
+ service: 'openai',
29
+ service_name: 'OpenAI',
30
+ cheapest_price_usdc: 0.00002,
31
+ avg_latency_ms: 250,
32
+ active_seller_count: 3,
33
+ total_capacity_rpm: 360,
34
+ avg_uptime_percent: 99.2,
35
+ avg_rating: 4.8,
36
+ best_rated_seller_wallet: '8Kag2c9vqVT7xLMpRa5JKrGeUVPxfYbcWEuvGLBAW123',
37
+ pricing_units: 'per_request',
38
+ },
39
+ ],
40
+ has_more: false,
41
+ cursor: null,
42
+ count: 1,
43
+ };
44
+ describe('services command', () => {
45
+ let logSpy;
46
+ beforeEach(() => {
47
+ vi.clearAllMocks();
48
+ logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
49
+ vi.spyOn(console, 'error').mockImplementation(() => { });
50
+ });
51
+ afterEach(() => {
52
+ vi.restoreAllMocks();
53
+ });
54
+ const run = async (...args) => {
55
+ const program = new Command('proxygate');
56
+ program
57
+ .option('--gateway <url>')
58
+ .option('--keypair <path>')
59
+ .option('--json', 'Output raw JSON');
60
+ registerServicesCommand(program);
61
+ await program.parseAsync(['node', 'proxygate', 'services', ...args]);
62
+ };
63
+ it('outputs formatted table by default', async () => {
64
+ mockServices.mockResolvedValue(SERVICES_RESULT);
65
+ await run();
66
+ const output = logSpy.mock.calls.map((c) => c[0]).join('\n');
67
+ expect(output).toContain('Services (1)');
68
+ expect(output).toContain('OpenAI');
69
+ expect(output).toContain('250ms');
70
+ expect(output).toContain('360');
71
+ expect(output).toContain('4.8');
72
+ });
73
+ it('outputs raw JSON with --json flag', async () => {
74
+ mockServices.mockResolvedValue(SERVICES_RESULT);
75
+ await run('--json');
76
+ expect(logSpy).toHaveBeenCalledTimes(1);
77
+ const parsed = JSON.parse(logSpy.mock.calls[0][0]);
78
+ expect(parsed).toEqual(SERVICES_RESULT);
79
+ });
80
+ it('shows empty message when no services', async () => {
81
+ mockServices.mockResolvedValue({ services: [], has_more: false, cursor: null, count: 0 });
82
+ await run();
83
+ const output = logSpy.mock.calls.map((c) => c[0]).join('\n');
84
+ expect(output).toContain('No services available');
85
+ });
86
+ });
87
+ //# sourceMappingURL=services.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.test.js","sourceRoot":"","sources":["../../src/commands/services.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerSettlementsCommand(program: Command): void;
3
+ //# sourceMappingURL=settlements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settlements.d.ts","sourceRoot":"","sources":["../../src/commands/settlements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4EjE"}