From cfcfc7bb901aa21c4a9d363684d6886aefa9068a Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Wed, 27 May 2026 01:29:29 -0700 Subject: [PATCH] fix(gitea): rewrite workspace:* in published tarballs (F16) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves F16 in docker-build-optimization-roadmap v5. Root cause: publish-outdated-packages.sh uses a pack-extract-repack pattern: 1. pnpm pack (rewrites workspace:* in tarball) 2. extract 3. npm pack (re-tar from extracted content) 4. npm publish Step 3 is the bug. npm pack does not recognize the pnpm-specific workspace: protocol — it treats workspace:* as a literal version string and passes it through to the final tarball. Result: any consumer doing 'pnpm install' inside Docker (where there is no workspace context) fails with ERR_PNPM_WORKSPACE_PKG_NOT_FOUND. Documented in roadmap §0 F16 + §3 Phase A-pre. Fix (publish-outdated-packages.sh): - Insert a workspace:* rewriter between publishConfig strip and npm pack. Reads source package.json for each @bytelyst/* target, resolves workspace:* / workspace:^ / workspace:~ to ^x.y.z. - Add defense-in-depth: grep the post-rewrite package.json for any surviving 'workspace:' literal. If found, refuse to publish. Republished 10 affected packages with workspace:* → resolved semver: @bytelyst/auth 0.1.5 → 0.1.6 @bytelyst/diagnostics-client 0.1.6 → 0.1.7 @bytelyst/events 0.1.5 → 0.1.6 @bytelyst/extraction 0.1.5 → 0.1.6 @bytelyst/fastify-auth 0.1.5 → 0.1.6 @bytelyst/fastify-core 0.1.5 → 0.1.6 @bytelyst/feedback-client 0.1.6 → 0.1.7 @bytelyst/field-encrypt 0.1.6 → 0.1.7 @bytelyst/react-auth 0.1.6 → 0.1.7 @bytelyst/sync 0.1.5 → 0.1.6 Verification: all 10 packages now scan with 0 workspace:* refs in their published package.json (per registry curl scan). Unblocks: A0-V verification on learning_ai_clock (currently blocked at learning_ai_clock@0be887288). --- packages/auth/package.json | 2 +- packages/diagnostics-client/package.json | 2 +- packages/events/package.json | 2 +- packages/extraction/package.json | 2 +- packages/fastify-auth/package.json | 2 +- packages/fastify-core/package.json | 2 +- packages/feedback-client/package.json | 2 +- packages/field-encrypt/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/sync/package.json | 2 +- scripts/gitea/.publish-manifest.json | 40 +++++++------- scripts/gitea/publish-outdated-packages.sh | 61 ++++++++++++++++++++++ 12 files changed, 91 insertions(+), 30 deletions(-) diff --git a/packages/auth/package.json b/packages/auth/package.json index d0818216..b393e153 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/auth", - "version": "0.1.5", + "version": "0.1.6", "type": "module", "exports": { ".": { diff --git a/packages/diagnostics-client/package.json b/packages/diagnostics-client/package.json index 1d582704..991c8265 100644 --- a/packages/diagnostics-client/package.json +++ b/packages/diagnostics-client/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/diagnostics-client", - "version": "0.1.6", + "version": "0.1.7", "description": "TypeScript client for remote diagnostics and debug tracing", "type": "module", "exports": { diff --git a/packages/events/package.json b/packages/events/package.json index f2d71150..109be61e 100644 --- a/packages/events/package.json +++ b/packages/events/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/events", - "version": "0.1.5", + "version": "0.1.6", "type": "module", "exports": { ".": { diff --git a/packages/extraction/package.json b/packages/extraction/package.json index 6adb44bf..b515cff2 100644 --- a/packages/extraction/package.json +++ b/packages/extraction/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/extraction", - "version": "0.1.5", + "version": "0.1.6", "type": "module", "description": "Shared types and client for the extraction service", "exports": { diff --git a/packages/fastify-auth/package.json b/packages/fastify-auth/package.json index 06df9d56..2e41321b 100644 --- a/packages/fastify-auth/package.json +++ b/packages/fastify-auth/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/fastify-auth", - "version": "0.1.5", + "version": "0.1.6", "description": "JWT auth middleware + request context for Fastify product backends", "type": "module", "main": "dist/index.js", diff --git a/packages/fastify-core/package.json b/packages/fastify-core/package.json index 2a1e2d0d..2f4cdaa6 100644 --- a/packages/fastify-core/package.json +++ b/packages/fastify-core/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/fastify-core", - "version": "0.1.5", + "version": "0.1.6", "type": "module", "exports": { ".": { diff --git a/packages/feedback-client/package.json b/packages/feedback-client/package.json index f6e811bf..1358e819 100644 --- a/packages/feedback-client/package.json +++ b/packages/feedback-client/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/feedback-client", - "version": "0.1.6", + "version": "0.1.7", "description": "TypeScript client for submitting user feedback with screenshots", "type": "module", "exports": { diff --git a/packages/field-encrypt/package.json b/packages/field-encrypt/package.json index 4ee5921f..207f3364 100644 --- a/packages/field-encrypt/package.json +++ b/packages/field-encrypt/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/field-encrypt", - "version": "0.1.6", + "version": "0.1.7", "type": "module", "exports": { ".": { diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index 1aeb930b..b14b05c4 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/react-auth", - "version": "0.1.6", + "version": "0.1.7", "type": "module", "exports": { ".": { diff --git a/packages/sync/package.json b/packages/sync/package.json index 8aee6570..d1a9e9c5 100644 --- a/packages/sync/package.json +++ b/packages/sync/package.json @@ -1,6 +1,6 @@ { "name": "@bytelyst/sync", - "version": "0.1.5", + "version": "0.1.6", "description": "Offline-first sync engine with configurable storage adapters and conflict resolution", "type": "module", "main": "./dist/index.js", diff --git a/scripts/gitea/.publish-manifest.json b/scripts/gitea/.publish-manifest.json index fffacf3b..a6f1fbf6 100644 --- a/scripts/gitea/.publish-manifest.json +++ b/scripts/gitea/.publish-manifest.json @@ -10,9 +10,9 @@ "publishedAt": "2026-05-15T05:32:21.764Z" }, "@bytelyst/auth": { - "version": "0.1.5", + "version": "0.1.6", "contentHash": "97f8e1ca0a609075e82751091a4a995740a5b06b513c14b55ee57ce6a9de7309", - "publishedAt": "2026-04-13T08:44:09.341Z" + "publishedAt": "2026-05-27T08:25:10.360Z" }, "@bytelyst/auth-client": { "version": "0.1.5", @@ -110,9 +110,9 @@ "publishedAt": "2026-05-15T05:32:29.061Z" }, "@bytelyst/diagnostics-client": { - "version": "0.1.6", + "version": "0.1.7", "contentHash": "776c4683ee405b2b833ac508d25beb591740c60262876c0289fc61c1894b74be", - "publishedAt": "2026-05-15T05:32:30.640Z" + "publishedAt": "2026-05-27T08:26:18.882Z" }, "@bytelyst/errors": { "version": "0.1.6", @@ -125,24 +125,24 @@ "publishedAt": "2026-04-13T08:44:37.491Z" }, "@bytelyst/events": { - "version": "0.1.5", + "version": "0.1.6", "contentHash": "ea584931f18cf682d3738545474ada10b67a775b7b549f4cc4862e145be8972f", - "publishedAt": "2026-04-13T08:44:39.134Z" + "publishedAt": "2026-05-27T08:26:37.820Z" }, "@bytelyst/extraction": { - "version": "0.1.5", + "version": "0.1.6", "contentHash": "0edce9563443f5daea8d5efb2481fedaad9746f4ee1b7b9fb29e9095c0fe9305", - "publishedAt": "2026-04-13T08:44:40.758Z" + "publishedAt": "2026-05-27T08:26:57.295Z" }, "@bytelyst/fastify-auth": { - "version": "0.1.5", + "version": "0.1.6", "contentHash": "d196ce76219aa420273d003781b83ecca11f11271dd2be9cfbe0c6b832d6d790", - "publishedAt": "2026-04-13T08:44:42.446Z" + "publishedAt": "2026-05-27T08:27:16.669Z" }, "@bytelyst/fastify-core": { - "version": "0.1.5", + "version": "0.1.6", "contentHash": "0140953510ee4cf2f584c6f2745e33817832a7848f13e4a26b805038238cba77", - "publishedAt": "2026-04-13T08:44:44.114Z" + "publishedAt": "2026-05-27T08:27:35.713Z" }, "@bytelyst/fastify-sse": { "version": "0.3.5", @@ -155,14 +155,14 @@ "publishedAt": "2026-04-13T08:44:47.385Z" }, "@bytelyst/feedback-client": { - "version": "0.1.6", + "version": "0.1.7", "contentHash": "c89ee90ebc104878d0f5346425d15b5d0ea0b2a39fdbba7ec6ca62918b5c3340", - "publishedAt": "2026-05-15T05:32:32.075Z" + "publishedAt": "2026-05-27T08:27:53.679Z" }, "@bytelyst/field-encrypt": { - "version": "0.1.6", + "version": "0.1.7", "contentHash": "ae9bf71cfe03b9cb42156586ed53219433a637673ad6b4502aa4f200d08aa890", - "publishedAt": "2026-05-15T05:32:33.679Z" + "publishedAt": "2026-05-27T08:28:12.143Z" }, "@bytelyst/gentle-notifications": { "version": "0.1.5", @@ -245,9 +245,9 @@ "publishedAt": "2026-04-13T08:45:13.687Z" }, "@bytelyst/react-auth": { - "version": "0.1.6", + "version": "0.1.7", "contentHash": "c4e4e86ed03b93ea6d1cb40e1a67315685cdb2a4e262858dfd29850a18a16a72", - "publishedAt": "2026-04-13T08:45:15.275Z" + "publishedAt": "2026-05-27T08:28:31.398Z" }, "@bytelyst/referral-client": { "version": "0.1.5", @@ -280,9 +280,9 @@ "publishedAt": "2026-04-13T08:45:24.602Z" }, "@bytelyst/sync": { - "version": "0.1.5", + "version": "0.1.6", "contentHash": "7bcc6c6e7df33f966a5c4ee240b31dba8a286dbcfdebaad3dfdcefdb0fccfc2c", - "publishedAt": "2026-04-13T08:45:26.173Z" + "publishedAt": "2026-05-27T08:28:50.384Z" }, "@bytelyst/telemetry-client": { "version": "0.1.5", diff --git a/scripts/gitea/publish-outdated-packages.sh b/scripts/gitea/publish-outdated-packages.sh index c25ca69a..631e07e5 100755 --- a/scripts/gitea/publish-outdated-packages.sh +++ b/scripts/gitea/publish-outdated-packages.sh @@ -391,6 +391,67 @@ for i in "${!outdated_dirs[@]}"; do fs.writeFileSync(f,JSON.stringify(p,null,2)+'\n'); " "$pack_dir/extracted/package/package.json" + # Rewrite workspace:* protocol → resolved semver (addresses F16). + # + # pnpm pack DOES rewrite workspace: refs in its output tarball, BUT we + # extract and re-pack with npm pack below (to work around a historical + # Gitea-compat issue with pnpm's tarball format). npm pack does not + # know about the workspace: protocol and passes it through literally, + # so without this step the published tarball contains + # "@bytelyst/errors": "workspace:*" + # which then fails 'pnpm install' inside any Docker build with + # ERR_PNPM_WORKSPACE_PKG_NOT_FOUND + # because there is no workspace context inside the container. + # + # This rewriter mirrors what pnpm publish would have done: look up the + # target package's current source version and write "^x.y.z". + node -e " + const fs=require('fs'),path=require('path'); + const pkgFile=process.argv[1]; + const packagesDir=process.argv[2]; + const p=JSON.parse(fs.readFileSync(pkgFile,'utf8')); + let rewrites=0; + for (const section of ['dependencies','peerDependencies','optionalDependencies','devDependencies']) { + if (!p[section]) continue; + for (const [name,ver] of Object.entries(p[section])) { + if (typeof ver !== 'string' || !ver.startsWith('workspace:')) continue; + // workspace:* | workspace:^ | workspace:~ | workspace:1.2.3 + const protoSpec=ver.slice('workspace:'.length); + let targetDir; + if (name.startsWith('@bytelyst/')) { + targetDir=path.join(packagesDir,name.replace('@bytelyst/','')); + } else { + // Should not happen for @bytelyst/* publishes, but be safe + console.error(' WARN: workspace: ref to non-@bytelyst package:',name); + continue; + } + const targetPkgFile=path.join(targetDir,'package.json'); + if (!fs.existsSync(targetPkgFile)) { + throw new Error('Cannot resolve workspace: ref '+name+' → '+targetPkgFile+' not found'); + } + const targetVersion=JSON.parse(fs.readFileSync(targetPkgFile,'utf8')).version; + let resolved; + if (protoSpec === '*' || protoSpec === '^') resolved='^'+targetVersion; + else if (protoSpec === '~') resolved='~'+targetVersion; + else if (/^[0-9]/.test(protoSpec)) resolved=protoSpec; + else resolved='^'+targetVersion; + p[section][name]=resolved; + rewrites++; + console.error(' rewrote',section+'.'+name,':',ver,'→',resolved); + } + } + if (rewrites > 0) { + fs.writeFileSync(pkgFile,JSON.stringify(p,null,2)+'\n'); + } + " "$pack_dir/extracted/package/package.json" "$PACKAGES_DIR" + + # Defense in depth: refuse to publish if any workspace: ref survived. + if grep -q '"workspace:' "$pack_dir/extracted/package/package.json"; then + echo " ERROR: workspace: ref survived rewriter in $pkg_name (F16 guard)" + grep -n '"workspace:' "$pack_dir/extracted/package/package.json" | head -5 + ((pub_errors++)); continue + fi + # Repack with npm (from already-extracted content — no second pnpm pack) rm -f "$pack_dir"/*.tgz if ! (cd "$pack_dir/extracted/package" && npm pack --pack-destination "$pack_dir" >/dev/null 2>&1); then