@proxy-checkout/cli 0.1.0-prx-128.111.1 → 0.1.0-prx-128.113.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/README.md CHANGED
@@ -20,7 +20,7 @@ proxy auth status \
20
20
  --mode test
21
21
  ```
22
22
 
23
- Authentication uses an RFC 8628 browser/device handoff. Proxy exchanges the short-lived approved browser session for a distinct `pcli_test_...` credential, revokes the temporary session, and stores only the CLI credential. The CLI never persists a Portal session or exposes a merchant `sk_test_*` key.
23
+ Authentication uses an RFC 8628 browser/device handoff. Proxy exchanges the short-lived approved browser session for a distinct but initially disabled `pcli_test_...` credential and revokes the temporary session. The CLI stores only that credential, then proves possession to an idempotent activation endpoint; a lost response or interrupted save cannot leave an unreachable active grant. The CLI never persists a Portal session or exposes a merchant `sk_test_*` key.
24
24
 
25
25
  Profiles bind the saved API origin, organization, merchant, and mode. `--merchant` and `--mode` assert the target returned by login or remote credential introspection; they do not select or elevate a merchant client-side. Stored credentials cannot be sent to a different API origin.
26
26
 
package/dist/cjs/auth.js CHANGED
@@ -47,27 +47,24 @@ async function login(input) {
47
47
  });
48
48
  const profile = requireExchangeProfile(exchanged.profile, input.apiBaseUrl);
49
49
  if (input.expectedMerchantId && profile.merchantId !== input.expectedMerchantId) {
50
- const mismatch = new errors_js_1.CliError("The approved CLI credential does not match the requested merchant", "cli_merchant_not_allowed", errors_js_1.cliExitCodes.permission);
51
- await revokeExchangedCredential(input.apiBaseUrl, exchanged.credential, profile, mismatch);
52
- throw mismatch;
50
+ throw new errors_js_1.CliError("The approved CLI credential does not match the requested merchant", "cli_merchant_not_allowed", errors_js_1.cliExitCodes.permission);
53
51
  }
54
52
  if (input.expectedMode && profile.mode !== input.expectedMode) {
55
- const mismatch = new errors_js_1.CliError("The approved CLI credential does not match the requested mode", input.expectedMode === "live" ? "cli_live_mode_not_enabled" : "cli_mode_not_allowed", errors_js_1.cliExitCodes.permission);
56
- await revokeExchangedCredential(input.apiBaseUrl, exchanged.credential, profile, mismatch);
57
- throw mismatch;
58
- }
59
- let saved;
60
- try {
61
- saved = await input.configStore.saveProfile(input.profileName, profile, exchanged.credential);
62
- }
63
- catch (error) {
64
- await revokeExchangedCredential(input.apiBaseUrl, exchanged.credential, profile, error);
65
- throw error;
53
+ throw new errors_js_1.CliError("The approved CLI credential does not match the requested mode", input.expectedMode === "live" ? "cli_live_mode_not_enabled" : "cli_mode_not_allowed", errors_js_1.cliExitCodes.permission);
66
54
  }
55
+ await revokeSupersededCredential(previousCredential, exchanged.credential, input.output);
56
+ const saved = await input.configStore.saveProfile(input.profileName, profile, exchanged.credential);
67
57
  if (saved.credentialStore === "file") {
68
58
  input.output.notice("Warning: native credential storage is unavailable; the CLI credential is in an owner-only (0600) file fallback.");
69
59
  }
70
- await revokeSupersededCredential(previousCredential, exchanged.credential, input.output);
60
+ await activateCredential({
61
+ apiBaseUrl: input.apiBaseUrl,
62
+ approvalId: approved.approvalId,
63
+ credential: exchanged.credential,
64
+ credentialId: profile.credentialId,
65
+ merchantId: profile.merchantId,
66
+ signal,
67
+ });
71
68
  return saved;
72
69
  }
73
70
  async function revokeSupersededCredential(previous, newCredential, output) {
@@ -83,27 +80,44 @@ async function revokeSupersededCredential(previous, newCredential, output) {
83
80
  catch (error) {
84
81
  if (error instanceof errors_js_1.CliError && error.exitCode === errors_js_1.cliExitCodes.authentication)
85
82
  return;
86
- throw new errors_js_1.CliError(`The new profile is saved, but previous credential ${previous.profile.credentialId} could not be revoked automatically; revoke it in the Proxy Portal`, "cli_previous_credential_cleanup_failed", errors_js_1.cliExitCodes.network, {
83
+ throw new errors_js_1.CliError(`Login stopped before replacing this profile because previous credential ${previous.profile.credentialId} could not be revoked automatically; retry or revoke it in the Proxy Portal`, "cli_previous_credential_cleanup_failed", errors_js_1.cliExitCodes.network, {
87
84
  cleanup_error_class: error instanceof Error ? error.name : typeof error,
88
85
  cleanup_error_code: error instanceof errors_js_1.CliError ? error.code : undefined,
89
86
  credential_id: previous.profile.credentialId,
90
87
  });
91
88
  }
92
89
  }
93
- async function revokeExchangedCredential(apiBaseUrl, credential, profile, originalError) {
94
- try {
95
- await new http_client_js_1.ProxyApiClient(apiBaseUrl, credential).request("/cli/auth/logout", {
96
- method: "POST",
97
- });
98
- }
99
- catch (cleanupError) {
100
- throw new errors_js_1.CliError(`Login did not complete and cleanup of credential ${profile.credentialId} could not be confirmed; revoke it in the Proxy Portal`, "cli_credential_cleanup_failed", errors_js_1.cliExitCodes.network, {
101
- cleanup_error_class: cleanupError instanceof Error ? cleanupError.name : typeof cleanupError,
102
- credential_id: profile.credentialId,
103
- original_error_class: originalError instanceof Error ? originalError.name : typeof originalError,
104
- original_error_code: originalError instanceof errors_js_1.CliError ? originalError.code : undefined,
105
- });
90
+ async function activateCredential(input) {
91
+ const client = new http_client_js_1.ProxyApiClient(input.apiBaseUrl, input.credential);
92
+ let lastError = new errors_js_1.CliError("Credential activation was not attempted", "cli_credential_activation_unconfirmed", errors_js_1.cliExitCodes.network);
93
+ for (let attempt = 0; attempt < 2; attempt += 1) {
94
+ try {
95
+ const result = await client.request("/cli/auth/activate", {
96
+ method: "POST",
97
+ signal: input.signal,
98
+ body: {
99
+ approval_id: input.approvalId,
100
+ credential_id: input.credentialId,
101
+ merchant_id: input.merchantId,
102
+ },
103
+ });
104
+ if (typeof result.activated !== "boolean") {
105
+ throw new errors_js_1.CliError("Proxy authentication returned an invalid credential activation response", "cli_invalid_auth_response", errors_js_1.cliExitCodes.network);
106
+ }
107
+ return;
108
+ }
109
+ catch (error) {
110
+ lastError = (0, errors_js_1.asCliError)(error);
111
+ if (lastError.exitCode !== errors_js_1.cliExitCodes.network) {
112
+ break;
113
+ }
114
+ }
106
115
  }
116
+ throw new errors_js_1.CliError(`CLI credential ${input.credentialId} was saved locally, but activation could not be confirmed; rerun proxy auth login to recover safely`, "cli_credential_activation_unconfirmed", lastError.exitCode, {
117
+ activation_error_class: lastError.name,
118
+ activation_error_code: lastError.code,
119
+ credential_id: input.credentialId,
120
+ });
107
121
  }
108
122
  async function status(input) {
109
123
  const response = await new http_client_js_1.ProxyApiClient(input.apiBaseUrl, input.token).request("/cli/auth/status", { signal: input.signal });
@@ -1,6 +1,6 @@
1
1
  import { CliConfigStore } from "./config.js";
2
2
  import { type CliIo } from "./output.js";
3
- export declare const cliVersion = "0.1.0-prx-128.111.1";
3
+ export declare const cliVersion = "0.1.0-prx-128.113.1";
4
4
  export interface RunCliOptions {
5
5
  configStore?: CliConfigStore;
6
6
  environment?: NodeJS.ProcessEnv;
package/dist/cjs/cli.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { CliConfigStore } from "./config.js";
2
2
  import { type CliIo } from "./output.js";
3
- export declare const cliVersion = "0.1.0-prx-128.111.1";
3
+ export declare const cliVersion = "0.1.0-prx-128.113.1";
4
4
  export interface RunCliOptions {
5
5
  configStore?: CliConfigStore;
6
6
  environment?: NodeJS.ProcessEnv;
package/dist/cjs/cli.js CHANGED
@@ -9,7 +9,7 @@ const config_js_1 = require("./config.js");
9
9
  const errors_js_1 = require("./errors.js");
10
10
  const output_js_1 = require("./output.js");
11
11
  const webhooks_js_1 = require("./webhooks.js");
12
- exports.cliVersion = "0.1.0-prx-128.111.1";
12
+ exports.cliVersion = "0.1.0-prx-128.113.1";
13
13
  async function runCli(argv, options = {}) {
14
14
  const io = options.io ?? {
15
15
  isTTY: Boolean(process.stdin.isTTY && process.stdout.isTTY),
@@ -89,6 +89,7 @@ async function runListener(input) {
89
89
  const destination = validateLoopbackDestination(input.forwardTo);
90
90
  const listener = await input.client.createListener(input.sourceEndpointId, input.signal);
91
91
  let stripeProcess;
92
+ let stripeProcessFailure;
92
93
  let forwarded = 0;
93
94
  let heartbeatFailure;
94
95
  const heartbeatTimer = setInterval(() => {
@@ -104,7 +105,9 @@ async function runListener(input) {
104
105
  if (input.stripe) {
105
106
  const webhookSecret = await captureStripeWebhookSecret(input.signal);
106
107
  const ingress = await input.client.createStripeIngress(listener.id, webhookSecret, input.pspConfigId, input.signal);
107
- stripeProcess = startStripeListener(ingress.inbound_url, input.output);
108
+ stripeProcess = await startStripeListener(ingress.inbound_url, input.output, (error) => {
109
+ stripeProcessFailure = stripeListenerStartError(error);
110
+ });
108
111
  input.output.event("stripe.started", {
109
112
  expires_at: ingress.expires_at,
110
113
  ingress_id: ingress.id,
@@ -117,6 +120,9 @@ async function runListener(input) {
117
120
  if (heartbeatFailure) {
118
121
  throw heartbeatFailure;
119
122
  }
123
+ if (stripeProcessFailure) {
124
+ throw stripeProcessFailure;
125
+ }
120
126
  if (stripeProcess && (stripeProcess.exitCode !== null || stripeProcess.signalCode)) {
121
127
  throw new errors_js_1.CliError("Stripe CLI listener exited unexpectedly", "stripe_cli_exited", errors_js_1.cliExitCodes.dependency, { exit_code: stripeProcess.exitCode, signal: stripeProcess.signalCode });
122
128
  }
@@ -135,6 +141,8 @@ async function runListener(input) {
135
141
  webhook_delivery_id: claim.webhook_delivery_id,
136
142
  }, `Forwarded ${claim.kind} ${claim.webhook_delivery_id} (${formatCompletion(completion)}).`);
137
143
  }
144
+ if (stripeProcessFailure)
145
+ throw stripeProcessFailure;
138
146
  if (input.signal.aborted)
139
147
  throw listenerInterrupted();
140
148
  return { forwarded, listener };
@@ -220,7 +228,7 @@ async function captureStripeWebhookSecret(signal) {
220
228
  function listenerInterrupted() {
221
229
  return new errors_js_1.CliError("Local webhook listener interrupted", "cli_listener_interrupted", errors_js_1.cliExitCodes.interrupted);
222
230
  }
223
- function startStripeListener(inboundUrl, output) {
231
+ function startStripeListener(inboundUrl, output, onError) {
224
232
  const child = (0, node_child_process_1.spawn)("stripe", ["listen", "--events", stripeEvents, "--forward-to", inboundUrl], {
225
233
  shell: false,
226
234
  stdio: ["pipe", "pipe", "pipe"],
@@ -228,8 +236,28 @@ function startStripeListener(inboundUrl, output) {
228
236
  child.stdin.end();
229
237
  pipeSanitized(child.stdout, (line) => output.notice(`[stripe] ${line}`));
230
238
  pipeSanitized(child.stderr, (line) => output.notice(`[stripe] ${line}`));
231
- child.once("error", () => undefined);
232
- return child;
239
+ return new Promise((resolve, reject) => {
240
+ const handleInitialError = (error) => {
241
+ child.removeListener("spawn", handleSpawn);
242
+ reject(stripeListenerStartError(error));
243
+ };
244
+ const handleSpawn = () => {
245
+ child.removeListener("spawn", handleSpawn);
246
+ child.removeListener("error", handleInitialError);
247
+ child.once("error", onError);
248
+ resolve(child);
249
+ };
250
+ child.once("error", handleInitialError);
251
+ child.once("spawn", handleSpawn);
252
+ if (child.exitCode !== null || child.signalCode)
253
+ handleSpawn();
254
+ });
255
+ }
256
+ function stripeListenerStartError(error) {
257
+ if (error?.code === "ENOENT") {
258
+ return new errors_js_1.CliError("Stripe CLI is not installed or not on PATH", "stripe_cli_not_found", errors_js_1.cliExitCodes.dependency);
259
+ }
260
+ return new errors_js_1.CliError("Stripe CLI listener could not start", "stripe_cli_start_failed", errors_js_1.cliExitCodes.dependency);
233
261
  }
234
262
  function pipeSanitized(stream, writeLine) {
235
263
  let pending = "";
package/dist/esm/auth.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { hostname, platform } from "node:os";
3
- import { CliError, cliExitCodes } from "./errors.js";
3
+ import { asCliError, CliError, cliExitCodes } from "./errors.js";
4
4
  import { ProxyApiClient } from "./http-client.js";
5
5
  const clientId = "proxy-cli";
6
6
  const deviceScope = "proxy.cli.local-webhook-development";
@@ -42,27 +42,24 @@ export async function login(input) {
42
42
  });
43
43
  const profile = requireExchangeProfile(exchanged.profile, input.apiBaseUrl);
44
44
  if (input.expectedMerchantId && profile.merchantId !== input.expectedMerchantId) {
45
- const mismatch = new CliError("The approved CLI credential does not match the requested merchant", "cli_merchant_not_allowed", cliExitCodes.permission);
46
- await revokeExchangedCredential(input.apiBaseUrl, exchanged.credential, profile, mismatch);
47
- throw mismatch;
45
+ throw new CliError("The approved CLI credential does not match the requested merchant", "cli_merchant_not_allowed", cliExitCodes.permission);
48
46
  }
49
47
  if (input.expectedMode && profile.mode !== input.expectedMode) {
50
- const mismatch = new CliError("The approved CLI credential does not match the requested mode", input.expectedMode === "live" ? "cli_live_mode_not_enabled" : "cli_mode_not_allowed", cliExitCodes.permission);
51
- await revokeExchangedCredential(input.apiBaseUrl, exchanged.credential, profile, mismatch);
52
- throw mismatch;
53
- }
54
- let saved;
55
- try {
56
- saved = await input.configStore.saveProfile(input.profileName, profile, exchanged.credential);
57
- }
58
- catch (error) {
59
- await revokeExchangedCredential(input.apiBaseUrl, exchanged.credential, profile, error);
60
- throw error;
48
+ throw new CliError("The approved CLI credential does not match the requested mode", input.expectedMode === "live" ? "cli_live_mode_not_enabled" : "cli_mode_not_allowed", cliExitCodes.permission);
61
49
  }
50
+ await revokeSupersededCredential(previousCredential, exchanged.credential, input.output);
51
+ const saved = await input.configStore.saveProfile(input.profileName, profile, exchanged.credential);
62
52
  if (saved.credentialStore === "file") {
63
53
  input.output.notice("Warning: native credential storage is unavailable; the CLI credential is in an owner-only (0600) file fallback.");
64
54
  }
65
- await revokeSupersededCredential(previousCredential, exchanged.credential, input.output);
55
+ await activateCredential({
56
+ apiBaseUrl: input.apiBaseUrl,
57
+ approvalId: approved.approvalId,
58
+ credential: exchanged.credential,
59
+ credentialId: profile.credentialId,
60
+ merchantId: profile.merchantId,
61
+ signal,
62
+ });
66
63
  return saved;
67
64
  }
68
65
  async function revokeSupersededCredential(previous, newCredential, output) {
@@ -78,27 +75,44 @@ async function revokeSupersededCredential(previous, newCredential, output) {
78
75
  catch (error) {
79
76
  if (error instanceof CliError && error.exitCode === cliExitCodes.authentication)
80
77
  return;
81
- throw new CliError(`The new profile is saved, but previous credential ${previous.profile.credentialId} could not be revoked automatically; revoke it in the Proxy Portal`, "cli_previous_credential_cleanup_failed", cliExitCodes.network, {
78
+ throw new CliError(`Login stopped before replacing this profile because previous credential ${previous.profile.credentialId} could not be revoked automatically; retry or revoke it in the Proxy Portal`, "cli_previous_credential_cleanup_failed", cliExitCodes.network, {
82
79
  cleanup_error_class: error instanceof Error ? error.name : typeof error,
83
80
  cleanup_error_code: error instanceof CliError ? error.code : undefined,
84
81
  credential_id: previous.profile.credentialId,
85
82
  });
86
83
  }
87
84
  }
88
- async function revokeExchangedCredential(apiBaseUrl, credential, profile, originalError) {
89
- try {
90
- await new ProxyApiClient(apiBaseUrl, credential).request("/cli/auth/logout", {
91
- method: "POST",
92
- });
93
- }
94
- catch (cleanupError) {
95
- throw new CliError(`Login did not complete and cleanup of credential ${profile.credentialId} could not be confirmed; revoke it in the Proxy Portal`, "cli_credential_cleanup_failed", cliExitCodes.network, {
96
- cleanup_error_class: cleanupError instanceof Error ? cleanupError.name : typeof cleanupError,
97
- credential_id: profile.credentialId,
98
- original_error_class: originalError instanceof Error ? originalError.name : typeof originalError,
99
- original_error_code: originalError instanceof CliError ? originalError.code : undefined,
100
- });
85
+ async function activateCredential(input) {
86
+ const client = new ProxyApiClient(input.apiBaseUrl, input.credential);
87
+ let lastError = new CliError("Credential activation was not attempted", "cli_credential_activation_unconfirmed", cliExitCodes.network);
88
+ for (let attempt = 0; attempt < 2; attempt += 1) {
89
+ try {
90
+ const result = await client.request("/cli/auth/activate", {
91
+ method: "POST",
92
+ signal: input.signal,
93
+ body: {
94
+ approval_id: input.approvalId,
95
+ credential_id: input.credentialId,
96
+ merchant_id: input.merchantId,
97
+ },
98
+ });
99
+ if (typeof result.activated !== "boolean") {
100
+ throw new CliError("Proxy authentication returned an invalid credential activation response", "cli_invalid_auth_response", cliExitCodes.network);
101
+ }
102
+ return;
103
+ }
104
+ catch (error) {
105
+ lastError = asCliError(error);
106
+ if (lastError.exitCode !== cliExitCodes.network) {
107
+ break;
108
+ }
109
+ }
101
110
  }
111
+ throw new CliError(`CLI credential ${input.credentialId} was saved locally, but activation could not be confirmed; rerun proxy auth login to recover safely`, "cli_credential_activation_unconfirmed", lastError.exitCode, {
112
+ activation_error_class: lastError.name,
113
+ activation_error_code: lastError.code,
114
+ credential_id: input.credentialId,
115
+ });
102
116
  }
103
117
  export async function status(input) {
104
118
  const response = await new ProxyApiClient(input.apiBaseUrl, input.token).request("/cli/auth/status", { signal: input.signal });
package/dist/esm/cli.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { CliConfigStore } from "./config.js";
2
2
  import { type CliIo } from "./output.js";
3
- export declare const cliVersion = "0.1.0-prx-128.111.1";
3
+ export declare const cliVersion = "0.1.0-prx-128.113.1";
4
4
  export interface RunCliOptions {
5
5
  configStore?: CliConfigStore;
6
6
  environment?: NodeJS.ProcessEnv;
package/dist/esm/cli.js CHANGED
@@ -5,7 +5,7 @@ import { CliConfigStore } from "./config.js";
5
5
  import { asCliError, CliError, cliExitCodes, usageError } from "./errors.js";
6
6
  import { CliOutput } from "./output.js";
7
7
  import { forwardSelectedDelivery, ProxyWebhooksClient, runListener, } from "./webhooks.js";
8
- export const cliVersion = "0.1.0-prx-128.111.1";
8
+ export const cliVersion = "0.1.0-prx-128.113.1";
9
9
  export async function runCli(argv, options = {}) {
10
10
  const io = options.io ?? {
11
11
  isTTY: Boolean(process.stdin.isTTY && process.stdout.isTTY),
@@ -83,6 +83,7 @@ export async function runListener(input) {
83
83
  const destination = validateLoopbackDestination(input.forwardTo);
84
84
  const listener = await input.client.createListener(input.sourceEndpointId, input.signal);
85
85
  let stripeProcess;
86
+ let stripeProcessFailure;
86
87
  let forwarded = 0;
87
88
  let heartbeatFailure;
88
89
  const heartbeatTimer = setInterval(() => {
@@ -98,7 +99,9 @@ export async function runListener(input) {
98
99
  if (input.stripe) {
99
100
  const webhookSecret = await captureStripeWebhookSecret(input.signal);
100
101
  const ingress = await input.client.createStripeIngress(listener.id, webhookSecret, input.pspConfigId, input.signal);
101
- stripeProcess = startStripeListener(ingress.inbound_url, input.output);
102
+ stripeProcess = await startStripeListener(ingress.inbound_url, input.output, (error) => {
103
+ stripeProcessFailure = stripeListenerStartError(error);
104
+ });
102
105
  input.output.event("stripe.started", {
103
106
  expires_at: ingress.expires_at,
104
107
  ingress_id: ingress.id,
@@ -111,6 +114,9 @@ export async function runListener(input) {
111
114
  if (heartbeatFailure) {
112
115
  throw heartbeatFailure;
113
116
  }
117
+ if (stripeProcessFailure) {
118
+ throw stripeProcessFailure;
119
+ }
114
120
  if (stripeProcess && (stripeProcess.exitCode !== null || stripeProcess.signalCode)) {
115
121
  throw new CliError("Stripe CLI listener exited unexpectedly", "stripe_cli_exited", cliExitCodes.dependency, { exit_code: stripeProcess.exitCode, signal: stripeProcess.signalCode });
116
122
  }
@@ -129,6 +135,8 @@ export async function runListener(input) {
129
135
  webhook_delivery_id: claim.webhook_delivery_id,
130
136
  }, `Forwarded ${claim.kind} ${claim.webhook_delivery_id} (${formatCompletion(completion)}).`);
131
137
  }
138
+ if (stripeProcessFailure)
139
+ throw stripeProcessFailure;
132
140
  if (input.signal.aborted)
133
141
  throw listenerInterrupted();
134
142
  return { forwarded, listener };
@@ -214,7 +222,7 @@ async function captureStripeWebhookSecret(signal) {
214
222
  function listenerInterrupted() {
215
223
  return new CliError("Local webhook listener interrupted", "cli_listener_interrupted", cliExitCodes.interrupted);
216
224
  }
217
- function startStripeListener(inboundUrl, output) {
225
+ function startStripeListener(inboundUrl, output, onError) {
218
226
  const child = spawn("stripe", ["listen", "--events", stripeEvents, "--forward-to", inboundUrl], {
219
227
  shell: false,
220
228
  stdio: ["pipe", "pipe", "pipe"],
@@ -222,8 +230,28 @@ function startStripeListener(inboundUrl, output) {
222
230
  child.stdin.end();
223
231
  pipeSanitized(child.stdout, (line) => output.notice(`[stripe] ${line}`));
224
232
  pipeSanitized(child.stderr, (line) => output.notice(`[stripe] ${line}`));
225
- child.once("error", () => undefined);
226
- return child;
233
+ return new Promise((resolve, reject) => {
234
+ const handleInitialError = (error) => {
235
+ child.removeListener("spawn", handleSpawn);
236
+ reject(stripeListenerStartError(error));
237
+ };
238
+ const handleSpawn = () => {
239
+ child.removeListener("spawn", handleSpawn);
240
+ child.removeListener("error", handleInitialError);
241
+ child.once("error", onError);
242
+ resolve(child);
243
+ };
244
+ child.once("error", handleInitialError);
245
+ child.once("spawn", handleSpawn);
246
+ if (child.exitCode !== null || child.signalCode)
247
+ handleSpawn();
248
+ });
249
+ }
250
+ function stripeListenerStartError(error) {
251
+ if (error?.code === "ENOENT") {
252
+ return new CliError("Stripe CLI is not installed or not on PATH", "stripe_cli_not_found", cliExitCodes.dependency);
253
+ }
254
+ return new CliError("Stripe CLI listener could not start", "stripe_cli_start_failed", cliExitCodes.dependency);
227
255
  }
228
256
  function pipeSanitized(stream, writeLine) {
229
257
  let pending = "";
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "sideEffects": false,
8
8
  "type": "module",
9
9
  "types": "./dist/esm/index.d.ts",
10
- "version": "0.1.0-prx-128.111.1",
10
+ "version": "0.1.0-prx-128.113.1",
11
11
  "bin": {
12
12
  "proxy": "./dist/esm/bin.js"
13
13
  },