@krx3d/tizentube2 1.16.30 → 1.30.0

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.
@@ -0,0 +1,674 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Build, publish, and cleanup TizenTube on npm
3
+ #
4
+ # WHAT THIS WORKFLOW DOES
5
+ # -----------------------
6
+ # - Runs on every push to the `main` branch (build + verification + version bump)
7
+ # - Runs on push to main and manual dispatch (build + npm publish + cleanup)
8
+ # - Builds:
9
+ # - dist/userScript.js (browser userscript, bundled & minified)
10
+ # - dist/service.js (DIAL service, bundled with Rollup)
11
+ # - Publishes the package to https://www.npmjs.com on release only
12
+ # - Automatically removes old versions from npm (within 72-hour window)
13
+ # - Deprecates older versions (beyond 72-hour window) if any remain
14
+ # - Purges jsDelivr CDN cache after publishing
15
+ #
16
+ # WHEN IT RUNS
17
+ # ------------
18
+ # push to main:
19
+ # - Bumps version in root package.json (+10 patch, rollover to minor)
20
+ # - Builds the project (dist files contain the NEW version)
21
+ # - Commits updated package.json + dist outputs back to repo
22
+ # - Does NOT publish to npm
23
+ #
24
+ # push/workflow_dispatch:
25
+ # - Builds the project
26
+ # - Publishes to npm
27
+ # - Removes old versions (≤72 hours old, keeps current version only)
28
+ # - Deprecates very old versions (>72 hours, if unpublish fails)
29
+ # - Purges jsDelivr cache
30
+ #
31
+ # AUTOMATIC VERSION CLEANUP
32
+ # -------------------------
33
+ # After publishing a new version, this workflow automatically:
34
+ # - Identifies all versions except the newly published one
35
+ # - Unpublishes versions that are ≤72 hours old (npm policy allows this)
36
+ # - Deprecates versions >72 hours old (unpublish no longer allowed)
37
+ # - Result: Only the latest version remains active on npm
38
+ #
39
+ # Note: npm allows unpublishing versions within ~72 hours of publication.
40
+ # After that window, versions can only be deprecated, not removed.
41
+ #
42
+ # VERSION BUMP RULE (push to main only)
43
+ # -------------------------------------
44
+ # - Increments patch by +10:
45
+ # 1.17.680 -> 1.17.690 -> ... -> 1.17.990
46
+ # - When patch would hit 1000:
47
+ # 1.17.990 -> 1.18.0
48
+ #
49
+ # LOOP PREVENTION
50
+ # --------------
51
+ # - Bot commits include "[skip ci]"
52
+ # - Job is skipped when:
53
+ # - actor is github-actions[bot], OR
54
+ # - commit message contains "[skip ci]"
55
+ #
56
+ # PREREQUISITES (REQUIRED)
57
+ # -----------------------
58
+ # 1) Create an npm account:
59
+ # https://www.npmjs.com/signup
60
+ #
61
+ # 2) Create an npm access token:
62
+ # - npm → Profile → Access Tokens
63
+ # - Click "Generate New Token"
64
+ # - Token name: anything you want
65
+ # - CHECK: "Bypass two-factor authentication (2FA)"
66
+ # - Packages and scopes:
67
+ # - Permissions: Read and Write
68
+ # - Scope: All packages
69
+ # - Expiration date: e.g. 90 days
70
+ # - Click "Generate token" and COPY it
71
+ #
72
+ # 3) Add the token to GitHub Secrets:
73
+ # - GitHub repository → Settings
74
+ # - Security → Secrets and variables → Actions
75
+ # - Repository secrets → New repository secret
76
+ # Name: NPM_TOKEN
77
+ # Secret: <paste npm token here>
78
+ #
79
+ # PACKAGE REQUIREMENTS
80
+ # --------------------
81
+ # - package.json must contain a unique name, e.g.:
82
+ # "@krx3d/tizentube"
83
+ # - The version MUST be increased before each release
84
+ # (npm will reject duplicate versions)
85
+ #
86
+ # HOW TO PUBLISH A NEW VERSION
87
+ # ----------------------------
88
+ # 1) Push to main (workflow auto-bumps version and rebuilds dist)
89
+ # 2) Create a GitHub Release
90
+ # 3) When the release is published:
91
+ # → GitHub Actions builds
92
+ # → npm publish runs automatically
93
+ # → Old versions are automatically removed
94
+ # → jsDelivr cache is purged
95
+ #
96
+ # CONFIGURATION
97
+ # -------------
98
+ # - PACKAGE_NAME: Set to your npm package name (e.g., '@krx3d/tizentube')
99
+ # - NODE_VERSION: Node.js version to use (default: '24', Active LTS)
100
+ # - UNPUBLISH_WINDOW_HOURS: How long versions can be unpublished (default: '72')
101
+ #
102
+ # -----------------------------------------------------------------------------
103
+
104
+ name: Build, publish and cleanup old npm versions
105
+
106
+ on:
107
+ pull_request:
108
+ paths-ignore:
109
+ - 'dist/**'
110
+ - 'package.json'
111
+ push:
112
+ branches:
113
+ - main
114
+ paths-ignore:
115
+ - '.github/**'
116
+ - '.gitattributes'
117
+ - '.gitignore'
118
+ - '.npmignore'
119
+ - 'LICENSE'
120
+ - 'AGENTS.md'
121
+ - 'README.md'
122
+ - 'package.json'
123
+ - 'tizen.log'
124
+ - 'dist/**'
125
+ - 'scripts/**'
126
+ workflow_dispatch:
127
+
128
+ # Serialize runs so two pushes to main in quick succession can't both read
129
+ # package.json's version before either has committed its own bump — that
130
+ # race produces two runs computing the same "+10" version and the second
131
+ # npm publish failing with "Cannot publish over previously published
132
+ # version". Queue rather than cancel: a bump/publish already in progress
133
+ # must finish (and land its commit) before the next one reads the version.
134
+ concurrency:
135
+ group: ${{ github.workflow }}
136
+ cancel-in-progress: false
137
+
138
+ # Allow this workflow to push back changes to the repo
139
+ permissions:
140
+ contents: write
141
+
142
+ env:
143
+ PACKAGE_NAME: '@krx3d/tizentube2'
144
+ PACKAGE_NAME_GH: 'KrX3D/TizenTube'
145
+ NODE_VERSION: '24'
146
+ UNPUBLISH_WINDOW_HOURS: '72'
147
+
148
+ jobs:
149
+ build-publish-clean:
150
+ runs-on: ubuntu-latest
151
+
152
+ # Prevent loop on bot commits and on our own "[skip ci]" commits
153
+ if: >
154
+ github.event_name != 'pull_request' &&
155
+ (github.event_name != 'push' ||
156
+ (github.actor != 'github-actions[bot]' && !contains(github.event.head_commit.message, '[skip ci]')))
157
+
158
+ steps:
159
+ - name: Checkout
160
+ uses: actions/checkout@v6
161
+ with:
162
+ # ensure the checkout action leaves credentials so we can push
163
+ persist-credentials: true
164
+ fetch-depth: 0
165
+
166
+ - name: Setup Node.js
167
+ uses: actions/setup-node@v6
168
+ with:
169
+ node-version: ${{ env.NODE_VERSION }}
170
+
171
+ # ----------------------------
172
+ # Version bump (push to main only) - MUST happen BEFORE building dist
173
+ # ----------------------------
174
+ - name: Bump root package.json version (+10 patch, rollover -> minor)
175
+ if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
176
+ run: |
177
+ set -euo pipefail
178
+ node - <<'NODE'
179
+ const fs = require('fs');
180
+ const path = 'package.json';
181
+ const pkg = JSON.parse(fs.readFileSync(path, 'utf8'));
182
+
183
+ const ver = pkg.version || '0.0.0';
184
+ const m = ver.match(/^(\d+)\.(\d+)\.(\d+)$/);
185
+ if (!m) throw new Error(`Invalid version in package.json: ${ver}`);
186
+
187
+ let major = parseInt(m[1], 10);
188
+ let minor = parseInt(m[2], 10);
189
+ let patch = parseInt(m[3], 10);
190
+
191
+ patch += 10;
192
+ if (patch >= 1000) {
193
+ minor += 1;
194
+ patch = 0;
195
+ }
196
+
197
+ // npm refuses forever to reuse a version number that was once
198
+ // published and later unpublished. The cleanup step in this same
199
+ // workflow unpublishes old releases, so 780 of the 857 numbers this
200
+ // package has ever used are permanently burned. Whenever
201
+ // package.json drops back into that range - a revert, a bad merge,
202
+ // an upstream sync - every run then fails with
203
+ // E400 Cannot publish over previously published version "x.y.z"
204
+ // and, because the bump is committed and pushed BEFORE publishing,
205
+ // main is left pinned on the burned number so every later run fails
206
+ // the same way. That is exactly what happened twice at 1.16.10.
207
+ //
208
+ // The registry time map lists every version ever used, live or not,
209
+ // so skipping past them makes the bump self-correcting.
210
+ //
211
+ // Wrapped in an async IIFE on purpose: this script is fed to `node -`
212
+ // on stdin, and a top-level await next to the require() above makes
213
+ // Node fail the whole script with ERR_AMBIGUOUS_MODULE_SYNTAX.
214
+ (async () => {
215
+ let used = null;
216
+ try {
217
+ const res = await fetch('https://registry.npmjs.org/' + pkg.name);
218
+ if (res.ok) {
219
+ const meta = await res.json();
220
+ const isSemver = (k) => /^[0-9]+[.][0-9]+[.][0-9]+$/.test(k);
221
+ used = new Set(Object.keys(meta.time || {}).filter(isSemver));
222
+ }
223
+ } catch (e) {
224
+ // Registry unreachable: fall through to the plain bump rather
225
+ // than blocking a release. A real collision still fails loudly
226
+ // at publish.
227
+ used = null;
228
+ }
229
+
230
+ let newVer = `${major}.${minor}.${patch}`;
231
+ if (used) {
232
+ const firstChoice = newVer;
233
+ let guard = 0;
234
+ while (used.has(newVer) && guard++ < 500) {
235
+ patch += 10;
236
+ if (patch >= 1000) { minor += 1; patch = 0; }
237
+ newVer = `${major}.${minor}.${patch}`;
238
+ }
239
+ if (used.has(newVer)) throw new Error('No unused version found near ' + ver);
240
+ if (newVer !== firstChoice) console.log('Skipped burned version numbers: ' + firstChoice + ' -> ' + newVer);
241
+ }
242
+
243
+ pkg.version = newVer;
244
+ fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + String.fromCharCode(10), 'utf8');
245
+ console.log('Bumped version: ' + ver + ' -> ' + newVer);
246
+ })();
247
+ NODE
248
+
249
+ - name: Show current version (old -> new)
250
+ if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
251
+ run: |
252
+ set -euo pipefail
253
+
254
+ OLD_VER="$(git show HEAD^:package.json 2>/dev/null | node -e "let s='';process.stdin.on('data',d=>s+=d);process.stdin.on('end',()=>{try{console.log(JSON.parse(s).version||'');}catch{console.log('');}})")"
255
+ NEW_VER="$(node -p "require('./package.json').version")"
256
+
257
+ if [ -z "${OLD_VER:-}" ]; then
258
+ echo "Version: (unknown) -> ${NEW_VER}"
259
+ else
260
+ echo "Version: ${OLD_VER} -> ${NEW_VER}"
261
+ fi
262
+
263
+ # ----------------------------
264
+ # Build mods (userScript.js)
265
+ # ----------------------------
266
+ - name: Clean dist
267
+ run: |
268
+ set -euo pipefail
269
+ rm -rf dist
270
+ mkdir -p dist
271
+
272
+ - name: Install mods dependencies
273
+ run: |
274
+ set -euo pipefail
275
+ cd mods
276
+ npm ci
277
+
278
+ - name: Update Browserslist DB (mods)
279
+ run: |
280
+ set -euo pipefail
281
+ cd mods
282
+ npx update-browserslist-db@latest
283
+
284
+ - name: Build mods (rollup)
285
+ run: |
286
+ set -euo pipefail
287
+ cd mods
288
+ npm install
289
+ npx rollup -c
290
+
291
+ # ----------------------------
292
+ # Build service (service.js)
293
+ # ----------------------------
294
+ - name: Install service dependencies
295
+ run: |
296
+ set -euo pipefail
297
+ cd service
298
+ npm ci
299
+
300
+ - name: Build service (rollup)
301
+ run: |
302
+ set -euo pipefail
303
+ cd service
304
+ npm install
305
+ npx rollup -c
306
+
307
+ # ----------------------------
308
+ # Verify output
309
+ # ----------------------------
310
+ - name: Verify dist output
311
+ run: |
312
+ set -euo pipefail
313
+ echo "Listing dist/ (should contain built outputs):"
314
+ ls -lah dist || true
315
+ test -f dist/userScript.js
316
+ test -f dist/service.js
317
+
318
+ # ----------------------------
319
+ # Commit version bump + built JS to repo (push to main only)
320
+ # NOTE: dist is often gitignored, so we force-add the built files.
321
+ # ----------------------------
322
+ - name: Commit version bump + built files in dist/ (if changed)
323
+ if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
324
+ run: |
325
+ set -euo pipefail
326
+ echo "Committing version bump + built files (if any changes)..."
327
+
328
+ git config --global user.name "github-actions[bot]"
329
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
330
+
331
+ # stage what you actually want to commit
332
+ git add package.json
333
+
334
+ # stage dist files (use -f because dist/ is in .gitignore)
335
+ git add -f dist/userScript.js dist/service.js
336
+
337
+ if git diff --cached --quiet; then
338
+ echo "No changes to commit."
339
+ exit 0
340
+ fi
341
+
342
+ NEWVER=$(node -p "require('./package.json').version")
343
+ git commit -m "chore: bump version to ${NEWVER} + rebuild dist [skip ci]"
344
+
345
+ # IMPORTANT: ensure clean tree before rebase/pull
346
+ # (drops any lockfile drift etc. that you didn't commit)
347
+ git reset --hard HEAD
348
+ git clean -fd
349
+
350
+ git fetch origin main
351
+ #git pull --rebase origin main
352
+ git rebase origin/main
353
+ # git reset --hard
354
+
355
+ echo "Pushing changes back to main..."
356
+ git push origin HEAD:main
357
+
358
+
359
+ # --------------------
360
+ # NPM AUTH
361
+ # --------------------
362
+ - name: Configure npm auth
363
+ if: success()
364
+ env:
365
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
366
+ run: |
367
+ set -euo pipefail
368
+ if [ -z "${NPM_TOKEN:-}" ]; then
369
+ echo "::error::NPM_TOKEN secret is not set"
370
+ exit 1
371
+ fi
372
+ printf "//registry.npmjs.org/:_authToken=%s\n" "$NPM_TOKEN" > ~/.npmrc
373
+ printf "always-auth=true\n" >> ~/.npmrc
374
+ npm whoami
375
+ echo "✓ npm auth OK"
376
+
377
+ # --------------------
378
+ # PUBLISH
379
+ # --------------------
380
+ - name: Publish package to npm
381
+ if: success()
382
+ id: publish_npm
383
+ run: |
384
+ set -euo pipefail
385
+ echo "Publishing package..."
386
+ npm publish --access public
387
+
388
+ - name: Wait for npm propagation (after publish)
389
+ if: steps.publish_npm.outcome == 'success'
390
+ run: |
391
+ echo "Waiting for npm propagation..."
392
+ sleep 10
393
+
394
+ # --------------------
395
+ # FETCH VERSIONS
396
+ # --------------------
397
+ - name: Gather versions and publish times
398
+ if: steps.publish_npm.outcome == 'success'
399
+ env:
400
+ PKG: ${{ env.PACKAGE_NAME }}
401
+ run: |
402
+ set -euo pipefail
403
+ echo "Fetching versions & times for ${PKG} ..."
404
+ npm view "${PKG}" versions --json > /tmp/versions.json
405
+ npm view "${PKG}" time --json > /tmp/time.json
406
+
407
+ CUR_VER=$(node -e "console.log(require('./package.json').version)")
408
+ echo "Current repo version: $CUR_VER"
409
+ echo "$CUR_VER" > /tmp/current_version.txt
410
+
411
+ # --------------------
412
+ # DECIDE WHAT TO REMOVE
413
+ # --------------------
414
+ - name: Decide versions to unpublish / deprecate
415
+ if: steps.publish_npm.outcome == 'success'
416
+ env:
417
+ UNPUBLISH_WINDOW_HOURS: ${{ env.UNPUBLISH_WINDOW_HOURS }}
418
+ run: |
419
+ set -euo pipefail
420
+ node -e '
421
+ const fs = require("fs");
422
+ const versions = JSON.parse(fs.readFileSync("/tmp/versions.json","utf8")||"[]");
423
+ const times = JSON.parse(fs.readFileSync("/tmp/time.json","utf8")||"{}");
424
+ const current = fs.readFileSync("/tmp/current_version.txt","utf8").trim();
425
+
426
+ const windowHours = Number(process.env.UNPUBLISH_WINDOW_HOURS || 72);
427
+ const now = Date.now();
428
+
429
+ const toUnpublish = [];
430
+ const toDeprecate = [];
431
+
432
+ for (const v of versions) {
433
+ if (v === current) continue;
434
+ const t = times[v] ? new Date(times[v]) : null;
435
+ if (!t) { toDeprecate.push(v); continue; }
436
+ const ageHours = (now - t.getTime()) / 36e5;
437
+ if (ageHours <= windowHours) toUnpublish.push(v);
438
+ else toDeprecate.push(v);
439
+ }
440
+
441
+ fs.writeFileSync("/tmp/to_unpublish.txt", toUnpublish.length ? toUnpublish.join("\n") + "\n" : "");
442
+ fs.writeFileSync("/tmp/to_deprecate.txt", toDeprecate.length ? toDeprecate.join("\n") + "\n" : "");
443
+ console.log("To unpublish (<= " + windowHours + "h):", toUnpublish);
444
+ console.log("To deprecate (> " + windowHours + "h + unknown):", toDeprecate);
445
+ '
446
+
447
+ echo ""
448
+ echo "=== Unpublish candidates ==="
449
+ if [ -s /tmp/to_unpublish.txt ]; then cat /tmp/to_unpublish.txt; else echo "(none)"; fi
450
+
451
+ echo ""
452
+ echo "=== Deprecate candidates ==="
453
+ if [ -s /tmp/to_deprecate.txt ]; then cat /tmp/to_deprecate.txt; else echo "(none)"; fi
454
+
455
+ # --------------------
456
+ # UNPUBLISH
457
+ # --------------------
458
+ - name: Unpublish old versions (verified) and fallback to deprecate
459
+ if: steps.publish_npm.outcome == 'success'
460
+ env:
461
+ PKG: ${{ env.PACKAGE_NAME }}
462
+ run: |
463
+ set -euo pipefail
464
+
465
+ verify_gone(){
466
+ ver="$1"
467
+ tries=8
468
+ i=1
469
+ while [ $i -le $tries ]; do
470
+ echo "verify_gone: attempt $i for ${PKG}@${ver}"
471
+ if npm view "${PKG}@${ver}" --json > /tmp/view_${ver}.json 2>&1; then
472
+ echo "npm view still shows ${PKG}@${ver}"
473
+ i=$((i+1))
474
+ sleep 3
475
+ continue
476
+ else
477
+ echo "npm view does NOT show ${PKG}@${ver} (gone)"
478
+ return 0
479
+ fi
480
+ done
481
+ return 1
482
+ }
483
+
484
+ if [ ! -s /tmp/to_unpublish.txt ]; then
485
+ echo "No versions to unpublish."
486
+ else
487
+ while IFS= read -r ver; do
488
+ ver="$(echo "$ver" | tr -d '\r' | xargs)"
489
+ [ -z "$ver" ] && continue
490
+
491
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
492
+ echo "Attempting unpublish: ${PKG}@${ver}"
493
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
494
+
495
+ if npm unpublish "${PKG}@${ver}" 2>&1 | tee /tmp/npm_unpublish_${ver}.log; then
496
+ echo "npm unpublish command returned success for ${PKG}@${ver}"
497
+ if verify_gone "$ver"; then
498
+ echo "Verified ${PKG}@${ver} removed."
499
+ else
500
+ echo "::warning::Still visible after unpublish attempts -> deprecate fallback"
501
+ 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}"
502
+ fi
503
+ else
504
+ echo "::warning::npm unpublish failed or returned non-zero for ${PKG}@${ver}"
505
+ echo "Attempting to deprecate as fallback..."
506
+ 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}"
507
+ fi
508
+
509
+ done < /tmp/to_unpublish.txt
510
+ fi
511
+
512
+ # --------------------
513
+ # DEPRECATE older (>72h)
514
+ # --------------------
515
+ - name: Deprecate older versions
516
+ if: steps.publish_npm.outcome == 'success'
517
+ env:
518
+ PKG: ${{ env.PACKAGE_NAME }}
519
+ run: |
520
+ set -euo pipefail
521
+ if [ ! -s /tmp/to_deprecate.txt ]; then
522
+ echo "No versions to deprecate."
523
+ exit 0
524
+ fi
525
+
526
+ while IFS= read -r ver; do
527
+ ver="$(echo "$ver" | tr -d '\r' | xargs)"
528
+ [ -z "$ver" ] && continue
529
+ echo "Deprecating ${PKG}@${ver}..."
530
+ npm deprecate "${PKG}@${ver}" "Deprecated — please upgrade to a newer release." 2>&1 | tee /tmp/npm_deprecate_${ver}.log || echo "::warning::Deprecate failed for ${PKG}@${ver}"
531
+ done < /tmp/to_deprecate.txt
532
+
533
+ # --------------------
534
+ # Final wait + verify final state
535
+ # --------------------
536
+ - name: Wait before final verify
537
+ if: steps.publish_npm.outcome == 'success'
538
+ run: |
539
+ echo "Short wait to let registry propagate final state..."
540
+ sleep 8
541
+
542
+ - name: Verify final state
543
+ if: steps.publish_npm.outcome == 'success'
544
+ env:
545
+ PKG: ${{ env.PACKAGE_NAME }}
546
+ run: |
547
+ set -euo pipefail
548
+ echo "Final versions on npm:"
549
+ npm view "${PKG}" versions --json
550
+ echo ""
551
+ echo "Latest version:"
552
+ npm view "${PKG}" version
553
+
554
+ # --------------------
555
+ # Purge jsDelivr cache
556
+ # --------------------
557
+ - name: Generate jsDelivr URLs to purge
558
+ if: steps.publish_npm.outcome == 'success'
559
+ id: cdn_urls
560
+ run: |
561
+ set -euo pipefail
562
+
563
+ NPM_BASE="https://cdn.jsdelivr.net/npm/${PACKAGE_NAME}"
564
+ GH_BASE="https://cdn.jsdelivr.net/gh/${PACKAGE_NAME_GH}"
565
+
566
+ # Create array of URLs (npm + GitHub)
567
+ declare -a URLS=(
568
+ # npm package URLs
569
+ "${NPM_BASE}@latest"
570
+ "${NPM_BASE}@latest/package.json"
571
+ "${NPM_BASE}@latest/dist/userScript.js"
572
+ "${NPM_BASE}@latest/dist/service.js"
573
+ "${NPM_BASE}@*/package.json"
574
+ "${NPM_BASE}@*/dist/userScript.js"
575
+ "${NPM_BASE}@*/dist/service.js"
576
+ "${NPM_BASE}/package.json"
577
+ "${NPM_BASE}/dist/userScript.js"
578
+ "${NPM_BASE}/dist/service.js"
579
+ "${NPM_BASE}@*"
580
+
581
+ # GitHub repo URLs - main branch
582
+ "${GH_BASE}@main"
583
+ "${GH_BASE}@main/package.json"
584
+ "${GH_BASE}@main/dist/userScript.js"
585
+ "${GH_BASE}@main/dist/service.js"
586
+
587
+ # GitHub repo URLs - master branch (if you use it)
588
+ "${GH_BASE}@master"
589
+ "${GH_BASE}@master/package.json"
590
+ "${GH_BASE}@master/dist/userScript.js"
591
+ "${GH_BASE}@master/dist/service.js"
592
+
593
+ # GitHub repo URLs - without branch
594
+ "${GH_BASE}/package.json"
595
+ "${GH_BASE}/dist/userScript.js"
596
+ "${GH_BASE}/dist/service.js"
597
+
598
+ # Purge all GitHub branches/tags
599
+ "${GH_BASE}@*"
600
+ )
601
+
602
+ # Join with commas
603
+ URL_STRING=$(IFS=,; echo "${URLS[*]}")
604
+
605
+ echo "urls=${URL_STRING}" >> $GITHUB_OUTPUT
606
+ echo "Generated CDN URLs:"
607
+ printf '%s\n' "${URLS[@]}"
608
+
609
+ - name: Purge jsDelivr cache
610
+ if: steps.publish_npm.outcome == 'success'
611
+ # jsDelivr rate-limits how often the same path can be re-purged
612
+ # ("Purging request ... was throttled") — expected on frequent
613
+ # releases, not an actual failure of the publish itself. The next
614
+ # step already exists specifically to handle this (runs on
615
+ # failure(), continue-on-error: true, purges each URL individually
616
+ # via curl) and has been confirmed working on-device. Without
617
+ # continue-on-error here, a benign throttle still failed the whole
618
+ # job even though that fallback ran and succeeded.
619
+ continue-on-error: true
620
+ uses: egad13/purge-jsdelivr-cache@v1
621
+ with:
622
+ url: ${{ steps.cdn_urls.outputs.urls }}
623
+ attempts: 3
624
+
625
+ - name: Purge individual URLs (fallback if batch fails)
626
+ if: steps.publish_npm.outcome == 'success' && failure()
627
+ continue-on-error: true
628
+ run: |
629
+ set +e
630
+
631
+ NPM_BASE="https://cdn.jsdelivr.net/npm/${PACKAGE_NAME}"
632
+ GH_BASE="https://cdn.jsdelivr.net/gh/${PACKAGE_NAME_GH}"
633
+
634
+ declare -a URLS=(
635
+ "${NPM_BASE}@latest"
636
+ "${NPM_BASE}@latest/package.json"
637
+ "${NPM_BASE}@latest/dist/userScript.js"
638
+ "${NPM_BASE}@latest/dist/service.js"
639
+ "${NPM_BASE}@*/package.json"
640
+ "${NPM_BASE}@*/dist/userScript.js"
641
+ "${NPM_BASE}@*/dist/service.js"
642
+ "${NPM_BASE}/package.json"
643
+ "${NPM_BASE}/dist/userScript.js"
644
+ "${NPM_BASE}/dist/service.js"
645
+ "${NPM_BASE}@*"
646
+ "${GH_BASE}@main"
647
+ "${GH_BASE}@main/package.json"
648
+ "${GH_BASE}@main/dist/userScript.js"
649
+ "${GH_BASE}@main/dist/service.js"
650
+ "${GH_BASE}@master"
651
+ "${GH_BASE}@master/package.json"
652
+ "${GH_BASE}@master/dist/userScript.js"
653
+ "${GH_BASE}@master/dist/service.js"
654
+ "${GH_BASE}/package.json"
655
+ "${GH_BASE}/dist/userScript.js"
656
+ "${GH_BASE}/dist/service.js"
657
+ "${GH_BASE}@*"
658
+ )
659
+
660
+ echo "Attempting individual URL purges..."
661
+ for url in "${URLS[@]}"; do
662
+ echo "Purging: $url"
663
+ curl -X POST "https://purge.jsdelivr.net/" \
664
+ -H "cache-control: no-cache" \
665
+ -d "path[]=$url" || echo "Failed to purge $url (continuing...)"
666
+ sleep 2
667
+ done
668
+
669
+ echo "Individual purge attempts complete"
670
+
671
+ - name: Cache purge complete
672
+ if: steps.publish_npm.outcome == 'success'
673
+
674
+ run: echo "✅ jsDelivr cache purge complete (npm + GitHub)"