@asteby/storefront 0.11.2 → 0.13.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/README.md +5 -0
- package/dist/cli.js +25 -2
- package/dist/fiscal-document.d.cts +2 -2
- package/dist/fiscal-document.d.ts +2 -2
- package/dist/index.cjs +67 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -4
- package/dist/index.d.ts +73 -4
- package/dist/index.js +65 -5
- package/dist/index.js.map +1 -1
- package/dist/mock.d.cts +1 -1
- package/dist/mock.d.ts +1 -1
- package/dist/mockup.d.cts +1 -1
- package/dist/mockup.d.ts +1 -1
- package/dist/node.cjs +1 -1
- package/dist/node.js +1 -1
- package/dist/{types-BQ7k6DwG.d.cts → types-BQ3S6VjF.d.cts} +15 -1
- package/dist/{types-D8nLoKyk.d.ts → types-C_rsJRCl.d.ts} +15 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -263,6 +263,9 @@ const result = await sf.checkouts.pay(checkout.checkout.id, { method: 'card', pr
|
|
|
263
263
|
{ idempotencyKey: paymentIdempotencyKey(checkout.checkout.id, attemptId) }) // idempotencyKey is REQUIRED (throws before calling)
|
|
264
264
|
const outcome = paymentOutcome(result, 'es-MX') // approved | in_review | voucher | challenge | redirect | rejected | expired | cancelled
|
|
265
265
|
paymentErrorView(error) // network (retry same attempt) | price_mismatch | payment_in_progress | expired | too_many_attempts
|
|
266
|
+
classifyPaymentError(error) // { kind, retryable } WITHOUT texts; same rules in the server and the browser
|
|
267
|
+
// kinds: transient | in_progress | rate_limited | merchant_config | provider_declined | stale_checkout | expired | price_mismatch | store_closed | validation | other
|
|
268
|
+
// honours OPS `retryable:false` and the stable codes payment_provider_rejected / payment_provider_misconfigured / unavailable / invalid_state
|
|
266
269
|
```
|
|
267
270
|
|
|
268
271
|
- `declineMessage(code, locale)` / `paymentMessages(locale, overrides)`: actionable es/en texts; unknown codes become `declined`.
|
|
@@ -443,6 +446,8 @@ connectStore().keepFresh() // heartbeat; rotates (POST /api/conne
|
|
|
443
446
|
missing and where to repair them (`OPS → Conexiones y API → <conexión> → Reparar permisos`), showing `sk_…a91f` and never
|
|
444
447
|
the key. Repairing permissions does not change the key.
|
|
445
448
|
|
|
449
|
+
`StorefrontError` also keeps what OPS sends in `error.*`: `retryable`, `retryAfter`, `checkoutId`, `cost` (of a `price_mismatch`) and `messageEn`.
|
|
450
|
+
|
|
446
451
|
Errors: a `403 insufficient_scope` is a `StorefrontError` with `code: 'insufficient_scope'`, `status: 403` and
|
|
447
452
|
`requiredScopes: ['customer:write']`. `customer.capabilities()` reports `password: false`, `unavailable_reason:
|
|
448
453
|
'missing_scope'` and `missing_scopes` when the key cannot create accounts. The mock rehearses all of it with
|
package/dist/cli.js
CHANGED
|
@@ -15,6 +15,16 @@ var StorefrontError = class extends Error {
|
|
|
15
15
|
url;
|
|
16
16
|
/** Scopes a `403 insufficient_scope` says the route needs (empty for any other error). */
|
|
17
17
|
requiredScopes;
|
|
18
|
+
/** `true`: repeating the request (same idempotency key) can succeed. `false`: not until someone fixes something. `undefined`: OPS did not say. */
|
|
19
|
+
retryable;
|
|
20
|
+
/** Seconds OPS asks to wait before retrying. */
|
|
21
|
+
retryAfter;
|
|
22
|
+
/** Checkout that a refused cart write can resume. */
|
|
23
|
+
checkoutId;
|
|
24
|
+
/** Current cart cost sent with a `price_mismatch` (untrusted shape). */
|
|
25
|
+
cost;
|
|
26
|
+
/** English version of `message`, when OPS sent one. */
|
|
27
|
+
messageEn;
|
|
18
28
|
constructor(init) {
|
|
19
29
|
super(init.message, init.cause === void 0 ? void 0 : { cause: init.cause });
|
|
20
30
|
this.status = init.status;
|
|
@@ -23,6 +33,11 @@ var StorefrontError = class extends Error {
|
|
|
23
33
|
this.details = init.details;
|
|
24
34
|
this.url = init.url;
|
|
25
35
|
this.requiredScopes = init.requiredScopes ?? [];
|
|
36
|
+
this.retryable = init.retryable;
|
|
37
|
+
this.retryAfter = init.retryAfter;
|
|
38
|
+
this.checkoutId = init.checkoutId;
|
|
39
|
+
this.cost = init.cost;
|
|
40
|
+
this.messageEn = init.messageEn;
|
|
26
41
|
}
|
|
27
42
|
/**
|
|
28
43
|
* Affected lines of a `409 insufficient_stock` (empty for any other error or a
|
|
@@ -41,7 +56,10 @@ var StorefrontError = class extends Error {
|
|
|
41
56
|
code: this.code,
|
|
42
57
|
message: this.message,
|
|
43
58
|
field: this.field,
|
|
44
|
-
...this.requiredScopes.length ? { requiredScopes: this.requiredScopes } : {}
|
|
59
|
+
...this.requiredScopes.length ? { requiredScopes: this.requiredScopes } : {},
|
|
60
|
+
...this.retryable !== void 0 ? { retryable: this.retryable } : {},
|
|
61
|
+
...this.retryAfter !== void 0 ? { retryAfter: this.retryAfter } : {},
|
|
62
|
+
...this.checkoutId ? { checkoutId: this.checkoutId } : {}
|
|
45
63
|
};
|
|
46
64
|
}
|
|
47
65
|
};
|
|
@@ -169,6 +187,11 @@ async function readError(res, url) {
|
|
|
169
187
|
message: e?.message ?? `Storefront API responded ${res.status}${res.statusText ? " " + res.statusText : ""}`,
|
|
170
188
|
...e?.field ? { field: e.field } : {},
|
|
171
189
|
...e?.details !== void 0 ? { details: e.details } : {},
|
|
190
|
+
...typeof e?.retryable === "boolean" ? { retryable: e.retryable } : {},
|
|
191
|
+
...typeof e?.retry_after === "number" && e.retry_after > 0 ? { retryAfter: e.retry_after } : {},
|
|
192
|
+
...typeof e?.checkout_id === "string" && e.checkout_id ? { checkoutId: e.checkout_id } : {},
|
|
193
|
+
...e?.cost !== void 0 ? { cost: e.cost } : {},
|
|
194
|
+
...typeof e?.message_en === "string" && e.message_en ? { messageEn: e.message_en } : {},
|
|
172
195
|
url
|
|
173
196
|
});
|
|
174
197
|
}
|
|
@@ -464,7 +487,7 @@ function repairPath(connectionName) {
|
|
|
464
487
|
import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeSync } from "fs";
|
|
465
488
|
import { dirname, join, resolve } from "path";
|
|
466
489
|
import { hostname } from "os";
|
|
467
|
-
var SDK_VERSION = true ? "0.
|
|
490
|
+
var SDK_VERSION = true ? "0.13.0" : "dev";
|
|
468
491
|
function writeFileAtomic(file, content, mode = 384) {
|
|
469
492
|
const dir = dirname(file);
|
|
470
493
|
mkdirSync(dir, { recursive: true });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { U as FiscalDocumentSource, aR as RegionFiscalEntry, Z as IdentityDocumentSpec, T as FiscalDocumentEvidence, aS as RegionFiscalId, $ as IdentityRulesV1 } from './types-
|
|
2
|
-
export { Y as IdentityCapture, _ as IdentityFieldRule, a0 as IdentityStrategy } from './types-
|
|
1
|
+
import { U as FiscalDocumentSource, aR as RegionFiscalEntry, Z as IdentityDocumentSpec, T as FiscalDocumentEvidence, aS as RegionFiscalId, $ as IdentityRulesV1 } from './types-BQ3S6VjF.cjs';
|
|
2
|
+
export { Y as IdentityCapture, _ as IdentityFieldRule, a0 as IdentityStrategy } from './types-BQ3S6VjF.cjs';
|
|
3
3
|
import './geo.cjs';
|
|
4
4
|
|
|
5
5
|
/** A value read from a document: text, or the codes of a catalog (`multiple` fields). */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { U as FiscalDocumentSource, aR as RegionFiscalEntry, Z as IdentityDocumentSpec, T as FiscalDocumentEvidence, aS as RegionFiscalId, $ as IdentityRulesV1 } from './types-
|
|
2
|
-
export { Y as IdentityCapture, _ as IdentityFieldRule, a0 as IdentityStrategy } from './types-
|
|
1
|
+
import { U as FiscalDocumentSource, aR as RegionFiscalEntry, Z as IdentityDocumentSpec, T as FiscalDocumentEvidence, aS as RegionFiscalId, $ as IdentityRulesV1 } from './types-C_rsJRCl.js';
|
|
2
|
+
export { Y as IdentityCapture, _ as IdentityFieldRule, a0 as IdentityStrategy } from './types-C_rsJRCl.js';
|
|
3
3
|
import './geo.js';
|
|
4
4
|
|
|
5
5
|
/** A value read from a document: text, or the codes of a catalog (`multiple` fields). */
|
package/dist/index.cjs
CHANGED
|
@@ -10,6 +10,16 @@ var StorefrontError = class extends Error {
|
|
|
10
10
|
url;
|
|
11
11
|
/** Scopes a `403 insufficient_scope` says the route needs (empty for any other error). */
|
|
12
12
|
requiredScopes;
|
|
13
|
+
/** `true`: repeating the request (same idempotency key) can succeed. `false`: not until someone fixes something. `undefined`: OPS did not say. */
|
|
14
|
+
retryable;
|
|
15
|
+
/** Seconds OPS asks to wait before retrying. */
|
|
16
|
+
retryAfter;
|
|
17
|
+
/** Checkout that a refused cart write can resume. */
|
|
18
|
+
checkoutId;
|
|
19
|
+
/** Current cart cost sent with a `price_mismatch` (untrusted shape). */
|
|
20
|
+
cost;
|
|
21
|
+
/** English version of `message`, when OPS sent one. */
|
|
22
|
+
messageEn;
|
|
13
23
|
constructor(init) {
|
|
14
24
|
super(init.message, init.cause === void 0 ? void 0 : { cause: init.cause });
|
|
15
25
|
this.status = init.status;
|
|
@@ -18,6 +28,11 @@ var StorefrontError = class extends Error {
|
|
|
18
28
|
this.details = init.details;
|
|
19
29
|
this.url = init.url;
|
|
20
30
|
this.requiredScopes = init.requiredScopes ?? [];
|
|
31
|
+
this.retryable = init.retryable;
|
|
32
|
+
this.retryAfter = init.retryAfter;
|
|
33
|
+
this.checkoutId = init.checkoutId;
|
|
34
|
+
this.cost = init.cost;
|
|
35
|
+
this.messageEn = init.messageEn;
|
|
21
36
|
}
|
|
22
37
|
/**
|
|
23
38
|
* Affected lines of a `409 insufficient_stock` (empty for any other error or a
|
|
@@ -36,7 +51,10 @@ var StorefrontError = class extends Error {
|
|
|
36
51
|
code: this.code,
|
|
37
52
|
message: this.message,
|
|
38
53
|
field: this.field,
|
|
39
|
-
...this.requiredScopes.length ? { requiredScopes: this.requiredScopes } : {}
|
|
54
|
+
...this.requiredScopes.length ? { requiredScopes: this.requiredScopes } : {},
|
|
55
|
+
...this.retryable !== void 0 ? { retryable: this.retryable } : {},
|
|
56
|
+
...this.retryAfter !== void 0 ? { retryAfter: this.retryAfter } : {},
|
|
57
|
+
...this.checkoutId ? { checkoutId: this.checkoutId } : {}
|
|
40
58
|
};
|
|
41
59
|
}
|
|
42
60
|
};
|
|
@@ -201,6 +219,11 @@ async function readError(res, url) {
|
|
|
201
219
|
message: e?.message ?? `Storefront API responded ${res.status}${res.statusText ? " " + res.statusText : ""}`,
|
|
202
220
|
...e?.field ? { field: e.field } : {},
|
|
203
221
|
...e?.details !== void 0 ? { details: e.details } : {},
|
|
222
|
+
...typeof e?.retryable === "boolean" ? { retryable: e.retryable } : {},
|
|
223
|
+
...typeof e?.retry_after === "number" && e.retry_after > 0 ? { retryAfter: e.retry_after } : {},
|
|
224
|
+
...typeof e?.checkout_id === "string" && e.checkout_id ? { checkoutId: e.checkout_id } : {},
|
|
225
|
+
...e?.cost !== void 0 ? { cost: e.cost } : {},
|
|
226
|
+
...typeof e?.message_en === "string" && e.message_en ? { messageEn: e.message_en } : {},
|
|
204
227
|
url
|
|
205
228
|
});
|
|
206
229
|
}
|
|
@@ -482,6 +505,35 @@ function storefrontDomainHeader(domain, market) {
|
|
|
482
505
|
return code && /^[a-z0-9_-]{1,32}$/.test(code) ? `${host}#${code}` : host;
|
|
483
506
|
}
|
|
484
507
|
|
|
508
|
+
// src/payment-errors.ts
|
|
509
|
+
function opsSaysNotRetryable(err) {
|
|
510
|
+
if (err.retryable === false) return true;
|
|
511
|
+
const d = err.details;
|
|
512
|
+
return typeof d === "object" && d !== null && d.retryable === false;
|
|
513
|
+
}
|
|
514
|
+
var PAYMENT_CHOICE_REFUSED_FIELD = "payment_choice";
|
|
515
|
+
var MERCHANT_CONFIG_CODE = /credential|not_configured|unconfigured|invalid_access|access_token|provider_config|merchant|invalid_public_key|unauthorized/i;
|
|
516
|
+
function classifyPaymentError(err) {
|
|
517
|
+
const status = typeof err.status === "number" ? err.status : 0;
|
|
518
|
+
const code = typeof err.code === "string" ? err.code : "";
|
|
519
|
+
if (code === "store_not_ready") return { kind: "store_closed", retryable: false };
|
|
520
|
+
if (code === "price_mismatch" || status === 422 && err.field === "expected_total") return { kind: "price_mismatch", retryable: false };
|
|
521
|
+
if (status === 409 && (code === "payment_in_progress" || err.field === "payment_in_progress")) return { kind: "in_progress", retryable: true };
|
|
522
|
+
if (status === 409 && code === "expired") return { kind: "expired", retryable: false };
|
|
523
|
+
if (status === 429 || code === "too_many_attempts" || code === "rate_limited") return { kind: "rate_limited", retryable: true };
|
|
524
|
+
if (status === 422 && code === "invalid_state") {
|
|
525
|
+
if (err.field === PAYMENT_CHOICE_REFUSED_FIELD) return { kind: "other", retryable: false };
|
|
526
|
+
return { kind: "stale_checkout", retryable: false };
|
|
527
|
+
}
|
|
528
|
+
if (code === "payment_provider_misconfigured") return { kind: "merchant_config", retryable: false };
|
|
529
|
+
if (code === "payment_provider_rejected") return { kind: "provider_declined", retryable: false };
|
|
530
|
+
if (MERCHANT_CONFIG_CODE.test(code) || status === 401 || status === 403) return { kind: "merchant_config", retryable: false };
|
|
531
|
+
if (status >= 500 && opsSaysNotRetryable(err)) return { kind: "other", retryable: false };
|
|
532
|
+
if (status === 0 || status >= 500 || code === "network" || code === "timeout" || code === "unavailable") return { kind: "transient", retryable: true };
|
|
533
|
+
if (status === 400 || code === "validation") return { kind: "validation", retryable: false };
|
|
534
|
+
return { kind: "other", retryable: false };
|
|
535
|
+
}
|
|
536
|
+
|
|
485
537
|
// src/diagnose.ts
|
|
486
538
|
function maskToken(token) {
|
|
487
539
|
if (!token) return "(sin token)";
|
|
@@ -781,7 +833,10 @@ var ES2 = {
|
|
|
781
833
|
"voucher.open": "Ver o imprimir ficha",
|
|
782
834
|
"voucher.email": "Tambi\xE9n te la enviamos a tu correo.",
|
|
783
835
|
"form.label": "Datos de tu tarjeta",
|
|
784
|
-
"challenge.title": "Verificaci\xF3n de tu banco"
|
|
836
|
+
"challenge.title": "Verificaci\xF3n de tu banco",
|
|
837
|
+
"challenge.escape": "Cancelar y volver al pago",
|
|
838
|
+
"challenge.escape_hint": "\xBFTarda demasiado? Puedes cerrar la verificaci\xF3n. Si ya la aprobaste en tu banco, el pago a\xFAn puede completarse: te confirmamos aqu\xED antes de dejarte pagar de nuevo.",
|
|
839
|
+
"challenge.left": "Cerraste la verificaci\xF3n. Estamos confirmando con tu banco si el pago se complet\xF3; no vuelvas a pagar todav\xEDa."
|
|
785
840
|
};
|
|
786
841
|
var EN2 = {
|
|
787
842
|
"decline.insufficient_funds": "Your card has insufficient funds. Try another card or pay in cash.",
|
|
@@ -825,7 +880,10 @@ var EN2 = {
|
|
|
825
880
|
"voucher.open": "View or print voucher",
|
|
826
881
|
"voucher.email": "We also emailed it to you.",
|
|
827
882
|
"form.label": "Your card details",
|
|
828
|
-
"challenge.title": "Your bank verification"
|
|
883
|
+
"challenge.title": "Your bank verification",
|
|
884
|
+
"challenge.escape": "Cancel and go back to payment",
|
|
885
|
+
"challenge.escape_hint": "Taking too long? You can close the verification. If you already approved it with your bank the payment may still go through: we confirm here before letting you pay again.",
|
|
886
|
+
"challenge.left": "You closed the verification. We are checking with your bank whether the payment went through; do not pay again yet."
|
|
829
887
|
};
|
|
830
888
|
var CATALOG2 = { es: ES2, en: EN2 };
|
|
831
889
|
function paymentMessages(locale, overrides) {
|
|
@@ -944,7 +1002,9 @@ function paymentErrorView(err, locale, overrides) {
|
|
|
944
1002
|
if (status === 429 || code === "too_many_attempts") {
|
|
945
1003
|
return { kind: "too_many_attempts", message: m["error.too_many_attempts"], retrySameAttempt: false, canRetry: false };
|
|
946
1004
|
}
|
|
947
|
-
|
|
1005
|
+
const declared = e.retryable;
|
|
1006
|
+
if (status >= 500 && declared === false) return { kind: "generic", message: m["error.generic"], retrySameAttempt: false, canRetry: true };
|
|
1007
|
+
if (status === 0 || status === 502 || status === 503 || status === 504 || code === "network" || code === "timeout" || status >= 500) {
|
|
948
1008
|
return { kind: "network", message: m["error.network"], retrySameAttempt: true, canRetry: true };
|
|
949
1009
|
}
|
|
950
1010
|
return { kind: "generic", message: m["error.generic"], retrySameAttempt: false, canRetry: true };
|
|
@@ -1247,6 +1307,7 @@ exports.CLIENT_IP_HEADER = CLIENT_IP_HEADER;
|
|
|
1247
1307
|
exports.COUNTRY_HEADERS = COUNTRY_HEADERS;
|
|
1248
1308
|
exports.MISSING_WEIGHT = MISSING_WEIGHT;
|
|
1249
1309
|
exports.NOTE_MAX_LENGTH = NOTE_MAX_LENGTH;
|
|
1310
|
+
exports.PAYMENT_CHOICE_REFUSED_FIELD = PAYMENT_CHOICE_REFUSED_FIELD;
|
|
1250
1311
|
exports.StorefrontError = StorefrontError;
|
|
1251
1312
|
exports.appendParams = appendParams;
|
|
1252
1313
|
exports.availabilityLocale = availabilityLocale;
|
|
@@ -1254,6 +1315,7 @@ exports.availabilityMessages = availabilityMessages;
|
|
|
1254
1315
|
exports.availabilityView = availabilityView;
|
|
1255
1316
|
exports.cartLineProblemView = cartLineProblemView;
|
|
1256
1317
|
exports.clampPercent = clampPercent;
|
|
1318
|
+
exports.classifyPaymentError = classifyPaymentError;
|
|
1257
1319
|
exports.createStorefrontClient = createStorefrontClient;
|
|
1258
1320
|
exports.declineMessage = declineMessage;
|
|
1259
1321
|
exports.declineMessageKey = declineMessageKey;
|
|
@@ -1271,6 +1333,7 @@ exports.maskToken = maskToken;
|
|
|
1271
1333
|
exports.negotiateLocale = negotiateLocale;
|
|
1272
1334
|
exports.normalizeClientIp = normalizeClientIp;
|
|
1273
1335
|
exports.normalizeNote = normalizeNote;
|
|
1336
|
+
exports.opsSaysNotRetryable = opsSaysNotRetryable;
|
|
1274
1337
|
exports.parseDelivery = parseDelivery;
|
|
1275
1338
|
exports.parseMoney = parseMoney;
|
|
1276
1339
|
exports.parseProductFilters = parseProductFilters;
|