react-native-bspatch 1.0.4 → 1.0.6

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.
@@ -14,7 +14,20 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
14
14
  * - Manifest: `${baseUrl}/${baseFolder}/ota_registry.json`
15
15
  * - Patch file: `${baseUrl}/${baseFolder}/${appVersion}/${channel}/${filename}`
16
16
  * - Assets: `${baseUrl}/${baseFolder}/assets/${hash}.${ext}`
17
+ *
18
+ * NOTE: All manifest/registry fetches include Cache-Control: no-cache and a
19
+ * timestamp query param to bypass GitHub CDN's 5-minute (max-age=300) cache.
20
+ * Asset URLs are content-addressed (hash-named) so they are immutable and
21
+ * intentionally NOT cache-busted.
17
22
  */
23
+
24
+ /** Headers to bypass GitHub CDN cache on mutable files (registry, manifests) */
25
+ const NO_CACHE_HEADERS = {
26
+ 'Cache-Control': 'no-cache'
27
+ };
28
+
29
+ /** Append a timestamp query param to defeat CDN caches on mutable URLs */
30
+ const bustCache = url => `${url}?cb=${Date.now()}`;
18
31
  class GitHubRawStorageProvider {
19
32
  async fetchManifest(config) {
20
33
  if (!config.customServer) return config.bundledPatches || [];
@@ -24,9 +37,10 @@ class GitHubRawStorageProvider {
24
37
  baseFolder = 'ota'
25
38
  } = config.customServer;
26
39
  const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
27
- const registryUrl = `${normalizedBaseUrl}/${baseFolder}/ota_registry.json`;
40
+ // Cache-bust: registry is mutable; must always fetch the latest version
41
+ const registryUrl = bustCache(`${normalizedBaseUrl}/${baseFolder}/ota_registry.json`);
28
42
  try {
29
- const res = await _reactNativeBlobUtil.default.fetch('GET', registryUrl);
43
+ const res = await _reactNativeBlobUtil.default.fetch('GET', registryUrl, NO_CACHE_HEADERS);
30
44
  if (res.respInfo.status !== 200) {
31
45
  throw new Error(`Registry fetch failed with status ${res.respInfo.status}`);
32
46
  }
@@ -53,7 +67,10 @@ class GitHubRawStorageProvider {
53
67
  } = config.customServer;
54
68
  const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
55
69
  const channelName = channel.toLowerCase();
56
- return `${normalizedBaseUrl}/${baseFolder}/${config.appVersion}/${channelName}/${filename}`;
70
+
71
+ // Cache-bust: patch files are versioned by name but GitHub CDN may
72
+ // serve a stale 404 response for newly uploaded files within 5 min.
73
+ return bustCache(`${normalizedBaseUrl}/${baseFolder}/${config.appVersion}/${channelName}/${filename}`);
57
74
  }
58
75
  async getAssetUrl(hash, ext, config) {
59
76
  if (!config.customServer) return '';
@@ -62,6 +79,8 @@ class GitHubRawStorageProvider {
62
79
  baseFolder = 'ota'
63
80
  } = config.customServer;
64
81
  const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
82
+
83
+ // Assets are content-addressed (hash = filename) → immutable, no cache-bust needed
65
84
  return `${normalizedBaseUrl}/${baseFolder}/assets/${hash}.${ext}`;
66
85
  }
67
86
  }
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","_reactNativeBlobUtil","_interopRequireDefault","e","__esModule","default","GitHubRawStorageProvider","fetchManifest","config","customServer","bundledPatches","baseUrl","channel","baseFolder","normalizedBaseUrl","endsWith","slice","registryUrl","res","ReactNativeBlobUtil","fetch","respInfo","status","Error","registry","data","JSON","parse","appGroup","apps","appVersion","flavorGroup","flavors","toLowerCase","development","patches","length","filter","p","platform","Platform","OS","error","console","warn","message","getUpdateFileUrl","filename","channelName","getAssetUrl","hash","ext","exports"],"sourceRoot":"../../../../src","sources":["ota/storage/GitHubRawStorage.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","_reactNativeBlobUtil","_interopRequireDefault","e","__esModule","default","NO_CACHE_HEADERS","bustCache","url","Date","now","GitHubRawStorageProvider","fetchManifest","config","customServer","bundledPatches","baseUrl","channel","baseFolder","normalizedBaseUrl","endsWith","slice","registryUrl","res","ReactNativeBlobUtil","fetch","respInfo","status","Error","registry","data","JSON","parse","appGroup","apps","appVersion","flavorGroup","flavors","toLowerCase","development","patches","length","filter","p","platform","Platform","OS","error","console","warn","message","getUpdateFileUrl","filename","channelName","getAssetUrl","hash","ext","exports"],"sourceRoot":"../../../../src","sources":["ota/storage/GitHubRawStorage.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AACA,IAAAC,oBAAA,GAAAC,sBAAA,CAAAF,OAAA;AAAyD,SAAAE,uBAAAC,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAGzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,MAAMG,gBAAgB,GAAG;EAAE,eAAe,EAAE;AAAW,CAAC;;AAExD;AACA,MAAMC,SAAS,GAAIC,GAAW,IAC1B,GAAGA,GAAG,OAAOC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAE;AAEtB,MAAMC,wBAAwB,CAA+B;EAChE,MAAMC,aAAaA,CAACC,MAAiB,EAAuB;IACxD,IAAI,CAACA,MAAM,CAACC,YAAY,EAAE,OAAOD,MAAM,CAACE,cAAc,IAAI,EAAE;IAE5D,MAAM;MAAEC,OAAO;MAAEC,OAAO;MAAEC,UAAU,GAAG;IAAM,CAAC,GAAGL,MAAM,CAACC,YAAY;IACpE,MAAMK,iBAAiB,GAAGH,OAAO,CAACI,QAAQ,CAAC,GAAG,CAAC,GACzCJ,OAAO,CAACK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACpBL,OAAO;IACb;IACA,MAAMM,WAAW,GAAGf,SAAS,CACzB,GAAGY,iBAAiB,IAAID,UAAU,oBACtC,CAAC;IAED,IAAI;MACA,MAAMK,GAAG,GAAG,MAAMC,4BAAmB,CAACC,KAAK,CACvC,KAAK,EACLH,WAAW,EACXhB,gBACJ,CAAC;MACD,IAAIiB,GAAG,CAACG,QAAQ,CAACC,MAAM,KAAK,GAAG,EAAE;QAC7B,MAAM,IAAIC,KAAK,CACX,qCAAqCL,GAAG,CAACG,QAAQ,CAACC,MAAM,EAC5D,CAAC;MACL;MAEA,MAAME,QAAQ,GACV,OAAON,GAAG,CAACO,IAAI,KAAK,QAAQ,GACtBC,IAAI,CAACC,KAAK,CAACT,GAAG,CAACO,IAAI,CAAC,GACpBP,GAAG,CAACO,IAAI;MAElB,MAAMG,QAAQ,GAAGJ,QAAQ,EAAEK,IAAI,GAAGrB,MAAM,CAACsB,UAAU,CAAC;MACpD,MAAMC,WAAW,GACbH,QAAQ,EAAEI,OAAO,GAAGpB,OAAO,CAACqB,WAAW,CAAC,CAAC,CAAC,IAC1CL,QAAQ,EAAEI,OAAO,EAAEE,WAAW;MAElC,IAAI,CAACH,WAAW,EAAEI,OAAO,EAAEC,MAAM,EAAE;QAC/B,OAAO5B,MAAM,CAACE,cAAc,IAAI,EAAE;MACtC;MAEA,OAAO,CAACqB,WAAW,CAACI,OAAO,IAAI,EAAE,EAAEE,MAAM,CACpCC,CAAW,IACR,CAACA,CAAC,CAACC,QAAQ,IACXD,CAAC,CAACC,QAAQ,CAACN,WAAW,CAAC,CAAC,KAAKO,qBAAQ,CAACC,EAAE,CAACR,WAAW,CAAC,CAC7D,CAAC;IACL,CAAC,CAAC,OAAOS,KAAK,EAAE;MACZC,OAAO,CAACC,IAAI,CACR,0CAA0C,EACzCF,KAAK,CAAWG,OACrB,CAAC;MACD,OAAOrC,MAAM,CAACE,cAAc,IAAI,EAAE;IACtC;EACJ;EAEA,MAAMoC,gBAAgBA,CAClBC,QAAgB,EAChBvC,MAAiB,EACF;IACf,IAAI,CAACA,MAAM,CAACC,YAAY,EAAE;MACtB,MAAM,IAAIc,KAAK,CAAC,oCAAoC,CAAC;IACzD;IAEA,MAAM;MAAEZ,OAAO;MAAEE,UAAU,GAAG,KAAK;MAAED;IAAQ,CAAC,GAAGJ,MAAM,CAACC,YAAY;IACpE,MAAMK,iBAAiB,GAAGH,OAAO,CAACI,QAAQ,CAAC,GAAG,CAAC,GACzCJ,OAAO,CAACK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACpBL,OAAO;IACb,MAAMqC,WAAW,GAAGpC,OAAO,CAACqB,WAAW,CAAC,CAAC;;IAEzC;IACA;IACA,OAAO/B,SAAS,CACZ,GAAGY,iBAAiB,IAAID,UAAU,IAAIL,MAAM,CAACsB,UAAU,IAAIkB,WAAW,IAAID,QAAQ,EACtF,CAAC;EACL;EAEA,MAAME,WAAWA,CACbC,IAAY,EACZC,GAAW,EACX3C,MAAiB,EACF;IACf,IAAI,CAACA,MAAM,CAACC,YAAY,EAAE,OAAO,EAAE;IAEnC,MAAM;MAAEE,OAAO;MAAEE,UAAU,GAAG;IAAM,CAAC,GAAGL,MAAM,CAACC,YAAY;IAC3D,MAAMK,iBAAiB,GAAGH,OAAO,CAACI,QAAQ,CAAC,GAAG,CAAC,GACzCJ,OAAO,CAACK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACpBL,OAAO;;IAEb;IACA,OAAO,GAAGG,iBAAiB,IAAID,UAAU,WAAWqC,IAAI,IAAIC,GAAG,EAAE;EACrE;AACJ;AAACC,OAAA,CAAA9C,wBAAA,GAAAA,wBAAA","ignoreList":[]}
@@ -9,7 +9,20 @@ import ReactNativeBlobUtil from 'react-native-blob-util';
9
9
  * - Manifest: `${baseUrl}/${baseFolder}/ota_registry.json`
10
10
  * - Patch file: `${baseUrl}/${baseFolder}/${appVersion}/${channel}/${filename}`
11
11
  * - Assets: `${baseUrl}/${baseFolder}/assets/${hash}.${ext}`
12
+ *
13
+ * NOTE: All manifest/registry fetches include Cache-Control: no-cache and a
14
+ * timestamp query param to bypass GitHub CDN's 5-minute (max-age=300) cache.
15
+ * Asset URLs are content-addressed (hash-named) so they are immutable and
16
+ * intentionally NOT cache-busted.
12
17
  */
18
+
19
+ /** Headers to bypass GitHub CDN cache on mutable files (registry, manifests) */
20
+ const NO_CACHE_HEADERS = {
21
+ 'Cache-Control': 'no-cache'
22
+ };
23
+
24
+ /** Append a timestamp query param to defeat CDN caches on mutable URLs */
25
+ const bustCache = url => `${url}?cb=${Date.now()}`;
13
26
  export class GitHubRawStorageProvider {
14
27
  async fetchManifest(config) {
15
28
  if (!config.customServer) return config.bundledPatches || [];
@@ -19,9 +32,10 @@ export class GitHubRawStorageProvider {
19
32
  baseFolder = 'ota'
20
33
  } = config.customServer;
21
34
  const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
22
- const registryUrl = `${normalizedBaseUrl}/${baseFolder}/ota_registry.json`;
35
+ // Cache-bust: registry is mutable; must always fetch the latest version
36
+ const registryUrl = bustCache(`${normalizedBaseUrl}/${baseFolder}/ota_registry.json`);
23
37
  try {
24
- const res = await ReactNativeBlobUtil.fetch('GET', registryUrl);
38
+ const res = await ReactNativeBlobUtil.fetch('GET', registryUrl, NO_CACHE_HEADERS);
25
39
  if (res.respInfo.status !== 200) {
26
40
  throw new Error(`Registry fetch failed with status ${res.respInfo.status}`);
27
41
  }
@@ -48,7 +62,10 @@ export class GitHubRawStorageProvider {
48
62
  } = config.customServer;
49
63
  const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
50
64
  const channelName = channel.toLowerCase();
51
- return `${normalizedBaseUrl}/${baseFolder}/${config.appVersion}/${channelName}/${filename}`;
65
+
66
+ // Cache-bust: patch files are versioned by name but GitHub CDN may
67
+ // serve a stale 404 response for newly uploaded files within 5 min.
68
+ return bustCache(`${normalizedBaseUrl}/${baseFolder}/${config.appVersion}/${channelName}/${filename}`);
52
69
  }
53
70
  async getAssetUrl(hash, ext, config) {
54
71
  if (!config.customServer) return '';
@@ -57,6 +74,8 @@ export class GitHubRawStorageProvider {
57
74
  baseFolder = 'ota'
58
75
  } = config.customServer;
59
76
  const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
77
+
78
+ // Assets are content-addressed (hash = filename) → immutable, no cache-bust needed
60
79
  return `${normalizedBaseUrl}/${baseFolder}/assets/${hash}.${ext}`;
61
80
  }
62
81
  }
@@ -1 +1 @@
1
- {"version":3,"names":["Platform","ReactNativeBlobUtil","GitHubRawStorageProvider","fetchManifest","config","customServer","bundledPatches","baseUrl","channel","baseFolder","normalizedBaseUrl","endsWith","slice","registryUrl","res","fetch","respInfo","status","Error","registry","data","JSON","parse","appGroup","apps","appVersion","flavorGroup","flavors","toLowerCase","development","patches","length","filter","p","platform","OS","error","console","warn","message","getUpdateFileUrl","filename","channelName","getAssetUrl","hash","ext"],"sourceRoot":"../../../../src","sources":["ota/storage/GitHubRawStorage.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["Platform","ReactNativeBlobUtil","NO_CACHE_HEADERS","bustCache","url","Date","now","GitHubRawStorageProvider","fetchManifest","config","customServer","bundledPatches","baseUrl","channel","baseFolder","normalizedBaseUrl","endsWith","slice","registryUrl","res","fetch","respInfo","status","Error","registry","data","JSON","parse","appGroup","apps","appVersion","flavorGroup","flavors","toLowerCase","development","patches","length","filter","p","platform","OS","error","console","warn","message","getUpdateFileUrl","filename","channelName","getAssetUrl","hash","ext"],"sourceRoot":"../../../../src","sources":["ota/storage/GitHubRawStorage.ts"],"mappings":"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","ignoreList":[]}
@@ -1,12 +1,4 @@
1
1
  import type { OtaConfig, OtaPatch, OtaStorageProvider } from '../types';
2
- /**
3
- * Storage Provider for fetching OTA updates directly from a GitHub Raw repository.
4
- *
5
- * Direct URL mapping:
6
- * - Manifest: `${baseUrl}/${baseFolder}/ota_registry.json`
7
- * - Patch file: `${baseUrl}/${baseFolder}/${appVersion}/${channel}/${filename}`
8
- * - Assets: `${baseUrl}/${baseFolder}/assets/${hash}.${ext}`
9
- */
10
2
  export declare class GitHubRawStorageProvider implements OtaStorageProvider {
11
3
  fetchManifest(config: OtaConfig): Promise<OtaPatch[]>;
12
4
  getUpdateFileUrl(filename: string, config: OtaConfig): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"GitHubRawStorage.d.ts","sourceRoot":"","sources":["../../../../src/ota/storage/GitHubRawStorage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAExE;;;;;;;GAOG;AACH,qBAAa,wBAAyB,YAAW,kBAAkB;IACzD,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IA6CrD,gBAAgB,CAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,GAClB,OAAO,CAAC,MAAM,CAAC;IAcZ,WAAW,CACb,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,SAAS,GAClB,OAAO,CAAC,MAAM,CAAC;CAUrB"}
1
+ {"version":3,"file":"GitHubRawStorage.d.ts","sourceRoot":"","sources":["../../../../src/ota/storage/GitHubRawStorage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAuBxE,qBAAa,wBAAyB,YAAW,kBAAkB;IACzD,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAoDrD,gBAAgB,CAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,GAClB,OAAO,CAAC,MAAM,CAAC;IAkBZ,WAAW,CACb,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,SAAS,GAClB,OAAO,CAAC,MAAM,CAAC;CAWrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-bspatch",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Premium OTA Update Solution for React Native using TurboModules and bsdiff",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -9,7 +9,20 @@ import type { OtaConfig, OtaPatch, OtaStorageProvider } from '../types';
9
9
  * - Manifest: `${baseUrl}/${baseFolder}/ota_registry.json`
10
10
  * - Patch file: `${baseUrl}/${baseFolder}/${appVersion}/${channel}/${filename}`
11
11
  * - Assets: `${baseUrl}/${baseFolder}/assets/${hash}.${ext}`
12
+ *
13
+ * NOTE: All manifest/registry fetches include Cache-Control: no-cache and a
14
+ * timestamp query param to bypass GitHub CDN's 5-minute (max-age=300) cache.
15
+ * Asset URLs are content-addressed (hash-named) so they are immutable and
16
+ * intentionally NOT cache-busted.
12
17
  */
18
+
19
+ /** Headers to bypass GitHub CDN cache on mutable files (registry, manifests) */
20
+ const NO_CACHE_HEADERS = { 'Cache-Control': 'no-cache' };
21
+
22
+ /** Append a timestamp query param to defeat CDN caches on mutable URLs */
23
+ const bustCache = (url: string): string =>
24
+ `${url}?cb=${Date.now()}`;
25
+
13
26
  export class GitHubRawStorageProvider implements OtaStorageProvider {
14
27
  async fetchManifest(config: OtaConfig): Promise<OtaPatch[]> {
15
28
  if (!config.customServer) return config.bundledPatches || [];
@@ -18,10 +31,17 @@ export class GitHubRawStorageProvider implements OtaStorageProvider {
18
31
  const normalizedBaseUrl = baseUrl.endsWith('/')
19
32
  ? baseUrl.slice(0, -1)
20
33
  : baseUrl;
21
- const registryUrl = `${normalizedBaseUrl}/${baseFolder}/ota_registry.json`;
34
+ // Cache-bust: registry is mutable; must always fetch the latest version
35
+ const registryUrl = bustCache(
36
+ `${normalizedBaseUrl}/${baseFolder}/ota_registry.json`,
37
+ );
22
38
 
23
39
  try {
24
- const res = await ReactNativeBlobUtil.fetch('GET', registryUrl);
40
+ const res = await ReactNativeBlobUtil.fetch(
41
+ 'GET',
42
+ registryUrl,
43
+ NO_CACHE_HEADERS,
44
+ );
25
45
  if (res.respInfo.status !== 200) {
26
46
  throw new Error(
27
47
  `Registry fetch failed with status ${res.respInfo.status}`,
@@ -70,7 +90,11 @@ export class GitHubRawStorageProvider implements OtaStorageProvider {
70
90
  : baseUrl;
71
91
  const channelName = channel.toLowerCase();
72
92
 
73
- return `${normalizedBaseUrl}/${baseFolder}/${config.appVersion}/${channelName}/${filename}`;
93
+ // Cache-bust: patch files are versioned by name but GitHub CDN may
94
+ // serve a stale 404 response for newly uploaded files within 5 min.
95
+ return bustCache(
96
+ `${normalizedBaseUrl}/${baseFolder}/${config.appVersion}/${channelName}/${filename}`,
97
+ );
74
98
  }
75
99
 
76
100
  async getAssetUrl(
@@ -85,6 +109,7 @@ export class GitHubRawStorageProvider implements OtaStorageProvider {
85
109
  ? baseUrl.slice(0, -1)
86
110
  : baseUrl;
87
111
 
112
+ // Assets are content-addressed (hash = filename) → immutable, no cache-bust needed
88
113
  return `${normalizedBaseUrl}/${baseFolder}/assets/${hash}.${ext}`;
89
114
  }
90
115
  }
@@ -95,17 +95,61 @@ if [ "$ACTION" != "reset" ]; then
95
95
 
96
96
  if [[ "$BASE_URL" == *"github"* ]] || [[ "$BASE_URL" == *"raw.githubusercontent"* ]]; then
97
97
  echo " Downloading remote registry from GitHub..."
98
- HTTP_CODE=$(curl -s -w "%{http_code}" -o "$REGISTRY_SHARED.tmp" "$BASE_URL/$BASE_FOLDER/ota_registry.json" 2>/dev/null || true)
99
- if [ "$HTTP_CODE" != "200" ]; then
100
- HTTP_CODE=$(curl -s -w "%{http_code}" -o "$REGISTRY_SHARED.tmp" "$BASE_URL/ota_registry.json" 2>/dev/null || true)
98
+
99
+ # Parse OWNER/REPO/BRANCH from the raw.githubusercontent URL or github.com URL
100
+ # e.g. https://raw.githubusercontent.com/owner/repo/branch OR
101
+ # https://github.com/owner/repo/tree/branch
102
+ CLEAN_URL=$(echo "$BASE_URL" | sed 's#https://raw.githubusercontent.com/##' | sed 's#https://github.com/##' | sed 's#/tree/##')
103
+ GH_OWNER=$(echo "$CLEAN_URL" | cut -d'/' -f1)
104
+ GH_REPO=$(echo "$CLEAN_URL" | cut -d'/' -f2)
105
+ GH_BRANCH=$(echo "$CLEAN_URL" | cut -d'/' -f3)
106
+ if [[ -z "$GH_BRANCH" ]]; then GH_BRANCH="main"; fi
107
+
108
+ # Prefer GitHub CLI token for authenticated requests (higher rate limit, no cache)
109
+ GH_CLI_TOKEN=$(gh auth token 2>/dev/null || true)
110
+ GH_API_TOKEN="${GH_CLI_TOKEN:-${GH_TOKEN:-${GITHUB_TOKEN:-}}}"
111
+
112
+ # Use GitHub Contents API — NOT raw CDN — to bypass the 5-min CDN cache.
113
+ # The API always returns the latest committed content.
114
+ REGISTRY_API_URL="https://api.github.com/repos/${GH_OWNER}/${GH_REPO}/contents/${BASE_FOLDER}/ota_registry.json?ref=${GH_BRANCH}"
115
+
116
+ if [[ -n "$GH_API_TOKEN" ]]; then
117
+ API_RES=$(curl -s -w "\n---HTTP:%{http_code}" \
118
+ -H "Authorization: Bearer $GH_API_TOKEN" \
119
+ -H "Accept: application/vnd.github.v3+json" \
120
+ "$REGISTRY_API_URL" 2>/dev/null || true)
121
+ else
122
+ API_RES=$(curl -s -w "\n---HTTP:%{http_code}" \
123
+ -H "Accept: application/vnd.github.v3+json" \
124
+ "$REGISTRY_API_URL" 2>/dev/null || true)
101
125
  fi
102
- if [ "$HTTP_CODE" = "200" ] && [ -s "$REGISTRY_SHARED.tmp" ]; then
103
- mv "$REGISTRY_SHARED.tmp" "$REGISTRY_SHARED"
104
- echo " ✓ Remote registry synced"
126
+
127
+ API_HTTP=$(echo "$API_RES" | grep -o '---HTTP:[0-9]*' | cut -d: -f2)
128
+ API_BODY=$(echo "$API_RES" | sed 's/---HTTP:.*//')
129
+
130
+ if [[ "$API_HTTP" = "200" ]]; then
131
+ # Decode base64 content returned by the API
132
+ echo "$API_BODY" | python3 -c "
133
+ import sys, json, base64
134
+ d = json.load(sys.stdin)
135
+ content = d.get('content', '')
136
+ # GitHub API returns base64 with newlines; strip them before decoding
137
+ decoded = base64.b64decode(content.replace('\n', ''))
138
+ sys.stdout.buffer.write(decoded)
139
+ " > "$REGISTRY_SHARED.tmp" 2>/dev/null || true
140
+
141
+ if [ -s "$REGISTRY_SHARED.tmp" ]; then
142
+ mv "$REGISTRY_SHARED.tmp" "$REGISTRY_SHARED"
143
+ echo " ✓ Remote registry synced (via GitHub API)"
144
+ else
145
+ rm -f "$REGISTRY_SHARED.tmp"
146
+ echo " Notice: Remote registry empty or decode failed (starting fresh with local state)."
147
+ fi
105
148
  else
106
149
  rm -f "$REGISTRY_SHARED.tmp"
107
- echo " Notice: Remote registry not found on GitHub (starting fresh with local state)."
150
+ echo " Notice: Remote registry not found on GitHub API (HTTP $API_HTTP — starting fresh with local state)."
108
151
  fi
152
+
109
153
  else
110
154
  if [[ -n "$UPCODE_USER" ]] && [[ -n "$UPCODE_PASS" ]]; then
111
155
  LOGIN_RES=$(curl -s -X "POST" "$BASE_URL/public/authen/login" \
@@ -150,9 +194,12 @@ fi
150
194
  download_from_minio() {
151
195
  local REMOTE_PATH="$1"
152
196
  local DEST="$2"
197
+ local CB="?cb=$(date +%s)"
153
198
 
154
199
  if [[ "$BASE_URL" == *"github"* ]] || [[ "$BASE_URL" == *"raw.githubusercontent"* ]]; then
155
- curl -s -f -o "$DEST" "$BASE_URL/$REMOTE_PATH" 2>/dev/null || curl -s -f -o "$DEST" "$BASE_URL/$(basename "$REMOTE_PATH")" 2>/dev/null
200
+ # Use Cache-Control: no-cache + timestamp query to bypass GitHub CDN 5-min cache
201
+ curl -s -f -H "Cache-Control: no-cache" -o "$DEST" "$BASE_URL/$REMOTE_PATH${CB}" 2>/dev/null || \
202
+ curl -s -f -H "Cache-Control: no-cache" -o "$DEST" "$BASE_URL/$(basename "$REMOTE_PATH")${CB}" 2>/dev/null
156
203
  return $?
157
204
  fi
158
205