@domandigital/craft 0.20.1 → 0.20.2

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,11 @@
1
1
  # @domandigital/craft
2
2
 
3
+ ## 0.20.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 5199c0e: `measureRoute(open, options)` measures every viewport for a page only the caller can open, such as a portal screen behind a sign-in: the phone half in a page the caller opens in `PHONE`, the wide half in one it opens in `DESKTOP` (now exported), merged and written once for `craft phone-first --measured`, as `measureSite` does for a public page (DOM-835).
8
+
3
9
  ## 0.20.1
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -305,7 +305,10 @@ test(`every viewport: ${route}`, async ({ page }) => {
305
305
  ```
306
306
 
307
307
  `measureViewports` works on the page the suite opened and signed in, so a
308
- portal keeps its fixtures. `measureSite(browser, { base, routes })` opens each
308
+ portal keeps its fixtures. `measureRoute(open, { route, mainAction })` does
309
+ both halves for such a page: `open("phone")` and `open("wide")` return the
310
+ route opened and signed in, in a `PHONE` and a `DESKTOP` context, and the two
311
+ halves are merged and written once (DOM-835). `measureSite(browser, { base, routes })` opens each
309
312
  route itself, the phone half in a phone context and the wide half in a desktop
310
313
  one, for a page anyone can open: create-site's `measure.mjs` uses it.
311
314
  `craft viewports --url <base> --route /` is the same for the command line: it
@@ -7,10 +7,10 @@ import {
7
7
  } from "./chunk-2OBDCIVW.js";
8
8
  import {
9
9
  loadNull
10
- } from "./chunk-IZ6GTU54.js";
10
+ } from "./chunk-YRXMPI3T.js";
11
11
  import {
12
12
  parseFlags
13
- } from "./chunk-6NXPDCUO.js";
13
+ } from "./chunk-JLLULDVW.js";
14
14
  import {
15
15
  toJson
16
16
  } from "./chunk-QIEDBL4J.js";
@@ -631,7 +631,7 @@ async function briefFor(flags, cwd) {
631
631
  if (typeof brief === "string" && brief.trim()) return brief;
632
632
  } else if (flags.direction) throw new Error(`no such file: ${flags.direction}`);
633
633
  if (flags.null) {
634
- const { loadNull } = await import("./cli-NTNUZUFP.js");
634
+ const { loadNull } = await import("./cli-KJRHO3YO.js");
635
635
  return loadNull(flags.null, cwd).brief;
636
636
  }
637
637
  return void 0;
@@ -657,37 +657,37 @@ async function compareWithCompetitor(flags, io) {
657
657
  function run(argv, io) {
658
658
  const [command, ...rest] = argv;
659
659
  if (command === "direction") {
660
- return import("./cli-MKZJMZUJ.js").then((m) => m.runDirection(rest, io));
660
+ return import("./cli-YQEVPRL5.js").then((m) => m.runDirection(rest, io));
661
661
  }
662
662
  if (command === "report" || command === "retrofit") {
663
- return import("./cli-VFKKFRB4.js").then((m) => m.runReport(command, rest, io));
663
+ return import("./cli-A6SNEMRL.js").then((m) => m.runReport(command, rest, io));
664
664
  }
665
665
  if (command === "register") {
666
666
  return import("./cli-ZXDGVDYU.js").then((m) => m.runRegister(rest, io));
667
667
  }
668
668
  if (command === "estate") {
669
- return import("./cli-HUN5ZTH5.js").then((m) => m.runEstate(rest, io));
669
+ return import("./cli-DZGQOIBX.js").then((m) => m.runEstate(rest, io));
670
670
  }
671
671
  if (command === "null") {
672
- return import("./cli-NTNUZUFP.js").then((m) => m.runNull(rest, io));
672
+ return import("./cli-KJRHO3YO.js").then((m) => m.runNull(rest, io));
673
673
  }
674
674
  if (command === "calibrate") {
675
- return import("./cli-DVYLDCEA.js").then((m) => m.runCalibrate(rest, io));
675
+ return import("./cli-LVYTLT2A.js").then((m) => m.runCalibrate(rest, io));
676
676
  }
677
677
  if (command === "tells" && rest[0] === "harvest") {
678
- return import("./cli-NTNUZUFP.js").then((m) => m.runHarvest(rest, io)).catch((error) => {
678
+ return import("./cli-KJRHO3YO.js").then((m) => m.runHarvest(rest, io)).catch((error) => {
679
679
  io.err(`craft: ${error.message}`);
680
680
  return 2;
681
681
  });
682
682
  }
683
683
  if (command === "phone-first") {
684
- return import("./cli-LSJI7QRD.js").then((m) => m.runPhoneFirst(rest, io));
684
+ return import("./cli-FF2YDHA4.js").then((m) => m.runPhoneFirst(rest, io));
685
685
  }
686
686
  if (command === "viewports") {
687
- return import("./viewports-cli-C4VXMPKK.js").then((m) => m.runViewports(rest, io));
687
+ return import("./viewports-cli-WWWWEBKI.js").then((m) => m.runViewports(rest, io));
688
688
  }
689
689
  if (command === "snapshot" || command === "audit") {
690
- return import("./cli-IREKGVSM.js").then((m) => m.runAudit(command, rest, io));
690
+ return import("./cli-U7PJQKZT.js").then((m) => m.runAudit(command, rest, io));
691
691
  }
692
692
  if (!command || command === "help" || command === "--help" || command === "-h") {
693
693
  io.out(HELP);
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  describeTypicality,
7
7
  loadNull
8
- } from "./chunk-IZ6GTU54.js";
8
+ } from "./chunk-YRXMPI3T.js";
9
9
  import {
10
10
  SOURCE_FILE,
11
11
  finish,
@@ -14,7 +14,7 @@ import {
14
14
  parseFlags,
15
15
  prepareReport,
16
16
  readPaths
17
- } from "./chunk-6NXPDCUO.js";
17
+ } from "./chunk-JLLULDVW.js";
18
18
  import {
19
19
  toJson
20
20
  } from "./chunk-QIEDBL4J.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-OQXTQQAU.js";
4
4
  import {
5
5
  parseFlags
6
- } from "./chunk-6NXPDCUO.js";
6
+ } from "./chunk-JLLULDVW.js";
7
7
  import {
8
8
  toJson
9
9
  } from "./chunk-QIEDBL4J.js";
@@ -3,21 +3,21 @@ import {
3
3
  } from "./chunk-OKVHWXYV.js";
4
4
  import {
5
5
  merge
6
- } from "./chunk-GOPHZI6O.js";
6
+ } from "./chunk-TCMM3PTK.js";
7
7
  import "./chunk-YOZLPNJS.js";
8
8
  import "./chunk-JYNXGCYZ.js";
9
9
  import {
10
10
  SIBLING_AT,
11
11
  compareToEstate,
12
12
  loadEstate
13
- } from "./chunk-FQYKKKHI.js";
13
+ } from "./chunk-IJXDBYHH.js";
14
14
  import {
15
15
  PAGE_TYPES,
16
16
  validateDirection
17
17
  } from "./chunk-2OBDCIVW.js";
18
18
  import {
19
19
  loadNull
20
- } from "./chunk-IZ6GTU54.js";
20
+ } from "./chunk-YRXMPI3T.js";
21
21
  import "./chunk-OQXTQQAU.js";
22
22
  import {
23
23
  COPY_FILE,
@@ -28,7 +28,7 @@ import {
28
28
  loadExceptions,
29
29
  parseFlags,
30
30
  readPaths
31
- } from "./chunk-6NXPDCUO.js";
31
+ } from "./chunk-JLLULDVW.js";
32
32
  import {
33
33
  toJson
34
34
  } from "./chunk-QIEDBL4J.js";
@@ -4,11 +4,11 @@ import {
4
4
  formatPairs,
5
5
  loadEstate,
6
6
  runEstate
7
- } from "./chunk-FQYKKKHI.js";
7
+ } from "./chunk-IJXDBYHH.js";
8
8
  import "./chunk-2OBDCIVW.js";
9
- import "./chunk-IZ6GTU54.js";
9
+ import "./chunk-YRXMPI3T.js";
10
10
  import "./chunk-OQXTQQAU.js";
11
- import "./chunk-6NXPDCUO.js";
11
+ import "./chunk-JLLULDVW.js";
12
12
  import "./chunk-QIEDBL4J.js";
13
13
  import "./chunk-WUACK2HX.js";
14
14
  import "./chunk-JGWOA4LI.js";
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  SOURCE_FILE,
11
11
  readPaths
12
- } from "./chunk-6NXPDCUO.js";
12
+ } from "./chunk-JLLULDVW.js";
13
13
  import {
14
14
  toJson
15
15
  } from "./chunk-QIEDBL4J.js";
@@ -9,9 +9,9 @@ import {
9
9
  runHarvest,
10
10
  runNull,
11
11
  serveDir
12
- } from "./chunk-IZ6GTU54.js";
12
+ } from "./chunk-YRXMPI3T.js";
13
13
  import "./chunk-OQXTQQAU.js";
14
- import "./chunk-6NXPDCUO.js";
14
+ import "./chunk-JLLULDVW.js";
15
15
  import "./chunk-QIEDBL4J.js";
16
16
  import "./chunk-WUACK2HX.js";
17
17
  import "./chunk-JGWOA4LI.js";
@@ -4,11 +4,11 @@ import {
4
4
  import {
5
5
  expandNullTargets,
6
6
  loadNull
7
- } from "./chunk-IZ6GTU54.js";
7
+ } from "./chunk-YRXMPI3T.js";
8
8
  import "./chunk-OQXTQQAU.js";
9
9
  import {
10
10
  parseFlags
11
- } from "./chunk-6NXPDCUO.js";
11
+ } from "./chunk-JLLULDVW.js";
12
12
  import {
13
13
  toJson
14
14
  } from "./chunk-QIEDBL4J.js";
@@ -4,12 +4,12 @@ import {
4
4
  merge,
5
5
  resolvePages,
6
6
  runAudit
7
- } from "./chunk-GOPHZI6O.js";
7
+ } from "./chunk-TCMM3PTK.js";
8
8
  import "./chunk-YOZLPNJS.js";
9
9
  import "./chunk-JYNXGCYZ.js";
10
- import "./chunk-IZ6GTU54.js";
10
+ import "./chunk-YRXMPI3T.js";
11
11
  import "./chunk-OQXTQQAU.js";
12
- import "./chunk-6NXPDCUO.js";
12
+ import "./chunk-JLLULDVW.js";
13
13
  import "./chunk-QIEDBL4J.js";
14
14
  import "./chunk-WUACK2HX.js";
15
15
  import "./chunk-JGWOA4LI.js";
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-2OBDCIVW.js";
11
11
  import {
12
12
  parseFlags
13
- } from "./chunk-6NXPDCUO.js";
13
+ } from "./chunk-JLLULDVW.js";
14
14
  import {
15
15
  toJson
16
16
  } from "./chunk-QIEDBL4J.js";
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  run
4
- } from "./chunk-6NXPDCUO.js";
4
+ } from "./chunk-JLLULDVW.js";
5
5
  import "./chunk-QIEDBL4J.js";
6
6
  import "./chunk-JGWOA4LI.js";
7
7
  import "./chunk-7DQDF3VL.js";
package/dist/phone.cjs CHANGED
@@ -24,6 +24,7 @@ __export(phone_exports, {
24
24
  DEFAULT_MEASURED_DIR: () => DEFAULT_MEASURED_DIR,
25
25
  DEFAULT_SWEEP: () => DEFAULT_SWEEP,
26
26
  DEFAULT_THRESHOLDS: () => DEFAULT_THRESHOLDS,
27
+ DESKTOP: () => DESKTOP,
27
28
  EMPTY_BASELINE: () => EMPTY_BASELINE,
28
29
  LADDER: () => LADDER,
29
30
  PHONE: () => PHONE,
@@ -38,6 +39,7 @@ __export(phone_exports, {
38
39
  mainActionFor: () => mainActionFor,
39
40
  measurePhone: () => measurePhone,
40
41
  measurePhoneInPage: () => measurePhoneInPage,
42
+ measureRoute: () => measureRoute,
41
43
  measureSite: () => measureSite,
42
44
  measureViewportInPage: () => measureViewportInPage,
43
45
  measureViewports: () => measureViewports,
@@ -724,6 +726,21 @@ async function measureViewports(page, options) {
724
726
  await page.evaluate(() => document.fonts?.ready.then(() => void 0), void 0);
725
727
  return finish(options.route, await collect(page, options), options.out);
726
728
  }
729
+ var DESKTOP = { viewport: { width: 1024, height: 768 }, deviceScaleFactor: 1 };
730
+ async function measureRoute(open, options) {
731
+ if (!options.route.startsWith("/")) throw new Error(`measureRoute: route "${options.route}" should start with /`);
732
+ const collected = [];
733
+ for (const scope of ["phone", "wide"]) {
734
+ const { page, close } = await open(scope);
735
+ try {
736
+ await page.evaluate(() => document.fonts?.ready.then(() => void 0), void 0);
737
+ collected.push(await collect(page, { ...options, scope }));
738
+ } finally {
739
+ await close?.();
740
+ }
741
+ }
742
+ return finish(options.route, { perViewport: collected.flatMap((c) => c.perViewport), tested: collected.flatMap((c) => c.tested) }, options.out);
743
+ }
727
744
  async function measureSite(browser, options) {
728
745
  const result = { routes: [], errors: [] };
729
746
  for (const route of options.routes) {
@@ -731,7 +748,7 @@ async function measureSite(browser, options) {
731
748
  let failed = null;
732
749
  for (const [scope, context] of [
733
750
  ["phone", PHONE],
734
- ["wide", { viewport: { width: 1024, height: 768 }, deviceScaleFactor: 1 }]
751
+ ["wide", DESKTOP]
735
752
  ]) {
736
753
  const ctx = await browser.newContext({ ...context });
737
754
  try {
@@ -775,6 +792,7 @@ async function measurePhone(page, options) {
775
792
  DEFAULT_MEASURED_DIR,
776
793
  DEFAULT_SWEEP,
777
794
  DEFAULT_THRESHOLDS,
795
+ DESKTOP,
778
796
  EMPTY_BASELINE,
779
797
  LADDER,
780
798
  PHONE,
@@ -789,6 +807,7 @@ async function measurePhone(page, options) {
789
807
  mainActionFor,
790
808
  measurePhone,
791
809
  measurePhoneInPage,
810
+ measureRoute,
792
811
  measureSite,
793
812
  measureViewportInPage,
794
813
  measureViewports,
package/dist/phone.d.cts CHANGED
@@ -335,6 +335,35 @@ interface ViewportsResult extends MeasuredRoute {
335
335
  * not judge or throw on a finding: the baseline decides.
336
336
  */
337
337
  declare function measureViewports(page: ViewportPage, options: MeasureViewportsOptions): Promise<ViewportsResult>;
338
+ /** The desktop context the wide half is measured in, beside `PHONE` for the phone half. Spread into `browser.newContext`. */
339
+ declare const DESKTOP: {
340
+ readonly viewport: {
341
+ readonly width: 1024;
342
+ readonly height: 768;
343
+ };
344
+ readonly deviceScaleFactor: 1;
345
+ };
346
+ /** A page opened at the route, and how to close it when its half is measured. */
347
+ interface OpenedPage {
348
+ page: ViewportPage;
349
+ close?: () => Promise<void>;
350
+ }
351
+ /**
352
+ * Every viewport for a route only the caller can open, such as a portal screen
353
+ * behind a sign-in (DOM-835). As `measureSite` does for a public page, the
354
+ * phone half is measured in a phone context and the wide half in a desktop
355
+ * one; `open(scope)` returns a page already at the route, signed in with the
356
+ * suite's fixtures, in `PHONE` for "phone" and `DESKTOP` for "wide". The two
357
+ * halves are merged and written once, for `craft phone-first --measured`.
358
+ *
359
+ * await measureRoute(async (scope) => {
360
+ * const context = await browser.newContext({ ...(scope === "phone" ? PHONE : DESKTOP), extraHTTPHeaders: auth });
361
+ * const page = await context.newPage();
362
+ * await page.goto(base + route);
363
+ * return { page, close: () => context.close() };
364
+ * }, { route, mainAction: 'a[href="/portal/requests/new"]' });
365
+ */
366
+ declare function measureRoute(open: (scope: "phone" | "wide") => Promise<OpenedPage>, options: Omit<MeasureViewportsOptions, "scope">): Promise<ViewportsResult>;
338
367
  interface SitePage extends ViewportPage {
339
368
  goto(url: string): Promise<{
340
369
  ok(): boolean;
@@ -419,4 +448,4 @@ interface MeasurePhoneOptions {
419
448
  */
420
449
  declare function measurePhone(page: MinimalPage, options: MeasurePhoneOptions): Promise<MeasuredRoute>;
421
450
 
422
- export { BANDS, type Band, type Baseline, DEFAULT_MEASURED_DIR, DEFAULT_SWEEP, DEFAULT_THRESHOLDS, EMPTY_BASELINE, type FileException, type InPageGroup, type Judgement, LADDER, type MainAction, type MeasurePhoneOptions, type MeasureSiteOptions, type MeasureViewportsOptions, type MeasuredRoute, PHONE, PHONE_FLOORS, type PhoneCheck, type PhoneFloors, type RawPhoneFinding, SHORT_PHONE, type SiteBrowser, type SitePage, type SiteResult, type StaticFinding, type Sweep, type Thresholds, type Viewport, type ViewportArg, type ViewportPage, type ViewportsResult, WIDE_WIDTHS, bandOf, checkExceptions, formatWidths, judgeMeasured, judgeStatic, mainActionFor, measurePhone, measurePhoneInPage, measureSite, measureViewportInPage, measureViewports, mergeViewportFindings, normaliseElement, reasonOf, routeFile, scanPhoneFirst, sweepWidths, writeBaseline };
451
+ export { BANDS, type Band, type Baseline, DEFAULT_MEASURED_DIR, DEFAULT_SWEEP, DEFAULT_THRESHOLDS, DESKTOP, EMPTY_BASELINE, type FileException, type InPageGroup, type Judgement, LADDER, type MainAction, type MeasurePhoneOptions, type MeasureSiteOptions, type MeasureViewportsOptions, type MeasuredRoute, type OpenedPage, PHONE, PHONE_FLOORS, type PhoneCheck, type PhoneFloors, type RawPhoneFinding, SHORT_PHONE, type SiteBrowser, type SitePage, type SiteResult, type StaticFinding, type Sweep, type Thresholds, type Viewport, type ViewportArg, type ViewportPage, type ViewportsResult, WIDE_WIDTHS, bandOf, checkExceptions, formatWidths, judgeMeasured, judgeStatic, mainActionFor, measurePhone, measurePhoneInPage, measureRoute, measureSite, measureViewportInPage, measureViewports, mergeViewportFindings, normaliseElement, reasonOf, routeFile, scanPhoneFirst, sweepWidths, writeBaseline };
package/dist/phone.d.ts CHANGED
@@ -335,6 +335,35 @@ interface ViewportsResult extends MeasuredRoute {
335
335
  * not judge or throw on a finding: the baseline decides.
336
336
  */
337
337
  declare function measureViewports(page: ViewportPage, options: MeasureViewportsOptions): Promise<ViewportsResult>;
338
+ /** The desktop context the wide half is measured in, beside `PHONE` for the phone half. Spread into `browser.newContext`. */
339
+ declare const DESKTOP: {
340
+ readonly viewport: {
341
+ readonly width: 1024;
342
+ readonly height: 768;
343
+ };
344
+ readonly deviceScaleFactor: 1;
345
+ };
346
+ /** A page opened at the route, and how to close it when its half is measured. */
347
+ interface OpenedPage {
348
+ page: ViewportPage;
349
+ close?: () => Promise<void>;
350
+ }
351
+ /**
352
+ * Every viewport for a route only the caller can open, such as a portal screen
353
+ * behind a sign-in (DOM-835). As `measureSite` does for a public page, the
354
+ * phone half is measured in a phone context and the wide half in a desktop
355
+ * one; `open(scope)` returns a page already at the route, signed in with the
356
+ * suite's fixtures, in `PHONE` for "phone" and `DESKTOP` for "wide". The two
357
+ * halves are merged and written once, for `craft phone-first --measured`.
358
+ *
359
+ * await measureRoute(async (scope) => {
360
+ * const context = await browser.newContext({ ...(scope === "phone" ? PHONE : DESKTOP), extraHTTPHeaders: auth });
361
+ * const page = await context.newPage();
362
+ * await page.goto(base + route);
363
+ * return { page, close: () => context.close() };
364
+ * }, { route, mainAction: 'a[href="/portal/requests/new"]' });
365
+ */
366
+ declare function measureRoute(open: (scope: "phone" | "wide") => Promise<OpenedPage>, options: Omit<MeasureViewportsOptions, "scope">): Promise<ViewportsResult>;
338
367
  interface SitePage extends ViewportPage {
339
368
  goto(url: string): Promise<{
340
369
  ok(): boolean;
@@ -419,4 +448,4 @@ interface MeasurePhoneOptions {
419
448
  */
420
449
  declare function measurePhone(page: MinimalPage, options: MeasurePhoneOptions): Promise<MeasuredRoute>;
421
450
 
422
- export { BANDS, type Band, type Baseline, DEFAULT_MEASURED_DIR, DEFAULT_SWEEP, DEFAULT_THRESHOLDS, EMPTY_BASELINE, type FileException, type InPageGroup, type Judgement, LADDER, type MainAction, type MeasurePhoneOptions, type MeasureSiteOptions, type MeasureViewportsOptions, type MeasuredRoute, PHONE, PHONE_FLOORS, type PhoneCheck, type PhoneFloors, type RawPhoneFinding, SHORT_PHONE, type SiteBrowser, type SitePage, type SiteResult, type StaticFinding, type Sweep, type Thresholds, type Viewport, type ViewportArg, type ViewportPage, type ViewportsResult, WIDE_WIDTHS, bandOf, checkExceptions, formatWidths, judgeMeasured, judgeStatic, mainActionFor, measurePhone, measurePhoneInPage, measureSite, measureViewportInPage, measureViewports, mergeViewportFindings, normaliseElement, reasonOf, routeFile, scanPhoneFirst, sweepWidths, writeBaseline };
451
+ export { BANDS, type Band, type Baseline, DEFAULT_MEASURED_DIR, DEFAULT_SWEEP, DEFAULT_THRESHOLDS, DESKTOP, EMPTY_BASELINE, type FileException, type InPageGroup, type Judgement, LADDER, type MainAction, type MeasurePhoneOptions, type MeasureSiteOptions, type MeasureViewportsOptions, type MeasuredRoute, type OpenedPage, PHONE, PHONE_FLOORS, type PhoneCheck, type PhoneFloors, type RawPhoneFinding, SHORT_PHONE, type SiteBrowser, type SitePage, type SiteResult, type StaticFinding, type Sweep, type Thresholds, type Viewport, type ViewportArg, type ViewportPage, type ViewportsResult, WIDE_WIDTHS, bandOf, checkExceptions, formatWidths, judgeMeasured, judgeStatic, mainActionFor, measurePhone, measurePhoneInPage, measureRoute, measureSite, measureViewportInPage, measureViewports, mergeViewportFindings, normaliseElement, reasonOf, routeFile, scanPhoneFirst, sweepWidths, writeBaseline };
package/dist/phone.js CHANGED
@@ -673,6 +673,21 @@ async function measureViewports(page, options) {
673
673
  await page.evaluate(() => document.fonts?.ready.then(() => void 0), void 0);
674
674
  return finish(options.route, await collect(page, options), options.out);
675
675
  }
676
+ var DESKTOP = { viewport: { width: 1024, height: 768 }, deviceScaleFactor: 1 };
677
+ async function measureRoute(open, options) {
678
+ if (!options.route.startsWith("/")) throw new Error(`measureRoute: route "${options.route}" should start with /`);
679
+ const collected = [];
680
+ for (const scope of ["phone", "wide"]) {
681
+ const { page, close } = await open(scope);
682
+ try {
683
+ await page.evaluate(() => document.fonts?.ready.then(() => void 0), void 0);
684
+ collected.push(await collect(page, { ...options, scope }));
685
+ } finally {
686
+ await close?.();
687
+ }
688
+ }
689
+ return finish(options.route, { perViewport: collected.flatMap((c) => c.perViewport), tested: collected.flatMap((c) => c.tested) }, options.out);
690
+ }
676
691
  async function measureSite(browser, options) {
677
692
  const result = { routes: [], errors: [] };
678
693
  for (const route of options.routes) {
@@ -680,7 +695,7 @@ async function measureSite(browser, options) {
680
695
  let failed = null;
681
696
  for (const [scope, context] of [
682
697
  ["phone", PHONE],
683
- ["wide", { viewport: { width: 1024, height: 768 }, deviceScaleFactor: 1 }]
698
+ ["wide", DESKTOP]
684
699
  ]) {
685
700
  const ctx = await browser.newContext({ ...context });
686
701
  try {
@@ -723,6 +738,7 @@ export {
723
738
  DEFAULT_MEASURED_DIR,
724
739
  DEFAULT_SWEEP,
725
740
  DEFAULT_THRESHOLDS,
741
+ DESKTOP,
726
742
  EMPTY_BASELINE,
727
743
  LADDER,
728
744
  PHONE,
@@ -737,6 +753,7 @@ export {
737
753
  mainActionFor,
738
754
  measurePhone,
739
755
  measurePhoneInPage,
756
+ measureRoute,
740
757
  measureSite,
741
758
  measureViewportInPage,
742
759
  measureViewports,
@@ -534,6 +534,7 @@ function writeMeasured(result, dir) {
534
534
  writeFileSync(join(dir, routeFile(route)), `${JSON.stringify({ route, ...viewport ? { viewport } : {}, ...viewports ? { viewports } : {}, findings }, null, 1)}
535
535
  `);
536
536
  }
537
+ var DESKTOP = { viewport: { width: 1024, height: 768 }, deviceScaleFactor: 1 };
537
538
  async function measureSite(browser, options) {
538
539
  const result = { routes: [], errors: [] };
539
540
  for (const route of options.routes) {
@@ -541,7 +542,7 @@ async function measureSite(browser, options) {
541
542
  let failed = null;
542
543
  for (const [scope, context] of [
543
544
  ["phone", PHONE],
544
- ["wide", { viewport: { width: 1024, height: 768 }, deviceScaleFactor: 1 }]
545
+ ["wide", DESKTOP]
545
546
  ]) {
546
547
  const ctx = await browser.newContext({ ...context });
547
548
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domandigital/craft",
3
- "version": "0.20.1",
3
+ "version": "0.20.2",
4
4
  "private": false,
5
5
  "description": "The Doman Digital house craft standard as numbers: OKLCh colour ramps that snap to existing anchors, derived semantic tokens with measured WCAG and APCA contrast, one shared motion vocabulary for CSS and JS, and a base stylesheet. Zero dependencies.",
6
6
  "license": "Apache-2.0",