brustjs 0.1.49-alpha → 0.1.51-alpha
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/package.json +39 -15
- package/runtime/cache-sync.ts +291 -0
- package/runtime/cache.ts +4 -0
- package/runtime/cli/build.ts +7 -0
- package/runtime/cli/dev.ts +7 -0
- package/runtime/cli/native-routes-emit.ts +147 -1
- package/runtime/cli/ssg.ts +94 -23
- package/runtime/config.ts +42 -0
- package/runtime/index.d.ts +63 -0
- package/runtime/index.js +57 -52
- package/runtime/index.ts +114 -9
- package/runtime/islands/page-cache.ts +32 -2
- package/runtime/native/runtime.ts +220 -7
- package/runtime/render/fragment.ts +87 -0
- package/runtime/routes.ts +482 -95
- package/runtime/templates.ts +47 -0
- package/runtime/treaty.ts +24 -1
- package/types/action-error.d.ts +18 -0
- package/types/cache-sync.d.ts +42 -0
- package/types/cache.d.ts +20 -0
- package/types/cli/help.d.ts +28 -0
- package/types/cli/jinja-staleness.d.ts +14 -0
- package/types/cli/native-routes-emit.d.ts +217 -0
- package/types/cli/new.d.ts +30 -0
- package/types/cli/templates.d.ts +39 -0
- package/types/client/index.d.ts +14 -0
- package/types/config.d.ts +42 -0
- package/types/cookies.d.ts +25 -0
- package/types/create.d.ts +1 -0
- package/types/css/build.d.ts +11 -0
- package/types/css/component-build.d.ts +17 -0
- package/types/css/component-loader.d.ts +8 -0
- package/types/css/manifest.d.ts +21 -0
- package/types/css/process-modules.d.ts +31 -0
- package/types/css/route-deps.d.ts +20 -0
- package/types/css/scan-imports.d.ts +13 -0
- package/types/css.d.ts +16 -0
- package/types/define-actions.d.ts +133 -0
- package/types/dev/client.d.ts +8 -0
- package/types/dev/coordinator.d.ts +33 -0
- package/types/dev/inject.d.ts +6 -0
- package/types/dev/jinja-reload.d.ts +7 -0
- package/types/dev/tui.d.ts +35 -0
- package/types/dev/watcher.d.ts +34 -0
- package/types/dev/worker-registry.d.ts +17 -0
- package/types/dev/ws-channel.d.ts +39 -0
- package/types/generator.d.ts +23 -0
- package/types/index.d.ts +222 -0
- package/types/islands/brust-page.d.ts +74 -0
- package/types/islands/build.d.ts +49 -0
- package/types/islands/chunk-id.d.ts +10 -0
- package/types/islands/importmap.d.ts +2 -0
- package/types/islands/island.d.ts +65 -0
- package/types/islands/isr-jsx.d.ts +31 -0
- package/types/islands/native-render.d.ts +89 -0
- package/types/loader-cache.d.ts +18 -0
- package/types/mcp/extractor.d.ts +14 -0
- package/types/mcp/manifest.d.ts +23 -0
- package/types/mcp/schema.d.ts +19 -0
- package/types/mcp/server.d.ts +15 -0
- package/types/md/emit.d.ts +72 -0
- package/types/md/render.d.ts +80 -0
- package/types/md/routes.d.ts +119 -0
- package/types/md/scan.d.ts +34 -0
- package/types/md/slug.d.ts +1 -0
- package/types/native/build.d.ts +30 -0
- package/types/native/index.d.ts +2 -0
- package/types/native/runtime.d.ts +52 -0
- package/types/navigation/active-nav.d.ts +2 -0
- package/types/navigation/index.d.ts +5 -0
- package/types/navigation/navigate.d.ts +14 -0
- package/types/navigation/react.d.ts +15 -0
- package/types/navigation/store.d.ts +44 -0
- package/types/render/fragment.d.ts +20 -0
- package/types/render/inject-action-prefix.d.ts +9 -0
- package/types/render/inject-css-link.d.ts +8 -0
- package/types/render/inject-dev-client.d.ts +6 -0
- package/types/render/inject-generator.d.ts +7 -0
- package/types/render/inject-store.d.ts +9 -0
- package/types/render/stream.d.ts +45 -0
- package/types/request-context.d.ts +16 -0
- package/types/routes.d.ts +506 -0
- package/types/sse/handler.d.ts +22 -0
- package/types/standard-schema.d.ts +31 -0
- package/types/store/define-store.d.ts +31 -0
- package/types/store/index.d.ts +5 -0
- package/types/store/react.d.ts +2 -0
- package/types/store/serialize.d.ts +5 -0
- package/types/store/server-context.d.ts +4 -0
- package/types/store/signal.d.ts +18 -0
- package/types/templates.d.ts +18 -0
- package/types/treaty.d.ts +70 -0
- package/types/ws/handler.d.ts +26 -0
package/runtime/cli/ssg.ts
CHANGED
|
@@ -147,6 +147,14 @@ export function collectStaticPaths(flatRoutes: FlatRouteLike[]): SsgRouteDecisio
|
|
|
147
147
|
/** Reserved sentinel param value (Phase B fallback shell crawl). */
|
|
148
148
|
export const SSG_FALLBACK_SENTINEL = '__brust_fallback__'
|
|
149
149
|
|
|
150
|
+
/** Definitely-unmatched URL path used to crawl the GLOBAL catch-all into
|
|
151
|
+
* 404.html: the dist server's NotFound tier renders the global catch-all at
|
|
152
|
+
* status 404 for any path no real route matches. Deliberately bogus — a
|
|
153
|
+
* double-underscore-namespaced segment no app route declares. NOT `/_brust/`-
|
|
154
|
+
* prefixed: those resolve to brust-internal handlers BEFORE route matching, so
|
|
155
|
+
* the catch-all tier would never see them. */
|
|
156
|
+
export const SSG_NOT_FOUND_SENTINEL_PATH = '/__brust_not_found_sentinel__'
|
|
157
|
+
|
|
150
158
|
/** Structural view of the leaf's ssg config (mirrors RouteSsgConfig). */
|
|
151
159
|
export interface RouteSsgLike {
|
|
152
160
|
params?: () => Array<Record<string, string>> | Promise<Array<Record<string, string>>>
|
|
@@ -263,24 +271,24 @@ export function hasClientLoaderExport(source: string): boolean {
|
|
|
263
271
|
return /export\s*\{[^}]*\bclientLoader\b[^}]*\}/.test(code)
|
|
264
272
|
}
|
|
265
273
|
|
|
266
|
-
/**
|
|
267
|
-
* [{pattern, doc}] manifest pairs; a path matching a
|
|
268
|
-
* the REAL url in sessionStorage (the takeover runtime
|
|
269
|
-
* history.replaceState) and redirects to the prerendered
|
|
270
|
-
* No match →
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
|
|
274
|
+
/** The redirect-only `<script>` for `fallback: 'client'` routes (no surrounding
|
|
275
|
+
* document): inlines the [{pattern, doc}] manifest pairs; a path matching a
|
|
276
|
+
* fallback pattern stashes the REAL url in sessionStorage (the takeover runtime
|
|
277
|
+
* restores it via history.replaceState) and redirects to the prerendered
|
|
278
|
+
* fallback shell. No match → no-op (the surrounding document is the 404 body).
|
|
279
|
+
* Extracted so it can be wrapped in the minimal `fallback404Html` shell OR
|
|
280
|
+
* injected into a crawled global-404 page (compose404Html). Pure string fn so
|
|
281
|
+
* the script/inline-JSON contract is unit-testable. Escapes for the <script>
|
|
282
|
+
* context: `<`/`>` (no `</script>`/`<!--`/`-->` sequences) and U+2028/U+2029
|
|
283
|
+
* (legal in JSON, illegal in pre-ES2019-parsed JS string literals). Patterns
|
|
284
|
+
* are author-controlled — belt-and-braces, not a trust boundary. */
|
|
285
|
+
export function fallback404Script(pairs: Array<{ pattern: string; doc: string }>): string {
|
|
276
286
|
const inlineJson = JSON.stringify(pairs)
|
|
277
287
|
.replace(/</g, '\\u003c')
|
|
278
288
|
.replace(/>/g, '\\u003e')
|
|
279
289
|
.replace(/\u2028/g, '\\u2028')
|
|
280
290
|
.replace(/\u2029/g, '\\u2029')
|
|
281
|
-
return
|
|
282
|
-
<p>Not found.</p>
|
|
283
|
-
<script>
|
|
291
|
+
return `<script>
|
|
284
292
|
(function () {
|
|
285
293
|
var MANIFEST = ${inlineJson};
|
|
286
294
|
function match(pattern, path) {
|
|
@@ -300,10 +308,43 @@ export function fallback404Html(pairs: Array<{ pattern: string; doc: string }>):
|
|
|
300
308
|
}
|
|
301
309
|
}
|
|
302
310
|
})()
|
|
303
|
-
</script
|
|
311
|
+
</script>`
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** Static-host 404 document for `fallback: 'client'` routes when NO global
|
|
315
|
+
* catch-all page exists: the minimal shell (`<p>Not found.</p>`) wrapping the
|
|
316
|
+
* redirect `<script>` from `fallback404Script`. When a global catch-all DOES
|
|
317
|
+
* exist its crawled page is the document and the script is injected instead
|
|
318
|
+
* (compose404Html) — this shell is unused in that case. */
|
|
319
|
+
export function fallback404Html(pairs: Array<{ pattern: string; doc: string }>): string {
|
|
320
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>404</title></head><body>
|
|
321
|
+
<p>Not found.</p>
|
|
322
|
+
${fallback404Script(pairs)}</body></html>
|
|
304
323
|
`
|
|
305
324
|
}
|
|
306
325
|
|
|
326
|
+
/** Inject `<script>…</script>` into `html` just before the closing `</body>`
|
|
327
|
+
* (last occurrence, case-insensitive). If the document has no `</body>` the
|
|
328
|
+
* script is appended — a static host still parses a trailing script. Used to
|
|
329
|
+
* compose the fallback redirect into a crawled global-404 page. */
|
|
330
|
+
export function injectBeforeBodyClose(html: string, script: string): string {
|
|
331
|
+
const idx = html.toLowerCase().lastIndexOf('</body>')
|
|
332
|
+
if (idx === -1) return `${html}\n${script}`
|
|
333
|
+
return `${html.slice(0, idx)}${script}\n${html.slice(idx)}`
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** Compose the final SSG `404.html` from a crawled global-catch-all page and,
|
|
337
|
+
* when `fallback: 'client'` routes also exist, the fallback redirect `<script>`
|
|
338
|
+
* injected before `</body>`. With no fallback pairs the crawled page is
|
|
339
|
+
* returned verbatim (pure rendered 404 page). */
|
|
340
|
+
export function compose404Html(
|
|
341
|
+
crawled: string,
|
|
342
|
+
fallbackPairs: Array<{ pattern: string; doc: string }>,
|
|
343
|
+
): string {
|
|
344
|
+
if (fallbackPairs.length === 0) return crawled
|
|
345
|
+
return injectBeforeBodyClose(crawled, fallback404Script(fallbackPairs))
|
|
346
|
+
}
|
|
347
|
+
|
|
307
348
|
// ----- static export -----
|
|
308
349
|
|
|
309
350
|
const READY_LINE = '[brust] listening on' // println! in brust-core server/mod.rs
|
|
@@ -415,13 +456,19 @@ export async function exportStatic(opts: {
|
|
|
415
456
|
routes: SsgRouteDecision[]
|
|
416
457
|
/** `fallback: 'client'` routes (pattern + built chunk URL) to emit shells for. */
|
|
417
458
|
fallbacks?: Array<{ pattern: string; chunk: string }>
|
|
459
|
+
/** True when the app declares a GLOBAL catch-all (notFoundPrefix === ''). The
|
|
460
|
+
* crawler fetches an unmatched sentinel path (→ NotFound tier renders the
|
|
461
|
+
* catch-all at 404) and writes its HTML to staticOut/404.html, composing the
|
|
462
|
+
* fallback redirect script when fallbacks also exist. An app public/404.html
|
|
463
|
+
* still wins. */
|
|
464
|
+
globalNotFound?: boolean
|
|
418
465
|
}): Promise<{
|
|
419
466
|
written: string[]
|
|
420
467
|
navWritten: string[]
|
|
421
468
|
fallbackWritten: string[]
|
|
422
469
|
skipped: SsgRouteDecision[]
|
|
423
470
|
}> {
|
|
424
|
-
const { distDir, entryDir, staticOut, routes, fallbacks = [] } = opts
|
|
471
|
+
const { distDir, entryDir, staticOut, routes, fallbacks = [], globalNotFound = false } = opts
|
|
425
472
|
const included = routes.filter((r) => r.include)
|
|
426
473
|
const skipped = routes.filter((r) => !r.include)
|
|
427
474
|
|
|
@@ -431,7 +478,7 @@ export async function exportStatic(opts: {
|
|
|
431
478
|
const written: string[] = []
|
|
432
479
|
const navWritten: string[] = []
|
|
433
480
|
const fallbackWritten: string[] = []
|
|
434
|
-
if (included.length > 0 || fallbacks.length > 0) {
|
|
481
|
+
if (included.length > 0 || fallbacks.length > 0 || globalNotFound) {
|
|
435
482
|
const port = await freePort()
|
|
436
483
|
const proc = Bun.spawn(['bun', join(distDir, 'index.js')], {
|
|
437
484
|
env: { ...process.env, BRUST_PORT: String(port), BRUST_WORKERS: '1' },
|
|
@@ -541,6 +588,13 @@ export async function exportStatic(opts: {
|
|
|
541
588
|
fallbackWritten.push(payloadFile)
|
|
542
589
|
}
|
|
543
590
|
|
|
591
|
+
// Fallback {pattern, doc} pairs for the 404.html redirect script — also
|
|
592
|
+
// inlined in the routes.json manifest. Empty when no fallback routes.
|
|
593
|
+
const fallbackPairs = fallbacks.map((f) => ({
|
|
594
|
+
pattern: f.pattern,
|
|
595
|
+
doc: `/_brust/fallback/${fallbackDiskPath(f.pattern)}/`,
|
|
596
|
+
}))
|
|
597
|
+
|
|
544
598
|
if (fallbacks.length > 0) {
|
|
545
599
|
// Manifest the client takeover runtime fetches to map a 404'd path to
|
|
546
600
|
// its fallback shell. doc/payload are directory-index URLs (trailing
|
|
@@ -557,19 +611,36 @@ export async function exportStatic(opts: {
|
|
|
557
611
|
const manifestPath = join(staticOut, '_brust', 'routes.json')
|
|
558
612
|
await mkdir(dirname(manifestPath), { recursive: true })
|
|
559
613
|
await Bun.write(manifestPath, JSON.stringify(manifest))
|
|
614
|
+
}
|
|
560
615
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
616
|
+
// 404.html, single static-host slot. Resolution:
|
|
617
|
+
// - app public/404.html present → author owns it (lands via the public/
|
|
618
|
+
// copy below); never overwrite, warn only when it would have mattered.
|
|
619
|
+
// - GLOBAL catch-all → crawl an unmatched sentinel (NotFound tier renders
|
|
620
|
+
// the catch-all at 404), use its HTML as the document; inject the
|
|
621
|
+
// fallback redirect <script> when fallbacks ALSO exist (compose404Html).
|
|
622
|
+
// - fallbacks only → the minimal fallback404Html shell (unchanged).
|
|
623
|
+
// - neither → no framework 404.html (byte-identical-today).
|
|
624
|
+
if (globalNotFound || fallbacks.length > 0) {
|
|
564
625
|
if (existsSync(join(entryDir, 'public', '404.html'))) {
|
|
565
626
|
console.warn(
|
|
566
627
|
'[brust build] ssg: public/404.html exists — NOT overwriting; your 404 page must redirect fallback routes itself (see docs)',
|
|
567
628
|
)
|
|
629
|
+
} else if (globalNotFound) {
|
|
630
|
+
// Crawl the global catch-all via an unmatched path: the dist server's
|
|
631
|
+
// NotFound tier renders it at status 404. A non-404 here means the
|
|
632
|
+
// catch-all isn't wired — fail the export rather than ship a wrong
|
|
633
|
+
// (or 200) page as the 404.
|
|
634
|
+
const resp = await fetch(`http://127.0.0.1:${port}${SSG_NOT_FOUND_SENTINEL_PATH}`)
|
|
635
|
+
const body = await resp.text()
|
|
636
|
+
if (resp.status !== 404) {
|
|
637
|
+
throw new Error(
|
|
638
|
+
`global catch-all crawl GET ${SSG_NOT_FOUND_SENTINEL_PATH} → ${resp.status} (expected 404)\n${body.slice(0, 500)}`,
|
|
639
|
+
)
|
|
640
|
+
}
|
|
641
|
+
await Bun.write(join(staticOut, '404.html'), compose404Html(body, fallbackPairs))
|
|
568
642
|
} else {
|
|
569
|
-
await Bun.write(
|
|
570
|
-
join(staticOut, '404.html'),
|
|
571
|
-
fallback404Html(manifest.fallbacks.map(({ pattern, doc }) => ({ pattern, doc }))),
|
|
572
|
-
)
|
|
643
|
+
await Bun.write(join(staticOut, '404.html'), fallback404Html(fallbackPairs))
|
|
573
644
|
}
|
|
574
645
|
}
|
|
575
646
|
} catch (err) {
|
package/runtime/config.ts
CHANGED
|
@@ -14,6 +14,12 @@ export interface BrustConfig {
|
|
|
14
14
|
cacheMaxEntries?: number
|
|
15
15
|
/** L2 page-cache capacity (entries). Undefined → Rust default of 1000. */
|
|
16
16
|
cachePageMaxEntries?: number
|
|
17
|
+
/** R9 cross-process cache invalidation: redis/dragonfly URL. Absent →
|
|
18
|
+
* feature disabled (current single-process behavior). */
|
|
19
|
+
cacheSyncUrl?: string
|
|
20
|
+
/** Pub/sub channel for cache invalidation. Undefined → module default
|
|
21
|
+
* (`brust:cache:invalidate`). */
|
|
22
|
+
cacheSyncChannel?: string
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
/** Caller-supplied fallbacks (e.g. `brust.run({ address, port })`) applied
|
|
@@ -85,6 +91,8 @@ export async function loadConfig(
|
|
|
85
91
|
workers,
|
|
86
92
|
cacheMaxEntries: fromToml.cacheMaxEntries,
|
|
87
93
|
cachePageMaxEntries: fromToml.cachePageMaxEntries,
|
|
94
|
+
cacheSyncUrl: fromEnv.cacheSyncUrl ?? fromToml.cacheSyncUrl,
|
|
95
|
+
cacheSyncChannel: fromEnv.cacheSyncChannel ?? fromToml.cacheSyncChannel,
|
|
88
96
|
}
|
|
89
97
|
}
|
|
90
98
|
|
|
@@ -168,6 +176,26 @@ function extractFromToml(parsed: unknown, file: string): Partial<BrustConfig> {
|
|
|
168
176
|
}
|
|
169
177
|
out.cachePageMaxEntries = pageMaxEntries
|
|
170
178
|
}
|
|
179
|
+
const syncUrl = (cache as Record<string, unknown>).sync_url
|
|
180
|
+
if (syncUrl !== undefined) {
|
|
181
|
+
if (typeof syncUrl !== 'string' || syncUrl.trim() === '') {
|
|
182
|
+
throw new BrustConfigError(
|
|
183
|
+
`${file}: cache.sync_url must be a non-empty string (got ${JSON.stringify(syncUrl)})`,
|
|
184
|
+
file,
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
out.cacheSyncUrl = syncUrl.trim()
|
|
188
|
+
}
|
|
189
|
+
const syncChannel = (cache as Record<string, unknown>).sync_channel
|
|
190
|
+
if (syncChannel !== undefined) {
|
|
191
|
+
if (typeof syncChannel !== 'string' || syncChannel.trim() === '') {
|
|
192
|
+
throw new BrustConfigError(
|
|
193
|
+
`${file}: cache.sync_channel must be a non-empty string (got ${JSON.stringify(syncChannel)})`,
|
|
194
|
+
file,
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
out.cacheSyncChannel = syncChannel.trim()
|
|
198
|
+
}
|
|
171
199
|
}
|
|
172
200
|
|
|
173
201
|
return out
|
|
@@ -202,5 +230,19 @@ function extractFromEnv(): Partial<BrustConfig> {
|
|
|
202
230
|
}
|
|
203
231
|
out.workers = n
|
|
204
232
|
}
|
|
233
|
+
if (process.env.BRUST_CACHE_SYNC_URL) {
|
|
234
|
+
const url = process.env.BRUST_CACHE_SYNC_URL.trim()
|
|
235
|
+
if (url === '') {
|
|
236
|
+
throw new BrustConfigError('BRUST_CACHE_SYNC_URL must be a non-empty string', null)
|
|
237
|
+
}
|
|
238
|
+
out.cacheSyncUrl = url
|
|
239
|
+
}
|
|
240
|
+
if (process.env.BRUST_CACHE_SYNC_CHANNEL) {
|
|
241
|
+
const channel = process.env.BRUST_CACHE_SYNC_CHANNEL.trim()
|
|
242
|
+
if (channel === '') {
|
|
243
|
+
throw new BrustConfigError('BRUST_CACHE_SYNC_CHANNEL must be a non-empty string', null)
|
|
244
|
+
}
|
|
245
|
+
out.cacheSyncChannel = channel
|
|
246
|
+
}
|
|
205
247
|
return out
|
|
206
248
|
}
|
package/runtime/index.d.ts
CHANGED
|
@@ -75,6 +75,38 @@ export interface NapiCompiledJsx {
|
|
|
75
75
|
warnings: Array<string>
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Global CORS policy (maps onto `brust_core::CorsConfig`). napi-rs camelCases
|
|
80
|
+
* the fields, so the TS runtime sends `origins`, `methods`, `headers`,
|
|
81
|
+
* `exposeHeaders`, `credentials`, `maxAgeSeconds`.
|
|
82
|
+
*/
|
|
83
|
+
export interface NapiCorsOptions {
|
|
84
|
+
/**
|
|
85
|
+
* Allowed origins (exact scheme+host+port match). `['*']` — or any list
|
|
86
|
+
* CONTAINING `'*'` — allows every origin (echoed as the literal `*`).
|
|
87
|
+
*/
|
|
88
|
+
origins: Array<string>
|
|
89
|
+
/**
|
|
90
|
+
* Preflight `Access-Control-Allow-Methods`. Omit for the default
|
|
91
|
+
* `GET,POST,PUT,PATCH,DELETE,OPTIONS`.
|
|
92
|
+
*/
|
|
93
|
+
methods?: Array<string>
|
|
94
|
+
/**
|
|
95
|
+
* Preflight `Access-Control-Allow-Headers`. Omit to echo the request's
|
|
96
|
+
* `Access-Control-Request-Headers`.
|
|
97
|
+
*/
|
|
98
|
+
headers?: Array<string>
|
|
99
|
+
/** `Access-Control-Expose-Headers` on actual responses. Omit for none. */
|
|
100
|
+
exposeHeaders?: Array<string>
|
|
101
|
+
/**
|
|
102
|
+
* Emit `Access-Control-Allow-Credentials: true`. INVALID with a wildcard
|
|
103
|
+
* origin — serve() throws at boot.
|
|
104
|
+
*/
|
|
105
|
+
credentials?: boolean
|
|
106
|
+
/** Preflight `Access-Control-Max-Age` seconds. Omit for 600. */
|
|
107
|
+
maxAgeSeconds?: number
|
|
108
|
+
}
|
|
109
|
+
|
|
78
110
|
/**
|
|
79
111
|
* Dev-mode: broadcast one JSON control frame (building / reload / css-update /
|
|
80
112
|
* error / ok) to every connected `/_brust/dev` client. Called from the main
|
|
@@ -87,6 +119,12 @@ export interface NapiCompiledJsx {
|
|
|
87
119
|
*/
|
|
88
120
|
export declare function napiDevBroadcast(json: string): void
|
|
89
121
|
|
|
122
|
+
/** R1 — true when `name` resolves in either tier (dynamic first, then boot). */
|
|
123
|
+
export declare function napiHasTemplate(name: string): boolean
|
|
124
|
+
|
|
125
|
+
/** R1 — names of runtime-registered templates (dynamic tier only). */
|
|
126
|
+
export declare function napiListDynamicTemplates(): Array<string>
|
|
127
|
+
|
|
90
128
|
/**
|
|
91
129
|
* Sub-project J — boot-time listing of registered minijinja templates.
|
|
92
130
|
* JS dispatcher uses this to validate every `native: true` route's
|
|
@@ -110,6 +148,13 @@ export declare function napiLoadJinjaTemplates(dir: string): Array<string>
|
|
|
110
148
|
*/
|
|
111
149
|
export declare function napiRegisterSsePaths(paths: Array<string>): NapiResult<undefined>
|
|
112
150
|
|
|
151
|
+
/**
|
|
152
|
+
* R1 dynamic template registry — register (or replace) a runtime template.
|
|
153
|
+
* Errors (name validation / jinja syntax) surface as a thrown JS Error with
|
|
154
|
+
* the minijinja message (includes line info).
|
|
155
|
+
*/
|
|
156
|
+
export declare function napiRegisterTemplate(name: string, source: string): NapiResult<undefined>
|
|
157
|
+
|
|
113
158
|
/**
|
|
114
159
|
* Boot-time registry of literal WS paths. Mirror of napi_register_sse_paths.
|
|
115
160
|
* Call once before begin_serve; exact-match only (parameterized routes are a
|
|
@@ -117,6 +162,12 @@ export declare function napiRegisterSsePaths(paths: Array<string>): NapiResult<u
|
|
|
117
162
|
*/
|
|
118
163
|
export declare function napiRegisterWsPaths(paths: Array<string>): NapiResult<undefined>
|
|
119
164
|
|
|
165
|
+
/**
|
|
166
|
+
* R1 — remove a runtime-registered template. Returns whether it existed.
|
|
167
|
+
* Boot-tier (directory-loaded) templates are not removable.
|
|
168
|
+
*/
|
|
169
|
+
export declare function napiRemoveTemplate(name: string): boolean
|
|
170
|
+
|
|
120
171
|
/**
|
|
121
172
|
* Worker-driven render chunk delivery. Worker calls this once per chunk
|
|
122
173
|
* it wants to emit; final call uses `len = 0` to close the channel.
|
|
@@ -177,6 +228,13 @@ export declare function napiRenderChunkFinal(workerId: number, slot: number, len
|
|
|
177
228
|
*/
|
|
178
229
|
export declare function napiRenderJinja(workerId: number, slot: number, dataLen: number, templateName: string, status?: number | undefined | null): NapiResult<number>
|
|
179
230
|
|
|
231
|
+
/**
|
|
232
|
+
* R1 — render a template (either tier) to an HTML string. NOT the request
|
|
233
|
+
* hot path (allocates a JS string per call; the fast lane is
|
|
234
|
+
* napi_render_jinja via SAB) — intended for handlers/loaders/tooling.
|
|
235
|
+
*/
|
|
236
|
+
export declare function napiRenderTemplate(name: string, dataJson: string): NapiResult<string>
|
|
237
|
+
|
|
180
238
|
/**
|
|
181
239
|
* Drop the connection's sender, which signals the per-conn task to exit
|
|
182
240
|
* and close the TCP socket. Idempotent — a missing conn is a no-op.
|
|
@@ -300,6 +358,11 @@ export interface ServeOptions {
|
|
|
300
358
|
* configured (cert + key present). An unrecognized value is rejected.
|
|
301
359
|
*/
|
|
302
360
|
tlsMinVersion?: string
|
|
361
|
+
/**
|
|
362
|
+
* Optional global CORS policy. Omit to keep CORS disabled (byte-identical
|
|
363
|
+
* default behavior: no `Access-Control-*` headers, OPTIONS still 405).
|
|
364
|
+
*/
|
|
365
|
+
cors?: NapiCorsOptions
|
|
303
366
|
}
|
|
304
367
|
|
|
305
368
|
/**
|