@nifrajs/web 5.6.0 → 5.8.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/CHANGELOG.md +97 -0
- package/README.md +21 -11
- package/dist/build.d.ts +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +1 -0
- package/dist/build.js.map +1 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +39 -16
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/codegen.d.ts.map +1 -1
- package/dist/internal/codegen.js +8 -2
- package/dist/internal/codegen.js.map +1 -1
- package/dist/internal/identity-epoch.d.ts +2 -2
- package/dist/internal/identity-epoch.d.ts.map +1 -1
- package/dist/internal/identity-epoch.js +15 -14
- package/dist/internal/identity-epoch.js.map +1 -1
- package/dist/internal/live-contract.d.ts +5 -0
- package/dist/internal/live-contract.d.ts.map +1 -1
- package/dist/internal/live-contract.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 +22 -5
- package/dist/internal/page-execution.js.map +1 -1
- package/dist/internal/parity.d.ts +3 -0
- package/dist/internal/parity.d.ts.map +1 -1
- package/dist/internal/parity.js +28 -5
- package/dist/internal/parity.js.map +1 -1
- package/dist/internal/ppr/runtime.d.ts +1 -1
- package/dist/internal/ppr/runtime.d.ts.map +1 -1
- package/dist/internal/ppr/runtime.js +4 -1
- package/dist/internal/ppr/runtime.js.map +1 -1
- package/dist/internal/ppr/server.d.ts.map +1 -1
- package/dist/internal/ppr/server.js +4 -2
- package/dist/internal/ppr/server.js.map +1 -1
- package/dist/internal/ppr/shell-store.d.ts +1 -0
- package/dist/internal/ppr/shell-store.d.ts.map +1 -1
- package/dist/internal/ppr/shell-store.js +17 -1
- package/dist/internal/ppr/shell-store.js.map +1 -1
- package/dist/internal/present.d.ts +11 -0
- package/dist/internal/present.d.ts.map +1 -0
- package/dist/internal/present.js +13 -0
- package/dist/internal/present.js.map +1 -0
- package/dist/internal/render-document.d.ts +6 -63
- package/dist/internal/render-document.d.ts.map +1 -1
- package/dist/internal/render-document.js +3 -50
- package/dist/internal/render-document.js.map +1 -1
- package/dist/internal/status-page.d.ts +68 -0
- package/dist/internal/status-page.d.ts.map +1 -0
- package/dist/internal/status-page.js +66 -0
- package/dist/internal/status-page.js.map +1 -0
- package/dist/internal/web-app.d.ts +3 -2
- package/dist/internal/web-app.d.ts.map +1 -1
- package/dist/internal/web-app.js +1 -0
- package/dist/internal/web-app.js.map +1 -1
- package/dist/keep-alive.d.ts.map +1 -1
- package/dist/keep-alive.js +46 -13
- package/dist/keep-alive.js.map +1 -1
- package/dist/live/bus.d.ts +16 -2
- package/dist/live/bus.d.ts.map +1 -1
- package/dist/live/bus.js +23 -0
- package/dist/live/bus.js.map +1 -1
- package/dist/live/hub.d.ts +4 -0
- package/dist/live/hub.d.ts.map +1 -1
- package/dist/live/hub.js +5 -0
- package/dist/live/hub.js.map +1 -1
- package/dist/live/keyring.d.ts +5 -0
- package/dist/live/keyring.d.ts.map +1 -1
- package/dist/live/keyring.js +6 -1
- package/dist/live/keyring.js.map +1 -1
- package/dist/live-client.d.ts.map +1 -1
- package/dist/live-client.js +45 -7
- package/dist/live-client.js.map +1 -1
- package/dist/live-redis.d.ts +14 -2
- package/dist/live-redis.d.ts.map +1 -1
- package/dist/live-redis.js +16 -5
- package/dist/live-redis.js.map +1 -1
- package/dist/live.d.ts +57 -1
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +119 -16
- package/dist/live.js.map +1 -1
- package/dist/render-seam.d.ts +2 -0
- package/dist/render-seam.d.ts.map +1 -1
- package/dist/render-seam.js +2 -0
- package/dist/render-seam.js.map +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +49 -37
- package/dist/router.js.map +1 -1
- package/dist/server-components/definition.d.ts.map +1 -1
- package/dist/server-components/definition.js +2 -1
- package/dist/server-components/definition.js.map +1 -1
- package/dist/server-components/runtime.d.ts.map +1 -1
- package/dist/server-components/runtime.js +2 -1
- package/dist/server-components/runtime.js.map +1 -1
- package/dist/server-components/vite.d.ts.map +1 -1
- package/dist/server-components/vite.js +26 -9
- package/dist/server-components/vite.js.map +1 -1
- package/package.json +3 -3
- package/src/build.ts +1 -0
- package/src/client.ts +42 -19
- package/src/index.ts +1 -4
- package/src/internal/codegen.ts +8 -1
- package/src/internal/identity-epoch.ts +20 -16
- package/src/internal/live-contract.ts +5 -0
- package/src/internal/page-execution.ts +29 -8
- package/src/internal/parity.ts +35 -6
- package/src/internal/ppr/runtime.ts +4 -1
- package/src/internal/ppr/server.ts +4 -2
- package/src/internal/ppr/shell-store.ts +14 -1
- package/src/internal/present.ts +20 -0
- package/src/internal/render-document.ts +10 -92
- package/src/internal/status-page.ts +95 -0
- package/src/internal/web-app.ts +4 -2
- package/src/keep-alive.ts +55 -16
- package/src/live/bus.ts +29 -2
- package/src/live/hub.ts +5 -0
- package/src/live/keyring.ts +6 -1
- package/src/live-client.ts +45 -7
- package/src/live-redis.ts +31 -6
- package/src/live.ts +178 -17
- package/src/render-seam.ts +2 -0
- package/src/router.ts +47 -38
- package/src/server-components/definition.ts +2 -1
- package/src/server-components/runtime.ts +2 -1
- package/src/server-components/vite.ts +33 -14
package/src/router.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type { StandardSchemaV1 } from "@nifrajs/core/server"
|
|
|
10
10
|
import type { BoundaryDescriptor, BoundaryState, BoundaryStates } from "./boundary.ts"
|
|
11
11
|
import { parseNdjsonData } from "./deferred.ts"
|
|
12
12
|
import { epochOf, IDENTITY_CHANNEL, onIdentityChange } from "./identity.ts"
|
|
13
|
+
import { present } from "./internal/present.ts"
|
|
13
14
|
import { parsePageData } from "./internal/revive-dates.ts"
|
|
14
15
|
import { appUrl, requestPattern } from "./internal/route-path.ts"
|
|
15
16
|
import { shareData } from "./internal/share-data.ts"
|
|
@@ -1361,11 +1362,14 @@ export function createClientRouter(options: ClientRouterOptions): ClientRouter {
|
|
|
1361
1362
|
searchClientKeys[state.routeId] ?? [],
|
|
1362
1363
|
)
|
|
1363
1364
|
) {
|
|
1364
|
-
++generation // supersede any in-flight navigation so its late result is dropped
|
|
1365
|
+
const mine = ++generation // supersede any in-flight navigation so its late result is dropped
|
|
1365
1366
|
navAbort?.abort()
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1367
|
+
await present(() => {
|
|
1368
|
+
if (mine !== generation) return
|
|
1369
|
+
cachePut(path, dataFields(state))
|
|
1370
|
+
state = { ...state, path, pending: false, pendingPath: undefined }
|
|
1371
|
+
emit()
|
|
1372
|
+
})
|
|
1369
1373
|
return
|
|
1370
1374
|
}
|
|
1371
1375
|
const mine = ++generation
|
|
@@ -1378,46 +1382,51 @@ export function createClientRouter(options: ClientRouterOptions): ClientRouter {
|
|
|
1378
1382
|
const [to, target, loaded] = await loadFollowing(mine, path, matched, ac.signal, true, true)
|
|
1379
1383
|
if (mine !== generation) return // a newer navigation superseded this one - drop the stale result
|
|
1380
1384
|
cachePut(to, loaded) // keep the keyed cache coherent with what we publish
|
|
1381
|
-
// The
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1385
|
+
// The swap can wait a frame for the presenter, and a newer navigation started meanwhile owns it.
|
|
1386
|
+
await present(() => {
|
|
1387
|
+
if (mine !== generation) return
|
|
1388
|
+
// The page's own URL is never intercepted: navigating there (Back out of a boundary, a link
|
|
1389
|
+
// to itself) shows the page, even when a boundary's pattern matches it.
|
|
1390
|
+
const pagePath = pagePathOf(state)
|
|
1391
|
+
const interception =
|
|
1392
|
+
loaded.terminalRouteId === undefined && pathnameOf(to) !== pathnameOf(pagePath)
|
|
1393
|
+
? interceptionFor(state.routeId, to, target)
|
|
1394
|
+
: undefined
|
|
1395
|
+
if (interception !== undefined) {
|
|
1396
|
+
// The target's ordinary data request has already completed (including its server authz and
|
|
1397
|
+
// optional client wrapper). Only the presentation route is retained; the current page stays
|
|
1398
|
+
// mounted underneath the named slot. A target that returned a terminal status never reaches
|
|
1399
|
+
// this branch, so an unauthorized/missing target cannot become a modal.
|
|
1400
|
+
state = {
|
|
1401
|
+
...state,
|
|
1402
|
+
path: to,
|
|
1403
|
+
boundaries: holdTarget(state.boundaries, interception, loaded),
|
|
1404
|
+
intercepted: { boundary: interception.name, pagePath },
|
|
1405
|
+
pending: false,
|
|
1406
|
+
pendingPath: undefined,
|
|
1407
|
+
}
|
|
1408
|
+
emit()
|
|
1409
|
+
return
|
|
1410
|
+
}
|
|
1393
1411
|
state = {
|
|
1394
|
-
|
|
1412
|
+
routeId: loaded.terminalRouteId ?? target.routeId,
|
|
1413
|
+
params: loaded.terminalRouteId === undefined ? target.params : {},
|
|
1395
1414
|
path: to,
|
|
1396
|
-
|
|
1397
|
-
|
|
1415
|
+
...dataFields(loaded),
|
|
1416
|
+
actionData: undefined, // a fresh navigation has no action result
|
|
1398
1417
|
pending: false,
|
|
1399
|
-
pendingPath: undefined,
|
|
1400
1418
|
}
|
|
1419
|
+
shownPage = loaded
|
|
1401
1420
|
emit()
|
|
1402
|
-
|
|
1403
|
-
}
|
|
1404
|
-
state = {
|
|
1405
|
-
routeId: loaded.terminalRouteId ?? target.routeId,
|
|
1406
|
-
params: loaded.terminalRouteId === undefined ? target.params : {},
|
|
1407
|
-
path: to,
|
|
1408
|
-
...dataFields(loaded),
|
|
1409
|
-
actionData: undefined, // a fresh navigation has no action result
|
|
1410
|
-
pending: false,
|
|
1411
|
-
}
|
|
1412
|
-
shownPage = loaded
|
|
1413
|
-
emit()
|
|
1421
|
+
})
|
|
1414
1422
|
} catch (err) {
|
|
1415
|
-
//
|
|
1416
|
-
//
|
|
1417
|
-
if (mine
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
}
|
|
1423
|
+
// A newer navigation or submit owns the page, and aborting this one's request is how it took
|
|
1424
|
+
// over: as with a submit, the superseded navigation settles quietly.
|
|
1425
|
+
if (mine !== generation) return
|
|
1426
|
+
// Clear our pending flag + target and rethrow - the caller decides how to recover (the history
|
|
1427
|
+
// layer falls back to a full-page navigation).
|
|
1428
|
+
state = { ...state, pending: false, pendingPath: undefined }
|
|
1429
|
+
emit()
|
|
1421
1430
|
throw err
|
|
1422
1431
|
}
|
|
1423
1432
|
},
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { narrowCapabilityContext } from "@nifrajs/core/capabilities"
|
|
2
2
|
import { validateStandard } from "@nifrajs/core/schema"
|
|
3
3
|
import { outputGuard, runGuard } from "../internal/output-guard.ts"
|
|
4
|
-
import { isControlFlow
|
|
4
|
+
import { isControlFlow } from "../internal/render-document.ts"
|
|
5
|
+
import { isStatusSignal } from "../internal/status-page.ts"
|
|
5
6
|
import { ServerComponentError } from "./error.ts"
|
|
6
7
|
import { assertComponentSchema, componentValue } from "./schema.ts"
|
|
7
8
|
import type {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CapabilityDefinition } from "@nifrajs/core/capabilities"
|
|
2
|
-
import { isResponseResult
|
|
2
|
+
import { isResponseResult } from "../internal/render-document.ts"
|
|
3
|
+
import { isStatusSignal, STATUS_SIGNAL } from "../internal/status-page.ts"
|
|
3
4
|
import {
|
|
4
5
|
authorizeServerComponent,
|
|
5
6
|
isServerComponent,
|
|
@@ -25,6 +25,17 @@ const reactRuntime = "\0nifra-component-react-runtime"
|
|
|
25
25
|
// Vite uses forward slashes for module IDs even when the filesystem uses backslashes.
|
|
26
26
|
const bare = (id: string): string => (id.split("?")[0] ?? id).replaceAll("\\", "/")
|
|
27
27
|
|
|
28
|
+
// Blanked with spaces rather than cut, so later offsets still point at the source.
|
|
29
|
+
function withoutUseClient(source: string, path: string): string {
|
|
30
|
+
for (const statement of sourceFile(source, path).statements) {
|
|
31
|
+
if (!ts.isExpressionStatement(statement) || !ts.isStringLiteral(statement.expression)) break
|
|
32
|
+
if (statement.expression.text !== "use client") continue
|
|
33
|
+
const start = statement.getStart()
|
|
34
|
+
return `${source.slice(0, start)}${" ".repeat(statement.end - start)}${source.slice(statement.end)}`
|
|
35
|
+
}
|
|
36
|
+
return source
|
|
37
|
+
}
|
|
38
|
+
|
|
28
39
|
export interface ServerComponentsPluginOptions {
|
|
29
40
|
readonly root: string
|
|
30
41
|
readonly adapter: "react" | "vue" | "svelte" | "solid" | "preact"
|
|
@@ -224,23 +235,31 @@ export function serverComponentsPlugin(
|
|
|
224
235
|
return null
|
|
225
236
|
},
|
|
226
237
|
transform(source, id) {
|
|
227
|
-
if (id.includes(nativeQuery) || internal.has(bare(id))) return null
|
|
228
238
|
const path = bare(id)
|
|
229
239
|
let code = source
|
|
230
|
-
if (
|
|
231
|
-
|
|
232
|
-
|
|
240
|
+
if (!id.includes(nativeQuery) && !internal.has(path)) {
|
|
241
|
+
if (componentFile.test(path)) {
|
|
242
|
+
code = compileComponentModule(source, path, options.root, this.environment.name).code
|
|
243
|
+
componentModules.add(path)
|
|
244
|
+
}
|
|
245
|
+
if (islandFile.test(path))
|
|
246
|
+
code = compileComponentModule(
|
|
247
|
+
source,
|
|
248
|
+
path,
|
|
249
|
+
options.root,
|
|
250
|
+
this.environment.name,
|
|
251
|
+
"island",
|
|
252
|
+
).code
|
|
253
|
+
if (this.environment.name === "rsc" && options.adapter === "react")
|
|
254
|
+
code = guardCreateElementCalls(code, path)
|
|
233
255
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
).code
|
|
242
|
-
if (this.environment.name === "rsc" && options.adapter === "react")
|
|
243
|
-
code = guardCreateElementCalls(code, path)
|
|
256
|
+
// Only the rsc build acts on "use client"; the client and ssr bundles would warn about it.
|
|
257
|
+
if (
|
|
258
|
+
this.environment.name !== "rsc" &&
|
|
259
|
+
options.adapter === "react" &&
|
|
260
|
+
code.includes("use client")
|
|
261
|
+
)
|
|
262
|
+
code = withoutUseClient(code, path)
|
|
244
263
|
return code === source ? null : { code, map: null }
|
|
245
264
|
},
|
|
246
265
|
}
|