@jay-framework/production-server 0.25.5 → 0.26.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.
@@ -0,0 +1,559 @@
1
+ import * as _jay_framework_ssr_runtime from '@jay-framework/ssr-runtime';
2
+ import { JayHtmlHeadMeta, JayHtmlScript, DevServerPagePart, HeadlessInstanceComponent, ForEachHeadlessInstance, ActionRegistry } from '@jay-framework/stack-server-runtime';
3
+ import { HeadTag } from '@jay-framework/fullstack-component';
4
+
5
+ interface RouteManifest {
6
+ version: string;
7
+ projectRoot: string;
8
+ sharedManifest: Record<string, string>;
9
+ routes: RouteEntry[];
10
+ actions: ActionEntry[];
11
+ plugins: PluginEntry[];
12
+ /**
13
+ * Site-level JSON-LD (Organization + WebSite) head tags, generated once at build from
14
+ * `.jay` `site` config and injected into every served page's `<head>` (DL#213). Empty/absent
15
+ * when `site.name` is not configured.
16
+ */
17
+ siteHeadTags?: HeadTag[];
18
+ /**
19
+ * Compiled error pages keyed by status token (`"404"`, `"502"`, `"5xx"`, …) (DL#218).
20
+ * Resolved by status (exact → family), never by URL — kept out of `routes[]` so they are
21
+ * non-navigable and excluded from sitemap/llms.txt/robots/internal-link validation.
22
+ */
23
+ errorPages?: Record<string, ErrorPageEntry>;
24
+ }
25
+ /**
26
+ * A compiled error page (DL#218). Mirrors the per-route compiled refs of a single-instance
27
+ * route, minus URL/param machinery: an error page is resolved by status, not by matching a URL.
28
+ */
29
+ interface ErrorPageEntry {
30
+ /** Status token this page serves — exact (`"404"`, `"502"`) or family (`"4xx"`, `"5xx"`). */
31
+ token: string;
32
+ /** Per-page server element path (relative to backend dir). */
33
+ serverElementPath: string;
34
+ /** Per-page CSS file path (relative to frontend dir). */
35
+ routeCssPath?: string;
36
+ /** Per-page hydrate script path (relative to frontend dir). */
37
+ routeHydratePath?: string;
38
+ /** Per-page client bundle path (relative to frontend dir). */
39
+ routeClientBundlePath?: string;
40
+ /** External @import URLs extracted from CSS at build time. */
41
+ cssImports?: string[];
42
+ /** Head metadata from the error page's jay-html <head>. */
43
+ headMeta?: JayHtmlHeadMeta;
44
+ /** Passthrough `<script jay-script="allow">` tags from the template. */
45
+ scripts?: JayHtmlScript[];
46
+ /** Shared chunk package names this page's hydrate/client bundle imports (DL#177). */
47
+ sharedDeps?: string[];
48
+ /** trackBy map threaded to the client hydration entry. */
49
+ trackByMap?: Record<string, string>;
50
+ /**
51
+ * Optional pre-rendered slow (static chrome) ViewState. Unused in v1 — an error page is a
52
+ * pass-through of the injected `error` ViewState (DL#218 Q6); its static chrome renders
53
+ * from the template without slow data. The renderer merges `slowCache?.slowViewState ?? {}`.
54
+ */
55
+ slowCache?: CacheEntry;
56
+ }
57
+ interface RouteSegment {
58
+ type: 'static' | 'param' | 'optional' | 'catchAll' | 'optionalCatchAll';
59
+ value: string;
60
+ }
61
+ interface RouteEntry {
62
+ pattern: string;
63
+ segments: RouteSegment[];
64
+ serverModule: string;
65
+ trackByMap?: Record<string, string>;
66
+ contracts?: string[];
67
+ componentExport?: string;
68
+ /** Per-route server element path (DL#144). Shared across all instances. */
69
+ serverElementPath?: string;
70
+ /** Per-route CSS file path (DL#144). Extracted from route-level server element compilation. */
71
+ routeCssPath?: string;
72
+ /** Per-route hydrate script path (DL#144). Shared across all instances. */
73
+ routeHydratePath?: string;
74
+ /** Per-route client bundle path (DL#144). Entry that imports route hydrate script. */
75
+ routeClientBundlePath?: string;
76
+ /** External @import URLs extracted from CSS at build time (DL#146). Used for preload hints. */
77
+ cssImports?: string[];
78
+ /** Head metadata from jay-html <head> (title, meta tags). */
79
+ headMeta?: JayHtmlHeadMeta;
80
+ /** Passthrough `<script jay-script="allow">` tags from the jay-html template (DL#149 Phase 2). */
81
+ scripts?: JayHtmlScript[];
82
+ /** True when page has static <meta name="robots" content="noindex"> */
83
+ noIndex?: boolean;
84
+ isPlugin?: boolean;
85
+ pluginName?: string;
86
+ /** Shared chunk package names this route's hydrate script imports (DL#177). */
87
+ sharedDeps?: string[];
88
+ /** When true, dev-server tooling route (future: excluded from production builds). */
89
+ devOnly?: boolean;
90
+ }
91
+ /**
92
+ * A resolved instance of a route (Design Log #227). Synthesized by the store from the route and
93
+ * the params — only `params` is per-instance information; the rest is route-level.
94
+ */
95
+ interface InstanceEntry {
96
+ params: Record<string, string>;
97
+ cachePath: string;
98
+ serverElementPath: string;
99
+ clientBundlePath: string;
100
+ clientCssPath?: string;
101
+ }
102
+ /** An instance as listed by `ArtifactStore.listInstances` (sitemap, llms.txt, …). */
103
+ interface InstanceRef {
104
+ params: Record<string, string>;
105
+ cachePath: string;
106
+ }
107
+ interface CacheEntry {
108
+ slowViewState: object;
109
+ carryForward: object;
110
+ /** Epoch ms at which the slow data was rendered (Design Log #226). */
111
+ renderedAt?: number;
112
+ /** Freshness lifetime in seconds; undefined = never stale (#226). */
113
+ ttl?: number;
114
+ /** Absolute age in seconds up to which stale data is served immediately (#226). */
115
+ grace?: number;
116
+ /** Route pattern and params of the instance — makes the cache item its own index entry (#227). */
117
+ route?: string;
118
+ params?: Record<string, string>;
119
+ }
120
+ interface ActionEntry {
121
+ serverModule: string;
122
+ packageName?: string;
123
+ isPlugin: boolean;
124
+ actionNames: string[];
125
+ }
126
+ interface PluginEntry {
127
+ name: string;
128
+ packageName: string;
129
+ }
130
+ interface BuildMetadata {
131
+ version: string;
132
+ sourceHash: string;
133
+ buildTimestamp: string;
134
+ nodeVersion: string;
135
+ instanceCount: number;
136
+ }
137
+ interface BuildOptions {
138
+ version: string;
139
+ projectRoot: string;
140
+ pagesRoot: string;
141
+ buildRoot: string;
142
+ concurrency: number;
143
+ tsConfigFilePath: string;
144
+ minify?: boolean;
145
+ /** Site base URL for sitemap generation (e.g. "https://example.com"). */
146
+ siteBaseUrl?: string;
147
+ /** Site identity for Organization + WebSite JSON-LD generation (DL#213). */
148
+ site?: {
149
+ name?: string;
150
+ baseUrl?: string;
151
+ logo?: string;
152
+ description?: string;
153
+ sameAs?: string[];
154
+ };
155
+ }
156
+ interface ServerElementModule {
157
+ renderToStream: (vs: object, ctx: _jay_framework_ssr_runtime.ServerRenderContext) => void;
158
+ }
159
+ interface PageModule {
160
+ [key: string]: any;
161
+ }
162
+
163
+ interface PagePartsConfigEntry {
164
+ modulePath: string;
165
+ exportName: string;
166
+ source: 'local' | 'npm';
167
+ structural?: boolean;
168
+ }
169
+ interface PagePartsConfig {
170
+ parts: Array<PagePartsConfigEntry & {
171
+ key?: string;
172
+ contractInfo?: {
173
+ contractName: string;
174
+ metadata?: Record<string, unknown>;
175
+ };
176
+ headlessProps?: Record<string, string>;
177
+ }>;
178
+ instanceComponents: Array<PagePartsConfigEntry & {
179
+ contractName: string;
180
+ propNames: string[];
181
+ structuralTags?: Array<{
182
+ name: string;
183
+ phase?: string;
184
+ }>;
185
+ }>;
186
+ forEachInstances: Array<{
187
+ contractName: string;
188
+ forEachPath: string;
189
+ trackBy: string;
190
+ propBindings: Record<string, string>;
191
+ coordinateSuffix: string;
192
+ }>;
193
+ discoveredInstances?: any[];
194
+ }
195
+ interface ProductionPageParts {
196
+ parts: DevServerPagePart[];
197
+ headlessContracts: any[];
198
+ headlessInstanceComponents: HeadlessInstanceComponent[];
199
+ discoveredInstances: any[];
200
+ forEachInstances: ForEachHeadlessInstance[];
201
+ keyedPartModules: any[];
202
+ headlessModuleInfos: any[];
203
+ }
204
+ declare function loadPagePartsFromConfig(configPath: string, artifacts: ArtifactStore): Promise<ProductionPageParts>;
205
+
206
+ /** Thrown by `readCacheData` when an instance has no stored data (Design Log #227). */
207
+ declare class CacheNotFoundError extends Error {
208
+ readonly cachePath: string;
209
+ constructor(cachePath: string);
210
+ }
211
+ interface ListInstancesOptions {
212
+ /** Bypass the listing cache and re-read from the backing store. */
213
+ fresh?: boolean;
214
+ }
215
+ /**
216
+ * Interface for reading (and, optionally, updating) build artifacts at serve time (DL#143).
217
+ * FilesystemArtifactStore is the default implementation.
218
+ * BaaS deployments provide a custom implementation that fetches from cloud storage.
219
+ *
220
+ * Instances (Design Log #227): the manifest holds route structure only. A store resolves and
221
+ * enumerates the instances of a route itself; an instance's cache item is its own index entry, so
222
+ * writing one creates the instance and removing one deletes it — callers never touch a list.
223
+ */
224
+ interface ArtifactStore {
225
+ readManifest(): Promise<RouteManifest>;
226
+ /** Throws {@link CacheNotFoundError} when the instance has no stored data. */
227
+ readCacheData(relativePath: string): Promise<CacheEntry>;
228
+ readPagePartsConfig(relativePath: string): Promise<PagePartsConfig>;
229
+ loadServerElement(relativePath: string): Promise<ServerElementModule>;
230
+ loadModule(modulePath: string, local?: boolean): Promise<any>;
231
+ getAssetPath(relativePath: string): string;
232
+ getBuildDir(): string;
233
+ /** Resolve the instance of `route` for `params`; `undefined` when it does not exist. */
234
+ getInstance(route: RouteEntry, params: Record<string, string>): Promise<InstanceEntry | undefined>;
235
+ /**
236
+ * Enumerate the instances of a route (sitemap, llms.txt, rebuild-all). Stores page through
237
+ * their backend and may serve a TTL-cached listing; `{ fresh: true }` re-reads.
238
+ */
239
+ listInstances(route: RouteEntry, options?: ListInstancesOptions): AsyncIterable<InstanceRef>;
240
+ /**
241
+ * Upsert an instance's data at its derived path and keep the store's instance index consistent
242
+ * (Design Log #226/#227). Absent → the store is read-only: refresh / render-on-miss are disabled.
243
+ */
244
+ writeCacheData?(route: RouteEntry, params: Record<string, string>, entry: CacheEntry): Promise<void>;
245
+ /** Remove an instance's data and index membership. */
246
+ removeInstance?(route: RouteEntry, params: Record<string, string>): Promise<void>;
247
+ /** Re-read an entry bypassing any local copy (shared stores: another server may have refreshed it). */
248
+ readCacheDataFresh?(relativePath: string): Promise<CacheEntry>;
249
+ }
250
+ /** The JSON stored for an instance: data + freshness + its own index fields. */
251
+ declare function serializeCacheEntry(route: Pick<RouteEntry, 'pattern'>, params: Record<string, string>, entry: CacheEntry): string;
252
+ /** Parse stored cache JSON into a CacheEntry. */
253
+ declare function parseCacheEntry(json: string): CacheEntry;
254
+ interface FilesystemArtifactStoreOptions {
255
+ /** Lifetime of cached instance listings (default 10 min). */
256
+ listTtlMs?: number;
257
+ /** Clock, for tests. */
258
+ now?: () => number;
259
+ }
260
+ declare class FilesystemArtifactStore implements ArtifactStore {
261
+ private basePath;
262
+ private manifestCache?;
263
+ private metadataMtime?;
264
+ private moduleCache;
265
+ private readonly listCache;
266
+ constructor(basePath: string, options?: FilesystemArtifactStoreOptions);
267
+ readManifest(): Promise<RouteManifest>;
268
+ readCacheData(relativePath: string): Promise<CacheEntry>;
269
+ readPagePartsConfig(relativePath: string): Promise<PagePartsConfig>;
270
+ loadServerElement(relativePath: string): Promise<ServerElementModule>;
271
+ getAssetPath(relativePath: string): string;
272
+ getBuildDir(): string;
273
+ getInstance(route: RouteEntry, params: Record<string, string>): Promise<InstanceEntry | undefined>;
274
+ listInstances(route: RouteEntry, options?: ListInstancesOptions): AsyncIterable<InstanceRef>;
275
+ writeCacheData(route: RouteEntry, params: Record<string, string>, entry: CacheEntry): Promise<void>;
276
+ removeInstance(route: RouteEntry, params: Record<string, string>): Promise<void>;
277
+ loadModule(modulePath: string, local?: boolean): Promise<any>;
278
+ /** Scan a route's directory for `*.cache.json` and read each instance's params. */
279
+ private scanInstances;
280
+ }
281
+
282
+ /** A route whose segments match a request path (before the instance is resolved). */
283
+ interface RouteMatch {
284
+ route: RouteEntry;
285
+ params: Record<string, string>;
286
+ pathname: string;
287
+ }
288
+ /** A matched route with its resolved instance. */
289
+ interface MatchResult {
290
+ route: RouteEntry;
291
+ instance: InstanceEntry;
292
+ params: Record<string, string>;
293
+ pathname: string;
294
+ }
295
+ /**
296
+ * Every route whose segments match `pathname`, in manifest (specificity) order, with the extracted
297
+ * params. The instance is resolved separately through the store (`getInstance`), so a route can
298
+ * match without an instance existing — that is the render-on-miss case (Design Log #227).
299
+ */
300
+ declare function matchRoutes(manifest: RouteManifest, pathname: string): Generator<RouteMatch>;
301
+
302
+ /**
303
+ * In-memory negative cache for render-on-miss (Design Log #227).
304
+ *
305
+ * Remembers that slow render answered a real 404 for `(route, params)` so repeated requests for the
306
+ * same unknown instance cost nothing. Only genuine 404s are added — never errors or timeouts.
307
+ * Per server instance; entries expire after `ttlMs` and the oldest are evicted beyond `maxEntries`.
308
+ */
309
+ declare class NegativeCache {
310
+ private readonly ttlMs;
311
+ private readonly maxEntries;
312
+ private readonly entries;
313
+ constructor(ttlMs?: number, maxEntries?: number);
314
+ has(key: string, now: number): boolean;
315
+ add(key: string, now: number): void;
316
+ /** Forget a key (e.g. when the instance turned out to exist). */
317
+ delete(key: string): void;
318
+ get size(): number;
319
+ }
320
+
321
+ /**
322
+ * Outcome of running the slow phase for one instance (Design Log #226/#227).
323
+ *
324
+ * - `rendered` — a fresh cache entry (with `renderedAt` / `ttl` / `grace`). Nothing is persisted here.
325
+ * - `notFound` — slow render answered a deterministic client error (404, 410, 400, 422, …): the item
326
+ * cannot be rendered for these params, exactly like the build, which skips them.
327
+ * - `redirect` — slow render returned a redirect (e.g. a renamed slug): served as that redirect.
328
+ * - `error` — anything else (5xx, 401/403/408/429, thrown): transient, never negative-cached.
329
+ */
330
+ type RenderInstanceOutcome = {
331
+ kind: 'rendered';
332
+ entry: CacheEntry;
333
+ } | {
334
+ kind: 'notFound';
335
+ } | {
336
+ kind: 'redirect';
337
+ status: number;
338
+ location: string;
339
+ } | {
340
+ kind: 'error';
341
+ reason: string;
342
+ };
343
+ type RenderInstanceFn = (route: RouteEntry, params: Record<string, string>, artifacts: ArtifactStore, now: number) => Promise<RenderInstanceOutcome>;
344
+
345
+ /** Result of asking for a background refresh of an existing instance. */
346
+ type RefreshStart =
347
+ /** A refresh is running (started now, or joined an in-flight one). `done` never rejects. */
348
+ {
349
+ kind: 'started' | 'joined';
350
+ done: Promise<CacheEntry | undefined>;
351
+ }
352
+ /** All slow-render slots are taken by other instances — nothing started, nothing queued. */
353
+ | {
354
+ kind: 'busy';
355
+ }
356
+ /** Refresh is not possible right now: store is read-only, or the instance is in failure backoff. */
357
+ | {
358
+ kind: 'skipped';
359
+ };
360
+ /** Result of render-on-miss for an instance that does not exist yet (Design Log #227). */
361
+ type MissOutcome = {
362
+ kind: 'rendered';
363
+ instance: InstanceEntry;
364
+ }
365
+ /** The item does not exist (slow render answered a deterministic 4xx, e.g. 404). */
366
+ | {
367
+ kind: 'notFound';
368
+ }
369
+ /** Slow render redirected (e.g. renamed slug): respond with this redirect. */
370
+ | {
371
+ kind: 'redirect';
372
+ status: number;
373
+ location: string;
374
+ }
375
+ /** Could not render now: no free slot, timeout, error, or backoff. Respond 503 + Retry-After. */
376
+ | {
377
+ kind: 'unavailable';
378
+ retryAfterSeconds: number;
379
+ };
380
+ interface InstanceRendererOptions {
381
+ /** Max concurrent slow renders (refresh + miss). Env `JAY_SLOW_RENDER_CONCURRENCY`, default 5. */
382
+ concurrency?: number;
383
+ /** Max wait of a render-on-miss. Env `JAY_MISS_TIMEOUT_MS`, default 8000. */
384
+ missTimeoutMs?: number;
385
+ retryAfterSeconds?: number;
386
+ negativeCache?: NegativeCache;
387
+ now?: () => number;
388
+ /** Slow-render function (tests inject fakes). */
389
+ render?: RenderInstanceFn;
390
+ }
391
+ /**
392
+ * Runs the slow phase for single instances in production (Design Log #226 / #227).
393
+ *
394
+ * - **Single-flight**: all concurrent requests for one instance (same route + params → same key)
395
+ * share one slow render, one slot and one write; followers never take a slot.
396
+ * - **Fixed slots, no queue**: at most `concurrency` renders run at once. When all slots are taken
397
+ * by other instances a refresh answers `busy` (the caller serves the old data) and a miss answers
398
+ * `unavailable` (the caller responds 503). Nothing is ever queued.
399
+ * - **Backoff**: a failed render puts the instance into exponential backoff.
400
+ * - **Negative cache**: a deterministic 4xx (404, 410, 400, 422, …) and redirects are remembered
401
+ * (10 min); transient errors (401/403/408/429, 5xx, thrown) never are.
402
+ *
403
+ * Persisting goes through the {@link ArtifactStore} (`writeCacheData` / `removeInstance`), so the
404
+ * same code serves the filesystem and shared stores.
405
+ */
406
+ declare class InstanceRenderer {
407
+ private readonly store;
408
+ private readonly concurrency;
409
+ private readonly missTimeoutMs;
410
+ private readonly retryAfterSeconds;
411
+ private readonly negativeCache;
412
+ private readonly now;
413
+ private readonly render;
414
+ private readonly flights;
415
+ private readonly backoff;
416
+ private readonly redirects;
417
+ private slotsInUse;
418
+ private busyCount;
419
+ constructor(store: ArtifactStore, options?: InstanceRendererOptions);
420
+ /** True when the store can persist rendered instances (otherwise refresh / render-on-miss are off). */
421
+ get canWrite(): boolean;
422
+ /** Monitoring counters. */
423
+ stats(): {
424
+ slotsInUse: number;
425
+ inFlight: number;
426
+ busy: number;
427
+ negativeEntries: number;
428
+ };
429
+ /**
430
+ * Refresh an existing instance in the background. Never waits for a slot and never throws.
431
+ * Callers may await `done` (only for `started` / `joined`) up to their own budget.
432
+ */
433
+ refresh(route: RouteEntry, params: Record<string, string>): RefreshStart;
434
+ /**
435
+ * Serve an instance that does not exist yet: render it once for all concurrent requests,
436
+ * persist it, and return the synthesized instance. A real 404 is negative-cached.
437
+ */
438
+ renderMissing(route: RouteEntry, params: Record<string, string>): Promise<MissOutcome>;
439
+ /** True when `(route, params)` is remembered as non-existent. */
440
+ isKnownMissing(route: RouteEntry, params: Record<string, string>): boolean;
441
+ private unavailable;
442
+ private inBackoff;
443
+ private startFlight;
444
+ private runFlight;
445
+ private rememberRedirect;
446
+ private recordFailure;
447
+ private toEntry;
448
+ private withTimeout;
449
+ }
450
+
451
+ type ResolveResult = {
452
+ kind: 'matched';
453
+ match: MatchResult;
454
+ }
455
+ /** No route/instance matches (and none could be rendered): respond with the 404 page. */
456
+ | {
457
+ kind: 'notFound';
458
+ }
459
+ /** The slow render of an unknown instance redirected: respond with this redirect. */
460
+ | {
461
+ kind: 'redirect';
462
+ status: number;
463
+ location: string;
464
+ }
465
+ /**
466
+ * An unknown instance could not be rendered right now (no free slow-render slot, timeout, error):
467
+ * respond `503` with `Retry-After`. Never cached — we cannot tell whether the item exists.
468
+ */
469
+ | {
470
+ kind: 'unavailable';
471
+ retryAfterSeconds: number;
472
+ };
473
+ /**
474
+ * Resolve a request path to a route + instance (Design Log #227).
475
+ *
476
+ * For each route whose segments match (in specificity order) the store resolves the instance. A
477
+ * matching route without an instance is rendered on demand through the {@link InstanceRenderer}
478
+ * (single-flight, shared slow-render slots, negative cache). A real 404 falls through to the next
479
+ * matching route, exactly like "no instance" did before; no renderer means build-time-only
480
+ * instances (the previous behavior).
481
+ */
482
+ declare function resolveRequest(manifest: RouteManifest, pathname: string, store: ArtifactStore, renderer?: InstanceRenderer): Promise<ResolveResult>;
483
+
484
+ /** Default lifetime of cached instance listings: 10 minutes (Design Log #227, A3). */
485
+ declare const DEFAULT_LIST_TTL_MS: number;
486
+ /**
487
+ * Small stale-while-revalidate cache for expensive, rarely-needed reads such as instance listings
488
+ * (Design Log #227). Within `ttlMs` the cached value is returned; past it the stale value is
489
+ * returned immediately while one background reload runs (single-flight). `fresh: true` awaits a
490
+ * reload. A failed background reload keeps the previous value.
491
+ */
492
+ declare class SwrCache<V> {
493
+ private readonly ttlMs;
494
+ private readonly now;
495
+ private readonly entries;
496
+ private readonly inflight;
497
+ constructor(ttlMs?: number, now?: () => number);
498
+ get(key: string, load: () => Promise<V>, fresh?: boolean): Promise<V>;
499
+ /** Forget a key so the next `get` reloads (e.g. after a local write). */
500
+ invalidate(key: string): void;
501
+ private reload;
502
+ }
503
+
504
+ /**
505
+ * Instance identity (Design Log #227): an instance of a route is identified by its params, and its
506
+ * data lives at a deterministic path derived from `(route pattern, params)`. Build, rebuild,
507
+ * refresh and render-on-miss all derive the path through this one module, so they agree.
508
+ */
509
+ /** Stable JSON of params (keys sorted) — the canonical form hashed into the instance id. */
510
+ declare function canonicalParams(params: Record<string, string>): string;
511
+ /** Key for maps/sets of instances of one route: `<pattern>:<canonical params>`. */
512
+ declare function instanceKey(routePattern: string, params: Record<string, string>): string;
513
+ /** Directory (relative to the backend dir) holding a route's instance files and page-parts.json. */
514
+ declare function routeInstanceDir(routePattern: string): string;
515
+ /** Path (relative to the backend dir) of an instance's cache data. */
516
+ declare function deriveCachePath(routePattern: string, params: Record<string, string>): string;
517
+ /**
518
+ * The instance entry for `(route, params)`. Everything except `params`/`cachePath` is route-level
519
+ * (server element, client bundle, CSS), so nothing per-instance is stored beyond the data itself.
520
+ */
521
+ declare function synthesizeInstance(route: Pick<RouteEntry, 'pattern' | 'serverElementPath' | 'routeClientBundlePath' | 'routeCssPath'>, params: Record<string, string>): InstanceEntry;
522
+ declare function toInstanceRef(route: Pick<RouteEntry, 'pattern'>, params: Record<string, string>): InstanceRef;
523
+
524
+ declare function fetchPageRequest(match: MatchResult, manifest: RouteManifest, requestUrl: URL, artifacts: ArtifactStore, staticBaseUrl: string, cookies?: Record<string, string>, renderer?: InstanceRenderer): Promise<Response>;
525
+
526
+ declare function isActionRequest(pathname: string): boolean;
527
+ declare function fetchActionRequest(request: Request, registry?: ActionRegistry): Promise<Response>;
528
+ declare function registerActionsFromManifest(actions: Array<{
529
+ serverModule: string;
530
+ isPlugin: boolean;
531
+ actionNames: string[];
532
+ packageName?: string;
533
+ }>, buildDir: string, registry?: ActionRegistry): Promise<void>;
534
+ /**
535
+ * Register actions from pre-imported modules (DL#143).
536
+ * Used by BaaS entry.mjs where action modules are bundled by esbuild.
537
+ */
538
+ declare function registerActionsFromModules(modules: Array<{
539
+ module: Record<string, unknown>;
540
+ name: string;
541
+ }>, registry?: ActionRegistry): Promise<void>;
542
+
543
+ declare function fetchStaticFile(pathname: string, frontendDir: string): Promise<Response | null>;
544
+
545
+ interface PreImportedPlugin {
546
+ name: string;
547
+ init: {
548
+ _serverInit: () => Promise<any>;
549
+ };
550
+ }
551
+ /**
552
+ * Initialize services from pre-imported plugin modules (DL#143).
553
+ * Used by BaaS entry.mjs where plugins are bundled by esbuild
554
+ * and cannot be discovered from the filesystem at runtime.
555
+ */
556
+ declare function initializeServicesFromModules(plugins: PreImportedPlugin[], label: string): Promise<void>;
557
+ declare function initializeServices(buildDir: string, projectRoot: string, label: string): Promise<void>;
558
+
559
+ export { type ArtifactStore as A, type BuildMetadata as B, type CacheEntry as C, DEFAULT_LIST_TTL_MS as D, type ErrorPageEntry as E, FilesystemArtifactStore as F, parseCacheEntry as G, registerActionsFromManifest as H, type InstanceEntry as I, registerActionsFromModules as J, resolveRequest as K, type ListInstancesOptions as L, type MatchResult as M, routeInstanceDir as N, serializeCacheEntry as O, type PageModule as P, synthesizeInstance as Q, type RouteManifest as R, type ServerElementModule as S, toInstanceRef as T, type RouteEntry as a, type ActionEntry as b, type BuildOptions as c, CacheNotFoundError as d, type InstanceRef as e, InstanceRenderer as f, type InstanceRendererOptions as g, type MissOutcome as h, type PluginEntry as i, type PreImportedPlugin as j, type RefreshStart as k, type ResolveResult as l, type RouteMatch as m, type RouteSegment as n, SwrCache as o, canonicalParams as p, deriveCachePath as q, fetchActionRequest as r, fetchPageRequest as s, fetchStaticFile as t, initializeServices as u, initializeServicesFromModules as v, instanceKey as w, isActionRequest as x, loadPagePartsFromConfig as y, matchRoutes as z };
@@ -1,4 +1,4 @@
1
- export { A as ArtifactStore, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, e as PreImportedPlugin, a as RouteEntry, R as RouteManifest, S as ServerElementModule, g as fetchActionRequest, h as fetchPageRequest, i as fetchStaticFile, j as initializeServices, k as initializeServicesFromModules, l as isActionRequest, n as matchRequest, r as registerActionsFromManifest, o as registerActionsFromModules } from './serve-index-C28bP6tW.js';
1
+ export { A as ArtifactStore, C as CacheEntry, d as CacheNotFoundError, D as DEFAULT_LIST_TTL_MS, F as FilesystemArtifactStore, I as InstanceEntry, e as InstanceRef, f as InstanceRenderer, g as InstanceRendererOptions, L as ListInstancesOptions, M as MatchResult, h as MissOutcome, j as PreImportedPlugin, k as RefreshStart, l as ResolveResult, a as RouteEntry, R as RouteManifest, m as RouteMatch, S as ServerElementModule, o as SwrCache, p as canonicalParams, q as deriveCachePath, r as fetchActionRequest, s as fetchPageRequest, t as fetchStaticFile, u as initializeServices, v as initializeServicesFromModules, w as instanceKey, x as isActionRequest, z as matchRoutes, G as parseCacheEntry, H as registerActionsFromManifest, J as registerActionsFromModules, K as resolveRequest, N as routeInstanceDir, O as serializeCacheEntry, Q as synthesizeInstance, T as toInstanceRef } from './serve-index-D5MDxOoW.js';
2
2
  import '@jay-framework/ssr-runtime';
3
3
  import '@jay-framework/stack-server-runtime';
4
4
  import '@jay-framework/fullstack-component';
@@ -1,13 +1,26 @@
1
- import { F, f, a, b, i, c, d, m, r, e } from "./init-services-CG_wDJmY.js";
1
+ import { C, D, F, I, S, c, d, f, a, b, i, e, g, h, m, p, r, j, k, l, s, n, t } from "./init-services-CItlWIEg.js";
2
2
  export {
3
+ C as CacheNotFoundError,
4
+ D as DEFAULT_LIST_TTL_MS,
3
5
  F as FilesystemArtifactStore,
6
+ I as InstanceRenderer,
7
+ S as SwrCache,
8
+ c as canonicalParams,
9
+ d as deriveCachePath,
4
10
  f as fetchActionRequest,
5
11
  a as fetchPageRequest,
6
12
  b as fetchStaticFile,
7
13
  i as initializeServices,
8
- c as initializeServicesFromModules,
9
- d as isActionRequest,
10
- m as matchRequest,
14
+ e as initializeServicesFromModules,
15
+ g as instanceKey,
16
+ h as isActionRequest,
17
+ m as matchRoutes,
18
+ p as parseCacheEntry,
11
19
  r as registerActionsFromManifest,
12
- e as registerActionsFromModules
20
+ j as registerActionsFromModules,
21
+ k as resolveRequest,
22
+ l as routeInstanceDir,
23
+ s as serializeCacheEntry,
24
+ n as synthesizeInstance,
25
+ t as toInstanceRef
13
26
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/production-server",
3
- "version": "0.25.5",
3
+ "version": "0.26.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,18 +30,18 @@
30
30
  "test:watch": "vitest"
31
31
  },
32
32
  "dependencies": {
33
- "@jay-framework/fullstack-component": "^0.25.5",
34
- "@jay-framework/logger": "^0.25.5",
35
- "@jay-framework/ssr-runtime": "^0.25.5",
36
- "@jay-framework/stack-server-runtime": "^0.25.5",
37
- "@jay-framework/view-state-merge": "^0.25.5"
33
+ "@jay-framework/fullstack-component": "^0.26.0",
34
+ "@jay-framework/logger": "^0.26.0",
35
+ "@jay-framework/ssr-runtime": "^0.26.0",
36
+ "@jay-framework/stack-server-runtime": "^0.26.0",
37
+ "@jay-framework/view-state-merge": "^0.26.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@jay-framework/dev-environment": "^0.25.5",
40
+ "@jay-framework/dev-environment": "^0.26.0",
41
41
  "@types/node": "^22.15.21",
42
42
  "rimraf": "^5.0.5",
43
43
  "tsup": "^8.0.1",
44
44
  "typescript": "^5.3.3",
45
- "vitest": "^1.2.1"
45
+ "vitest": "^4.1.11"
46
46
  }
47
47
  }