@zappie/check 0.2.3 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @zappie/check
2
2
 
3
+ ## 0.2.6
4
+
5
+ ### Patch Changes
6
+
7
+ - dc14434: Reload `zappie.config.ts` whenever its content changes, including when a rewrite keeps the same modification time.
8
+
9
+ ## 0.2.5
10
+
11
+ ### Patch Changes
12
+
13
+ - b0b2a59: Let a site raise V15's first-card tappable limit to 5000 ms with an explained site budget, and record the applied limit in the verify report. A site that adds `budgets.tappableMs` must upgrade `@zappie/check` and `@zappie/sdk` in the same change.
14
+ - Updated dependencies [b0b2a59]
15
+ - @zappie/sdk@0.1.15
16
+
17
+ ## 0.2.4
18
+
19
+ ### Patch Changes
20
+
21
+ - 5a2bce9: Verify can start somewhere other than `/`, for a site whose root is a directory of its menus. Set `verify.startPath` in `zappie.config.ts`, or pass `startPath` to `verify()` or `verifyProject()`. Every check that opened `/` as the menu opens that route instead. Set `verify.cataloguePath`, such as `/menu?menu={menu}`, when each menu has its own page: V03 then needs 95% of each menu's available items on that menu's page, instead of 95% of the branch's items on one page, and the checks that use an item open the page of a menu that holds it. A route must start with one `/` and contain no backslash. A site that sets neither runs as before. The report's `environment` records `startPath`, and `cataloguePath` when it is set. When `--store` is passed and `zappie.config.ts` exists but can't be read, the report's `warnings` says its verify settings were ignored. The `@zappie/sdk` site config and `zappie check` accept the `verify` settings, so a site that adds them needs `@zappie/sdk` 0.1.14 and `@zappie/check` 0.2.4 in the same change. This is a minor release, so a regression comparison doesn't compare these reports with reports from 0.2.
22
+ - Updated dependencies [5a2bce9]
23
+ - @zappie/sdk@0.1.14
24
+
3
25
  ## 0.2.3
4
26
 
5
27
  ### Patch Changes
package/dist/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
  var DEFAULT_BUDGETS = {
3
3
  jsKbGz: 200,
4
4
  cssKbGz: 50,
5
- lcpMs: 2500
5
+ lcpMs: 2500,
6
+ tappableMs: 3e3
6
7
  };
7
8
  var GLOBAL_PACKAGE_ALLOWLIST = [
8
9
  "react",
@@ -96,7 +97,7 @@ function budgets(value, issue, error) {
96
97
  nested(
97
98
  value,
98
99
  "budgets",
99
- ["jsKbGz", "cssKbGz", "lcpMs", "override"],
100
+ [...Object.keys(DEFAULT_BUDGETS), "override"],
100
101
  issue,
101
102
  (budget) => {
102
103
  nested(
@@ -114,28 +115,35 @@ function budgets(value, issue, error) {
114
115
  }
115
116
  }
116
117
  );
117
- for (const key of ["jsKbGz", "cssKbGz", "lcpMs"]) {
118
+ for (const key of Object.keys(DEFAULT_BUDGETS)) {
118
119
  const amount = budget[key];
120
+ const path15 = `budgets.${key}`;
119
121
  if (amount === void 0) {
120
122
  continue;
121
123
  }
122
124
  if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0) {
123
125
  error(
124
- `budgets.${key}`,
126
+ path15,
125
127
  "invalid_type",
126
- `Expected a positive finite number. Set budgets.${key} to a number greater than zero.`
128
+ `Expected a positive finite number. Set ${path15} to a number greater than zero.`
129
+ );
130
+ } else if (key === "tappableMs" && amount > 5e3) {
131
+ error(
132
+ path15,
133
+ "invalid_format",
134
+ "The tappableMs budget cannot exceed 5000. Set budgets.tappableMs to 5000 or less."
127
135
  );
128
136
  } else if (amount > DEFAULT_BUDGETS[key]) {
129
137
  const message6 = `The ${key} budget exceeds the ${DEFAULT_BUDGETS[key]} default.`;
130
138
  if (budget.override === void 0) {
131
139
  error(
132
- `budgets.${key}`,
140
+ path15,
133
141
  "budget_override",
134
142
  `${message6} Add budgets.override.reason to explain the increase.`
135
143
  );
136
144
  } else {
137
145
  issue({
138
- path: `budgets.${key}`,
146
+ path: path15,
139
147
  code: "budget_override",
140
148
  message: `${message6} Lower it to the default when the exception is no longer needed.`,
141
149
  severity: "warning"
@@ -186,7 +194,8 @@ var rootKeys = [
186
194
  "security",
187
195
  "budgets",
188
196
  "readiness",
189
- "analytics"
197
+ "analytics",
198
+ "verify"
190
199
  ];
191
200
  function validateConfig(input) {
192
201
  const issues = [];
@@ -206,14 +215,30 @@ function validateConfig(input) {
206
215
  };
207
216
  }
208
217
  unknownKeys(input, rootKeys, "", issue);
209
- requiredSlug(input.store, "store", error);
218
+ if (!nonblank(input.store)) {
219
+ error(
220
+ "store",
221
+ input.store === void 0 ? "missing_required" : "invalid_type",
222
+ "Expected a non-empty storefront slug. Set store to the slug used by createZappie()."
223
+ );
224
+ }
210
225
  theme(input.theme, error);
211
226
  stringList(input.branches, "branches", error, {
212
227
  nonempty: true,
213
228
  unique: true,
214
229
  slug: true
215
230
  });
216
- paths(input.prerender, error);
231
+ stringList(input.prerender, "prerender", error, { unique: true })?.forEach(
232
+ (path15, index) => {
233
+ if (!path15.startsWith("/")) {
234
+ error(
235
+ `prerender[${index}]`,
236
+ "invalid_format",
237
+ "Expected a route starting with /. Prefix the route with /."
238
+ );
239
+ }
240
+ }
241
+ );
217
242
  nested(input.menu, "menu", ["hiddenCategories"], issue, (value) => {
218
243
  stringList(value.hiddenCategories, "menu.hiddenCategories", error);
219
244
  });
@@ -285,20 +310,19 @@ function validateConfig(input) {
285
310
  }
286
311
  );
287
312
  analytics(input.analytics, issue, error);
313
+ nested(
314
+ input.verify,
315
+ "verify",
316
+ ["startPath", "cataloguePath"],
317
+ issue,
318
+ () => {
319
+ }
320
+ );
288
321
  return {
289
322
  valid: !issues.some((entry) => entry.severity === "error"),
290
323
  issues
291
324
  };
292
325
  }
293
- function requiredSlug(value, path15, error) {
294
- if (!nonblank(value)) {
295
- error(
296
- path15,
297
- value === void 0 ? "missing_required" : "invalid_type",
298
- `Expected a non-empty storefront slug. Set ${path15} to the slug used by createZappie().`
299
- );
300
- }
301
- }
302
326
  function theme(value, error) {
303
327
  if (typeof value !== "string") {
304
328
  error(
@@ -362,18 +386,6 @@ function hostList(value, path15, error) {
362
386
  }
363
387
  });
364
388
  }
365
- function paths(value, error) {
366
- const values = stringList(value, "prerender", error, { unique: true });
367
- values?.forEach((path15, index) => {
368
- if (!path15.startsWith("/")) {
369
- error(
370
- `prerender[${index}]`,
371
- "invalid_format",
372
- "Expected a route starting with /. Prefix the route with /."
373
- );
374
- }
375
- });
376
- }
377
389
 
378
390
  // src/allowlist.ts
379
391
  import { access, readFile as readFile3 } from "fs/promises";
@@ -1076,7 +1088,8 @@ function validateTheme(input) {
1076
1088
  }
1077
1089
 
1078
1090
  // src/config.ts
1079
- import { readFile as readFile2, stat } from "fs/promises";
1091
+ import { createHash } from "crypto";
1092
+ import { readFile as readFile2 } from "fs/promises";
1080
1093
  import path2 from "path";
1081
1094
  import { pathToFileURL } from "url";
1082
1095
 
@@ -1127,7 +1140,7 @@ async function loadConfig(cwd) {
1127
1140
  );
1128
1141
  }
1129
1142
  const source = await readFile2(file, "utf8");
1130
- const version = (await stat(file)).mtimeMs;
1143
+ const version = createHash("sha256").update(source).digest("hex");
1131
1144
  const loaded = await import(`${pathToFileURL(file).href}?check=${version}`);
1132
1145
  return { value: loaded.default, source, file };
1133
1146
  }