@vonpay/checkout-cli 0.13.0 → 0.14.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 (113) hide show
  1. package/dist/index.js +2397 -12
  2. package/package.json +5 -3
  3. package/dist/app-info.d.ts +0 -5
  4. package/dist/app-info.d.ts.map +0 -1
  5. package/dist/app-info.js +0 -11
  6. package/dist/app-info.js.map +0 -1
  7. package/dist/client-factory.d.ts +0 -10
  8. package/dist/client-factory.d.ts.map +0 -1
  9. package/dist/client-factory.js +0 -31
  10. package/dist/client-factory.js.map +0 -1
  11. package/dist/commands/capabilities.d.ts +0 -22
  12. package/dist/commands/capabilities.d.ts.map +0 -1
  13. package/dist/commands/capabilities.js +0 -123
  14. package/dist/commands/capabilities.js.map +0 -1
  15. package/dist/commands/checkout.d.ts +0 -3
  16. package/dist/commands/checkout.d.ts.map +0 -1
  17. package/dist/commands/checkout.js +0 -39
  18. package/dist/commands/checkout.js.map +0 -1
  19. package/dist/commands/doctor.d.ts +0 -59
  20. package/dist/commands/doctor.d.ts.map +0 -1
  21. package/dist/commands/doctor.js +0 -366
  22. package/dist/commands/doctor.js.map +0 -1
  23. package/dist/commands/health.d.ts +0 -3
  24. package/dist/commands/health.d.ts.map +0 -1
  25. package/dist/commands/health.js +0 -52
  26. package/dist/commands/health.js.map +0 -1
  27. package/dist/commands/init.d.ts +0 -10
  28. package/dist/commands/init.d.ts.map +0 -1
  29. package/dist/commands/init.js +0 -112
  30. package/dist/commands/init.js.map +0 -1
  31. package/dist/commands/listen.d.ts +0 -19
  32. package/dist/commands/listen.d.ts.map +0 -1
  33. package/dist/commands/listen.js +0 -249
  34. package/dist/commands/listen.js.map +0 -1
  35. package/dist/commands/login.d.ts +0 -27
  36. package/dist/commands/login.d.ts.map +0 -1
  37. package/dist/commands/login.js +0 -75
  38. package/dist/commands/login.js.map +0 -1
  39. package/dist/commands/logout.d.ts +0 -3
  40. package/dist/commands/logout.d.ts.map +0 -1
  41. package/dist/commands/logout.js +0 -23
  42. package/dist/commands/logout.js.map +0 -1
  43. package/dist/commands/payment-intents.d.ts +0 -62
  44. package/dist/commands/payment-intents.d.ts.map +0 -1
  45. package/dist/commands/payment-intents.js +0 -271
  46. package/dist/commands/payment-intents.js.map +0 -1
  47. package/dist/commands/refunds.d.ts +0 -40
  48. package/dist/commands/refunds.d.ts.map +0 -1
  49. package/dist/commands/refunds.js +0 -142
  50. package/dist/commands/refunds.js.map +0 -1
  51. package/dist/commands/sessions.d.ts +0 -16
  52. package/dist/commands/sessions.d.ts.map +0 -1
  53. package/dist/commands/sessions.js +0 -152
  54. package/dist/commands/sessions.js.map +0 -1
  55. package/dist/commands/tokens.d.ts +0 -3
  56. package/dist/commands/tokens.d.ts.map +0 -1
  57. package/dist/commands/tokens.js +0 -89
  58. package/dist/commands/tokens.js.map +0 -1
  59. package/dist/commands/trigger.d.ts +0 -38
  60. package/dist/commands/trigger.d.ts.map +0 -1
  61. package/dist/commands/trigger.js +0 -246
  62. package/dist/commands/trigger.js.map +0 -1
  63. package/dist/config.d.ts +0 -22
  64. package/dist/config.d.ts.map +0 -1
  65. package/dist/config.js +0 -72
  66. package/dist/config.js.map +0 -1
  67. package/dist/index.d.ts +0 -3
  68. package/dist/index.d.ts.map +0 -1
  69. package/dist/index.js.map +0 -1
  70. package/dist/utils/errors.d.ts +0 -80
  71. package/dist/utils/errors.d.ts.map +0 -1
  72. package/dist/utils/errors.js +0 -179
  73. package/dist/utils/errors.js.map +0 -1
  74. package/dist/utils/forward-to.d.ts +0 -38
  75. package/dist/utils/forward-to.d.ts.map +0 -1
  76. package/dist/utils/forward-to.js +0 -92
  77. package/dist/utils/forward-to.js.map +0 -1
  78. package/dist/utils/json-errors.d.ts +0 -16
  79. package/dist/utils/json-errors.d.ts.map +0 -1
  80. package/dist/utils/json-errors.js +0 -41
  81. package/dist/utils/json-errors.js.map +0 -1
  82. package/dist/utils/listen-forward.d.ts +0 -49
  83. package/dist/utils/listen-forward.d.ts.map +0 -1
  84. package/dist/utils/listen-forward.js +0 -113
  85. package/dist/utils/listen-forward.js.map +0 -1
  86. package/dist/utils/listen-output.d.ts +0 -52
  87. package/dist/utils/listen-output.d.ts.map +0 -1
  88. package/dist/utils/listen-output.js +0 -85
  89. package/dist/utils/listen-output.js.map +0 -1
  90. package/dist/utils/live-key.d.ts +0 -22
  91. package/dist/utils/live-key.d.ts.map +0 -1
  92. package/dist/utils/live-key.js +0 -37
  93. package/dist/utils/live-key.js.map +0 -1
  94. package/dist/utils/metadata.d.ts +0 -2
  95. package/dist/utils/metadata.d.ts.map +0 -1
  96. package/dist/utils/metadata.js +0 -31
  97. package/dist/utils/metadata.js.map +0 -1
  98. package/dist/utils/sanitize.d.ts +0 -4
  99. package/dist/utils/sanitize.d.ts.map +0 -1
  100. package/dist/utils/sanitize.js +0 -18
  101. package/dist/utils/sanitize.js.map +0 -1
  102. package/dist/utils/spinner.d.ts +0 -15
  103. package/dist/utils/spinner.d.ts.map +0 -1
  104. package/dist/utils/spinner.js +0 -18
  105. package/dist/utils/spinner.js.map +0 -1
  106. package/dist/utils/sse-consumer.d.ts +0 -81
  107. package/dist/utils/sse-consumer.d.ts.map +0 -1
  108. package/dist/utils/sse-consumer.js +0 -172
  109. package/dist/utils/sse-consumer.js.map +0 -1
  110. package/dist/utils/sse-parser.d.ts +0 -63
  111. package/dist/utils/sse-parser.d.ts.map +0 -1
  112. package/dist/utils/sse-parser.js +0 -149
  113. package/dist/utils/sse-parser.js.map +0 -1
@@ -1,179 +0,0 @@
1
- import chalk from "chalk";
2
- import { VonPayError, } from "@vonpay/checkout-node";
3
- import { emitCliError, jsonErrorsEnabled, printJsonError } from "./json-errors.js";
4
- /**
5
- * Secret shapes redacted from anything this CLI prints about an error.
6
- *
7
- * ⛔ Until 0.8.0 this matched `vp_sk_*` only, so a webhook signing secret, a
8
- * session-signing secret or a Stripe key inside an error message (a failed
9
- * config read, a proxy echoing a header) was printed in the clear — and CLI
10
- * output lands in CI logs and pasted support threads.
11
- *
12
- * One of the lists `tests/scripts/secret-shape-parity.test.mjs` holds to the
13
- * same definition of "a secret" as the SDK telemetry blocklists, the commit
14
- * gate and the scrubbers. Add a shape there and here together.
15
- *
16
- * Publishable keys (`vp_pk_*`, `pk_*`) are deliberately NOT redacted: they are
17
- * public by design (the commit gate does not block them either), and an error
18
- * naming the publishable key that was rejected is useful.
19
- *
20
- * `vp_sk_live_…` contains `sk_live_…`. The Vonpay pattern runs first so the
21
- * key is redacted as a Vonpay key; the output (`vp_sk_***`) is the same either
22
- * way, and the Stripe pattern does not match it again.
23
- */
24
- export const SECRET_PATTERNS = [
25
- [/vp_sk_(?:test|live)_[A-Za-z0-9_-]+/g, "vp_sk_***"],
26
- [/ss_(?:test|live)_[A-Za-z0-9_-]+/g, "ss_***"],
27
- [/whsec_[A-Za-z0-9_-]+/g, "whsec_***"],
28
- [/sk_(?:test|live)_[A-Za-z0-9_-]+/g, "sk_***"],
29
- [/rk_(?:test|live)_[A-Za-z0-9_-]+/g, "rk_***"],
30
- ];
31
- export function scrubSecrets(s) {
32
- let out = s;
33
- for (const [re, replacement] of SECRET_PATTERNS)
34
- out = out.replace(re, replacement);
35
- return out;
36
- }
37
- const str = (v) => (v === undefined || v === null ? null : String(v));
38
- const FIELD_PRINTERS = {
39
- code: (e) => `Code: ${str(e.code)}`,
40
- fix: (e) => `Fix: ${str(e.fix)}`,
41
- nextAction: (e) => (e.nextAction ? `Next action: ${str(e.nextAction)}` : null),
42
- retryable: (e) => typeof e.retryable === "boolean"
43
- ? `Retryable: ${e.retryable ? "yes" : "no — do not re-run this command as-is"}`
44
- : null,
45
- retryWithheld: (e) => e.retryWithheld === true
46
- ? "Retry withheld: the outcome was unclear and no idempotency key was sent, so the CLI did not retry. Check whether it went through before running it again; with --idempotency-key, re-running the SAME key is safe."
47
- : null,
48
- captureOutcome: (e) => e.captureOutcome
49
- ? `Capture outcome: ${str(e.captureOutcome)} — the provider accepted the capture but it could not be recorded, so money may have moved. Do NOT capture again; read the payment intent back first.`
50
- : null,
51
- voidOutcome: (e) => e.voidOutcome
52
- ? `Void outcome: ${str(e.voidOutcome)} — the provider accepted the void but it could not be recorded. Do NOT void again or tell the buyer the hold was released until a read-back confirms it.`
53
- : null,
54
- currentStatus: (e) => (e.currentStatus ? `Current status: ${str(e.currentStatus)}` : null),
55
- rejectReason: (e) => (e.rejectReason ? `Reject reason: ${str(e.rejectReason)}` : null),
56
- paymentIntent: (e) => (e.paymentIntent ? `Payment intent: ${str(e.paymentIntent)}` : null),
57
- // refund_target_is_duplicate: the SDK has already checked this is a
58
- // transaction id (vp_tx_*), so it is safe to echo as a command.
59
- refundInstead: (e) => e.refundInstead
60
- ? `Refund instead: vonpay checkout refunds create --transaction ${str(e.refundInstead)}`
61
- : null,
62
- reason: (e) => (e.reason ? `Reason: ${str(e.reason)}` : null),
63
- // An unrecognised expire reason reads "unknown"; show what the API sent.
64
- rawReason: (e) => e.rawReason && e.rawReason !== e.reason ? `Reason as sent: ${str(e.rawReason)}` : null,
65
- retryAfterSeconds: (e) => typeof e.retryAfterSeconds === "number"
66
- ? `Retry after: ${e.retryAfterSeconds} seconds — then ask again`
67
- : null,
68
- session: (e) => (e.session ? `Session: ${JSON.stringify(e.session)}` : null),
69
- llmHint: (e) => (e.llmHint ? `Hint: ${str(e.llmHint)}` : null),
70
- docs: (e) => (e.docs ? `Docs: ${str(e.docs)}` : null),
71
- status: (e) => (typeof e.status === "number" ? `HTTP status: ${e.status}` : null),
72
- rateLimit: (e) => (e.rateLimit ? `Rate limit: ${JSON.stringify(e.rateLimit)}` : null),
73
- requestId: (e) => (e.requestId ? `Request ID: ${str(e.requestId)}` : null),
74
- };
75
- /**
76
- * The structured fields, in print order. ONE list, read by both output
77
- * formats: the text lines below and the `--json` object. It is the key list of
78
- * `FIELD_PRINTERS`, whose mapped type makes `tsc` fail when `VonPayError` gains
79
- * a field the CLI does not handle — so the JSON cannot silently drop a field
80
- * the text prints, or the reverse.
81
- *
82
- * The MCP server's error envelope (`ERROR_ENVELOPE_FIELDS` in
83
- * `@vonpay/checkout-mcp`) is held to the same set by
84
- * `tests/integration/cli-mcp-error-field-parity.test.ts`. The two packages are
85
- * published separately, so neither imports the other.
86
- */
87
- export const ERROR_FIELDS = Object.keys(FIELD_PRINTERS);
88
- /** The detail lines printed under `Error: <message>`, already scrubbed. */
89
- function errorDetailLines(err) {
90
- const source = err;
91
- const lines = [];
92
- for (const print of Object.values(FIELD_PRINTERS)) {
93
- const line = print(source);
94
- if (line !== null)
95
- lines.push(` ${scrubSecrets(line)}`);
96
- }
97
- return lines;
98
- }
99
- /** Scrub every string inside a JSON-able value (the `session` object, for one). */
100
- function scrubDeep(value) {
101
- if (typeof value === "string")
102
- return scrubSecrets(value);
103
- if (Array.isArray(value))
104
- return value.map(scrubDeep);
105
- if (value !== null && typeof value === "object") {
106
- const out = {};
107
- for (const [k, v] of Object.entries(value))
108
- out[k] = scrubDeep(v);
109
- return out;
110
- }
111
- return value;
112
- }
113
- /**
114
- * The one JSON object printed for an error under `--json`.
115
- *
116
- * Every error has:
117
- * - `error` — the message (always a string)
118
- * - `code` — the API error code, or `null` when no API response was
119
- * involved (a network failure, or a problem the CLI caught
120
- * before sending anything)
121
- * and an API error adds every structured field the SDK's error carries that is
122
- * not `undefined` — the same fields, under the same names, as the MCP server's
123
- * error envelope: `status`, `nextAction`, `retryable`, `retryWithheld`,
124
- * `captureOutcome`, `voidOutcome`, … Unlike the text output, `false` values are
125
- * kept: `"retryWithheld": false` is an answer.
126
- *
127
- * ⚠️ `code: null` on `payment-intents capture` / `void` / `create` or
128
- * `refunds create` does NOT mean nothing happened: a network failure leaves
129
- * the outcome unknown. Read the resource back before running it again.
130
- *
131
- * Nothing here can carry the API key, the idempotency key or the request body:
132
- * `VonPayError` holds none of them, and any other error contributes only its
133
- * message. Every string still goes through the same redaction as the text
134
- * output.
135
- */
136
- export function errorJson(err) {
137
- if (err instanceof VonPayError) {
138
- const out = { error: err.message };
139
- const source = err;
140
- for (const field of ERROR_FIELDS) {
141
- const value = source[field];
142
- if (value !== undefined)
143
- out[field] = value;
144
- }
145
- return scrubDeep(out);
146
- }
147
- const message = err instanceof Error ? err.message : String(err);
148
- return { error: scrubSecrets(message), code: null };
149
- }
150
- /**
151
- * Exit 1 on a problem the CLI caught itself, before calling the API (a live
152
- * key without --confirm-live, a bad flag value). In text mode `text` is
153
- * printed exactly as given; under `--json` the output is
154
- * `{"error": <message>, "code": null}`, redacted like everything else.
155
- */
156
- export function exitWithCliError(message, text) {
157
- return emitCliError({ error: scrubSecrets(message), code: null }, text);
158
- }
159
- export function handleError(err) {
160
- if (jsonErrorsEnabled()) {
161
- printJsonError(errorJson(err));
162
- process.exit(1);
163
- }
164
- if (err instanceof VonPayError) {
165
- // Server-supplied text is scrubbed too: it is echoed to a terminal and
166
- // from there into logs, and nothing guarantees it never quotes a secret.
167
- console.error(chalk.red(`Error: ${scrubSecrets(err.message)}`));
168
- for (const line of errorDetailLines(err))
169
- console.error(chalk.dim(line));
170
- process.exit(1);
171
- }
172
- const message = err instanceof Error ? err.message : String(err);
173
- console.error(chalk.red(`Error: ${scrubSecrets(message)}`));
174
- process.exit(1);
175
- }
176
- export const __testing__ = {
177
- scrubSecrets,
178
- };
179
- //# sourceMappingURL=errors.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"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"}
@@ -1,38 +0,0 @@
1
- /**
2
- * URL validation for `vonpay checkout listen --forward-to` and
3
- * `vonpay checkout trigger --url` (same policy since 0.8.1; the flag names in
4
- * messages are passed in).
5
- *
6
- * Default posture: loopback-only. Refuses any URL whose hostname is not
7
- * one of the IPv4/IPv6 loopback aliases. This protects against the
8
- * "I typed the prod URL by mistake" class of incident, where a dev
9
- * starts forwarding production webhook attempts at their staging
10
- * endpoint or a public colleague's URL.
11
- *
12
- * The opt-in --forward-to-tunnel flag allows non-loopback hosts for
13
- * ngrok / Cloudflare Tunnel workflows. When set, only `https://` is
14
- * additionally rejected for non-loopback — http on a public host is
15
- * a stronger anti-pattern than tunneled https.
16
- *
17
- * Scheme: http and https accepted on loopback; non-loopback requires
18
- * the tunnel flag.
19
- */
20
- export type ForwardToVerdict = {
21
- ok: true;
22
- url: URL;
23
- isLoopback: boolean;
24
- warning?: string;
25
- } | {
26
- ok: false;
27
- reason: string;
28
- };
29
- /**
30
- * Pure validator. No I/O. Caller decides what to do with the verdict
31
- * (the CLI surfaces `reason` to stderr and exits non-zero).
32
- */
33
- export declare function validateForwardTo(raw: string, opts: {
34
- allowTunnel: boolean;
35
- flag?: string;
36
- tunnelFlag?: string;
37
- }): ForwardToVerdict;
38
- //# sourceMappingURL=forward-to.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"forward-to.d.ts","sourceRoot":"","sources":["../../src/utils/forward-to.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAmBH,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE,gBAAgB,CA+ClB"}
@@ -1,92 +0,0 @@
1
- /**
2
- * URL validation for `vonpay checkout listen --forward-to` and
3
- * `vonpay checkout trigger --url` (same policy since 0.8.1; the flag names in
4
- * messages are passed in).
5
- *
6
- * Default posture: loopback-only. Refuses any URL whose hostname is not
7
- * one of the IPv4/IPv6 loopback aliases. This protects against the
8
- * "I typed the prod URL by mistake" class of incident, where a dev
9
- * starts forwarding production webhook attempts at their staging
10
- * endpoint or a public colleague's URL.
11
- *
12
- * The opt-in --forward-to-tunnel flag allows non-loopback hosts for
13
- * ngrok / Cloudflare Tunnel workflows. When set, only `https://` is
14
- * additionally rejected for non-loopback — http on a public host is
15
- * a stronger anti-pattern than tunneled https.
16
- *
17
- * Scheme: http and https accepted on loopback; non-loopback requires
18
- * the tunnel flag.
19
- */
20
- const LOOPBACK_HOSTS = new Set([
21
- "localhost",
22
- "127.0.0.1",
23
- "0.0.0.0", // kernel-wildcard often routes to loopback on Linux / macOS dev hosts
24
- "::1",
25
- // URL.hostname surrounds IPv6 with brackets, but the bracket-stripping
26
- // happens before this set is consulted (see normalizeHost). Both forms
27
- // listed for defensiveness.
28
- "[::1]",
29
- // IPv6-mapped IPv4 loopback. Node's URL parser normalizes
30
- // `[::ffff:127.0.0.1]` to either form depending on version — both
31
- // are functionally loopback so we list every variant we have
32
- // observed in the wild.
33
- "::ffff:127.0.0.1",
34
- "::ffff:7f00:1",
35
- ]);
36
- /**
37
- * Pure validator. No I/O. Caller decides what to do with the verdict
38
- * (the CLI surfaces `reason` to stderr and exits non-zero).
39
- */
40
- export function validateForwardTo(raw, opts) {
41
- const flag = opts.flag ?? "--forward-to";
42
- const tunnelFlag = opts.tunnelFlag ?? "--forward-to-tunnel";
43
- if (typeof raw !== "string" || raw.length === 0) {
44
- return { ok: false, reason: `${flag} URL is required` };
45
- }
46
- let url;
47
- try {
48
- url = new URL(raw);
49
- }
50
- catch {
51
- return {
52
- ok: false,
53
- reason: `${flag} is not a parseable URL: ${truncate(raw)}`,
54
- };
55
- }
56
- if (url.protocol !== "http:" && url.protocol !== "https:") {
57
- return {
58
- ok: false,
59
- reason: `${flag} scheme must be http or https; got ${url.protocol}`,
60
- };
61
- }
62
- const host = normalizeHost(url.hostname);
63
- const isLoopback = LOOPBACK_HOSTS.has(host);
64
- if (!isLoopback && !opts.allowTunnel) {
65
- return {
66
- ok: false,
67
- reason: `${flag} refuses non-loopback hosts by default (got ${url.hostname}). ` +
68
- `Re-run with ${tunnelFlag} if forwarding through ngrok / Cloudflare Tunnel / etc.`,
69
- };
70
- }
71
- // `0.0.0.0` is treated as loopback for dev convenience, but it's a
72
- // bind-wildcard, not a guaranteed destination — in some container /
73
- // network configs an outbound connection to 0.0.0.0 routes off-host.
74
- // Accept it (non-breaking) but warn so a dev who meant "localhost"
75
- // isn't silently forwarding off-loopback.
76
- const warning = host === "0.0.0.0"
77
- ? "forwarding to 0.0.0.0 — that's a bind-wildcard, not a guaranteed loopback destination (it can route off-host in some container/network setups). Prefer 127.0.0.1 or localhost if you meant your local machine."
78
- : undefined;
79
- return { ok: true, url, isLoopback, warning };
80
- }
81
- function normalizeHost(hostname) {
82
- // URL.hostname returns IPv6 addresses unwrapped (no brackets), but
83
- // dual-coverage doesn't hurt.
84
- if (hostname.startsWith("[") && hostname.endsWith("]")) {
85
- return hostname.slice(1, -1);
86
- }
87
- return hostname.toLowerCase();
88
- }
89
- function truncate(s) {
90
- return s.length <= 120 ? s : `${s.slice(0, 117)}...`;
91
- }
92
- //# sourceMappingURL=forward-to.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"forward-to.js","sourceRoot":"","sources":["../../src/utils/forward-to.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,WAAW;IACX,WAAW;IACX,SAAS,EAAE,sEAAsE;IACjF,KAAK;IACL,uEAAuE;IACvE,uEAAuE;IACvE,4BAA4B;IAC5B,OAAO;IACP,0DAA0D;IAC1D,kEAAkE;IAClE,6DAA6D;IAC7D,wBAAwB;IACxB,kBAAkB;IAClB,eAAe;CAChB,CAAC,CAAC;AAMH;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAW,EACX,IAAkE;IAElE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,cAAc,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,qBAAqB,CAAC;IAC5D,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,kBAAkB,EAAE,CAAC;IAC1D,CAAC;IAED,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG,IAAI,4BAA4B,QAAQ,CAAC,GAAG,CAAC,EAAE;SAC3D,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG,IAAI,sCAAsC,GAAG,CAAC,QAAQ,EAAE;SACpE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE5C,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACrC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EACJ,GAAG,IAAI,+CAA+C,GAAG,CAAC,QAAQ,KAAK;gBACvE,eAAe,UAAU,yDAAyD;SACrF,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,oEAAoE;IACpE,qEAAqE;IACrE,mEAAmE;IACnE,0CAA0C;IAC1C,MAAM,OAAO,GACX,IAAI,KAAK,SAAS;QAChB,CAAC,CAAC,gNAAgN;QAClN,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,mEAAmE;IACnE,8BAA8B;IAC9B,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,QAAQ,CAAC,WAAW,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC;AACvD,CAAC"}
@@ -1,16 +0,0 @@
1
- export declare function setJsonErrors(enabled: boolean): void;
2
- export declare function jsonErrorsEnabled(): boolean;
3
- /**
4
- * One error, as one JSON line, on stderr. stdout is left alone: under
5
- * `--json` it carries the command's RESULT, and a script reading stdout must
6
- * never be handed an error it could parse as a result. The exit code (1) is
7
- * what says the command failed.
8
- */
9
- export declare function printJsonError(obj: Record<string, unknown>): void;
10
- /**
11
- * Print an error the CLI caught itself and exit 1: `json` under `--json`,
12
- * otherwise `text` exactly as given. Callers pass already-redacted values;
13
- * `exitWithCliError` in `errors.ts` does that for a message.
14
- */
15
- export declare function emitCliError(json: Record<string, unknown>, text: string): never;
16
- //# sourceMappingURL=json-errors.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"json-errors.d.ts","sourceRoot":"","sources":["../../src/utils/json-errors.ts"],"names":[],"mappings":"AAcA,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEpD;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEjE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,CAI/E"}
@@ -1,41 +0,0 @@
1
- /**
2
- * Whether errors in this run are printed as JSON, and the one place they are
3
- * written. Deliberately a leaf module (no imports) so the lowest-level code —
4
- * `config.ts`'s `requireApiKey` — can use it without pulling in the SDK. The
5
- * error formatting itself lives in `errors.ts`.
6
- *
7
- * Set once per run, before the command's action, from that command's own
8
- * `--json` flag — by the `preAction` hook in `commands/checkout.ts`. A process
9
- * runs one command, so a process-wide setting is the honest scope, and it
10
- * reaches the checks that fail before any request is sent (no key, the
11
- * live-key gate) without threading the flag through each of them.
12
- */
13
- let jsonErrors = false;
14
- export function setJsonErrors(enabled) {
15
- jsonErrors = enabled;
16
- }
17
- export function jsonErrorsEnabled() {
18
- return jsonErrors;
19
- }
20
- /**
21
- * One error, as one JSON line, on stderr. stdout is left alone: under
22
- * `--json` it carries the command's RESULT, and a script reading stdout must
23
- * never be handed an error it could parse as a result. The exit code (1) is
24
- * what says the command failed.
25
- */
26
- export function printJsonError(obj) {
27
- console.error(JSON.stringify(obj));
28
- }
29
- /**
30
- * Print an error the CLI caught itself and exit 1: `json` under `--json`,
31
- * otherwise `text` exactly as given. Callers pass already-redacted values;
32
- * `exitWithCliError` in `errors.ts` does that for a message.
33
- */
34
- export function emitCliError(json, text) {
35
- if (jsonErrors)
36
- printJsonError(json);
37
- else
38
- console.error(text);
39
- return process.exit(1);
40
- }
41
- //# sourceMappingURL=json-errors.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"json-errors.js","sourceRoot":"","sources":["../../src/utils/json-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,IAAI,UAAU,GAAG,KAAK,CAAC;AAEvB,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,UAAU,GAAG,OAAO,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,GAA4B;IACzD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAA6B,EAAE,IAAY;IACtE,IAAI,UAAU;QAAE,cAAc,CAAC,IAAI,CAAC,CAAC;;QAChC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzB,CAAC"}
@@ -1,49 +0,0 @@
1
- import type { ForwardOutcome } from "./listen-output.js";
2
- /**
3
- * Shadow-forward a webhook event to a local URL.
4
- *
5
- * The CLI receives a delivery-attempt TRANSCRIPT over SSE — not the
6
- * payload itself. To replay the same delivery against a local URL,
7
- * the CLI:
8
- *
9
- * 1. Fetches the full event record via GET /v1/webhook_events/:id
10
- * (the public webhook-event read endpoint)
11
- * 2. Signs it with the v1 webhook contract — a single
12
- * `x-vonpay-signature: t=<unix-seconds>,v1=<hex>` header whose
13
- * HMAC-SHA256 is computed over `${t}.${body}` (the same shape the
14
- * SDK's `webhooks.constructEvent` verifies). For this local dev loop
15
- * the signing secret is your API key, so verify with
16
- * `webhooks.constructEvent(rawBody, signatureHeader, yourApiKey)`.
17
- * 3. POSTs to the local URL with that single header, matching the live
18
- * delivery shape. The `t` is stamped HERE, at forward time — see the
19
- * `forwardPayload` body for the fresh-timestamp rationale.
20
- *
21
- * Bounded by a per-forward timeout (default 5s) and never retries —
22
- * shadow-forward is best-effort; if the local URL is down, the
23
- * transcript line shows the failure and the dev moves on.
24
- *
25
- * This re-delivers from the SSE delivery transcript, which differs from
26
- * Stripe CLI's `stripe listen --forward-to` pre-empt model.
27
- */
28
- interface ForwardOptions {
29
- /** Local URL to POST the payload to. */
30
- url: URL;
31
- /** Secret used to key the v1 HMAC. The listen stream exposes no
32
- * per-endpoint signing secret, so for this local forward loop the API
33
- * key (vp_sk_*) is used as a stand-in — verify the forwarded delivery
34
- * with `constructEvent(rawBody, signatureHeader, sameKey)`. Production
35
- * deliveries are keyed by the per-endpoint signing secret (whsec_…). */
36
- signingSecret: string;
37
- /** Per-forward timeout. Default 5_000. */
38
- timeoutMs?: number;
39
- /** AbortSignal for graceful shutdown. */
40
- signal: AbortSignal;
41
- }
42
- /**
43
- * Sign + POST a JSON payload to the local URL. Returns an outcome
44
- * shape that the output formatters render — never throws (errors
45
- * surface via `outcome.error`).
46
- */
47
- export declare function forwardPayload(payload: Record<string, unknown>, opts: ForwardOptions): Promise<ForwardOutcome>;
48
- export {};
49
- //# sourceMappingURL=listen-forward.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"listen-forward.d.ts","sourceRoot":"","sources":["../../src/utils/listen-forward.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,UAAU,cAAc;IACtB,wCAAwC;IACxC,GAAG,EAAE,GAAG,CAAC;IACT;;;;6EAIyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,cAAc,CAAC,CAsEzB"}
@@ -1,113 +0,0 @@
1
- import { createHmac } from "node:crypto";
2
- /**
3
- * Sign + POST a JSON payload to the local URL. Returns an outcome
4
- * shape that the output formatters render — never throws (errors
5
- * surface via `outcome.error`).
6
- */
7
- export async function forwardPayload(payload, opts) {
8
- const body = JSON.stringify(payload);
9
- // Stamp `t` at the moment we forward — NOT the server's original
10
- // delivery-attempt time. The CLI is the *re-sender* for this local
11
- // delivery: the dev's handler calls `webhooks.constructEvent`, which
12
- // rejects any `t` outside the freshness window (>5 min old / >30 sec
13
- // future). The server's original timestamp (carried on the SSE
14
- // `webhook.attempt` frame) is routinely minutes old — retries,
15
- // processing lag, a transcript the dev scrolled back through — so
16
- // replaying it would trip the window. A fresh `t` here matches Stripe
17
- // CLI's re-sign posture. Unlike the old bare-hex shape, `t` IS folded
18
- // into the HMAC per the v1 contract (`${t}.${body}`).
19
- const t = Math.floor(Date.now() / 1000);
20
- // v1 signature contract (https://docs.vonpay.com/integration/webhook-verification):
21
- // ONE header `x-vonpay-signature: t=<unix-seconds>,v1=<hex>`, HMAC-SHA256
22
- // over `${t}.${body}`. There is NO separate timestamp header. Rotation
23
- // (multiple `v1=` entries) does not apply to this synthetic local loop —
24
- // we sign with a single secret (the API key). When the server ships a
25
- // per-subscription signing secret on the SSE `webhook.attempt` frame,
26
- // sign with that here instead of the API key. (The 0.0.0.0 loopback
27
- // warning already shipped in forward-to.ts.)
28
- const v1 = createHmac("sha256", opts.signingSecret)
29
- .update(`${t}.${body}`)
30
- .digest("hex");
31
- const signatureHeader = `t=${t},v1=${v1}`;
32
- const timeoutMs = opts.timeoutMs ?? 5_000;
33
- const localController = new AbortController();
34
- const timeoutId = setTimeout(() => localController.abort(), timeoutMs);
35
- const combinedSignal = anySignal([opts.signal, localController.signal]);
36
- const start = Date.now();
37
- try {
38
- const res = await fetch(opts.url.toString(), {
39
- method: "POST",
40
- headers: {
41
- "Content-Type": "application/json",
42
- "x-vonpay-signature": signatureHeader,
43
- "User-Agent": "vonpay-cli-listen",
44
- },
45
- body,
46
- signal: combinedSignal,
47
- });
48
- // Drain response body so the connection can be reused — best practice
49
- // for repeated POSTs to the same local endpoint.
50
- try {
51
- await res.arrayBuffer();
52
- }
53
- catch {
54
- // ignore drain errors; not relevant to forward semantics
55
- }
56
- return {
57
- attempted: true,
58
- status: res.status,
59
- latencyMs: Date.now() - start,
60
- error: null,
61
- };
62
- }
63
- catch (err) {
64
- if (opts.signal.aborted) {
65
- return { attempted: true, status: null, latencyMs: null, error: "aborted" };
66
- }
67
- if (localController.signal.aborted) {
68
- return { attempted: true, status: null, latencyMs: null, error: `timeout after ${timeoutMs}ms` };
69
- }
70
- const message = err instanceof Error ? err.message : String(err);
71
- return { attempted: true, status: null, latencyMs: null, error: message };
72
- }
73
- finally {
74
- clearTimeout(timeoutId);
75
- }
76
- }
77
- /**
78
- * Combine multiple AbortSignals into one. The returned signal is
79
- * aborted when any input signal aborts. Polyfill for `AbortSignal.any`
80
- * which is Node 20.5+ only — guard for older 20.x deployments.
81
- *
82
- * The polyfill tracks every listener it registers and removes them all
83
- * once any input fires — without this, the long-lived parent
84
- * `opts.signal` accumulates one orphaned listener per forward call,
85
- * which on a busy listen stream is a measurable leak.
86
- */
87
- function anySignal(signals) {
88
- if (typeof AbortSignal.any === "function") {
89
- return AbortSignal.any(signals);
90
- }
91
- const controller = new AbortController();
92
- const tracked = [];
93
- const onAbort = () => {
94
- for (const sig of tracked) {
95
- sig.removeEventListener("abort", onAbort);
96
- }
97
- controller.abort();
98
- };
99
- for (const signal of signals) {
100
- if (signal.aborted) {
101
- controller.abort();
102
- // Remove already-added listeners — none yet, but defensive.
103
- for (const sig of tracked) {
104
- sig.removeEventListener("abort", onAbort);
105
- }
106
- return controller.signal;
107
- }
108
- signal.addEventListener("abort", onAbort);
109
- tracked.push(signal);
110
- }
111
- return controller.signal;
112
- }
113
- //# sourceMappingURL=listen-forward.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"listen-forward.js","sourceRoot":"","sources":["../../src/utils/listen-forward.ts"],"names":[],"mappings":"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"}
@@ -1,52 +0,0 @@
1
- /**
2
- * Output formatters for `vonpay checkout listen`.
3
- *
4
- * Two modes:
5
- * - "human" (default) — colored transcript, one line per attempt.
6
- * Optimized for the dev sitting at a terminal watching events
7
- * flow in real time.
8
- * - "json" — one JSON object per line on stdout. Optimized for
9
- * piping to `jq`, `grep`, or log aggregators.
10
- *
11
- * Lifecycle messages (connecting, reconnecting, etc.) ALWAYS go to
12
- * stderr in human mode so stdout stays parseable in `--json` mode
13
- * even when interleaved with reconnects.
14
- */
15
- export type OutputMode = "human" | "json";
16
- /**
17
- * Wire shape of the SSE `webhook.attempt` payload. Mirrors
18
- * vonpay-checkout's WebhookListenAttempt (snake_case on the wire).
19
- *
20
- * Duplicated here rather than importing from @vonpay/checkout-node
21
- * because the SDK does not currently export an SSE-event type — the
22
- * listen surface is CLI-only. If the SDK adds a streaming consumer in
23
- * a future minor, this type should move to the SDK and be re-imported.
24
- */
25
- export interface WebhookAttemptPayload {
26
- type: "webhook.attempt";
27
- subscription_id: string;
28
- event_id: string;
29
- event_type: string;
30
- attempt: number;
31
- succeeded: boolean;
32
- response_status: number | null;
33
- latency_ms: number;
34
- timestamp: string;
35
- livemode: boolean;
36
- }
37
- export interface ForwardOutcome {
38
- attempted: boolean;
39
- /** Local-URL response status, or null when no attempt was made (no --forward-to). */
40
- status: number | null;
41
- /** Latency ms of the local-URL POST. */
42
- latencyMs: number | null;
43
- /** Error message if the forward attempt failed at the network layer. */
44
- error: string | null;
45
- }
46
- export declare function formatAttemptHuman(payload: WebhookAttemptPayload, forward: ForwardOutcome | null): string;
47
- export declare function formatAttemptJson(payload: WebhookAttemptPayload, forward: ForwardOutcome | null): string;
48
- /** Lifecycle line for human mode (stderr). */
49
- export declare function formatLifecycleHuman(message: string, kind: "info" | "warn" | "error"): string;
50
- /** Lifecycle line for JSON mode (stderr). */
51
- export declare function formatLifecycleJson(kind: "connecting" | "connected" | "disconnected" | "auth_failed" | "fatal" | "ready" | "shutdown" | "warning", extra?: Record<string, unknown>): string;
52
- //# sourceMappingURL=listen-output.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"listen-output.d.ts","sourceRoot":"","sources":["../../src/utils/listen-output.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,iBAAiB,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,qFAAqF;IACrF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,wCAAwC;IACxC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,wEAAwE;IACxE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,cAAc,GAAG,IAAI,GAC7B,MAAM,CAwBR;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,cAAc,GAAG,IAAI,GAC7B,MAAM,CAqBR;AAED,8CAA8C;AAC9C,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAQ7F;AAED,6CAA6C;AAC7C,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,EAC9G,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAClC,MAAM,CAER"}