@proxy-checkout/cli 0.1.0-prx-128.104.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/cjs/auth.d.cts +38 -0
- package/dist/cjs/auth.d.ts +38 -0
- package/dist/cjs/auth.js +258 -0
- package/dist/cjs/bin.d.cts +2 -0
- package/dist/cjs/bin.d.ts +2 -0
- package/dist/cjs/bin.js +10 -0
- package/dist/cjs/cli.d.cts +10 -0
- package/dist/cjs/cli.d.ts +10 -0
- package/dist/cjs/cli.js +469 -0
- package/dist/cjs/command-schema.d.cts +23 -0
- package/dist/cjs/command-schema.d.ts +23 -0
- package/dist/cjs/command-schema.js +238 -0
- package/dist/cjs/config.d.cts +55 -0
- package/dist/cjs/config.d.ts +55 -0
- package/dist/cjs/config.js +339 -0
- package/dist/cjs/errors.d.cts +20 -0
- package/dist/cjs/errors.d.ts +20 -0
- package/dist/cjs/errors.js +52 -0
- package/dist/cjs/http-client.d.cts +25 -0
- package/dist/cjs/http-client.d.ts +25 -0
- package/dist/cjs/http-client.js +102 -0
- package/dist/cjs/index.d.cts +5 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +17 -0
- package/dist/cjs/output.d.cts +19 -0
- package/dist/cjs/output.d.ts +19 -0
- package/dist/cjs/output.js +76 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/webhooks.d.cts +81 -0
- package/dist/cjs/webhooks.d.ts +81 -0
- package/dist/cjs/webhooks.js +343 -0
- package/dist/esm/auth.d.ts +38 -0
- package/dist/esm/auth.js +253 -0
- package/dist/esm/bin.d.ts +2 -0
- package/dist/esm/bin.js +8 -0
- package/dist/esm/cli.d.ts +10 -0
- package/dist/esm/cli.js +465 -0
- package/dist/esm/command-schema.d.ts +23 -0
- package/dist/esm/command-schema.js +232 -0
- package/dist/esm/config.d.ts +55 -0
- package/dist/esm/config.js +333 -0
- package/dist/esm/errors.d.ts +20 -0
- package/dist/esm/errors.js +46 -0
- package/dist/esm/http-client.d.ts +25 -0
- package/dist/esm/http-client.js +98 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/output.d.ts +19 -0
- package/dist/esm/output.js +71 -0
- package/dist/esm/webhooks.d.ts +81 -0
- package/dist/esm/webhooks.js +337 -0
- package/package.json +68 -0
package/dist/esm/cli.js
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { login, logout, status } from "./auth.js";
|
|
3
|
+
import { commandSchemaDocument, commandSchemas, llmsFullDocument } from "./command-schema.js";
|
|
4
|
+
import { CliConfigStore } from "./config.js";
|
|
5
|
+
import { asCliError, CliError, cliExitCodes, usageError } from "./errors.js";
|
|
6
|
+
import { CliOutput } from "./output.js";
|
|
7
|
+
import { forwardSelectedDelivery, ProxyWebhooksClient, runListener, } from "./webhooks.js";
|
|
8
|
+
export const cliVersion = "0.1.0-prx-128.104.1";
|
|
9
|
+
export async function runCli(argv, options = {}) {
|
|
10
|
+
const io = options.io ?? {
|
|
11
|
+
isTTY: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
12
|
+
stderr: process.stderr,
|
|
13
|
+
stdin: process.stdin,
|
|
14
|
+
stdout: process.stdout,
|
|
15
|
+
};
|
|
16
|
+
let output = new CliOutput(io.isTTY ? "human" : "jsonl", io);
|
|
17
|
+
let processSignal;
|
|
18
|
+
try {
|
|
19
|
+
const parsedGlobals = parseGlobalOptions([...argv], io, options.environment ?? process.env);
|
|
20
|
+
output = new CliOutput(parsedGlobals.options.format, io);
|
|
21
|
+
if (parsedGlobals.options.version) {
|
|
22
|
+
output.result({ version: cliVersion }, `proxy ${cliVersion}`);
|
|
23
|
+
return cliExitCodes.success;
|
|
24
|
+
}
|
|
25
|
+
if (parsedGlobals.options.llmsFull) {
|
|
26
|
+
const document = llmsFullDocument();
|
|
27
|
+
output.result({ document, schema_version: "2026-07-14" }, document);
|
|
28
|
+
return cliExitCodes.success;
|
|
29
|
+
}
|
|
30
|
+
if (parsedGlobals.args.join(" ") === "commands schema") {
|
|
31
|
+
output.result(commandSchemaDocument(), JSON.stringify(commandSchemaDocument(), null, 2));
|
|
32
|
+
return cliExitCodes.success;
|
|
33
|
+
}
|
|
34
|
+
const matched = matchCommand(parsedGlobals.args);
|
|
35
|
+
if (parsedGlobals.options.schema) {
|
|
36
|
+
if (!matched)
|
|
37
|
+
throw usageError("Unknown command for --schema");
|
|
38
|
+
const schema = commandSchemaDocument(matched.command.path);
|
|
39
|
+
if (!schema)
|
|
40
|
+
throw usageError("Unknown command for --schema");
|
|
41
|
+
output.result(schema, JSON.stringify(schema, null, 2));
|
|
42
|
+
return cliExitCodes.success;
|
|
43
|
+
}
|
|
44
|
+
if (!matched || parsedGlobals.options.help) {
|
|
45
|
+
output.result({ commands: commandSchemas.map((command) => command.path), version: cliVersion }, matched ? commandHelp(matched.command) : rootHelp());
|
|
46
|
+
return matched || parsedGlobals.options.help ? cliExitCodes.success : cliExitCodes.usage;
|
|
47
|
+
}
|
|
48
|
+
if (matched.command.streaming && parsedGlobals.options.format === "json") {
|
|
49
|
+
throw usageError("Streaming commands require --format jsonl or human");
|
|
50
|
+
}
|
|
51
|
+
assertRequestedMode(matched.command, parsedGlobals.options.expectedMode);
|
|
52
|
+
const commandOptions = parseCommandOptions(matched.args, matched.command.options);
|
|
53
|
+
const configStore = options.configStore ??
|
|
54
|
+
new CliConfigStore({ environment: options.environment ?? process.env });
|
|
55
|
+
const profileName = configStore.profileName(parsedGlobals.options.profileName ?? readOptionalString(commandOptions, "--profile"));
|
|
56
|
+
const requestedApiBase = parsedGlobals.options.apiBaseUrl ?? readOptionalString(commandOptions, "--api-base");
|
|
57
|
+
processSignal = options.signal ? undefined : createProcessSignal();
|
|
58
|
+
const signal = options.signal ?? processSignal?.signal;
|
|
59
|
+
if (!signal)
|
|
60
|
+
throw new Error("CLI abort signal was not initialized");
|
|
61
|
+
await executeCommand({
|
|
62
|
+
command: matched.command,
|
|
63
|
+
configStore,
|
|
64
|
+
expectedMerchantId: parsedGlobals.options.expectedMerchantId,
|
|
65
|
+
expectedMode: parsedGlobals.options.expectedMode,
|
|
66
|
+
io,
|
|
67
|
+
noInput: parsedGlobals.options.noInput,
|
|
68
|
+
options: commandOptions,
|
|
69
|
+
output,
|
|
70
|
+
profileName,
|
|
71
|
+
requestedApiBase,
|
|
72
|
+
signal,
|
|
73
|
+
});
|
|
74
|
+
return cliExitCodes.success;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const cliError = asCliError(error);
|
|
78
|
+
output.error(cliError);
|
|
79
|
+
return cliError.exitCode;
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
processSignal?.dispose();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function executeCommand(input) {
|
|
86
|
+
if (input.command.path === "auth login") {
|
|
87
|
+
const existingProfile = await input.configStore.readProfile(input.profileName);
|
|
88
|
+
const apiBaseUrl = input.configStore.apiBaseUrl(input.requestedApiBase, existingProfile);
|
|
89
|
+
const profile = await login({
|
|
90
|
+
apiBaseUrl,
|
|
91
|
+
configStore: input.configStore,
|
|
92
|
+
expectedMerchantId: input.expectedMerchantId,
|
|
93
|
+
expectedMode: input.expectedMode,
|
|
94
|
+
name: readOptionalString(input.options, "--name"),
|
|
95
|
+
noBrowser: readBoolean(input.options, "--no-browser"),
|
|
96
|
+
output: input.output,
|
|
97
|
+
profileName: input.profileName,
|
|
98
|
+
signal: input.signal,
|
|
99
|
+
});
|
|
100
|
+
input.output.result(publicProfile(input.profileName, profile), `Authenticated profile ${input.profileName} for test merchant ${profile.merchantId}.`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const resolved = await input.configStore.resolveCredential({
|
|
104
|
+
apiBaseUrl: input.requestedApiBase,
|
|
105
|
+
profileName: input.profileName,
|
|
106
|
+
});
|
|
107
|
+
if (input.command.path === "auth status") {
|
|
108
|
+
const remoteProfile = await status(resolved);
|
|
109
|
+
assertRemoteTarget(remoteProfile, input);
|
|
110
|
+
input.output.result({
|
|
111
|
+
profile: {
|
|
112
|
+
...remoteProfile,
|
|
113
|
+
credential_source: resolved.source,
|
|
114
|
+
profile: resolved.profileName,
|
|
115
|
+
},
|
|
116
|
+
}, `Profile ${resolved.profileName} is authenticated for ${remoteProfile.merchant_id} (${remoteProfile.mode}).`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (input.command.path === "auth logout") {
|
|
120
|
+
if (input.expectedMerchantId || input.expectedMode) {
|
|
121
|
+
assertRemoteTarget(await status(resolved), input);
|
|
122
|
+
}
|
|
123
|
+
await logout({
|
|
124
|
+
apiBaseUrl: resolved.apiBaseUrl,
|
|
125
|
+
configStore: input.configStore,
|
|
126
|
+
profileName: resolved.profileName,
|
|
127
|
+
removeLocalProfile: resolved.source !== "environment",
|
|
128
|
+
token: resolved.token,
|
|
129
|
+
});
|
|
130
|
+
input.output.result({ profile: resolved.profileName, revoked: true }, `Logged out profile ${resolved.profileName}.`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (input.expectedMerchantId || input.expectedMode) {
|
|
134
|
+
assertRemoteTarget(await status(resolved), input);
|
|
135
|
+
}
|
|
136
|
+
const webhooks = new ProxyWebhooksClient(resolved.apiBaseUrl, resolved.token);
|
|
137
|
+
if (input.command.path === "webhooks endpoints list") {
|
|
138
|
+
const endpoints = await webhooks.listEndpoints();
|
|
139
|
+
input.output.result({ webhook_endpoints: endpoints }, formatEndpointList(endpoints));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (input.command.path === "webhooks listeners create") {
|
|
143
|
+
const listener = await webhooks.createListener(readRequiredString(input.options, "--endpoint"));
|
|
144
|
+
input.output.result({ listener }, `Created listener ${listener.id}; lease expires ${listener.lease_expires_at}.`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (input.command.path === "webhooks listeners status") {
|
|
148
|
+
const listener = await webhooks.getListener(readRequiredString(input.options, "--listener"));
|
|
149
|
+
input.output.result({ listener }, `Listener ${listener.id} is ${listener.status}; lease expires ${listener.lease_expires_at}.`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (input.command.path === "webhooks listeners heartbeat") {
|
|
153
|
+
const listener = await webhooks.heartbeat(readRequiredString(input.options, "--listener"));
|
|
154
|
+
input.output.result({ listener }, `Extended listener ${listener.id} through ${listener.lease_expires_at}.`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (input.command.path === "webhooks listeners close") {
|
|
158
|
+
const listener = await webhooks.close(readRequiredString(input.options, "--listener"));
|
|
159
|
+
input.output.result({ listener }, `Closed listener ${listener.id}.`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (input.command.path === "webhooks deliveries list") {
|
|
163
|
+
const deliveries = await webhooks.listDeliveries(readRequiredString(input.options, "--listener"), readOptionalInteger(input.options, "--limit"));
|
|
164
|
+
input.output.result({ deliveries }, `${deliveries.length} local webhook deliveries.`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (input.command.path === "webhooks deliveries replay") {
|
|
168
|
+
const replay = await webhooks.replay(readRequiredString(input.options, "--listener"), readRequiredString(input.options, "--delivery"), readRequiredString(input.options, "--reason"));
|
|
169
|
+
input.output.result(replay, "Replay scheduled.");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (input.command.path === "webhooks deliveries forward") {
|
|
173
|
+
const deliveryId = readOptionalString(input.options, "--delivery");
|
|
174
|
+
const replayOutboxEventId = readOptionalString(input.options, "--replay-outbox");
|
|
175
|
+
if (Number(Boolean(deliveryId)) + Number(Boolean(replayOutboxEventId)) !== 1) {
|
|
176
|
+
throw usageError("Exactly one of --delivery or --replay-outbox is required");
|
|
177
|
+
}
|
|
178
|
+
const result = await forwardSelectedDelivery({
|
|
179
|
+
client: webhooks,
|
|
180
|
+
...(deliveryId ? { deliveryId } : {}),
|
|
181
|
+
forwardTo: readRequiredString(input.options, "--forward-to"),
|
|
182
|
+
listenerId: readRequiredString(input.options, "--listener"),
|
|
183
|
+
...(replayOutboxEventId ? { replayOutboxEventId } : {}),
|
|
184
|
+
signal: input.signal,
|
|
185
|
+
});
|
|
186
|
+
input.output.result(result, `Forwarded selected delivery ${result.webhook_delivery_id}.`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (input.command.path === "listen") {
|
|
190
|
+
const endpoints = await webhooks.listEndpoints();
|
|
191
|
+
const sourceEndpointId = await selectEndpoint({
|
|
192
|
+
endpoints,
|
|
193
|
+
io: input.io,
|
|
194
|
+
noInput: input.noInput,
|
|
195
|
+
output: input.output,
|
|
196
|
+
requested: readOptionalString(input.options, "--endpoint"),
|
|
197
|
+
});
|
|
198
|
+
const maxEvents = readOptionalInteger(input.options, "--max-events") ?? 0;
|
|
199
|
+
if (maxEvents < 0)
|
|
200
|
+
throw usageError("--max-events must be zero or greater");
|
|
201
|
+
await runListener({
|
|
202
|
+
client: webhooks,
|
|
203
|
+
forwardTo: readRequiredString(input.options, "--forward-to"),
|
|
204
|
+
maxEvents,
|
|
205
|
+
output: input.output,
|
|
206
|
+
pspConfigId: readOptionalString(input.options, "--stripe-psp-config"),
|
|
207
|
+
signal: input.signal,
|
|
208
|
+
sourceEndpointId,
|
|
209
|
+
stripe: readBoolean(input.options, "--stripe"),
|
|
210
|
+
});
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
throw usageError(`Unsupported command: ${input.command.path}`);
|
|
214
|
+
}
|
|
215
|
+
function parseGlobalOptions(args, io, environment) {
|
|
216
|
+
const defaultFormat = io.isTTY ? "human" : "jsonl";
|
|
217
|
+
const options = {
|
|
218
|
+
format: parseFormat(environment.PROXY_FORMAT ?? defaultFormat),
|
|
219
|
+
help: false,
|
|
220
|
+
llmsFull: false,
|
|
221
|
+
noInput: false,
|
|
222
|
+
schema: false,
|
|
223
|
+
version: false,
|
|
224
|
+
};
|
|
225
|
+
const remaining = [];
|
|
226
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
227
|
+
const argument = args[index];
|
|
228
|
+
const [name, inlineValue] = splitOption(argument);
|
|
229
|
+
if (name === "--format" ||
|
|
230
|
+
name === "--profile" ||
|
|
231
|
+
name === "--api-base" ||
|
|
232
|
+
name === "--merchant" ||
|
|
233
|
+
name === "--mode") {
|
|
234
|
+
const value = inlineValue ?? args[index + 1];
|
|
235
|
+
if (!value || value.startsWith("--"))
|
|
236
|
+
throw usageError(`${name} requires a value`);
|
|
237
|
+
if (inlineValue === undefined)
|
|
238
|
+
index += 1;
|
|
239
|
+
if (name === "--format")
|
|
240
|
+
options.format = parseFormat(value);
|
|
241
|
+
if (name === "--profile")
|
|
242
|
+
options.profileName = value;
|
|
243
|
+
if (name === "--api-base")
|
|
244
|
+
options.apiBaseUrl = value;
|
|
245
|
+
if (name === "--merchant") {
|
|
246
|
+
if (!/^merch_[A-Za-z0-9_-]+$/.test(value)) {
|
|
247
|
+
throw usageError("--merchant must be a Proxy merchant ID");
|
|
248
|
+
}
|
|
249
|
+
options.expectedMerchantId = value;
|
|
250
|
+
}
|
|
251
|
+
if (name === "--mode") {
|
|
252
|
+
if (value !== "test" && value !== "live") {
|
|
253
|
+
throw usageError("--mode must be test or live");
|
|
254
|
+
}
|
|
255
|
+
options.expectedMode = value;
|
|
256
|
+
}
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (name === "--no-input")
|
|
260
|
+
options.noInput = true;
|
|
261
|
+
else if (name === "--schema")
|
|
262
|
+
options.schema = true;
|
|
263
|
+
else if (name === "--llms-full")
|
|
264
|
+
options.llmsFull = true;
|
|
265
|
+
else if (name === "--help" || name === "-h")
|
|
266
|
+
options.help = true;
|
|
267
|
+
else if (name === "--version" || name === "-v")
|
|
268
|
+
options.version = true;
|
|
269
|
+
else
|
|
270
|
+
remaining.push(argument);
|
|
271
|
+
}
|
|
272
|
+
return { args: remaining, options };
|
|
273
|
+
}
|
|
274
|
+
function parseCommandOptions(args, schemas) {
|
|
275
|
+
const allowed = new Map(schemas.map((schema) => [schema.name, schema]));
|
|
276
|
+
const values = new Map();
|
|
277
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
278
|
+
const argument = args[index];
|
|
279
|
+
if (!argument.startsWith("--"))
|
|
280
|
+
throw usageError(`Unexpected argument: ${argument}`);
|
|
281
|
+
const [name, inlineValue] = splitOption(argument);
|
|
282
|
+
const schema = allowed.get(name);
|
|
283
|
+
if (!schema)
|
|
284
|
+
throw usageError(`Unknown option for this command: ${name}`);
|
|
285
|
+
if (values.has(schema.name))
|
|
286
|
+
throw usageError(`Option may be specified only once: ${name}`);
|
|
287
|
+
if (schema.type === "boolean") {
|
|
288
|
+
if (inlineValue !== undefined)
|
|
289
|
+
throw usageError(`${name} does not accept a value`);
|
|
290
|
+
values.set(schema.name, true);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
const raw = inlineValue ?? args[index + 1];
|
|
294
|
+
if (!raw || raw.startsWith("--"))
|
|
295
|
+
throw usageError(`${name} requires a value`);
|
|
296
|
+
if (inlineValue === undefined)
|
|
297
|
+
index += 1;
|
|
298
|
+
if (schema.type === "integer") {
|
|
299
|
+
if (!/^-?\d+$/.test(raw))
|
|
300
|
+
throw usageError(`${name} requires an integer`);
|
|
301
|
+
values.set(schema.name, Number(raw));
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
values.set(schema.name, raw);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
for (const schema of schemas) {
|
|
308
|
+
if (schema.required && !values.has(schema.name)) {
|
|
309
|
+
throw usageError(`Missing required option: ${schema.name}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return values;
|
|
313
|
+
}
|
|
314
|
+
function matchCommand(args) {
|
|
315
|
+
const sorted = [...commandSchemas].sort((left, right) => right.path.split(" ").length - left.path.split(" ").length);
|
|
316
|
+
for (const command of sorted) {
|
|
317
|
+
const parts = command.path.split(" ");
|
|
318
|
+
if (parts.every((part, index) => args[index] === part)) {
|
|
319
|
+
return { args: args.slice(parts.length), command };
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
async function selectEndpoint(input) {
|
|
325
|
+
if (input.requested) {
|
|
326
|
+
if (!input.endpoints.some((endpoint) => endpoint.id === input.requested)) {
|
|
327
|
+
throw new CliError("Requested source endpoint is not active or does not belong to this merchant", "cli_source_endpoint_not_found", cliExitCodes.conflict);
|
|
328
|
+
}
|
|
329
|
+
return input.requested;
|
|
330
|
+
}
|
|
331
|
+
if (input.endpoints.length === 0) {
|
|
332
|
+
throw new CliError("No active HTTPS webhook endpoint is available as a relay source", "cli_source_endpoint_required", cliExitCodes.conflict);
|
|
333
|
+
}
|
|
334
|
+
if (input.endpoints.length === 1)
|
|
335
|
+
return input.endpoints[0].id;
|
|
336
|
+
if (input.noInput || !input.io.isTTY) {
|
|
337
|
+
throw usageError("Multiple source endpoints are available; pass --endpoint with --no-input");
|
|
338
|
+
}
|
|
339
|
+
input.output.notice(input.endpoints
|
|
340
|
+
.map((endpoint, index) => `${index + 1}. ${endpoint.id} — ${endpoint.url}`)
|
|
341
|
+
.join("\n"));
|
|
342
|
+
const prompt = createInterface({
|
|
343
|
+
input: input.io.stdin,
|
|
344
|
+
output: input.io.stderr,
|
|
345
|
+
});
|
|
346
|
+
try {
|
|
347
|
+
const answer = await prompt.question("Select a source endpoint number: ");
|
|
348
|
+
const selected = input.endpoints[Number(answer) - 1];
|
|
349
|
+
if (!selected)
|
|
350
|
+
throw usageError("Invalid endpoint selection");
|
|
351
|
+
return selected.id;
|
|
352
|
+
}
|
|
353
|
+
finally {
|
|
354
|
+
prompt.close();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function publicProfile(profileName, profile) {
|
|
358
|
+
return {
|
|
359
|
+
profile: {
|
|
360
|
+
api_base_url: profile.apiBaseUrl,
|
|
361
|
+
api_version: profile.apiVersion,
|
|
362
|
+
capability_version: profile.capabilityVersion,
|
|
363
|
+
credential_id: profile.credentialId,
|
|
364
|
+
credential_store: profile.credentialStore,
|
|
365
|
+
expires_at: profile.expiresAt,
|
|
366
|
+
merchant_id: profile.merchantId,
|
|
367
|
+
mode: profile.mode,
|
|
368
|
+
name: profile.name,
|
|
369
|
+
organization_id: profile.organizationId,
|
|
370
|
+
profile: profileName,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function formatEndpointList(endpoints) {
|
|
375
|
+
return endpoints.length === 0
|
|
376
|
+
? "No active HTTPS webhook endpoints."
|
|
377
|
+
: endpoints.map((endpoint) => `${endpoint.id}\t${endpoint.url}`).join("\n");
|
|
378
|
+
}
|
|
379
|
+
function parseFormat(value) {
|
|
380
|
+
if (value === "human" || value === "json" || value === "jsonl")
|
|
381
|
+
return value;
|
|
382
|
+
throw usageError("--format must be human, json, or jsonl");
|
|
383
|
+
}
|
|
384
|
+
function assertRequestedMode(command, mode) {
|
|
385
|
+
if (!mode || command.modes.includes(mode)) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
throw new CliError(mode === "live"
|
|
389
|
+
? "This CLI command is not enabled for live mode"
|
|
390
|
+
: "This CLI command is not enabled for the requested mode", mode === "live" ? "cli_live_mode_not_enabled" : "cli_mode_not_allowed", cliExitCodes.permission);
|
|
391
|
+
}
|
|
392
|
+
function assertRemoteTarget(profile, expected) {
|
|
393
|
+
if (expected.expectedMerchantId && profile.merchant_id !== expected.expectedMerchantId) {
|
|
394
|
+
throw new CliError("The CLI credential does not match the requested merchant", "cli_merchant_not_allowed", cliExitCodes.permission);
|
|
395
|
+
}
|
|
396
|
+
if (expected.expectedMode && profile.mode !== expected.expectedMode) {
|
|
397
|
+
throw new CliError("The CLI credential does not match the requested mode", expected.expectedMode === "live" ? "cli_live_mode_not_enabled" : "cli_mode_not_allowed", cliExitCodes.permission);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
function splitOption(value) {
|
|
401
|
+
const separator = value.indexOf("=");
|
|
402
|
+
return separator < 0
|
|
403
|
+
? [value, undefined]
|
|
404
|
+
: [value.slice(0, separator), value.slice(separator + 1)];
|
|
405
|
+
}
|
|
406
|
+
function readRequiredString(values, name) {
|
|
407
|
+
const value = values.get(name);
|
|
408
|
+
if (typeof value !== "string")
|
|
409
|
+
throw usageError(`Missing required option: ${name}`);
|
|
410
|
+
return value;
|
|
411
|
+
}
|
|
412
|
+
function readOptionalString(values, name) {
|
|
413
|
+
const value = values.get(name);
|
|
414
|
+
return typeof value === "string" ? value : undefined;
|
|
415
|
+
}
|
|
416
|
+
function readOptionalInteger(values, name) {
|
|
417
|
+
const value = values.get(name);
|
|
418
|
+
return typeof value === "number" ? value : undefined;
|
|
419
|
+
}
|
|
420
|
+
function readBoolean(values, name) {
|
|
421
|
+
return values.get(name) === true;
|
|
422
|
+
}
|
|
423
|
+
function createProcessSignal() {
|
|
424
|
+
const controller = new AbortController();
|
|
425
|
+
const abort = () => controller.abort();
|
|
426
|
+
process.once("SIGINT", abort);
|
|
427
|
+
process.once("SIGTERM", abort);
|
|
428
|
+
return {
|
|
429
|
+
signal: controller.signal,
|
|
430
|
+
dispose() {
|
|
431
|
+
process.removeListener("SIGINT", abort);
|
|
432
|
+
process.removeListener("SIGTERM", abort);
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function rootHelp() {
|
|
437
|
+
return [
|
|
438
|
+
`Proxy CLI ${cliVersion}`,
|
|
439
|
+
"",
|
|
440
|
+
"Usage: proxy <command> [options]",
|
|
441
|
+
"",
|
|
442
|
+
...commandSchemas.map((command) => ` ${command.path.padEnd(31)} ${command.description}`),
|
|
443
|
+
"",
|
|
444
|
+
"Global options:",
|
|
445
|
+
" --format human|json|jsonl Structured output (non-TTY default: jsonl)",
|
|
446
|
+
" --no-input Prohibit prompts",
|
|
447
|
+
" --profile NAME Credential profile",
|
|
448
|
+
" --merchant ID Assert the target merchant",
|
|
449
|
+
" --mode test|live Assert the command mode",
|
|
450
|
+
" --api-base URL Proxy API base URL",
|
|
451
|
+
" --schema Print a command's machine-readable schema",
|
|
452
|
+
" --llms-full Print the complete agent-facing command reference",
|
|
453
|
+
" --help Show help",
|
|
454
|
+
" --version Show version",
|
|
455
|
+
].join("\n");
|
|
456
|
+
}
|
|
457
|
+
function commandHelp(command) {
|
|
458
|
+
return [
|
|
459
|
+
`Usage: proxy ${command.path} [options]`,
|
|
460
|
+
"",
|
|
461
|
+
command.description,
|
|
462
|
+
"",
|
|
463
|
+
...command.options.map((option) => ` ${option.name.padEnd(24)} ${option.description}`),
|
|
464
|
+
].join("\n");
|
|
465
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type CommandOptionType = "boolean" | "integer" | "string";
|
|
2
|
+
export interface CommandOptionSchema {
|
|
3
|
+
description: string;
|
|
4
|
+
env?: string;
|
|
5
|
+
name: `--${string}`;
|
|
6
|
+
required?: boolean;
|
|
7
|
+
sensitive?: boolean;
|
|
8
|
+
type: CommandOptionType;
|
|
9
|
+
}
|
|
10
|
+
export interface CommandSchema {
|
|
11
|
+
capabilities: string[];
|
|
12
|
+
description: string;
|
|
13
|
+
interactive: boolean;
|
|
14
|
+
modes: Array<"test" | "live">;
|
|
15
|
+
options: CommandOptionSchema[];
|
|
16
|
+
output: string;
|
|
17
|
+
path: string;
|
|
18
|
+
streaming?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare const commandSchemas: readonly CommandSchema[];
|
|
21
|
+
export declare function findCommandSchema(path: string): CommandSchema | undefined;
|
|
22
|
+
export declare function commandSchemaDocument(path?: string): unknown;
|
|
23
|
+
export declare function llmsFullDocument(): string;
|