@krx3d/tizentube2 1.30.20 → 1.30.50
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.
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
# - dist/userScript.js (browser userscript, bundled & minified)
|
|
10
10
|
# - dist/service.js (DIAL service, bundled with Rollup)
|
|
11
11
|
# - Publishes the package to https://www.npmjs.com on release only
|
|
12
|
-
# -
|
|
13
|
-
# -
|
|
12
|
+
# - Deprecates older versions once the new one is confirmed live on npm
|
|
13
|
+
# - Fails the run if npm's `latest` tag does not match what it published
|
|
14
14
|
# - Purges jsDelivr CDN cache after publishing
|
|
15
15
|
#
|
|
16
16
|
# WHEN IT RUNS
|
|
@@ -30,14 +30,25 @@
|
|
|
30
30
|
#
|
|
31
31
|
# AUTOMATIC VERSION CLEANUP
|
|
32
32
|
# -------------------------
|
|
33
|
-
# After publishing
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# - Deprecates versions >72 hours old (unpublish no longer allowed)
|
|
37
|
-
# - Result: Only the latest version remains active on npm
|
|
33
|
+
# After publishing, this workflow tidies up older versions — but only once the
|
|
34
|
+
# new version is actually readable on npm, and only with writes that change
|
|
35
|
+
# something. Both rules exist because of a real failure:
|
|
38
36
|
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
37
|
+
# - npm publish is asynchronous. The CLI exits 0 while the version is still
|
|
38
|
+
# being processed, and 1.30.30 only appeared in the registry 96 seconds later.
|
|
39
|
+
# - Unpublish and deprecate both work by rewriting the ENTIRE package document.
|
|
40
|
+
# A rewrite built from a snapshot taken before the new version landed deletes
|
|
41
|
+
# it again — which is how 1.30.30 vanished one second after it appeared,
|
|
42
|
+
# leaving `latest` at 1.30.20 while the GitHub release said 1.30.30.
|
|
43
|
+
#
|
|
44
|
+
# So:
|
|
45
|
+
# - Nothing touches the registry until GET /<pkg>/<version> succeeds
|
|
46
|
+
# - Versions that already carry a deprecation message are skipped entirely
|
|
47
|
+
# - The current version and every dist-tag target are never touched
|
|
48
|
+
# - Removal is attempted every run; npm rejects it from a granular token that
|
|
49
|
+
# bypasses 2FA, so those versions are deprecated instead and a local script
|
|
50
|
+
# (scripts/npm-cleanup) does the real removal with a 2FA code
|
|
51
|
+
# - The job fails if `latest` does not end up pointing at what it published
|
|
41
52
|
#
|
|
42
53
|
# VERSION BUMP RULE (push to main only)
|
|
43
54
|
# -------------------------------------
|
|
@@ -144,6 +155,13 @@ env:
|
|
|
144
155
|
PACKAGE_NAME_GH: 'KrX3D/TizenTube'
|
|
145
156
|
NODE_VERSION: '24'
|
|
146
157
|
UNPUBLISH_WINDOW_HOURS: '72'
|
|
158
|
+
# Removal is still attempted on every run. npm currently refuses it from a
|
|
159
|
+
# granular access token with bypass-2FA (its only token type since November
|
|
160
|
+
# 2025), so the attempts 403 and the versions are deprecated instead — but a
|
|
161
|
+
# refused request writes nothing, and if npm allows this again for
|
|
162
|
+
# automation, removal resumes on the next run with no change here.
|
|
163
|
+
# Set to 'false' only to stop attempting it altogether.
|
|
164
|
+
ALLOW_UNPUBLISH: 'true'
|
|
147
165
|
|
|
148
166
|
jobs:
|
|
149
167
|
build-publish-clean:
|
|
@@ -414,63 +432,137 @@ jobs:
|
|
|
414
432
|
echo "Publishing package..."
|
|
415
433
|
npm publish --access public
|
|
416
434
|
|
|
417
|
-
|
|
435
|
+
# --------------------
|
|
436
|
+
# CONFIRM THE PUBLISH LANDED
|
|
437
|
+
# --------------------
|
|
438
|
+
# npm's publish endpoint is asynchronous. The CLI prints "Your package is
|
|
439
|
+
# being processed and may take a few minutes to become available" and exits
|
|
440
|
+
# 0 well before the version exists in the registry document.
|
|
441
|
+
#
|
|
442
|
+
# That is not a cosmetic delay, because every cleanup step below works by
|
|
443
|
+
# PUTting the WHOLE package document back. npm builds that document from
|
|
444
|
+
# whatever it can read at the time, so a PUT issued while the new version
|
|
445
|
+
# is still in flight writes a snapshot that does not contain it — and the
|
|
446
|
+
# version that was just published is gone again.
|
|
447
|
+
#
|
|
448
|
+
# 1.30.30 is what that looks like: published 18:40:16, appeared in the
|
|
449
|
+
# registry's own time map at 18:41:52, erased at 18:41:53 by the last
|
|
450
|
+
# npm deprecate of the very same job. The GitHub release said 1.30.30
|
|
451
|
+
# while the latest tag pointed back at 1.30.20, so every TV loading the
|
|
452
|
+
# userscript from the CDN got a bundle one version behind its own app.
|
|
453
|
+
#
|
|
454
|
+
# So nothing touches the registry until the new version is readable, and if
|
|
455
|
+
# it never becomes readable the job fails instead of cleaning up around a
|
|
456
|
+
# version that isn't there.
|
|
457
|
+
- name: Confirm the published version is live on npm
|
|
418
458
|
if: steps.publish_npm.outcome == 'success'
|
|
459
|
+
id: confirm_publish
|
|
460
|
+
env:
|
|
461
|
+
PKG: ${{ env.PACKAGE_NAME }}
|
|
419
462
|
run: |
|
|
420
|
-
|
|
421
|
-
|
|
463
|
+
set -euo pipefail
|
|
464
|
+
VER=$(node -e "console.log(require('./package.json').version)")
|
|
465
|
+
echo "$VER" > /tmp/current_version.txt
|
|
466
|
+
echo "Waiting for ${PKG}@${VER} to become readable..."
|
|
467
|
+
for i in $(seq 1 40); do
|
|
468
|
+
# The registry is read directly rather than through npm view, which
|
|
469
|
+
# has its own HTTP cache and will happily answer from a packument
|
|
470
|
+
# fetched before the publish landed.
|
|
471
|
+
if curl -fsSL "https://registry.npmjs.org/${PKG}/${VER}" -o /tmp/published.json; then
|
|
472
|
+
echo "${PKG}@${VER} is live (attempt ${i})."
|
|
473
|
+
echo "confirmed=true" >> "$GITHUB_OUTPUT"
|
|
474
|
+
exit 0
|
|
475
|
+
fi
|
|
476
|
+
sleep 15
|
|
477
|
+
done
|
|
478
|
+
echo "confirmed=false" >> "$GITHUB_OUTPUT"
|
|
479
|
+
echo "::error::${PKG}@${VER} never became readable on npm after 10 minutes. Cleanup is skipped so nothing can overwrite it."
|
|
480
|
+
exit 1
|
|
422
481
|
|
|
423
482
|
# --------------------
|
|
424
|
-
# FETCH
|
|
483
|
+
# FETCH THE REGISTRY DOCUMENT
|
|
425
484
|
# --------------------
|
|
426
|
-
- name: Gather versions and
|
|
427
|
-
if: steps.
|
|
485
|
+
- name: Gather versions, times and deprecation state
|
|
486
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
428
487
|
env:
|
|
429
488
|
PKG: ${{ env.PACKAGE_NAME }}
|
|
430
489
|
run: |
|
|
431
490
|
set -euo pipefail
|
|
432
|
-
echo "Fetching
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
491
|
+
echo "Fetching the registry document for ${PKG} ..."
|
|
492
|
+
curl -fsSL "https://registry.npmjs.org/${PKG}" -o /tmp/packument.json
|
|
493
|
+
node -e '
|
|
494
|
+
const fs = require("fs");
|
|
495
|
+
const doc = JSON.parse(fs.readFileSync("/tmp/packument.json","utf8"));
|
|
496
|
+
const versions = Object.keys(doc.versions || {});
|
|
497
|
+
const deprecated = versions.filter(function (v) { return doc.versions[v].deprecated; });
|
|
498
|
+
fs.writeFileSync("/tmp/versions.json", JSON.stringify(versions));
|
|
499
|
+
fs.writeFileSync("/tmp/time.json", JSON.stringify(doc.time || {}));
|
|
500
|
+
fs.writeFileSync("/tmp/deprecated.json", JSON.stringify(deprecated));
|
|
501
|
+
fs.writeFileSync("/tmp/dist_tags.json", JSON.stringify(doc["dist-tags"] || {}));
|
|
502
|
+
console.log("Live versions: " + versions.length + ", already deprecated: " + deprecated.length);
|
|
503
|
+
console.log("dist-tags: " + JSON.stringify(doc["dist-tags"] || {}));
|
|
504
|
+
'
|
|
505
|
+
echo "Current repo version: $(cat /tmp/current_version.txt)"
|
|
439
506
|
|
|
440
507
|
# --------------------
|
|
441
508
|
# DECIDE WHAT TO REMOVE
|
|
442
509
|
# --------------------
|
|
510
|
+
# Two rules, both about never issuing a registry write that changes
|
|
511
|
+
# nothing — since each one rewrites the whole package document, and one of
|
|
512
|
+
# those rewrites is what erased 1.30.30:
|
|
513
|
+
#
|
|
514
|
+
# * a version that already carries a deprecation message is skipped. All
|
|
515
|
+
# 80 live versions were already deprecated, so the previous run made
|
|
516
|
+
# about 80 full-document writes for no effect at all.
|
|
517
|
+
#
|
|
518
|
+
# * unpublishing is off unless ALLOW_UNPUBLISH is "true". The npm token
|
|
519
|
+
# here is a granular access token, and npm refuses unpublish from tokens
|
|
520
|
+
# that bypass two-factor authentication ("Granular access tokens that
|
|
521
|
+
# bypass two-factor authentication may not perform this action"). Every
|
|
522
|
+
# attempt returned 403 — and every one of those was still a write.
|
|
523
|
+
# Re-enable it only with a token that can actually perform it.
|
|
524
|
+
#
|
|
525
|
+
# The version just published is kept, as before, and so is whatever each
|
|
526
|
+
# dist-tag resolves to: installing the tag npm points people at must not
|
|
527
|
+
# print a deprecation warning. The latest tag was itself deprecated by the
|
|
528
|
+
# run that lost 1.30.30.
|
|
443
529
|
- name: Decide versions to unpublish / deprecate
|
|
444
|
-
if: steps.
|
|
530
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
445
531
|
env:
|
|
446
532
|
UNPUBLISH_WINDOW_HOURS: ${{ env.UNPUBLISH_WINDOW_HOURS }}
|
|
533
|
+
ALLOW_UNPUBLISH: ${{ env.ALLOW_UNPUBLISH }}
|
|
447
534
|
run: |
|
|
448
535
|
set -euo pipefail
|
|
449
536
|
node -e '
|
|
450
537
|
const fs = require("fs");
|
|
451
538
|
const versions = JSON.parse(fs.readFileSync("/tmp/versions.json","utf8")||"[]");
|
|
452
539
|
const times = JSON.parse(fs.readFileSync("/tmp/time.json","utf8")||"{}");
|
|
540
|
+
const deprecated = new Set(JSON.parse(fs.readFileSync("/tmp/deprecated.json","utf8")||"[]"));
|
|
541
|
+
const distTags = JSON.parse(fs.readFileSync("/tmp/dist_tags.json","utf8")||"{}");
|
|
453
542
|
const current = fs.readFileSync("/tmp/current_version.txt","utf8").trim();
|
|
454
543
|
|
|
455
544
|
const windowHours = Number(process.env.UNPUBLISH_WINDOW_HOURS || 72);
|
|
545
|
+
const allowUnpublish = String(process.env.ALLOW_UNPUBLISH || "") === "true";
|
|
456
546
|
const now = Date.now();
|
|
457
547
|
|
|
548
|
+
const keep = new Set([current].concat(Object.keys(distTags).map(function (tag) { return distTags[tag]; })));
|
|
549
|
+
|
|
458
550
|
const toUnpublish = [];
|
|
459
551
|
const toDeprecate = [];
|
|
460
552
|
|
|
461
553
|
for (const v of versions) {
|
|
462
|
-
if (v
|
|
554
|
+
if (keep.has(v)) continue;
|
|
463
555
|
const t = times[v] ? new Date(times[v]) : null;
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (
|
|
467
|
-
else toDeprecate.push(v);
|
|
556
|
+
const ageHours = t ? (now - t.getTime()) / 36e5 : Infinity;
|
|
557
|
+
if (allowUnpublish && t && ageHours <= windowHours) { toUnpublish.push(v); continue; }
|
|
558
|
+
if (!deprecated.has(v)) toDeprecate.push(v);
|
|
468
559
|
}
|
|
469
560
|
|
|
470
561
|
fs.writeFileSync("/tmp/to_unpublish.txt", toUnpublish.length ? toUnpublish.join("\n") + "\n" : "");
|
|
471
562
|
fs.writeFileSync("/tmp/to_deprecate.txt", toDeprecate.length ? toDeprecate.join("\n") + "\n" : "");
|
|
472
|
-
console.log("
|
|
473
|
-
console.log("To
|
|
563
|
+
console.log("Keeping (current version + every dist-tag): " + Array.from(keep).join(", "));
|
|
564
|
+
console.log("To unpublish (<= " + windowHours + "h, enabled=" + allowUnpublish + "):", toUnpublish);
|
|
565
|
+
console.log("To deprecate (not already deprecated):", toDeprecate);
|
|
474
566
|
'
|
|
475
567
|
|
|
476
568
|
echo ""
|
|
@@ -484,8 +576,30 @@ jobs:
|
|
|
484
576
|
# --------------------
|
|
485
577
|
# UNPUBLISH
|
|
486
578
|
# --------------------
|
|
579
|
+
# Unpublishing is the only thing that actually removes a version;
|
|
580
|
+
# deprecating just labels it. So this still tries, every run, for every
|
|
581
|
+
# version inside npm's 72-hour window.
|
|
582
|
+
#
|
|
583
|
+
# It cannot currently succeed. npm removed legacy tokens in November 2025,
|
|
584
|
+
# leaving granular access tokens as the only kind, and since August 2026 a
|
|
585
|
+
# granular token with "bypass 2FA" is refused for sensitive actions, with
|
|
586
|
+
# unpublish among them — the 403 says so in as many words. Deprecating
|
|
587
|
+
# still works with the same token.
|
|
588
|
+
#
|
|
589
|
+
# Attempting anyway is deliberate and costs nothing. A refused PUT writes
|
|
590
|
+
# nothing, so those 403s never touched the package document; the version
|
|
591
|
+
# that got erased was erased by a deprecate that SUCCEEDED. And if npm
|
|
592
|
+
# restores this for automation, removal resumes with no change here.
|
|
593
|
+
#
|
|
594
|
+
# What is not repeated is the noise. The 2FA refusal is reported once and
|
|
595
|
+
# the remaining versions go straight to the deprecate fallback, instead of
|
|
596
|
+
# making the same doomed request nineteen more times.
|
|
597
|
+
#
|
|
598
|
+
# To actually remove versions today, run
|
|
599
|
+
# scripts/npm-cleanup/unpublish-old-versions.ps1 locally; it prompts for a
|
|
600
|
+
# 2FA code, which is the only path npm still allows.
|
|
487
601
|
- name: Unpublish old versions (verified) and fallback to deprecate
|
|
488
|
-
if: steps.
|
|
602
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
489
603
|
env:
|
|
490
604
|
PKG: ${{ env.PACKAGE_NAME }}
|
|
491
605
|
run: |
|
|
@@ -510,6 +624,29 @@ jobs:
|
|
|
510
624
|
return 1
|
|
511
625
|
}
|
|
512
626
|
|
|
627
|
+
# Deprecating something that is already deprecated is rejected as 422,
|
|
628
|
+
# and gets there by rewriting the whole package document — the write
|
|
629
|
+
# that erased 1.30.30. So the fallback checks first.
|
|
630
|
+
already_deprecated(){
|
|
631
|
+
node -e '
|
|
632
|
+
const fs = require("fs");
|
|
633
|
+
let list = [];
|
|
634
|
+
try { list = JSON.parse(fs.readFileSync("/tmp/deprecated.json","utf8")); } catch (e) { }
|
|
635
|
+
process.exit(list.indexOf(process.argv[1]) === -1 ? 1 : 0);
|
|
636
|
+
' "$1"
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
deprecate_fallback(){
|
|
640
|
+
ver="$1"
|
|
641
|
+
if already_deprecated "$ver"; then
|
|
642
|
+
echo "${PKG}@${ver} is already deprecated; leaving it alone."
|
|
643
|
+
return 0
|
|
644
|
+
fi
|
|
645
|
+
npm deprecate "${PKG}@${ver}" "Deprecated — please upgrade to a newer release." 2>&1 | tee /tmp/npm_deprecate_${ver}.log || echo "::warning::deprecate failed for ${ver}"
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
UNPUBLISH_BLOCKED=0
|
|
649
|
+
|
|
513
650
|
if [ ! -s /tmp/to_unpublish.txt ]; then
|
|
514
651
|
echo "No versions to unpublish."
|
|
515
652
|
else
|
|
@@ -517,6 +654,11 @@ jobs:
|
|
|
517
654
|
ver="$(echo "$ver" | tr -d '\r' | xargs)"
|
|
518
655
|
[ -z "$ver" ] && continue
|
|
519
656
|
|
|
657
|
+
if [ "$UNPUBLISH_BLOCKED" = "1" ]; then
|
|
658
|
+
deprecate_fallback "$ver"
|
|
659
|
+
continue
|
|
660
|
+
fi
|
|
661
|
+
|
|
520
662
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
521
663
|
echo "Attempting unpublish: ${PKG}@${ver}"
|
|
522
664
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
@@ -527,12 +669,17 @@ jobs:
|
|
|
527
669
|
echo "Verified ${PKG}@${ver} removed."
|
|
528
670
|
else
|
|
529
671
|
echo "::warning::Still visible after unpublish attempts -> deprecate fallback"
|
|
530
|
-
|
|
672
|
+
deprecate_fallback "$ver"
|
|
531
673
|
fi
|
|
532
674
|
else
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
675
|
+
if grep -q "bypass two-factor authentication" "/tmp/npm_unpublish_${ver}.log"; then
|
|
676
|
+
UNPUBLISH_BLOCKED=1
|
|
677
|
+
echo "::warning::npm refuses unpublish from this token: a granular access token with bypass-2FA may not perform it (npm policy, August 2026). The remaining versions would fail identically, so they are deprecated instead. To remove versions, run scripts/npm-cleanup/unpublish-old-versions.ps1 locally."
|
|
678
|
+
else
|
|
679
|
+
echo "::warning::npm unpublish failed or returned non-zero for ${PKG}@${ver}"
|
|
680
|
+
fi
|
|
681
|
+
echo "Deprecating instead..."
|
|
682
|
+
deprecate_fallback "$ver"
|
|
536
683
|
fi
|
|
537
684
|
|
|
538
685
|
done < /tmp/to_unpublish.txt
|
|
@@ -542,7 +689,7 @@ jobs:
|
|
|
542
689
|
# DEPRECATE older (>72h)
|
|
543
690
|
# --------------------
|
|
544
691
|
- name: Deprecate older versions
|
|
545
|
-
if: steps.
|
|
692
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
546
693
|
env:
|
|
547
694
|
PKG: ${{ env.PACKAGE_NAME }}
|
|
548
695
|
run: |
|
|
@@ -563,13 +710,18 @@ jobs:
|
|
|
563
710
|
# Final wait + verify final state
|
|
564
711
|
# --------------------
|
|
565
712
|
- name: Wait before final verify
|
|
566
|
-
if: steps.
|
|
713
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
567
714
|
run: |
|
|
568
715
|
echo "Short wait to let registry propagate final state..."
|
|
569
716
|
sleep 8
|
|
570
717
|
|
|
718
|
+
# The cleanup steps above rewrite the whole package document, so the last
|
|
719
|
+
# thing this job does is check that the version it published is still the
|
|
720
|
+
# one npm hands out. Without this the job reported success while `latest`
|
|
721
|
+
# had silently fallen back a release, and the first sign of it was a TV
|
|
722
|
+
# loading a userscript older than its own app.
|
|
571
723
|
- name: Verify final state
|
|
572
|
-
if: steps.
|
|
724
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
573
725
|
env:
|
|
574
726
|
PKG: ${{ env.PACKAGE_NAME }}
|
|
575
727
|
run: |
|
|
@@ -577,14 +729,31 @@ jobs:
|
|
|
577
729
|
echo "Final versions on npm:"
|
|
578
730
|
npm view "${PKG}" versions --json
|
|
579
731
|
echo ""
|
|
580
|
-
|
|
581
|
-
npm view
|
|
732
|
+
|
|
733
|
+
# Read through the registry rather than `npm view`, whose cache is
|
|
734
|
+
# what made the original breakage invisible here.
|
|
735
|
+
curl -fsSL "https://registry.npmjs.org/${PKG}" -o /tmp/packument_final.json
|
|
736
|
+
node -e '
|
|
737
|
+
const fs = require("fs");
|
|
738
|
+
const doc = JSON.parse(fs.readFileSync("/tmp/packument_final.json","utf8"));
|
|
739
|
+
const want = fs.readFileSync("/tmp/current_version.txt","utf8").trim();
|
|
740
|
+
const latest = (doc["dist-tags"] || {}).latest;
|
|
741
|
+
const live = !!(doc.versions || {})[want];
|
|
742
|
+
const deprecated = live && !!doc.versions[want].deprecated;
|
|
743
|
+
console.log("published: " + want + ", latest tag: " + latest + ", still live: " + live);
|
|
744
|
+
let failed = false;
|
|
745
|
+
if (!live) { console.log("::error::" + want + " is no longer on npm. A cleanup write removed the version this run published."); failed = true; }
|
|
746
|
+
if (latest !== want) { console.log("::error::npm latest is " + latest + ", not " + want + ". The CDN will serve the wrong bundle to every TV."); failed = true; }
|
|
747
|
+
if (deprecated) { console.log("::error::" + want + " was published deprecated."); failed = true; }
|
|
748
|
+
if (failed) process.exit(1);
|
|
749
|
+
console.log("npm latest matches the version this run published.");
|
|
750
|
+
'
|
|
582
751
|
|
|
583
752
|
# --------------------
|
|
584
753
|
# Purge jsDelivr cache
|
|
585
754
|
# --------------------
|
|
586
755
|
- name: Generate jsDelivr URLs to purge
|
|
587
|
-
if: steps.
|
|
756
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
588
757
|
id: cdn_urls
|
|
589
758
|
run: |
|
|
590
759
|
set -euo pipefail
|
|
@@ -636,7 +805,7 @@ jobs:
|
|
|
636
805
|
printf '%s\n' "${URLS[@]}"
|
|
637
806
|
|
|
638
807
|
- name: Purge jsDelivr cache
|
|
639
|
-
if: steps.
|
|
808
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
640
809
|
# jsDelivr rate-limits how often the same path can be re-purged
|
|
641
810
|
# ("Purging request ... was throttled") — expected on frequent
|
|
642
811
|
# releases, not an actual failure of the publish itself. The next
|
|
@@ -652,7 +821,7 @@ jobs:
|
|
|
652
821
|
attempts: 3
|
|
653
822
|
|
|
654
823
|
- name: Purge individual URLs (fallback if batch fails)
|
|
655
|
-
if: steps.
|
|
824
|
+
if: steps.confirm_publish.outputs.confirmed == 'true' && failure()
|
|
656
825
|
continue-on-error: true
|
|
657
826
|
run: |
|
|
658
827
|
set +e
|
|
@@ -698,6 +867,6 @@ jobs:
|
|
|
698
867
|
echo "Individual purge attempts complete"
|
|
699
868
|
|
|
700
869
|
- name: Cache purge complete
|
|
701
|
-
if: steps.
|
|
870
|
+
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
702
871
|
|
|
703
872
|
run: echo "✅ jsDelivr cache purge complete (npm + GitHub)"
|
package/AGENTS.md
CHANGED
|
@@ -102,6 +102,9 @@ standalone/ # standalone installable app — see "Standalone mo
|
|
|
102
102
|
|
|
103
103
|
scripts/tampermonkey/ # local Chrome-based dev/test loader — see README.md
|
|
104
104
|
scripts/log-receiver/ # PC-side PS1 receiver for logServer.js's remote logging (see Feature map)
|
|
105
|
+
scripts/npm-cleanup/ # local `npm unpublish` of old versions, with a 2FA code — the publish
|
|
106
|
+
# workflow attempts removal too, but npm refuses it from any token it
|
|
107
|
+
# still issues, so this is the only path that works
|
|
105
108
|
scripts/pc-installer/ # PC-side install/update script (SDB from the PC, no on-device installer app
|
|
106
109
|
# needed) — workaround for the Host PC IP 127.0.0.1 conflict with standalone's
|
|
107
110
|
# proxy path; in progress, see AGENTS.md "Known unresolved issues"
|