@nifrajs/web 5.4.0 → 5.5.1
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/CHANGELOG.md +54 -0
- package/dist/build-plan.d.ts +6 -0
- package/dist/build-plan.d.ts.map +1 -1
- package/dist/build-plan.js +25 -0
- package/dist/build-plan.js.map +1 -1
- package/dist/build-vite.d.ts +2 -0
- package/dist/build-vite.d.ts.map +1 -1
- package/dist/build-vite.js +2 -0
- package/dist/build-vite.js.map +1 -1
- package/dist/build.d.ts +17 -3
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +81 -40
- package/dist/build.js.map +1 -1
- package/dist/deferred.d.ts.map +1 -1
- package/dist/deferred.js +20 -6
- package/dist/deferred.js.map +1 -1
- package/dist/dev.d.ts +5 -0
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +7 -6
- package/dist/dev.js.map +1 -1
- package/dist/diagnostic.d.ts +6 -0
- package/dist/diagnostic.d.ts.map +1 -1
- package/dist/diagnostic.js +41 -0
- package/dist/diagnostic.js.map +1 -1
- package/dist/host-policy.d.ts +72 -0
- package/dist/host-policy.d.ts.map +1 -0
- package/dist/host-policy.js +149 -0
- package/dist/host-policy.js.map +1 -0
- package/dist/host-reach.d.ts +49 -0
- package/dist/host-reach.d.ts.map +1 -0
- package/dist/host-reach.js +144 -0
- package/dist/host-reach.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/certified-components.d.ts +8 -0
- package/dist/internal/certified-components.d.ts.map +1 -0
- package/dist/internal/certified-components.js +8 -0
- package/dist/internal/certified-components.js.map +1 -0
- package/dist/internal/codegen.d.ts +8 -0
- package/dist/internal/codegen.d.ts.map +1 -1
- package/dist/internal/codegen.js +15 -4
- package/dist/internal/codegen.js.map +1 -1
- package/dist/internal/output-guard.d.ts +6 -0
- package/dist/internal/output-guard.d.ts.map +1 -1
- package/dist/internal/output-guard.js +118 -16
- package/dist/internal/output-guard.js.map +1 -1
- package/dist/internal/page-execution.d.ts +2 -0
- package/dist/internal/page-execution.d.ts.map +1 -1
- package/dist/internal/page-execution.js +16 -11
- package/dist/internal/page-execution.js.map +1 -1
- package/dist/internal/render-document.d.ts +3 -1
- package/dist/internal/render-document.d.ts.map +1 -1
- package/dist/internal/render-document.js +10 -4
- package/dist/internal/render-document.js.map +1 -1
- package/dist/internal/web-app.d.ts +15 -1
- package/dist/internal/web-app.d.ts.map +1 -1
- package/dist/internal/web-app.js +8 -0
- package/dist/internal/web-app.js.map +1 -1
- package/dist/public-dir.d.ts +4 -3
- package/dist/public-dir.d.ts.map +1 -1
- package/dist/public-dir.js +24 -18
- package/dist/public-dir.js.map +1 -1
- package/dist/router.d.ts +2 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +9 -8
- package/dist/router.js.map +1 -1
- package/dist/server-components/vite.d.ts.map +1 -1
- package/dist/server-components/vite.js +8 -6
- package/dist/server-components/vite.js.map +1 -1
- package/dist/service-worker.d.ts +3 -1
- package/dist/service-worker.d.ts.map +1 -1
- package/dist/service-worker.js +29 -8
- package/dist/service-worker.js.map +1 -1
- package/dist/zones.d.ts +5 -1
- package/dist/zones.d.ts.map +1 -1
- package/dist/zones.js +17 -4
- package/dist/zones.js.map +1 -1
- package/package.json +4 -4
- package/src/build-plan.ts +26 -0
- package/src/build-vite.ts +4 -0
- package/src/build.ts +114 -44
- package/src/deferred.ts +20 -6
- package/src/dev.ts +7 -6
- package/src/diagnostic.ts +43 -0
- package/src/host-policy.ts +219 -0
- package/src/host-reach.ts +177 -0
- package/src/index.ts +10 -2
- package/src/internal/certified-components.ts +7 -0
- package/src/internal/codegen.ts +24 -5
- package/src/internal/output-guard.ts +166 -15
- package/src/internal/page-execution.ts +23 -9
- package/src/internal/render-document.ts +11 -4
- package/src/internal/web-app.ts +27 -1
- package/src/public-dir.ts +31 -24
- package/src/router.ts +9 -8
- package/src/server-components/vite.ts +11 -6
- package/src/service-worker.ts +32 -9
- package/src/zones.ts +27 -5
package/src/service-worker.ts
CHANGED
|
@@ -37,7 +37,9 @@ export interface ServiceWorkerOptions {
|
|
|
37
37
|
/**
|
|
38
38
|
* URL of a page to serve when a navigation fails and the network is unreachable. It must be a
|
|
39
39
|
* static, user-independent document (a prerendered `/offline`), because every visitor gets the same
|
|
40
|
-
* bytes.
|
|
40
|
+
* bytes. Install fails rather than store it, or any precached URL, when the response is an error, a
|
|
41
|
+
* redirect, or marked `private` or `no-store`. Omit it and failed navigations simply fail, which is
|
|
42
|
+
* the honest default.
|
|
41
43
|
*/
|
|
42
44
|
readonly offlineUrl?: string
|
|
43
45
|
/**
|
|
@@ -115,10 +117,35 @@ const OWN_URLS = new Set(PRECACHE)
|
|
|
115
117
|
const OWN = { cacheName: CACHE }
|
|
116
118
|
const OFFLINE = ${offline === undefined ? "null" : JSON.stringify(offline)}
|
|
117
119
|
|
|
120
|
+
// Whether every visitor may be served these bytes from this cache. CacheStorage itself ignores
|
|
121
|
+
// Cache-Control, and a redirect can land one visitor's page under a shared URL.
|
|
122
|
+
const shareable = (response) =>
|
|
123
|
+
response.ok &&
|
|
124
|
+
response.type === "basic" &&
|
|
125
|
+
!response.redirected &&
|
|
126
|
+
!(response.headers.get("cache-control") ?? "")
|
|
127
|
+
.split(",")
|
|
128
|
+
.some((directive) => /^\\s*(?:no-store|private)\\s*(?:=|$)/i.test(directive))
|
|
129
|
+
|
|
118
130
|
self.addEventListener("install", (event) => {
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
|
|
131
|
+
// Every response is checked before any is stored, so a refused one leaves this build's cache
|
|
132
|
+
// empty and the install failed, as addAll would on an error status. Take over as soon as the new
|
|
133
|
+
// assets are stored; the activate handler drops the old cache, so waiting would only serve stale
|
|
134
|
+
// bytes for longer.
|
|
135
|
+
event.waitUntil(
|
|
136
|
+
Promise.all(
|
|
137
|
+
PRECACHE.map((url) =>
|
|
138
|
+
fetch(url).then((response) => {
|
|
139
|
+
if (shareable(response)) return response
|
|
140
|
+
throw new TypeError("[nifra/web] not precached, the response is not shareable: " + url)
|
|
141
|
+
}),
|
|
142
|
+
),
|
|
143
|
+
)
|
|
144
|
+
.then((responses) =>
|
|
145
|
+
caches.open(CACHE).then((c) => Promise.all(responses.map((r, i) => c.put(PRECACHE[i], r)))),
|
|
146
|
+
)
|
|
147
|
+
.then(() => self.skipWaiting()),
|
|
148
|
+
)
|
|
122
149
|
})
|
|
123
150
|
|
|
124
151
|
self.addEventListener("activate", (event) => {
|
|
@@ -156,11 +183,7 @@ self.addEventListener("fetch", (event) => {
|
|
|
156
183
|
caches.match(request, OWN).then((hit) => {
|
|
157
184
|
if (hit !== undefined) return hit
|
|
158
185
|
return fetch(request).then((response) => {
|
|
159
|
-
|
|
160
|
-
response.ok &&
|
|
161
|
-
response.type === "basic" &&
|
|
162
|
-
!(response.headers.get("cache-control") ?? "").includes("no-store")
|
|
163
|
-
if (cacheable) {
|
|
186
|
+
if (shareable(response)) {
|
|
164
187
|
const copy = response.clone()
|
|
165
188
|
void caches.open(CACHE).then((c) => c.put(request, copy))
|
|
166
189
|
}
|
package/src/zones.ts
CHANGED
|
@@ -170,7 +170,11 @@ export interface ZoneConfig {
|
|
|
170
170
|
readonly backend?: readonly string[]
|
|
171
171
|
/** App-relative folders or files holding frontend code, beside `frontend/`. */
|
|
172
172
|
readonly frontend?: readonly string[]
|
|
173
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* App-relative folders or files holding code both sides import, beside `shared/`. Unlike the other
|
|
175
|
+
* sides, an entry may sit inside `frontend/` or `backend/`: a module there that both sides import
|
|
176
|
+
* stays where it is, held to the shared rules (it may import only shared code and packages).
|
|
177
|
+
*/
|
|
174
178
|
readonly shared?: readonly string[]
|
|
175
179
|
}
|
|
176
180
|
|
|
@@ -258,8 +262,15 @@ export function parseZoneConfig(value: unknown, source: string): ZoneConfig {
|
|
|
258
262
|
if (folder.split("/").includes("..")) fail(`"${side}" entry "${entry}" may not contain ".."`)
|
|
259
263
|
if (/[*?[\]{}!]/.test(folder))
|
|
260
264
|
fail(`"${side}" entry "${entry}" must be a plain path (a trailing "/**" is allowed)`)
|
|
261
|
-
|
|
262
|
-
|
|
265
|
+
const sharedInSide =
|
|
266
|
+
side === "shared" && (top === "frontend" || top === "backend") && folder !== top
|
|
267
|
+
if ((RESERVED_FOLDERS.has(top) && !sharedInSide) || top.startsWith(".nifra"))
|
|
268
|
+
fail(
|
|
269
|
+
`"${side}" entry "${entry}" is inside ${top}/, which already has its own rules` +
|
|
270
|
+
(top === "frontend" || top === "backend"
|
|
271
|
+
? `; only a "shared" entry may name a path inside ${top}/`
|
|
272
|
+
: ""),
|
|
273
|
+
)
|
|
263
274
|
const other = owner.get(folder)
|
|
264
275
|
if (other !== undefined && other !== side)
|
|
265
276
|
fail(`"${folder}" is listed as both ${other} and ${side}; a path has one side`)
|
|
@@ -587,11 +598,22 @@ export function createZoneClassifier(options: ZoneClassifierOptions): ZoneClassi
|
|
|
587
598
|
if (suffix === "shared") return { zone: "shared" }
|
|
588
599
|
return { zone: "route-frontend" }
|
|
589
600
|
}
|
|
590
|
-
|
|
591
|
-
const
|
|
601
|
+
// Inside a reserved folder only a "shared" entry can match: the parser refuses the others there.
|
|
602
|
+
const configured = configuredPath(rel)
|
|
603
|
+
const folder = configured?.[1] ?? ZONE_FOLDERS[top]
|
|
592
604
|
if (folder !== undefined) {
|
|
593
605
|
if (suffix === undefined || suffix === folder) return { zone: folder }
|
|
594
606
|
if (suffix === "fn" && folder === "backend") return { zone: "fn" }
|
|
607
|
+
// Code both sides import may live beside the side that wrote it. Shared code may import only
|
|
608
|
+
// shared code and packages, so the declaration narrows what the file may reach, never widens it.
|
|
609
|
+
// A file "nifra.zones" lists by name has that side; its suffix cannot contradict it.
|
|
610
|
+
if (
|
|
611
|
+
suffix === "shared" &&
|
|
612
|
+
(folder === "frontend" || folder === "backend") &&
|
|
613
|
+
top !== "public" &&
|
|
614
|
+
configured?.[0] !== rel
|
|
615
|
+
)
|
|
616
|
+
return { zone: "shared" }
|
|
595
617
|
const where =
|
|
596
618
|
configured === undefined
|
|
597
619
|
? `sits in ${top}/`
|