1+ import { readFileSync , writeFileSync } from 'node:fs' ;
2+
13import { scanLockfile } from './parsers/index.js' ;
24import { buildWirePayload } from './normalize.js' ;
3- import { markProductionBuild } from './buildFlag .js' ;
5+ import { computeManifestChecksum } from './checksum .js' ;
46import { buildClaimUrl , postManifest } from './client.js' ;
57import { persistSiteUuid , resolveConfig , writeConfigFile } from './config.js' ;
8+ import {
9+ buildInjectionSnippet ,
10+ findHtmlFiles ,
11+ injectMarker ,
12+ resolveBuildDir ,
13+ } from './mark-build.js' ;
614import { PatchstackError } from './types.js' ;
715
816const HELP = `@patchstack/connect — scan your lockfile and report packages to Patchstack.
@@ -14,10 +22,8 @@ Usage:
1422 patchstack-connect init <site-uuid> Optional: pre-seed .patchstackrc.json
1523 with an existing site UUID
1624 patchstack-connect status [options] Show current configuration
17- patchstack-connect mark-build [--dir <path>] Inject the production flag into
18- the built HTML (run as a postbuild
19- step). Tells the widget it's live so
20- it hides the claim flow.
25+ patchstack-connect mark-build [options] Stamp built HTML with a production flag +
26+ build fingerprint (run as a postbuild step)
2127 patchstack-connect help Print this message
2228
2329Options (for scan and status):
@@ -26,8 +32,8 @@ Options (for scan and status):
2632 --dry-run (scan only) Show the payload without posting
2733
2834Options (for mark-build):
29- --dir <path> Build output dir (default: auto-detect dist/, build/,
30- out/, .output/public)
35+ --dir <path> Build output directory (default: auto-detect
36+ dist/ build/ out/ .output/public)
3137
3238Environment:
3339 PATCHSTACK_SITE_UUID Site UUID
@@ -197,25 +203,49 @@ async function runStatus(args: ParsedArgs): Promise<number> {
197203}
198204
199205async function runMarkBuild ( args : ParsedArgs ) : Promise < number > {
200- const result = await markProductionBuild ( process . cwd ( ) , getStringFlag ( args . flags , 'dir' ) ) ;
206+ const cwd = process . cwd ( ) ;
207+
208+ // Compute the build fingerprint from the lockfile. Best-effort: mark-build is a
209+ // postbuild step and must never fail the build, so a missing/unreadable lockfile
210+ // just means we stamp the production flag without a fingerprint.
211+ let checksum : string | null = null ;
212+ try {
213+ const manifest = await scanLockfile ( cwd ) ;
214+ const { payload } = buildWirePayload ( manifest ) ;
215+ checksum = computeManifestChecksum ( payload . packages ) ;
216+ } catch ( err ) {
217+ console . warn (
218+ `mark-build: could not compute the build fingerprint (${ ( err as Error ) . message } ). Stamping the production flag only.` ,
219+ ) ;
220+ }
201221
202- // Never fail the build over this — a missing flag just means the widget falls
203- // back to showing the claim flow, which is safe.
204- if ( result . dir === null ) {
222+ const dir = resolveBuildDir ( cwd , getStringFlag ( args . flags , 'dir' ) ) ;
223+ if ( dir === null ) {
205224 console . warn (
206- 'patchstack: no build output found (looked for dist/, build/, out/, .output/public). ' +
207- 'Pass --dir <path> if your build outputs elsewhere. Skipping production flag.' ,
225+ 'mark-build: no build output directory found (looked for dist/, build/, out/, .output/public). Pass --dir <path> if it is elsewhere. Nothing to mark.' ,
208226 ) ;
209227 return 0 ;
210228 }
211- if ( result . patched . length === 0 && result . skipped . length === 0 ) {
212- console . warn ( `patchstack: no HTML files found under ${ result . dir } ; skipping production flag.` ) ;
229+
230+ const files = findHtmlFiles ( dir ) ;
231+ if ( files . length === 0 ) {
232+ console . warn ( `mark-build: no HTML files found under ${ dir } . Nothing to mark.` ) ;
213233 return 0 ;
214234 }
215235
216- const already = result . skipped . length > 0 ? ` (${ result . skipped . length } already marked)` : '' ;
236+ const snippet = buildInjectionSnippet ( checksum ) ;
237+ let marked = 0 ;
238+ for ( const file of files ) {
239+ const before = readFileSync ( file , 'utf8' ) ;
240+ const after = injectMarker ( before , snippet ) ;
241+ if ( after !== before ) {
242+ writeFileSync ( file , after ) ;
243+ marked += 1 ;
244+ }
245+ }
246+
217247 console . log (
218- `patchstack : marked ${ result . patched . length } HTML file(s) as a production build in ${ result . dir } ${ already } .` ,
248+ `mark-build : marked ${ marked } HTML file(s) in ${ dir } ${ checksum !== null ? ` (build ${ checksum } )` : '' } .` ,
219249 ) ;
220250 return 0 ;
221251}
0 commit comments