styleproof 4.4.7 → 4.4.9

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
@@ -7,8 +7,27 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [4.4.8] - 2026-07-13
11
+
12
+ ### Fixed
13
+
14
+ - **Map-store restore now retrieves only the requested commit bundle.** Restore
15
+ clones branch metadata without a checkout, sparsely selects the requested SHA,
16
+ and, on partial-clone-capable remotes such as GitHub, downloads only that
17
+ bundle's blobs. Large long-lived map stores therefore no longer make every
18
+ cache lookup clone all historical bundles on supported remotes. Publishing
19
+ uses the same sparse checkout and stages only the requested bundle plus the
20
+ store README; Git's sparse index preserves unseen bundles without downloading
21
+ their blobs, so cache misses no longer materialise the complete store either.
22
+
23
+ ## [4.4.7] - 2026-07-13
24
+
10
25
  ### Fixed
11
26
 
27
+ - **Explicit map-store credentials take precedence over checkout state.** When
28
+ `STYLEPROOF_MAP_STORE_TOKEN` is set, StyleProof now uses it before inspecting
29
+ persisted Git headers, so stale `actions/checkout` credentials cannot break a
30
+ cold-cache map upload.
12
31
  - **Generated CI authenticates map publication explicitly.** `styleproof-init`
13
32
  passes the workflow's least-privilege `github.token` as
14
33
  `STYLEPROOF_MAP_STORE_TOKEN`, so cold-cache uploads do not depend on private
@@ -19,6 +38,11 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
19
38
  directly in `.git/config`; StyleProof now explicitly enables Git config includes
20
39
  and falls back to its locally registered checkout config before carrying that
21
40
  header into the isolated clone and push.
41
+ - **Map-store uploads now reuse credentials from `actions/checkout@v7`.**
42
+ Checkout v7 keeps its HTTP header in an included temporary config rather than
43
+ directly in `.git/config`; StyleProof now explicitly enables Git config includes
44
+ and falls back to its locally registered checkout config before carrying that
45
+ header into the isolated clone and push.
22
46
  - **Map-store uploads now reuse the HTTP authentication persisted by
23
47
  `actions/checkout`.** The isolated `styleproof-maps` clone carries the
24
48
  checkout's URL-scoped extra header through clone and push, so cache-miss
package/dist/map-store.js CHANGED
@@ -64,6 +64,15 @@ function parseGitHttpExtraHeaders(configuredHeaders) {
64
64
  });
65
65
  }
66
66
  function effectiveGitHttpExtraHeaders(cwd) {
67
+ const mapStoreToken = process.env.STYLEPROOF_MAP_STORE_TOKEN;
68
+ if (mapStoreToken) {
69
+ return [
70
+ {
71
+ key: ['http.https:', '', 'github.com', '.extraheader'].join('/'),
72
+ value: `AUTHORIZATION: basic ${Buffer.from(`x-access-token:${mapStoreToken}`).toString('base64')}`,
73
+ },
74
+ ];
75
+ }
67
76
  const configuredHeaders = runGit(cwd, ['config', '--includes', '--get-regexp', '^http\\..*\\.extraheader$'], 1 << 20);
68
77
  const effectiveHeaders = parseGitHttpExtraHeaders(configuredHeaders.stdout);
69
78
  if (effectiveHeaders.length > 0)
@@ -82,15 +91,7 @@ function effectiveGitHttpExtraHeaders(cwd) {
82
91
  });
83
92
  if (includedHeaders.length > 0)
84
93
  return includedHeaders;
85
- const mapStoreToken = process.env.STYLEPROOF_MAP_STORE_TOKEN;
86
- if (!mapStoreToken)
87
- return [];
88
- return [
89
- {
90
- key: ['http.https:', '', 'github.com', '.extraheader'].join('/'),
91
- value: `AUTHORIZATION: basic ${Buffer.from(`x-access-token:${mapStoreToken}`).toString('base64')}`,
92
- },
93
- ];
94
+ return [];
94
95
  }
95
96
  function gitOutput(cwd, args) {
96
97
  const r = runGit(cwd, args);
@@ -435,15 +436,27 @@ function copyDir(src, dest, includeHar) {
435
436
  filter: (source) => includeHar || !source.endsWith('.har'),
436
437
  });
437
438
  }
438
- function checkoutMapStore(cwd, remote, branch) {
439
+ function checkoutSparseSegment(tmp, branch, segment) {
440
+ const sparseCheckout = runGit(tmp, ['sparse-checkout', 'set', segment], 1 << 20);
441
+ const checkout = sparseCheckout.status === 0 ? runGit(tmp, ['checkout', '-q', branch], 1 << 20) : sparseCheckout;
442
+ if (checkout.status !== 0) {
443
+ fs.rmSync(tmp, { recursive: true, force: true });
444
+ throw new MapStoreError(checkout.stderr.trim() || `could not check out ${segment} from map store`);
445
+ }
446
+ }
447
+ function checkoutMapStore(cwd, remote, branch, sparseSegment) {
439
448
  if (!remoteExists(remote, cwd))
440
449
  throw new MapStoreError(`git remote ${remote} was not found`);
441
450
  const remoteUrl = gitOutput(cwd, ['remote', 'get-url', remote]);
442
451
  const httpExtraHeaders = effectiveGitHttpExtraHeaders(cwd);
443
452
  const authenticationArguments = httpExtraHeaders.flatMap(({ key, value }) => ['-c', `${key}=${value}`]);
444
453
  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'styleproof-map-store-'));
445
- if (runGit(cwd, ['ls-remote', '--exit-code', '--heads', remote, branch], 1 << 20).status === 0) {
446
- const clone = spawnSync('git', [...authenticationArguments, 'clone', '-q', '--depth', '1', '--branch', branch, remoteUrl, tmp], {
454
+ const branchExists = runGit(cwd, ['ls-remote', '--exit-code', '--heads', remote, branch], 1 << 20).status === 0;
455
+ if (branchExists) {
456
+ const cloneArguments = sparseSegment
457
+ ? ['clone', '-q', '--filter=blob:none', '--no-checkout', '--depth', '1', '--single-branch', '--branch', branch]
458
+ : ['clone', '-q', '--depth', '1', '--branch', branch];
459
+ const clone = spawnSync('git', [...authenticationArguments, ...cloneArguments, remoteUrl, tmp], {
447
460
  encoding: 'utf8',
448
461
  maxBuffer: 1 << 20,
449
462
  env: gitProcessEnvironment(),
@@ -459,6 +472,8 @@ function checkoutMapStore(cwd, remote, branch) {
459
472
  }
460
473
  for (const { key, value } of httpExtraHeaders)
461
474
  runGit(tmp, ['config', '--local', key, value]);
475
+ if (sparseSegment && branchExists)
476
+ checkoutSparseSegment(tmp, branch, sparseSegment);
462
477
  return tmp;
463
478
  }
464
479
  export function publishMapBundle(options) {
@@ -479,7 +494,7 @@ export function publishMapBundle(options) {
479
494
  let ok = false;
480
495
  let lastError = '';
481
496
  for (let attempt = 1; attempt <= 5; attempt++) {
482
- const tmp = checkoutMapStore(cwd, remote, branch);
497
+ const tmp = checkoutMapStore(cwd, remote, branch, sha);
483
498
  try {
484
499
  runGit(tmp, ['config', 'user.name', 'github-actions[bot]']);
485
500
  runGit(tmp, ['config', 'user.email', '41898282+github-actions[bot]@users.noreply.github.com']);
@@ -489,7 +504,7 @@ export function publishMapBundle(options) {
489
504
  if (!options.includeHar) {
490
505
  fs.writeFileSync(path.join(tmp, target, MAP_MANIFEST), JSON.stringify({ ...manifest, har: false }, null, 2));
491
506
  }
492
- runGit(tmp, ['add', '-A']);
507
+ runGit(tmp, ['add', '-A', '--sparse', '--', 'README.md', target]);
493
508
  runGit(tmp, ['commit', '-q', '-m', `StyleProof map ${sha.slice(0, 12)} ${compatibilityKey}`], 1 << 20);
494
509
  const push = runGit(tmp, ['push', '-q', 'origin', `HEAD:${branch}`], 1 << 20);
495
510
  if (push.status === 0) {
@@ -520,7 +535,7 @@ export function restoreMapBundle(options) {
520
535
  if (runGit(cwd, ['ls-remote', '--exit-code', '--heads', remote, branch], 1 << 20).status !== 0) {
521
536
  throw new MapStoreError(`map store branch ${branch} does not exist`);
522
537
  }
523
- const tmp = checkoutMapStore(cwd, remote, branch);
538
+ const tmp = checkoutMapStore(cwd, remote, branch, sha);
524
539
  try {
525
540
  const shaDir = path.join(tmp, sha);
526
541
  if (!fs.existsSync(shaDir))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "styleproof",
3
- "version": "4.4.7",
3
+ "version": "4.4.9",
4
4
  "description": "Catch every CSS change before it ships — review PRs and certify refactors by the browser's computed styles, not pixels. Works with any styling system.",
5
5
  "keywords": [
6
6
  "playwright",