@stardeck-customer-apps/testing 0.28.0 → 0.30.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.
@@ -82,6 +82,12 @@ var state = globalSingleton("state", () => ({
82
82
  stripePaymentIntents: /* @__PURE__ */ new Map(),
83
83
  stripePaymentIntentCounter: 0,
84
84
  stripeIdempotentIntents: /* @__PURE__ */ new Map(),
85
+ stripeRefunds: /* @__PURE__ */ new Map(),
86
+ stripeRefundCounter: 0,
87
+ stripeIdempotentRefunds: /* @__PURE__ */ new Map(),
88
+ beamRefunds: /* @__PURE__ */ new Map(),
89
+ beamRefundCounter: 0,
90
+ beamIdempotentRefunds: /* @__PURE__ */ new Map(),
85
91
  stripeAllowedMethods: ["card", "promptpay"],
86
92
  stripeChargesEnabled: true,
87
93
  uploads: [],
@@ -55,6 +55,12 @@ var state = globalSingleton("state", () => ({
55
55
  stripePaymentIntents: /* @__PURE__ */ new Map(),
56
56
  stripePaymentIntentCounter: 0,
57
57
  stripeIdempotentIntents: /* @__PURE__ */ new Map(),
58
+ stripeRefunds: /* @__PURE__ */ new Map(),
59
+ stripeRefundCounter: 0,
60
+ stripeIdempotentRefunds: /* @__PURE__ */ new Map(),
61
+ beamRefunds: /* @__PURE__ */ new Map(),
62
+ beamRefundCounter: 0,
63
+ beamIdempotentRefunds: /* @__PURE__ */ new Map(),
58
64
  stripeAllowedMethods: ["card", "promptpay"],
59
65
  stripeChargesEnabled: true,
60
66
  uploads: [],
package/dist/setup.js CHANGED
@@ -87,6 +87,12 @@ var state = globalSingleton("state", () => ({
87
87
  stripePaymentIntents: /* @__PURE__ */ new Map(),
88
88
  stripePaymentIntentCounter: 0,
89
89
  stripeIdempotentIntents: /* @__PURE__ */ new Map(),
90
+ stripeRefunds: /* @__PURE__ */ new Map(),
91
+ stripeRefundCounter: 0,
92
+ stripeIdempotentRefunds: /* @__PURE__ */ new Map(),
93
+ beamRefunds: /* @__PURE__ */ new Map(),
94
+ beamRefundCounter: 0,
95
+ beamIdempotentRefunds: /* @__PURE__ */ new Map(),
90
96
  stripeAllowedMethods: ["card", "promptpay"],
91
97
  stripeChargesEnabled: true,
92
98
  uploads: [],
@@ -1553,7 +1559,11 @@ var requestScopeStorage = globalSingleton(
1553
1559
  var SIM_STRIPE_PUBLISHABLE_KEY = "pk_test_sim_stripe";
1554
1560
  var SIM_STRIPE_DEFAULT_ACCOUNT = "acct_sim_default";
1555
1561
  var METHODS = ["card", "promptpay"];
1556
- var RESERVED_METADATA_KEYS = ["projectId", "stardeckReferenceId", "stardeckStagingDeploymentId"];
1562
+ var RESERVED_METADATA_KEYS = [
1563
+ "projectId",
1564
+ "stardeckReferenceId",
1565
+ "stardeckStagingDeploymentId"
1566
+ ];
1557
1567
  var PROMPTPAY_QR_TTL_SECONDS = 15 * 60;
1558
1568
  var PATH_RE = /^\/api\/store\/(?!beam\/)([^/]+)\/(payment-intents(?:\/([^/]+)(?:\/(cancel))?)?|elements-config|readiness)$/;
1559
1569
  function err(error, status, code) {
@@ -1824,6 +1834,350 @@ async function handleStripePaymentIntentRequest(request, url, projectId) {
1824
1834
  return null;
1825
1835
  }
1826
1836
 
1837
+ // src/simulator/refunds.ts
1838
+ var REFUND_ROW_KEY = "refundRowId";
1839
+ var REFUND_METADATA_MAX_KEYS = 50 - RESERVED_METADATA_KEYS.length - 1;
1840
+ var REFUND_REASONS = ["duplicate", "fraudulent", "requested_by_customer"];
1841
+ var PROMPTPAY_BANK_DETAILS_WINDOW_SECONDS = 7 * 24 * 60 * 60;
1842
+ var BEAM_PARTIAL_METHODS = ["CARD", "CARD_TOKEN"];
1843
+ function refundFailure(plan) {
1844
+ return err(plan.message, plan.status, plan.code);
1845
+ }
1846
+ function isPositiveInt(value) {
1847
+ return typeof value === "number" && Number.isInteger(value) && value > 0;
1848
+ }
1849
+ function hasValidKey(value) {
1850
+ return typeof value === "string" && value.length >= 1 && value.length <= 255;
1851
+ }
1852
+ function isValidDeploymentId(value) {
1853
+ return typeof value === "string" && UUID_RE2.test(value);
1854
+ }
1855
+ function isValidRefundMetadata(value) {
1856
+ if (!isStringRecord(value)) return false;
1857
+ const entries = Object.entries(value);
1858
+ return entries.length <= REFUND_METADATA_MAX_KEYS && entries.every(
1859
+ ([k, v]) => k.length >= 1 && k.length <= 40 && v.length <= 500 && !RESERVED_METADATA_KEYS.includes(k) && k !== REFUND_ROW_KEY
1860
+ );
1861
+ }
1862
+ var COUNTED_STRIPE_STATUSES = [
1863
+ "pending",
1864
+ "requires_action",
1865
+ "succeeded"
1866
+ ];
1867
+ function refundedAmount(intentId) {
1868
+ let total = 0;
1869
+ for (const refund of state.stripeRefunds.values()) {
1870
+ if (refund.paymentIntentId === intentId && COUNTED_STRIPE_STATUSES.includes(refund.status)) {
1871
+ total += refund.amount;
1872
+ }
1873
+ }
1874
+ return total;
1875
+ }
1876
+ function syncAmountRefunded(intent) {
1877
+ intent.amountRefunded = refundedAmount(intent.id);
1878
+ }
1879
+ function validateStripeRefund(body) {
1880
+ const checks = [
1881
+ [isValidDeploymentId(body.deploymentId), "Invalid deployment ID"],
1882
+ [hasValidKey(body.idempotencyKey), "idempotencyKey is required (1 to 255 characters)"],
1883
+ [isOptional(body.amount, isPositiveInt), "amount must be a positive integer in minor units"],
1884
+ [
1885
+ isOptional(body.reason, (v) => typeof v === "string" && REFUND_REASONS.includes(v)),
1886
+ `reason must be one of: ${REFUND_REASONS.join(", ")}`
1887
+ ],
1888
+ [isOptional(body.instructionsEmail, isEmail), "instructionsEmail must be an email address"],
1889
+ [
1890
+ isOptional(
1891
+ body.refundRowId,
1892
+ (v) => typeof v === "string" && v.length >= 1 && v.length <= 500
1893
+ ),
1894
+ "refundRowId must be 1 to 500 characters"
1895
+ ],
1896
+ [
1897
+ isOptional(body.metadata, isValidRefundMetadata),
1898
+ `metadata must map keys (1-40 chars) to strings (max 500), at most ${REFUND_METADATA_MAX_KEYS} keys, without the keys the platform reserves (use refundRowId instead)`
1899
+ ]
1900
+ ];
1901
+ const failed = checks.find(([ok]) => !ok);
1902
+ return failed ? failed[1] : null;
1903
+ }
1904
+ function planStripeRefund(intent, requested) {
1905
+ if (intent.status !== "succeeded") {
1906
+ return {
1907
+ ok: false,
1908
+ status: 409,
1909
+ code: "payment_not_refundable",
1910
+ message: "This payment hasn't succeeded, so there is nothing to refund"
1911
+ };
1912
+ }
1913
+ const remaining = intent.amount - refundedAmount(intent.id);
1914
+ const amount = requested ?? remaining;
1915
+ if (remaining <= 0 || amount > remaining) {
1916
+ return {
1917
+ ok: false,
1918
+ status: 409,
1919
+ code: "refund_exceeds_remaining",
1920
+ message: `Only ${remaining} can still be refunded on this payment`
1921
+ };
1922
+ }
1923
+ return { ok: true, amount };
1924
+ }
1925
+ function toStripeRefundSummary(refund) {
1926
+ const intent = state.stripePaymentIntents.get(refund.paymentIntentId);
1927
+ return {
1928
+ id: refund.id,
1929
+ paymentIntentId: refund.paymentIntentId,
1930
+ amount: refund.amount,
1931
+ currency: refund.currency,
1932
+ status: refund.status,
1933
+ failureReason: refund.failureReason,
1934
+ pendingReason: refund.pendingReason,
1935
+ nextActionExpiresAt: refund.nextActionExpiresAt,
1936
+ refundRowId: refund.refundRowId,
1937
+ metadata: { ...refund.appMetadata },
1938
+ created: refund.created,
1939
+ livemode: false,
1940
+ playground: intent?.playground ?? false
1941
+ };
1942
+ }
1943
+ function newStripeRefund(input) {
1944
+ state.stripeRefundCounter += 1;
1945
+ const refund = {
1946
+ id: `re_sim_${state.stripeRefundCounter}`,
1947
+ paymentIntentId: input.intent.id,
1948
+ projectId: input.intent.projectId,
1949
+ amount: input.amount,
1950
+ currency: input.intent.currency,
1951
+ // A refund made in the Stripe dashboard is already done; the app's waits for `settleRefund`.
1952
+ status: input.origin === "dashboard" ? "succeeded" : "pending",
1953
+ failureReason: null,
1954
+ pendingReason: null,
1955
+ nextActionExpiresAt: null,
1956
+ refundRowId: input.refundRowId ?? null,
1957
+ appMetadata: input.appMetadata ?? {},
1958
+ reason: input.reason ?? null,
1959
+ origin: input.origin,
1960
+ revision: 0,
1961
+ created: Math.floor(Date.now() / 1e3)
1962
+ };
1963
+ state.stripeRefunds.set(refund.id, refund);
1964
+ syncAmountRefunded(input.intent);
1965
+ console.log(
1966
+ `[stardeck-testing] stripe refund ${refund.id} created payment=${refund.paymentIntentId} amount=${refund.amount} origin=${refund.origin}`
1967
+ );
1968
+ return refund;
1969
+ }
1970
+ function createStripeRefund(body, intent, projectId) {
1971
+ const scopedKey = JSON.stringify(["refund", projectId, intent.account, body.idempotencyKey]);
1972
+ const fingerprint = stableStringify({
1973
+ paymentIntentId: intent.id,
1974
+ amount: body.amount,
1975
+ reason: body.reason,
1976
+ instructionsEmail: body.instructionsEmail,
1977
+ refundRowId: body.refundRowId,
1978
+ metadata: body.metadata
1979
+ });
1980
+ const saved = state.stripeIdempotentRefunds.get(scopedKey);
1981
+ if (saved) {
1982
+ if (saved.fingerprint !== fingerprint) {
1983
+ return err(
1984
+ "This idempotency key was already used with different parameters. Use a new key for a different refund.",
1985
+ 409,
1986
+ "idempotency_conflict"
1987
+ );
1988
+ }
1989
+ return json({ refund: toStripeRefundSummary(state.stripeRefunds.get(saved.id)) });
1990
+ }
1991
+ const plan = planStripeRefund(intent, body.amount);
1992
+ if (!plan.ok) return refundFailure(plan);
1993
+ const refund = newStripeRefund({
1994
+ intent,
1995
+ amount: plan.amount,
1996
+ origin: "app",
1997
+ refundRowId: typeof body.refundRowId === "string" ? body.refundRowId : null,
1998
+ appMetadata: appMetadata(body.metadata),
1999
+ reason: typeof body.reason === "string" ? body.reason : null
2000
+ });
2001
+ state.stripeIdempotentRefunds.set(scopedKey, { fingerprint, id: refund.id });
2002
+ return json({ refund: toStripeRefundSummary(refund) });
2003
+ }
2004
+ var STRIPE_REFUND_PATH = /^\/api\/store\/(?!beam\/)[^/]+\/(?:payment-intents\/([^/]+)\/refunds|refunds\/([^/]+))$/;
2005
+ async function handleStripeRefundRequest(request, url, projectId) {
2006
+ const match = url.pathname.match(STRIPE_REFUND_PATH);
2007
+ if (!match) return null;
2008
+ const [, intentId, refundId] = match;
2009
+ const isCreate = request.method === "POST" && intentId !== void 0;
2010
+ const isRead = request.method === "GET" && refundId !== void 0;
2011
+ if (!isCreate && !isRead) return null;
2012
+ if (!projectId) return err("Missing authentication", 401, "unauthorized");
2013
+ if (isRead) {
2014
+ if (!url.searchParams.get("deploymentId")) {
2015
+ return err("deploymentId is required", 400, "invalid_request");
2016
+ }
2017
+ const refund = state.stripeRefunds.get(decode(refundId));
2018
+ if (!refund || refund.projectId !== projectId) {
2019
+ return err("Refund not found", 404, "refund_not_found");
2020
+ }
2021
+ return json({ refund: toStripeRefundSummary(refund) });
2022
+ }
2023
+ const body = await readJsonBody(request);
2024
+ const problem = validateStripeRefund(body);
2025
+ if (problem) return err(problem, 400, "invalid_request");
2026
+ const intent = ownedIntent(decode(intentId), projectId);
2027
+ if (!intent) return err("No such payment for this app", 404, "payment_not_owned");
2028
+ return createStripeRefund(body, intent, projectId);
2029
+ }
2030
+ function refundsOfCharge(chargeId) {
2031
+ return [...state.beamRefunds.values()].filter((r) => r.chargeId === chargeId);
2032
+ }
2033
+ function planBeamRefund(charge, requested) {
2034
+ if (charge.status !== "SUCCEEDED") {
2035
+ return {
2036
+ ok: false,
2037
+ status: 409,
2038
+ code: "payment_not_refundable",
2039
+ message: "This charge hasn't succeeded, so there is nothing to refund"
2040
+ };
2041
+ }
2042
+ const refunds = refundsOfCharge(charge.id);
2043
+ if (refunds.some((r) => r.status === "PENDING")) {
2044
+ return {
2045
+ ok: false,
2046
+ status: 409,
2047
+ code: "refund_in_progress",
2048
+ message: "This charge already has a refund in progress. Wait for it to finish."
2049
+ };
2050
+ }
2051
+ const refunded = refunds.filter((r) => r.status === "SUCCEEDED").reduce((n, r) => n + r.amount, 0);
2052
+ const remaining = charge.amount - refunded;
2053
+ const amount = requested ?? remaining;
2054
+ if (remaining <= 0 || amount > remaining) {
2055
+ return {
2056
+ ok: false,
2057
+ status: 409,
2058
+ code: "refund_exceeds_remaining",
2059
+ message: `Only ${remaining} can still be refunded on this charge`
2060
+ };
2061
+ }
2062
+ if (amount < charge.amount && !BEAM_PARTIAL_METHODS.includes(charge.paymentMethodType)) {
2063
+ return {
2064
+ ok: false,
2065
+ status: 409,
2066
+ code: "refund_partial_not_allowed",
2067
+ message: `${charge.paymentMethodType} charges can only be refunded in full`
2068
+ };
2069
+ }
2070
+ return { ok: true, amount };
2071
+ }
2072
+ function toBeamRefundSummary(refund) {
2073
+ return {
2074
+ refundId: refund.refundId,
2075
+ chargeId: refund.chargeId,
2076
+ amount: refund.amount,
2077
+ currency: refund.currency,
2078
+ status: refund.status,
2079
+ failureCode: refund.failureCode,
2080
+ reason: refund.reason,
2081
+ createdAt: refund.createdAt
2082
+ };
2083
+ }
2084
+ function newBeamRefund(input) {
2085
+ state.beamRefundCounter += 1;
2086
+ const refund = {
2087
+ refundId: `rf_sim_${state.beamRefundCounter}`,
2088
+ chargeId: input.charge.id,
2089
+ amount: input.amount,
2090
+ currency: input.charge.currency,
2091
+ status: input.origin === "dashboard" ? "SUCCEEDED" : "PENDING",
2092
+ failureCode: null,
2093
+ reason: input.reason ?? null,
2094
+ origin: input.origin,
2095
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
2096
+ };
2097
+ state.beamRefunds.set(refund.refundId, refund);
2098
+ console.log(
2099
+ `[stardeck-testing] beam refund ${refund.refundId} created charge=${refund.chargeId} amount=${refund.amount} origin=${refund.origin}`
2100
+ );
2101
+ return refund;
2102
+ }
2103
+ function validateBeamRefund(body) {
2104
+ const checks = [
2105
+ [isValidDeploymentId(body.deploymentId), "Invalid deployment ID"],
2106
+ [hasValidKey(body.idempotencyKey), "idempotencyKey is required (1 to 255 characters)"],
2107
+ [isOptional(body.amount, isPositiveInt), "amount must be a positive integer in satang"],
2108
+ [
2109
+ isOptional(body.reason, (v) => typeof v === "string" && v.length <= 500),
2110
+ "reason must be at most 500 characters"
2111
+ ]
2112
+ ];
2113
+ const failed = checks.find(([ok]) => !ok);
2114
+ return failed ? failed[1] : null;
2115
+ }
2116
+ function createBeamRefund(body, charge, merchant) {
2117
+ const scopedKey = JSON.stringify(["beam-refund", merchant, body.idempotencyKey]);
2118
+ const fingerprint = stableStringify({
2119
+ chargeId: charge.id,
2120
+ amount: body.amount,
2121
+ reason: body.reason
2122
+ });
2123
+ const saved = state.beamIdempotentRefunds.get(scopedKey);
2124
+ if (saved) {
2125
+ if (saved.fingerprint !== fingerprint) {
2126
+ return err(
2127
+ "This idempotency key was already used with different parameters. Use a new key for a different refund.",
2128
+ 409,
2129
+ "idempotency_conflict"
2130
+ );
2131
+ }
2132
+ return json({ refund: toBeamRefundSummary(state.beamRefunds.get(saved.id)) });
2133
+ }
2134
+ const plan = planBeamRefund(charge, body.amount);
2135
+ if (!plan.ok) return refundFailure(plan);
2136
+ const refund = newBeamRefund({
2137
+ charge,
2138
+ amount: plan.amount,
2139
+ origin: "app",
2140
+ reason: typeof body.reason === "string" ? body.reason : null
2141
+ });
2142
+ state.beamIdempotentRefunds.set(scopedKey, { fingerprint, id: refund.refundId });
2143
+ return json({ refund: toBeamRefundSummary(refund) });
2144
+ }
2145
+ var BEAM_REFUND_PATH = /^\/api\/store\/beam\/([^/]+)\/(?:charges\/([^/]+)\/refunds|refunds\/([^/]+))$/;
2146
+ async function handleBeamRefundRequest(request, url) {
2147
+ const match = url.pathname.match(BEAM_REFUND_PATH);
2148
+ if (!match) return null;
2149
+ const [, merchant, chargeId, refundId] = match;
2150
+ const isCreate = request.method === "POST" && chargeId !== void 0;
2151
+ const isRead = request.method === "GET" && refundId !== void 0;
2152
+ if (!isCreate && !isRead) return null;
2153
+ if (isRead) {
2154
+ if (!url.searchParams.get("deploymentId")) {
2155
+ return err("deploymentId is required", 400, "invalid_request");
2156
+ }
2157
+ const refund = state.beamRefunds.get(decode(refundId));
2158
+ if (!refund) return err("Refund not found", 404, "refund_not_found");
2159
+ return json({ refund: toBeamRefundSummary(refund) });
2160
+ }
2161
+ const body = await readJsonBody(request);
2162
+ const problem = validateBeamRefund(body);
2163
+ if (problem) return err(problem, 400, "invalid_request");
2164
+ const charge = state.directCharges.get(decode(chargeId));
2165
+ if (!charge) return err("No such charge for this app", 404, "payment_not_owned");
2166
+ return createBeamRefund(body, charge, decode(merchant));
2167
+ }
2168
+ function findCheckoutSessionByIntent(url, projectId) {
2169
+ if (!projectId) return err("Missing authentication", 401, "unauthorized");
2170
+ if (!url.searchParams.get("deploymentId")) {
2171
+ return err("deploymentId is required", 400, "invalid_request");
2172
+ }
2173
+ const intentId = url.searchParams.get("paymentIntentId");
2174
+ if (!intentId) return err("paymentIntentId is required", 400, "invalid_request");
2175
+ const intent = state.stripePaymentIntents.get(intentId);
2176
+ if (intent && intent.projectId !== projectId) return json({ session: null });
2177
+ const session = [...state.sessionStatuses.values()].find((s) => s.paymentIntentId === intentId);
2178
+ return json({ session: session ?? null });
2179
+ }
2180
+
1827
2181
  // src/simulator/webhook-signing.ts
1828
2182
  var import_node_crypto4 = __toESM(require("crypto"));
1829
2183
 
@@ -1869,6 +2223,15 @@ function paymentOperationForRequest(request, pathname) {
1869
2223
  if (request.method === "GET" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout-sessions\/[^/]+$/.test(pathname)) {
1870
2224
  return "stripe.getCheckoutSessionStatus";
1871
2225
  }
2226
+ if (request.method === "POST" && /^\/api\/store\/beam\/[^/]+\/charges\/[^/]+\/refunds$/.test(pathname)) {
2227
+ return "beam.refundCharge";
2228
+ }
2229
+ if (request.method === "GET" && /^\/api\/store\/beam\/[^/]+\/refunds\/[^/]+$/.test(pathname)) {
2230
+ return "beam.getRefund";
2231
+ }
2232
+ if (request.method === "GET" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout-sessions$/.test(pathname)) {
2233
+ return "stripe.findCheckoutSessionByIntent";
2234
+ }
1872
2235
  return stripeInlineOperation(request.method, pathname);
1873
2236
  }
1874
2237
  var STRIPE_INLINE_OPERATIONS = [
@@ -1880,6 +2243,12 @@ var STRIPE_INLINE_OPERATIONS = [
1880
2243
  /^\/api\/store\/(?!beam\/)[^/]+\/payment-intents\/[^/]+\/cancel$/,
1881
2244
  "stripe.cancelPaymentIntent"
1882
2245
  ],
2246
+ [
2247
+ "POST",
2248
+ /^\/api\/store\/(?!beam\/)[^/]+\/payment-intents\/[^/]+\/refunds$/,
2249
+ "stripe.refundPaymentIntent"
2250
+ ],
2251
+ ["GET", /^\/api\/store\/(?!beam\/)[^/]+\/refunds\/[^/]+$/, "stripe.getRefund"],
1883
2252
  ["GET", /^\/api\/store\/(?!beam\/)[^/]+\/elements-config$/, "stripe.getElementsConfig"],
1884
2253
  ["GET", /^\/api\/store\/(?!beam\/)[^/]+\/readiness$/, "stripe.getReadiness"]
1885
2254
  ];
@@ -1960,7 +2329,8 @@ function seedStripeSession(id, body, expiresAt) {
1960
2329
  currency,
1961
2330
  customerEmail: body.customerEmail ? String(body.customerEmail) : null,
1962
2331
  metadata: body.metadata ?? {},
1963
- expiresAt
2332
+ expiresAt,
2333
+ paymentIntentId: null
1964
2334
  });
1965
2335
  }
1966
2336
  function seedBeamLink(id, body, merchantId) {
@@ -2035,6 +2405,10 @@ async function handlePaymentsRequest(request, url, signedProjectId = null) {
2035
2405
  signedProjectId
2036
2406
  );
2037
2407
  if (inlineStripeResponse) return inlineStripeResponse;
2408
+ const stripeRefundResponse = await handleStripeRefundRequest(request, url, signedProjectId);
2409
+ if (stripeRefundResponse) return stripeRefundResponse;
2410
+ const beamRefundResponse = await handleBeamRefundRequest(request, url);
2411
+ if (beamRefundResponse) return beamRefundResponse;
2038
2412
  const directChargeResponse = await handleDirectChargeRequest(request, pathname);
2039
2413
  if (directChargeResponse) return directChargeResponse;
2040
2414
  if (/\/billing-portal$/.test(pathname)) {
@@ -2356,6 +2730,9 @@ async function handlePaymentsRequest(request, url, signedProjectId = null) {
2356
2730
  if (scopedKey) state.idempotentCheckouts.set(scopedKey, { fingerprint, response });
2357
2731
  return json(response);
2358
2732
  }
2733
+ if (subPath === "checkout-sessions" && request.method === "GET") {
2734
+ return findCheckoutSessionByIntent(url, signedProjectId);
2735
+ }
2359
2736
  const sessionMatch = subPath.match(/^checkout-sessions\/([^/]+)$/);
2360
2737
  if (sessionMatch && request.method === "GET") {
2361
2738
  const session = state.sessionStatuses.get(sessionMatch[1]);