styleproof 4.4.6 → 4.4.8

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,33 @@ 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
+ - **Generated CI authenticates map publication explicitly.** `styleproof-init`
28
+ passes the workflow's least-privilege `github.token` as
29
+ `STYLEPROOF_MAP_STORE_TOKEN`, so cold-cache uploads do not depend on private
30
+ `actions/checkout` credential-storage details. Local hooks continue to reuse
31
+ normal Git credentials without requiring this variable.
32
+ - **Map-store uploads now reuse credentials from `actions/checkout@v7`.**
33
+ Checkout v7 keeps its HTTP header in an included temporary config rather than
34
+ directly in `.git/config`; StyleProof now explicitly enables Git config includes
35
+ and falls back to its locally registered checkout config before carrying that
36
+ header into the isolated clone and push.
12
37
  - **Map-store uploads now reuse credentials from `actions/checkout@v7`.**
13
38
  Checkout v7 keeps its HTTP header in an included temporary config rather than
14
39
  directly in `.git/config`; StyleProof now explicitly enables Git config includes
@@ -388,6 +388,8 @@ jobs:
388
388
  # Report on open/update; the prune job below handles close.
389
389
  if: github.event.action != 'closed'
390
390
  runs-on: ubuntu-latest
391
+ env:
392
+ STYLEPROOF_MAP_STORE_TOKEN: \${{ github.token }}
391
393
  steps:
392
394
  - uses: actions/checkout@v4
393
395
  with:
package/dist/map-store.js CHANGED
@@ -69,7 +69,7 @@ function effectiveGitHttpExtraHeaders(cwd) {
69
69
  if (effectiveHeaders.length > 0)
70
70
  return effectiveHeaders;
71
71
  const registeredIncludes = runGit(cwd, ['config', '--local', '--get-regexp', '^includeIf\\..*\\.path$'], 1 << 20);
72
- return registeredIncludes.stdout
72
+ const includedHeaders = registeredIncludes.stdout
73
73
  .split('\n')
74
74
  .filter(Boolean)
75
75
  .flatMap((registeredInclude) => {
@@ -80,6 +80,17 @@ function effectiveGitHttpExtraHeaders(cwd) {
80
80
  const includedHeaders = runGit(cwd, ['config', '--file', includedConfigPath, '--get-regexp', '^http\\..*\\.extraheader$'], 1 << 20);
81
81
  return parseGitHttpExtraHeaders(includedHeaders.stdout);
82
82
  });
83
+ if (includedHeaders.length > 0)
84
+ 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
+ ];
83
94
  }
84
95
  function gitOutput(cwd, args) {
85
96
  const r = runGit(cwd, args);
@@ -424,15 +435,27 @@ function copyDir(src, dest, includeHar) {
424
435
  filter: (source) => includeHar || !source.endsWith('.har'),
425
436
  });
426
437
  }
427
- function checkoutMapStore(cwd, remote, branch) {
438
+ function checkoutSparseSegment(tmp, branch, segment) {
439
+ const sparseCheckout = runGit(tmp, ['sparse-checkout', 'set', segment], 1 << 20);
440
+ const checkout = sparseCheckout.status === 0 ? runGit(tmp, ['checkout', '-q', branch], 1 << 20) : sparseCheckout;
441
+ if (checkout.status !== 0) {
442
+ fs.rmSync(tmp, { recursive: true, force: true });
443
+ throw new MapStoreError(checkout.stderr.trim() || `could not check out ${segment} from map store`);
444
+ }
445
+ }
446
+ function checkoutMapStore(cwd, remote, branch, sparseSegment) {
428
447
  if (!remoteExists(remote, cwd))
429
448
  throw new MapStoreError(`git remote ${remote} was not found`);
430
449
  const remoteUrl = gitOutput(cwd, ['remote', 'get-url', remote]);
431
450
  const httpExtraHeaders = effectiveGitHttpExtraHeaders(cwd);
432
451
  const authenticationArguments = httpExtraHeaders.flatMap(({ key, value }) => ['-c', `${key}=${value}`]);
433
452
  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'styleproof-map-store-'));
434
- if (runGit(cwd, ['ls-remote', '--exit-code', '--heads', remote, branch], 1 << 20).status === 0) {
435
- const clone = spawnSync('git', [...authenticationArguments, 'clone', '-q', '--depth', '1', '--branch', branch, remoteUrl, tmp], {
453
+ const branchExists = runGit(cwd, ['ls-remote', '--exit-code', '--heads', remote, branch], 1 << 20).status === 0;
454
+ if (branchExists) {
455
+ const cloneArguments = sparseSegment
456
+ ? ['clone', '-q', '--filter=blob:none', '--no-checkout', '--depth', '1', '--single-branch', '--branch', branch]
457
+ : ['clone', '-q', '--depth', '1', '--branch', branch];
458
+ const clone = spawnSync('git', [...authenticationArguments, ...cloneArguments, remoteUrl, tmp], {
436
459
  encoding: 'utf8',
437
460
  maxBuffer: 1 << 20,
438
461
  env: gitProcessEnvironment(),
@@ -448,6 +471,8 @@ function checkoutMapStore(cwd, remote, branch) {
448
471
  }
449
472
  for (const { key, value } of httpExtraHeaders)
450
473
  runGit(tmp, ['config', '--local', key, value]);
474
+ if (sparseSegment && branchExists)
475
+ checkoutSparseSegment(tmp, branch, sparseSegment);
451
476
  return tmp;
452
477
  }
453
478
  export function publishMapBundle(options) {
@@ -468,7 +493,7 @@ export function publishMapBundle(options) {
468
493
  let ok = false;
469
494
  let lastError = '';
470
495
  for (let attempt = 1; attempt <= 5; attempt++) {
471
- const tmp = checkoutMapStore(cwd, remote, branch);
496
+ const tmp = checkoutMapStore(cwd, remote, branch, sha);
472
497
  try {
473
498
  runGit(tmp, ['config', 'user.name', 'github-actions[bot]']);
474
499
  runGit(tmp, ['config', 'user.email', '41898282+github-actions[bot]@users.noreply.github.com']);
@@ -478,7 +503,7 @@ export function publishMapBundle(options) {
478
503
  if (!options.includeHar) {
479
504
  fs.writeFileSync(path.join(tmp, target, MAP_MANIFEST), JSON.stringify({ ...manifest, har: false }, null, 2));
480
505
  }
481
- runGit(tmp, ['add', '-A']);
506
+ runGit(tmp, ['add', '-A', '--sparse', '--', 'README.md', target]);
482
507
  runGit(tmp, ['commit', '-q', '-m', `StyleProof map ${sha.slice(0, 12)} ${compatibilityKey}`], 1 << 20);
483
508
  const push = runGit(tmp, ['push', '-q', 'origin', `HEAD:${branch}`], 1 << 20);
484
509
  if (push.status === 0) {
@@ -509,7 +534,7 @@ export function restoreMapBundle(options) {
509
534
  if (runGit(cwd, ['ls-remote', '--exit-code', '--heads', remote, branch], 1 << 20).status !== 0) {
510
535
  throw new MapStoreError(`map store branch ${branch} does not exist`);
511
536
  }
512
- const tmp = checkoutMapStore(cwd, remote, branch);
537
+ const tmp = checkoutMapStore(cwd, remote, branch, sha);
513
538
  try {
514
539
  const shaDir = path.join(tmp, sha);
515
540
  if (!fs.existsSync(shaDir))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "styleproof",
3
- "version": "4.4.6",
3
+ "version": "4.4.8",
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",