platform-types 1.10.764 → 1.10.766
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/dist/auth.d.ts +99 -0
- package/dist/auth.js +52 -0
- package/dist/cjs/auth.js +53 -1
- package/dist/cjs/notification.js +9 -1
- package/dist/cjs/order.js +17 -1
- package/dist/customer.d.ts +14 -4
- package/dist/notification.d.ts +57 -1
- package/dist/notification.js +8 -0
- package/dist/order.d.ts +53 -2
- package/dist/order.js +17 -1
- package/dist/store.d.ts +8 -0
- package/package.json +1 -1
package/dist/auth.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EmailSuppressionReason } from './emailSuppression.ts';
|
|
1
2
|
declare global {
|
|
2
3
|
interface Login {
|
|
3
4
|
email: string;
|
|
@@ -1079,6 +1080,56 @@ declare global {
|
|
|
1079
1080
|
/** Unix ms after which the code no longer redeems (mint + 60 s). */
|
|
1080
1081
|
expiresAt: number;
|
|
1081
1082
|
}
|
|
1083
|
+
/**
|
|
1084
|
+
* `POST /auth` (Web API) body for `send-otp`: mail a 6-digit code to the
|
|
1085
|
+
* address STORED on the caller's customer row. Needs a Bearer customer ACCESS
|
|
1086
|
+
* token (`Authorization: Bearer …`); the method has no API Gateway authorizer,
|
|
1087
|
+
* so the handler verifies it. The body carries no address — one supplied is
|
|
1088
|
+
* ignored.
|
|
1089
|
+
*
|
|
1090
|
+
* `200 { message }` with no `data` when a code was queued. Refusals: see
|
|
1091
|
+
* {@link CUSTOMER_OTP_ERROR_CODES}. Timing: see {@link CUSTOMER_OTP_LIMITS}.
|
|
1092
|
+
* Nothing is mailed automatically after the customer changes their address —
|
|
1093
|
+
* call this.
|
|
1094
|
+
*/
|
|
1095
|
+
interface CustomerSendOtpRequest {
|
|
1096
|
+
mode: 'send-otp';
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* `POST /auth` (Web API) body for `verify-otp`, with the same Bearer customer
|
|
1100
|
+
* ACCESS token as `send-otp`.
|
|
1101
|
+
*/
|
|
1102
|
+
interface CustomerVerifyOtpRequest {
|
|
1103
|
+
mode: 'verify-otp';
|
|
1104
|
+
/** Exactly six ASCII digits; anything else is `400 VALIDATION_FAILED`. */
|
|
1105
|
+
code: string;
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* `verify-otp` 200 `data`. Merge it into the cached `AuthCustomer`; the same
|
|
1109
|
+
* pair also arrives as a `customers` socket frame (`data: { customerId,
|
|
1110
|
+
* emailVerified, emailVerifiedAt }`) on every socket of this customer, so other
|
|
1111
|
+
* open tabs update without a refresh.
|
|
1112
|
+
*/
|
|
1113
|
+
interface CustomerVerifyOtpResponse {
|
|
1114
|
+
emailVerified: true;
|
|
1115
|
+
/** ms-epoch of the verification. */
|
|
1116
|
+
emailVerifiedAt: number;
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* `verify-otp` `400 OTP_WRONG_CODE` body.
|
|
1120
|
+
*
|
|
1121
|
+
* ⚠️ `attemptsLeft` is TOP-LEVEL, beside `error`, not under `data`. `0` means
|
|
1122
|
+
* the next guess answers `429 OTP_LOCKED`.
|
|
1123
|
+
*/
|
|
1124
|
+
interface CustomerOtpWrongCodeBody {
|
|
1125
|
+
error: 'OTP_WRONG_CODE';
|
|
1126
|
+
message: string;
|
|
1127
|
+
attemptsLeft: number;
|
|
1128
|
+
}
|
|
1129
|
+
/** `send-otp` `409 EMAIL_ADDRESS_SUPPRESSED` `data`: why the stored address cannot receive mail. */
|
|
1130
|
+
interface CustomerOtpSuppressedData {
|
|
1131
|
+
reason: EmailSuppressionReason;
|
|
1132
|
+
}
|
|
1082
1133
|
/**
|
|
1083
1134
|
* `POST /auth` body for `social-bridge-redeem`. Public, captcha-exempt.
|
|
1084
1135
|
*
|
|
@@ -1854,4 +1905,52 @@ export type PasskeyErrorCode = (typeof PASSKEY_ERROR_CODES)[number];
|
|
|
1854
1905
|
*/
|
|
1855
1906
|
export declare const SESSION_ACTION_ERROR_CODES: readonly ["SESSION_LOOKUP_INCOMPLETE", "SESSION_UNKNOWN", "REVOKE_INCOMPLETE"];
|
|
1856
1907
|
export type SessionActionErrorCode = (typeof SESSION_ACTION_ERROR_CODES)[number];
|
|
1908
|
+
/**
|
|
1909
|
+
* `body.error` codes the two customer email-OTP modes (Web API `POST /auth`
|
|
1910
|
+
* `send-otp` / `verify-otp`) refuse with. Match on `body.error`.
|
|
1911
|
+
*
|
|
1912
|
+
* NOT members, and answered by both modes before any of these: the shared
|
|
1913
|
+
* customer-identity refusals — `MISSING_TOKEN`, `INVALID_TOKEN`,
|
|
1914
|
+
* `REFRESH_TOKEN_NOT_ALLOWED` (401), `ROLE_NOT_ALLOWED`,
|
|
1915
|
+
* `CUSTOMER_ACCESS_PENDING`, `CUSTOMER_ACCESS_REJECTED` (403),
|
|
1916
|
+
* `CUSTOMER_NOT_FOUND` (404), `ACCOUNT_DISABLED` (400) — and, on `verify-otp`,
|
|
1917
|
+
* `VALIDATION_FAILED` (400) for a `code` that is not six digits.
|
|
1918
|
+
*
|
|
1919
|
+
* - `OTP_COOLDOWN` · 429 — `send-otp` inside 60 s of the last live code.
|
|
1920
|
+
* - `EMAIL_ADDRESS_SUPPRESSED` · 409 — `send-otp`; the address bounced.
|
|
1921
|
+
* `data` is {@link CustomerOtpSuppressedData}.
|
|
1922
|
+
* - `EMAIL_ALREADY_VERIFIED` · 409 — `send-otp`; the stored address is already
|
|
1923
|
+
* verified, so nothing was mailed. Hide the resend action.
|
|
1924
|
+
* - `OTP_INVALID` · 400 — `verify-otp`; no code outstanding for the CURRENT
|
|
1925
|
+
* address: none was sent, or the one sent went to an address the account no
|
|
1926
|
+
* longer holds. Ask for a new code.
|
|
1927
|
+
* - `OTP_ALREADY_USED` · 400 — `verify-otp`; the code was consumed, or lost a
|
|
1928
|
+
* race (including a concurrent address change). Ask for a new code.
|
|
1929
|
+
* - `OTP_EXPIRED` · 400 — `verify-otp`; past its 10-minute TTL.
|
|
1930
|
+
* - `OTP_LOCKED` · 429 — `verify-otp`; 5 wrong guesses. Only a new `send-otp`
|
|
1931
|
+
* unlocks.
|
|
1932
|
+
* - `OTP_WRONG_CODE` · 400 — `verify-otp`; {@link CustomerOtpWrongCodeBody},
|
|
1933
|
+
* `attemptsLeft` at the TOP level.
|
|
1934
|
+
*
|
|
1935
|
+
* ⚠️ Deliberately not the operator tree's vocabulary (`OTP_INVALID_OR_EXPIRED`,
|
|
1936
|
+
* `OTP_TOO_MANY_ATTEMPTS`, `OTP_RESEND_TOO_SOON`); the two are not unified.
|
|
1937
|
+
*/
|
|
1938
|
+
export declare const CUSTOMER_OTP_ERROR_CODES: readonly ["OTP_COOLDOWN", "EMAIL_ADDRESS_SUPPRESSED", "EMAIL_ALREADY_VERIFIED", "OTP_INVALID", "OTP_ALREADY_USED", "OTP_EXPIRED", "OTP_LOCKED", "OTP_WRONG_CODE"];
|
|
1939
|
+
export type CustomerOtpErrorCode = (typeof CUSTOMER_OTP_ERROR_CODES)[number];
|
|
1940
|
+
/**
|
|
1941
|
+
* The numbers the customer email OTP enforces, so a client countdown matches
|
|
1942
|
+
* the server. The api's own OTP service reads them from here, for operators and
|
|
1943
|
+
* customers alike.
|
|
1944
|
+
*
|
|
1945
|
+
* - `ttlSeconds` — a code expires this long after it was sent.
|
|
1946
|
+
* - `resendCooldownSeconds` — `send-otp` answers `429 OTP_COOLDOWN` until this
|
|
1947
|
+
* long after the last live code.
|
|
1948
|
+
* - `maxAttempts` — wrong guesses per code before `429 OTP_LOCKED`; a new code
|
|
1949
|
+
* starts the count again.
|
|
1950
|
+
*/
|
|
1951
|
+
export declare const CUSTOMER_OTP_LIMITS: {
|
|
1952
|
+
readonly ttlSeconds: 600;
|
|
1953
|
+
readonly resendCooldownSeconds: 60;
|
|
1954
|
+
readonly maxAttempts: 5;
|
|
1955
|
+
};
|
|
1857
1956
|
export {};
|
package/dist/auth.js
CHANGED
|
@@ -502,3 +502,55 @@ export const SESSION_ACTION_ERROR_CODES = [
|
|
|
502
502
|
'SESSION_UNKNOWN',
|
|
503
503
|
'REVOKE_INCOMPLETE',
|
|
504
504
|
];
|
|
505
|
+
/**
|
|
506
|
+
* `body.error` codes the two customer email-OTP modes (Web API `POST /auth`
|
|
507
|
+
* `send-otp` / `verify-otp`) refuse with. Match on `body.error`.
|
|
508
|
+
*
|
|
509
|
+
* NOT members, and answered by both modes before any of these: the shared
|
|
510
|
+
* customer-identity refusals — `MISSING_TOKEN`, `INVALID_TOKEN`,
|
|
511
|
+
* `REFRESH_TOKEN_NOT_ALLOWED` (401), `ROLE_NOT_ALLOWED`,
|
|
512
|
+
* `CUSTOMER_ACCESS_PENDING`, `CUSTOMER_ACCESS_REJECTED` (403),
|
|
513
|
+
* `CUSTOMER_NOT_FOUND` (404), `ACCOUNT_DISABLED` (400) — and, on `verify-otp`,
|
|
514
|
+
* `VALIDATION_FAILED` (400) for a `code` that is not six digits.
|
|
515
|
+
*
|
|
516
|
+
* - `OTP_COOLDOWN` · 429 — `send-otp` inside 60 s of the last live code.
|
|
517
|
+
* - `EMAIL_ADDRESS_SUPPRESSED` · 409 — `send-otp`; the address bounced.
|
|
518
|
+
* `data` is {@link CustomerOtpSuppressedData}.
|
|
519
|
+
* - `EMAIL_ALREADY_VERIFIED` · 409 — `send-otp`; the stored address is already
|
|
520
|
+
* verified, so nothing was mailed. Hide the resend action.
|
|
521
|
+
* - `OTP_INVALID` · 400 — `verify-otp`; no code outstanding for the CURRENT
|
|
522
|
+
* address: none was sent, or the one sent went to an address the account no
|
|
523
|
+
* longer holds. Ask for a new code.
|
|
524
|
+
* - `OTP_ALREADY_USED` · 400 — `verify-otp`; the code was consumed, or lost a
|
|
525
|
+
* race (including a concurrent address change). Ask for a new code.
|
|
526
|
+
* - `OTP_EXPIRED` · 400 — `verify-otp`; past its 10-minute TTL.
|
|
527
|
+
* - `OTP_LOCKED` · 429 — `verify-otp`; 5 wrong guesses. Only a new `send-otp`
|
|
528
|
+
* unlocks.
|
|
529
|
+
* - `OTP_WRONG_CODE` · 400 — `verify-otp`; {@link CustomerOtpWrongCodeBody},
|
|
530
|
+
* `attemptsLeft` at the TOP level.
|
|
531
|
+
*
|
|
532
|
+
* ⚠️ Deliberately not the operator tree's vocabulary (`OTP_INVALID_OR_EXPIRED`,
|
|
533
|
+
* `OTP_TOO_MANY_ATTEMPTS`, `OTP_RESEND_TOO_SOON`); the two are not unified.
|
|
534
|
+
*/
|
|
535
|
+
export const CUSTOMER_OTP_ERROR_CODES = [
|
|
536
|
+
'OTP_COOLDOWN',
|
|
537
|
+
'EMAIL_ADDRESS_SUPPRESSED',
|
|
538
|
+
'EMAIL_ALREADY_VERIFIED',
|
|
539
|
+
'OTP_INVALID',
|
|
540
|
+
'OTP_ALREADY_USED',
|
|
541
|
+
'OTP_EXPIRED',
|
|
542
|
+
'OTP_LOCKED',
|
|
543
|
+
'OTP_WRONG_CODE',
|
|
544
|
+
];
|
|
545
|
+
/**
|
|
546
|
+
* The numbers the customer email OTP enforces, so a client countdown matches
|
|
547
|
+
* the server. The api's own OTP service reads them from here, for operators and
|
|
548
|
+
* customers alike.
|
|
549
|
+
*
|
|
550
|
+
* - `ttlSeconds` — a code expires this long after it was sent.
|
|
551
|
+
* - `resendCooldownSeconds` — `send-otp` answers `429 OTP_COOLDOWN` until this
|
|
552
|
+
* long after the last live code.
|
|
553
|
+
* - `maxAttempts` — wrong guesses per code before `429 OTP_LOCKED`; a new code
|
|
554
|
+
* starts the count again.
|
|
555
|
+
*/
|
|
556
|
+
export const CUSTOMER_OTP_LIMITS = { ttlSeconds: 600, resendCooldownSeconds: 60, maxAttempts: 5 };
|
package/dist/cjs/auth.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SESSION_ACTION_ERROR_CODES = exports.PASSKEY_ERROR_CODES = exports.TWO_FACTOR_MANAGEMENT_ERROR_CODES = exports.LOGIN_2FA_ERROR_CODES = exports.LOGIN_ERROR_CODES = exports.STEP_UP_ERROR_CODES = exports.REFRESH_ERROR_CODES = exports.CUSTOMER_SOCIAL_REGISTER_ERROR_CODES = exports.SOCIAL_BRIDGE_ERROR_CODES = exports.SIGN_IN_METHOD_ERROR_CODES = void 0;
|
|
3
|
+
exports.CUSTOMER_OTP_LIMITS = exports.CUSTOMER_OTP_ERROR_CODES = exports.SESSION_ACTION_ERROR_CODES = exports.PASSKEY_ERROR_CODES = exports.TWO_FACTOR_MANAGEMENT_ERROR_CODES = exports.LOGIN_2FA_ERROR_CODES = exports.LOGIN_ERROR_CODES = exports.STEP_UP_ERROR_CODES = exports.REFRESH_ERROR_CODES = exports.CUSTOMER_SOCIAL_REGISTER_ERROR_CODES = exports.SOCIAL_BRIDGE_ERROR_CODES = exports.SIGN_IN_METHOD_ERROR_CODES = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* `body.error` codes the sign-in-method paths can refuse with.
|
|
6
6
|
*
|
|
@@ -505,3 +505,55 @@ exports.SESSION_ACTION_ERROR_CODES = [
|
|
|
505
505
|
'SESSION_UNKNOWN',
|
|
506
506
|
'REVOKE_INCOMPLETE',
|
|
507
507
|
];
|
|
508
|
+
/**
|
|
509
|
+
* `body.error` codes the two customer email-OTP modes (Web API `POST /auth`
|
|
510
|
+
* `send-otp` / `verify-otp`) refuse with. Match on `body.error`.
|
|
511
|
+
*
|
|
512
|
+
* NOT members, and answered by both modes before any of these: the shared
|
|
513
|
+
* customer-identity refusals — `MISSING_TOKEN`, `INVALID_TOKEN`,
|
|
514
|
+
* `REFRESH_TOKEN_NOT_ALLOWED` (401), `ROLE_NOT_ALLOWED`,
|
|
515
|
+
* `CUSTOMER_ACCESS_PENDING`, `CUSTOMER_ACCESS_REJECTED` (403),
|
|
516
|
+
* `CUSTOMER_NOT_FOUND` (404), `ACCOUNT_DISABLED` (400) — and, on `verify-otp`,
|
|
517
|
+
* `VALIDATION_FAILED` (400) for a `code` that is not six digits.
|
|
518
|
+
*
|
|
519
|
+
* - `OTP_COOLDOWN` · 429 — `send-otp` inside 60 s of the last live code.
|
|
520
|
+
* - `EMAIL_ADDRESS_SUPPRESSED` · 409 — `send-otp`; the address bounced.
|
|
521
|
+
* `data` is {@link CustomerOtpSuppressedData}.
|
|
522
|
+
* - `EMAIL_ALREADY_VERIFIED` · 409 — `send-otp`; the stored address is already
|
|
523
|
+
* verified, so nothing was mailed. Hide the resend action.
|
|
524
|
+
* - `OTP_INVALID` · 400 — `verify-otp`; no code outstanding for the CURRENT
|
|
525
|
+
* address: none was sent, or the one sent went to an address the account no
|
|
526
|
+
* longer holds. Ask for a new code.
|
|
527
|
+
* - `OTP_ALREADY_USED` · 400 — `verify-otp`; the code was consumed, or lost a
|
|
528
|
+
* race (including a concurrent address change). Ask for a new code.
|
|
529
|
+
* - `OTP_EXPIRED` · 400 — `verify-otp`; past its 10-minute TTL.
|
|
530
|
+
* - `OTP_LOCKED` · 429 — `verify-otp`; 5 wrong guesses. Only a new `send-otp`
|
|
531
|
+
* unlocks.
|
|
532
|
+
* - `OTP_WRONG_CODE` · 400 — `verify-otp`; {@link CustomerOtpWrongCodeBody},
|
|
533
|
+
* `attemptsLeft` at the TOP level.
|
|
534
|
+
*
|
|
535
|
+
* ⚠️ Deliberately not the operator tree's vocabulary (`OTP_INVALID_OR_EXPIRED`,
|
|
536
|
+
* `OTP_TOO_MANY_ATTEMPTS`, `OTP_RESEND_TOO_SOON`); the two are not unified.
|
|
537
|
+
*/
|
|
538
|
+
exports.CUSTOMER_OTP_ERROR_CODES = [
|
|
539
|
+
'OTP_COOLDOWN',
|
|
540
|
+
'EMAIL_ADDRESS_SUPPRESSED',
|
|
541
|
+
'EMAIL_ALREADY_VERIFIED',
|
|
542
|
+
'OTP_INVALID',
|
|
543
|
+
'OTP_ALREADY_USED',
|
|
544
|
+
'OTP_EXPIRED',
|
|
545
|
+
'OTP_LOCKED',
|
|
546
|
+
'OTP_WRONG_CODE',
|
|
547
|
+
];
|
|
548
|
+
/**
|
|
549
|
+
* The numbers the customer email OTP enforces, so a client countdown matches
|
|
550
|
+
* the server. The api's own OTP service reads them from here, for operators and
|
|
551
|
+
* customers alike.
|
|
552
|
+
*
|
|
553
|
+
* - `ttlSeconds` — a code expires this long after it was sent.
|
|
554
|
+
* - `resendCooldownSeconds` — `send-otp` answers `429 OTP_COOLDOWN` until this
|
|
555
|
+
* long after the last live code.
|
|
556
|
+
* - `maxAttempts` — wrong guesses per code before `429 OTP_LOCKED`; a new code
|
|
557
|
+
* starts the count again.
|
|
558
|
+
*/
|
|
559
|
+
exports.CUSTOMER_OTP_LIMITS = { ttlSeconds: 600, resendCooldownSeconds: 60, maxAttempts: 5 };
|
package/dist/cjs/notification.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NotificationTypeEnum = void 0;
|
|
3
|
+
exports.WEB_NOTIFICATIONS_MAX_LIMIT = exports.CUSTOMER_NOTIFICATION_TYPES = exports.NotificationTypeEnum = void 0;
|
|
4
4
|
// Canonical notification taxonomy and keys for legacy/type × channel preferences.
|
|
5
5
|
// Indexed producers resolve candidates through `getNotificationSubscribers`:
|
|
6
6
|
// legacy opt-ins and explicit channel maps remain source data on USER rows.
|
|
@@ -200,3 +200,11 @@ var NotificationTypeEnum;
|
|
|
200
200
|
*/
|
|
201
201
|
NotificationTypeEnum["PAYMENT_ATTEMPT_RESOLUTION"] = "PAYMENT_ATTEMPT_RESOLUTION";
|
|
202
202
|
})(NotificationTypeEnum || (exports.NotificationTypeEnum = NotificationTypeEnum = {}));
|
|
203
|
+
/**
|
|
204
|
+
* The notification types a CUSTOMER bell can carry today; each links through
|
|
205
|
+
* `orderId`. Adding one means a new {@link CustomerNotification} member with its
|
|
206
|
+
* own link field — the storefront maps type → route from this list.
|
|
207
|
+
*/
|
|
208
|
+
exports.CUSTOMER_NOTIFICATION_TYPES = [NotificationTypeEnum.ORDER];
|
|
209
|
+
/** Web `GET /notifications` page ceiling and default (`?Limit=`). */
|
|
210
|
+
exports.WEB_NOTIFICATIONS_MAX_LIMIT = 500;
|
package/dist/cjs/order.js
CHANGED
|
@@ -372,12 +372,26 @@ exports.orderFulfilmentProgress = orderFulfilmentProgress;
|
|
|
372
372
|
* Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
373
373
|
*
|
|
374
374
|
* Storefront checkout business refusals. None allocates an order
|
|
375
|
-
* id, redeems a coupon or writes an order; none is logged as an error
|
|
375
|
+
* id, redeems a coupon or writes an order; none is logged as an error —
|
|
376
|
+
* except `CART_CHANGED_SINCE_CONFIRM` refused at commit, as its entry says:
|
|
376
377
|
* - `DELIVERY_METHOD_NOT_FOUND` · 400 — `deliveryMethod` is not in the store's
|
|
377
378
|
* delivery catalogue, including an absent/empty catalogue. `data: {}`;
|
|
378
379
|
* refused before reading the cart.
|
|
379
380
|
* - `ORDER_INVALID_CART` · 400 — the normalized cart has no finite numeric
|
|
380
381
|
* `totals.grandTotal`. `data: {}`; refused before repricing/allocation.
|
|
382
|
+
* - `CART_CHANGED_SINCE_CONFIRM` · 409 — the body sent `expectedCartId` /
|
|
383
|
+
* `expectedCartVersion` and the stored cart is not the cart the shopper
|
|
384
|
+
* confirmed (gone, replaced by another `cartId`, or at another `version`);
|
|
385
|
+
* `data` is `CartChangedSinceConfirmData` and carries no cart. Distinct from
|
|
386
|
+
* `ORDER_INVALID_CART` (a non-finite total) and from the operator's
|
|
387
|
+
* `CART_REVISION_STALE` / `CART_VERSION_*` (whose `data.basket` keeps
|
|
388
|
+
* `cost`). Decided at TWO points: right after the server's cart read, with
|
|
389
|
+
* nothing written and nothing logged; and at the commit, when the cart moved
|
|
390
|
+
* between the read and the write — then no order committed, but the order id
|
|
391
|
+
* allocated before the commit is consumed, a coupon redeemed before the
|
|
392
|
+
* commit is not released, and an ERROR row is logged.
|
|
393
|
+
* Re-read the cart and confirm again under a new `Idempotency-Key`; on
|
|
394
|
+
* `currentCartVersion: null` check the shopper's orders first.
|
|
381
395
|
* - `ORDER_BELOW_MINIMUM_PURCHASE` · 400 — after repricing has confirmed the
|
|
382
396
|
* cart, its grand total is below a finite positive `Number(customer.minBuy)`.
|
|
383
397
|
* Equality passes. `data: OrderBelowMinimumPurchaseData` carries minBuy,
|
|
@@ -638,6 +652,8 @@ exports.ORDER_ERROR_CODES = [
|
|
|
638
652
|
'DELIVERY_METHOD_NOT_FOUND',
|
|
639
653
|
'ORDER_BELOW_MINIMUM_PURCHASE',
|
|
640
654
|
'ORDER_INVALID_CART',
|
|
655
|
+
// The storefront's confirmed-cart pin (`StorefrontOrderCreateRequest.expectedCartId` / `expectedCartVersion`).
|
|
656
|
+
'CART_CHANGED_SINCE_CONFIRM',
|
|
641
657
|
'EMAIL_VERIFICATION_REQUIRED',
|
|
642
658
|
'ACCOUNT_DISABLED',
|
|
643
659
|
'CUSTOMER_ACCESS_PENDING',
|
package/dist/customer.d.ts
CHANGED
|
@@ -302,8 +302,16 @@ declare global {
|
|
|
302
302
|
email?: string;
|
|
303
303
|
/**
|
|
304
304
|
* Set `true` ONLY where the address is proven: by the customer OTP verify
|
|
305
|
-
* transaction
|
|
306
|
-
* provider verified the email (an unverified identity creates nothing)
|
|
305
|
+
* transaction; at creation by a storefront `register-social`, whose
|
|
306
|
+
* provider verified the email (an unverified identity creates nothing); or
|
|
307
|
+
* by a storefront social sign-in (`social`, `social-bridge-redeem`) or
|
|
308
|
+
* `link-sign-in-method` whose provider asserts a verified email equal,
|
|
309
|
+
* case-insensitively, to the stored one — never through an Apple Hide My
|
|
310
|
+
* Email relay, which is not the stored address. A sign-in then answers
|
|
311
|
+
* `true` in its body and the customer's own sockets get a `customers` frame.
|
|
312
|
+
* When that sign-in is the provider's FIRST on a row that held an unproven
|
|
313
|
+
* password, the password is removed and every earlier session revoked.
|
|
314
|
+
* Any move or clear of the address resets it to `false`.
|
|
307
315
|
*
|
|
308
316
|
* ⚠️ UNDEFINED MEANS **NOT** VERIFIED — deliberately the INVERSE of
|
|
309
317
|
* `User.emailVerified`, which carries a grandfather clause telling apps to
|
|
@@ -314,8 +322,10 @@ declare global {
|
|
|
314
322
|
*/
|
|
315
323
|
emailVerified?: boolean;
|
|
316
324
|
/**
|
|
317
|
-
* ms-epoch of the proof: the OTP verification,
|
|
318
|
-
*
|
|
325
|
+
* ms-epoch of the proof: the OTP verification, the social sign-in or link
|
|
326
|
+
* that proved it, or — for a `register-social` account — the row's
|
|
327
|
+
* `createdAt`. Kept from the FIRST proof; a later social sign-in does not
|
|
328
|
+
* move it. Absent or `null` whenever `emailVerified` is not `true`.
|
|
319
329
|
*/
|
|
320
330
|
emailVerifiedAt?: number;
|
|
321
331
|
/**
|
package/dist/notification.d.ts
CHANGED
|
@@ -179,6 +179,14 @@ export declare enum NotificationTypeEnum {
|
|
|
179
179
|
*/
|
|
180
180
|
PAYMENT_ATTEMPT_RESOLUTION = "PAYMENT_ATTEMPT_RESOLUTION"
|
|
181
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* The notification types a CUSTOMER bell can carry today; each links through
|
|
184
|
+
* `orderId`. Adding one means a new {@link CustomerNotification} member with its
|
|
185
|
+
* own link field — the storefront maps type → route from this list.
|
|
186
|
+
*/
|
|
187
|
+
export declare const CUSTOMER_NOTIFICATION_TYPES: readonly [NotificationTypeEnum.ORDER];
|
|
188
|
+
/** Web `GET /notifications` page ceiling and default (`?Limit=`). */
|
|
189
|
+
export declare const WEB_NOTIFICATIONS_MAX_LIMIT = 500;
|
|
182
190
|
declare global {
|
|
183
191
|
type CustomerNotificationPreferences = Partial<Record<'reminder-scheduled' | 'appointment-reminder', {
|
|
184
192
|
email: boolean;
|
|
@@ -241,6 +249,7 @@ declare global {
|
|
|
241
249
|
createdAt: number;
|
|
242
250
|
type: NotificationTypeEnum;
|
|
243
251
|
title: string;
|
|
252
|
+
/** `ORDER` links through `orderId` on both audiences (operator and customer). */
|
|
244
253
|
orderId?: string;
|
|
245
254
|
productId?: string;
|
|
246
255
|
lotId?: string;
|
|
@@ -305,7 +314,8 @@ declare global {
|
|
|
305
314
|
};
|
|
306
315
|
/**
|
|
307
316
|
* `GET /notifications` body on the operator host — the caller's own
|
|
308
|
-
* notifications, newest first, projected through an allow-list.
|
|
317
|
+
* notifications, newest first, projected through an allow-list. Operator
|
|
318
|
+
* host only; the web leg is {@link WebGetNotificationsResponse}.
|
|
309
319
|
*
|
|
310
320
|
* ⚠️ There is no `hasMore` on this leg: the ABSENCE of `LastEvaluatedKey` is
|
|
311
321
|
* the end of the list. A client that waits for a `hasMore: false` never stops
|
|
@@ -337,6 +347,52 @@ declare global {
|
|
|
337
347
|
hasMore: boolean;
|
|
338
348
|
};
|
|
339
349
|
}
|
|
350
|
+
type CustomerNotificationType = (typeof CUSTOMER_NOTIFICATION_TYPES)[number];
|
|
351
|
+
/**
|
|
352
|
+
* The customer projection: what web `GET`/`POST /notifications` and the
|
|
353
|
+
* customer socket carry — the stored row minus the operator-only pointers.
|
|
354
|
+
* A union keyed on `type`; `ORDER` is its only member today.
|
|
355
|
+
*/
|
|
356
|
+
type CustomerNotification = Omit<NotificationInterface, 'cartRef' | 'pendingCustomerRef' | 'TableName' | 'type' | 'orderId'> & {
|
|
357
|
+
type: NotificationTypeEnum.ORDER;
|
|
358
|
+
/** Set on every customer row: the order the bell is about. */
|
|
359
|
+
orderId: string;
|
|
360
|
+
};
|
|
361
|
+
/**
|
|
362
|
+
* Web `GET /notifications`: the caller's own rows, newest first by
|
|
363
|
+
* `createdAt`. An `offSet` outside the caller's own key range is
|
|
364
|
+
* `400 INVALID_CURSOR`; one inside it resumes from that position, whether
|
|
365
|
+
* or not a row with that id still exists.
|
|
366
|
+
*/
|
|
367
|
+
interface WebGetNotificationsResponse {
|
|
368
|
+
message: string;
|
|
369
|
+
data: CustomerNotification[];
|
|
370
|
+
/** The last row's `notificationId`; send it back as `?offSet=`. Absent = end of list. */
|
|
371
|
+
LastEvaluatedKey?: string;
|
|
372
|
+
}
|
|
373
|
+
/** Web `POST /notifications` (single, or `all: true`). */
|
|
374
|
+
interface WebPostNotificationsResponse {
|
|
375
|
+
message: string;
|
|
376
|
+
data: CustomerNotification[];
|
|
377
|
+
/** `all: true` only. */
|
|
378
|
+
updatedCount?: number;
|
|
379
|
+
/** `all: true` only — `true` means call again. */
|
|
380
|
+
hasMore?: boolean;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Customer socket frames, action `notifications`: one row as it is now
|
|
384
|
+
* stored (its `read` is the stored value, so a mark-unread reads `false`), or
|
|
385
|
+
* the mark-all summary.
|
|
386
|
+
*/
|
|
387
|
+
type CustomerNotificationFrame = CustomerNotification | {
|
|
388
|
+
storeId: string;
|
|
389
|
+
customerId: string;
|
|
390
|
+
bulkRead: true;
|
|
391
|
+
updatedCount: number;
|
|
392
|
+
hasMore: boolean;
|
|
393
|
+
/** Every row this call marked read (their `notificationId`); patch these, no refetch needed. */
|
|
394
|
+
notificationIds: string[];
|
|
395
|
+
};
|
|
340
396
|
/**
|
|
341
397
|
* What the outbound seam (`notify()`) knew about one call the moment its
|
|
342
398
|
* transport returned. It is never a delivery receipt: `enqueued` and
|
package/dist/notification.js
CHANGED
|
@@ -197,3 +197,11 @@ export var NotificationTypeEnum;
|
|
|
197
197
|
*/
|
|
198
198
|
NotificationTypeEnum["PAYMENT_ATTEMPT_RESOLUTION"] = "PAYMENT_ATTEMPT_RESOLUTION";
|
|
199
199
|
})(NotificationTypeEnum || (NotificationTypeEnum = {}));
|
|
200
|
+
/**
|
|
201
|
+
* The notification types a CUSTOMER bell can carry today; each links through
|
|
202
|
+
* `orderId`. Adding one means a new {@link CustomerNotification} member with its
|
|
203
|
+
* own link field — the storefront maps type → route from this list.
|
|
204
|
+
*/
|
|
205
|
+
export const CUSTOMER_NOTIFICATION_TYPES = [NotificationTypeEnum.ORDER];
|
|
206
|
+
/** Web `GET /notifications` page ceiling and default (`?Limit=`). */
|
|
207
|
+
export const WEB_NOTIFICATIONS_MAX_LIMIT = 500;
|
package/dist/order.d.ts
CHANGED
|
@@ -2137,6 +2137,24 @@ declare global {
|
|
|
2137
2137
|
*/
|
|
2138
2138
|
basket: Cart | null;
|
|
2139
2139
|
}
|
|
2140
|
+
/**
|
|
2141
|
+
* `data` of the storefront's `409 CART_CHANGED_SINCE_CONFIRM` — a web
|
|
2142
|
+
* `POST /orders` that sent {@link StorefrontOrderCreateRequest.expectedCartId}
|
|
2143
|
+
* or {@link StorefrontOrderCreateRequest.expectedCartVersion} against a cart
|
|
2144
|
+
* that is no longer the one the shopper confirmed. It carries no cart: re-read
|
|
2145
|
+
* it (`GET /basket`) and confirm again under a NEW `Idempotency-Key`.
|
|
2146
|
+
*/
|
|
2147
|
+
interface CartChangedSinceConfirmData {
|
|
2148
|
+
/**
|
|
2149
|
+
* The confirmed cart's stored `version` as the server now reads it — a
|
|
2150
|
+
* row with no stored `version` reads as `0`. `null` when the confirmed cart
|
|
2151
|
+
* is no longer the stored cart: it is gone, or a different cart replaced
|
|
2152
|
+
* it. ⚠️ On `null` the order may already exist (the confirmed cart is
|
|
2153
|
+
* deleted by its own checkout), so check the shopper's orders before
|
|
2154
|
+
* letting them retry.
|
|
2155
|
+
*/
|
|
2156
|
+
currentCartVersion: number | null;
|
|
2157
|
+
}
|
|
2140
2158
|
/**
|
|
2141
2159
|
* `data` of `409 CART_CUSTOMER_MISMATCH` — a create that sent
|
|
2142
2160
|
* {@link CreateOrderRequest.expectedCartVersion} for a cart that carries a
|
|
@@ -2358,6 +2376,25 @@ declare global {
|
|
|
2358
2376
|
};
|
|
2359
2377
|
/** Persist `deliveryAddress` as the customer's default. Directive only, never stored. */
|
|
2360
2378
|
saveAsDefault?: boolean;
|
|
2379
|
+
/**
|
|
2380
|
+
* The `cartId` of the cart the shopper confirmed (`CART` + 6-10 digits).
|
|
2381
|
+
* Omit it ONLY when that cart had none (a legacy cart). ⚠️ Compared
|
|
2382
|
+
* together with {@link expectedCartVersion} as ONE cart identity: a body
|
|
2383
|
+
* sending the version without this field means "the cart I confirmed had
|
|
2384
|
+
* no `cartId`", so a stored cart that has one is refused. A checkout
|
|
2385
|
+
* deletes its cart and the next add mints a NEW `cartId` at `version: 1`,
|
|
2386
|
+
* so a version alone does not identify a cart — always send this when the
|
|
2387
|
+
* rendered cart has one. A mismatch is `409 CART_CHANGED_SINCE_CONFIRM`.
|
|
2388
|
+
*/
|
|
2389
|
+
expectedCartId?: string;
|
|
2390
|
+
/**
|
|
2391
|
+
* The `version` of the cart the shopper confirmed, an integer ≥ 1. Omit it
|
|
2392
|
+
* when that cart had none. Refused `409 CART_CHANGED_SINCE_CONFIRM` when
|
|
2393
|
+
* the stored cart's version (absent reads as `0`) differs, and re-asserted
|
|
2394
|
+
* at the commit, so a write between the server's read and the order
|
|
2395
|
+
* transaction refuses too.
|
|
2396
|
+
*/
|
|
2397
|
+
expectedCartVersion?: number;
|
|
2361
2398
|
}
|
|
2362
2399
|
interface ZebraTag {
|
|
2363
2400
|
orderId: string;
|
|
@@ -2730,12 +2767,26 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2730
2767
|
* Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
2731
2768
|
*
|
|
2732
2769
|
* Storefront checkout business refusals. None allocates an order
|
|
2733
|
-
* id, redeems a coupon or writes an order; none is logged as an error
|
|
2770
|
+
* id, redeems a coupon or writes an order; none is logged as an error —
|
|
2771
|
+
* except `CART_CHANGED_SINCE_CONFIRM` refused at commit, as its entry says:
|
|
2734
2772
|
* - `DELIVERY_METHOD_NOT_FOUND` · 400 — `deliveryMethod` is not in the store's
|
|
2735
2773
|
* delivery catalogue, including an absent/empty catalogue. `data: {}`;
|
|
2736
2774
|
* refused before reading the cart.
|
|
2737
2775
|
* - `ORDER_INVALID_CART` · 400 — the normalized cart has no finite numeric
|
|
2738
2776
|
* `totals.grandTotal`. `data: {}`; refused before repricing/allocation.
|
|
2777
|
+
* - `CART_CHANGED_SINCE_CONFIRM` · 409 — the body sent `expectedCartId` /
|
|
2778
|
+
* `expectedCartVersion` and the stored cart is not the cart the shopper
|
|
2779
|
+
* confirmed (gone, replaced by another `cartId`, or at another `version`);
|
|
2780
|
+
* `data` is `CartChangedSinceConfirmData` and carries no cart. Distinct from
|
|
2781
|
+
* `ORDER_INVALID_CART` (a non-finite total) and from the operator's
|
|
2782
|
+
* `CART_REVISION_STALE` / `CART_VERSION_*` (whose `data.basket` keeps
|
|
2783
|
+
* `cost`). Decided at TWO points: right after the server's cart read, with
|
|
2784
|
+
* nothing written and nothing logged; and at the commit, when the cart moved
|
|
2785
|
+
* between the read and the write — then no order committed, but the order id
|
|
2786
|
+
* allocated before the commit is consumed, a coupon redeemed before the
|
|
2787
|
+
* commit is not released, and an ERROR row is logged.
|
|
2788
|
+
* Re-read the cart and confirm again under a new `Idempotency-Key`; on
|
|
2789
|
+
* `currentCartVersion: null` check the shopper's orders first.
|
|
2739
2790
|
* - `ORDER_BELOW_MINIMUM_PURCHASE` · 400 — after repricing has confirmed the
|
|
2740
2791
|
* cart, its grand total is below a finite positive `Number(customer.minBuy)`.
|
|
2741
2792
|
* Equality passes. `data: OrderBelowMinimumPurchaseData` carries minBuy,
|
|
@@ -2873,6 +2924,6 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2873
2924
|
* `SUBSCRIPTION_READONLY`) sit on the order CREATE leg only: an edit is not a new
|
|
2874
2925
|
* order, so `bareOrderPostHandler` routes past `requireMetered` entirely.
|
|
2875
2926
|
*/
|
|
2876
|
-
export declare const ORDER_ERROR_CODES: readonly ["ORDER_COST_DENOMINATION_UNKNOWN", "SERVICE_ORDER_DELIVERY_MANAGED", "ORDER_NOT_FOUND", "ORDER_LOCKED", "ORDER_NOT_READY", "ORDER_DELIVERED_ANOTHER_DAY", "ORDER_DELIVERY_STATE_UNCHANGED", "ORDER_ILLEGAL_TRANSITION", "ORDER_VERSION_CONFLICT", "CUSTOMER_NOT_FOUND", "CUSTOMER_MERGED", "ORDER_HAS_NO_CUSTOMER", "CUSTOMER_ANONYMIZED", "FX_CONVERSION_UNAVAILABLE", "ROLE_FORBIDDEN", "ORDER_CANCELLED", "PAYMENT_SETTLED_ON_ANOTHER_ORDER", "ORDER_HAS_SHIPMENTS", "ORDER_HAS_RETURNS", "SHIPMENT_QUANTITY_EXCEEDED", "SHIPMENT_LINE_MISMATCH", "SHIPMENT_NOT_FOUND", "SHIPMENT_LIMIT_REACHED", "SHIPMENT_TOO_LARGE", "ORDER_FULFILMENT_EXTERNAL", "SHIPMENT_FAILED", "ADMIN_REQUIRED", "IDEMPOTENCY_KEY_REQUIRED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_LOCK_CONTENTION", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENT_RESPONSE_NOT_CACHED", "ORDER_CANCELLATION_NOT_PROTECTED", "ORDER_CANCELLATION_COMMITTED", "ORDER_CANCELLATION_LOCKED", "ORDER_CANCELLATION_TOO_LARGE", "ORDER_CANCELLATION_FAILED", "SALE_LEDGER_RETRACTION_REFUSED", "SALE_LEDGER_ROW_NOT_OWNED", "PRODUCT_NOT_FOUND", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "DEPOSIT_SOURCE_NOT_ALLOWED", "DEPOSIT_CURRENCY_MISMATCH", "DEPOSIT_EXCEEDS_TOTAL", "DEPOSIT_FREEZE_REQUIRES_INVOICE", "DEPOSIT_FREEZE_INVOICE_PENDING", "DEPOSIT_CHARACTERIZATION_CONFLICT", "DEPOSIT_FREEZE_INVOICE_NOT_QUALIFYING", "DEPOSIT_INVOICED_ORDER_MUST_FREEZE", "DEPOSIT_FROZEN_ORDER_MUST_FREEZE", "DEPOSIT_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "TILL_TENDER_REQUIRES_DEPOSIT", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "ORDER_PRICE_FROZEN", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "UNIT_QUANTITY_UNREPRESENTABLE", "KIT_RECIPE_CHANGED", "CART_PROMOTION_UNAVAILABLE", "ORDER_HAS_KIT_LINES", "ORDER_TARGET_REQUIRED", "ORDER_SOURCE_CONFLICT", "ORDER_CUSTOMER_REQUIRED", "BASKET_EMPTY", "BASKET_CHANGED_DURING_CHECKOUT", "CART_VERSION_CREATE_ONLY", "CART_VERSION_REQUIRES_CART_ID", "CART_REVISION_STALE", "CART_CUSTOMER_MISMATCH", "COUNTER_SALE_CREATE_ONLY", "SOLD_AT_CREATE_ONLY", "SOLD_AT_IN_FUTURE", "ORDER_TENDER_CREATE_ONLY", "CREDIT_OVERRIDE_CREATE_ONLY", "ON_ACCOUNT_CREATE_ONLY", "ON_ACCOUNT_WITH_TENDERS", "TENDERS_REQUIRE_COUNTER_SALE", "LINES_REQUIRE_COUNTER_SALE", "PRODUCT_COST_UNKNOWN", "PRICE_CHANGE_DISABLED", "LINE_DISCOUNT_EXCEEDS_MAX", "CUSTOMER_DISABLED", "SHIFT_NOT_AVAILABLE", "SOLD_AT_OUTSIDE_SHIFT", "ORDER_CURRENCY_NOT_SUBSCRIBED", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "PAYMENT_METHOD_UNAVAILABLE", "CART_PRICES_CHANGED", "ORDER_ID_COLLISION", "DELIVERY_METHOD_NOT_FOUND", "ORDER_BELOW_MINIMUM_PURCHASE", "ORDER_INVALID_CART", "EMAIL_VERIFICATION_REQUIRED", "ACCOUNT_DISABLED", "CUSTOMER_ACCESS_PENDING", "CUSTOMER_ACCESS_REJECTED", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "ORDER_DISCOUNT_AFTER_INVOICE", "ORDER_DISCOUNT_ON_SERVICE_ORDER", "ORDER_DISCOUNT_ON_MARKETPLACE_ORDER", "ORDER_INVOICE_METHOD_OUTSTANDING_FACTURA", "ORDER_SERVICE_PERIOD_AFTER_INVOICE", "ORDER_ATTEMPT_COMMITTED", "ORDER_ATTEMPT_ABANDONED", "ORDER_ATTEMPT_KEY_EXPIRED", "ORDER_ATTEMPT_KEY_SCOPE_MISMATCH", "ORDER_COMPLETION_ATTEMPT_COMMITTED", "ORDER_COMPLETION_ATTEMPT_ABANDONED"];
|
|
2927
|
+
export declare const ORDER_ERROR_CODES: readonly ["ORDER_COST_DENOMINATION_UNKNOWN", "SERVICE_ORDER_DELIVERY_MANAGED", "ORDER_NOT_FOUND", "ORDER_LOCKED", "ORDER_NOT_READY", "ORDER_DELIVERED_ANOTHER_DAY", "ORDER_DELIVERY_STATE_UNCHANGED", "ORDER_ILLEGAL_TRANSITION", "ORDER_VERSION_CONFLICT", "CUSTOMER_NOT_FOUND", "CUSTOMER_MERGED", "ORDER_HAS_NO_CUSTOMER", "CUSTOMER_ANONYMIZED", "FX_CONVERSION_UNAVAILABLE", "ROLE_FORBIDDEN", "ORDER_CANCELLED", "PAYMENT_SETTLED_ON_ANOTHER_ORDER", "ORDER_HAS_SHIPMENTS", "ORDER_HAS_RETURNS", "SHIPMENT_QUANTITY_EXCEEDED", "SHIPMENT_LINE_MISMATCH", "SHIPMENT_NOT_FOUND", "SHIPMENT_LIMIT_REACHED", "SHIPMENT_TOO_LARGE", "ORDER_FULFILMENT_EXTERNAL", "SHIPMENT_FAILED", "ADMIN_REQUIRED", "IDEMPOTENCY_KEY_REQUIRED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_LOCK_CONTENTION", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENT_RESPONSE_NOT_CACHED", "ORDER_CANCELLATION_NOT_PROTECTED", "ORDER_CANCELLATION_COMMITTED", "ORDER_CANCELLATION_LOCKED", "ORDER_CANCELLATION_TOO_LARGE", "ORDER_CANCELLATION_FAILED", "SALE_LEDGER_RETRACTION_REFUSED", "SALE_LEDGER_ROW_NOT_OWNED", "PRODUCT_NOT_FOUND", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "DEPOSIT_SOURCE_NOT_ALLOWED", "DEPOSIT_CURRENCY_MISMATCH", "DEPOSIT_EXCEEDS_TOTAL", "DEPOSIT_FREEZE_REQUIRES_INVOICE", "DEPOSIT_FREEZE_INVOICE_PENDING", "DEPOSIT_CHARACTERIZATION_CONFLICT", "DEPOSIT_FREEZE_INVOICE_NOT_QUALIFYING", "DEPOSIT_INVOICED_ORDER_MUST_FREEZE", "DEPOSIT_FROZEN_ORDER_MUST_FREEZE", "DEPOSIT_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "TILL_TENDER_REQUIRES_DEPOSIT", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "ORDER_PRICE_FROZEN", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "UNIT_QUANTITY_UNREPRESENTABLE", "KIT_RECIPE_CHANGED", "CART_PROMOTION_UNAVAILABLE", "ORDER_HAS_KIT_LINES", "ORDER_TARGET_REQUIRED", "ORDER_SOURCE_CONFLICT", "ORDER_CUSTOMER_REQUIRED", "BASKET_EMPTY", "BASKET_CHANGED_DURING_CHECKOUT", "CART_VERSION_CREATE_ONLY", "CART_VERSION_REQUIRES_CART_ID", "CART_REVISION_STALE", "CART_CUSTOMER_MISMATCH", "COUNTER_SALE_CREATE_ONLY", "SOLD_AT_CREATE_ONLY", "SOLD_AT_IN_FUTURE", "ORDER_TENDER_CREATE_ONLY", "CREDIT_OVERRIDE_CREATE_ONLY", "ON_ACCOUNT_CREATE_ONLY", "ON_ACCOUNT_WITH_TENDERS", "TENDERS_REQUIRE_COUNTER_SALE", "LINES_REQUIRE_COUNTER_SALE", "PRODUCT_COST_UNKNOWN", "PRICE_CHANGE_DISABLED", "LINE_DISCOUNT_EXCEEDS_MAX", "CUSTOMER_DISABLED", "SHIFT_NOT_AVAILABLE", "SOLD_AT_OUTSIDE_SHIFT", "ORDER_CURRENCY_NOT_SUBSCRIBED", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "PAYMENT_METHOD_UNAVAILABLE", "CART_PRICES_CHANGED", "ORDER_ID_COLLISION", "DELIVERY_METHOD_NOT_FOUND", "ORDER_BELOW_MINIMUM_PURCHASE", "ORDER_INVALID_CART", "CART_CHANGED_SINCE_CONFIRM", "EMAIL_VERIFICATION_REQUIRED", "ACCOUNT_DISABLED", "CUSTOMER_ACCESS_PENDING", "CUSTOMER_ACCESS_REJECTED", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "ORDER_DISCOUNT_AFTER_INVOICE", "ORDER_DISCOUNT_ON_SERVICE_ORDER", "ORDER_DISCOUNT_ON_MARKETPLACE_ORDER", "ORDER_INVOICE_METHOD_OUTSTANDING_FACTURA", "ORDER_SERVICE_PERIOD_AFTER_INVOICE", "ORDER_ATTEMPT_COMMITTED", "ORDER_ATTEMPT_ABANDONED", "ORDER_ATTEMPT_KEY_EXPIRED", "ORDER_ATTEMPT_KEY_SCOPE_MISMATCH", "ORDER_COMPLETION_ATTEMPT_COMMITTED", "ORDER_COMPLETION_ATTEMPT_ABANDONED"];
|
|
2877
2928
|
export type OrderErrorCode = (typeof ORDER_ERROR_CODES)[number];
|
|
2878
2929
|
export {};
|
package/dist/order.js
CHANGED
|
@@ -365,12 +365,26 @@ export const orderFulfilmentProgress = (order) => {
|
|
|
365
365
|
* Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
366
366
|
*
|
|
367
367
|
* Storefront checkout business refusals. None allocates an order
|
|
368
|
-
* id, redeems a coupon or writes an order; none is logged as an error
|
|
368
|
+
* id, redeems a coupon or writes an order; none is logged as an error —
|
|
369
|
+
* except `CART_CHANGED_SINCE_CONFIRM` refused at commit, as its entry says:
|
|
369
370
|
* - `DELIVERY_METHOD_NOT_FOUND` · 400 — `deliveryMethod` is not in the store's
|
|
370
371
|
* delivery catalogue, including an absent/empty catalogue. `data: {}`;
|
|
371
372
|
* refused before reading the cart.
|
|
372
373
|
* - `ORDER_INVALID_CART` · 400 — the normalized cart has no finite numeric
|
|
373
374
|
* `totals.grandTotal`. `data: {}`; refused before repricing/allocation.
|
|
375
|
+
* - `CART_CHANGED_SINCE_CONFIRM` · 409 — the body sent `expectedCartId` /
|
|
376
|
+
* `expectedCartVersion` and the stored cart is not the cart the shopper
|
|
377
|
+
* confirmed (gone, replaced by another `cartId`, or at another `version`);
|
|
378
|
+
* `data` is `CartChangedSinceConfirmData` and carries no cart. Distinct from
|
|
379
|
+
* `ORDER_INVALID_CART` (a non-finite total) and from the operator's
|
|
380
|
+
* `CART_REVISION_STALE` / `CART_VERSION_*` (whose `data.basket` keeps
|
|
381
|
+
* `cost`). Decided at TWO points: right after the server's cart read, with
|
|
382
|
+
* nothing written and nothing logged; and at the commit, when the cart moved
|
|
383
|
+
* between the read and the write — then no order committed, but the order id
|
|
384
|
+
* allocated before the commit is consumed, a coupon redeemed before the
|
|
385
|
+
* commit is not released, and an ERROR row is logged.
|
|
386
|
+
* Re-read the cart and confirm again under a new `Idempotency-Key`; on
|
|
387
|
+
* `currentCartVersion: null` check the shopper's orders first.
|
|
374
388
|
* - `ORDER_BELOW_MINIMUM_PURCHASE` · 400 — after repricing has confirmed the
|
|
375
389
|
* cart, its grand total is below a finite positive `Number(customer.minBuy)`.
|
|
376
390
|
* Equality passes. `data: OrderBelowMinimumPurchaseData` carries minBuy,
|
|
@@ -631,6 +645,8 @@ export const ORDER_ERROR_CODES = [
|
|
|
631
645
|
'DELIVERY_METHOD_NOT_FOUND',
|
|
632
646
|
'ORDER_BELOW_MINIMUM_PURCHASE',
|
|
633
647
|
'ORDER_INVALID_CART',
|
|
648
|
+
// The storefront's confirmed-cart pin (`StorefrontOrderCreateRequest.expectedCartId` / `expectedCartVersion`).
|
|
649
|
+
'CART_CHANGED_SINCE_CONFIRM',
|
|
634
650
|
'EMAIL_VERIFICATION_REQUIRED',
|
|
635
651
|
'ACCOUNT_DISABLED',
|
|
636
652
|
'CUSTOMER_ACCESS_PENDING',
|
package/dist/store.d.ts
CHANGED
|
@@ -1222,6 +1222,14 @@ declare global {
|
|
|
1222
1222
|
* until they verify. That is the tenant's decision to make, but a
|
|
1223
1223
|
* settings UI should say so rather than presenting it as a neutral
|
|
1224
1224
|
* switch.
|
|
1225
|
+
*
|
|
1226
|
+
* Web `GET /store` (and the storefront preview's store frame) ALWAYS
|
|
1227
|
+
* carries it as a boolean, `true` only when the stored value is exactly
|
|
1228
|
+
* `true` — absent, `false` or any other stored value reads `false`, the
|
|
1229
|
+
* same test checkout applies. A storefront reads it to prompt for
|
|
1230
|
+
* verification before checkout rather than after the
|
|
1231
|
+
* `403 EMAIL_VERIFICATION_REQUIRED`. It is not on the customer `stores`
|
|
1232
|
+
* socket frame; the next `GET /store` picks up a change.
|
|
1225
1233
|
*/
|
|
1226
1234
|
requireEmailVerification?: boolean;
|
|
1227
1235
|
}
|