@stardeck-customer-apps/testing 0.21.0 → 0.22.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.
- package/SKILL.md +22 -3
- package/dist/index.d.mts +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +360 -2
- package/dist/index.mjs +360 -2
- package/dist/next/headers-shim.js +5 -0
- package/dist/next/headers-shim.mjs +5 -0
- package/dist/setup.js +309 -2
- package/dist/setup.mjs +309 -2
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -309,6 +309,11 @@ var state = globalSingleton("state", () => ({
|
|
|
309
309
|
boltIntentCounter: 0,
|
|
310
310
|
boltCharges: [],
|
|
311
311
|
boltChargeCounter: 0,
|
|
312
|
+
directCharges: /* @__PURE__ */ new Map(),
|
|
313
|
+
directChargeCounter: 0,
|
|
314
|
+
cardTokens: /* @__PURE__ */ new Map(),
|
|
315
|
+
cardTokenCounter: 0,
|
|
316
|
+
cardTokenizationEnabled: true,
|
|
312
317
|
uploads: [],
|
|
313
318
|
uploadCounter: 0,
|
|
314
319
|
storageFiles: /* @__PURE__ */ new Map(),
|
|
@@ -1676,6 +1681,311 @@ function createDirectory() {
|
|
|
1676
1681
|
};
|
|
1677
1682
|
}
|
|
1678
1683
|
|
|
1684
|
+
// src/simulator/beam-direct-charges.ts
|
|
1685
|
+
var SIM_BEAM_HOST = "beam.stardeck.test";
|
|
1686
|
+
var SIM_BEAM_MERCHANT_ID = "sim_merchant";
|
|
1687
|
+
var SIM_BEAM_PUBLISHABLE_KEY = "pk_test_sim";
|
|
1688
|
+
var DIRECT_CHARGE_METHODS = /* @__PURE__ */ new Set([
|
|
1689
|
+
"CARD",
|
|
1690
|
+
"CARD_INSTALLMENTS",
|
|
1691
|
+
"CARD_TOKEN",
|
|
1692
|
+
"CARD_TOKEN_INSTALLMENTS",
|
|
1693
|
+
"QR_PROMPT_PAY",
|
|
1694
|
+
"ALIPAY",
|
|
1695
|
+
"ALIPAY_PLUS",
|
|
1696
|
+
"WECHAT_PAY",
|
|
1697
|
+
"TRUE_MONEY",
|
|
1698
|
+
"LINE_PAY",
|
|
1699
|
+
"SHOPEE_PAY",
|
|
1700
|
+
"KPLUS",
|
|
1701
|
+
"MAKE",
|
|
1702
|
+
"SCB_EASY",
|
|
1703
|
+
"KRUNGSRI_APP",
|
|
1704
|
+
"BANGKOK_BANK_APP",
|
|
1705
|
+
"SPAY_LATER"
|
|
1706
|
+
]);
|
|
1707
|
+
var TEST_CARDS = {
|
|
1708
|
+
"4111111111111111": { outcome: "SUCCEEDED" },
|
|
1709
|
+
"5372074248113841": { outcome: "SUCCEEDED" },
|
|
1710
|
+
"378282246310005": { outcome: "SUCCEEDED" },
|
|
1711
|
+
"4953261730509988": { outcome: "REDIRECT" },
|
|
1712
|
+
"4389783280144506": { outcome: "REDIRECT" },
|
|
1713
|
+
"4943129900084541": { outcome: "FAILED", failureCode: "CH_INSUFFICIENT_FUNDS" },
|
|
1714
|
+
"4111111111000025": { outcome: "FAILED", failureCode: "CH_CARD_DECLINED" },
|
|
1715
|
+
"4111111111000033": { outcome: "FAILED", failureCode: "CH_CARD_RESTRICTED" }
|
|
1716
|
+
};
|
|
1717
|
+
var SIM_QR_PNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
|
|
1718
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1719
|
+
function invalid(issues) {
|
|
1720
|
+
return json({ error: "Invalid request body", details: issues }, 400);
|
|
1721
|
+
}
|
|
1722
|
+
var DEVICE_TYPES = /* @__PURE__ */ new Set(["ANDROID", "IOS", "WEB"]);
|
|
1723
|
+
function issue(path, message, code = "custom") {
|
|
1724
|
+
return { path, message, code };
|
|
1725
|
+
}
|
|
1726
|
+
function validateChargeFields(body) {
|
|
1727
|
+
const issues = [];
|
|
1728
|
+
const isInt = (v) => typeof v === "number" && Number.isInteger(v);
|
|
1729
|
+
if (!isInt(body.amount) || body.amount < 1) {
|
|
1730
|
+
issues.push(issue(["amount"], "Number must be greater than 0", "too_small"));
|
|
1731
|
+
}
|
|
1732
|
+
if (typeof body.deploymentId !== "string" || !UUID_RE.test(body.deploymentId)) {
|
|
1733
|
+
issues.push(issue(["deploymentId"], "Invalid deployment ID", "invalid_string"));
|
|
1734
|
+
}
|
|
1735
|
+
if (body.referenceId !== void 0 && (typeof body.referenceId !== "string" || body.referenceId.length > 100)) {
|
|
1736
|
+
issues.push(issue(["referenceId"], "Too long", "too_big"));
|
|
1737
|
+
}
|
|
1738
|
+
const expiry = body.expiryDurationInSec;
|
|
1739
|
+
if (expiry !== void 0 && (!isInt(expiry) || expiry < 60 || expiry > 3600)) {
|
|
1740
|
+
issues.push(issue(["expiryDurationInSec"], "Must be an integer from 60 to 3600", "too_big"));
|
|
1741
|
+
}
|
|
1742
|
+
if (body.returnUrl !== void 0 && (typeof body.returnUrl !== "string" || !URL.canParse(body.returnUrl))) {
|
|
1743
|
+
issues.push(issue(["returnUrl"], "Invalid URL", "invalid_format"));
|
|
1744
|
+
}
|
|
1745
|
+
if (body.deviceType !== void 0 && !DEVICE_TYPES.has(String(body.deviceType))) {
|
|
1746
|
+
issues.push(issue(["deviceType"], "Invalid enum value", "invalid_value"));
|
|
1747
|
+
}
|
|
1748
|
+
const key = body.idempotencyKey;
|
|
1749
|
+
if (key !== void 0 && (typeof key !== "string" || key.length < 1 || key.length > 255)) {
|
|
1750
|
+
issues.push(issue(["idempotencyKey"], "Must be 1 to 255 characters", "too_small"));
|
|
1751
|
+
}
|
|
1752
|
+
return issues;
|
|
1753
|
+
}
|
|
1754
|
+
function validateChargeMethod(body) {
|
|
1755
|
+
const method = body.paymentMethod;
|
|
1756
|
+
const type = method?.paymentMethodType;
|
|
1757
|
+
if (typeof type !== "string" || !DIRECT_CHARGE_METHODS.has(type)) {
|
|
1758
|
+
return [issue(["paymentMethod", "paymentMethodType"], "Invalid enum value", "invalid_value")];
|
|
1759
|
+
}
|
|
1760
|
+
const issues = [];
|
|
1761
|
+
const isToken = type === "CARD_TOKEN" || type === "CARD_TOKEN_INSTALLMENTS";
|
|
1762
|
+
const token = method?.cardToken;
|
|
1763
|
+
if (isToken && (typeof token?.cardTokenId !== "string" || token.cardTokenId === "")) {
|
|
1764
|
+
issues.push(
|
|
1765
|
+
issue(["paymentMethod", "cardToken"], `${type} requires paymentMethod.cardToken.cardTokenId`)
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
if (token?.securityCode !== void 0 && !/^\d{3,4}$/.test(String(token.securityCode))) {
|
|
1769
|
+
issues.push(
|
|
1770
|
+
issue(
|
|
1771
|
+
["paymentMethod", "cardToken", "securityCode"],
|
|
1772
|
+
"Invalid security code",
|
|
1773
|
+
"invalid_format"
|
|
1774
|
+
)
|
|
1775
|
+
);
|
|
1776
|
+
}
|
|
1777
|
+
if (type === "CARD_TOKEN_INSTALLMENTS" && ![3, 4, 6, 10].includes(method?.installmentPeriod)) {
|
|
1778
|
+
issues.push(
|
|
1779
|
+
issue(
|
|
1780
|
+
["paymentMethod", "installmentPeriod"],
|
|
1781
|
+
"CARD_TOKEN_INSTALLMENTS requires paymentMethod.installmentPeriod (3, 4, 6 or 10)"
|
|
1782
|
+
)
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
if (type !== "QR_PROMPT_PAY" && !body.returnUrl) {
|
|
1786
|
+
issues.push(
|
|
1787
|
+
issue(
|
|
1788
|
+
["returnUrl"],
|
|
1789
|
+
`${type} sends the shopper away to pay; returnUrl is required to bring them back`
|
|
1790
|
+
)
|
|
1791
|
+
);
|
|
1792
|
+
}
|
|
1793
|
+
if (type === "CARD" || type === "CARD_INSTALLMENTS") {
|
|
1794
|
+
issues.push(
|
|
1795
|
+
issue(
|
|
1796
|
+
["paymentMethod", "paymentMethodType"],
|
|
1797
|
+
`${type} takes raw card data; tokenize the card in the browser and charge CARD_TOKEN instead`
|
|
1798
|
+
)
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
return issues;
|
|
1802
|
+
}
|
|
1803
|
+
function validateDirectCharge(body) {
|
|
1804
|
+
return [...validateChargeFields(body), ...validateChargeMethod(body)];
|
|
1805
|
+
}
|
|
1806
|
+
function chargeResponse(charge) {
|
|
1807
|
+
const response = {
|
|
1808
|
+
chargeId: charge.id,
|
|
1809
|
+
actionRequired: charge.actionRequired,
|
|
1810
|
+
paymentMethodType: charge.paymentMethodType
|
|
1811
|
+
};
|
|
1812
|
+
if (charge.actionRequired === "ENCODED_IMAGE") {
|
|
1813
|
+
response.encodedImage = {
|
|
1814
|
+
imageBase64Encoded: SIM_QR_PNG,
|
|
1815
|
+
rawData: `00020101021230SIM${charge.id}`,
|
|
1816
|
+
expiry: charge.expiresAt
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
if (charge.actionRequired === "REDIRECT") {
|
|
1820
|
+
response.redirect = { redirectUrl: charge.redirectUrl };
|
|
1821
|
+
response.redirectUrl = charge.redirectUrl;
|
|
1822
|
+
}
|
|
1823
|
+
return response;
|
|
1824
|
+
}
|
|
1825
|
+
function nextChargeId() {
|
|
1826
|
+
state.directChargeCounter += 1;
|
|
1827
|
+
return `ch_sim_${state.directChargeCounter}`;
|
|
1828
|
+
}
|
|
1829
|
+
function createCharge(body) {
|
|
1830
|
+
const method = body.paymentMethod;
|
|
1831
|
+
const type = method.paymentMethodType;
|
|
1832
|
+
const id = nextChargeId();
|
|
1833
|
+
const now3 = /* @__PURE__ */ new Date();
|
|
1834
|
+
const expirySec = typeof body.expiryDurationInSec === "number" ? body.expiryDurationInSec : 30 * 60;
|
|
1835
|
+
const returnUrl = typeof body.returnUrl === "string" ? body.returnUrl : null;
|
|
1836
|
+
let actionRequired = "REDIRECT";
|
|
1837
|
+
let status = "PENDING";
|
|
1838
|
+
let failureCode = null;
|
|
1839
|
+
let cardLast4 = null;
|
|
1840
|
+
if (type === "QR_PROMPT_PAY") {
|
|
1841
|
+
actionRequired = "ENCODED_IMAGE";
|
|
1842
|
+
} else if (type === "CARD_TOKEN" || type === "CARD_TOKEN_INSTALLMENTS") {
|
|
1843
|
+
const token = state.cardTokens.get(method.cardToken.cardTokenId);
|
|
1844
|
+
if (!token) {
|
|
1845
|
+
return json({ error: "Card token not found", code: "CARD_TOKEN_NOT_FOUND" }, 404);
|
|
1846
|
+
}
|
|
1847
|
+
cardLast4 = token.last4;
|
|
1848
|
+
const card = TEST_CARDS[token.pan] ?? {
|
|
1849
|
+
outcome: "FAILED",
|
|
1850
|
+
failureCode: "CH_PROCESSING_FAILED"
|
|
1851
|
+
};
|
|
1852
|
+
if (card.outcome === "REDIRECT") {
|
|
1853
|
+
actionRequired = "REDIRECT";
|
|
1854
|
+
} else {
|
|
1855
|
+
actionRequired = "NONE";
|
|
1856
|
+
status = card.outcome;
|
|
1857
|
+
failureCode = card.failureCode ?? null;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
const charge = {
|
|
1861
|
+
id,
|
|
1862
|
+
status,
|
|
1863
|
+
amount: body.amount,
|
|
1864
|
+
currency: String(body.currency ?? "THB"),
|
|
1865
|
+
paymentMethodType: type,
|
|
1866
|
+
referenceId: typeof body.referenceId === "string" ? body.referenceId : null,
|
|
1867
|
+
deviceType: typeof body.deviceType === "string" ? body.deviceType : null,
|
|
1868
|
+
returnUrl,
|
|
1869
|
+
actionRequired,
|
|
1870
|
+
redirectUrl: actionRequired === "REDIRECT" ? `https://${SIM_BEAM_HOST}/pay/${id}${returnUrl ? `?returnUrl=${encodeURIComponent(returnUrl)}` : ""}` : null,
|
|
1871
|
+
expiresAt: new Date(now3.getTime() + expirySec * 1e3).toISOString(),
|
|
1872
|
+
failureCode,
|
|
1873
|
+
cardLast4,
|
|
1874
|
+
idempotencyKey: typeof body.idempotencyKey === "string" ? body.idempotencyKey : null,
|
|
1875
|
+
createdAt: now3.toISOString()
|
|
1876
|
+
};
|
|
1877
|
+
state.directCharges.set(id, charge);
|
|
1878
|
+
return charge;
|
|
1879
|
+
}
|
|
1880
|
+
async function handleDirectChargeRequest(request, pathname) {
|
|
1881
|
+
if (request.method === "POST" && /^\/api\/store\/beam\/[^/]+\/charges$/.test(pathname)) {
|
|
1882
|
+
const body = await readJsonBody(request);
|
|
1883
|
+
const issues = validateDirectCharge(body);
|
|
1884
|
+
if (issues.length > 0) return invalid(issues);
|
|
1885
|
+
const key = typeof body.idempotencyKey === "string" ? body.idempotencyKey : null;
|
|
1886
|
+
if (key) {
|
|
1887
|
+
const existing = [...state.directCharges.values()].find((c) => c.idempotencyKey === key);
|
|
1888
|
+
if (existing) return json(chargeResponse(existing));
|
|
1889
|
+
}
|
|
1890
|
+
const created = createCharge(body);
|
|
1891
|
+
if (created instanceof Response) return created;
|
|
1892
|
+
return json(chargeResponse(created));
|
|
1893
|
+
}
|
|
1894
|
+
const getMatch = pathname.match(/^\/api\/store\/beam\/[^/]+\/charges\/([^/]+)$/);
|
|
1895
|
+
if (request.method === "GET" && getMatch) {
|
|
1896
|
+
const charge = state.directCharges.get(decodeURIComponent(getMatch[1]));
|
|
1897
|
+
if (!charge) return json({ error: "Charge not found", code: "NOT_FOUND" }, 404);
|
|
1898
|
+
return json({ charge: toChargeDetail(charge) });
|
|
1899
|
+
}
|
|
1900
|
+
if (request.method === "GET" && /^\/api\/store\/beam\/[^/]+\/card-tokenization$/.test(pathname)) {
|
|
1901
|
+
if (!state.cardTokenizationEnabled) {
|
|
1902
|
+
return json(
|
|
1903
|
+
{
|
|
1904
|
+
error: "Add the Beam publishable key to this merchant account to take cards in your own checkout",
|
|
1905
|
+
code: "CARD_TOKENIZATION_NOT_CONFIGURED"
|
|
1906
|
+
},
|
|
1907
|
+
409
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
return json({
|
|
1911
|
+
merchantId: SIM_BEAM_MERCHANT_ID,
|
|
1912
|
+
publishableKey: SIM_BEAM_PUBLISHABLE_KEY,
|
|
1913
|
+
tokenizeUrl: `https://${SIM_BEAM_HOST}/client/v1/card-tokens`,
|
|
1914
|
+
isSandbox: true
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
return null;
|
|
1918
|
+
}
|
|
1919
|
+
function toChargeDetail(charge) {
|
|
1920
|
+
return {
|
|
1921
|
+
id: charge.id,
|
|
1922
|
+
chargeId: charge.id,
|
|
1923
|
+
status: charge.status,
|
|
1924
|
+
amount: charge.amount,
|
|
1925
|
+
currency: charge.currency,
|
|
1926
|
+
paymentMethodType: charge.paymentMethodType,
|
|
1927
|
+
...charge.referenceId !== null ? { referenceId: charge.referenceId } : {},
|
|
1928
|
+
...charge.failureCode ? { failureCode: charge.failureCode } : {},
|
|
1929
|
+
source: "API",
|
|
1930
|
+
createdAt: charge.createdAt
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
async function handleCardTokenRequest(request, url) {
|
|
1934
|
+
if (request.method !== "POST" || url.pathname !== "/client/v1/card-tokens") {
|
|
1935
|
+
return json({ error: `No Beam simulator for ${request.method} ${url.pathname}` }, 404);
|
|
1936
|
+
}
|
|
1937
|
+
const expected = `Basic ${btoa(`${SIM_BEAM_MERCHANT_ID}:${SIM_BEAM_PUBLISHABLE_KEY}`)}`;
|
|
1938
|
+
if (request.headers.get("Authorization") !== expected) {
|
|
1939
|
+
return json(
|
|
1940
|
+
{
|
|
1941
|
+
message: "invalid credentials",
|
|
1942
|
+
error: { errorCode: "INVALID_CREDENTIALS_ERROR", errorMessage: "invalid credentials" }
|
|
1943
|
+
},
|
|
1944
|
+
401
|
|
1945
|
+
);
|
|
1946
|
+
}
|
|
1947
|
+
const body = await readJsonBody(request);
|
|
1948
|
+
const pan = typeof body.pan === "string" ? body.pan : "";
|
|
1949
|
+
const month = body.expiryMonth;
|
|
1950
|
+
const year = body.expiryYear;
|
|
1951
|
+
if (!/^\d{12,19}$/.test(pan) || typeof month !== "number" || month < 1 || month > 12 || typeof year !== "number" || year < 0 || year > 99) {
|
|
1952
|
+
return json(
|
|
1953
|
+
{
|
|
1954
|
+
message: "inputs are failing validation",
|
|
1955
|
+
error: {
|
|
1956
|
+
errorCode: "API_VALIDATION_ERROR",
|
|
1957
|
+
errorMessage: "inputs are failing validation"
|
|
1958
|
+
}
|
|
1959
|
+
},
|
|
1960
|
+
400
|
|
1961
|
+
);
|
|
1962
|
+
}
|
|
1963
|
+
state.cardTokenCounter += 1;
|
|
1964
|
+
const token = {
|
|
1965
|
+
id: `ctok_sim_${state.cardTokenCounter}`,
|
|
1966
|
+
pan,
|
|
1967
|
+
last4: pan.slice(-4),
|
|
1968
|
+
expiryMonth: month,
|
|
1969
|
+
expiryYear: year
|
|
1970
|
+
};
|
|
1971
|
+
state.cardTokens.set(token.id, token);
|
|
1972
|
+
return json({ id: token.id });
|
|
1973
|
+
}
|
|
1974
|
+
function chargeWebhookPayload(charge) {
|
|
1975
|
+
return {
|
|
1976
|
+
chargeId: charge.id,
|
|
1977
|
+
merchantId: SIM_BEAM_MERCHANT_ID,
|
|
1978
|
+
...charge.referenceId !== null ? { referenceId: charge.referenceId } : {},
|
|
1979
|
+
status: charge.status,
|
|
1980
|
+
currency: charge.currency,
|
|
1981
|
+
amount: charge.amount,
|
|
1982
|
+
source: "API",
|
|
1983
|
+
sourceId: charge.id,
|
|
1984
|
+
...charge.failureCode ? { failureCode: charge.failureCode } : {},
|
|
1985
|
+
paymentMethod: { paymentMethodType: charge.paymentMethodType }
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1679
1989
|
// src/simulator/payments.ts
|
|
1680
1990
|
import crypto5 from "crypto";
|
|
1681
1991
|
|
|
@@ -1790,7 +2100,7 @@ var BEAM_BOLT_PAYMENT_METHODS = [
|
|
|
1790
2100
|
"SPAY_LATER"
|
|
1791
2101
|
];
|
|
1792
2102
|
var BEAM_BOLT_INTENT_STATUSES = ["PENDING", "PAID", "FAILED", "CANCELED", "EXPIRED"];
|
|
1793
|
-
var
|
|
2103
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1794
2104
|
function payErr(error, status = 400, code, details) {
|
|
1795
2105
|
const body = { error };
|
|
1796
2106
|
if (code) body.code = code;
|
|
@@ -1804,6 +2114,12 @@ function paymentOperationForRequest(request, pathname) {
|
|
|
1804
2114
|
if (request.method === "GET" && /^\/api\/store\/beam\/[^/]+\/payment-links\/[^/]+$/.test(pathname)) {
|
|
1805
2115
|
return "beam.getPaymentLinkStatus";
|
|
1806
2116
|
}
|
|
2117
|
+
if (request.method === "POST" && /^\/api\/store\/beam\/[^/]+\/charges$/.test(pathname)) {
|
|
2118
|
+
return "beam.createDirectCharge";
|
|
2119
|
+
}
|
|
2120
|
+
if (request.method === "GET" && /^\/api\/store\/beam\/[^/]+\/charges\/[^/]+$/.test(pathname)) {
|
|
2121
|
+
return "beam.getCharge";
|
|
2122
|
+
}
|
|
1807
2123
|
if (request.method === "POST" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout$/.test(pathname)) {
|
|
1808
2124
|
return "stripe.createCheckout";
|
|
1809
2125
|
}
|
|
@@ -1979,6 +2295,8 @@ async function handlePaymentsRequest(request, url) {
|
|
|
1979
2295
|
const pathname = url.pathname;
|
|
1980
2296
|
const injectedFailure = consumePaymentFailure(request, pathname);
|
|
1981
2297
|
if (injectedFailure) return injectedFailure;
|
|
2298
|
+
const directChargeResponse = await handleDirectChargeRequest(request, pathname);
|
|
2299
|
+
if (directChargeResponse) return directChargeResponse;
|
|
1982
2300
|
if (/\/billing-portal$/.test(pathname)) {
|
|
1983
2301
|
return payErr("Not found", 404, "NOT_FOUND");
|
|
1984
2302
|
}
|
|
@@ -2075,7 +2393,7 @@ async function handlePaymentsRequest(request, url) {
|
|
|
2075
2393
|
code: "too_small"
|
|
2076
2394
|
});
|
|
2077
2395
|
}
|
|
2078
|
-
if (typeof body.deploymentId !== "string" || !
|
|
2396
|
+
if (typeof body.deploymentId !== "string" || !UUID_RE2.test(body.deploymentId)) {
|
|
2079
2397
|
issues.push({
|
|
2080
2398
|
path: ["deploymentId"],
|
|
2081
2399
|
message: "Invalid uuid",
|
|
@@ -2262,6 +2580,18 @@ async function handlePaymentsRequest(request, url) {
|
|
|
2262
2580
|
}
|
|
2263
2581
|
return payErr(`No payments simulator for ${request.method} ${pathname}`, 404);
|
|
2264
2582
|
}
|
|
2583
|
+
function requirePendingDirectCharge(chargeId) {
|
|
2584
|
+
const charge = state.directCharges.get(chargeId);
|
|
2585
|
+
if (!charge) {
|
|
2586
|
+
throw new Error(`[stardeck-testing] Unknown direct charge id: ${chargeId}`);
|
|
2587
|
+
}
|
|
2588
|
+
if (charge.status !== "PENDING") {
|
|
2589
|
+
throw new Error(
|
|
2590
|
+
`[stardeck-testing] Direct charge ${chargeId} is ${charge.status}, not PENDING`
|
|
2591
|
+
);
|
|
2592
|
+
}
|
|
2593
|
+
return charge;
|
|
2594
|
+
}
|
|
2265
2595
|
function createPayments() {
|
|
2266
2596
|
return {
|
|
2267
2597
|
get checkouts() {
|
|
@@ -2380,6 +2710,26 @@ function createPayments() {
|
|
|
2380
2710
|
if (!intent) return void 0;
|
|
2381
2711
|
return toBoltIntentRecord(intent);
|
|
2382
2712
|
},
|
|
2713
|
+
get directCharges() {
|
|
2714
|
+
return [...state.directCharges.values()];
|
|
2715
|
+
},
|
|
2716
|
+
getDirectCharge(chargeId) {
|
|
2717
|
+
return state.directCharges.get(chargeId);
|
|
2718
|
+
},
|
|
2719
|
+
completeDirectCharge(chargeId) {
|
|
2720
|
+
const charge = requirePendingDirectCharge(chargeId);
|
|
2721
|
+
charge.status = "SUCCEEDED";
|
|
2722
|
+
return chargeWebhookPayload(charge);
|
|
2723
|
+
},
|
|
2724
|
+
failDirectCharge(chargeId, failureCode = "CH_PROCESSING_FAILED") {
|
|
2725
|
+
const charge = requirePendingDirectCharge(chargeId);
|
|
2726
|
+
charge.status = "FAILED";
|
|
2727
|
+
charge.failureCode = failureCode;
|
|
2728
|
+
return chargeWebhookPayload(charge);
|
|
2729
|
+
},
|
|
2730
|
+
setCardTokenization(enabled) {
|
|
2731
|
+
state.cardTokenizationEnabled = enabled;
|
|
2732
|
+
},
|
|
2383
2733
|
clear() {
|
|
2384
2734
|
state.checkouts = [];
|
|
2385
2735
|
state.checkoutCounter = 0;
|
|
@@ -2394,6 +2744,11 @@ function createPayments() {
|
|
|
2394
2744
|
state.boltIntentCounter = 0;
|
|
2395
2745
|
state.boltCharges = [];
|
|
2396
2746
|
state.boltChargeCounter = 0;
|
|
2747
|
+
state.directCharges.clear();
|
|
2748
|
+
state.directChargeCounter = 0;
|
|
2749
|
+
state.cardTokens.clear();
|
|
2750
|
+
state.cardTokenCounter = 0;
|
|
2751
|
+
state.cardTokenizationEnabled = true;
|
|
2397
2752
|
},
|
|
2398
2753
|
get count() {
|
|
2399
2754
|
return state.checkouts.length;
|
|
@@ -3273,6 +3628,9 @@ async function handleSimulatedRequest(request, url) {
|
|
|
3273
3628
|
if (isStorageHost) {
|
|
3274
3629
|
return handleStorageRequest(request, url);
|
|
3275
3630
|
}
|
|
3631
|
+
if (url.hostname === SIM_BEAM_HOST) {
|
|
3632
|
+
return handleCardTokenRequest(request, url);
|
|
3633
|
+
}
|
|
3276
3634
|
if (isEmail && request.method === "POST") {
|
|
3277
3635
|
return handleEmailSend(request);
|
|
3278
3636
|
}
|
|
@@ -70,6 +70,11 @@ var state = globalSingleton("state", () => ({
|
|
|
70
70
|
boltIntentCounter: 0,
|
|
71
71
|
boltCharges: [],
|
|
72
72
|
boltChargeCounter: 0,
|
|
73
|
+
directCharges: /* @__PURE__ */ new Map(),
|
|
74
|
+
directChargeCounter: 0,
|
|
75
|
+
cardTokens: /* @__PURE__ */ new Map(),
|
|
76
|
+
cardTokenCounter: 0,
|
|
77
|
+
cardTokenizationEnabled: true,
|
|
73
78
|
uploads: [],
|
|
74
79
|
uploadCounter: 0,
|
|
75
80
|
storageFiles: /* @__PURE__ */ new Map(),
|
|
@@ -43,6 +43,11 @@ var state = globalSingleton("state", () => ({
|
|
|
43
43
|
boltIntentCounter: 0,
|
|
44
44
|
boltCharges: [],
|
|
45
45
|
boltChargeCounter: 0,
|
|
46
|
+
directCharges: /* @__PURE__ */ new Map(),
|
|
47
|
+
directChargeCounter: 0,
|
|
48
|
+
cardTokens: /* @__PURE__ */ new Map(),
|
|
49
|
+
cardTokenCounter: 0,
|
|
50
|
+
cardTokenizationEnabled: true,
|
|
46
51
|
uploads: [],
|
|
47
52
|
uploadCounter: 0,
|
|
48
53
|
storageFiles: /* @__PURE__ */ new Map(),
|