@hot-updater/server 1.0.0-rc.41 → 1.0.0-rc.43

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,6 +9,22 @@ const ORIGIN_CACHE_MAX_ENTRIES = 128;
9
9
  const NO_CATALOG_HEADER = "x-hot-updater-catalog";
10
10
  /** A shared cache keeps a catalog, or a scope's lack of one, five seconds. */
11
11
  const CATALOG_CACHE_CONTROL = "public, max-age=0, s-maxage=5";
12
+ /**
13
+ * The same five seconds for a CDN that reads `CDN-Cache-Control` (RFC 9213),
14
+ * such as Cloudflare's Workers Cache, which then ignores `Cache-Control`.
15
+ * `s-maxage` forbids serving stale, so there an expired catalog held requests
16
+ * at that location until the origin answered. Here, for five more seconds,
17
+ * the CDN answers with the expired copy while it revalidates in the
18
+ * background. `stale-if-error=0` keeps origin errors visible: without it,
19
+ * Cloudflare serves a stale copy on error indefinitely.
20
+ *
21
+ * A device can see a catalog up to 15 seconds after a deploy or a Roll back
22
+ * replaced it: the origin's 5-second catalog memo, then 5 seconds fresh and
23
+ * 5 stale at the CDN. A revoked API key can read a cached catalog up to
24
+ * 10 seconds. Devices and caches that don't read the header keep
25
+ * `Cache-Control`.
26
+ */
27
+ const CATALOG_CDN_CACHE_CONTROL = "public, max-age=5, stale-while-revalidate=5, stale-if-error=0";
12
28
  const privateNotFound = () => Response.json({ error: "Not found" }, {
13
29
  status: 404,
14
30
  headers: { "cache-control": "private, no-store" }
@@ -24,6 +40,7 @@ const missingCatalog = () => Response.json({ error: "Not found" }, {
24
40
  status: 404,
25
41
  headers: {
26
42
  "cache-control": CATALOG_CACHE_CONTROL,
43
+ "cdn-cache-control": CATALOG_CDN_CACHE_CONTROL,
27
44
  vary: "Accept-Encoding",
28
45
  [NO_CATALOG_HEADER]: "none"
29
46
  }
@@ -38,6 +55,7 @@ const catalogResponse = async (catalog, request) => {
38
55
  const etag = `"sha256:${await responseHash(body)}"`;
39
56
  const headers = {
40
57
  "cache-control": CATALOG_CACHE_CONTROL,
58
+ "cdn-cache-control": CATALOG_CDN_CACHE_CONTROL,
41
59
  "content-type": CATALOG_CONTENT_TYPE,
42
60
  etag,
43
61
  vary: "Accept-Encoding"
@@ -9,6 +9,22 @@ const ORIGIN_CACHE_MAX_ENTRIES = 128;
9
9
  const NO_CATALOG_HEADER = "x-hot-updater-catalog";
10
10
  /** A shared cache keeps a catalog, or a scope's lack of one, five seconds. */
11
11
  const CATALOG_CACHE_CONTROL = "public, max-age=0, s-maxage=5";
12
+ /**
13
+ * The same five seconds for a CDN that reads `CDN-Cache-Control` (RFC 9213),
14
+ * such as Cloudflare's Workers Cache, which then ignores `Cache-Control`.
15
+ * `s-maxage` forbids serving stale, so there an expired catalog held requests
16
+ * at that location until the origin answered. Here, for five more seconds,
17
+ * the CDN answers with the expired copy while it revalidates in the
18
+ * background. `stale-if-error=0` keeps origin errors visible: without it,
19
+ * Cloudflare serves a stale copy on error indefinitely.
20
+ *
21
+ * A device can see a catalog up to 15 seconds after a deploy or a Roll back
22
+ * replaced it: the origin's 5-second catalog memo, then 5 seconds fresh and
23
+ * 5 stale at the CDN. A revoked API key can read a cached catalog up to
24
+ * 10 seconds. Devices and caches that don't read the header keep
25
+ * `Cache-Control`.
26
+ */
27
+ const CATALOG_CDN_CACHE_CONTROL = "public, max-age=5, stale-while-revalidate=5, stale-if-error=0";
12
28
  const privateNotFound = () => Response.json({ error: "Not found" }, {
13
29
  status: 404,
14
30
  headers: { "cache-control": "private, no-store" }
@@ -24,6 +40,7 @@ const missingCatalog = () => Response.json({ error: "Not found" }, {
24
40
  status: 404,
25
41
  headers: {
26
42
  "cache-control": CATALOG_CACHE_CONTROL,
43
+ "cdn-cache-control": CATALOG_CDN_CACHE_CONTROL,
27
44
  vary: "Accept-Encoding",
28
45
  [NO_CATALOG_HEADER]: "none"
29
46
  }
@@ -38,6 +55,7 @@ const catalogResponse = async (catalog, request) => {
38
55
  const etag = `"sha256:${await responseHash(body)}"`;
39
56
  const headers = {
40
57
  "cache-control": CATALOG_CACHE_CONTROL,
58
+ "cdn-cache-control": CATALOG_CDN_CACHE_CONTROL,
41
59
  "content-type": CATALOG_CONTENT_TYPE,
42
60
  etag,
43
61
  vary: "Accept-Encoding"
package/dist/package.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "1.0.0-rc.41";
2
+ var version = "1.0.0-rc.43";
3
3
  //#endregion
4
4
  Object.defineProperty(exports, "version", {
5
5
  enumerable: true,
package/dist/package.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "1.0.0-rc.41";
2
+ var version = "1.0.0-rc.43";
3
3
  //#endregion
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/server",
3
- "version": "1.0.0-rc.41",
3
+ "version": "1.0.0-rc.43",
4
4
  "type": "module",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "sideEffects": false,
@@ -58,11 +58,11 @@
58
58
  "dependencies": {
59
59
  "rou3": "0.7.9",
60
60
  "verkit": "0.4.0",
61
- "@hot-updater/protocol": "1.0.0-rc.41",
62
- "@hot-updater/plugin-core": "1.0.0-rc.41",
63
- "@hot-updater/plugin-remote-config": "1.0.0-rc.41",
64
- "@hot-updater/plugin-api-keys": "1.0.0-rc.41",
65
- "@hot-updater/plugin-insights": "1.0.0-rc.41"
61
+ "@hot-updater/plugin-core": "1.0.0-rc.43",
62
+ "@hot-updater/plugin-api-keys": "1.0.0-rc.43",
63
+ "@hot-updater/protocol": "1.0.0-rc.43",
64
+ "@hot-updater/plugin-remote-config": "1.0.0-rc.43",
65
+ "@hot-updater/plugin-insights": "1.0.0-rc.43"
66
66
  },
67
67
  "peerDependencies": {
68
68
  "@prisma/client": "*",
@@ -103,8 +103,8 @@
103
103
  "prisma": "6.19.3",
104
104
  "uuidv7": "^1.0.2",
105
105
  "wrangler": "^4.69.0",
106
- "@hot-updater/standalone": "1.0.0-rc.41",
107
- "@hot-updater/test-utils": "1.0.0-rc.41"
106
+ "@hot-updater/standalone": "1.0.0-rc.43",
107
+ "@hot-updater/test-utils": "1.0.0-rc.43"
108
108
  },
109
109
  "nx": {
110
110
  "implicitDependencies": [