platform-types 1.10.763 → 1.10.765
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/product.js +13 -1
- package/dist/collection.d.ts +2 -1
- package/dist/customer.d.ts +14 -4
- package/dist/product.d.ts +62 -3
- package/dist/product.js +12 -0
- package/dist/store.d.ts +8 -0
- package/dist/storefrontDesign.d.ts +3 -2
- 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/product.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PRODUCT_MEDIA_INVALID_REASONS = exports.MAX_PRODUCT_PICTURE_ALT_CHARS = exports.PRODUCT_UPSERT_ERROR_CODES = exports.PRODUCT_UPSERT_ROW_ERROR_CODES = exports.PRODUCT_UPSERT_ROW_CAP = exports.PUBLIC_PRODUCT_BY_SLUG_ERROR_CODES = exports.PRODUCT_PUBLISH_OVERDUE_AFTER_MS = exports.PRODUCT_PUBLISH_AT_MAX_AHEAD_MS = exports.PRODUCT_POST_ERROR_CODES = exports.PRODUCT_IDENTITY_ERROR_CODES = exports.PRODUCT_EXPORT_ERROR_CODES = exports.PRODUCT_CATALOG_EXPORT_COLUMNS = exports.MAX_BASE_QUANTITY = exports.BASE_QUANTITY_DECIMAL_PLACES = void 0;
|
|
3
|
+
exports.PRODUCT_MEDIA_INVALID_REASONS = exports.MAX_PRODUCT_PICTURE_ALT_CHARS = exports.PRODUCT_UPSERT_ERROR_CODES = exports.PRODUCT_UPSERT_ROW_ERROR_CODES = exports.PRODUCT_UPSERT_ROW_CAP = exports.PUBLIC_PRODUCT_SUGGEST_ERROR_CODES = exports.PUBLIC_PRODUCT_BY_SLUG_ERROR_CODES = exports.PRODUCT_PUBLISH_OVERDUE_AFTER_MS = exports.PRODUCT_PUBLISH_AT_MAX_AHEAD_MS = exports.PRODUCT_POST_ERROR_CODES = exports.PRODUCT_IDENTITY_ERROR_CODES = exports.PRODUCT_EXPORT_ERROR_CODES = exports.PRODUCT_CATALOG_EXPORT_COLUMNS = exports.DISCOVERY_SORTS = exports.MAX_BASE_QUANTITY = exports.BASE_QUANTITY_DECIMAL_PLACES = void 0;
|
|
4
4
|
/** Maximum decimal places in a canonical base quantity; inputs are exact, never rounded. */
|
|
5
5
|
exports.BASE_QUANTITY_DECIMAL_PLACES = 6;
|
|
6
6
|
/** Absolute base-quantity input bound; signed adjustments admit the negative of this value. */
|
|
7
7
|
exports.MAX_BASE_QUANTITY = 1_000_000;
|
|
8
|
+
/**
|
|
9
|
+
* The `sort` values Web `GET /products?mode=discover` serves. `newest` is
|
|
10
|
+
* descending product id; name and price sorts are not served (no index can
|
|
11
|
+
* order them inside one bounded request).
|
|
12
|
+
*/
|
|
13
|
+
exports.DISCOVERY_SORTS = ['newest'];
|
|
8
14
|
/**
|
|
9
15
|
* The CSV header of `GET /products?mode=export`, in file order.
|
|
10
16
|
*
|
|
@@ -161,6 +167,12 @@ exports.PUBLIC_PRODUCT_BY_SLUG_ERROR_CODES = [
|
|
|
161
167
|
'PRODUCT_NOT_FOUND',
|
|
162
168
|
'PRODUCT_LOOKUP_INCOMPLETE',
|
|
163
169
|
];
|
|
170
|
+
/** Refusals of Web `GET /products?mode=suggest`: 400, 400, 503. */
|
|
171
|
+
exports.PUBLIC_PRODUCT_SUGGEST_ERROR_CODES = [
|
|
172
|
+
'VALIDATION_FAILED',
|
|
173
|
+
'INVALID_SUGGEST_QUERY',
|
|
174
|
+
'PRODUCT_LOOKUP_INCOMPLETE',
|
|
175
|
+
];
|
|
164
176
|
/** Rows one `POST /products { mode: 'upsert' }` request takes; a longer file is sent in chunks. */
|
|
165
177
|
exports.PRODUCT_UPSERT_ROW_CAP = 200;
|
|
166
178
|
/**
|
package/dist/collection.d.ts
CHANGED
|
@@ -28,7 +28,8 @@ declare global {
|
|
|
28
28
|
* nothing with it and list everything the rest selects. `inOffer` and
|
|
29
29
|
* `inStock` are the string `'true'`, as on that read.
|
|
30
30
|
*/
|
|
31
|
-
|
|
31
|
+
/** A stored discovery query: the filters only — never `sort` (a collection answers in discovery order). */
|
|
32
|
+
type CollectionQuery = Omit<PublicProductDiscoverInput, 'mode' | 'startKey' | 'sort'>;
|
|
32
33
|
interface Collection {
|
|
33
34
|
storeId: string;
|
|
34
35
|
/** `COL` + at least six digits, minted by the api. */
|
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/product.d.ts
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
export declare const BASE_QUANTITY_DECIMAL_PLACES = 6;
|
|
3
3
|
/** Absolute base-quantity input bound; signed adjustments admit the negative of this value. */
|
|
4
4
|
export declare const MAX_BASE_QUANTITY = 1000000;
|
|
5
|
+
/**
|
|
6
|
+
* The `sort` values Web `GET /products?mode=discover` serves. `newest` is
|
|
7
|
+
* descending product id; name and price sorts are not served (no index can
|
|
8
|
+
* order them inside one bounded request).
|
|
9
|
+
*/
|
|
10
|
+
export declare const DISCOVERY_SORTS: readonly ["newest"];
|
|
11
|
+
export type DiscoverySort = (typeof DISCOVERY_SORTS)[number];
|
|
5
12
|
declare global {
|
|
6
13
|
type ProductUnitsErrorCode = 'UNIT_REVISION_STALE' | 'UNIT_FACTOR_INVALID' | 'UNIT_FACTOR_MISMATCH' | 'UNIT_INCOMPATIBLE_DIMENSION' | 'UNIT_QUANTITY_UNREPRESENTABLE' | 'UNIT_QUANTITY_NOT_WHOLE';
|
|
7
14
|
type ProductUnit = 'each' | 'gram' | 'kilogram' | 'millilitre' | 'litre' | 'metre';
|
|
@@ -247,23 +254,72 @@ declare global {
|
|
|
247
254
|
* while no product carries it.
|
|
248
255
|
*/
|
|
249
256
|
tagId?: string;
|
|
250
|
-
/**
|
|
257
|
+
/**
|
|
258
|
+
* Only products on offer at the caller's own price: a promo window open now
|
|
259
|
+
* on the one price slot the caller is priced at (a guest's is the store
|
|
260
|
+
* default list). A promo on another list does not count.
|
|
261
|
+
*/
|
|
251
262
|
inOffer?: 'true';
|
|
252
263
|
/** Only products the online stock authority can sell now; services always pass. */
|
|
253
264
|
inStock?: 'true';
|
|
254
265
|
/** Only products explicitly marked as new; an absent flag does not pass. */
|
|
255
266
|
isNew?: 'true';
|
|
256
|
-
/**
|
|
267
|
+
/**
|
|
268
|
+
* A member of `DISCOVERY_SORTS`. `newest` = descending product id (mint
|
|
269
|
+
* order), on every filter combination. A well-formed value the api does not
|
|
270
|
+
* serve is 400 `DISCOVERY_SORT_UNSUPPORTED` ({@link DiscoverySortRefusal});
|
|
271
|
+
* one not matching `^[a-z_]{1,32}$` is 400 `INVALID_DISCOVERY_QUERY`. An
|
|
272
|
+
* empty value is absent. Bound into the cursor when present.
|
|
273
|
+
*/
|
|
274
|
+
sort?: string;
|
|
275
|
+
/** The previous response's `LastEvaluatedKey`, under the SAME filters and sort; else 400 INVALID_CURSOR. */
|
|
257
276
|
startKey?: string;
|
|
258
277
|
}
|
|
259
278
|
/** One page of a discovery walk; `data` can be empty while `LastEvaluatedKey` is set. */
|
|
260
279
|
interface PublicProductDiscoverResponse {
|
|
261
280
|
message: string;
|
|
262
|
-
/** Public price/projection and online stock, in index order. */
|
|
281
|
+
/** Public price/projection and online stock, in `sort` order, else index order. */
|
|
263
282
|
data: PublicProduct[];
|
|
283
|
+
/** The sort applied — present only when the request carried one. */
|
|
284
|
+
sort?: (typeof DISCOVERY_SORTS)[number];
|
|
264
285
|
/** Present while rows remain; absent means the walk is complete. */
|
|
265
286
|
LastEvaluatedKey?: string;
|
|
266
287
|
}
|
|
288
|
+
/** Anonymous Web GET /products typeahead; the tenant comes from the public store context. */
|
|
289
|
+
interface PublicProductSuggestInput {
|
|
290
|
+
mode: 'suggest';
|
|
291
|
+
/** Trimmed, 2–64 chars, at least one search term after the split; else 400 INVALID_SUGGEST_QUERY. */
|
|
292
|
+
q: string;
|
|
293
|
+
/** Integer 1–10, default 8; anything else 400 INVALID_SUGGEST_QUERY. */
|
|
294
|
+
limit?: string;
|
|
295
|
+
}
|
|
296
|
+
/** Why a suggestion matched; drives ranking and the storefront's highlight. */
|
|
297
|
+
type PublicProductSuggestMatch = 'barcode' | 'sku' | 'name' | 'text';
|
|
298
|
+
/** One typeahead row: identity and display only — never a price, stock or offer flag. */
|
|
299
|
+
type PublicProductSuggestion = Pick<PublicProduct, 'slug' | 'sku' | 'thumbnailUrl'> & {
|
|
300
|
+
productId: string;
|
|
301
|
+
name: string;
|
|
302
|
+
/** Why it matched; drives ranking and the storefront's highlight. */
|
|
303
|
+
match: PublicProductSuggestMatch;
|
|
304
|
+
};
|
|
305
|
+
interface PublicProductSuggestResponse {
|
|
306
|
+
message: string;
|
|
307
|
+
/** Ranked barcode > sku > name > text, ties newest first; never more than `limit`. No cursor. */
|
|
308
|
+
data: PublicProductSuggestion[];
|
|
309
|
+
/**
|
|
310
|
+
* Present when the text walk stopped with catalogue rows unread (page
|
|
311
|
+
* budget, the soft deadline or a full `limit`): a better match may exist.
|
|
312
|
+
*/
|
|
313
|
+
truncated?: true;
|
|
314
|
+
}
|
|
315
|
+
/** Refusals of Web `GET /products?mode=discover`. */
|
|
316
|
+
type DiscoveryErrorCode = 'INVALID_DISCOVERY_QUERY' | 'INVALID_CURSOR' | 'DISCOVERY_SORT_UNSUPPORTED';
|
|
317
|
+
/** 400 body for a well-formed `sort` the api does not serve; `supportedSorts` lists what it does. */
|
|
318
|
+
interface DiscoverySortRefusal {
|
|
319
|
+
message: string;
|
|
320
|
+
error: 'DISCOVERY_SORT_UNSUPPORTED';
|
|
321
|
+
supportedSorts: (typeof DISCOVERY_SORTS)[number][];
|
|
322
|
+
}
|
|
267
323
|
/** Write shape for product create/update — carries the transient picture-removal control. */
|
|
268
324
|
type ProductUpsertInput = Omit<Partial<Product>, 'pictures' | 'thumbnailUrl' | 'publishAt' | 'units' | 'unitRevisionGeneration'> & {
|
|
269
325
|
/** Omitted preserves the declaration; null clears it only when the product is unused. */
|
|
@@ -1519,6 +1575,9 @@ export declare const PRODUCT_PUBLISH_OVERDUE_AFTER_MS: number;
|
|
|
1519
1575
|
*/
|
|
1520
1576
|
export declare const PUBLIC_PRODUCT_BY_SLUG_ERROR_CODES: readonly ["VALIDATION_FAILED", "INVALID_SLUG", "PRODUCT_NOT_FOUND", "PRODUCT_LOOKUP_INCOMPLETE"];
|
|
1521
1577
|
export type PublicProductBySlugErrorCode = (typeof PUBLIC_PRODUCT_BY_SLUG_ERROR_CODES)[number];
|
|
1578
|
+
/** Refusals of Web `GET /products?mode=suggest`: 400, 400, 503. */
|
|
1579
|
+
export declare const PUBLIC_PRODUCT_SUGGEST_ERROR_CODES: readonly ["VALIDATION_FAILED", "INVALID_SUGGEST_QUERY", "PRODUCT_LOOKUP_INCOMPLETE"];
|
|
1580
|
+
export type PublicProductSuggestErrorCode = (typeof PUBLIC_PRODUCT_SUGGEST_ERROR_CODES)[number];
|
|
1522
1581
|
/** Rows one `POST /products { mode: 'upsert' }` request takes; a longer file is sent in chunks. */
|
|
1523
1582
|
export declare const PRODUCT_UPSERT_ROW_CAP = 200;
|
|
1524
1583
|
/**
|
package/dist/product.js
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
export const BASE_QUANTITY_DECIMAL_PLACES = 6;
|
|
3
3
|
/** Absolute base-quantity input bound; signed adjustments admit the negative of this value. */
|
|
4
4
|
export const MAX_BASE_QUANTITY = 1_000_000;
|
|
5
|
+
/**
|
|
6
|
+
* The `sort` values Web `GET /products?mode=discover` serves. `newest` is
|
|
7
|
+
* descending product id; name and price sorts are not served (no index can
|
|
8
|
+
* order them inside one bounded request).
|
|
9
|
+
*/
|
|
10
|
+
export const DISCOVERY_SORTS = ['newest'];
|
|
5
11
|
/**
|
|
6
12
|
* The CSV header of `GET /products?mode=export`, in file order.
|
|
7
13
|
*
|
|
@@ -158,6 +164,12 @@ export const PUBLIC_PRODUCT_BY_SLUG_ERROR_CODES = [
|
|
|
158
164
|
'PRODUCT_NOT_FOUND',
|
|
159
165
|
'PRODUCT_LOOKUP_INCOMPLETE',
|
|
160
166
|
];
|
|
167
|
+
/** Refusals of Web `GET /products?mode=suggest`: 400, 400, 503. */
|
|
168
|
+
export const PUBLIC_PRODUCT_SUGGEST_ERROR_CODES = [
|
|
169
|
+
'VALIDATION_FAILED',
|
|
170
|
+
'INVALID_SUGGEST_QUERY',
|
|
171
|
+
'PRODUCT_LOOKUP_INCOMPLETE',
|
|
172
|
+
];
|
|
161
173
|
/** Rows one `POST /products { mode: 'upsert' }` request takes; a longer file is sent in chunks. */
|
|
162
174
|
export const PRODUCT_UPSERT_ROW_CAP = 200;
|
|
163
175
|
/**
|
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
|
}
|
|
@@ -663,11 +663,12 @@ declare global {
|
|
|
663
663
|
* The codes a catalogue operation answers through its public web route's own core, as that
|
|
664
664
|
* route does: 404 `PRODUCT_NOT_FOUND` / `PRODUCT_GROUP_NOT_FOUND` / `COLLECTION_NOT_FOUND`,
|
|
665
665
|
* 400 `INVALID_CURSOR` / `INVALID_DISCOVERY_QUERY` / `INVALID_UPDATED_AT` (an `incomes`
|
|
666
|
-
* `updatedAt` that is not digits within the safe-integer range)
|
|
666
|
+
* `updatedAt` that is not digits within the safe-integer range) / `DISCOVERY_SORT_UNSUPPORTED`
|
|
667
|
+
* (a `products` read with a well-formed `sort` the api does not serve), 409 `CURSOR_STALE` (a
|
|
667
668
|
* collection that changed between the reads bracketing a page) and 503
|
|
668
669
|
* `PRODUCT_LOOKUP_INCOMPLETE`.
|
|
669
670
|
*/
|
|
670
|
-
type StorefrontPreviewCatalogueErrorCode = 'PRODUCT_NOT_FOUND' | 'PRODUCT_GROUP_NOT_FOUND' | 'COLLECTION_NOT_FOUND' | 'INVALID_CURSOR' | 'INVALID_DISCOVERY_QUERY' | 'INVALID_UPDATED_AT' | 'CURSOR_STALE' | 'PRODUCT_LOOKUP_INCOMPLETE';
|
|
671
|
+
type StorefrontPreviewCatalogueErrorCode = 'PRODUCT_NOT_FOUND' | 'PRODUCT_GROUP_NOT_FOUND' | 'COLLECTION_NOT_FOUND' | 'INVALID_CURSOR' | 'INVALID_DISCOVERY_QUERY' | 'INVALID_UPDATED_AT' | 'DISCOVERY_SORT_UNSUPPORTED' | 'CURSOR_STALE' | 'PRODUCT_LOOKUP_INCOMPLETE';
|
|
671
672
|
interface StorefrontPreviewReadFailure {
|
|
672
673
|
message: string;
|
|
673
674
|
error: StorefrontPreviewReadErrorCode | StorefrontPreviewCatalogueErrorCode;
|