fix(gitea): rewrite workspace:* in published tarballs (F16)

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).
This commit is contained in:
saravanakumardb1 2026-05-27 01:29:29 -07:00
parent 678d8df42c
commit cfcfc7bb90
12 changed files with 91 additions and 30 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@bytelyst/auth",
"version": "0.1.5",
"version": "0.1.6",
"type": "module",
"exports": {
".": {

View File

@ -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": {

View File

@ -1,6 +1,6 @@
{
"name": "@bytelyst/events",
"version": "0.1.5",
"version": "0.1.6",
"type": "module",
"exports": {
".": {

View File

@ -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": {

View File

@ -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",

View File

@ -1,6 +1,6 @@
{
"name": "@bytelyst/fastify-core",
"version": "0.1.5",
"version": "0.1.6",
"type": "module",
"exports": {
".": {

View File

@ -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": {

View File

@ -1,6 +1,6 @@
{
"name": "@bytelyst/field-encrypt",
"version": "0.1.6",
"version": "0.1.7",
"type": "module",
"exports": {
".": {

View File

@ -1,6 +1,6 @@
{
"name": "@bytelyst/react-auth",
"version": "0.1.6",
"version": "0.1.7",
"type": "module",
"exports": {
".": {

View File

@ -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",

View File

@ -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",

View File

@ -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