@nifrajs/cli 5.0.0 → 5.1.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 +7 -2
- package/dist/assure-hydration.d.ts.map +1 -1
- package/dist/assure-hydration.js +4 -2
- package/dist/assure-hydration.js.map +1 -1
- package/dist/assure.d.ts +12 -2
- package/dist/assure.d.ts.map +1 -1
- package/dist/assure.js +59 -8
- package/dist/assure.js.map +1 -1
- package/dist/capabilities-tool.d.ts.map +1 -1
- package/dist/capabilities-tool.js +24 -7
- package/dist/capabilities-tool.js.map +1 -1
- package/dist/check-diagnostics.d.ts +2 -0
- package/dist/check-diagnostics.d.ts.map +1 -1
- package/dist/check-diagnostics.js.map +1 -1
- package/dist/check-scan.d.ts +8 -2
- package/dist/check-scan.d.ts.map +1 -1
- package/dist/check-scan.js +43 -10
- package/dist/check-scan.js.map +1 -1
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +39 -33
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +106 -48
- package/dist/cli.js.map +1 -1
- package/dist/client-module.d.ts +5 -3
- package/dist/client-module.d.ts.map +1 -1
- package/dist/client-module.js +34 -10
- package/dist/client-module.js.map +1 -1
- package/dist/command-catalog.d.ts +9 -1
- package/dist/command-catalog.d.ts.map +1 -1
- package/dist/command-catalog.js +67 -22
- package/dist/command-catalog.js.map +1 -1
- package/dist/dev-feed-tool.d.ts +18 -1
- package/dist/dev-feed-tool.d.ts.map +1 -1
- package/dist/dev-feed-tool.js +93 -0
- package/dist/dev-feed-tool.js.map +1 -1
- package/dist/fix-recipes.d.ts +2 -0
- package/dist/fix-recipes.d.ts.map +1 -1
- package/dist/fix-recipes.js +93 -12
- package/dist/fix-recipes.js.map +1 -1
- package/dist/init-agents.d.ts +16 -0
- package/dist/init-agents.d.ts.map +1 -1
- package/dist/init-agents.js +3 -2
- package/dist/init-agents.js.map +1 -1
- package/dist/internal/config-paths.d.ts +16 -0
- package/dist/internal/config-paths.d.ts.map +1 -0
- package/dist/internal/config-paths.js +124 -0
- package/dist/internal/config-paths.js.map +1 -0
- package/dist/internal/installed-package.d.ts +4 -0
- package/dist/internal/installed-package.d.ts.map +1 -0
- package/dist/internal/installed-package.js +17 -0
- package/dist/internal/installed-package.js.map +1 -0
- package/dist/internal/project-specifiers.d.ts +14 -1
- package/dist/internal/project-specifiers.d.ts.map +1 -1
- package/dist/internal/project-specifiers.js +54 -15
- package/dist/internal/project-specifiers.js.map +1 -1
- package/dist/internal/source-facts.d.ts +6 -1
- package/dist/internal/source-facts.d.ts.map +1 -1
- package/dist/internal/source-facts.js +11 -5
- package/dist/internal/source-facts.js.map +1 -1
- package/dist/internal/typescript-import.d.ts.map +1 -1
- package/dist/internal/typescript-import.js +5 -3
- package/dist/internal/typescript-import.js.map +1 -1
- package/dist/introspect.d.ts +9 -0
- package/dist/introspect.d.ts.map +1 -1
- package/dist/introspect.js +32 -1
- package/dist/introspect.js.map +1 -1
- package/dist/levels-tool.d.ts.map +1 -1
- package/dist/levels-tool.js +5 -8
- package/dist/levels-tool.js.map +1 -1
- package/dist/load.d.ts +2 -2
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +23 -3
- package/dist/load.js.map +1 -1
- package/dist/mcp-context.d.ts.map +1 -1
- package/dist/mcp-context.js +6 -21
- package/dist/mcp-context.js.map +1 -1
- package/dist/mcp-delegate.d.ts +2 -2
- package/dist/mcp-delegate.d.ts.map +1 -1
- package/dist/mcp-delegate.js +19 -7
- package/dist/mcp-delegate.js.map +1 -1
- package/dist/mcp-exec.d.ts +1 -0
- package/dist/mcp-exec.d.ts.map +1 -1
- package/dist/mcp-exec.js +8 -3
- package/dist/mcp-exec.js.map +1 -1
- package/dist/mcp-http.js +1 -1
- package/dist/mcp-io.d.ts +13 -0
- package/dist/mcp-io.d.ts.map +1 -1
- package/dist/mcp-io.js +23 -0
- package/dist/mcp-io.js.map +1 -1
- package/dist/mcp-path.d.ts +2 -1
- package/dist/mcp-path.d.ts.map +1 -1
- package/dist/mcp-path.js +9 -24
- package/dist/mcp-path.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +40 -17
- package/dist/mcp.js.map +1 -1
- package/dist/migrate-layout.d.ts +40 -1
- package/dist/migrate-layout.d.ts.map +1 -1
- package/dist/migrate-layout.js +1316 -228
- package/dist/migrate-layout.js.map +1 -1
- package/dist/output-schemas.d.ts +34 -0
- package/dist/output-schemas.d.ts.map +1 -1
- package/dist/output-schemas.js +132 -21
- package/dist/output-schemas.js.map +1 -1
- package/dist/project-path.d.ts +6 -0
- package/dist/project-path.d.ts.map +1 -1
- package/dist/project-path.js +48 -14
- package/dist/project-path.js.map +1 -1
- package/dist/release-verification.d.ts +5 -0
- package/dist/release-verification.d.ts.map +1 -1
- package/dist/release-verification.js +14 -0
- package/dist/release-verification.js.map +1 -1
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +5 -0
- package/dist/review.js.map +1 -1
- package/dist/rules/codes.d.ts +3 -1
- package/dist/rules/codes.d.ts.map +1 -1
- package/dist/rules/codes.js +3 -1
- package/dist/rules/codes.js.map +1 -1
- package/dist/rules/data-guard.d.ts +6 -0
- package/dist/rules/data-guard.d.ts.map +1 -1
- package/dist/rules/data-guard.js +37 -0
- package/dist/rules/data-guard.js.map +1 -1
- package/dist/rules/legacy.d.ts.map +1 -1
- package/dist/rules/legacy.js +20 -1
- package/dist/rules/legacy.js.map +1 -1
- package/dist/rules/pages.d.ts +29 -3
- package/dist/rules/pages.d.ts.map +1 -1
- package/dist/rules/pages.js +236 -22
- package/dist/rules/pages.js.map +1 -1
- package/dist/rules/security.d.ts +3 -2
- package/dist/rules/security.d.ts.map +1 -1
- package/dist/rules/security.js +42 -11
- package/dist/rules/security.js.map +1 -1
- package/dist/rules/zones.d.ts.map +1 -1
- package/dist/rules/zones.js +31 -9
- package/dist/rules/zones.js.map +1 -1
- package/dist/stylex-migrate.d.ts.map +1 -1
- package/dist/stylex-migrate.js +127 -17
- package/dist/stylex-migrate.js.map +1 -1
- package/dist/test-tool.d.ts.map +1 -1
- package/dist/test-tool.js +3 -9
- package/dist/test-tool.js.map +1 -1
- package/dist/upgrade.d.ts +20 -5
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/upgrade.js +86 -9
- package/dist/upgrade.js.map +1 -1
- package/dist/verification-plan.d.ts.map +1 -1
- package/dist/verification-plan.js +5 -2
- package/dist/verification-plan.js.map +1 -1
- package/dist/version-drift.d.ts.map +1 -1
- package/dist/version-drift.js +55 -3
- package/dist/version-drift.js.map +1 -1
- package/docs/examples.json +2 -2
- package/docs/llms-full.txt +481 -61
- package/docs/types.json +147 -70
- package/package.json +11 -11
- package/src/assure-hydration.ts +4 -1
- package/src/assure.ts +88 -10
- package/src/capabilities-tool.ts +33 -7
- package/src/check-diagnostics.ts +2 -0
- package/src/check-scan.ts +56 -9
- package/src/check.ts +55 -39
- package/src/cli.ts +104 -35
- package/src/client-module.ts +45 -9
- package/src/command-catalog.ts +77 -21
- package/src/dev-feed-tool.ts +112 -1
- package/src/fix-recipes.ts +101 -10
- package/src/init-agents.ts +4 -3
- package/src/internal/config-paths.ts +154 -0
- package/src/internal/installed-package.ts +15 -0
- package/src/internal/project-specifiers.ts +69 -16
- package/src/internal/source-facts.ts +23 -5
- package/src/internal/typescript-import.ts +5 -3
- package/src/introspect.ts +39 -1
- package/src/levels-tool.ts +7 -9
- package/src/load.ts +29 -3
- package/src/mcp-context.ts +5 -18
- package/src/mcp-delegate.ts +22 -10
- package/src/mcp-exec.ts +9 -2
- package/src/mcp-http.ts +1 -1
- package/src/mcp-io.ts +33 -0
- package/src/mcp-path.ts +8 -22
- package/src/mcp.ts +48 -19
- package/src/migrate-layout.ts +1496 -237
- package/src/output-schemas.ts +179 -23
- package/src/project-path.ts +44 -13
- package/src/release-verification.ts +20 -0
- package/src/review.ts +5 -0
- package/src/rules/codes.ts +3 -1
- package/src/rules/data-guard.ts +40 -0
- package/src/rules/legacy.ts +22 -1
- package/src/rules/pages.ts +266 -24
- package/src/rules/security.ts +49 -11
- package/src/rules/zones.ts +30 -7
- package/src/stylex-migrate.ts +117 -17
- package/src/test-tool.ts +3 -9
- package/src/upgrade.ts +96 -8
- package/src/verification-plan.ts +9 -2
- package/src/version-drift.ts +53 -2
package/docs/llms-full.txt
CHANGED
|
@@ -1404,7 +1404,9 @@ that is not JSON, says so in a comment, and marks what it wrote with a
|
|
|
1404
1404
|
under the line was edited (reformatting it is not an edit); delete the line to own the
|
|
1405
1405
|
schema by hand. A hand-written schema is never rewritten: the report lists the
|
|
1406
1406
|
returned fields it drops, by path. Nothing is derived at request time - the schema in the
|
|
1407
|
-
file is the one the guard enforces.
|
|
1407
|
+
file is the one the guard enforces. `nifra fix --code NF-C030` writes the same
|
|
1408
|
+
draft for one flagged route, and `nifra migrate layout` drafts one for each
|
|
1409
|
+
route it splits whose loader or action returns data without a schema.
|
|
1408
1410
|
|
|
1409
1411
|
A field named like a credential (`password`, `token`,
|
|
1410
1412
|
`apiKey`) fails the route when it loads unless its schema is wrapped in
|
|
@@ -1448,6 +1450,18 @@ export default function NewUser() {
|
|
|
1448
1450
|
}
|
|
1449
1451
|
```
|
|
1450
1452
|
|
|
1453
|
+
A form can post to another site and the browser sends that site's cookies with it, so an action
|
|
1454
|
+
refuses a POST whose `Origin` is another site's with 403, before middleware, gates or
|
|
1455
|
+
the action run. A request without an `Origin`, such as one from a server, passes, and
|
|
1456
|
+
so does a form on the app's own page sent under `Referrer-Policy: no-referrer`, which
|
|
1457
|
+
arrives as `Origin: null` with `Sec-Fetch-Site: same-origin`.
|
|
1458
|
+
Same-origin is judged from the request URL's host, so a proxy in front must forward the
|
|
1459
|
+
`Host` header. A route that takes posts from elsewhere, such as an identity
|
|
1460
|
+
provider's `form_post` callback, exports `allowedOrigins` from its backend
|
|
1461
|
+
file: an array of exact origins, or a function that receives the origin (`null` when
|
|
1462
|
+
absent). It checks where the browser says the request comes from, not who sent it, so keep the
|
|
1463
|
+
action's own authentication.
|
|
1464
|
+
|
|
1451
1465
|
### Layout loaders on navigation
|
|
1452
1466
|
|
|
1453
1467
|
A `_layout.backend.ts` can have a `loader` too; its output reaches the
|
|
@@ -1455,7 +1469,11 @@ layout component as `data`. On a client navigation that keeps the layout on scre
|
|
|
1455
1469
|
browser already holds that data, so the loader runs again only when a param the layout owns
|
|
1456
1470
|
changes (`org` for `orgs/[org]/_layout.tsx`) or the query changes. After
|
|
1457
1471
|
an action, every loader runs. A layout that exports `gate = true` runs on every
|
|
1458
|
-
request; a layout loader without it is not an authorization boundary
|
|
1472
|
+
request; a layout loader without it is not an authorization boundary: a client navigation can
|
|
1473
|
+
skip it, and an action below it runs without it. Put a check that refuses access in a gate or
|
|
1474
|
+
in middleware. In development, nifra warns the first time a layout loader without
|
|
1475
|
+
`gate` refuses a request with a redirect, a `Response`, or a 401 or 403,
|
|
1476
|
+
and `nifra check` reports one whose loader refuses in its own body (NF-C042). A
|
|
1459
1477
|
`_layout.backend.ts` that exports `middleware` guards a directory, with
|
|
1460
1478
|
or without a layout component - see [Route middleware](/docs/routing#middleware).
|
|
1461
1479
|
|
|
@@ -1561,8 +1579,9 @@ host - defence in depth behind the JSON requirement, at the cost of one comparis
|
|
|
1561
1579
|
Serialising closed-over variables to the browser and back is a class of problem worth not
|
|
1562
1580
|
having rather than encrypting.
|
|
1563
1581
|
|
|
1564
|
-
Both content-type rules were measured rather than assumed. A body schema alone still
|
|
1565
|
-
|
|
1582
|
+
Both content-type rules were measured rather than assumed. A body schema alone still reads a
|
|
1583
|
+
urlencoded form that carries no `Origin` or one from a site in
|
|
1584
|
+
`formOrigins` - 200, attacker-controlled fields - and a bounded JSON read alone
|
|
1566
1585
|
accepts the `text/plain` trick where a form's `name=value` is crafted to
|
|
1567
1586
|
parse as valid JSON. Neither is sufficient by itself.
|
|
1568
1587
|
|
|
@@ -2952,6 +2971,20 @@ Svelte resolve deferred data on the **client**, so JS-off users see the fallback
|
|
|
2952
2971
|
deferred boundary. Put critical page data in the route `loader`; use
|
|
2953
2972
|
`defer()` for slower, non-critical data.
|
|
2954
2973
|
|
|
2974
|
+
### Markup outside the page
|
|
2975
|
+
|
|
2976
|
+
Svelte's `<svelte:head>` renders into the document's
|
|
2977
|
+
`<head>`, after the tags from the route's `meta`. The document
|
|
2978
|
+
always has a `<title>` of its own and a browser uses the first one, so set the
|
|
2979
|
+
title in `meta`.
|
|
2980
|
+
|
|
2981
|
+
A Vue `<Teleport>` is server-rendered where Vue hydrates it from, the first
|
|
2982
|
+
children of its target. `to="body"` content comes first in
|
|
2983
|
+
`<body>`. An `#id` target the app renders empty receives it, and one
|
|
2984
|
+
the app does not render gets a container before the app root. Any other selector, a target that
|
|
2985
|
+
has children of its own, and every teleport on a page that uses `defer()` render on
|
|
2986
|
+
the client, with a warning in development.
|
|
2987
|
+
|
|
2955
2988
|
### Dev HMR support
|
|
2956
2989
|
|
|
2957
2990
|
Dev HMR works for all five adapters through `createViteDevServer` and the
|
|
@@ -2997,6 +3030,47 @@ app
|
|
|
2997
3030
|
app.use((a) => a.decorate("db", db).derive((c) => ({ now: Date.now() })))
|
|
2998
3031
|
```
|
|
2999
3032
|
|
|
3033
|
+
### What a parent’s use() covers
|
|
3034
|
+
|
|
3035
|
+
A `group()` scope inherits the parent’s chain as it stands at the call. A
|
|
3036
|
+
`merge()`d server was compiled on its own, so its routes keep _their_ chain. Only
|
|
3037
|
+
what the parent installed **before** the `group()` or `merge()` counts.
|
|
3038
|
+
|
|
3039
|
+
Installed on the parent
|
|
3040
|
+
|
|
3041
|
+
`group()` route
|
|
3042
|
+
|
|
3043
|
+
`merge()`d route
|
|
3044
|
+
|
|
3045
|
+
`derive`, `decorate`, `authenticate`,
|
|
3046
|
+
`beforeHandle`, `afterHandle`, `onError`,
|
|
3047
|
+
`around`, route-scoped assurance
|
|
3048
|
+
|
|
3049
|
+
yes
|
|
3050
|
+
no - wire it on the merged server
|
|
3051
|
+
|
|
3052
|
+
`onRequest`, `onResponse`, `responseHeaders`
|
|
3053
|
+
|
|
3054
|
+
yes
|
|
3055
|
+
yes (app-wide)
|
|
3056
|
+
|
|
3057
|
+
`responseContract()`
|
|
3058
|
+
|
|
3059
|
+
yes
|
|
3060
|
+
yes, when the route declares a response and its own server installed no contract
|
|
3061
|
+
|
|
3062
|
+
`effectLedger()`
|
|
3063
|
+
|
|
3064
|
+
yes
|
|
3065
|
+
yes, when the route declares capabilities and has no ledger of its own
|
|
3066
|
+
|
|
3067
|
+
`idempotency()`
|
|
3068
|
+
|
|
3069
|
+
yes
|
|
3070
|
+
|
|
3071
|
+
the merged server’s own - a route declaring `idempotency` without one is
|
|
3072
|
+
refused at registration
|
|
3073
|
+
|
|
3000
3074
|
### Route/hook plugins: keep types with defineRouterPlugin
|
|
3001
3075
|
|
|
3002
3076
|
A plugin that registers routes or hooks but adds **no context type** - e.g. mounting an auth
|
|
@@ -3285,7 +3359,10 @@ const app = server()
|
|
|
3285
3359
|
`healthcheck()` adds liveness (`/health`) and readiness (`/ready`)
|
|
3286
3360
|
endpoints - apply it **before** any auth guard so they stay public. `openapi()`
|
|
3287
3361
|
serves an OpenAPI 3.1 document at `/openapi.json`, generated from your routes - add
|
|
3288
|
-
`ui: true` for a Scalar API-reference page at `/reference`.
|
|
3362
|
+
`ui: true` for a Scalar API-reference page at `/reference`. The page
|
|
3363
|
+
loads an exact Scalar version from jsDelivr under a Subresource Integrity hash; serve your own
|
|
3364
|
+
copy with `ui: { cdn, integrity }` to keep a third-party origin out of your
|
|
3365
|
+
Content-Security-Policy. Paths,
|
|
3289
3366
|
methods, and params are introspected; `servers`, `tags`,
|
|
3290
3367
|
`security`, and `securitySchemes` are document options, and
|
|
3291
3368
|
`operations` (keyed by `"GET /users/:id"`) supplies per-route bodies/security
|
|
@@ -3330,7 +3407,10 @@ app.use(idempotency({ store: new MemoryIdempotencyStore() }))
|
|
|
3330
3407
|
enforced by default, and claims (`iss`/`aud`/`nbf`) are checked.
|
|
3331
3408
|
Read the typed claims off the returned plugin - `auth.requireClaims(c.req)` (throws
|
|
3332
3409
|
`401`) or `auth.claims(c.req)` (nullable). For rotating keys, pass
|
|
3333
|
-
`key: jwks({ url })` (HTTPS-only, cached, size/time-bounded).
|
|
3410
|
+
`key: jwks({ url })` (HTTPS-only, cached, size/time-bounded). A fetch that fails
|
|
3411
|
+
or returns no keys is remembered for `failureCooldownMs` (default 5 s), so while the
|
|
3412
|
+
identity provider is down a request fails at once instead of waiting on a fetch of its own.
|
|
3413
|
+
`basicAuth`
|
|
3334
3414
|
compares static credentials in **constant time** (or takes a `verify` callback).
|
|
3335
3415
|
|
|
3336
3416
|
```ts
|
|
@@ -3473,7 +3553,7 @@ const PublicUser = t.object({ id: t.string(), name: t.string() })
|
|
|
3473
3553
|
|
|
3474
3554
|
// "warn" logs and changes nothing; "enforce" makes the contract the upper bound too.
|
|
3475
3555
|
// Not installing the plugin is "off" - and keeps the lane out of your bundle entirely.
|
|
3476
|
-
export const app = server().use(responseContract("enforce")).get(
|
|
3556
|
+
export const app = server().use(responseContract("enforce", { extra: "strip" })).get(
|
|
3477
3557
|
"/me",
|
|
3478
3558
|
{ response: PublicUser },
|
|
3479
3559
|
async () => {
|
|
@@ -3483,8 +3563,10 @@ export const app = server().use(responseContract("enforce")).get(
|
|
|
3483
3563
|
},
|
|
3484
3564
|
)
|
|
3485
3565
|
|
|
3486
|
-
// off
|
|
3487
|
-
// enforce
|
|
3566
|
+
// off -> 200 {"id":"u1","name":"Ada","email":"a@b.c","passwordHash":"..."}
|
|
3567
|
+
// enforce -> 500 {"ok":false,"error":"internal_error"}
|
|
3568
|
+
// (t.object is closed; the log names email and passwordHash)
|
|
3569
|
+
// enforce, { extra: "strip" } -> 200 {"id":"u1","name":"Ada"}
|
|
3488
3570
|
```
|
|
3489
3571
|
|
|
3490
3572
|
Not installing the plugin is “off”, which is exactly today’s behaviour and
|
|
@@ -3499,12 +3581,19 @@ returns it early, or `onError` answers with it; only a hand-built
|
|
|
3499
3581
|
should cover: like
|
|
3500
3582
|
`idempotency()`, the decision is made per route at registration.
|
|
3501
3583
|
|
|
3502
|
-
|
|
3503
|
-
`validate` and no way to enumerate declared keys. A _stripping_ schema
|
|
3504
|
-
Valibot) yields a cleaned value, so the extra fields are dropped. A _strict_ one
|
|
3584
|
+
By default, enforcement follows your schema’s own semantics, because Standard Schema
|
|
3585
|
+
exposes `validate` and no way to enumerate declared keys. A _stripping_ schema
|
|
3586
|
+
(Zod, Valibot) yields a cleaned value, so the extra fields are dropped. A _strict_ one
|
|
3505
3587
|
(`@nifrajs/schema`’s `t.object`) reports them as issues, so the
|
|
3506
|
-
response becomes a 500 and the detail goes to the logger, never to the caller.
|
|
3507
|
-
|
|
3588
|
+
response becomes a 500 and the detail goes to the logger, never to the caller.
|
|
3589
|
+
`{ extra: "strip" }` changes that for `t` schemas: they carry their
|
|
3590
|
+
JSON Schema, which does list the declared keys, so the payload is projected onto them - nested
|
|
3591
|
+
objects, arrays and records included - before it is validated. In `"warn"`
|
|
3592
|
+
mode the same option makes the log name the fields `"enforce"` would drop.
|
|
3593
|
+
|
|
3594
|
+
A `merge()`d server’s routes are covered by a contract the parent installed
|
|
3595
|
+
before the merge, as long as the route declares a response and its own server installed none.
|
|
3596
|
+
See [what a parent’s use() covers](/docs/plugins#parent-use).
|
|
3508
3597
|
|
|
3509
3598
|
The check itself is essentially free: with a compiled validator it measures in the
|
|
3510
3599
|
~100ns-per-response range, and a realistic middleware-carrying route benchmarks within noise
|
|
@@ -3727,8 +3816,12 @@ one the bytes proved.
|
|
|
3727
3816
|
|
|
3728
3817
|
-
|
|
3729
3818
|
**A form post is a simple cross-origin request.** A browser sends
|
|
3730
|
-
`multipart/form-data` with cookies and no
|
|
3731
|
-
route
|
|
3819
|
+
`multipart/form-data`, urlencoded and `text/plain` with cookies and no
|
|
3820
|
+
preflight. A body-schema route refuses one whose `Origin` is another site’s
|
|
3821
|
+
with `403` before reading it; list a site that must post forms to the app in the
|
|
3822
|
+
server’s `formOrigins`. A request without an `Origin` passes, so
|
|
3823
|
+
a cookie-authenticated upload route still needs `csrf()` like any other state
|
|
3824
|
+
change.
|
|
3732
3825
|
|
|
3733
3826
|
-
|
|
3734
3827
|
**The form is held in memory.** Budget roughly twice `bodyLimit` per request in
|
|
@@ -3909,7 +4002,12 @@ accept either during a key rotation.
|
|
|
3909
4002
|
|
|
3910
4003
|
A dropped connection or an impatient double-tap shouldn't double-charge a card. With an
|
|
3911
4004
|
`Idempotency-Key` header, a retried unsafe request replays the first response instead of
|
|
3912
|
-
re-running the side effect.
|
|
4005
|
+
re-running the side effect. The key is claimed in `onRequest`, so a concurrent retry gets
|
|
4006
|
+
a `409`; the stored response is replayed from `beforeHandle`, _after_ the
|
|
4007
|
+
route's authentication accepts the retry, so a credential revoked since the first request gets the
|
|
4008
|
+
route's current answer. Declare routes after `.use(idempotency())`:
|
|
4009
|
+
`beforeHandle` is order-scoped, and a route declared earlier replays from
|
|
4010
|
+
`onRequest`.
|
|
3913
4011
|
|
|
3914
4012
|
```ts
|
|
3915
4013
|
// doc-check: skip - fragment: `app`, `chargeCard`, and `id` are your application's.
|
|
@@ -4659,6 +4757,15 @@ a `SessionStore`; in **cookie mode** (no store) the data is signed into the cook
|
|
|
4659
4757
|
Stores mirror the ISR discipline: `MemorySessionStore` is prod-guarded;
|
|
4660
4758
|
`KVSessionStore` is the durable, shared production store.
|
|
4661
4759
|
|
|
4760
|
+
The signature covers the cookie name, so two managers that share a secret never read each
|
|
4761
|
+
other's cookies; still, give sessions a secret no other signed value uses. A cookie-mode
|
|
4762
|
+
session lives at most `maxAge`, whatever expiry its payload names. Upgrading from
|
|
4763
|
+
4.x, whose cookies were signed without the name, signs everyone out unless you pass
|
|
4764
|
+
`acceptLegacyCookies: true`: keep it for one `maxAge` after the upgrade
|
|
4765
|
+
(each such session is re-signed on its next commit), then remove it, since while it is on any
|
|
4766
|
+
session-shaped value the app signs with the same secret through `signValue` reads
|
|
4767
|
+
as a session.
|
|
4768
|
+
|
|
4662
4769
|
```ts
|
|
4663
4770
|
// backend/auth.ts - one session manager, created on first use so the secret is read at request time.
|
|
4664
4771
|
// Store mode keeps data server-side; cookie mode (no store) is stateless.
|
|
@@ -5770,7 +5877,9 @@ bridge an external fan-out (Redis pub/sub, NATS, a queue) to broadcast across al
|
|
|
5770
5877
|
**Cloudflare Workers**, a stateless isolate can’t broadcast across connections,
|
|
5771
5878
|
so Nifra ships a Durable Object hub: `createWebSocketHub(app)` holds the
|
|
5772
5879
|
connections, and `toFetchHandler(app, { webSocketHub })` routes upgrades to it
|
|
5773
|
-
- then `ws.subscribe` / `app.publish` behave exactly as on Bun.
|
|
5880
|
+
- then `ws.subscribe` / `app.publish` behave exactly as on Bun. An
|
|
5881
|
+
upgrade request for a path with no WebSocket route still gets that path's HTTP answer, as on
|
|
5882
|
+
every other runtime.
|
|
5774
5883
|
|
|
5775
5884
|
```ts
|
|
5776
5885
|
// doc-check: skip - Workers entry: a Durable Object hub holds the connections.
|
|
@@ -5823,6 +5932,14 @@ it). Install it when you use `app.ws()`; without it a WS upgrade gets a clean
|
|
|
5823
5932
|
npm i ws
|
|
5824
5933
|
```
|
|
5825
5934
|
|
|
5935
|
+
`server({ wsMaxPayloadBytes })` caps one inbound message (default
|
|
5936
|
+
`maxBodyBytes`, 1 MB): a socket that sends more is closed with `1009`
|
|
5937
|
+
and the message never reaches your handler. Bun and Node refuse it while it arrives. Deno's
|
|
5938
|
+
`Deno.upgradeWebSocket` takes no size limit, so Deno receives each message whole
|
|
5939
|
+
(up to its own limit, 64 MiB on Deno 2.9) before nifra can check it: the cap still keeps the
|
|
5940
|
+
message from your handler, but it does not bound the memory Deno spent receiving it. Where that
|
|
5941
|
+
matters, cap message size in a proxy in front of a Deno app.
|
|
5942
|
+
|
|
5826
5943
|
### In a composed app
|
|
5827
5944
|
|
|
5828
5945
|
`mount({ path, app })` carries WebSocket upgrades as well as HTTP: when the
|
|
@@ -5834,6 +5951,11 @@ implement it too, building the outcome from `@nifrajs/core/ws`:
|
|
|
5834
5951
|
owns its pub/sub. On Bun, install `websocket()` on the parent or on a mounted nifra
|
|
5835
5952
|
child, or `listen()` refuses to start with `INVALID_WS_RUNTIME`.
|
|
5836
5953
|
|
|
5954
|
+
Each mounted nifra app keeps its own `wsMaxPayloadBytes`: a message over the
|
|
5955
|
+
child's cap closes that socket with `1009`, whether the cap is below or above the
|
|
5956
|
+
parent's. On Bun one listener serves them all, so its frame limit is the largest cap among the
|
|
5957
|
+
parent and the apps mounted on it, and a socket whose app declares less checks its own.
|
|
5958
|
+
|
|
5837
5959
|
`mountFetch(path, handler)` and a plain fetch handler carry HTTP only. An upgrade
|
|
5838
5960
|
request under such a path reaches the handler as an ordinary request and never becomes a
|
|
5839
5961
|
socket. Serve that path's WebSockets from a mounted child, or keep that server beside nifra.
|
|
@@ -6281,10 +6403,13 @@ when the rollback is intended); a target newer than the running CLI prints the c
|
|
|
6281
6403
|
that release's CLI. It edits files under the workspace root only: a symlinked package
|
|
6282
6404
|
directory or `package.json` is never followed, and a group package installed by a
|
|
6283
6405
|
link from outside the root is listed under "Left alone" for you to upgrade in its
|
|
6284
|
-
own repository.
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6406
|
+
own repository. The MCP launch pin in `.mcp.json`, `.cursor/mcp.json`,
|
|
6407
|
+
`CLAUDE.md` and `AGENTS.md` moves to the target, the edit
|
|
6408
|
+
`nifra init-agents --sync-mcp` makes. Another version pinned outside
|
|
6409
|
+
`package.json` is listed with its line: the rest of an agent file, an MCP config
|
|
6410
|
+
elsewhere, a Dockerfile or compose file, a CI workflow, and a lockfile other than the
|
|
6411
|
+
workspace's own (an image build's frozen lockfile, say), which you regenerate after
|
|
6412
|
+
installing. With `--write` it also
|
|
6288
6413
|
prints how hook scope changed across the
|
|
6289
6414
|
upgrade (`--no-hooks` skips that). `nifra doctor` and
|
|
6290
6415
|
`nifra check` (NF-D002) point here when a workspace carries more than one version;
|
|
@@ -6869,7 +6994,10 @@ emit `approval.required` with an opaque approval id, action, capability, and bou
|
|
|
6869
6994
|
coordinates. Resolve it through the host or RPC with `approval.resolve`; the backend
|
|
6870
6995
|
emits `approval.resolved` and only then executes the tool. Denial, cancellation,
|
|
6871
6996
|
timeout, and closed sessions all fail closed, and `approvalTimeoutMs` bounds how long
|
|
6872
|
-
a pending decision can remain open
|
|
6997
|
+
a pending decision can remain open: 5 minutes by default, at most 24 hours, or
|
|
6998
|
+
`"never"` to wait until it is answered, cancelled, its turn ends, or the session
|
|
6999
|
+
closes. The host's broker takes the same values as `approvals.timeoutMs` on
|
|
7000
|
+
`CodingAgentHost` and `CodingAgentRpcServer`.
|
|
6873
7001
|
|
|
6874
7002
|
### Expose the same agent to other clients
|
|
6875
7003
|
|
|
@@ -6967,12 +7095,13 @@ fail-open OpenTelemetry run and step spans. Providers, credentials, durable stor
|
|
|
6967
7095
|
and tenant policy remain application-owned ports.
|
|
6968
7096
|
|
|
6969
7097
|
A step that suspends for approval resumes with the decision the caller sends in
|
|
6970
|
-
`resume.approval`.
|
|
6971
|
-
|
|
7098
|
+
`resume.approval`. On an AG-UI or `mountAgent` route that anyone can
|
|
7099
|
+
reach, that caller may be the party asking for the tool. Return
|
|
6972
7100
|
`resumeApproval: "port"` from `ports` to keep the configured approval
|
|
6973
7101
|
port authoritative: it is asked again on resume, receives the caller's decision as
|
|
6974
7102
|
`callerDecision`, and its verdict stands. Without a port, such a resume suspends
|
|
6975
|
-
again.
|
|
7103
|
+
again. A2A does this by default, since the resuming peer is the agent that asked for the
|
|
7104
|
+
tool; return `resumeApproval: "caller"` there only when the peer is the approver.
|
|
6976
7105
|
|
|
6977
7106
|
### Where your code and secrets run
|
|
6978
7107
|
|
|
@@ -7000,9 +7129,11 @@ values (`nifra mcp --env-file .env.secrets`), reach all of them.
|
|
|
7000
7129
|
-
|
|
7001
7130
|
**No `.env` in the server.** When Bun loaded `.env`
|
|
7002
7131
|
values into the server at startup, the server hands the session to a copy of itself that
|
|
7003
|
-
loads none, keeping the values from the environment and `--env-file`.
|
|
7004
|
-
|
|
7005
|
-
|
|
7132
|
+
loads none, keeping the values from the environment and `--env-file`. A project
|
|
7133
|
+
that installs another release of `@nifrajs/cli` gets the session handed to that
|
|
7134
|
+
CLI the same way, with no `.env` loaded. The process the client started stays to
|
|
7135
|
+
forward signals and the exit code: it still holds the values Bun loaded, but runs no project
|
|
7136
|
+
code and reads no messages.
|
|
7006
7137
|
|
|
7007
7138
|
-
|
|
7008
7139
|
**A process per call has a cost.** A call that loads the app pays one process
|
|
@@ -8091,6 +8222,13 @@ written down: `nifra fix --code NF-C035` adds
|
|
|
8091
8222
|
`export const apiPrefix = "/api"`, which is what 4.x mounted by default, and
|
|
8092
8223
|
`""` keeps the backend loader-only.
|
|
8093
8224
|
|
|
8225
|
+
With both files, `nifra dev` and `nifra build` take
|
|
8226
|
+
`apiPrefix`, `apiStrip`, `mounts`, `csp`,
|
|
8227
|
+
`nonce`, `serverComponents` and `use` from
|
|
8228
|
+
`backend/framework.ts` when `nifra.config.ts` does not set them, so the
|
|
8229
|
+
server entry and the dev server read one value without a re-export. A hand-written
|
|
8230
|
+
`createWebApp` call passes `apiPrefix` itself.
|
|
8231
|
+
|
|
8094
8232
|
Because the backend answers first and its 404 is final, a page file under the prefix (
|
|
8095
8233
|
`routes/api/report.tsx`) could never render. Nifra refuses it instead of serving a
|
|
8096
8234
|
silent 404: `createWebApp` throws at startup naming the file, `nifra build`
|
|
@@ -8807,7 +8945,9 @@ pass through, and every `<link>` attribute with a normal name -
|
|
|
8807
8945
|
|
|
8808
8946
|
A route's `meta` emits the full social / structured-data head with three public
|
|
8809
8947
|
helpers - `canonical()`, `openGraph()`, and `jsonLd()` - and
|
|
8810
|
-
builds **absolute** URLs from the `origin` argument.
|
|
8948
|
+
builds **absolute** URLs from the `origin` argument. Import them from
|
|
8949
|
+
`@nifrajs/web/seo`: the entry imports nothing at runtime, so a page's browser bundle
|
|
8950
|
+
gets the three helpers and none of the server modules the package root also exports. Because
|
|
8811
8951
|
`meta()` runs in **both** SSR and client navigation it has
|
|
8812
8952
|
**no server env**: never read `process.env` or the request inside it.
|
|
8813
8953
|
The framework injects `origin` (the site's scheme + host, e.g.
|
|
@@ -8819,9 +8959,11 @@ base, a CDN host) belongs in the `loader`, not `meta()`.
|
|
|
8819
8959
|
|
|
8820
8960
|
```ts
|
|
8821
8961
|
// routes/articles/[slug].tsx - a complete SEO head: canonical + Open Graph + Twitter + JSON-LD,
|
|
8822
|
-
// with ABSOLUTE URLs built from `origin`. The three helpers (canonical/openGraph/jsonLd)
|
|
8823
|
-
//
|
|
8824
|
-
|
|
8962
|
+
// with ABSOLUTE URLs built from `origin`. The three helpers (canonical/openGraph/jsonLd) come from
|
|
8963
|
+
// @nifrajs/web/seo, which imports nothing at runtime, so the page's browser bundle takes only them;
|
|
8964
|
+
// `origin` is a MetaArgs field beside data, pageData and params.
|
|
8965
|
+
import type { MetaArgs } from "@nifrajs/web"
|
|
8966
|
+
import { canonical, jsonLd, openGraph } from "@nifrajs/web/seo"
|
|
8825
8967
|
|
|
8826
8968
|
// CAVEAT: meta() runs in BOTH SSR and client navigation, so it has NO server env - never read
|
|
8827
8969
|
// `process.env` or the request here. The framework injects `origin` (the site's scheme+host, e.g.
|
|
@@ -9916,7 +10058,8 @@ Schema that describes exactly the fields the page needs. `nifra check` flags rou
|
|
|
9916
10058
|
without one (NF-C030): an error when the loader's own body returns a literal (an object,
|
|
9917
10059
|
array, string, number or boolean), since every request that reaches that return fails, and a
|
|
9918
10060
|
warning when only running it shows what it returns. `nifra schemas --write` drafts
|
|
9919
|
-
a schema from the loader's return type for review
|
|
10061
|
+
a schema from the loader's return type for review, and
|
|
10062
|
+
`nifra fix --code NF-C030` writes that draft for each flagged route.
|
|
9920
10063
|
|
|
9921
10064
|
### Rendering and data
|
|
9922
10065
|
|
|
@@ -9995,6 +10138,10 @@ as information, with the comment and its reason as evidence. Some codes also ans
|
|
|
9995
10138
|
`@nifra-gate-reviewed` silences nothing; a finding under it names the comment to
|
|
9996
10139
|
write instead.
|
|
9997
10140
|
|
|
10141
|
+
A fail-open gate (NF-S001) or a non-constant-time comparison (NF-S002) in code that only
|
|
10142
|
+
ever runs in a browser is a warning rather than an error: the server's own gate decides
|
|
10143
|
+
there.
|
|
10144
|
+
|
|
9998
10145
|
## Nifra - Failure laboratory
|
|
9999
10146
|
|
|
10000
10147
|
> Replayable durable-failure schedules on virtual time: crash after commit, duplicate delivery, reordering, budget expiry, and checkpoint contention.
|
|
@@ -10514,6 +10661,146 @@ If the project has `nifra.assurance.ts`, run `nifra assure --json`.
|
|
|
10514
10661
|
Exercise every redirect path - loader, action, and layout gate - and, if the app proxies,
|
|
10515
10662
|
each deploy adapter it uses.
|
|
10516
10663
|
|
|
10664
|
+
## Nifra 5.0 migration guide - upgrade from 3.x or 4.x
|
|
10665
|
+
|
|
10666
|
+
> Upgrade a Nifra 3.x or 4.x application to 5.0: the chained upgrade command, the frontend/backend layout move and its follow-ups, drafted output schemas, the backend's HTTP mount, the 5.0 defaults that changed, and the release gates.
|
|
10667
|
+
|
|
10668
|
+
Nifra 4.0 split every app into a frontend and a backend half, and 5.0 enforces the split and
|
|
10669
|
+
changes a handful of defaults. The upgrade command pins the packages and moves imports; the
|
|
10670
|
+
layout migration moves files; this guide covers what each leaves to you and how to tell a
|
|
10671
|
+
finished migration from one that needs a decision.
|
|
10672
|
+
|
|
10673
|
+
### 1. Run the executable upgrade
|
|
10674
|
+
|
|
10675
|
+
```ts
|
|
10676
|
+
|
|
10677
|
+
```
|
|
10678
|
+
|
|
10679
|
+
Run the command from the release you are moving to. It chains every release recipe between
|
|
10680
|
+
the installed version and 5.0, so a 3.x app takes the 4.0 steps (the retired
|
|
10681
|
+
`@nifrajs/web/server-only` import moves to `@nifrajs/web/backend-only`)
|
|
10682
|
+
and the 5.0 ones in one pass, and prints each release's notes. It lists every
|
|
10683
|
+
`@nifra-gate-reviewed` comment, which silences nothing in 5.0: after review, write
|
|
10684
|
+
`// nifra-expect : ` with the code `nifra check`
|
|
10685
|
+
reports there. The upgrade never writes a reason for you.
|
|
10686
|
+
|
|
10687
|
+
### 2. Move onto the frontend/backend layout (from 3.x)
|
|
10688
|
+
|
|
10689
|
+
```ts
|
|
10690
|
+
|
|
10691
|
+
```
|
|
10692
|
+
|
|
10693
|
+
Each route file splits into `x.tsx`, the page, and `x.backend.ts`, which
|
|
10694
|
+
holds `loader`, `action`, `middleware` and the other server
|
|
10695
|
+
exports. The root `backend.ts` and `framework.ts` move to
|
|
10696
|
+
`backend/app.ts` and `backend/framework.ts`, and every other module goes
|
|
10697
|
+
to `frontend/`, `backend/` or `shared/` by who imports it at
|
|
10698
|
+
runtime. A folder whose imported files all land in one zone moves whole, so a component nothing
|
|
10699
|
+
imports yet travels with its folder; a folder split between zones is reported instead.
|
|
10700
|
+
|
|
10701
|
+
```ts
|
|
10702
|
+
|
|
10703
|
+
```
|
|
10704
|
+
|
|
10705
|
+
To keep a folder where it is, declare it a zone before migrating. The migration leaves zoned
|
|
10706
|
+
folders in place, and builds, `nifra dev` and `nifra check` enforce them
|
|
10707
|
+
like the default folders.
|
|
10708
|
+
|
|
10709
|
+
```ts
|
|
10710
|
+
|
|
10711
|
+
```
|
|
10712
|
+
|
|
10713
|
+
`nifra migrate layout --zones` writes those entries for you: every module the
|
|
10714
|
+
layout would move stays where it is, and `package.json` lists the widest folder
|
|
10715
|
+
whose files all belong to one side, or the file itself where its folder holds both. Route
|
|
10716
|
+
files are still split and the root entries still move. A path nested in another's folder
|
|
10717
|
+
overrides it, so a backend file can sit in a frontend folder without moving.
|
|
10718
|
+
|
|
10719
|
+
The command exits `0` when nothing needs a decision. A step with a known command,
|
|
10720
|
+
such as drafting an output schema for a backend half it did not write, is listed under
|
|
10721
|
+
`next` and in `followUps` with `--json`, and does not fail it.
|
|
10722
|
+
An issue (an import it could not place, a frontend that still uses a moved name at runtime)
|
|
10723
|
+
exits `1`.
|
|
10724
|
+
|
|
10725
|
+
5.0 refuses a route file that still exports a server name: `nifra build` and the
|
|
10726
|
+
server stop on it, and `nifra check` reports it as NF-C041.
|
|
10727
|
+
`nifra fix --code NF-C041` moves the export and the code only it uses into the
|
|
10728
|
+
route's backend half.
|
|
10729
|
+
|
|
10730
|
+
### 3. Draft and review output schemas
|
|
10731
|
+
|
|
10732
|
+
A loader or action that returns data needs `loaderOutput` or
|
|
10733
|
+
`actionOutput`; the data is projected through it, so undeclared keys never reach
|
|
10734
|
+
the page. `nifra schemas --write` drafts each missing one from the function's return
|
|
10735
|
+
type, leaves out credential-like fields and marks it `nifra:generated` so later runs
|
|
10736
|
+
keep it current. A value typed `any` or `unknown` drafts as
|
|
10737
|
+
`t.json()`, which admits anything: `nifra schemas` lists those paths and
|
|
10738
|
+
`nifra check` warns on them (NF-C030). Give the value a type and draft again.
|
|
10739
|
+
`nifra schemas --check` fails on a missing, stale or open schema, for CI.
|
|
10740
|
+
|
|
10741
|
+
### 4. Choose where the backend is served
|
|
10742
|
+
|
|
10743
|
+
3.x and 4.x served `backend/app.ts` at `/api` by default. In 5.0
|
|
10744
|
+
`createWebApp` serves it over HTTP only at an `apiPrefix` the app sets;
|
|
10745
|
+
without one the backend is loader-only, reached in-process through `ctx.api`, and a
|
|
10746
|
+
browser call to `/api` reaches page routing. `nifra migrate layout` adds
|
|
10747
|
+
`apiPrefix = "/api"` when it moves a root `backend.ts`, and
|
|
10748
|
+
`nifra check` reports a framework config that sets none (NF-C035).
|
|
10749
|
+
|
|
10750
|
+
```ts
|
|
10751
|
+
|
|
10752
|
+
```
|
|
10753
|
+
|
|
10754
|
+
With both `nifra.config.ts` and `backend/framework.ts`, every command
|
|
10755
|
+
takes `apiPrefix`, `apiStrip`, `mounts`, `csp`,
|
|
10756
|
+
`nonce`, `serverComponents` and `use` from
|
|
10757
|
+
`backend/framework.ts` when `nifra.config.ts` leaves them unset. The
|
|
10758
|
+
backend sees each request's full path unless `apiStrip` is on, so its routes are
|
|
10759
|
+
registered under the prefix; `nifra routes` marks one outside it as in-process
|
|
10760
|
+
only, and `nifra dev` and `nifra build` warn about it.
|
|
10761
|
+
|
|
10762
|
+
### 5. Review the 5.0 defaults that changed
|
|
10763
|
+
|
|
10764
|
+
-
|
|
10765
|
+
Root status pages (`_404.tsx`, `_<status>.tsx`) and
|
|
10766
|
+
`_error.tsx` render inside the layouts above them. One that imports the root
|
|
10767
|
+
layout to wrap itself renders it twice (NF-C034); remove the wrap, or export
|
|
10768
|
+
`inLayouts = false`.
|
|
10769
|
+
|
|
10770
|
+
-
|
|
10771
|
+
A layout's `meta` receives its own loader data as `data` and the page's
|
|
10772
|
+
as `pageData` (NF-C040).
|
|
10773
|
+
|
|
10774
|
+
-
|
|
10775
|
+
A WebSocket handshake runs the route chain an HTTP `GET` at the same point runs, so
|
|
10776
|
+
guards added before `app.ws()` apply to it.
|
|
10777
|
+
|
|
10778
|
+
-
|
|
10779
|
+
A `Response` returned to more than one request is no longer shared; build one per
|
|
10780
|
+
request.
|
|
10781
|
+
|
|
10782
|
+
-
|
|
10783
|
+
`nifra check` fails a secret comparison (NF-S002) outside browser code of a web
|
|
10784
|
+
app.
|
|
10785
|
+
|
|
10786
|
+
`nifra upgrade` prints the full list with the finding or the one-line change that
|
|
10787
|
+
keeps the 4.x behavior for each.
|
|
10788
|
+
|
|
10789
|
+
### 6. Run the release gates
|
|
10790
|
+
|
|
10791
|
+
-
|
|
10792
|
+
Run `nifra check --json` and fix every error. `nifra doctor` lists any
|
|
10793
|
+
package still on another release.
|
|
10794
|
+
|
|
10795
|
+
-
|
|
10796
|
+
If the project has `nifra.assurance.ts`, run `nifra assure --json`.
|
|
10797
|
+
|
|
10798
|
+
- Run the application test suite and a production build.
|
|
10799
|
+
|
|
10800
|
+
-
|
|
10801
|
+
Exercise the pages that load or post data, and every browser call to the backend, under
|
|
10802
|
+
`nifra dev` and against the production build.
|
|
10803
|
+
|
|
10517
10804
|
## Nifra - Migrating from Express, Hono, Fastify & Elysia
|
|
10518
10805
|
|
|
10519
10806
|
> Move a backend to Nifra: routing, middleware, validation, and body parsing map directly from Express, Hono, Fastify, and Elysia - and you gain a typed client, multi-runtime deploy, and optional SSR.
|
|
@@ -11434,6 +11721,34 @@ in its `package.json`:
|
|
|
11434
11721
|
`{'"nifra": { "environment": "frontend" | "backend" | "shared" | "library" }'}`.
|
|
11435
11722
|
A file in no zone is a build error, so nothing is ever classified by accident.
|
|
11436
11723
|
|
|
11724
|
+
A package whose entries run on different sides gives each export subpath its own:
|
|
11725
|
+
|
|
11726
|
+
```ts
|
|
11727
|
+
{
|
|
11728
|
+
"name": "@shop/payments",
|
|
11729
|
+
"exports": {
|
|
11730
|
+
".": "./src/index.ts",
|
|
11731
|
+
"./react": "./src/react.tsx",
|
|
11732
|
+
"./schema": "./src/schema.ts"
|
|
11733
|
+
},
|
|
11734
|
+
"nifra": {
|
|
11735
|
+
"environment": {
|
|
11736
|
+
".": "backend",
|
|
11737
|
+
"./react": "frontend",
|
|
11738
|
+
"./schema": "library"
|
|
11739
|
+
}
|
|
11740
|
+
}
|
|
11741
|
+
}
|
|
11742
|
+
```
|
|
11743
|
+
|
|
11744
|
+
An import is judged by the entry it names: the exact subpath first, then the most specific
|
|
11745
|
+
`*` pattern. Here a page may import `@shop/payments/react` but not
|
|
11746
|
+
`@shop/payments`, and backend code may not import the React entry, even when two
|
|
11747
|
+
entries are backed by one file. Importing an entry the map leaves out is an error. A file
|
|
11748
|
+
reached by path rather than by entry, through a relative or aliased deep import, takes the
|
|
11749
|
+
side of every mapped entry whose own imports reach it, and a file no mapped entry reaches is
|
|
11750
|
+
an error.
|
|
11751
|
+
|
|
11437
11752
|
The app's own `package.json` can set sides too, so a folder that has to stay
|
|
11438
11753
|
where it is, or a family of workspace packages, needs no edit of its own:
|
|
11439
11754
|
|
|
@@ -11443,7 +11758,8 @@ where it is, or a family of workspace packages, needs no edit of its own:
|
|
|
11443
11758
|
"nifra": {
|
|
11444
11759
|
"zones": {
|
|
11445
11760
|
"packages": { "@shop/*": "library", "@shop/db": "backend" },
|
|
11446
|
-
"backend": ["migrations"]
|
|
11761
|
+
"backend": ["migrations", "src/ui/mailer.ts"],
|
|
11762
|
+
"frontend": ["src/ui"]
|
|
11447
11763
|
}
|
|
11448
11764
|
}
|
|
11449
11765
|
}
|
|
@@ -11451,9 +11767,11 @@ where it is, or a family of workspace packages, needs no edit of its own:
|
|
|
11451
11767
|
|
|
11452
11768
|
`packages` gives a side to a package that does not declare one, by exact name or
|
|
11453
11769
|
by a prefix ending in `*`; a package's own declaration always wins.
|
|
11454
|
-
`backend`, `frontend` and `shared` list app folders
|
|
11455
|
-
count as that zone
|
|
11456
|
-
|
|
11770
|
+
`backend`, `frontend` and `shared` list app folders, or
|
|
11771
|
+
single files, that count as that zone. A path inside another's folder overrides it, so the
|
|
11772
|
+
most specific entry decides: above, `src/ui/mailer.ts` is backend code in a
|
|
11773
|
+
frontend folder. One path listed under two sides is refused. Builds, dev servers,
|
|
11774
|
+
`nifra check` and the editor plugin all read this setting.
|
|
11457
11775
|
|
|
11458
11776
|
A project that serves no pages has no browser, so the zones do not apply to it. Declare that
|
|
11459
11777
|
in its `package.json` with `{'"nifra": { "kind": "api" }'}`:
|
|
@@ -11569,24 +11887,37 @@ import fails the build with the chain that led to it:
|
|
|
11569
11887
|
-
|
|
11570
11888
|
**Browser code reads only public environment variables** - `NODE_ENV` and
|
|
11571
11889
|
names with the `PUBLIC_` prefix. Any other `process.env` read in a
|
|
11572
|
-
page, `frontend/` or `shared/` fails the build
|
|
11890
|
+
page, `frontend/` or `shared/` fails the build, optional access (
|
|
11891
|
+
`process.env?.["SECRET"]`) included.
|
|
11573
11892
|
|
|
11574
11893
|
-
|
|
11575
11894
|
**The build scans what it emits.** A client bundle, a public file or a prerendered page
|
|
11576
|
-
that contains what looks like a credential fails the build.
|
|
11895
|
+
that contains what looks like a credential fails the build. A label in a message catalog (
|
|
11896
|
+
`{'{ password: "Password" }'}`) and a documented placeholder (
|
|
11897
|
+
`your-api-key`) are text, not credentials.
|
|
11577
11898
|
|
|
11578
11899
|
The same rules run in `nifra dev` (a refused module is answered with a 403 before
|
|
11579
11900
|
its source is sent), in both bundlers, for every framework, and in `nifra check`,
|
|
11580
11901
|
which follows the imports the bundler follows: relative paths, tsconfig `paths`
|
|
11581
11902
|
and `baseUrl`, `package.json` `imports`, and the
|
|
11582
|
-
`clientModule` the browser entry loads. An app on the older layout moves with
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
`
|
|
11589
|
-
|
|
11903
|
+
`clientModule` the browser entry loads. An app on the older layout moves with
|
|
11904
|
+
`nifra migrate layout`: a dry run that reports every move, then
|
|
11905
|
+
`--write`. It follows the same imports, rewrites them and test-runner mocks (an
|
|
11906
|
+
alias through the same alias), and moves the config's `clientModule`, any module
|
|
11907
|
+
path the config builds from its own folder, and component pipeline entries with their
|
|
11908
|
+
modules. A test moves with the file beside it, snapshots included. Each
|
|
11909
|
+
`tsconfig*.json` keeps every file in, or out of, its program as before. It adds
|
|
11910
|
+
`.nifra/` to `.gitignore` and leaves data files and folders zoned in
|
|
11911
|
+
`package.json` where they are.
|
|
11912
|
+
|
|
11913
|
+
A route file that holds server code splits into the page and its
|
|
11914
|
+
`x.backend.ts`. Data both halves read moves to `x.shared.ts` beside
|
|
11915
|
+
them; a value that cannot move is copied into each half and reported. A loader or action
|
|
11916
|
+
that returns data without an output schema gets a draft one, typed from what it returns:
|
|
11917
|
+
review that the browser may see every field it declares. The migration reports what still
|
|
11918
|
+
needs a hand, such as an alias with no target that covers a moved file, a specifier that
|
|
11919
|
+
names nothing installed, or a sibling workspace package that names a moved file. It never
|
|
11920
|
+
edits files outside the app.
|
|
11590
11921
|
|
|
11591
11922
|
An API-only app, one that declares `{'"nifra": { "kind": "api" }'}` or has no web
|
|
11592
11923
|
config, no `routes/` and a `backend.ts` that exports
|
|
@@ -12132,6 +12463,43 @@ export default defineAssuranceConfig({
|
|
|
12132
12463
|
})
|
|
12133
12464
|
```
|
|
12134
12465
|
|
|
12466
|
+
### Response contracts
|
|
12467
|
+
|
|
12468
|
+
Next to the ladder, `nifra levels` counts the routes that declare a
|
|
12469
|
+
`response` or `errors` schema and how each is held at runtime:
|
|
12470
|
+
_enforced_, _warn-only_ (checked, original payload still sent) or _typed-only_
|
|
12471
|
+
(no `responseContract()` covers it). A typed-only route is usually registered on a
|
|
12472
|
+
server other than the one the plugin is installed on, or before it; the report names the routes
|
|
12473
|
+
and says which.
|
|
12474
|
+
|
|
12475
|
+
The count does not fail a level on its own. To make L1 require enforcement, add a
|
|
12476
|
+
`baseline` rule selecting `hasResponse: true`: unlike
|
|
12477
|
+
`rules`, where the first match owns a route, a baseline rule is checked on every
|
|
12478
|
+
route it matches, so one entry covers every class. `nifra assure --strict` also fails
|
|
12479
|
+
while any declared route is typed-only or warn-only.
|
|
12480
|
+
|
|
12481
|
+
```ts
|
|
12482
|
+
// nifra.assurance.ts
|
|
12483
|
+
// doc-check: skip - the backend is app-specific
|
|
12484
|
+
import { defineAssuranceConfig, NIFRA_ASSURANCE } from "@nifrajs/core/assurance"
|
|
12485
|
+
import { backend } from "./backend"
|
|
12486
|
+
|
|
12487
|
+
export default defineAssuranceConfig({
|
|
12488
|
+
source: backend,
|
|
12489
|
+
policy: {
|
|
12490
|
+
rules: [/* first match owns each route: classify by path, method, capability ... */],
|
|
12491
|
+
// Checked on every route it matches, whichever rule owns the route.
|
|
12492
|
+
baseline: [
|
|
12493
|
+
{
|
|
12494
|
+
name: "response-contract",
|
|
12495
|
+
match: { hasResponse: true },
|
|
12496
|
+
require: [NIFRA_ASSURANCE.RESPONSE_CONTRACT],
|
|
12497
|
+
},
|
|
12498
|
+
],
|
|
12499
|
+
},
|
|
12500
|
+
})
|
|
12501
|
+
```
|
|
12502
|
+
|
|
12135
12503
|
### For coding agents
|
|
12136
12504
|
|
|
12137
12505
|
The `nifra_levels` MCP tool returns the same
|
|
@@ -12303,9 +12671,11 @@ A suspended task's status message carries the pending continuation in `metadata`
|
|
|
12303
12671
|
}
|
|
12304
12672
|
```
|
|
12305
12673
|
|
|
12674
|
+
The resuming peer is usually the agent that asked for the tool, so it does not approve its own call: the run asks `ports.approval` again and hands it the peer's `approval` as `callerDecision`. With no approval port the task stays `TASK_STATE_INPUT_REQUIRED`. Return `resumeApproval: "caller"` from `ports` only when the peer is the approver, such as a human operator's client.
|
|
12675
|
+
|
|
12306
12676
|
Cross-request registries (cancellation, subscription fan-out, push notifications) are deliberately out of scope for the stateless seam; those spec methods answer `UnsupportedOperationError` (-32004).
|
|
12307
12677
|
|
|
12308
|
-
A reply larger than `maxOutputBytes` answers the request with a JSON-RPC internal error (-32603, `output_limit`), the same error a stream sends when it runs out of budget. A request whose ports or store fail answers with -32603 `internal_error`, keeping the request's `id`.
|
|
12678
|
+
A reply larger than `maxOutputBytes` answers the request with a JSON-RPC internal error (-32603, `output_limit`), the same error a stream sends when it runs out of budget. A stream that runs out also aborts the run's signal, as a client disconnect does, so the run stops calling the model. A request whose ports or store fail answers with -32603 `internal_error`, keeping the request's `id`.
|
|
12309
12679
|
|
|
12310
12680
|
The seam performs no authentication or authorization - wrap it with your app's route guards and scope every port in `ports(c)` to the caller.
|
|
12311
12681
|
|
|
@@ -12509,7 +12879,8 @@ adapter implementing the same `AgentEvidenceLog` interface.
|
|
|
12509
12879
|
When more than one caller shares the route, also pass `evidenceOwner: (c) => <the caller's user or
|
|
12510
12880
|
tenant id>`: turns are recorded and replayed under that owner, so another caller's reconnect or
|
|
12511
12881
|
reused `runId` finds none of them. Without it a turn id (by default the client's `runId`) works as a
|
|
12512
|
-
bearer capability. The owner function runs before any replay; throwing from it refuses the request
|
|
12882
|
+
bearer capability. The owner function runs before any replay; throwing from it refuses the request with `403`, and a
|
|
12883
|
+
thrown `Response` answers the request as built, as one thrown from `ports` does.
|
|
12513
12884
|
|
|
12514
12885
|
The seam performs no authentication or authorization - wrap it with your app's route guards and scope every port in `ports(c)` to the caller.
|
|
12515
12886
|
|
|
@@ -12603,7 +12974,9 @@ on from where the response stopped; without one the run is cancelled.
|
|
|
12603
12974
|
When more than one caller shares the route, also pass `evidenceOwner: (c) => <the caller's user or
|
|
12604
12975
|
tenant id>`: turns are recorded and replayed under that owner, so another caller's reconnect or
|
|
12605
12976
|
reused `turnId` finds none of them. Without it a turn id works as a bearer capability. The owner
|
|
12606
|
-
function runs before any replay; throwing from it refuses the request
|
|
12977
|
+
function runs before any replay; throwing from it refuses the request with `403`, and a thrown
|
|
12978
|
+
`Response` answers the request as built, as one thrown from `ports` does. A JSON-mode run that
|
|
12979
|
+
throws answers `500 run_failed`, or `409 resume_unavailable` when the POST resumed a turn.
|
|
12607
12980
|
|
|
12608
12981
|
Execution policies can be required by a tool contract. `createLocalProcessAdapter` applies cwd and
|
|
12609
12982
|
environment filtering, timeouts, and cancellation to child processes. On POSIX each run leads its
|
|
@@ -12975,6 +13348,7 @@ How it holds the line:
|
|
|
12975
13348
|
|
|
12976
13349
|
- **Post-decode body limits.** The body is decoded (base64 or UTF-8) and its real `byteLength` checked against `maxBodyBytes` (default 1,000,000 - match your app's setting if you changed it) *before* a `Request` is constructed. The event's own length claims are never trusted; over the limit answers a flat `413`.
|
|
12977
13350
|
- **One header merge site.** Request headers come from the v2 `headers` map plus the separate `cookies` array in exactly one function; the array is canonical, so a `cookie` key smuggled into `headers` never reaches the app. Response `Set-Cookie` values travel in the result's `cookies` array, one entry each - never comma-joined.
|
|
13351
|
+
- **Body-less HEAD.** A `HEAD` answer keeps the GET route's status and headers but carries no body, on both handlers. A streaming body is cancelled rather than read, so its producer stops.
|
|
12978
13352
|
- **Base64 honesty.** Response `isBase64Encoded` is decided by a strict UTF-8 decode of the actual bytes, never by content-type guessing. Binary round-trips exactly; text ships as text.
|
|
12979
13353
|
- **Client IP.** `event.requestContext.http.sourceIp` feeds core's client-IP seam; `X-Forwarded-For` trust stays where it belongs, in the app's `clientIp` server option.
|
|
12980
13354
|
- **Flat errors.** Uncaught failures collapse to the same `{"ok":false,"error":"internal_error"}` 500 as every other nifra runtime - the event is never echoed.
|
|
@@ -13226,6 +13600,9 @@ nifra sdk --lang <python|go> [--strict]
|
|
|
13226
13600
|
nifra doctor [--json] [--auto-fix] Catch undeclared imports and duplicate Nifra/React installs.
|
|
13227
13601
|
```
|
|
13228
13602
|
|
|
13603
|
+
`nifra dev`, `build` and `start` take a flag's value as `--target vercel` or `--target=vercel`, and refuse
|
|
13604
|
+
a flag or argument they do not know instead of ignoring it.
|
|
13605
|
+
|
|
13229
13606
|
## `nifra doctor` - dependency health
|
|
13230
13607
|
|
|
13231
13608
|
Doctor diffs source imports against declared dependencies, then resolves identity-sensitive
|
|
@@ -13266,7 +13643,8 @@ is the feedback plan and reports which release gates it omits. CI and release au
|
|
|
13266
13643
|
`nifra verify --release` (or `bun run check:release`), which includes build, coverage, corpus,
|
|
13267
13644
|
consumer, publish, and cross-runtime gates. Each gate runs a `package.json` script (`bun run lint`,
|
|
13268
13645
|
`bun run check:docs`, ...); a gate whose script the project does not declare is reported as
|
|
13269
|
-
`undeclared` and does not fail the run.
|
|
13646
|
+
`undeclared` and does not fail the run. The nifra repository's own `bun run verify` and
|
|
13647
|
+
`bun run check:release` fail that gate instead, so a renamed script cannot drop it. Run `nifra port --ci --target <target>` for an app's
|
|
13270
13648
|
resolved deployment target; CI never guesses a target when none is configured.
|
|
13271
13649
|
|
|
13272
13650
|
## `nifra check` - the drift gate (run as "done")
|
|
@@ -13277,7 +13655,8 @@ remember them. It does three things and exits non-zero if any fails:
|
|
|
13277
13655
|
1. **Typecheck** (`tsc --noEmit`, using the project's own TypeScript) - the frontend↔backend contract is
|
|
13278
13656
|
compiler-enforced. `client<typeof app>` derives request inputs **and** `res.data` from your routes, so
|
|
13279
13657
|
a screen that expects the wrong shape is a type error. Running the typecheck is what turns that latent
|
|
13280
|
-
guarantee into an enforced one.
|
|
13658
|
+
guarantee into an enforced one. TypeScript sources with no `tsconfig.json` beside them fail this step,
|
|
13659
|
+
as a missing `typescript` install does: nothing typechecked them. A JavaScript-only project skips it.
|
|
13281
13660
|
2. **Typed-client lint** - flags any hand-rolled `fetch()` to your own API (a relative URL like
|
|
13282
13661
|
`fetch("/users")`), which bypasses the typed client so the compiler can't see the drift. External
|
|
13283
13662
|
absolute-URL fetches are not flagged.
|
|
@@ -13511,6 +13890,14 @@ default 8 MiB) answers `409 resync_required`, so read `session.events` instead;
|
|
|
13511
13890
|
`turn.send` while one runs answers `409 turn_running`; and a turn no client has followed for
|
|
13512
13891
|
`detachedTimeoutMs` (default 2 minutes) is cancelled.
|
|
13513
13892
|
|
|
13893
|
+
An approval, or a coding tool's question to the person, is denied once it has waited 5 minutes.
|
|
13894
|
+
Pass `approvals: { timeoutMs }` to `CodingAgentHost` or `CodingAgentRpcServer` for up to 24 h, or
|
|
13895
|
+
`timeoutMs: "never"` to keep it until it is answered, cancelled, its turn ends, or the session
|
|
13896
|
+
closes; `maxPending` (default 32) still bounds how many can wait. `NifraBackend` has its own
|
|
13897
|
+
`approvalTimeoutMs`, taking the same values, and the host denies in the backend whatever its broker
|
|
13898
|
+
denies, so the shorter of the two applies. A never-expiring approval reports `expiresAt` as
|
|
13899
|
+
`APPROVAL_NEVER_EXPIRES_AT`, which survives JSON and stays later than any `Date.now()`.
|
|
13900
|
+
|
|
13514
13901
|
`nifra-agent` loads `.nifra/extensions/**` from `--cwd` only when started with
|
|
13515
13902
|
`--extensions`. An extension module's top-level code runs as soon as it is
|
|
13516
13903
|
imported, before its declared `capabilities` are checked, so pass the flag only
|
|
@@ -13819,8 +14206,11 @@ cron.stop() // graceful - in-flight handlers finish
|
|
|
13819
14206
|
|
|
13820
14207
|
Macros: `@hourly` `@daily` (`@midnight`) `@weekly` `@monthly` `@yearly` (`@annually`).
|
|
13821
14208
|
|
|
14209
|
+
Day-of-week runs 0-6 from Sunday, and 7 is Sunday too.
|
|
14210
|
+
|
|
13822
14211
|
Day-of-month + day-of-week follow the **standard OR rule**: when both are restricted, a match on
|
|
13823
|
-
either fires the job.
|
|
14212
|
+
either fires the job. A field that starts with `*` is not restricted, a step like `*/2` included,
|
|
14213
|
+
so `0 0 */2 * 1` fires on an odd day that is also a Monday, as in Vixie cron.
|
|
13824
14214
|
|
|
13825
14215
|
## Guarantees
|
|
13826
14216
|
|
|
@@ -13890,6 +14280,14 @@ cap live inside `app.fetch`, so they apply through this adapter automatically.
|
|
|
13890
14280
|
|
|
13891
14281
|
Works with any `{ fetch(req): Promise<Response> }` handler, not just nifra. ESM/TS. MIT.
|
|
13892
14282
|
|
|
14283
|
+
## WebSocket message size
|
|
14284
|
+
|
|
14285
|
+
`app.ws()` routes upgrade through `Deno.upgradeWebSocket`, which takes no size limit: Deno receives
|
|
14286
|
+
each inbound message whole (up to its own limit, 64 MiB on Deno 2.9) before the app sees it.
|
|
14287
|
+
`server({ wsMaxPayloadBytes })` then closes the socket with `1009` and keeps the message from your
|
|
14288
|
+
handler, but it cannot bound the memory Deno spent receiving it. Where that matters, cap message
|
|
14289
|
+
size in a proxy in front of the app. On Bun and Node the cap is enforced while the message arrives.
|
|
14290
|
+
|
|
13893
14291
|
## For AI agents
|
|
13894
14292
|
|
|
13895
14293
|
Start with [`LLM.md`](./LLM.md) - this package's contract card (the exports you call + its footguns),
|
|
@@ -14109,8 +14507,11 @@ pass the request's bindings: `defineEnv(shape, { source: env })`.
|
|
|
14109
14507
|
## Secret safety
|
|
14110
14508
|
|
|
14111
14509
|
Error messages name the offending variable and the reason - **never its value** (it may be a
|
|
14112
|
-
secret). A BYO validator such as valibot may quote the value in its message
|
|
14113
|
-
|
|
14510
|
+
secret). A BYO validator such as valibot or zod may quote the value in its message, escaped or
|
|
14511
|
+
cut short, so when it refuses a set value `defineEnv` reports the variable as invalid without the
|
|
14512
|
+
validator's message. For an unset variable the message is shown, since there is no value to quote.
|
|
14513
|
+
Use the `env.*` helpers when you want the reason as well. `defineEnv` returns a frozen object, so a
|
|
14514
|
+
validated config can't be mutated downstream.
|
|
14114
14515
|
|
|
14115
14516
|
## For AI agents
|
|
14116
14517
|
|
|
@@ -14250,6 +14651,7 @@ With `subscriptions: true`, a socket is admitted only when `authorize` accepts i
|
|
|
14250
14651
|
| `allowedOrigins` | reflect `*` | CORS origin allowlist. |
|
|
14251
14652
|
| `authorize` | - | Per-request guard; return `false` for 401. |
|
|
14252
14653
|
| `enableGet` | `true` | Serve `GET /graphql` (queries only). |
|
|
14654
|
+
| `introspection` | `true` | `false` refuses `__schema` and `__type` as a validation error (400 over HTTP, an `error` frame over WS); `__typename` still resolves. Subscriptions inherit it unless their own options set it. |
|
|
14253
14655
|
| `subscriptions` | `false` | `true` (reuse schema, context, `authorize` and limits) or explicit WS options. |
|
|
14254
14656
|
| `legacyJsonResponse` | `false` | Old always-200 `application/json` shape. |
|
|
14255
14657
|
|
|
@@ -14569,6 +14971,8 @@ fails at the call site, not three retries later.
|
|
|
14569
14971
|
|
|
14570
14972
|
Per-job: `retries: number` (attempts) or `{ attempts, backoff }`. A handler that throws is routed to
|
|
14571
14973
|
`onError`, then retried with the backoff delay; after the last attempt it's **dead-lettered**, not lost.
|
|
14974
|
+
An attempt count (and `createQueue({ defaultAttempts })`) must be a whole number; `NaN`, `Infinity` or
|
|
14975
|
+
a fraction throws a `RangeError`, and a count below 1 means one attempt.
|
|
14572
14976
|
|
|
14573
14977
|
```ts
|
|
14574
14978
|
import { exponentialBackoff, fixedBackoff } from "@nifrajs/jobs"
|
|
@@ -14590,10 +14994,18 @@ const q = createQueue({ store: new RedisJobStore(redis) })
|
|
|
14590
14994
|
Leasing is at-least-once: a leased job is hidden for `leaseMs`; a worker that dies mid-job releases it
|
|
14591
14995
|
back automatically. Make handlers **idempotent**.
|
|
14592
14996
|
|
|
14997
|
+
While a handler runs, the worker renews its lease about three times per `leaseMs` through the store's
|
|
14998
|
+
optional `renew(id, until, lease)`, so a job that runs longer than `leaseMs` is not handed to another
|
|
14999
|
+
worker. A store without `renew` cannot do that: such a job may then run twice, on two workers, though
|
|
15000
|
+
never twice on the same queue. Each `lease` may also return a `lease` token on the job; the queue
|
|
15001
|
+
passes it back to `complete` / `retry` / `deadLetter` / `renew`, so a store can ignore a worker whose
|
|
15002
|
+
lease another worker has since taken. `MemoryJobStore` does both.
|
|
15003
|
+
|
|
14593
15004
|
A job's `timeoutMs` bounds each attempt: one still running after that many ms fails with a
|
|
14594
15005
|
`JobTimeoutError` (then retries or dead-letters), frees its worker slot, and aborts `ctx.signal`. Pass the
|
|
14595
|
-
signal on to `fetch` or your driver, since a handler that ignores it keeps running unobserved.
|
|
14596
|
-
`timeoutMs` below `leaseMs
|
|
15006
|
+
signal on to `fetch` or your driver, since a handler that ignores it keeps running unobserved.
|
|
15007
|
+
`timeoutMs` must be below the worker's `leaseMs`: `start()` (and a later `define()`) throws a
|
|
15008
|
+
`RangeError` otherwise.
|
|
14597
15009
|
|
|
14598
15010
|
```ts
|
|
14599
15011
|
q.define("render", { timeoutMs: 10_000, async handler(id, ctx) { await fetch(url(id), { signal: ctx.signal }) } })
|
|
@@ -16054,6 +16466,14 @@ Framework-agnostic SSR core for nifra - the render seam + HTML document orchestr
|
|
|
16054
16466
|
|
|
16055
16467
|
Part of the **[nifra](https://nifra.dev)** full-stack TypeScript framework - one core, five UI libraries, every runtime. Scaffold a new app with `bun create nifra`.
|
|
16056
16468
|
|
|
16469
|
+
## Guarding pages
|
|
16470
|
+
|
|
16471
|
+
A `_layout.backend.ts` loader is data, not a guard: a client navigation can skip it while the browser
|
|
16472
|
+
keeps the layout's data, and an action below it runs without it. Refuse access in that file's
|
|
16473
|
+
`middleware`, or export `gate = true` so its loader runs on every request and before every action,
|
|
16474
|
+
ahead of the page loader. In development, nifra warns when a layout loader without `gate` refuses a
|
|
16475
|
+
request, and `nifra check` reports one whose refusal it can read (NF-C042). See [Layout loaders on navigation](https://nifra.dev/docs/data).
|
|
16476
|
+
|
|
16057
16477
|
## Install
|
|
16058
16478
|
|
|
16059
16479
|
```sh
|
|
@@ -16545,7 +16965,7 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
16545
16965
|
|
|
16546
16966
|
## @nifrajs/coding-agent
|
|
16547
16967
|
|
|
16548
|
-
`AGENT_CAPABILITY_MANIFEST_VERSION`, `AGENT_PRESETS`, `AgentCapability`, `AgentCapabilityManifest`, `AgentPlan`, `AgentPreset`, `AgentPresetName`, `ApprovalDecision`, `ApprovalManager`, `ApprovalManagerOptions`, `ApprovalMatchRejection`, `ApprovalMatchResult`, `ApprovalRequest`, `BoundedSubagentRunner`, `BoundedText`, `CapabilityDescriptor`, `CiDeploymentAdapter`, `CodingAgentExtension`, `CodingAgentHost`, `CodingAgentHostOptions`, `CodingAgentRpcServer`, `CodingAgentRpcServerHandle`, `CodingAgentRpcServerOptions`, `CompactionReport`, `ContextRecord`, `ContextWindow`, `ContextWindowOptions`, `DEPLOYMENT_REFERENCE_PROFILES`, `ExtensionCommand`, `ExtensionContext`, `ExtensionDescriptorOptions`, `ExtensionDescriptorSource`, `ExtensionEventHandler`, `ExtensionHost`, `ExtensionHostOptions`, `ExtensionProvider`, `ExtensionReloadResult`, `ExtensionSubagent`, `ExtensionTool`, `FileSessionStore`, `FileSessionStoreOptions`, `HandoffCoordinator`, `HandoffCoordinatorOptions`, `HandoffDecision`, `HandoffError`, `HandoffRejection`, `HandoffView`, `HealingEvent`, `HealingOptions`, `HealingResult`, `IsolatedExtensionSnapshot`, `IsolatedExtensionTool`, `IsolatedExtensionWorker`, `IsolatedExtensionWorkerOptions`, `LocalProcessDeploymentAdapter`, `MigrateLegacySessionOptions`, `NIFRA_AGENT_INSTRUCTIONS`, `NativeApprovalPort`, `NativeGatewayModelPortOptions`, `NativeMessage`, `NativeModelChunk`, `NativeModelPort`, `NativeModelRequest`, `NativeModelResponse`, `NativeTool`, `NifraAgentTool`, `NifraBackend`, `NifraBackendOptions`, `NifraContextOptions`, `NifraContextResult`, `OpenHandoffInput`, `PiBackend`, `PiBackendOptions`, `PlanEvent`, `PlanPhase`, `PlanResult`, `PlanRunner`, `PlanRunnerOptions`, `ProjectDiffOptions`, `ProjectDiffResult`, `RepairProposal`, `ReplayBackend`, `ReplayBackendOptions`, `ReplayDeploymentAdapter`, `ReviewExecutionErrorCode`, `ReviewExecutionResult`, `ReviewOptions`, `SESSION_EVIDENCE_VERSION`, `SelfHealingController`, `SessionEvidenceRecord`, `SessionLogEntry`, `SessionMigrationError`, `SessionMigrationReport`, `SessionStore`, `SubagentAbandonment`, `SubagentAbandonmentLedger`, `SubagentExecutor`, `SubagentResult`, `SubagentRunnerOptions`, `SubagentSpec`, `UiExtensionHost`, `UiExtensionHostOptions`, `UiExtensionManifest`, `UiExtensionSlot`, `UiReloadResult`, `UiStatusWidget`, `UiThemeDescriptor`, `VerificationOptions`, `VerificationRepairTask`, `VerificationResult`, `WorkflowContext`, `WorkflowEvent`, `WorkflowResult`, `WorkflowRunner`, `WorkflowRunnerOptions`, `WorkflowStep`, `approvalRequestFromEvent`, `approvalResolvedEvent`, `createCapabilityManifest`, `createCiDeploymentAdapter`, `createLocalProcessDeploymentAdapter`, `createNativeGatewayModelPort`, `createNifraTools`, `createPresetSpec`, `createReplayDeploymentAdapter`, `createVerificationRepairTask`, `deniedCapabilities`, `discoverExtensions`, `extensionDescriptor`, `extensionDescriptors`, `getAgentPreset`, `isSafeReviewDiff`, `isVerificationAvailable`, `migrateLegacySession`, `parseCapabilityManifest`, `parseSessionEvidenceRecord`, `readBoundedText`, `readProjectDiff`, `readReplayEvents`, `runNifraContext`, `runNifraReview`, `runNifraVerification`, `stableSessionEventCode`, `validateExtensionModule`
|
|
16968
|
+
`AGENT_CAPABILITY_MANIFEST_VERSION`, `AGENT_PRESETS`, `APPROVAL_NEVER_EXPIRES_AT`, `AgentCapability`, `AgentCapabilityManifest`, `AgentPlan`, `AgentPreset`, `AgentPresetName`, `ApprovalDecision`, `ApprovalManager`, `ApprovalManagerOptions`, `ApprovalMatchRejection`, `ApprovalMatchResult`, `ApprovalRequest`, `ApprovalTimeout`, `BoundedSubagentRunner`, `BoundedText`, `CapabilityDescriptor`, `CiDeploymentAdapter`, `CodingAgentExtension`, `CodingAgentHost`, `CodingAgentHostOptions`, `CodingAgentRpcServer`, `CodingAgentRpcServerHandle`, `CodingAgentRpcServerOptions`, `CompactionReport`, `ContextRecord`, `ContextWindow`, `ContextWindowOptions`, `DEPLOYMENT_REFERENCE_PROFILES`, `ExtensionCommand`, `ExtensionContext`, `ExtensionDescriptorOptions`, `ExtensionDescriptorSource`, `ExtensionEventHandler`, `ExtensionHost`, `ExtensionHostOptions`, `ExtensionProvider`, `ExtensionReloadResult`, `ExtensionSubagent`, `ExtensionTool`, `FileSessionStore`, `FileSessionStoreOptions`, `HandoffCoordinator`, `HandoffCoordinatorOptions`, `HandoffDecision`, `HandoffError`, `HandoffRejection`, `HandoffView`, `HealingEvent`, `HealingOptions`, `HealingResult`, `IsolatedExtensionSnapshot`, `IsolatedExtensionTool`, `IsolatedExtensionWorker`, `IsolatedExtensionWorkerOptions`, `LocalProcessDeploymentAdapter`, `MigrateLegacySessionOptions`, `NIFRA_AGENT_INSTRUCTIONS`, `NativeApprovalPort`, `NativeGatewayModelPortOptions`, `NativeMessage`, `NativeModelChunk`, `NativeModelPort`, `NativeModelRequest`, `NativeModelResponse`, `NativeTool`, `NifraAgentTool`, `NifraBackend`, `NifraBackendOptions`, `NifraContextOptions`, `NifraContextResult`, `OpenHandoffInput`, `PiBackend`, `PiBackendOptions`, `PlanEvent`, `PlanPhase`, `PlanResult`, `PlanRunner`, `PlanRunnerOptions`, `ProjectDiffOptions`, `ProjectDiffResult`, `RepairProposal`, `ReplayBackend`, `ReplayBackendOptions`, `ReplayDeploymentAdapter`, `ReviewExecutionErrorCode`, `ReviewExecutionResult`, `ReviewOptions`, `SESSION_EVIDENCE_VERSION`, `SelfHealingController`, `SessionEvidenceRecord`, `SessionLogEntry`, `SessionMigrationError`, `SessionMigrationReport`, `SessionStore`, `SubagentAbandonment`, `SubagentAbandonmentLedger`, `SubagentExecutor`, `SubagentResult`, `SubagentRunnerOptions`, `SubagentSpec`, `UiExtensionHost`, `UiExtensionHostOptions`, `UiExtensionManifest`, `UiExtensionSlot`, `UiReloadResult`, `UiStatusWidget`, `UiThemeDescriptor`, `VerificationOptions`, `VerificationRepairTask`, `VerificationResult`, `WorkflowContext`, `WorkflowEvent`, `WorkflowResult`, `WorkflowRunner`, `WorkflowRunnerOptions`, `WorkflowStep`, `approvalRequestFromEvent`, `approvalResolvedEvent`, `createCapabilityManifest`, `createCiDeploymentAdapter`, `createLocalProcessDeploymentAdapter`, `createNativeGatewayModelPort`, `createNifraTools`, `createPresetSpec`, `createReplayDeploymentAdapter`, `createVerificationRepairTask`, `deniedCapabilities`, `discoverExtensions`, `extensionDescriptor`, `extensionDescriptors`, `getAgentPreset`, `isSafeReviewDiff`, `isVerificationAvailable`, `migrateLegacySession`, `parseCapabilityManifest`, `parseSessionEvidenceRecord`, `readBoundedText`, `readProjectDiff`, `readReplayEvents`, `runNifraContext`, `runNifraReview`, `runNifraVerification`, `stableSessionEventCode`, `validateExtensionModule`
|
|
16549
16969
|
|
|
16550
16970
|
## @nifrajs/content
|
|
16551
16971
|
|
|
@@ -16553,7 +16973,7 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
16553
16973
|
|
|
16554
16974
|
## @nifrajs/core
|
|
16555
16975
|
|
|
16556
|
-
`AdmissionController`, `AdmissionDecision`, `AnyServer`, `AuthHeaders`, `AuthMaybePromise`, `AuthenticationFailure`, `AuthenticationFailureReason`, `AuthenticationInput`, `AuthenticationResult`, `AuthenticationStage`, `AuthenticationSuccess`, `Context`, `ContextPlugin`, `CookieOptions`, `CookieSecret`, `DeclaredMountRoute`, `DefinePluginResult`, `DurableObjectNamespaceLike`, `ExecutionContext`, `FRAMEWORK_NAME`, `FetchApp`, `FrameworkError`, `FrameworkName`, `Handler`, `IdentityPlugin`, `InferInput`, `InferOutput`, `JoinRoutePath`, `LambdaEvent`, `LambdaHandler`, `LambdaResponse`, `LambdaV1Event`, `LambdaV2Event`, `ListenTlsOptions`, `LogFields`, `Logger`, `METHODS`, `McpPromptDescriptor`, `McpResourceDescriptor`, `Method`, `Middleware`, `MountFetchOptions`, `MountOptions`, `MountableApp`, `NetlifyEvent`, `NetlifyHandler`, `NifraFeatureVersion`, `NifraPlugin`, `NifraWebSocket`, `NodeRequestContext`, `NodeRequestHook`, `NodeResponseBodyHook`, `NodeResponseContext`, `NodeResponseHook`, `NodeServeOutcome`, `OnRequestResult`, `OpaqueMountDeclaration`, `Params`, `PlainRender`, `Platform`, `PlatformResponse`, `PluginTypeCollapsed`, `PrefixRegistry`, `Prettify`, `PromptArgument`, `PromptMessage`, `ROUTE_PATTERN_OVERLAP_MAX_STATES`, `RedactOptions`, `Registry`, `RequestPath`, `ResponseBodyHook`, `ResponseBodyReplacement`, `ResponseControls`, `ResponseFinalization`, `ResponseHeadersHook`, `ResponseHeadersView`, `ResponseMapFor`, `ResponseResult`, `RouteConfigError`, `RouteConfigErrorCode`, `RouteDescriptor`, `RouteInfo`, `RouteInfoFor`, `RouteMethod`, `RoutePatternOverlapLimitError`, `RouteSchema`, `Router`, `RouterMatch`, `RunningServer`, `SSEContext`, `SSEInit`, `SSEMessage`, `SSEStream`, `ScheduledController`, `ScheduledHandler`, `Server`, `ServerOptions`, `StandardIssue`, `StandardResult`, `StandardSchemaV1`, `StandardTypes`, `StandardWebSocket`, `StatusResponse`, `ToolAnnotations`, `TypedSSEStream`, `UrlParts`, `VERSION`, `ValidationOutcome`, `VercelHandler`, `Version`, `WebSocketContext`, `WebSocketData`, `WebSocketHandler`, `WebSocketUpgradeOutcome`, `authenticated`, `commonSecretPatterns`, `cookieNamePrefix`, `defineContextPlugin`, `defineIdentityPlugin`, `definePlugin`, `defineRouterPlugin`, `hasDuplicateCookie`, `isAuthenticatedRequest`, `isSameOriginPath`, `isSameOriginRequest`, `jsonLogger`, `markAuthenticatedRequest`, `parseCookies`, `pathnameOf`, `redactLogFields`, `rejected`, `replacedRequestOf`, `routePatternOverlap`, `serializeCookie`, `server`, `signValue`, `silentLogger`, `status`, `toFetchHandler`, `toLambdaHandler`, `toNetlifyHandler`, `toVercelHandler`, `unsignValue`, `urlPartsOf`, `writableResponse`
|
|
16976
|
+
`AdmissionController`, `AdmissionDecision`, `AnyServer`, `AuthHeaders`, `AuthMaybePromise`, `AuthenticationFailure`, `AuthenticationFailureReason`, `AuthenticationInput`, `AuthenticationResult`, `AuthenticationStage`, `AuthenticationSuccess`, `Context`, `ContextPlugin`, `CookieOptions`, `CookieSecret`, `DeclaredMountRoute`, `DefinePluginResult`, `DurableObjectNamespaceLike`, `ExecutionContext`, `FRAMEWORK_NAME`, `FetchApp`, `FrameworkError`, `FrameworkName`, `Handler`, `IdentityPlugin`, `InferInput`, `InferOutput`, `JoinRoutePath`, `LambdaEvent`, `LambdaHandler`, `LambdaResponse`, `LambdaV1Event`, `LambdaV2Event`, `ListenTlsOptions`, `LogFields`, `Logger`, `METHODS`, `McpPromptDescriptor`, `McpResourceDescriptor`, `Method`, `Middleware`, `MountFetchOptions`, `MountOptions`, `MountableApp`, `NetlifyEvent`, `NetlifyHandler`, `NifraFeatureVersion`, `NifraPlugin`, `NifraWebSocket`, `NodeRequestContext`, `NodeRequestHook`, `NodeResponseBodyHook`, `NodeResponseContext`, `NodeResponseHook`, `NodeServeOutcome`, `OnRequestResult`, `OpaqueMountDeclaration`, `Params`, `PlainRender`, `Platform`, `PlatformResponse`, `PluginTypeCollapsed`, `PrefixRegistry`, `Prettify`, `PromptArgument`, `PromptMessage`, `ROUTE_PATTERN_OVERLAP_MAX_STATES`, `RedactOptions`, `Registry`, `RequestPath`, `ResponseBodyHook`, `ResponseBodyReplacement`, `ResponseControls`, `ResponseFinalization`, `ResponseHeadersHook`, `ResponseHeadersView`, `ResponseMapFor`, `ResponseResult`, `RouteConfigError`, `RouteConfigErrorCode`, `RouteDescriptor`, `RouteInfo`, `RouteInfoFor`, `RouteMethod`, `RoutePatternOverlapLimitError`, `RouteSchema`, `Router`, `RouterMatch`, `RunningServer`, `SSEContext`, `SSEInit`, `SSEMessage`, `SSEStream`, `ScheduledController`, `ScheduledHandler`, `Server`, `ServerOptions`, `StandardIssue`, `StandardResult`, `StandardSchemaV1`, `StandardTypes`, `StandardWebSocket`, `StatusResponse`, `ToolAnnotations`, `TypedSSEStream`, `UrlParts`, `VERSION`, `ValidationOutcome`, `VercelHandler`, `Version`, `WebSocketContext`, `WebSocketData`, `WebSocketHandler`, `WebSocketUpgradeOutcome`, `authenticated`, `commonSecretPatterns`, `cookieNamePrefix`, `defineContextPlugin`, `defineIdentityPlugin`, `definePlugin`, `defineRouterPlugin`, `hasDuplicateCookie`, `isAuthenticatedRequest`, `isSameOriginForm`, `isSameOriginPath`, `isSameOriginRequest`, `jsonLogger`, `markAuthenticatedRequest`, `parseCookies`, `pathnameOf`, `redactLogFields`, `rejected`, `replacedRequestOf`, `routePatternOverlap`, `serializeCookie`, `server`, `signValue`, `silentLogger`, `status`, `toFetchHandler`, `toLambdaHandler`, `toNetlifyHandler`, `toVercelHandler`, `unsignValue`, `urlPartsOf`, `writableResponse`
|
|
16557
16977
|
|
|
16558
16978
|
## @nifrajs/cron
|
|
16559
16979
|
|
|
@@ -16665,7 +17085,7 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
16665
17085
|
|
|
16666
17086
|
## @nifrajs/web
|
|
16667
17087
|
|
|
16668
|
-
`ACTION_GLOBAL`, `Action`, `BOUNDARY_GLOBAL`, `BackendOnly`, `Blocker`, `BlockerController`, `BlockerFunction`, `BlockerLocation`, `BlockerState`, `Boundary`, `BoundaryDescriptor`, `BoundaryError`, `BoundaryMode`, `BoundaryRegistration`, `BoundaryRequestCtx`, `BoundaryState`, `BoundaryStates`, `BoundaryStatus`, `BrowserNavigate`, `CacheStore`, `CachedResponse`, `CdnPurgeOutcome`, `CdnPurgeTarget`, `ClientAction`, `ClientActionArgs`, `ClientActionResult`, `ClientLoader`, `ClientLoaderArgs`, `ClientRequestBody`, `ClientRouteHooks`, `ClientRouter`, `ClientRouterOptions`, `CreateCspPolicyOptions`, `CreateNonceResolverOptions`, `CreateWebAppOptions`, `CspHeaderContext`, `CspPolicy`, `CssLoadingMode`, `DATA_GLOBAL`, `DATA_HEADER`, `DEFAULT_CSS_LOADING`, `DEFAULT_DEV_PORT`, `DRAFT_COOKIE`, `Deferred`, `DehydratedState`, `DraftCookieControls`, `DynamicBoundary`, `DynamicBoundaryBatch`, `EnableDraftOptions`, `FetchRouteData`, `Fetcher`, `FetcherState`, `FontDisplay`, `FontFace`, `FontPreloadInput`, `FontSource`, `GenerateClientEntryOptions`, `GenerateRouteSearchTypesOptions`, `GenerateServerManifestOptions`, `GetStaticPaths`, `HANDOVER_ID`, `HtmlSanitizer`, `IDLE_BLOCKER`, `ISRApp`, `ISROptions`, `ISRPlatform`, `ISRQuery`, `ISRStoreOp`, `ISR_REVALIDATE_HEADER`, `ISR_REVALIDATE_TAGS_HEADER`, `ISR_STATUS_HEADER`, `InertScriptType`, `InfiniteData`, `InfiniteQueryHandle`, `InfiniteQueryOptions`, `InterceptBoundary`, `KVCacheStore`, `KVCacheStoreOptions`, `KVNamespaceLike`, `LAYOUT_DATA_GLOBAL`, `LayoutEntry`, `LinkDescriptor`, `Loader`, `LoaderContext`, `LoaderResponseControls`, `LoadingEntry`, `Manifest`, `MatchChain`, `MemoryCacheStore`, `MemoryCacheStoreOptions`, `MemoryStaticBoundaryCache`, `Meta`, `MetaArgs`, `MetaDescriptor`, `MetaInput`, `MiddlewareOutcome`, `MountRouterOptions`, `MutationCallbacks`, `MutationHandle`, `MutationState`, `MutationStatus`, `NAV_FROM_HEADER`, `NavigateFunction`, `NavigateOptions`, `NavigateSearchOf`, `NavigateTargetInput`, `NonceContext`, `NonceGenerator`, `NonceHeader`, `NonceHeaderContext`, `NonceResolver`, `NotFoundEntry`, `NotFoundScope`, `OpenGraphInput`, `PRE_HYDRATION_GUARD`, `PendingBoundary`, `PrefetchMode`, `PreviewEndpointOptions`, `PublicDirCache`, `QueryClient`, `QueryClientOptions`, `QueryHandle`, `QueryOptions`, `QueryState`, `QueryStatus`, `REDIRECT_HEADER`, `RETAIN_HEADER`, `REVALIDATE_HEADER`, `ROOT_ATTRIBUTE`, `ROUTE_GLOBAL`, `RedirectOptions`, `RenderAdapter`, `RenderAdapterConformanceError`, `RenderAdapterConformanceFixture`, `RenderAssemblyCache`, `RenderPageInput`, `RenderPageOptions`, `RenderProps`, `RenderStreamOptions`, `RenderedPage`, `RevalidateEndpointOptions`, `RevalidateResult`, `RevalidateTags`, `RevalidateTagsInput`, `RouteEntry`, `RouteMatch`, `RouteMiddleware`, `RouteModule`, `RoutePattern`, `RouteSearch`, `RouterState`, `SERVER_FN_MODULE`, `STATUS_HEADER`, `SanitizedHtml`, `ScriptDescriptor`, `SearchOf`, `ServePublicDirOptions`, `ShouldRevalidate`, `ShouldRevalidateArgs`, `SsrModuleLoader`, `StaticBoundary`, `StaticBoundaryCache`, `StaticBoundaryImportEdge`, `StaticBoundaryRoot`, `StaticCtx`, `StaticPath`, `StaticPaths`, `StaticRoutes`, `StatusPageOptions`, `Submission`, `SubmitOptions`, `TrustedHtml`, `UIMatch`, `UnsafeScriptDescriptor`, `assertCssLoadingCompatible`, `assertRenderAdapterConformance`, `assertStaticBoundaryImports`, `boundaryDescriptors`, `boundaryModeKey`, `buildManifest`, `canonical`, `createClientRouter`, `createCspPolicy`, `createMatcher`, `createMutation`, `createNonceResolver`, `createQueryClient`, `createWebApp`, `defer`, `disableDraft`, `enableDraft`, `enumerateStaticRoutes`, `filePathToPattern`, `filePathToPatterns`, `fontFace`, `fontPreload`, `generateClientEntry`, `generateRouteSearchTypes`, `generateServerManifest`, `getBrowserNavigate`, `gone`, `hashQueryKey`, `isCacheablePage`, `isDraftEnabled`, `jsonLd`, `mergeHeads`, `nifraScriptHashes`, `normalizeCssLoading`, `notFound`, `openGraph`, `previewEndpoint`, `redirect`, `registerBlocker`, `renderPage`, `renderPageResult`, `resolveChainMeta`, `resolveDynamicBoundaries`, `resolveMeta`, `resolveNavigate`, `resolvePublicPath`, `resolveStaticBoundaries`, `revalidate`, `revalidateEndpoint`, `sanitizeHtml`, `sanitizedHtml`, `searchOf`, `searchOfChain`, `serializeData`, `serializeSearch`, `servePublicDir`, `setBlockerController`, `setBrowserNavigate`, `setSsrModuleLoader`, `ssrModuleLoader`, `startDynamicBoundaries`, `statusPage`, `trustHtml`, `unsafeInlineScript`, `webProjectEvidence`, `withISR`
|
|
17088
|
+
`ACTION_GLOBAL`, `Action`, `BOUNDARY_GLOBAL`, `BackendOnly`, `Blocker`, `BlockerController`, `BlockerFunction`, `BlockerLocation`, `BlockerState`, `Boundary`, `BoundaryDescriptor`, `BoundaryError`, `BoundaryMode`, `BoundaryRegistration`, `BoundaryRequestCtx`, `BoundaryState`, `BoundaryStates`, `BoundaryStatus`, `BrowserNavigate`, `CacheStore`, `CachedResponse`, `CdnPurgeOutcome`, `CdnPurgeTarget`, `ClientAction`, `ClientActionArgs`, `ClientActionResult`, `ClientLoader`, `ClientLoaderArgs`, `ClientRequestBody`, `ClientRouteHooks`, `ClientRouter`, `ClientRouterOptions`, `CreateCspPolicyOptions`, `CreateNonceResolverOptions`, `CreateWebAppOptions`, `CspHeaderContext`, `CspPolicy`, `CssLoadingMode`, `DATA_GLOBAL`, `DATA_HEADER`, `DEFAULT_CSS_LOADING`, `DEFAULT_DEV_PORT`, `DRAFT_COOKIE`, `Deferred`, `DehydratedState`, `DocumentParts`, `DraftCookieControls`, `DynamicBoundary`, `DynamicBoundaryBatch`, `EnableDraftOptions`, `FetchRouteData`, `Fetcher`, `FetcherState`, `FontDisplay`, `FontFace`, `FontPreloadInput`, `FontSource`, `GenerateClientEntryOptions`, `GenerateRouteSearchTypesOptions`, `GenerateServerManifestOptions`, `GetStaticPaths`, `HANDOVER_ID`, `HtmlSanitizer`, `IDLE_BLOCKER`, `ISRApp`, `ISROptions`, `ISRPlatform`, `ISRQuery`, `ISRStoreOp`, `ISR_REVALIDATE_HEADER`, `ISR_REVALIDATE_TAGS_HEADER`, `ISR_STATUS_HEADER`, `InertScriptType`, `InfiniteData`, `InfiniteQueryHandle`, `InfiniteQueryOptions`, `InterceptBoundary`, `KVCacheStore`, `KVCacheStoreOptions`, `KVNamespaceLike`, `LAYOUT_DATA_GLOBAL`, `LayoutEntry`, `LinkDescriptor`, `Loader`, `LoaderContext`, `LoaderResponseControls`, `LoadingEntry`, `Manifest`, `MatchChain`, `MemoryCacheStore`, `MemoryCacheStoreOptions`, `MemoryStaticBoundaryCache`, `Meta`, `MetaArgs`, `MetaDescriptor`, `MetaInput`, `MiddlewareOutcome`, `MountRouterOptions`, `MutationCallbacks`, `MutationHandle`, `MutationState`, `MutationStatus`, `NAV_FROM_HEADER`, `NavigateFunction`, `NavigateOptions`, `NavigateSearchOf`, `NavigateTargetInput`, `NonceContext`, `NonceGenerator`, `NonceHeader`, `NonceHeaderContext`, `NonceResolver`, `NotFoundEntry`, `NotFoundScope`, `OpenGraphInput`, `PRE_HYDRATION_GUARD`, `PendingBoundary`, `PrefetchMode`, `PreviewEndpointOptions`, `PublicDirCache`, `QueryClient`, `QueryClientOptions`, `QueryHandle`, `QueryOptions`, `QueryState`, `QueryStatus`, `REDIRECT_HEADER`, `RETAIN_HEADER`, `REVALIDATE_HEADER`, `ROOT_ATTRIBUTE`, `ROUTE_GLOBAL`, `RedirectOptions`, `RenderAdapter`, `RenderAdapterConformanceError`, `RenderAdapterConformanceFixture`, `RenderAssemblyCache`, `RenderPageInput`, `RenderPageOptions`, `RenderProps`, `RenderStreamOptions`, `RenderedPage`, `RevalidateEndpointOptions`, `RevalidateResult`, `RevalidateTags`, `RevalidateTagsInput`, `RouteEntry`, `RouteMatch`, `RouteMiddleware`, `RouteModule`, `RoutePattern`, `RouteSearch`, `RouterState`, `SERVER_FN_MODULE`, `STATUS_HEADER`, `SanitizedHtml`, `ScriptDescriptor`, `SearchOf`, `ServePublicDirOptions`, `ShouldRevalidate`, `ShouldRevalidateArgs`, `SsrModuleLoader`, `StaticBoundary`, `StaticBoundaryCache`, `StaticBoundaryImportEdge`, `StaticBoundaryRoot`, `StaticCtx`, `StaticPath`, `StaticPaths`, `StaticRoutes`, `StatusPageOptions`, `Submission`, `SubmitOptions`, `TrustedHtml`, `UIMatch`, `UnsafeScriptDescriptor`, `assertCssLoadingCompatible`, `assertRenderAdapterConformance`, `assertStaticBoundaryImports`, `boundaryDescriptors`, `boundaryModeKey`, `buildManifest`, `canonical`, `createClientRouter`, `createCspPolicy`, `createMatcher`, `createMutation`, `createNonceResolver`, `createQueryClient`, `createWebApp`, `defer`, `disableDraft`, `enableDraft`, `enumerateStaticRoutes`, `filePathToPattern`, `filePathToPatterns`, `fontFace`, `fontPreload`, `generateClientEntry`, `generateRouteSearchTypes`, `generateServerManifest`, `getBrowserNavigate`, `gone`, `hashQueryKey`, `isCacheablePage`, `isDraftEnabled`, `jsonLd`, `mergeHeads`, `nifraScriptHashes`, `normalizeCssLoading`, `notFound`, `openGraph`, `previewEndpoint`, `redirect`, `registerBlocker`, `renderPage`, `renderPageResult`, `resolveChainMeta`, `resolveDynamicBoundaries`, `resolveMeta`, `resolveNavigate`, `resolvePublicPath`, `resolveStaticBoundaries`, `revalidate`, `revalidateEndpoint`, `sanitizeHtml`, `sanitizedHtml`, `searchOf`, `searchOfChain`, `serializeData`, `serializeSearch`, `servePublicDir`, `setBlockerController`, `setBrowserNavigate`, `setSsrModuleLoader`, `ssrModuleLoader`, `startDynamicBoundaries`, `statusPage`, `trustHtml`, `unsafeInlineScript`, `webProjectEvidence`, `withISR`
|
|
16669
17089
|
|
|
16670
17090
|
## @nifrajs/web-preact
|
|
16671
17091
|
|