@tokenoftrust/cli 3.7.4 → 3.7.5
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/package.json +1 -1
- package/src/declared-config.d.mts +3 -0
- package/src/declared-config.mjs +51 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/cli",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.5",
|
|
4
4
|
"description": "Token of Trust developer CLI — clone a tenant store, run it locally with save→reload, and submit it for preview. Installs the `tot` command.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Token of Trust",
|
|
@@ -23,7 +23,10 @@ export const CURRENCY_CODES: readonly string[];
|
|
|
23
23
|
export function resolveStoreCurrency(declared: unknown): string;
|
|
24
24
|
export function currencyDeclarationProblems(currency: unknown): string[];
|
|
25
25
|
export const SHIPPING_KEYS: readonly string[];
|
|
26
|
+
export const SHIPPING_TIER_KEYS: readonly string[];
|
|
26
27
|
export const MAX_SHIPPING_AMOUNT: number;
|
|
28
|
+
export const MAX_SHIPPING_TIERS: number;
|
|
29
|
+
export const MAX_SHIPPING_LABEL_LENGTH: number;
|
|
27
30
|
export function shippingDeclarationProblems(shipping: unknown): string[];
|
|
28
31
|
export const COMPLIANCE_NOTICES: Record<string, string>;
|
|
29
32
|
export const MANDATED_NOTICE_KEYS: string[];
|
package/src/declared-config.mjs
CHANGED
|
@@ -197,20 +197,38 @@ export function seoDeclarationProblems(seo) {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
/** Every `shipping` key (mirrors packages/public-runtime/src/declared-tenant-config.mjs). */
|
|
200
|
-
export const SHIPPING_KEYS = Object.freeze(["
|
|
200
|
+
export const SHIPPING_KEYS = Object.freeze(["tiers"]);
|
|
201
|
+
|
|
202
|
+
/** Every key of one `shipping.tiers` entry. */
|
|
203
|
+
export const SHIPPING_TIER_KEYS = Object.freeze(["atOrAbove", "rate", "label"]);
|
|
201
204
|
|
|
202
205
|
/** Largest shipping amount a declaration may state, in the cart's currency. */
|
|
203
206
|
export const MAX_SHIPPING_AMOUNT = 100000;
|
|
204
207
|
|
|
208
|
+
/** Most tiers one policy may declare. */
|
|
209
|
+
export const MAX_SHIPPING_TIERS = 10;
|
|
210
|
+
|
|
211
|
+
/** Longest shipping-line label, in characters. */
|
|
212
|
+
export const MAX_SHIPPING_LABEL_LENGTH = 100;
|
|
213
|
+
|
|
205
214
|
/** @param {unknown} value */
|
|
206
215
|
const isShippingAmount = (value) =>
|
|
207
216
|
typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= MAX_SHIPPING_AMOUNT
|
|
208
217
|
&& Math.abs(value * 100 - Math.round(value * 100)) < 1e-6;
|
|
209
218
|
|
|
219
|
+
/** @param {unknown} value */
|
|
220
|
+
const isShippingLabel = (value) =>
|
|
221
|
+
typeof value === "string" && value.trim() === value && value.length > 0
|
|
222
|
+
&& [...value].length <= MAX_SHIPPING_LABEL_LENGTH && !/[\u0000-\u001f\u007f]/.test(value);
|
|
223
|
+
|
|
210
224
|
/**
|
|
211
225
|
* What is wrong with a declared `shipping` value, one sentence per problem; `[]` when it is
|
|
212
226
|
* valid. A policy with any problem is refused whole, so checkout never charges half of one.
|
|
213
227
|
*
|
|
228
|
+
* Tiers are ordered by the item subtotal they start at. The first starts at 0 and states no
|
|
229
|
+
* `atOrAbove`; each later tier's `atOrAbove` is above the one before it and is inclusive, so an
|
|
230
|
+
* order whose subtotal equals it pays that tier's `rate`.
|
|
231
|
+
*
|
|
214
232
|
* @param {unknown} shipping
|
|
215
233
|
* @returns {string[]}
|
|
216
234
|
*/
|
|
@@ -221,12 +239,38 @@ export function shippingDeclarationProblems(shipping) {
|
|
|
221
239
|
for (const key of Object.keys(source)) {
|
|
222
240
|
if (!SHIPPING_KEYS.includes(key)) problems.push(`\`shipping.${key}\` is not a shipping key (${SHIPPING_KEYS.join(", ")})`);
|
|
223
241
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
problems.push(`\`shipping.freeAtOrAbove\` must be an amount above 0 and at most ${MAX_SHIPPING_AMOUNT} with at most two decimal places`);
|
|
242
|
+
const tiers = source.tiers;
|
|
243
|
+
if (!Array.isArray(tiers) || tiers.length === 0 || tiers.length > MAX_SHIPPING_TIERS) {
|
|
244
|
+
problems.push(`\`shipping.tiers\` must be a list of 1 to ${MAX_SHIPPING_TIERS} tiers`);
|
|
245
|
+
return problems;
|
|
229
246
|
}
|
|
247
|
+
let previous = 0;
|
|
248
|
+
tiers.forEach((tier, index) => {
|
|
249
|
+
const at = `shipping.tiers[${index}]`;
|
|
250
|
+
if (!isPlainObject(tier)) {
|
|
251
|
+
problems.push(`\`${at}\` must be an object`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const entry = /** @type {Record<string, unknown>} */ (tier);
|
|
255
|
+
for (const key of Object.keys(entry)) {
|
|
256
|
+
if (!SHIPPING_TIER_KEYS.includes(key)) problems.push(`\`${at}.${key}\` is not a tier key (${SHIPPING_TIER_KEYS.join(", ")})`);
|
|
257
|
+
}
|
|
258
|
+
if (!isShippingAmount(entry.rate)) {
|
|
259
|
+
problems.push(`\`${at}.rate\` must be an amount from 0 to ${MAX_SHIPPING_AMOUNT} with at most two decimal places`);
|
|
260
|
+
}
|
|
261
|
+
if (entry.label !== undefined && !isShippingLabel(entry.label)) {
|
|
262
|
+
problems.push(`\`${at}.label\` must be text of 1 to ${MAX_SHIPPING_LABEL_LENGTH} characters with no surrounding spaces or line breaks`);
|
|
263
|
+
}
|
|
264
|
+
if (index === 0) {
|
|
265
|
+
if (entry.atOrAbove !== undefined) problems.push(`\`${at}\` starts at 0, so it states no \`atOrAbove\``);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (!(isShippingAmount(entry.atOrAbove) && /** @type {number} */ (entry.atOrAbove) > previous)) {
|
|
269
|
+
problems.push(`\`${at}.atOrAbove\` must be an amount above ${previous}, where the tier before it starts, and at most ${MAX_SHIPPING_AMOUNT} with at most two decimal places`);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
previous = /** @type {number} */ (entry.atOrAbove);
|
|
273
|
+
});
|
|
230
274
|
return problems;
|
|
231
275
|
}
|
|
232
276
|
|
|
@@ -702,7 +746,7 @@ export function validateDeclaredConfig(config, file = ".tot/config.json") {
|
|
|
702
746
|
const problems = shippingDeclarationProblems(config.shipping);
|
|
703
747
|
if (problems.length > 0) {
|
|
704
748
|
out.push(mk(ERROR, "config-shipping", `${file} shipping`, shippingProblemMessage(problems),
|
|
705
|
-
'declare e.g. `"shipping": { "
|
|
749
|
+
'declare e.g. `"shipping": { "tiers": [ { "rate": 5.99 }, { "atOrAbove": 100, "rate": 0, "label": "Free shipping" } ] }`, or remove `shipping` to charge none'));
|
|
706
750
|
}
|
|
707
751
|
}
|
|
708
752
|
return out;
|