@vzn/vx-ci 0.0.591 → 0.0.595

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vzn/vx-ci",
3
- "version": "0.0.591",
3
+ "version": "0.0.595",
4
4
  "license": "MIT",
5
5
  "description": "GitHub Actions integration for vx — a telemetry plugin that writes the run as a GitHub Actions job summary.",
6
6
  "keywords": [
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "peerDependencies": {
36
- "@vzn/vx": "^0.0.591"
36
+ "@vzn/vx": "^0.0.595"
37
37
  },
38
38
  "repository": {
39
39
  "type": "git",
package/src/checks.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  // `GITHUB_TOKEN` with `checks: write`; the plugin declines the check (not
4
4
  // the whole sink) without one, so the summary still works token-less.
5
5
  import type { RunSummaryRecord } from '@vzn/vx'
6
+ import { truncateUtf8 } from './summary.js'
6
7
 
7
8
  export type FetchFn = (
8
9
  url: string,
@@ -67,14 +68,11 @@ function isCertificateRefusal(err: unknown): boolean {
67
68
  * summary's does.
68
69
  */
69
70
  export function clampSummary(markdown: string): string {
70
- const MAX = 65_535
71
- if (markdown.length * 3 <= MAX) return markdown
72
- const bytes = new TextEncoder().encode(markdown)
73
- if (bytes.byteLength <= MAX) return markdown
74
- const suffix = '\n\n…truncated by @vzn/vx-ci (65535-char Checks API limit)'
75
- let end = MAX - new TextEncoder().encode(suffix).byteLength
76
- while (end > 0 && (bytes[end]! & 0xc0) === 0x80) end--
77
- return new TextDecoder().decode(bytes.subarray(0, end)) + suffix
71
+ return truncateUtf8(
72
+ markdown,
73
+ 65_535,
74
+ '\n\n…truncated by @vzn/vx-ci (65535-char Checks API limit)',
75
+ )
78
76
  }
79
77
 
80
78
  export function buildCheckRunPayload(args: {
package/src/summary.ts CHANGED
@@ -60,16 +60,24 @@ function hitSplit(s: RunSummaryRecord): string {
60
60
  export const MAX_JOB_SUMMARY_BYTES = 1024 * 1024
61
61
 
62
62
  export function clampJobSummary(markdown: string, room = MAX_JOB_SUMMARY_BYTES): string {
63
+ return truncateUtf8(
64
+ markdown,
65
+ room,
66
+ '\n\n…truncated by @vzn/vx-ci (GitHub caps a job summary at 1 MiB)\n',
67
+ )
68
+ }
69
+
70
+ /** Cuts `text` to `maxBytes` of UTF-8, `suffix` included, never splitting a character. */
71
+ export function truncateUtf8(text: string, maxBytes: number, suffix: string): string {
63
72
  // The cap is BYTES, and the page is not ASCII: every status label is an
64
73
  // emoji (4 bytes, 2 UTF-16 units) and every separator a `·` or a `—`
65
74
  // (2 and 3 bytes, 1 unit). Measured in `.length`, a clamped page of those
66
75
  // rows came out past 1 MiB and GitHub refused it whole (item 806). A unit
67
76
  // is at most 3 bytes, so a short page skips the encode.
68
- if (markdown.length * 3 <= room) return markdown
69
- const bytes = new TextEncoder().encode(markdown)
70
- if (bytes.byteLength <= room) return markdown
71
- const suffix = '\n\n…truncated by @vzn/vx-ci (GitHub caps a job summary at 1 MiB)\n'
72
- let end = room - new TextEncoder().encode(suffix).byteLength
77
+ if (text.length * 3 <= maxBytes) return text
78
+ const bytes = new TextEncoder().encode(text)
79
+ if (bytes.byteLength <= maxBytes) return text
80
+ let end = maxBytes - new TextEncoder().encode(suffix).byteLength
73
81
  if (end <= 0) return ''
74
82
  // Back up off a continuation byte, so the cut never splits a character.
75
83
  while (end > 0 && (bytes[end]! & 0xc0) === 0x80) end--