@ultimat3/render 27.6.0 → 27.7.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.
- package/README.md +3 -1
- package/package.json +6 -6
- package/src/render-isr-store.ts +2 -0
- package/src/render-isr.ts +14 -6
package/README.md
CHANGED
|
@@ -588,7 +588,9 @@ a job boundary the class is gone and the `code` is what survives — match on th
|
|
|
588
588
|
`DEFAULT_ISR_REGENERATE_DEADLINE_MS` (30 s; `isrController({ regenerateDeadlineMs })`),
|
|
589
589
|
so a render that never settles no longer pins the page for the life of the process. A stored
|
|
590
590
|
path takes its TTL and tags from the most specific matching route (static > `:param` >
|
|
591
|
-
`*catch-all`, per segment), never the first in table order.
|
|
591
|
+
`*catch-all`, per segment), never the first in table order. The route is matched on the path
|
|
592
|
+
with its query and its routed locale prefix removed (`unlocalizedPath`), as the router matches
|
|
593
|
+
it — the key keeps both, so `/en/blog/a` is its own entry under `/blog/:slug`'s TTL and tags.
|
|
592
594
|
- **A tag-revalidated ISR document carries its purge keys while it is shared-cacheable**,
|
|
593
595
|
`As of 2026-10-02` — `@ultimat3/http`'s `cache-headers` stage rewrites the response to `private`
|
|
594
596
|
for a signed-in visitor and strips both headers: `Surrogate-Key`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimat3/render",
|
|
3
|
-
"version": "27.
|
|
3
|
+
"version": "27.7.0",
|
|
4
4
|
"description": "The route primitive and the five render modes: static, isr, ssr, stream, spa.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"test": "bun test"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@ultimat3/cache": "27.
|
|
44
|
-
"@ultimat3/core": "27.
|
|
45
|
-
"@ultimat3/http": "27.
|
|
46
|
-
"@ultimat3/i18n": "27.
|
|
47
|
-
"@ultimat3/seo": "27.
|
|
43
|
+
"@ultimat3/cache": "27.7.0",
|
|
44
|
+
"@ultimat3/core": "27.7.0",
|
|
45
|
+
"@ultimat3/http": "27.7.0",
|
|
46
|
+
"@ultimat3/i18n": "27.7.0",
|
|
47
|
+
"@ultimat3/seo": "27.7.0",
|
|
48
48
|
"sass": "1.105.1"
|
|
49
49
|
}
|
|
50
50
|
}
|
package/src/render-isr-store.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface IsrEntry {
|
|
|
12
12
|
* The store key: the request's pathname AND its query, params sorted. Not the route's pattern
|
|
13
13
|
* and not the bare pathname — `/blog?page=2` and `/blog?page=3` render different documents, and
|
|
14
14
|
* keying both as `/blog` served the second visitor the first one's HTML (#171).
|
|
15
|
+
* A routed locale prefix stays on it (`/en/blog`): the controller removes it only to find the
|
|
16
|
+
* route, so a store may never use this as a route path.
|
|
15
17
|
*/
|
|
16
18
|
readonly path: string;
|
|
17
19
|
readonly html: string;
|
package/src/render-isr.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from '@ultimat3/cache';
|
|
19
19
|
import type { Scheduler } from '@ultimat3/core';
|
|
20
20
|
import { finiteCount, logger, renderThrowable, singleFlight } from '@ultimat3/core';
|
|
21
|
+
import { unlocalizedPath } from '@ultimat3/i18n';
|
|
21
22
|
import { parseTtlMs } from './duration';
|
|
22
23
|
import { finiteStatus, isRenderStatus } from './finite-status';
|
|
23
24
|
import type { RouteDescriptor } from './registry';
|
|
@@ -64,15 +65,22 @@ export function isrKey(url: URL, locale: string): string {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
|
-
* The
|
|
68
|
-
* descriptor, and therefore the TTL — has to
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
68
|
+
* The path the ROUTE TABLE knows a key by. Every lookup that asks the table a question — the
|
|
69
|
+
* descriptor, and therefore the TTL and the tags — has to undo what the key carries beyond the
|
|
70
|
+
* route, in the order the router does before it matches (`@ultimat3/http`'s `routing` stage):
|
|
71
|
+
*
|
|
72
|
+
* - the query: `descriptorFor('/blog?page=2')` matches no route;
|
|
73
|
+
* - the routed locale prefix: `/en/blog/a` is the `/blog/:slug` route in English. The key KEEPS the
|
|
74
|
+
* prefix — it is the URL the document was rendered for, `canonical` and all — and the table has
|
|
75
|
+
* never heard of it. Left on, a prefixed page matched no route: `ttlMs: null` and no tag edge, so
|
|
76
|
+
* it was fresh forever while the default locale's copy of the same page went stale on schedule.
|
|
77
|
+
*
|
|
78
|
+
* `unlocalizedPath` is i18n's, the one the router's own split is built on: a segment that names no
|
|
79
|
+
* routed locale is left alone, so `/fr/blog` is still no route.
|
|
72
80
|
*/
|
|
73
81
|
function routePathOf(key: string): string {
|
|
74
82
|
const query = key.indexOf('?');
|
|
75
|
-
return query === -1 ? key : key.slice(0, query);
|
|
83
|
+
return unlocalizedPath(query === -1 ? key : key.slice(0, query));
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
/**
|