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:
parent
678d8df42c
commit
cfcfc7bb90
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bytelyst/auth",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bytelyst/events",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bytelyst/fastify-core",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bytelyst/field-encrypt",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.7",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bytelyst/react-auth",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.7",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user