@crvouga/mockingbird-service-stripe 2.2.0 → 2.2.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/CHANGELOG.md +9 -1
- package/README.md +6 -1
- package/dist/{chunk-PNBTN2AA.js → chunk-4G5L7P7I.js} +2 -2
- package/dist/{chunk-CHK6KZV4.js → chunk-7ZVXTTT4.js} +157 -20
- package/dist/{chunk-CHK6KZV4.js.map → chunk-7ZVXTTT4.js.map} +2 -2
- package/dist/cli.js +2 -2
- package/dist/index.js +1 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- /package/dist/{chunk-PNBTN2AA.js.map → chunk-4G5L7P7I.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-stripe
|
|
2
2
|
|
|
3
|
-
## 2.2.
|
|
3
|
+
## 2.2.1 (2026-10-05)
|
|
4
|
+
|
|
5
|
+
### Fixes and improvements
|
|
6
|
+
|
|
7
|
+
- validate card element input ([d53f042](https://github.com/crvouga/mockingbird/commit/d53f042089ee20b2708b489e5412065013309a55))
|
|
8
|
+
- reject empty customer account filters ([b7910c7](https://github.com/crvouga/mockingbird/commit/b7910c73ad24fb1ae6767fc83effce76bfd09eaa))
|
|
9
|
+
- render split card elements independently ([99e9a5d](https://github.com/crvouga/mockingbird/commit/99e9a5d82f9189ca5d347ff5d071d05f2d9fbf21))
|
|
10
|
+
|
|
11
|
+
## 2.2.0 (2026-10-04)
|
|
4
12
|
|
|
5
13
|
### Features
|
|
6
14
|
|
package/README.md
CHANGED
|
@@ -252,7 +252,12 @@ finalize; a customer credit balance is applied at finalize; `void` works only on
|
|
|
252
252
|
payment mode, inactive prices, mixed currencies, quantities below 1, `trial_end` under 48 h.
|
|
253
253
|
- `POST /__admin/checkout/sessions/:id/complete {"card": "4242…"}` does the same without a browser;
|
|
254
254
|
`…/expire` and `…/async_payment_succeeded` too.
|
|
255
|
-
- `GET /v3` — the Stripe.js stand-in: `Stripe(pk)`, `elements()` → `create("payment"|"card")
|
|
255
|
+
- `GET /v3` — the Stripe.js stand-in: `Stripe(pk)`, `elements()` → combined `create("payment"|"card")`
|
|
256
|
+
or split `create("cardNumber"|"cardExpiry"|"cardCvc")` inputs. Split inputs share card data
|
|
257
|
+
within their `Elements` group, add no visible labels, and the combined card honors
|
|
258
|
+
`hidePostalCode`. Card inputs format number/expiry/CVC values, report field-level `empty`,
|
|
259
|
+
`complete`, `brand`, and validation errors through change events, and refuse tokenization until
|
|
260
|
+
all required split or combined values are valid. It also provides
|
|
256
261
|
`confirmPayment`, `confirmSetup`, `confirmCardPayment`, `confirmCardSetup`,
|
|
257
262
|
`retrievePaymentIntent`, `retrieveSetupIntent`, `createPaymentMethod`, `handleCardAction`. It calls
|
|
258
263
|
`POST /v1/{payment,setup}_intents/:id/confirm` with the publishable key and `client_secret` (the
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
parseDuration,
|
|
5
5
|
resolveAdminPrefix,
|
|
6
6
|
validateAccounts
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7ZVXTTT4.js";
|
|
8
8
|
|
|
9
9
|
// src/server.ts
|
|
10
10
|
import { readFileSync } from "node:fs";
|
|
@@ -874,4 +874,4 @@ export {
|
|
|
874
874
|
createServer2 as createServer,
|
|
875
875
|
serveTarget
|
|
876
876
|
};
|
|
877
|
-
//# sourceMappingURL=chunk-
|
|
877
|
+
//# sourceMappingURL=chunk-4G5L7P7I.js.map
|
|
@@ -2337,7 +2337,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
2337
2337
|
};
|
|
2338
2338
|
|
|
2339
2339
|
// ../core/dist/version.js
|
|
2340
|
-
var PACKAGE_VERSION = true ? "2.2.
|
|
2340
|
+
var PACKAGE_VERSION = true ? "2.2.1" : UNRELEASED_VERSION;
|
|
2341
2341
|
|
|
2342
2342
|
// ../core/dist/signing.js
|
|
2343
2343
|
var encoder = new TextEncoder();
|
|
@@ -11817,9 +11817,120 @@ var stripeJs = (base2) => `/* Mockingbird Stripe.js stand-in */
|
|
|
11817
11817
|
["cvc", "CVC", "stripe-mock-cvc", "123"],
|
|
11818
11818
|
["zip", "ZIP", "stripe-mock-zip", "94107"],
|
|
11819
11819
|
];
|
|
11820
|
-
function
|
|
11820
|
+
function fieldsFor(type, options) {
|
|
11821
|
+
var names = type === "cardNumber" ? ["card"]
|
|
11822
|
+
: type === "cardExpiry" ? ["exp"]
|
|
11823
|
+
: type === "cardCvc" ? ["cvc"]
|
|
11824
|
+
: type === "postalCode" ? ["zip"]
|
|
11825
|
+
: FIELDS.map(function (field) { return field[0]; });
|
|
11826
|
+
if (type === "card" && options && options.hidePostalCode) {
|
|
11827
|
+
names = names.filter(function (name) { return name !== "zip"; });
|
|
11828
|
+
}
|
|
11829
|
+
return FIELDS.filter(function (field) { return names.indexOf(field[0]) !== -1; });
|
|
11830
|
+
}
|
|
11831
|
+
function digits(value) { return String(value || "").replace(/\\D/g, ""); }
|
|
11832
|
+
function brandOf(value) {
|
|
11833
|
+
var number = digits(value);
|
|
11834
|
+
if (/^3[47]/.test(number)) return "amex";
|
|
11835
|
+
if (/^(5[1-5]|2[2-7])/.test(number)) return "mastercard";
|
|
11836
|
+
if (/^(6011|65)/.test(number)) return "discover";
|
|
11837
|
+
if (/^4/.test(number)) return "visa";
|
|
11838
|
+
return "unknown";
|
|
11839
|
+
}
|
|
11840
|
+
function luhn(number) {
|
|
11841
|
+
var sum = 0;
|
|
11842
|
+
var alternate = false;
|
|
11843
|
+
for (var index = number.length - 1; index >= 0; index -= 1) {
|
|
11844
|
+
var digit = Number(number[index]);
|
|
11845
|
+
if (alternate) { digit *= 2; if (digit > 9) digit -= 9; }
|
|
11846
|
+
sum += digit;
|
|
11847
|
+
alternate = !alternate;
|
|
11848
|
+
}
|
|
11849
|
+
return number.length > 0 && sum % 10 === 0;
|
|
11850
|
+
}
|
|
11851
|
+
function cardError(code, message) {
|
|
11852
|
+
return { type: "validation_error", code: code, message: message };
|
|
11853
|
+
}
|
|
11854
|
+
function validateField(element, name) {
|
|
11855
|
+
var raw = element.value(name);
|
|
11856
|
+
if (name === "card") {
|
|
11857
|
+
var number = digits(raw);
|
|
11858
|
+
var brand = brandOf(number);
|
|
11859
|
+
var expected = brand === "amex" ? 15 : 16;
|
|
11860
|
+
if (!number || number.length < expected) return cardError("incomplete_number", "Your card number is incomplete.");
|
|
11861
|
+
if (number.length !== expected || !luhn(number)) return cardError("invalid_number", "Your card number is invalid.");
|
|
11862
|
+
}
|
|
11863
|
+
if (name === "exp") {
|
|
11864
|
+
var expiry = digits(raw);
|
|
11865
|
+
if (expiry.length < 4) return cardError("incomplete_expiry", "Your card's expiration date is incomplete.");
|
|
11866
|
+
var month = Number(expiry.slice(0, 2));
|
|
11867
|
+
var year = 2000 + Number(expiry.slice(2, 4));
|
|
11868
|
+
if (month < 1 || month > 12) return cardError("invalid_expiry_month", "Your card's expiration month is invalid.");
|
|
11869
|
+
var now = new Date();
|
|
11870
|
+
if (year < now.getFullYear() || (year === now.getFullYear() && month < now.getMonth() + 1)) {
|
|
11871
|
+
return cardError("invalid_expiry_year_past", "Your card's expiration year is in the past.");
|
|
11872
|
+
}
|
|
11873
|
+
}
|
|
11874
|
+
if (name === "cvc") {
|
|
11875
|
+
var cvc = digits(raw);
|
|
11876
|
+
var cvcLength = brandOf(element.value("card")) === "amex" ? 4 : 3;
|
|
11877
|
+
if (cvc.length < cvcLength) return cardError("incomplete_cvc", "Your card's security code is incomplete.");
|
|
11878
|
+
if (cvc.length !== cvcLength) return cardError("invalid_cvc", "Your card's security code is invalid.");
|
|
11879
|
+
}
|
|
11880
|
+
if (name === "zip" && !String(raw || "").trim()) {
|
|
11881
|
+
return cardError("incomplete_zip", "Your postal code is incomplete.");
|
|
11882
|
+
}
|
|
11883
|
+
return null;
|
|
11884
|
+
}
|
|
11885
|
+
function stateOf(element) {
|
|
11886
|
+
var fields = fieldsFor(element.type, element.options);
|
|
11887
|
+
var empty = fields.every(function (field) { return String(element.value(field[0]) || "") === ""; });
|
|
11888
|
+
var error = null;
|
|
11889
|
+
for (var index = 0; index < fields.length && !error; index += 1) error = validateField(element, fields[index][0]);
|
|
11890
|
+
var event = { complete: !error, empty: empty, elementType: element.type };
|
|
11891
|
+
if (error) event.error = error;
|
|
11892
|
+
if (element.type === "card" || element.type === "cardNumber") event.brand = brandOf(element.value("card"));
|
|
11893
|
+
return event;
|
|
11894
|
+
}
|
|
11895
|
+
function cardValidationOf(element) {
|
|
11896
|
+
var card = element.card();
|
|
11897
|
+
var values = {
|
|
11898
|
+
card: card.number,
|
|
11899
|
+
exp: String(card.exp_month || "").padStart(2, "0") + "/" + String(card.exp_year || "").slice(-2),
|
|
11900
|
+
cvc: card.cvc,
|
|
11901
|
+
};
|
|
11902
|
+
var cardView = { value: function (name) { return values[name] || ""; } };
|
|
11903
|
+
var names = ["card", "exp", "cvc"];
|
|
11904
|
+
for (var index = 0; index < names.length; index += 1) {
|
|
11905
|
+
var error = validateField(cardView, names[index]);
|
|
11906
|
+
if (error) return error;
|
|
11907
|
+
}
|
|
11908
|
+
return null;
|
|
11909
|
+
}
|
|
11910
|
+
function formatInput(element, input) {
|
|
11911
|
+
if (input.name === "card") {
|
|
11912
|
+
var number = digits(input.value).slice(0, 19);
|
|
11913
|
+
var brand = brandOf(number);
|
|
11914
|
+
var sizes = brand === "amex" ? [4, 6, 5] : [4, 4, 4, 4, 3];
|
|
11915
|
+
var groups = [];
|
|
11916
|
+
var offset = 0;
|
|
11917
|
+
sizes.forEach(function (size) {
|
|
11918
|
+
if (offset < number.length) groups.push(number.slice(offset, offset + size));
|
|
11919
|
+
offset += size;
|
|
11920
|
+
});
|
|
11921
|
+
input.value = groups.join(" ");
|
|
11922
|
+
} else if (input.name === "exp") {
|
|
11923
|
+
var expiry = digits(input.value).slice(0, 4);
|
|
11924
|
+
input.value = expiry.length > 2 ? expiry.slice(0, 2) + "/" + expiry.slice(2) : expiry;
|
|
11925
|
+
} else if (input.name === "cvc") {
|
|
11926
|
+
var limit = brandOf(element.value("card")) === "amex" ? 4 : 3;
|
|
11927
|
+
input.value = digits(input.value).slice(0, limit);
|
|
11928
|
+
}
|
|
11929
|
+
}
|
|
11930
|
+
function Element(type, options, group) {
|
|
11821
11931
|
this.type = type;
|
|
11822
11932
|
this.options = options || {};
|
|
11933
|
+
this.group = group;
|
|
11823
11934
|
this.node = null;
|
|
11824
11935
|
this.handlers = {};
|
|
11825
11936
|
}
|
|
@@ -11829,45 +11940,63 @@ var stripeJs = (base2) => `/* Mockingbird Stripe.js stand-in */
|
|
|
11829
11940
|
var root = document.createElement("div");
|
|
11830
11941
|
root.setAttribute("data-testid", "stripe-mock-element");
|
|
11831
11942
|
root.setAttribute("data-element-type", this.type);
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11943
|
+
var split = this.type === "cardNumber" || this.type === "cardExpiry" || this.type === "cardCvc" || this.type === "postalCode";
|
|
11944
|
+
var self = this;
|
|
11945
|
+
fieldsFor(this.type, this.options).forEach(function (field) {
|
|
11835
11946
|
var input = document.createElement("input");
|
|
11836
11947
|
input.name = field[0];
|
|
11837
11948
|
input.setAttribute("data-testid", field[2]);
|
|
11949
|
+
input.setAttribute("aria-label", field[1]);
|
|
11838
11950
|
input.placeholder = field[3];
|
|
11839
|
-
|
|
11840
|
-
|
|
11951
|
+
input.addEventListener("input", function () {
|
|
11952
|
+
formatInput(self, input);
|
|
11953
|
+
self.emit("change", stateOf(self));
|
|
11954
|
+
});
|
|
11955
|
+
input.addEventListener("focus", function () { self.emit("focus", { elementType: self.type }); });
|
|
11956
|
+
input.addEventListener("blur", function () { self.emit("blur", { elementType: self.type }); });
|
|
11957
|
+
if (split) {
|
|
11958
|
+
root.appendChild(input);
|
|
11959
|
+
} else {
|
|
11960
|
+
var label = document.createElement("label");
|
|
11961
|
+
label.textContent = field[1];
|
|
11962
|
+
label.appendChild(input);
|
|
11963
|
+
root.appendChild(label);
|
|
11964
|
+
}
|
|
11841
11965
|
});
|
|
11842
11966
|
host.appendChild(root);
|
|
11843
11967
|
this.node = root;
|
|
11844
|
-
var self = this;
|
|
11845
|
-
root.addEventListener("input", function () { self.emit("change", { complete: true, empty: false, elementType: self.type }); });
|
|
11846
11968
|
setTimeout(function () { self.emit("ready", { elementType: self.type }); }, 0);
|
|
11847
11969
|
return this;
|
|
11848
11970
|
};
|
|
11849
11971
|
Element.prototype.value = function (name) {
|
|
11850
11972
|
var input = this.node && this.node.querySelector('[name="' + name + '"]');
|
|
11851
|
-
|
|
11973
|
+
if (input) return input.value;
|
|
11974
|
+
for (var index = 0; index < this.group.length; index += 1) {
|
|
11975
|
+
var sibling = this.group[index];
|
|
11976
|
+
var siblingInput = sibling !== this && sibling.node && sibling.node.querySelector('[name="' + name + '"]');
|
|
11977
|
+
if (siblingInput) return siblingInput.value;
|
|
11978
|
+
}
|
|
11979
|
+
return "";
|
|
11852
11980
|
};
|
|
11853
11981
|
Element.prototype.card = function () {
|
|
11854
|
-
var exp = (this.value("exp") || "
|
|
11855
|
-
var year = Number(exp[1] || "
|
|
11982
|
+
var exp = String(this.value("exp") || "").split("/");
|
|
11983
|
+
var year = Number(exp[1] || "0");
|
|
11856
11984
|
return {
|
|
11857
|
-
number: (this.value("card")
|
|
11858
|
-
exp_month: Number(exp[0] || "
|
|
11985
|
+
number: digits(this.value("card")),
|
|
11986
|
+
exp_month: Number(exp[0] || "0"),
|
|
11859
11987
|
exp_year: year < 100 ? 2000 + year : year,
|
|
11860
|
-
cvc: this.value("cvc")
|
|
11988
|
+
cvc: digits(this.value("cvc")),
|
|
11861
11989
|
};
|
|
11862
11990
|
};
|
|
11991
|
+
Element.prototype.validation = function () { return stateOf(this); };
|
|
11863
11992
|
Element.prototype.on = function (name, handler) { (this.handlers[name] = this.handlers[name] || []).push(handler); return this; };
|
|
11864
11993
|
Element.prototype.off = function (name, handler) { this.handlers[name] = (this.handlers[name] || []).filter(function (h) { return h !== handler; }); return this; };
|
|
11865
11994
|
Element.prototype.once = function (name, handler) { var self = this; var wrapped = function (e) { self.off(name, wrapped); handler(e); }; return this.on(name, wrapped); };
|
|
11866
11995
|
Element.prototype.emit = function (name, event) { (this.handlers[name] || []).forEach(function (h) { h(event); }); };
|
|
11867
|
-
Element.prototype.update = function (options) { this.options = Object.assign(this.options, options || {}); };
|
|
11996
|
+
Element.prototype.update = function (options) { this.options = Object.assign(this.options, options || {}); if (this.node) this.emit("change", stateOf(this)); };
|
|
11868
11997
|
Element.prototype.focus = function () { var input = this.node && this.node.querySelector("input"); if (input) input.focus(); };
|
|
11869
|
-
Element.prototype.blur = function () {};
|
|
11870
|
-
Element.prototype.clear = function () { if (this.node) this.node.querySelectorAll("input").forEach(function (i) { i.value = ""; }); };
|
|
11998
|
+
Element.prototype.blur = function () { var input = this.node && this.node.querySelector("input"); if (input && input.blur) input.blur(); };
|
|
11999
|
+
Element.prototype.clear = function () { if (this.node) this.node.querySelectorAll("input").forEach(function (i) { i.value = ""; }); this.emit("change", stateOf(this)); };
|
|
11871
12000
|
Element.prototype.collapse = function () {};
|
|
11872
12001
|
Element.prototype.unmount = function () { if (this.node && this.node.parentNode) this.node.parentNode.removeChild(this.node); this.node = null; };
|
|
11873
12002
|
Element.prototype.destroy = Element.prototype.unmount;
|
|
@@ -11883,7 +12012,7 @@ var stripeJs = (base2) => `/* Mockingbird Stripe.js stand-in */
|
|
|
11883
12012
|
return {
|
|
11884
12013
|
_clientSecret: clientSecret,
|
|
11885
12014
|
_elements: created,
|
|
11886
|
-
create: function (type, opts) { var element = new Element(type, opts); created.push(element); return element; },
|
|
12015
|
+
create: function (type, opts) { var element = new Element(type, opts, created); created.push(element); return element; },
|
|
11887
12016
|
getElement: function (type) {
|
|
11888
12017
|
var elementType = type && type.__elementType ? type.__elementType : type;
|
|
11889
12018
|
return created.filter(function (e) { return e.type === elementType || (e.type === "payment" && type && type.type === "payment"); })[0] || null;
|
|
@@ -11914,6 +12043,13 @@ var stripeJs = (base2) => `/* Mockingbird Stripe.js stand-in */
|
|
|
11914
12043
|
"4000051230000072": "tok_hsa",
|
|
11915
12044
|
};
|
|
11916
12045
|
Stripe.prototype.createToken = function (element) {
|
|
12046
|
+
var validation = element && typeof element.validation === "function" ? cardValidationOf(element) : null;
|
|
12047
|
+
if (validation) {
|
|
12048
|
+
return Promise.resolve({ error: validation });
|
|
12049
|
+
}
|
|
12050
|
+
if (!element) {
|
|
12051
|
+
return Promise.resolve({ error: cardError("incomplete_number", "Your card number is incomplete.") });
|
|
12052
|
+
}
|
|
11917
12053
|
var card = element && typeof element.card === "function" ? element.card() : null;
|
|
11918
12054
|
var number = card && String(card.number || "").replace(/[\\s-]/g, "");
|
|
11919
12055
|
var token = number && CARD_TOKENS[number];
|
|
@@ -13427,6 +13563,7 @@ var paymentMethodHandlers = (services) => ({
|
|
|
13427
13563
|
render: renderPaymentMethod
|
|
13428
13564
|
});
|
|
13429
13565
|
const account = stringOf(params, "customer_account");
|
|
13566
|
+
if (context.query.customer_account === "") throw parameterInvalidEmpty("customer_account");
|
|
13430
13567
|
if (account !== null && account !== "")
|
|
13431
13568
|
throw resourceMissing("customer", account, "customer_account", 400);
|
|
13432
13569
|
return jsonRes(200, page);
|
|
@@ -19019,4 +19156,4 @@ export {
|
|
|
19019
19156
|
createRuntime2 as createRuntime,
|
|
19020
19157
|
StripeAPI
|
|
19021
19158
|
};
|
|
19022
|
-
//# sourceMappingURL=chunk-
|
|
19159
|
+
//# sourceMappingURL=chunk-7ZVXTTT4.js.map
|