@stratal/inertia 0.0.22 → 0.0.24

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.
Files changed (38) hide show
  1. package/README.md +33 -1
  2. package/dist/build-seo-tags-DBsHKxX9.mjs +123 -0
  3. package/dist/build-seo-tags-DBsHKxX9.mjs.map +1 -0
  4. package/dist/{decorate-CzXVx7ZH.mjs → decorate-B7nr7eBl.mjs} +1 -1
  5. package/dist/generator/type-generator.worker.mjs +1 -1
  6. package/dist/generator/type-generator.worker.mjs.map +1 -1
  7. package/dist/index.d.mts +209 -78
  8. package/dist/index.d.mts.map +1 -1
  9. package/dist/index.mjs +274 -60
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/quarry.d.mts +9 -0
  12. package/dist/quarry.d.mts.map +1 -1
  13. package/dist/quarry.mjs +56 -9
  14. package/dist/quarry.mjs.map +1 -1
  15. package/dist/react.d.mts +15 -3
  16. package/dist/react.d.mts.map +1 -1
  17. package/dist/react.mjs +21 -8
  18. package/dist/react.mjs.map +1 -1
  19. package/dist/seo-runtime.d.mts +1 -0
  20. package/dist/seo-runtime.mjs +56 -0
  21. package/dist/seo-runtime.mjs.map +1 -0
  22. package/dist/ssr.d.mts +65 -0
  23. package/dist/ssr.d.mts.map +1 -0
  24. package/dist/ssr.mjs +56 -0
  25. package/dist/ssr.mjs.map +1 -0
  26. package/dist/testing.d.mts +1 -1
  27. package/dist/testing.mjs.map +1 -1
  28. package/dist/{type-generator-bfo14BJI.mjs → type-generator-DFpha_Fp.mjs} +178 -28
  29. package/dist/type-generator-DFpha_Fp.mjs.map +1 -0
  30. package/dist/types-BhgXhWx6.d.mts +82 -0
  31. package/dist/types-BhgXhWx6.d.mts.map +1 -0
  32. package/dist/types-DzE1pdZs.d.mts +76 -0
  33. package/dist/types-DzE1pdZs.d.mts.map +1 -0
  34. package/dist/vite.d.mts.map +1 -1
  35. package/dist/vite.mjs +22 -2
  36. package/dist/vite.mjs.map +1 -1
  37. package/package.json +27 -18
  38. package/dist/type-generator-bfo14BJI.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/augment/router-context.ts","../src/inertia.tokens.ts","../src/middleware/inertia.middleware.ts","../src/types.ts","../src/services/inertia.service.ts","../src/services/manifest.service.ts","../src/services/ssr-renderer.service.ts","../src/services/template.service.ts","../src/inertia.module.ts","../src/flash/cookie-flash-store.ts","../src/decorators/inertia.decorators.ts","../src/middleware/handle-precognitive-requests.middleware.ts"],"sourcesContent":["import type { RedirectStatusCode } from 'hono/utils/http-status'\nimport { RouterContext } from 'stratal/router'\nimport type { InertiaService } from '../services/inertia.service'\nimport type {\n InertiaAlwaysProp,\n InertiaDeferredProp,\n InertiaMergeProp,\n InertiaMergeStrategy,\n InertiaOnceProp,\n InertiaOptionalProp,\n InertiaPageComponent,\n InertiaPageRegistry,\n InertiaRenderOptions,\n ResolvedInertiaPageProps,\n} from '../types'\n\nexport interface InertiaMergeOptions {\n strategy?: InertiaMergeStrategy\n matchOn?: string\n}\n\nexport interface InertiaOnceOptions {\n expiresAt?: number | null\n key?: string\n}\n\ndeclare module 'stratal/router' {\n interface RouterContext {\n /** Renders an Inertia page component with the given props and returns an HTTP response. */\n inertia<C extends InertiaPageComponent>(\n component: C,\n ...args: keyof InertiaPageRegistry extends never\n ? [props?: Record<string, unknown>, options?: InertiaRenderOptions]\n : Record<string, never> extends ResolvedInertiaPageProps<C>\n ? [props?: ResolvedInertiaPageProps<C>, options?: InertiaRenderOptions]\n : [props: ResolvedInertiaPageProps<C>, options?: InertiaRenderOptions]\n ): Promise<Response>\n /** Creates a deferred prop that is resolved after the initial page render, optionally grouped for batch loading. */\n defer<T>(callback: () => T, group?: string): InertiaDeferredProp<T>\n /** Creates an optional prop that is only included in the response when explicitly requested by the client. */\n optional<T>(callback: () => T): InertiaOptionalProp<T>\n /** Creates a mergeable prop that merges with existing client-side page data instead of replacing it. */\n merge<T>(callback: () => T, options?: InertiaMergeOptions): InertiaMergeProp<T>\n /** Creates a prop that is only sent on the first visit and cached for subsequent requests. */\n once<T>(callback: () => T, options?: InertiaOnceOptions): InertiaOnceProp<T>\n /** Creates a prop that is always evaluated and included, even on partial reload requests. */\n always<T>(callback: () => T): InertiaAlwaysProp<T>\n /** Sets a flash data entry that will be available on the next page visit. */\n flash(key: string, value: unknown): void\n /** Disables server-side rendering for the current request. */\n withoutSsr(): void\n }\n}\n\nexport function augmentRouterContext(resolveService: (ctx: RouterContext) => InertiaService): void {\n // Override redirect to auto-convert 302 → 303 for non-GET/HEAD requests\n // so the browser follows with GET instead of preserving the original method\n // eslint-disable-next-line @typescript-eslint/unbound-method -- intentionally saving reference, called with .call(this)\n const originalRedirect = RouterContext.prototype.redirect\n RouterContext.macro('redirect', function (this: RouterContext, url: string, status?: RedirectStatusCode) {\n if (!status || status === 302) {\n const method = this.c.req.method\n if (method !== 'GET' && method !== 'HEAD') {\n return originalRedirect.call(this, url, 303)\n }\n }\n return originalRedirect.call(this, url, status)\n })\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RouterContext.macro('inertia', function (this: RouterContext, component: string, props?: any, options?: InertiaRenderOptions) {\n const service = resolveService(this)\n return service.render(this, component, props as Record<string, unknown>, options)\n })\n\n RouterContext.macro('defer', function <T>(this: RouterContext, callback: () => T, group?: string) {\n const service = resolveService(this)\n return service.defer(callback, group)\n })\n\n RouterContext.macro('optional', function <T>(this: RouterContext, callback: () => T) {\n const service = resolveService(this)\n return service.optional(callback)\n })\n\n RouterContext.macro('merge', function <T>(this: RouterContext, callback: () => T, options?: InertiaMergeOptions) {\n const service = resolveService(this)\n return service.merge(callback, options)\n })\n\n RouterContext.macro('once', function <T>(this: RouterContext, callback: () => T, options?: InertiaOnceOptions) {\n const service = resolveService(this)\n return service.once(callback, options)\n })\n\n RouterContext.macro('always', function <T>(this: RouterContext, callback: () => T) {\n const service = resolveService(this)\n return service.always(callback)\n })\n\n RouterContext.macro('flash', function (this: RouterContext, key: string, value: unknown) {\n const flashOut = this.c.get('inertiaFlashOut') as Record<string, unknown> | undefined\n if (flashOut) {\n flashOut[key] = value\n }\n })\n\n RouterContext.macro('withoutSsr', function (this: RouterContext) {\n this.c.set('withoutSsr', true)\n })\n}\n","export const INERTIA_TOKENS = {\n Options: Symbol.for('stratal:inertia:options'),\n InertiaService: Symbol.for('stratal:inertia:service'),\n TemplateService: Symbol.for('stratal:inertia:template'),\n ManifestService: Symbol.for('stratal:inertia:manifest'),\n SsrRenderer: Symbol.for('stratal:inertia:ssr-renderer'),\n} as const\n","import { Transient, inject } from 'stratal/di'\nimport type { Middleware, Next, RouterContext } from 'stratal/router'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\n\n@Transient()\nexport class InertiaMiddleware implements Middleware {\n constructor(\n @inject(INERTIA_TOKENS.Options) private readonly options: InertiaModuleOptions,\n ) { }\n\n async handle(ctx: RouterContext, next: Next): Promise<void> {\n const isInertia = ctx.header('x-inertia') === 'true'\n const isPrefetch = ctx.header('purpose') === 'prefetch'\n\n // Store Inertia state on context for services to access\n ctx.c.set('inertia', isInertia)\n ctx.c.set('inertiaPrefetch', isPrefetch)\n ctx.c.set('withoutSsr', false)\n\n // Initialize flash buckets\n ctx.c.set('inertiaFlashOut', {})\n\n // Read incoming flash data from store (read-only — no response headers touched)\n let hadFlash = false\n if (this.options.flash) {\n const flashData = await this.options.flash.store.read(ctx)\n hadFlash = Object.keys(flashData).length > 0\n ctx.c.set('inertiaFlash', flashData)\n } else {\n ctx.c.set('inertiaFlash', {})\n }\n\n // Version mismatch check on GET requests\n if (isInertia && ctx.c.req.method === 'GET') {\n const clientVersion = ctx.header('x-inertia-version')\n const serverVersion = this.options.version ?? ''\n\n if (clientVersion && serverVersion && clientVersion !== serverVersion) {\n ctx.c.header('X-Inertia-Location', ctx.c.req.url)\n ctx.c.status(409)\n return\n }\n }\n\n await next()\n\n // Flash cookie operations AFTER next() — ctx.c.res is now the actual Response,\n // so setSignedCookie/deleteCookie will modify the real response headers.\n if (this.options.flash) {\n const flashOut = ctx.c.get('inertiaFlashOut')\n if (Object.keys(flashOut).length > 0) {\n // New flash data was set during this request — write cookie for next request\n await this.options.flash.store.write(ctx, flashOut)\n } else if (hadFlash) {\n // Flash was consumed but no new flash set — clear the cookie\n await this.options.flash.store.clear(ctx)\n }\n }\n\n // Skip response mutation for statuses Hono can't clone (e.g. 101 WebSocket\n // upgrades, Response.error()'s status 0). `c.header()` would otherwise call\n // `new Response(c.res.body, c.res)` and the Response constructor throws a\n // RangeError for any status outside 200-599.\n const status = ctx.c.res?.status\n if (typeof status !== 'number' || status < 200 || status > 599) return\n\n // Add Vary header to all responses\n ctx.c.header('Vary', 'X-Inertia')\n\n // Convert 302 to 303 for non-GET/HEAD Inertia requests\n if (isInertia && status === 302) {\n const method = ctx.c.req.method\n if (method !== 'GET' && method !== 'HEAD') {\n ctx.c.status(303)\n }\n }\n }\n}\n","import type { InertiaAppSSRResponse, Page, SharedPageProps } from '@inertiajs/core'\nimport type { ContentfulStatusCode } from 'hono/utils/http-status'\nimport type { RouterContext } from 'stratal/router'\n\n\nexport interface InertiaPageRegistry {}\n\n// Derive shared props from @inertiajs/core's InertiaConfig.sharedPageProps.\n// Users augment InertiaConfig in their global.d.ts — this type stays in sync automatically.\nexport type InertiaSharedProps = SharedPageProps\n\nexport type InertiaPageComponent = keyof InertiaPageRegistry extends never\n ? string\n : Extract<keyof InertiaPageRegistry, string>\n\n// Allows each prop value to be wrapped with defer/merge/optional/once/always\ntype AllowInertiaWrappers<T> = {\n [K in keyof T]: T[K] | InertiaDeferredProp | InertiaMergeProp | InertiaOptionalProp | InertiaOnceProp | InertiaAlwaysProp\n}\n\n// Props the controller passes to ctx.inertia() — page-specific only, shared props are auto-injected\n// Each prop can be the raw value OR a deferred/merge/optional/once/always wrapper\nexport type ResolvedInertiaPageProps<C extends InertiaPageComponent> =\n C extends keyof InertiaPageRegistry ? AllowInertiaWrappers<InertiaPageRegistry[C]> : Record<string, unknown>\n\n// Full props the React page component receives — page-specific + shared (auto-injected), no wrappers\nexport type InertiaFullPageProps<C extends InertiaPageComponent> =\n (C extends keyof InertiaPageRegistry ? InertiaPageRegistry[C] : Record<string, unknown>) & InertiaSharedProps\n\n// Re-export Page from @inertiajs/core as InertiaPage for convenience\nexport type { Page as InertiaPage } from '@inertiajs/core'\n\nexport interface InertiaRenderOptions {\n encryptHistory?: boolean\n clearHistory?: boolean\n preserveFragment?: boolean\n /**\n * HTTP status code to use for the rendered response. Defaults to `200`.\n * Useful for rendering Inertia error pages (e.g. `Errors/404` with status 404).\n */\n status?: ContentfulStatusCode\n}\n\n// Use InertiaAppSSRResponse from @inertiajs/core — { head: string[]; body: string }\nexport type InertiaSsrResult = InertiaAppSSRResponse\n\nexport interface InertiaSsrBundle {\n render(page: Page): Promise<InertiaSsrResult>\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SharedDataResolver = (ctx: RouterContext) => any\n\nexport interface ViteManifestEntry {\n file: string\n css?: string[]\n isEntry?: boolean\n imports?: string[]\n dynamicImports?: string[]\n src?: string\n}\n\nexport type ViteManifest = Record<string, ViteManifestEntry>\n\nexport const INERTIA_PROP_OPTIONAL = Symbol.for('stratal:inertia:prop:optional')\nexport const INERTIA_PROP_DEFERRED = Symbol.for('stratal:inertia:prop:deferred')\nexport const INERTIA_PROP_MERGE = Symbol.for('stratal:inertia:prop:merge')\nexport const INERTIA_PROP_ONCE = Symbol.for('stratal:inertia:prop:once')\nexport const INERTIA_PROP_ALWAYS = Symbol.for('stratal:inertia:prop:always')\n\nexport interface InertiaOptionalProp<T = unknown> {\n [INERTIA_PROP_OPTIONAL]: true\n callback: () => T\n}\n\nexport interface InertiaDeferredProp<T = unknown> {\n [INERTIA_PROP_DEFERRED]: true\n callback: () => T\n group: string\n}\n\nexport type InertiaMergeStrategy = 'append' | 'prepend' | 'deep'\n\nexport interface InertiaMergeProp<T = unknown> {\n [INERTIA_PROP_MERGE]: true\n callback: () => T\n strategy: InertiaMergeStrategy\n matchOn?: string\n}\n\nexport interface InertiaOnceProp<T = unknown> {\n [INERTIA_PROP_ONCE]: true\n callback: () => T\n expiresAt?: number | null\n key?: string\n}\n\nexport interface InertiaAlwaysProp<T = unknown> {\n [INERTIA_PROP_ALWAYS]: true\n callback: () => T\n}\n","import type { Page } from '@inertiajs/core'\nimport type { Application } from 'stratal'\nimport { DI_TOKENS, Request, inject } from 'stratal/di'\nimport { I18N_TOKENS, type MessageLoaderService } from 'stratal/i18n'\nimport { ROUTER_TOKENS, type CurrentRoute, type RegisteredRoute, type RouteRegistry, type RouterContext, type SerializedRoutes, type Uri } from 'stratal/router'\nimport type { InertiaMergeOptions, InertiaOnceOptions } from '../augment/router-context'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\nimport type {\n InertiaAlwaysProp,\n InertiaDeferredProp,\n InertiaMergeProp,\n InertiaOnceProp,\n InertiaOptionalProp,\n InertiaRenderOptions,\n SharedDataResolver,\n} from '../types'\nimport {\n INERTIA_PROP_ALWAYS,\n INERTIA_PROP_DEFERRED,\n INERTIA_PROP_MERGE,\n INERTIA_PROP_ONCE,\n INERTIA_PROP_OPTIONAL,\n} from '../types'\nimport type { SsrRendererService } from './ssr-renderer.service'\nimport type { TemplateService } from './template.service'\n\n@Request(INERTIA_TOKENS.InertiaService)\nexport class InertiaService {\n private sharedData: Record<string, unknown> = {}\n\n constructor(\n @inject(INERTIA_TOKENS.Options) private readonly options: InertiaModuleOptions,\n @inject(INERTIA_TOKENS.TemplateService) private readonly template: TemplateService,\n @inject(INERTIA_TOKENS.SsrRenderer) private readonly ssr: SsrRendererService,\n ) { }\n\n share(key: string, value: unknown): void {\n this.sharedData[key] = value\n }\n\n location(url: string): Response {\n return new Response('', {\n status: 409,\n headers: { 'X-Inertia-Location': url },\n })\n }\n\n optional<T>(callback: () => T): InertiaOptionalProp<T> {\n return { [INERTIA_PROP_OPTIONAL]: true, callback }\n }\n\n defer<T>(callback: () => T, group = 'default'): InertiaDeferredProp<T> {\n return { [INERTIA_PROP_DEFERRED]: true, callback, group }\n }\n\n merge<T>(callback: () => T, options?: InertiaMergeOptions): InertiaMergeProp<T> {\n return {\n [INERTIA_PROP_MERGE]: true,\n callback,\n strategy: options?.strategy ?? 'append',\n matchOn: options?.matchOn,\n }\n }\n\n once<T>(callback: () => T, options?: InertiaOnceOptions): InertiaOnceProp<T> {\n return {\n [INERTIA_PROP_ONCE]: true,\n callback,\n expiresAt: options?.expiresAt ?? null,\n key: options?.key,\n }\n }\n\n always<T>(callback: () => T): InertiaAlwaysProp<T> {\n return { [INERTIA_PROP_ALWAYS]: true, callback }\n }\n\n async render(\n ctx: RouterContext,\n component: string,\n props: Record<string, unknown> = {},\n renderOptions: InertiaRenderOptions = {},\n ): Promise<Response> {\n const reqUrl = new URL(ctx.c.req.url)\n const url = reqUrl.search ? `${reqUrl.pathname}${reqUrl.search}` : reqUrl.pathname\n const isInertia = ctx.c.get('inertia')\n\n // Resolve shared data from module options\n const { shared: resolvedShared, sharedKeys } = await this.resolveSharedData(ctx)\n\n // Merge shared data with route props\n const allProps = { ...resolvedShared, ...this.sharedData, ...props }\n\n // Track all shared prop keys (module config + per-request .share())\n const allSharedKeys = [...sharedKeys, ...Object.keys(this.sharedData)]\n\n // Process props: handle optional, deferred, merge, once, always\n const result = await this.processProps(allProps, ctx, component, isInertia)\n\n // Read flash data from context (set by middleware)\n const rawFlash = (ctx.c.get('inertiaFlash') as Record<string, unknown> | undefined) ?? {}\n const { errors: flashErrors, ...flash } = rawFlash\n const errors = (flashErrors && typeof flashErrors === 'object' && !Array.isArray(flashErrors))\n ? flashErrors as Page['props']['errors']\n : {} as Page['props']['errors']\n\n const page: Page = {\n component,\n props: { ...result.resolvedProps, errors },\n url,\n version: this.options.version ?? null,\n flash,\n rememberedState: {},\n rescuedProps: [],\n ...(result.mergeProps.length > 0 ? { mergeProps: result.mergeProps } : {}),\n ...(result.prependProps.length > 0 ? { prependProps: result.prependProps } : {}),\n ...(result.deepMergeProps.length > 0 ? { deepMergeProps: result.deepMergeProps } : {}),\n ...(result.matchPropsOn.length > 0 ? { matchPropsOn: result.matchPropsOn } : {}),\n ...(Object.keys(result.deferredProps).length > 0 ? { deferredProps: result.deferredProps } : {}),\n ...(Object.keys(result.deferredProps).length > 0 && !this.isPartialReload(ctx, component) ? { initialDeferredProps: result.deferredProps } : {}),\n ...(Object.keys(result.onceProps).length > 0 ? { onceProps: result.onceProps } : {}),\n ...(allSharedKeys.length > 0 ? { sharedProps: allSharedKeys } : {}),\n ...(renderOptions.encryptHistory ? { encryptHistory: true } : {}),\n ...(renderOptions.clearHistory ? { clearHistory: true } : {}),\n ...(renderOptions.preserveFragment ? { preserveFragment: true } : {}),\n }\n\n const status = renderOptions.status ?? 200\n\n if (isInertia) {\n return new Response(JSON.stringify(page), {\n status,\n headers: {\n 'Content-Type': 'application/json',\n 'X-Inertia': 'true',\n 'Vary': 'X-Inertia',\n },\n })\n }\n\n // Full page render — skip SSR if disabled for this route\n const ssrDisabled = ctx.c.get('withoutSsr') || this.isSsrDisabled(url)\n const ssrResult = ssrDisabled\n ? { head: [] as string[], body: '' }\n : await this.ssr.render(page)\n const html = this.template.render(page, ssrResult.head, ssrResult.body)\n\n return new Response(html, {\n status,\n headers: {\n 'Content-Type': 'text/html; charset=utf-8',\n },\n })\n }\n\n /**\n * Resolve shared data from module options and i18n configuration.\n *\n * Processes static values and resolver functions from `sharedData` config.\n * When `i18n` option is set, auto-injects `locale` and `translations` props\n * using the core {@link MessageLoaderService} resolved from the request container.\n */\n private async resolveSharedData(ctx: RouterContext): Promise<{ shared: Record<string, unknown>; sharedKeys: string[] }> {\n const shared: Record<string, unknown> = {}\n const configShared = this.options.sharedData\n\n if (configShared) {\n for (const [key, value] of Object.entries(configShared)) {\n if (typeof value === 'function') {\n shared[key] = await (value as SharedDataResolver)(ctx)\n } else {\n shared[key] = value\n }\n }\n }\n\n if (this.options.i18n) {\n const loader = ctx.getContainer().resolve<MessageLoaderService>(I18N_TOKENS.MessageLoader)\n const locale = ctx.getLocale()\n shared.locale = locale\n shared.translations = loader.getFilteredMessages(locale, { only: this.options.i18n.only })\n }\n\n if (this.options.routes) {\n const container = ctx.getContainer()\n const registry = container.resolve<RouteRegistry>(ROUTER_TOKENS.RouteRegistry)\n const application = container.resolve<Application>(DI_TOKENS.Application)\n const uri = container.resolve<Uri>(ROUTER_TOKENS.Uri)\n\n const name = registry.findNameByRoute(ctx.c.req.method, ctx.c.req.routePath) ?? null\n const params = { ...ctx.param() }\n\n shared.routes = this.serializeRoutes(registry.named())\n shared.trailingSlash = application.config.trailingSlash ?? 'ignore'\n shared.route = { name, params, defaults: uri.getDefaults() } satisfies CurrentRoute\n }\n\n return { shared, sharedKeys: Object.keys(shared) }\n }\n\n private isPartialReload(ctx: RouterContext, component: string): boolean {\n const isInertia = ctx.c.get('inertia')\n const partialComponent = ctx.header('x-inertia-partial-component')\n const partialDataHeader = ctx.header('x-inertia-partial-data')\n return !!(isInertia && partialComponent === component && partialDataHeader)\n }\n\n private async processProps(\n allProps: Record<string, unknown>,\n ctx: RouterContext,\n component: string,\n isInertia: boolean,\n ): Promise<{\n resolvedProps: Record<string, unknown>\n mergeProps: string[]\n prependProps: string[]\n deepMergeProps: string[]\n matchPropsOn: string[]\n deferredProps: Record<string, string[]>\n onceProps: Record<string, { prop: string; expiresAt?: number | null }>\n }> {\n const resolvedProps: Record<string, unknown> = {}\n const mergeProps: string[] = []\n const prependProps: string[] = []\n const deepMergeProps: string[] = []\n const matchPropsOn: string[] = []\n const deferredProps: Record<string, string[]> = {}\n const onceProps: Record<string, { prop: string; expiresAt?: number | null }> = {}\n\n const partialComponent = ctx.header('x-inertia-partial-component')\n const partialDataHeader = ctx.header('x-inertia-partial-data')\n const partialExceptHeader = ctx.header('x-inertia-partial-except')\n const resetHeader = ctx.header('x-inertia-reset')\n const shouldResolveDeferred = ctx.header('x-inertia-resolve-deferred') === 'true'\n const isPartialReload = isInertia && partialComponent === component && partialDataHeader\n\n const requestedProps = partialDataHeader?.split(',').map((s) => s.trim()) ?? []\n const exceptProps = partialExceptHeader?.split(',').map((s) => s.trim()) ?? []\n const _resetProps = resetHeader?.split(',').map((s) => s.trim()) ?? []\n\n for (const [key, value] of Object.entries(allProps)) {\n // Handle always props — always resolve regardless of partial reload\n if (this.isAlwaysProp(value)) {\n resolvedProps[key] = await value.callback()\n continue\n }\n\n // Handle once props\n if (this.isOnceProp(value)) {\n if (isPartialReload && this.isRequested(key, requestedProps)) {\n resolvedProps[key] = await value.callback()\n } else if (!isPartialReload) {\n resolvedProps[key] = await value.callback()\n onceProps[key] = {\n prop: value.key ?? key,\n ...(value.expiresAt != null ? { expiresAt: value.expiresAt } : {}),\n }\n }\n continue\n }\n\n // Handle deferred props\n if (this.isDeferredProp(value)) {\n if (isPartialReload && this.isRequested(key, requestedProps)) {\n resolvedProps[key] = await value.callback()\n } else if (!isPartialReload) {\n if (shouldResolveDeferred) {\n resolvedProps[key] = await value.callback()\n } else {\n deferredProps[value.group] ??= []\n deferredProps[value.group].push(key)\n }\n }\n continue\n }\n\n // Handle merge props (append/prepend/deep)\n if (this.isMergeProp(value)) {\n if (isPartialReload && !this.isRequested(key, requestedProps)) {\n continue\n }\n\n switch (value.strategy) {\n case 'prepend':\n prependProps.push(key)\n break\n case 'deep':\n deepMergeProps.push(key)\n break\n default:\n mergeProps.push(key)\n break\n }\n\n if (value.matchOn) {\n matchPropsOn.push(`${key}:${value.matchOn}`)\n }\n\n resolvedProps[key] = await value.callback()\n continue\n }\n\n // Handle optional props\n if (this.isOptionalProp(value)) {\n if (isPartialReload && this.isRequested(key, requestedProps)) {\n resolvedProps[key] = await value.callback()\n }\n continue\n }\n\n // Regular props\n if (isPartialReload) {\n if (this.isRequested(key, requestedProps) && !this.isExcepted(key, exceptProps)) {\n resolvedProps[key] = value\n }\n } else {\n resolvedProps[key] = value\n }\n }\n\n return { resolvedProps, mergeProps, prependProps, deepMergeProps, matchPropsOn, deferredProps, onceProps }\n }\n\n /**\n * Check if a prop key is requested — supports dot-notation (e.g., `user.permissions`\n * matches the top-level `user` key).\n */\n private isRequested(key: string, requestedProps: string[]): boolean {\n return requestedProps.some((prop) => prop === key || prop.startsWith(`${key}.`))\n }\n\n private isExcepted(key: string, exceptProps: string[]): boolean {\n return exceptProps.some((prop) => prop === key || prop.startsWith(`${key}.`))\n }\n\n private isOptionalProp(value: unknown): value is InertiaOptionalProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_OPTIONAL in value\n }\n\n private isDeferredProp(value: unknown): value is InertiaDeferredProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_DEFERRED in value\n }\n\n private isMergeProp(value: unknown): value is InertiaMergeProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_MERGE in value\n }\n\n private isOnceProp(value: unknown): value is InertiaOnceProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_ONCE in value\n }\n\n private isAlwaysProp(value: unknown): value is InertiaAlwaysProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_ALWAYS in value\n }\n\n private serializeRoutes(routes: RegisteredRoute[]): SerializedRoutes {\n const serialized: SerializedRoutes = {}\n for (const route of routes) {\n if (route.name) {\n serialized[route.name] = {\n path: route.path,\n paramNames: route.paramNames,\n domainParamNames: route.domainParamNames,\n ...(route.domain ? { domain: route.domain } : {}),\n ...(route.localePaths?.length ? { localePaths: route.localePaths } : {}),\n }\n }\n }\n return serialized\n }\n\n private isSsrDisabled(pathname: string): boolean {\n const patterns = this.options.ssr?.disabled\n if (!patterns || patterns.length === 0) return false\n\n return patterns.some((pattern) => {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const regex = new RegExp(`^/${escaped.replace(/\\*/g, '[^/]*')}$`)\n return regex.test(pathname)\n })\n }\n}\n","/// <reference types=\"vite/client\" />\n\nimport { Transient, inject } from 'stratal/di'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\nimport type { ViteManifest } from '../types'\n\nconst DEFAULT_ENTRY_CLIENT_PATH = 'src/inertia/app.tsx'\n\ninterface ManifestGlobal {\n __STRATAL_INERTIA_MANIFEST__?: ViteManifest\n}\n\n@Transient()\nexport class ManifestService {\n private readonly manifest: ViteManifest | null\n private readonly entryClientPath: string\n private readonly isDev: boolean = Boolean(import.meta.env.DEV)\n\n constructor(\n @inject(INERTIA_TOKENS.Options) options: InertiaModuleOptions,\n ) {\n this.manifest = (globalThis as ManifestGlobal).__STRATAL_INERTIA_MANIFEST__ ?? null\n this.entryClientPath = (options.entryClientPath ?? DEFAULT_ENTRY_CLIENT_PATH).replace(/^\\/+/, '')\n\n if (!this.isDev && !this.manifest) {\n throw new Error(\n '@stratal/inertia: production build is missing the Vite client manifest. '\n + 'This is wired by stratalInertia() in vite.config.ts — confirm it is in your plugin list '\n + 'and that the client environment built successfully before the worker environment.',\n )\n }\n }\n\n getHeadTags(): string {\n if (this.isDev) {\n return '<link rel=\"stylesheet\" href=\"/__inertia/ssr-css\" data-ssr-css />'\n }\n\n const tags: string[] = []\n const seen = new Set<string>()\n for (const entry of Object.values(this.manifest!)) {\n if (entry.css) {\n for (const cssFile of entry.css) {\n if (seen.has(cssFile)) continue\n seen.add(cssFile)\n tags.push(`<link rel=\"stylesheet\" href=\"/${cssFile}\" />`)\n }\n }\n }\n\n return tags.join('\\n')\n }\n\n getScriptTags(): string {\n if (this.isDev) {\n return [\n '<script type=\"module\" src=\"/@vite/client\"></script>',\n `<script type=\"module\">\nimport { createHotContext } from \"/@vite/client\";\nconst hot = createHotContext(\"/__ssr_css\");\nhot.on(\"vite:afterUpdate\", () => {\n document.querySelectorAll(\"[data-ssr-css]\").forEach(el => el.remove());\n});\n</script>`,\n `<script type=\"module\" src=\"/${this.entryClientPath}\"></script>`,\n ].join('\\n')\n }\n\n const tags: string[] = []\n for (const entry of Object.values(this.manifest!)) {\n if (entry.isEntry) {\n tags.push(`<script type=\"module\" src=\"/${entry.file}\"></script>`)\n }\n }\n\n return tags.join('\\n')\n }\n}\n","import type { InertiaAppSSRResponse, Page } from '@inertiajs/core'\nimport { Singleton, inject } from 'stratal/di'\nimport { LOGGER_TOKENS, type LoggerService } from 'stratal/logger'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\n\ninterface LoadedSsrBundle {\n render(page: Page): Promise<InertiaAppSSRResponse>\n}\n\n@Singleton()\nexport class SsrRendererService {\n private bundle: LoadedSsrBundle | null = null\n private loadPromise: Promise<void> | null = null\n\n constructor(\n @inject(INERTIA_TOKENS.Options) private readonly options: InertiaModuleOptions,\n @inject(LOGGER_TOKENS.LoggerService) private readonly logger: LoggerService\n ) { }\n\n async render(page: Page): Promise<InertiaAppSSRResponse> {\n if (!this.options.ssr) {\n return { head: [], body: '' }\n }\n\n await this.ensureBundle()\n\n if (!this.bundle) {\n return { head: [], body: '' }\n }\n\n return this.bundle.render(page)\n }\n\n private async ensureBundle(): Promise<void> {\n if (this.bundle) return\n\n this.loadPromise ??= this.loadBundle()\n\n try {\n await this.loadPromise\n } catch {\n // loadBundle already clears loadPromise on failure\n }\n }\n\n private async loadBundle(): Promise<void> {\n if (!this.options.ssr) return\n\n try {\n const mod = await this.options.ssr.bundle()\n const resolved = ('default' in mod ? mod.default : mod) as LoadedSsrBundle\n this.bundle = resolved\n } catch (error: unknown) {\n this.logger.warn('[stratal:inertia] Failed to load SSR bundle. Falling back to client-side rendering.', { error })\n this.loadPromise = null\n }\n }\n}\n","import type { Page } from '@inertiajs/core'\nimport { Transient, inject } from 'stratal/di'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\nimport type { ManifestService } from './manifest.service'\n\n@Transient()\nexport class TemplateService {\n constructor(\n @inject(INERTIA_TOKENS.Options) private readonly options: InertiaModuleOptions,\n @inject(INERTIA_TOKENS.ManifestService) private readonly manifest: ManifestService,\n ) { }\n\n render(page: Page, ssrHead: string[], ssrBody: string): string {\n // When SSR body is present, Inertia's buildSSRBody already returns the\n // <script data-page=\"app\"> tag + <div id=\"app\" data-server-rendered=\"true\">.\n // Without SSR, we generate both elements ourselves for client-side hydration.\n const appHtml = ssrBody || this.buildClientOnlyBody(page)\n\n const headTags = ssrHead.length > 0 ? ssrHead.join('\\n') : ''\n const viteHead = this.manifest.getHeadTags()\n const viteScripts = this.manifest.getScriptTags()\n\n let html = this.options.rootView\n html = html.replace('@inertiaHead', headTags)\n html = html.replace('@inertia', appHtml)\n html = html.replace('@viteHead', viteHead)\n html = html.replace('@viteScripts', viteScripts)\n\n return html\n }\n\n private buildClientOnlyBody(page: Page): string {\n const json = JSON.stringify(page).replace(/\\//g, '\\\\/')\n return `<script data-page=\"app\" type=\"application/json\">${json}</script><div id=\"app\"></div>`\n }\n}\n","import { ApplicationError, type ApplicationErrorConstructor, type ExceptionHandler, type HttpExceptionContext } from 'stratal/errors'\nimport type { AsyncModuleOptions, DynamicModule, OnException, OnInitialize } from 'stratal/module'\nimport { Module } from 'stratal/module'\nimport { SchemaValidationError, type RouteConfigurable, type Router } from 'stratal/router'\nimport { augmentRouterContext } from './augment/router-context'\nimport type { InertiaModuleOptions } from './inertia.options'\nimport { INERTIA_TOKENS } from './inertia.tokens'\nimport { InertiaMiddleware } from './middleware/inertia.middleware'\nimport { InertiaService } from './services/inertia.service'\nimport { ManifestService } from './services/manifest.service'\nimport { SsrRendererService } from './services/ssr-renderer.service'\nimport { TemplateService } from './services/template.service'\n\n@Module({\n providers: [\n { provide: INERTIA_TOKENS.InertiaService, useClass: InertiaService },\n { provide: INERTIA_TOKENS.TemplateService, useClass: TemplateService },\n { provide: INERTIA_TOKENS.ManifestService, useClass: ManifestService },\n { provide: INERTIA_TOKENS.SsrRenderer, useClass: SsrRendererService },\n ],\n})\nexport class InertiaModule implements RouteConfigurable, OnInitialize, OnException {\n static forRoot(options: InertiaModuleOptions): DynamicModule {\n return {\n module: InertiaModule,\n providers: [\n { provide: INERTIA_TOKENS.Options, useValue: options },\n ],\n }\n }\n\n static forRootAsync(options: AsyncModuleOptions<InertiaModuleOptions>): DynamicModule {\n return {\n module: InertiaModule,\n providers: [\n {\n provide: INERTIA_TOKENS.Options,\n useFactory: options.useFactory,\n inject: options.inject,\n },\n ],\n }\n }\n\n configureRoutes(router: Router): void {\n router.use(InertiaMiddleware)\n }\n\n onException(handler: ExceptionHandler): void {\n // Convert Zod validation errors to Inertia form errors\n handler.renderable(SchemaValidationError, (error, context) => {\n if (context.type !== 'http') return undefined\n\n if (this.isPrecognitionRequest(context)) {\n return this.handlePrecognitionValidationError(error, context)\n }\n\n if (!this.isInertiaRequest(context)) return undefined\n\n const issues = error.issues ?? []\n const errors: Record<string, string> = {}\n for (const issue of issues) {\n errors[issue.path] = issue.message\n }\n\n context.ctx.flash('errors', errors)\n return this.redirectBack(context)\n })\n\n // Convert business ApplicationErrors to Inertia form-level errors\n handler.renderable(ApplicationError as unknown as ApplicationErrorConstructor, (error, context) => {\n if (context.type !== 'http') return undefined\n\n const message = error.message\n\n if (this.isPrecognitionRequest(context)) {\n return this.createPrecognitionErrorResponse({ _form: message })\n }\n\n if (!this.isInertiaRequest(context)) return undefined\n\n context.ctx.flash('errors', { _form: message } as const)\n return this.redirectBack(context)\n })\n\n // Render full Inertia error pages for HTTP HTML requests. Convention:\n // consumers ship `pages/Errors/${status}.tsx` (e.g. Errors/404, Errors/500).\n handler.errorPage(async (errorResponse, status, context) => {\n try {\n const inertia = context.ctx.getContainer().resolve<InertiaService>(INERTIA_TOKENS.InertiaService)\n return await inertia.render(\n context.ctx,\n `Errors/${status}`,\n { status, message: errorResponse.message },\n { status },\n )\n } catch {\n return undefined\n }\n })\n }\n\n onInitialize(): void {\n augmentRouterContext((ctx) => {\n const requestContainer = ctx.getContainer()\n return requestContainer.resolve<InertiaService>(INERTIA_TOKENS.InertiaService)\n })\n }\n\n private isInertiaRequest(context: HttpExceptionContext): boolean {\n return context.ctx.header('x-inertia') === 'true'\n }\n\n private isPrecognitionRequest(context: HttpExceptionContext): boolean {\n return context.ctx.header('precognition') === 'true'\n }\n\n private handlePrecognitionValidationError(error: SchemaValidationError, context: HttpExceptionContext): Response {\n const issues = error.issues ?? []\n let errors: Record<string, string> = {}\n for (const issue of issues) {\n errors[issue.path] = issue.message\n }\n\n // Filter to only requested fields if Precognition-Validate-Only is present\n const validateOnly = context.ctx.header('precognition-validate-only')\n if (validateOnly) {\n const fields = validateOnly.split(',').map(f => f.trim())\n const filtered: Record<string, string> = {}\n for (const field of fields) {\n if (errors[field]) {\n filtered[field] = errors[field]\n }\n }\n errors = filtered\n }\n\n // If after filtering there are no errors for the requested fields, treat as success\n if (Object.keys(errors).length === 0) {\n return new Response(null, {\n status: 204,\n headers: {\n 'Precognition': 'true',\n 'Precognition-Success': 'true',\n 'Vary': 'Precognition',\n },\n })\n }\n\n return this.createPrecognitionErrorResponse(errors)\n }\n\n private createPrecognitionErrorResponse(errors: Record<string, string>): Response {\n return new Response(JSON.stringify({ errors }), {\n status: 422,\n headers: {\n 'Content-Type': 'application/json',\n 'Precognition': 'true',\n 'Vary': 'Precognition',\n },\n })\n }\n\n private redirectBack(context: HttpExceptionContext): Response {\n const referer = context.ctx.header('referer')\n if (referer) {\n const parsed = new URL(referer)\n const url = parsed.search ? `${parsed.pathname}${parsed.search}` : parsed.pathname\n return context.ctx.redirect(url, 303)\n }\n return context.ctx.redirect('/', 303)\n }\n}\n","import { deleteCookie, getSignedCookie, setSignedCookie } from 'hono/cookie'\nimport type { CookieOptions } from 'hono/utils/cookie'\nimport type { RouterContext } from 'stratal/router'\nimport type { FlashStore } from './flash-store'\n\nexport interface CookieFlashStoreOptions {\n secret: string | BufferSource\n cookie?: string\n cookieOptions?: CookieOptions\n}\n\nexport class CookieFlashStore implements FlashStore {\n private readonly cookieName: string\n private readonly secret: string | BufferSource\n private readonly cookieOptions: CookieOptions\n\n constructor(options: CookieFlashStoreOptions) {\n this.secret = options.secret\n this.cookieName = options.cookie ?? 'stratal_flash'\n this.cookieOptions = {\n path: '/',\n httpOnly: true,\n sameSite: 'Lax',\n ...options.cookieOptions,\n }\n }\n\n async read(ctx: RouterContext): Promise<Record<string, unknown>> {\n const value = await getSignedCookie(ctx.c, this.secret, this.cookieName)\n if (!value) return {}\n\n try {\n return JSON.parse(atob(value)) as Record<string, unknown>\n } catch {\n return {}\n }\n }\n\n async write(ctx: RouterContext, data: Record<string, unknown>): Promise<void> {\n const encoded = btoa(JSON.stringify(data))\n await setSignedCookie(ctx.c, this.cookieName, encoded, this.secret, this.cookieOptions)\n }\n\n clear(ctx: RouterContext): Promise<void> {\n deleteCookie(ctx.c, this.cookieName, { path: this.cookieOptions.path })\n return Promise.resolve()\n }\n}\n","import type { RouteConfig } from 'stratal/router'\nimport { Delete, Get, Patch, Post, Put, Route } from 'stratal/router'\nimport { z } from 'stratal/validation'\n\n/**\n * Zod schema for the Inertia page JSON response (returned for X-Inertia XHR requests)\n */\nexport const inertiaPageSchema = z.object({\n component: z.string(),\n props: z.record(z.string(), z.unknown()),\n url: z.string(),\n version: z.string().nullable(),\n flash: z.record(z.string(), z.unknown()),\n rememberedState: z.record(z.string(), z.unknown()),\n mergeProps: z.array(z.string()).optional(),\n prependProps: z.array(z.string()).optional(),\n deepMergeProps: z.array(z.string()).optional(),\n matchPropsOn: z.array(z.string()).optional(),\n deferredProps: z.record(z.string(), z.array(z.string())).optional(),\n initialDeferredProps: z.record(z.string(), z.array(z.string())).optional(),\n onceProps: z.record(z.string(), z.object({ prop: z.string(), expiresAt: z.number().nullable().optional() })).optional(),\n sharedProps: z.array(z.string()).optional(),\n encryptHistory: z.boolean().optional(),\n clearHistory: z.boolean().optional(),\n preserveFragment: z.boolean().optional(),\n})\n\nexport type InertiaRouteConfig = Omit<RouteConfig, 'response' | 'statusCode' | 'hideFromDocs'> & {\n hideFromDocs?: boolean\n}\n\nconst inertiaResponse = {\n schema: inertiaPageSchema,\n description: 'Inertia page response',\n contentType: 'text/html',\n} as const\n\n/**\n * Builds a full RouteConfig from InertiaRouteConfig by applying inertia defaults.\n */\nfunction buildInertiaConfig(config: InertiaRouteConfig): Omit<RouteConfig, 'statusCode'> {\n const { hideFromDocs = true, ...rest } = config\n return { ...rest, response: inertiaResponse, hideFromDocs }\n}\n\n/**\n * Decorator for Inertia page routes using convention-based routing.\n *\n * Wraps `@Route()` with:\n * - Auto-applied Inertia page response schema\n * - `hideFromDocs: true` by default (overridable)\n *\n * **Cannot be mixed with HTTP method decorators** (`@Get`, `@Post`, `@InertiaGet`, etc.)\n * in the same controller.\n *\n * @example\n * ```typescript\n * @Controller('/notes')\n * export class NotesController implements IController {\n * @InertiaRoute({ query: z.object({ page: z.string().optional() }) })\n * async index(ctx: RouterContext) {\n * return ctx.inertia('notes/Index', { notes: [] })\n * }\n * }\n * ```\n */\nexport function InertiaRoute(config: InertiaRouteConfig = {}) {\n return Route(buildInertiaConfig(config))\n}\n\n/**\n * Registers a GET route for an Inertia page.\n *\n * Wraps `@Get()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (query, params, tags, etc.)\n *\n * @example\n * ```typescript\n * @Controller('/notes')\n * export class NotesController {\n * @InertiaGet('/')\n * async index(ctx: RouterContext) {\n * return ctx.inertia('notes/Index', { notes: [] })\n * }\n *\n * @InertiaGet('/:id', { params: z.object({ id: z.string() }) })\n * async show(ctx: RouterContext) {\n * return ctx.inertia('notes/Show', { note })\n * }\n * }\n * ```\n */\nexport function InertiaGet(path: string, config: InertiaRouteConfig = {}) {\n return Get(path, buildInertiaConfig(config))\n}\n\n/**\n * Registers a POST route for an Inertia form submission.\n *\n * Wraps `@Post()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (body, params, tags, etc.)\n */\nexport function InertiaPost(path: string, config: InertiaRouteConfig = {}) {\n return Post(path, buildInertiaConfig(config))\n}\n\n/**\n * Registers a PUT route for an Inertia form submission.\n *\n * Wraps `@Put()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (body, params, tags, etc.)\n */\nexport function InertiaPut(path: string, config: InertiaRouteConfig = {}) {\n return Put(path, buildInertiaConfig(config))\n}\n\n/**\n * Registers a PATCH route for an Inertia form submission.\n *\n * Wraps `@Patch()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (body, params, tags, etc.)\n */\nexport function InertiaPatch(path: string, config: InertiaRouteConfig = {}) {\n return Patch(path, buildInertiaConfig(config))\n}\n\n/**\n * Registers a DELETE route for an Inertia form submission.\n *\n * Wraps `@Delete()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (params, tags, etc.)\n */\nexport function InertiaDelete(path: string, config: InertiaRouteConfig = {}) {\n return Delete(path, buildInertiaConfig(config))\n}\n","import { Transient } from 'stratal/di'\nimport type { Middleware, Next, RouterContext } from 'stratal/router'\n\n@Transient()\nexport class HandlePrecognitiveRequests implements Middleware {\n async handle(ctx: RouterContext, next: Next): Promise<void> {\n const isPrecognition = ctx.header('precognition') === 'true'\n ctx.c.set('precognition', isPrecognition)\n\n if (isPrecognition) {\n ctx.c.set('validationSuccessResponse', new Response(null, {\n status: 204,\n headers: {\n 'Precognition': 'true',\n 'Precognition-Success': 'true',\n 'Vary': 'Precognition',\n },\n }))\n }\n\n await next()\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/augment/router-context.ts","../src/inertia.tokens.ts","../src/middleware/inertia.middleware.ts","../src/services/hreflang.service.ts","../src/types.ts","../src/services/inertia.service.ts","../src/services/manifest.service.ts","../src/services/seo.service.ts","../src/services/ssr-renderer.service.ts","../src/services/template.service.ts","../src/inertia.module.ts","../src/flash/cookie-flash-store.ts","../src/decorators/inertia.decorators.ts","../src/middleware/handle-precognitive-requests.middleware.ts"],"sourcesContent":["import type { RedirectStatusCode } from 'hono/utils/http-status'\nimport { RouterContext } from 'stratal/router'\nimport type { InertiaService } from '../services/inertia.service'\nimport type { SeoData } from '../seo/types'\nimport type {\n InertiaAlwaysProp,\n InertiaDeferredProp,\n InertiaMergeProp,\n InertiaMergeStrategy,\n InertiaOnceProp,\n InertiaOptionalProp,\n InertiaPageComponent,\n InertiaPageRegistry,\n InertiaRenderOptions,\n ResolvedInertiaPageProps,\n} from '../types'\n\nexport interface InertiaMergeOptions {\n strategy?: InertiaMergeStrategy\n matchOn?: string\n}\n\nexport interface InertiaOnceOptions {\n expiresAt?: number | null\n key?: string\n}\n\ndeclare module 'stratal/router' {\n interface RouterContext {\n /** Renders an Inertia page component with the given props and returns an HTTP response. */\n inertia<C extends InertiaPageComponent>(\n component: C,\n ...args: keyof InertiaPageRegistry extends never\n ? [props?: Record<string, unknown>, options?: InertiaRenderOptions]\n : Record<string, never> extends ResolvedInertiaPageProps<C>\n ? [props?: ResolvedInertiaPageProps<C>, options?: InertiaRenderOptions]\n : [props: ResolvedInertiaPageProps<C>, options?: InertiaRenderOptions]\n ): Promise<Response>\n /** Creates a deferred prop that is resolved after the initial page render, optionally grouped for batch loading. */\n defer<T>(callback: () => T, group?: string): InertiaDeferredProp<T>\n /** Creates an optional prop that is only included in the response when explicitly requested by the client. */\n optional<T>(callback: () => T): InertiaOptionalProp<T>\n /** Creates a mergeable prop that merges with existing client-side page data instead of replacing it. */\n merge<T>(callback: () => T, options?: InertiaMergeOptions): InertiaMergeProp<T>\n /** Creates a prop that is only sent on the first visit and cached for subsequent requests. */\n once<T>(callback: () => T, options?: InertiaOnceOptions): InertiaOnceProp<T>\n /** Creates a prop that is always evaluated and included, even on partial reload requests. */\n always<T>(callback: () => T): InertiaAlwaysProp<T>\n /** Sets a flash data entry that will be available on the next page visit. */\n flash(key: string, value: unknown): void\n /**\n * Adds a shared prop to the current request, available on every Inertia page\n * rendered during this request. Useful for middleware and packages that want\n * to contribute data to the frontend without a controller passing it through.\n */\n share(key: string, value: unknown): void\n /**\n * Sets SEO metadata (title, description, Open Graph, Twitter, etc.) for the\n * page rendered in this request. Merges with module-level defaults and any\n * earlier `seo()` calls. The resolved tags are injected into `<head>` and\n * shared as the `seo` prop; the client head is kept in sync automatically\n * by the runtime the `stratalInertia()` Vite plugin injects.\n */\n seo(data: SeoData): void\n /** Disables server-side rendering for the current request. */\n withoutSsr(): void\n }\n}\n\nexport function augmentRouterContext(resolveService: (ctx: RouterContext) => InertiaService): void {\n // Override redirect to auto-convert 302 → 303 for non-GET/HEAD requests\n // so the browser follows with GET instead of preserving the original method\n // eslint-disable-next-line @typescript-eslint/unbound-method -- intentionally saving reference, called with .call(this)\n const originalRedirect = RouterContext.prototype.redirect\n RouterContext.macro('redirect', function (this: RouterContext, url: string, status?: RedirectStatusCode) {\n if (!status || status === 302) {\n const method = this.c.req.method\n if (method !== 'GET' && method !== 'HEAD') {\n return originalRedirect.call(this, url, 303)\n }\n }\n return originalRedirect.call(this, url, status)\n })\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RouterContext.macro('inertia', function (this: RouterContext, component: string, props?: any, options?: InertiaRenderOptions) {\n const service = resolveService(this)\n return service.render(this, component, props as Record<string, unknown>, options)\n })\n\n RouterContext.macro('defer', function <T>(this: RouterContext, callback: () => T, group?: string) {\n const service = resolveService(this)\n return service.defer(callback, group)\n })\n\n RouterContext.macro('optional', function <T>(this: RouterContext, callback: () => T) {\n const service = resolveService(this)\n return service.optional(callback)\n })\n\n RouterContext.macro('merge', function <T>(this: RouterContext, callback: () => T, options?: InertiaMergeOptions) {\n const service = resolveService(this)\n return service.merge(callback, options)\n })\n\n RouterContext.macro('once', function <T>(this: RouterContext, callback: () => T, options?: InertiaOnceOptions) {\n const service = resolveService(this)\n return service.once(callback, options)\n })\n\n RouterContext.macro('always', function <T>(this: RouterContext, callback: () => T) {\n const service = resolveService(this)\n return service.always(callback)\n })\n\n RouterContext.macro('flash', function (this: RouterContext, key: string, value: unknown) {\n const flashOut = this.c.get('inertiaFlashOut') as Record<string, unknown> | undefined\n if (flashOut) {\n flashOut[key] = value\n }\n })\n\n RouterContext.macro('share', function (this: RouterContext, key: string, value: unknown) {\n const service = resolveService(this)\n service.share(key, value)\n })\n\n RouterContext.macro('seo', function (this: RouterContext, data: SeoData) {\n const service = resolveService(this)\n service.seo(data)\n })\n\n RouterContext.macro('withoutSsr', function (this: RouterContext) {\n this.c.set('withoutSsr', true)\n })\n}\n","export const INERTIA_TOKENS = {\n Options: Symbol.for('stratal:inertia:options'),\n InertiaService: Symbol.for('stratal:inertia:service'),\n TemplateService: Symbol.for('stratal:inertia:template'),\n ManifestService: Symbol.for('stratal:inertia:manifest'),\n SsrRenderer: Symbol.for('stratal:inertia:ssr-renderer'),\n HreflangService: Symbol.for('stratal:inertia:hreflang'),\n SeoService: Symbol.for('stratal:inertia:seo'),\n} as const\n","import { Transient, inject } from 'stratal/di'\nimport type { Middleware, Next, RouterContext } from 'stratal/router'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\n\n@Transient()\nexport class InertiaMiddleware implements Middleware {\n constructor(\n @inject(INERTIA_TOKENS.Options) private readonly options: InertiaModuleOptions,\n ) { }\n\n async handle(ctx: RouterContext, next: Next): Promise<void> {\n const isInertia = ctx.header('x-inertia') === 'true'\n const isPrefetch = ctx.header('purpose') === 'prefetch'\n\n // Store Inertia state on context for services to access\n ctx.c.set('inertia', isInertia)\n ctx.c.set('inertiaPrefetch', isPrefetch)\n ctx.c.set('withoutSsr', false)\n\n // Initialize flash buckets\n ctx.c.set('inertiaFlashOut', {})\n\n // Read incoming flash data from store (read-only — no response headers touched)\n let hadFlash = false\n if (this.options.flash) {\n const flashData = await this.options.flash.store.read(ctx)\n hadFlash = Object.keys(flashData).length > 0\n ctx.c.set('inertiaFlash', flashData)\n } else {\n ctx.c.set('inertiaFlash', {})\n }\n\n // Version mismatch check on GET requests\n if (isInertia && ctx.c.req.method === 'GET') {\n const clientVersion = ctx.header('x-inertia-version')\n const serverVersion = this.options.version ?? ''\n\n if (clientVersion && serverVersion && clientVersion !== serverVersion) {\n ctx.c.header('X-Inertia-Location', ctx.c.req.url)\n ctx.c.status(409)\n return\n }\n }\n\n await next()\n\n // Flash cookie operations AFTER next() — ctx.c.res is now the actual Response,\n // so setSignedCookie/deleteCookie will modify the real response headers.\n if (this.options.flash) {\n const flashOut = ctx.c.get('inertiaFlashOut')\n if (Object.keys(flashOut).length > 0) {\n // New flash data was set during this request — write cookie for next request\n await this.options.flash.store.write(ctx, flashOut)\n } else if (hadFlash) {\n // Flash was consumed but no new flash set — clear the cookie\n await this.options.flash.store.clear(ctx)\n }\n }\n\n // Skip response mutation for statuses Hono can't clone (e.g. 101 WebSocket\n // upgrades, Response.error()'s status 0). `c.header()` would otherwise call\n // `new Response(c.res.body, c.res)` and the Response constructor throws a\n // RangeError for any status outside 200-599.\n const status = ctx.c.res?.status\n if (typeof status !== 'number' || status < 200 || status > 599) return\n\n // Add Vary header to all responses\n ctx.c.header('Vary', 'X-Inertia')\n\n // Convert 302 to 303 for non-GET/HEAD Inertia requests\n if (isInertia && status === 302) {\n const method = ctx.c.req.method\n if (method !== 'GET' && method !== 'HEAD') {\n ctx.c.status(303)\n }\n }\n }\n}\n","import type { Application } from 'stratal'\nimport { CONTAINER_TOKEN, type Container, DI_TOKENS, Singleton, inject } from 'stratal/di'\nimport { I18N_TOKENS } from 'stratal/i18n'\nimport type { I18nModuleOptions } from 'stratal/i18n'\nimport { ROUTER_TOKENS, applyTrailingSlash, type LocaleUrlService, type TrailingSlashMode } from 'stratal/router'\nimport type { SeoLinkTag } from '../seo/types'\n\n/**\n * Produces `rel=\"alternate\" hreflang=\"…\"` link descriptors for the SEO pipeline.\n *\n * Activated when i18n detection produces URL-distinct locale variants:\n * - `path` strategy with ≥2 locales → locale-prefixed pathname variants\n * - `querystring` strategy with ≥2 locales → `?locale=xx` variants\n *\n * Returns `[]` for cookie/header strategies (no URL distinction) and for\n * single-locale apps. Emits an additional `x-default` link pointing at the\n * default-locale URL.\n *\n * The descriptors are merged into the resolved {@link SeoData} by\n * {@link import('./seo.service').SeoService}, so hreflang rides the same\n * `<head>` injection (initial render) and client reconciliation (SPA\n * navigation) as the rest of the SEO tags — no separate head path.\n *\n * Every generated `href` runs through {@link applyTrailingSlash} with the\n * app-wide mode so hreflang URLs match the canonical form the rest of the\n * router emits.\n */\n@Singleton()\nexport class HreflangService {\n constructor(\n @inject(CONTAINER_TOKEN) private readonly container: Container,\n ) { }\n\n buildLinks(currentUrl: URL): SeoLinkTag[] {\n const i18n = this.container.tryResolve<I18nModuleOptions>(I18N_TOKENS.Options)\n if (!i18n) return []\n const locales = i18n.locales ?? ['en']\n if (locales.length < 2) return []\n const defaultLocale = i18n.defaultLocale ?? 'en'\n\n const app = this.container.resolve<Application>(DI_TOKENS.Application)\n const trailingSlash: TrailingSlashMode = app.config.trailingSlash ?? 'ignore'\n\n const localeUrl = this.container.resolve<LocaleUrlService>(ROUTER_TOKENS.LocaleUrlService)\n if (localeUrl.pathEnabled) {\n return this.buildPathLinks(currentUrl, locales, defaultLocale, localeUrl, trailingSlash)\n }\n\n const strategy = (i18n.detection && 'strategy' in i18n.detection) ? i18n.detection.strategy : undefined\n if (strategy === 'querystring') {\n return this.buildQuerystringLinks(currentUrl, locales, defaultLocale, trailingSlash)\n }\n\n return []\n }\n\n private buildPathLinks(\n url: URL,\n locales: string[],\n defaultLocale: string,\n localeUrl: LocaleUrlService,\n trailingSlash: TrailingSlashMode,\n ): SeoLinkTag[] {\n const basePath = localeUrl.stripPrefix(url.pathname)\n const links = locales.map((locale) =>\n this.linkTag(locale, this.compose(url, localeUrl.applyPrefix(basePath, locale), url.search, trailingSlash)),\n )\n links.push(this.linkTag('x-default', this.compose(url, localeUrl.applyPrefix(basePath, defaultLocale), url.search, trailingSlash)))\n return links\n }\n\n private buildQuerystringLinks(\n url: URL,\n locales: string[],\n defaultLocale: string,\n trailingSlash: TrailingSlashMode,\n ): SeoLinkTag[] {\n const params = new URLSearchParams(url.search)\n params.delete('locale')\n const baseQs = params.toString()\n const links = locales.map((locale) => {\n const qs = this.composeQuery(baseQs, locale === defaultLocale ? null : ['locale', locale])\n return this.linkTag(locale, this.compose(url, url.pathname, qs, trailingSlash))\n })\n const xDefaultQs = baseQs ? `?${baseQs}` : ''\n links.push(this.linkTag('x-default', this.compose(url, url.pathname, xDefaultQs, trailingSlash)))\n return links\n }\n\n private compose(url: URL, pathname: string, search: string, mode: TrailingSlashMode): string {\n return applyTrailingSlash(url.origin + pathname + search, mode)\n }\n\n private composeQuery(baseQs: string, extra: [string, string] | null): string {\n if (!extra) return baseQs ? `?${baseQs}` : ''\n const tail = `${extra[0]}=${encodeURIComponent(extra[1])}`\n return baseQs ? `?${baseQs}&${tail}` : `?${tail}`\n }\n\n private linkTag(hreflang: string, href: string): SeoLinkTag {\n return { rel: 'alternate', hreflang, href }\n }\n}\n","import type { Page, SharedPageProps } from '@inertiajs/core'\nimport type { ContentfulStatusCode } from 'hono/utils/http-status'\nimport type { MessageKeys } from 'stratal/i18n'\nimport type { RouterContext } from 'stratal/router'\n\n\nexport interface InertiaPageRegistry {}\n\nexport interface InertiaI18nConfig {}\n\nexport type InertiaTranslationKeys =\n InertiaI18nConfig extends { translationKeys: infer T extends string } ? T : MessageKeys\n\n// Derive shared props from @inertiajs/core's InertiaConfig.sharedPageProps.\n// Users augment InertiaConfig in their global.d.ts — this type stays in sync automatically.\nexport type InertiaSharedProps = SharedPageProps\n\nexport type InertiaPageComponent = keyof InertiaPageRegistry extends never\n ? string\n : Extract<keyof InertiaPageRegistry, string>\n\n// Allows each prop value to be wrapped with defer/merge/optional/once/always\ntype AllowInertiaWrappers<T> = {\n [K in keyof T]: T[K] | InertiaDeferredProp | InertiaMergeProp | InertiaOptionalProp | InertiaOnceProp | InertiaAlwaysProp\n}\n\n// Props the controller passes to ctx.inertia() — page-specific only, shared props are auto-injected\n// Each prop can be the raw value OR a deferred/merge/optional/once/always wrapper\nexport type ResolvedInertiaPageProps<C extends InertiaPageComponent> =\n C extends keyof InertiaPageRegistry ? AllowInertiaWrappers<InertiaPageRegistry[C]> : Record<string, unknown>\n\n// Full props the React page component receives — page-specific + shared (auto-injected), no wrappers\nexport type InertiaFullPageProps<C extends InertiaPageComponent> =\n (C extends keyof InertiaPageRegistry ? InertiaPageRegistry[C] : Record<string, unknown>) & InertiaSharedProps\n\n// Re-export Page from @inertiajs/core as InertiaPage for convenience\nexport type { Page as InertiaPage } from '@inertiajs/core'\n\nexport interface InertiaRenderOptions {\n encryptHistory?: boolean\n clearHistory?: boolean\n preserveFragment?: boolean\n /**\n * HTTP status code to use for the rendered response. Defaults to `200`.\n * Useful for rendering Inertia error pages (e.g. `Errors/404` with status 404).\n */\n status?: ContentfulStatusCode\n}\n\n/**\n * Streaming SSR render result. `head` carries the document `<head>` tags Inertia\n * collected during the synchronous shell render (known once the shell is ready);\n * `stream` is React's `renderToReadableStream` output, piped into the `#app` body.\n */\nexport interface InertiaSsrResult {\n head: string[]\n stream: ReadableStream<Uint8Array>\n}\n\nexport interface InertiaSsrBundle {\n render(page: Page): Promise<InertiaSsrResult>\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SharedDataResolver = (ctx: RouterContext) => any\n\nexport interface ViteManifestEntry {\n file: string\n css?: string[]\n isEntry?: boolean\n imports?: string[]\n dynamicImports?: string[]\n src?: string\n}\n\nexport type ViteManifest = Record<string, ViteManifestEntry>\n\nexport const INERTIA_PROP_OPTIONAL = Symbol.for('stratal:inertia:prop:optional')\nexport const INERTIA_PROP_DEFERRED = Symbol.for('stratal:inertia:prop:deferred')\nexport const INERTIA_PROP_MERGE = Symbol.for('stratal:inertia:prop:merge')\nexport const INERTIA_PROP_ONCE = Symbol.for('stratal:inertia:prop:once')\nexport const INERTIA_PROP_ALWAYS = Symbol.for('stratal:inertia:prop:always')\n\nexport interface InertiaOptionalProp<T = unknown> {\n [INERTIA_PROP_OPTIONAL]: true\n callback: () => T\n}\n\nexport interface InertiaDeferredProp<T = unknown> {\n [INERTIA_PROP_DEFERRED]: true\n callback: () => T\n group: string\n}\n\nexport type InertiaMergeStrategy = 'append' | 'prepend' | 'deep'\n\nexport interface InertiaMergeProp<T = unknown> {\n [INERTIA_PROP_MERGE]: true\n callback: () => T\n strategy: InertiaMergeStrategy\n matchOn?: string\n}\n\nexport interface InertiaOnceProp<T = unknown> {\n [INERTIA_PROP_ONCE]: true\n callback: () => T\n expiresAt?: number | null\n key?: string\n}\n\nexport interface InertiaAlwaysProp<T = unknown> {\n [INERTIA_PROP_ALWAYS]: true\n callback: () => T\n}\n","import type { Page } from '@inertiajs/core'\nimport type { Application } from 'stratal'\nimport { DI_TOKENS, Request, inject } from 'stratal/di'\nimport { I18N_TOKENS, type MessageLoaderService } from 'stratal/i18n'\nimport { ROUTER_TOKENS, type CurrentRoute, type LocalePathService, type LocaleUrlConfig, type RegisteredRoute, type RouteRegistry, type RouterContext, type SerializedRoutes, type Uri } from 'stratal/router'\nimport type { InertiaMergeOptions, InertiaOnceOptions } from '../augment/router-context'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\nimport type { SeoData } from '../seo/types'\nimport type {\n InertiaAlwaysProp,\n InertiaDeferredProp,\n InertiaMergeProp,\n InertiaOnceProp,\n InertiaOptionalProp,\n InertiaRenderOptions,\n SharedDataResolver,\n} from '../types'\nimport {\n INERTIA_PROP_ALWAYS,\n INERTIA_PROP_DEFERRED,\n INERTIA_PROP_MERGE,\n INERTIA_PROP_ONCE,\n INERTIA_PROP_OPTIONAL,\n} from '../types'\nimport type { SeoService } from './seo.service'\nimport type { SsrRendererService } from './ssr-renderer.service'\nimport type { TemplateService } from './template.service'\n\n@Request(INERTIA_TOKENS.InertiaService)\nexport class InertiaService {\n private sharedData: Record<string, unknown> = {}\n\n constructor(\n @inject(INERTIA_TOKENS.Options) private readonly options: InertiaModuleOptions,\n @inject(INERTIA_TOKENS.TemplateService) private readonly template: TemplateService,\n @inject(INERTIA_TOKENS.SsrRenderer) private readonly ssr: SsrRendererService,\n @inject(INERTIA_TOKENS.SeoService) private readonly seoService: SeoService,\n ) { }\n\n share(key: string, value: unknown): void {\n this.sharedData[key] = value\n }\n\n seo(data: SeoData): void {\n this.seoService.set(data)\n }\n\n location(url: string): Response {\n return new Response('', {\n status: 409,\n headers: { 'X-Inertia-Location': url },\n })\n }\n\n optional<T>(callback: () => T): InertiaOptionalProp<T> {\n return { [INERTIA_PROP_OPTIONAL]: true, callback }\n }\n\n defer<T>(callback: () => T, group = 'default'): InertiaDeferredProp<T> {\n return { [INERTIA_PROP_DEFERRED]: true, callback, group }\n }\n\n merge<T>(callback: () => T, options?: InertiaMergeOptions): InertiaMergeProp<T> {\n return {\n [INERTIA_PROP_MERGE]: true,\n callback,\n strategy: options?.strategy ?? 'append',\n matchOn: options?.matchOn,\n }\n }\n\n once<T>(callback: () => T, options?: InertiaOnceOptions): InertiaOnceProp<T> {\n return {\n [INERTIA_PROP_ONCE]: true,\n callback,\n expiresAt: options?.expiresAt ?? null,\n key: options?.key,\n }\n }\n\n always<T>(callback: () => T): InertiaAlwaysProp<T> {\n return { [INERTIA_PROP_ALWAYS]: true, callback }\n }\n\n async render(\n ctx: RouterContext,\n component: string,\n props: Record<string, unknown> = {},\n renderOptions: InertiaRenderOptions = {},\n ): Promise<Response> {\n const reqUrl = new URL(ctx.c.req.url)\n const url = reqUrl.search ? `${reqUrl.pathname}${reqUrl.search}` : reqUrl.pathname\n // `ssr.disabled` globs match the path only — keep the query string out of it.\n const pathname = reqUrl.pathname\n const isInertia = ctx.c.get('inertia')\n\n // Resolve shared data from module options\n const { shared: resolvedShared, sharedKeys } = await this.resolveSharedData(ctx)\n\n // Resolve SEO once: shared as the `seo` prop (drives the client head-sync runtime)\n // and rendered into <head> below for the initial paint. Wrapped as an ALWAYS\n // prop so it is present on every response — including partial reloads that\n // don't request it — otherwise the client runtime would see a missing `seo`\n // key and wipe the managed head tags even though nothing changed.\n const resolvedSeo = await this.seoService.resolve(ctx)\n\n // Merge shared data with route props. `seo` is always-evaluated so it can\n // never be filtered out by partial-reload prop selection.\n const allProps = { ...resolvedShared, ...this.sharedData, seo: this.always(() => resolvedSeo), ...props }\n\n // Track all shared prop keys (module config + per-request .share() + seo)\n const allSharedKeys = [...sharedKeys, ...Object.keys(this.sharedData), 'seo']\n\n // Process props: handle optional, deferred, merge, once, always\n const result = await this.processProps(allProps, ctx, component, isInertia)\n\n // Read flash data from context (set by middleware)\n const rawFlash = (ctx.c.get('inertiaFlash') as Record<string, unknown> | undefined) ?? {}\n const { errors: flashErrors, ...flash } = rawFlash\n const errors = (flashErrors && typeof flashErrors === 'object' && !Array.isArray(flashErrors))\n ? flashErrors as Page['props']['errors']\n : {} as Page['props']['errors']\n\n const page: Page = {\n component,\n props: { ...result.resolvedProps, errors },\n url,\n version: this.options.version ?? null,\n flash,\n rememberedState: {},\n rescuedProps: [],\n ...(result.mergeProps.length > 0 ? { mergeProps: result.mergeProps } : {}),\n ...(result.prependProps.length > 0 ? { prependProps: result.prependProps } : {}),\n ...(result.deepMergeProps.length > 0 ? { deepMergeProps: result.deepMergeProps } : {}),\n ...(result.matchPropsOn.length > 0 ? { matchPropsOn: result.matchPropsOn } : {}),\n ...(Object.keys(result.deferredProps).length > 0 ? { deferredProps: result.deferredProps } : {}),\n ...(Object.keys(result.deferredProps).length > 0 && !this.isPartialReload(ctx, component) ? { initialDeferredProps: result.deferredProps } : {}),\n ...(Object.keys(result.onceProps).length > 0 ? { onceProps: result.onceProps } : {}),\n ...(allSharedKeys.length > 0 ? { sharedProps: allSharedKeys } : {}),\n ...(renderOptions.encryptHistory ? { encryptHistory: true } : {}),\n ...(renderOptions.clearHistory ? { clearHistory: true } : {}),\n ...(renderOptions.preserveFragment ? { preserveFragment: true } : {}),\n }\n\n const status = renderOptions.status ?? 200\n\n if (isInertia) {\n return new Response(JSON.stringify(page), {\n status,\n headers: {\n 'Content-Type': 'application/json',\n 'X-Inertia': 'true',\n 'Vary': 'X-Inertia',\n },\n })\n }\n\n // Full page render — skip SSR if disabled for this route or not configured\n const seoTags = this.seoService.tagsFor(resolvedSeo)\n const ssrDisabled = ctx.c.get('withoutSsr') || this.isSsrDisabled(pathname) || !this.options.ssr\n\n if (ssrDisabled) {\n const html = this.template.renderClientOnly(page, seoTags)\n return new Response(html, {\n status,\n headers: { 'Content-Type': 'text/html; charset=utf-8' },\n })\n }\n\n // Streaming SSR: awaiting render resolves once the shell is ready (so the\n // Inertia `<Head>` tags are known); the body then streams progressively.\n const { head, stream } = await this.ssr.render(page)\n const body = this.template.renderStream(page, [...head, ...seoTags], stream)\n\n return new Response(body, {\n status,\n headers: { 'Content-Type': 'text/html; charset=utf-8' },\n })\n }\n\n /**\n * Resolve shared data from module options and i18n configuration.\n *\n * Processes static values and resolver functions from `sharedData` config.\n * When `i18n` option is set, auto-injects `locale` and `translations` props\n * using the core {@link MessageLoaderService} resolved from the request container.\n */\n private async resolveSharedData(ctx: RouterContext): Promise<{ shared: Record<string, unknown>; sharedKeys: string[] }> {\n const shared: Record<string, unknown> = {}\n const configShared = this.options.sharedData\n\n if (configShared) {\n for (const [key, value] of Object.entries(configShared)) {\n if (typeof value === 'function') {\n shared[key] = await (value as SharedDataResolver)(ctx)\n } else {\n shared[key] = value\n }\n }\n }\n\n if (this.options.i18n) {\n const loader = ctx.getContainer().resolve<MessageLoaderService>(I18N_TOKENS.MessageLoader)\n const locale = ctx.getLocale()\n shared.locale = locale\n shared.translations = loader.getFilteredMessages(locale, { only: this.options.i18n.only })\n }\n\n if (this.options.routes) {\n const container = ctx.getContainer()\n const registry = container.resolve<RouteRegistry>(ROUTER_TOKENS.RouteRegistry)\n const application = container.resolve<Application>(DI_TOKENS.Application)\n const uri = container.resolve<Uri>(ROUTER_TOKENS.Uri)\n\n const name = registry.findNameByRoute(ctx.c.req.method, ctx.c.req.routePath) ?? null\n const params = { ...ctx.param() }\n\n const localePathService = container.resolve<LocalePathService>(ROUTER_TOKENS.LocalePathService)\n\n shared.routes = this.serializeRoutes(registry.named())\n shared.trailingSlash = application.config.trailingSlash ?? 'ignore'\n shared.route = { name, params, defaults: uri.getDefaults() } satisfies CurrentRoute\n shared.localeConfig = {\n defaultLocale: localePathService.localePathConfig?.defaultLocale ?? null,\n prefixDefaultLocale: localePathService.prefixDefaultLocale,\n } satisfies LocaleUrlConfig\n }\n\n return { shared, sharedKeys: Object.keys(shared) }\n }\n\n private isPartialReload(ctx: RouterContext, component: string): boolean {\n const isInertia = ctx.c.get('inertia')\n const partialComponent = ctx.header('x-inertia-partial-component')\n const partialDataHeader = ctx.header('x-inertia-partial-data')\n return !!(isInertia && partialComponent === component && partialDataHeader)\n }\n\n private async processProps(\n allProps: Record<string, unknown>,\n ctx: RouterContext,\n component: string,\n isInertia: boolean,\n ): Promise<{\n resolvedProps: Record<string, unknown>\n mergeProps: string[]\n prependProps: string[]\n deepMergeProps: string[]\n matchPropsOn: string[]\n deferredProps: Record<string, string[]>\n onceProps: Record<string, { prop: string; expiresAt?: number | null }>\n }> {\n const resolvedProps: Record<string, unknown> = {}\n const mergeProps: string[] = []\n const prependProps: string[] = []\n const deepMergeProps: string[] = []\n const matchPropsOn: string[] = []\n const deferredProps: Record<string, string[]> = {}\n const onceProps: Record<string, { prop: string; expiresAt?: number | null }> = {}\n\n const partialComponent = ctx.header('x-inertia-partial-component')\n const partialDataHeader = ctx.header('x-inertia-partial-data')\n const partialExceptHeader = ctx.header('x-inertia-partial-except')\n const resetHeader = ctx.header('x-inertia-reset')\n const shouldResolveDeferred = ctx.header('x-inertia-resolve-deferred') === 'true'\n const isPartialReload = isInertia && partialComponent === component && partialDataHeader\n\n const requestedProps = partialDataHeader?.split(',').map((s) => s.trim()) ?? []\n const exceptProps = partialExceptHeader?.split(',').map((s) => s.trim()) ?? []\n const _resetProps = resetHeader?.split(',').map((s) => s.trim()) ?? []\n\n for (const [key, value] of Object.entries(allProps)) {\n // Handle always props — always resolve regardless of partial reload\n if (this.isAlwaysProp(value)) {\n resolvedProps[key] = await value.callback()\n continue\n }\n\n // Handle once props\n if (this.isOnceProp(value)) {\n if (isPartialReload && this.isRequested(key, requestedProps)) {\n resolvedProps[key] = await value.callback()\n } else if (!isPartialReload) {\n resolvedProps[key] = await value.callback()\n onceProps[key] = {\n prop: value.key ?? key,\n ...(value.expiresAt != null ? { expiresAt: value.expiresAt } : {}),\n }\n }\n continue\n }\n\n // Handle deferred props\n if (this.isDeferredProp(value)) {\n if (isPartialReload && this.isRequested(key, requestedProps)) {\n resolvedProps[key] = await value.callback()\n } else if (!isPartialReload) {\n if (shouldResolveDeferred) {\n resolvedProps[key] = await value.callback()\n } else {\n deferredProps[value.group] ??= []\n deferredProps[value.group].push(key)\n }\n }\n continue\n }\n\n // Handle merge props (append/prepend/deep)\n if (this.isMergeProp(value)) {\n if (isPartialReload && !this.isRequested(key, requestedProps)) {\n continue\n }\n\n switch (value.strategy) {\n case 'prepend':\n prependProps.push(key)\n break\n case 'deep':\n deepMergeProps.push(key)\n break\n default:\n mergeProps.push(key)\n break\n }\n\n if (value.matchOn) {\n matchPropsOn.push(`${key}:${value.matchOn}`)\n }\n\n resolvedProps[key] = await value.callback()\n continue\n }\n\n // Handle optional props\n if (this.isOptionalProp(value)) {\n if (isPartialReload && this.isRequested(key, requestedProps)) {\n resolvedProps[key] = await value.callback()\n }\n continue\n }\n\n // Regular props\n if (isPartialReload) {\n if (this.isRequested(key, requestedProps) && !this.isExcepted(key, exceptProps)) {\n resolvedProps[key] = value\n }\n } else {\n resolvedProps[key] = value\n }\n }\n\n return { resolvedProps, mergeProps, prependProps, deepMergeProps, matchPropsOn, deferredProps, onceProps }\n }\n\n /**\n * Check if a prop key is requested — supports dot-notation (e.g., `user.permissions`\n * matches the top-level `user` key).\n */\n private isRequested(key: string, requestedProps: string[]): boolean {\n return requestedProps.some((prop) => prop === key || prop.startsWith(`${key}.`))\n }\n\n private isExcepted(key: string, exceptProps: string[]): boolean {\n return exceptProps.some((prop) => prop === key || prop.startsWith(`${key}.`))\n }\n\n private isOptionalProp(value: unknown): value is InertiaOptionalProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_OPTIONAL in value\n }\n\n private isDeferredProp(value: unknown): value is InertiaDeferredProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_DEFERRED in value\n }\n\n private isMergeProp(value: unknown): value is InertiaMergeProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_MERGE in value\n }\n\n private isOnceProp(value: unknown): value is InertiaOnceProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_ONCE in value\n }\n\n private isAlwaysProp(value: unknown): value is InertiaAlwaysProp {\n return typeof value === 'object' && value !== null && INERTIA_PROP_ALWAYS in value\n }\n\n private serializeRoutes(routes: RegisteredRoute[]): SerializedRoutes {\n const serialized: SerializedRoutes = {}\n for (const route of routes) {\n if (route.name) {\n serialized[route.name] = {\n path: route.path,\n paramNames: route.paramNames,\n domainParamNames: route.domainParamNames,\n ...(route.domain ? { domain: route.domain } : {}),\n ...(route.localePaths?.length ? { localePaths: route.localePaths } : {}),\n }\n }\n }\n return serialized\n }\n\n private isSsrDisabled(pathname: string): boolean {\n const patterns = this.options.ssr?.disabled\n if (!patterns || patterns.length === 0) return false\n\n return patterns.some((pattern) => {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const regex = new RegExp(`^/${escaped.replace(/\\*/g, '[^/]*')}$`)\n return regex.test(pathname)\n })\n }\n}\n","/// <reference types=\"vite/client\" />\n\nimport { Singleton, inject } from 'stratal/di'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\nimport type { ViteManifest } from '../types'\n\nconst DEFAULT_ENTRY_CLIENT_PATH = 'src/inertia/app.tsx'\n\ninterface ManifestGlobal {\n __STRATAL_INERTIA_MANIFEST__?: ViteManifest\n}\n\n@Singleton()\nexport class ManifestService {\n private readonly manifest: ViteManifest | null\n private readonly entryClientPath: string\n private readonly isDev: boolean = Boolean(import.meta.env.DEV)\n // The manifest is static for the lifetime of the worker, so the derived\n // head/script tag strings are computed once and cached.\n private headTags: string | null = null\n private scriptTags: string | null = null\n\n constructor(\n @inject(INERTIA_TOKENS.Options) options: InertiaModuleOptions,\n ) {\n this.manifest = (globalThis as ManifestGlobal).__STRATAL_INERTIA_MANIFEST__ ?? null\n this.entryClientPath = (options.entryClientPath ?? DEFAULT_ENTRY_CLIENT_PATH).replace(/^\\/+/, '')\n\n if (!this.isDev && !this.manifest) {\n throw new Error(\n '@stratal/inertia: production build is missing the Vite client manifest. '\n + 'This is wired by stratalInertia() in vite.config.ts — confirm it is in your plugin list '\n + 'and that the client environment built successfully before the worker environment.',\n )\n }\n }\n\n getHeadTags(): string {\n return this.headTags ??= this.buildHeadTags()\n }\n\n getScriptTags(): string {\n return this.scriptTags ??= this.buildScriptTags()\n }\n\n private buildHeadTags(): string {\n if (this.isDev) {\n return '<link rel=\"stylesheet\" href=\"/__inertia/ssr-css\" data-ssr-css />'\n }\n\n const tags: string[] = []\n const seen = new Set<string>()\n for (const entry of Object.values(this.manifest!)) {\n if (entry.css) {\n for (const cssFile of entry.css) {\n if (seen.has(cssFile)) continue\n seen.add(cssFile)\n tags.push(`<link rel=\"stylesheet\" href=\"/${cssFile}\" />`)\n }\n }\n }\n\n return tags.join('\\n')\n }\n\n private buildScriptTags(): string {\n if (this.isDev) {\n return [\n '<script type=\"module\" src=\"/@vite/client\"></script>',\n `<script type=\"module\">\nimport { createHotContext } from \"/@vite/client\";\nconst hot = createHotContext(\"/__ssr_css\");\nhot.on(\"vite:afterUpdate\", () => {\n document.querySelectorAll(\"[data-ssr-css]\").forEach(el => el.remove());\n});\n</script>`,\n `<script type=\"module\" src=\"/${this.entryClientPath}\"></script>`,\n ].join('\\n')\n }\n\n const tags: string[] = []\n for (const entry of Object.values(this.manifest!)) {\n if (entry.isEntry) {\n tags.push(`<script type=\"module\" src=\"/${entry.file}\"></script>`)\n }\n }\n\n return tags.join('\\n')\n }\n}\n","import { Request, inject } from 'stratal/di'\nimport type { RouterContext } from 'stratal/router'\nimport type { InertiaModuleOptions, InertiaSeoOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\nimport { buildSeoTags, descriptorToHtml } from '../seo/build-seo-tags'\nimport type { SeoData } from '../seo/types'\nimport type { HreflangService } from './hreflang.service'\n\n/**\n * Request-scoped accumulator for page SEO metadata.\n *\n * Controllers (and middleware) call `ctx.seo()` to contribute metadata; at\n * render time {@link InertiaService} resolves it against the module-level\n * defaults and title template, shares the result as the `seo` prop, and injects\n * the rendered tags into `<head>`.\n */\n@Request(INERTIA_TOKENS.SeoService)\nexport class SeoService {\n private accumulated: SeoData = {}\n\n constructor(\n @inject(INERTIA_TOKENS.Options) private readonly options: InertiaModuleOptions,\n @inject(INERTIA_TOKENS.HreflangService) private readonly hreflang: HreflangService,\n ) { }\n\n /** Merges the given metadata into the request's accumulated SEO data. */\n set(data: SeoData): void {\n this.accumulated = mergeSeo(this.accumulated, data)\n }\n\n /**\n * Resolves the final SEO data: module defaults (base) merged with the\n * request's accumulated data, then the title template applied. Resolver\n * functions for `defaults`/`titleTemplate` are awaited with the request `ctx`.\n * Locale-aware `hreflang` alternates are appended last so they ride the same\n * head injection and SPA reconciliation as the rest of the SEO tags.\n *\n * The resolved `title` is ALWAYS a string (falling back to `''`). This makes\n * the `<title>` descriptor deterministic: every navigation — including to a\n * page with no SEO — produces a title, so the client head-sync sets\n * `document.title` rather than leaving the previous page's title stale.\n */\n async resolve(ctx: RouterContext): Promise<SeoData> {\n const seo: InertiaSeoOptions | undefined = this.options.seo\n\n const defaults = typeof seo?.defaults === 'function'\n ? await seo.defaults(ctx)\n : seo?.defaults ?? {}\n\n const resolved = mergeSeo(defaults, this.accumulated)\n\n const template = seo?.titleTemplate\n if (typeof template === 'function') {\n resolved.title = await template(resolved.title, ctx)\n } else if (typeof template === 'string' && this.accumulated.title != null) {\n // Only wrap a page-provided title; a bare default title is used as-is.\n // Use split/join rather than String.replace so every `%s` is substituted\n // and `$`-sequences in the title (`$&`, `$$`, …) are treated literally.\n resolved.title = template.split('%s').join(this.accumulated.title)\n }\n\n // Always settle on a string title so `buildSeoTags` emits a `<title>` on\n // every response. Without this, navigating to a page with no title would\n // skip the title descriptor and the client would keep the prior title.\n resolved.title ??= ''\n\n // Append hreflang alternates for the current URL after any user-set links so\n // user links keep their document order. Computed fresh per request — never\n // stored on `accumulated`.\n const hreflang = this.hreflang.buildLinks(new URL(ctx.c.req.url))\n if (hreflang.length > 0) {\n resolved.link = [...(resolved.link ?? []), ...hreflang]\n }\n\n return resolved\n }\n\n /** Renders resolved SEO data into a list of head-tag HTML strings. */\n tagsFor(resolved: SeoData): string[] {\n return buildSeoTags(resolved).map(descriptorToHtml)\n }\n}\n\n/** Merges `b` over `a`: `openGraph`/`twitter` shallow-merge, `meta`/`link` concat, scalars overwrite. */\nfunction mergeSeo(a: SeoData, b: SeoData): SeoData {\n return {\n ...a,\n ...b,\n ...(a.openGraph || b.openGraph ? { openGraph: { ...a.openGraph, ...b.openGraph } } : {}),\n ...(a.twitter || b.twitter ? { twitter: { ...a.twitter, ...b.twitter } } : {}),\n ...(a.meta || b.meta ? { meta: [...(a.meta ?? []), ...(b.meta ?? [])] } : {}),\n ...(a.link || b.link ? { link: [...(a.link ?? []), ...(b.link ?? [])] } : {}),\n }\n}\n","import type { Page } from '@inertiajs/core'\nimport { Singleton, inject } from 'stratal/di'\nimport { ApplicationError } from 'stratal/errors'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\nimport type { InertiaSsrBundle, InertiaSsrResult } from '../types'\n\n@Singleton()\nexport class SsrRendererService {\n private bundle: InertiaSsrBundle | null = null\n private loadPromise: Promise<void> | null = null\n\n constructor(\n @inject(INERTIA_TOKENS.Options) private readonly options: InertiaModuleOptions,\n ) { }\n\n /**\n * Render a page to a streaming SSR result.\n *\n * The SSR bundle is imported once per worker (memoized). Bundle-load and render\n * errors propagate — there is no silent client-side fallback. Callers must only\n * invoke this when `options.ssr` is configured.\n */\n async render(page: Page): Promise<InertiaSsrResult> {\n if (!this.options.ssr) {\n throw new ApplicationError('[stratal:inertia] SSR bundle is not configured.')\n }\n\n await this.ensureBundle()\n return this.bundle!.render(page)\n }\n\n private async ensureBundle(): Promise<void> {\n if (this.bundle) return\n this.loadPromise ??= this.loadBundle()\n try {\n await this.loadPromise\n } catch (error) {\n // Allow a later request to retry a transient import failure, but still\n // surface the error to this request (no silent client-side fallback).\n this.loadPromise = null\n throw error\n }\n }\n\n private async loadBundle(): Promise<void> {\n const mod = await this.options.ssr!.bundle()\n this.bundle = ('default' in mod ? mod.default : mod)\n }\n}\n","import type { Page } from '@inertiajs/core'\nimport { Singleton, inject } from 'stratal/di'\nimport { ApplicationError } from 'stratal/errors'\nimport type { InertiaModuleOptions } from '../inertia.options'\nimport { INERTIA_TOKENS } from '../inertia.tokens'\nimport type { ManifestService } from './manifest.service'\n\nconst APP_ID = 'app'\n\n@Singleton()\nexport class TemplateService {\n // The root template is split once around the @inertia placeholder so the\n // document shell can be flushed before the React stream and closed after it.\n private readonly pre: string\n private readonly post: string\n\n constructor(\n @inject(INERTIA_TOKENS.Options) options: InertiaModuleOptions,\n @inject(INERTIA_TOKENS.ManifestService) private readonly manifest: ManifestService,\n ) {\n // Match the standalone @inertia token, not the @inertiaHead placeholder it\n // is a prefix of (the word boundary fails between `a` and `H`).\n const match = /@inertia\\b/.exec(options.rootView)\n if (!match) {\n throw new ApplicationError('[stratal:inertia] rootView template is missing the @inertia placeholder.')\n }\n this.pre = options.rootView.slice(0, match.index)\n this.post = options.rootView.slice(match.index + '@inertia'.length)\n }\n\n /**\n * Compose the streamed HTML response: the document shell (head + opening\n * `#app` wrapper) is flushed first, the React stream is piped verbatim, then\n * the wrapper is closed and the trailing scripts are appended.\n *\n * Reproduces Inertia's `buildSSRBody` markup: a `<script data-page>` JSON tag\n * (parsed before hydration) followed by `<div data-server-rendered id=\"app\">`.\n */\n renderStream(page: Page, head: string[], reactStream: ReadableStream<Uint8Array>): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder()\n const shellPre = this.fillPlaceholders(this.pre, head)\n + `<script data-page=\"${APP_ID}\" type=\"application/json\">${this.serialize(page)}</script>`\n + `<div data-server-rendered=\"true\" id=\"${APP_ID}\">`\n const shellPost = `</div>${this.fillPlaceholders(this.post, head)}`\n\n let reader: ReadableStreamDefaultReader<Uint8Array> | undefined\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n controller.enqueue(encoder.encode(shellPre))\n reader = reactStream.getReader()\n try {\n for (; ;) {\n const { done, value } = await reader.read()\n if (done) break\n controller.enqueue(value)\n }\n controller.enqueue(encoder.encode(shellPost))\n controller.close()\n } catch (error) {\n controller.error(error)\n } finally {\n reader.releaseLock()\n reader = undefined\n }\n },\n // Forward a downstream cancellation (e.g. the client disconnects) up to the\n // React render so it stops working on a response no one is reading.\n cancel(reason) {\n return reader?.cancel(reason) ?? reactStream.cancel(reason)\n },\n })\n }\n\n /**\n * Buffered, client-only document used when SSR is disabled for the request.\n * Emits an empty `#app` div for the client bundle to hydrate.\n */\n renderClientOnly(page: Page, head: string[]): string {\n return this.fillPlaceholders(this.pre, head)\n + `<script data-page=\"${APP_ID}\" type=\"application/json\">${this.serialize(page)}</script><div id=\"${APP_ID}\"></div>`\n + this.fillPlaceholders(this.post, head)\n }\n\n // Fill the document placeholders in a template segment. Function replacements\n // are required: a string replacement interprets `$$`, `$&`, `` $` `` and `$'`\n // patterns, which would corrupt head/script content that legitimately contains\n // a `$`. Each token is filled wherever it appears (a token absent from the\n // segment is a no-op), so placement of @viteHead/@viteScripts doesn't matter.\n private fillPlaceholders(segment: string, head: string[]): string {\n return segment\n .replace('@inertiaHead', () => head.join('\\n'))\n .replace('@viteHead', () => this.manifest.getHeadTags())\n .replace('@viteScripts', () => this.manifest.getScriptTags())\n }\n\n private serialize(page: Page): string {\n return JSON.stringify(page).replace(/\\//g, '\\\\/')\n }\n}\n","import { ApplicationError, type ApplicationErrorConstructor, type ExceptionHandler, type HttpExceptionContext } from 'stratal/errors'\nimport type { AsyncModuleOptions, DynamicModule, OnException, OnInitialize } from 'stratal/module'\nimport { Module } from 'stratal/module'\nimport { SchemaValidationError, type RouteConfigurable, type Router } from 'stratal/router'\nimport { augmentRouterContext } from './augment/router-context'\nimport type { InertiaModuleOptions } from './inertia.options'\nimport { INERTIA_TOKENS } from './inertia.tokens'\nimport { InertiaMiddleware } from './middleware/inertia.middleware'\nimport { HreflangService } from './services/hreflang.service'\nimport { InertiaService } from './services/inertia.service'\nimport { ManifestService } from './services/manifest.service'\nimport { SeoService } from './services/seo.service'\nimport { SsrRendererService } from './services/ssr-renderer.service'\nimport { TemplateService } from './services/template.service'\n\n@Module({\n providers: [\n { provide: INERTIA_TOKENS.InertiaService, useClass: InertiaService },\n { provide: INERTIA_TOKENS.TemplateService, useClass: TemplateService },\n { provide: INERTIA_TOKENS.ManifestService, useClass: ManifestService },\n { provide: INERTIA_TOKENS.SsrRenderer, useClass: SsrRendererService },\n { provide: INERTIA_TOKENS.HreflangService, useClass: HreflangService },\n { provide: INERTIA_TOKENS.SeoService, useClass: SeoService },\n ],\n})\nexport class InertiaModule implements RouteConfigurable, OnInitialize, OnException {\n static forRoot(options: InertiaModuleOptions): DynamicModule {\n return {\n module: InertiaModule,\n providers: [\n { provide: INERTIA_TOKENS.Options, useValue: options },\n ],\n }\n }\n\n static forRootAsync(options: AsyncModuleOptions<InertiaModuleOptions>): DynamicModule {\n return {\n module: InertiaModule,\n providers: [\n {\n provide: INERTIA_TOKENS.Options,\n useFactory: options.useFactory,\n inject: options.inject,\n },\n ],\n }\n }\n\n configureRoutes(router: Router): void {\n router.use(InertiaMiddleware)\n }\n\n onException(handler: ExceptionHandler): void {\n // Convert Zod validation errors to Inertia form errors\n handler.renderable(SchemaValidationError, (error, context) => {\n if (context.type !== 'http') return undefined\n\n if (this.isPrecognitionRequest(context)) {\n return this.handlePrecognitionValidationError(error, context)\n }\n\n if (!this.isInertiaRequest(context)) return undefined\n\n // GET/HEAD navigations (including deferred partial reloads) can't use the\n // flash-errors + redirect-back convention — see `isReadRequest`. Fall\n // through to the errorPage pipeline so the error renders in place.\n if (this.isReadRequest(context)) return undefined\n\n const issues = error.issues ?? []\n const errors: Record<string, string> = {}\n for (const issue of issues) {\n errors[issue.path] = issue.message\n }\n\n context.ctx.flash('errors', errors)\n return this.redirectBack(context)\n })\n\n // Convert business ApplicationErrors to Inertia form-level errors\n handler.renderable(ApplicationError as unknown as ApplicationErrorConstructor, (error, context) => {\n if (context.type !== 'http') return undefined\n\n const message = error.message\n\n if (this.isPrecognitionRequest(context)) {\n return this.createPrecognitionErrorResponse({ _form: message })\n }\n\n if (!this.isInertiaRequest(context)) return undefined\n\n // GET/HEAD navigations (including deferred partial reloads) can't use the\n // flash-errors + redirect-back convention — see `isReadRequest`. Fall\n // through to the errorPage pipeline so the error renders in place.\n if (this.isReadRequest(context)) return undefined\n\n context.ctx.flash('errors', { _form: message } as const)\n return this.redirectBack(context)\n })\n\n // Render full Inertia error pages for HTTP HTML requests. Convention:\n // consumers ship `pages/Errors/${status}.tsx` (e.g. Errors/404, Errors/500).\n handler.errorPage(async (errorResponse, status, context) => {\n try {\n const inertia = context.ctx.getContainer().resolve<InertiaService>(INERTIA_TOKENS.InertiaService)\n return await inertia.render(\n context.ctx,\n `Errors/${status}`,\n { status, message: errorResponse.message },\n { status },\n )\n } catch {\n return undefined\n }\n })\n }\n\n onInitialize(): void {\n augmentRouterContext((ctx) => {\n const requestContainer = ctx.getContainer()\n return requestContainer.resolve<InertiaService>(INERTIA_TOKENS.InertiaService)\n })\n }\n\n private isInertiaRequest(context: HttpExceptionContext): boolean {\n return context.ctx.header('x-inertia') === 'true'\n }\n\n /**\n * GET/HEAD requests are idempotent navigations — including Inertia deferred\n * partial reloads, which fetch deferred props over a follow-up XHR that still\n * carries `X-Inertia: true`.\n *\n * Such requests must NOT use the flash-errors + redirect-back convention: the\n * redirect points back at the very URL that just threw, so an error raised\n * while resolving a deferred prop would redirect → re-request → throw again\n * in an infinite loop (`ERR_TOO_MANY_REDIRECTS`). For these we fall through to\n * the errorPage pipeline, which renders `Errors/${status}` in place as an\n * Inertia response. Redirect-back stays for mutations (POST/PUT/PATCH/DELETE),\n * where it drives the post-submit form-error flow.\n */\n private isReadRequest(context: HttpExceptionContext): boolean {\n const method = context.ctx.c.req.method.toUpperCase()\n return method === 'GET' || method === 'HEAD'\n }\n\n private isPrecognitionRequest(context: HttpExceptionContext): boolean {\n return context.ctx.header('precognition') === 'true'\n }\n\n private handlePrecognitionValidationError(error: SchemaValidationError, context: HttpExceptionContext): Response {\n const issues = error.issues ?? []\n let errors: Record<string, string> = {}\n for (const issue of issues) {\n errors[issue.path] = issue.message\n }\n\n // Filter to only requested fields if Precognition-Validate-Only is present\n const validateOnly = context.ctx.header('precognition-validate-only')\n if (validateOnly) {\n const fields = validateOnly.split(',').map(f => f.trim())\n const filtered: Record<string, string> = {}\n for (const field of fields) {\n if (errors[field]) {\n filtered[field] = errors[field]\n }\n }\n errors = filtered\n }\n\n // If after filtering there are no errors for the requested fields, treat as success\n if (Object.keys(errors).length === 0) {\n return new Response(null, {\n status: 204,\n headers: {\n 'Precognition': 'true',\n 'Precognition-Success': 'true',\n 'Vary': 'Precognition',\n },\n })\n }\n\n return this.createPrecognitionErrorResponse(errors)\n }\n\n private createPrecognitionErrorResponse(errors: Record<string, string>): Response {\n return new Response(JSON.stringify({ errors }), {\n status: 422,\n headers: {\n 'Content-Type': 'application/json',\n 'Precognition': 'true',\n 'Vary': 'Precognition',\n },\n })\n }\n\n private redirectBack(context: HttpExceptionContext): Response {\n const referer = context.ctx.header('referer')\n if (referer) {\n const parsed = new URL(referer)\n const url = parsed.search ? `${parsed.pathname}${parsed.search}` : parsed.pathname\n return context.ctx.redirect(url, 303)\n }\n return context.ctx.redirect('/', 303)\n }\n}\n","import { deleteCookie, getSignedCookie, setSignedCookie } from 'hono/cookie'\nimport type { CookieOptions } from 'hono/utils/cookie'\nimport type { RouterContext } from 'stratal/router'\nimport type { FlashStore } from './flash-store'\n\nexport interface CookieFlashStoreOptions {\n secret: string | BufferSource\n cookie?: string\n cookieOptions?: CookieOptions\n}\n\nexport class CookieFlashStore implements FlashStore {\n private readonly cookieName: string\n private readonly secret: string | BufferSource\n private readonly cookieOptions: CookieOptions\n\n constructor(options: CookieFlashStoreOptions) {\n this.secret = options.secret\n this.cookieName = options.cookie ?? 'stratal_flash'\n this.cookieOptions = {\n path: '/',\n httpOnly: true,\n sameSite: 'Lax',\n ...options.cookieOptions,\n }\n }\n\n async read(ctx: RouterContext): Promise<Record<string, unknown>> {\n const value = await getSignedCookie(ctx.c, this.secret, this.cookieName)\n if (!value) return {}\n\n try {\n return JSON.parse(atob(value)) as Record<string, unknown>\n } catch {\n return {}\n }\n }\n\n async write(ctx: RouterContext, data: Record<string, unknown>): Promise<void> {\n const encoded = btoa(JSON.stringify(data))\n await setSignedCookie(ctx.c, this.cookieName, encoded, this.secret, this.cookieOptions)\n }\n\n clear(ctx: RouterContext): Promise<void> {\n deleteCookie(ctx.c, this.cookieName, { path: this.cookieOptions.path })\n return Promise.resolve()\n }\n}\n","import type { RouteConfig } from 'stratal/router'\nimport { Delete, Get, Patch, Post, Put, Route } from 'stratal/router'\nimport { z } from 'stratal/validation'\n\n/**\n * Zod schema for the Inertia page JSON response (returned for X-Inertia XHR requests)\n */\nexport const inertiaPageSchema = z.object({\n component: z.string(),\n props: z.record(z.string(), z.unknown()),\n url: z.string(),\n version: z.string().nullable(),\n flash: z.record(z.string(), z.unknown()),\n rememberedState: z.record(z.string(), z.unknown()),\n mergeProps: z.array(z.string()).optional(),\n prependProps: z.array(z.string()).optional(),\n deepMergeProps: z.array(z.string()).optional(),\n matchPropsOn: z.array(z.string()).optional(),\n deferredProps: z.record(z.string(), z.array(z.string())).optional(),\n initialDeferredProps: z.record(z.string(), z.array(z.string())).optional(),\n onceProps: z.record(z.string(), z.object({ prop: z.string(), expiresAt: z.number().nullable().optional() })).optional(),\n sharedProps: z.array(z.string()).optional(),\n encryptHistory: z.boolean().optional(),\n clearHistory: z.boolean().optional(),\n preserveFragment: z.boolean().optional(),\n})\n\nexport type InertiaRouteConfig = Omit<RouteConfig, 'response' | 'statusCode' | 'hideFromDocs'> & {\n hideFromDocs?: boolean\n}\n\nconst inertiaResponse = {\n schema: inertiaPageSchema,\n description: 'Inertia page response',\n contentType: 'text/html',\n} as const\n\n/**\n * Builds a full RouteConfig from InertiaRouteConfig by applying inertia defaults.\n */\nfunction buildInertiaConfig(config: InertiaRouteConfig): Omit<RouteConfig, 'statusCode'> {\n const { hideFromDocs = true, ...rest } = config\n return { ...rest, response: inertiaResponse, hideFromDocs }\n}\n\n/**\n * Decorator for Inertia page routes using convention-based routing.\n *\n * Wraps `@Route()` with:\n * - Auto-applied Inertia page response schema\n * - `hideFromDocs: true` by default (overridable)\n *\n * **Cannot be mixed with HTTP method decorators** (`@Get`, `@Post`, `@InertiaGet`, etc.)\n * in the same controller.\n *\n * @example\n * ```typescript\n * @Controller('/notes')\n * export class NotesController implements IController {\n * @InertiaRoute({ query: z.object({ page: z.string().optional() }) })\n * async index(ctx: RouterContext) {\n * return ctx.inertia('notes/Index', { notes: [] })\n * }\n * }\n * ```\n */\nexport function InertiaRoute(config: InertiaRouteConfig = {}) {\n return Route(buildInertiaConfig(config))\n}\n\n/**\n * Registers a GET route for an Inertia page.\n *\n * Wraps `@Get()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (query, params, tags, etc.)\n *\n * @example\n * ```typescript\n * @Controller('/notes')\n * export class NotesController {\n * @InertiaGet('/')\n * async index(ctx: RouterContext) {\n * return ctx.inertia('notes/Index', { notes: [] })\n * }\n *\n * @InertiaGet('/:id', { params: z.object({ id: z.string() }) })\n * async show(ctx: RouterContext) {\n * return ctx.inertia('notes/Show', { note })\n * }\n * }\n * ```\n */\nexport function InertiaGet(path: string, config: InertiaRouteConfig = {}) {\n return Get(path, buildInertiaConfig(config))\n}\n\n/**\n * Registers a POST route for an Inertia form submission.\n *\n * Wraps `@Post()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (body, params, tags, etc.)\n */\nexport function InertiaPost(path: string, config: InertiaRouteConfig = {}) {\n return Post(path, buildInertiaConfig(config))\n}\n\n/**\n * Registers a PUT route for an Inertia form submission.\n *\n * Wraps `@Put()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (body, params, tags, etc.)\n */\nexport function InertiaPut(path: string, config: InertiaRouteConfig = {}) {\n return Put(path, buildInertiaConfig(config))\n}\n\n/**\n * Registers a PATCH route for an Inertia form submission.\n *\n * Wraps `@Patch()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (body, params, tags, etc.)\n */\nexport function InertiaPatch(path: string, config: InertiaRouteConfig = {}) {\n return Patch(path, buildInertiaConfig(config))\n}\n\n/**\n * Registers a DELETE route for an Inertia form submission.\n *\n * Wraps `@Delete()` with auto-applied Inertia page response schema\n * and `hideFromDocs: true` by default.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (params, tags, etc.)\n */\nexport function InertiaDelete(path: string, config: InertiaRouteConfig = {}) {\n return Delete(path, buildInertiaConfig(config))\n}\n","import { Transient } from 'stratal/di'\nimport type { Middleware, Next, RouterContext } from 'stratal/router'\n\n@Transient()\nexport class HandlePrecognitiveRequests implements Middleware {\n async handle(ctx: RouterContext, next: Next): Promise<void> {\n const isPrecognition = ctx.header('precognition') === 'true'\n ctx.c.set('precognition', isPrecognition)\n\n if (isPrecognition) {\n ctx.c.set('validationSuccessResponse', new Response(null, {\n status: 204,\n headers: {\n 'Precognition': 'true',\n 'Precognition-Success': 'true',\n 'Vary': 'Precognition',\n },\n }))\n }\n\n await next()\n }\n}\n"],"mappings":"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"}
package/dist/quarry.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Command } from "stratal/quarry";
2
+
2
3
  //#region src/commands/inertia-build.command.d.ts
3
4
  declare class InertiaBuildCommand extends Command {
4
5
  static command: string;
@@ -20,6 +21,14 @@ declare class InertiaInstallCommand extends Command {
20
21
  static description: string;
21
22
  handle(): Promise<number | undefined>;
22
23
  private updateAppModule;
24
+ /**
25
+ * Ensure an existing `InertiaModule.forRoot({...})` call opts into the streaming
26
+ * SSR bundle. Returns `ssr-added` when the option is inserted, `unchanged` when
27
+ * one is already present, or `unwired` when no plain `forRoot({...})` object
28
+ * literal is found (e.g. `forRootAsync`, or a config passed by reference) — in
29
+ * which case the caller surfaces a manual instruction.
30
+ */
31
+ private ensureSsrWiring;
23
32
  }
24
33
  //#endregion
25
34
  //#region src/commands/inertia-types.command.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"quarry.d.mts","names":[],"sources":["../src/commands/inertia-build.command.ts","../src/commands/inertia-dev.command.ts","../src/commands/inertia-install.command.ts","../src/commands/inertia-types.command.ts","../src/generator/type-generator.ts","../src/quarry.ts"],"mappings":";;cAOa,mBAAA,SAA4B,OAAA;EAAA,OAChC,OAAA;EAAA,OACA,WAAA;EAED,MAAA,CAAA,GAAU,OAAA;EAAA,QA8DR,SAAA;AAAA;;;cCnEG,iBAAA,SAA0B,OAAA;EAAA,OAC9B,OAAA;EAAA,OACA,WAAA;EAED,MAAA,CAAA,GAAU,OAAA;AAAA;;;cC6BL,qBAAA,SAA8B,OAAA;EAAA,OAClC,OAAA;EAAA,OACA,WAAA;EAED,MAAA,CAAA,GAAU,OAAA;EAAA,QA4EF,eAAA;AAAA;;;cCjHH,mBAAA,SAA4B,OAAA;EAAA,OAChC,OAAA;EAAA,OACA,WAAA;EAED,MAAA,CAAA,GAAU,OAAA;EAAA,QAoBF,QAAA;EAAA,QAYA,eAAA;AAAA;;;iBCqtBM,iBAAA,CAAkB,GAAA,WAAc,OAAA;EAAU,UAAA;EAAoB,SAAA;AAAA;;;cCjvBvE,mBAAA"}
1
+ {"version":3,"file":"quarry.d.mts","names":[],"sources":["../src/commands/inertia-build.command.ts","../src/commands/inertia-dev.command.ts","../src/commands/inertia-install.command.ts","../src/commands/inertia-types.command.ts","../src/generator/type-generator.ts","../src/quarry.ts"],"mappings":";;;cAOa,mBAAA,SAA4B,OAAO;EAAA,OACvC,OAAA;EAAA,OACA,WAAA;EAED,MAAA,IAAU,OAAA;EAAA,QA8DR,SAAA;AAAA;;;cCnEG,iBAAA,SAA0B,OAAO;EAAA,OACrC,OAAA;EAAA,OACA,WAAA;EAED,MAAA,IAAU,OAAA;AAAA;;;cCqDL,qBAAA,SAA8B,OAAO;EAAA,OACzC,OAAA;EAAA,OACA,WAAA;EAED,MAAA,IAAU,OAAA;EAAA,QAkFF,eAAA;EF9IgC;;;;;;;EAAA,QEoNtC,eAAA;AAAA;;;cCrNG,mBAAA,SAA4B,OAAO;EAAA,OACvC,OAAA;EAAA,OACA,WAAA;EAED,MAAA,IAAU,OAAA;EAAA,QAoBF,QAAA;EAAA,QAYA,eAAA;AAAA;;;iBCs7BM,iBAAA,CAAkB,GAAA,WAAc,OAAO;EAAG,UAAA;EAAoB,SAAA;AAAA;;;cCl9BvE,mBAAA"}
package/dist/quarry.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { t as __decorate } from "./decorate-CzXVx7ZH.mjs";
2
- import { n as runTypeGeneration, t as findPagesDir } from "./type-generator-bfo14BJI.mjs";
1
+ import { t as __decorate } from "./decorate-B7nr7eBl.mjs";
2
+ import { n as runTypeGeneration, t as findPagesDir } from "./type-generator-DFpha_Fp.mjs";
3
3
  import { Module } from "stratal/module";
4
4
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
5
5
  import { dirname, join, relative } from "node:path";
@@ -64,12 +64,12 @@ try {
64
64
  } catch {}
65
65
 
66
66
  const baseConfig = {
67
+ publicDir: 'src/inertia/public',
67
68
  plugins: [
68
69
  cloudflare(${options.persistTo ? `{ persistState: { path: ${JSON.stringify(options.persistTo)} } }` : ""}),
69
70
  ...(inertiaPlugin ? [inertiaPlugin] : []),
70
71
  ...stratalInertia(${options.clientManifestPath ? `{ clientManifestPath: ${JSON.stringify(options.clientManifestPath)} }` : ""}),
71
72
  ],
72
- publicDir: '${join(options.cwd, "src", "inertia", "public").replace(/\\/g, "/")}',
73
73
  build: {
74
74
  ${outDirConfig}
75
75
  },
@@ -227,6 +227,16 @@ createInertiaApp({
227
227
  return page
228
228
  },
229
229
  })`;
230
+ const SSR_TSX = `import { createInertiaSsrApp } from '@stratal/inertia/ssr'
231
+
232
+ export const { render } = createInertiaSsrApp({
233
+ resolve: async (name) => {
234
+ const pages = import.meta.glob('./pages/**/*.tsx')
235
+ const page = await pages[\`./pages/\${name}.tsx\`]?.()
236
+ if (!page) throw new Error(\`Page not found: \${name}\`)
237
+ return page
238
+ },
239
+ })`;
230
240
  const HOME_TSX = `export default function Home({ message }: { message: string }) {
231
241
  return (
232
242
  <div>
@@ -261,6 +271,11 @@ var InertiaInstallCommand = class extends Command {
261
271
  content: APP_TSX,
262
272
  name: "app.tsx"
263
273
  },
274
+ {
275
+ path: join(inertiaDir, "ssr.tsx"),
276
+ content: SSR_TSX,
277
+ name: "ssr.tsx"
278
+ },
264
279
  {
265
280
  path: join(pagesDir, "Home.tsx"),
266
281
  content: HOME_TSX,
@@ -276,8 +291,14 @@ var InertiaInstallCommand = class extends Command {
276
291
  if (existsSync(appModulePath)) {
277
292
  this.info("Updating src/app.module.ts...");
278
293
  try {
279
- if (await this.updateAppModule(appModulePath)) this.success("Updated src/app.module.ts with InertiaModule");
280
- else this.info("InertiaModule already configured in app.module.ts");
294
+ const result = await this.updateAppModule(appModulePath);
295
+ if (result === "created") this.success("Updated src/app.module.ts with InertiaModule");
296
+ else if (result === "ssr-added") this.success("Enabled streaming SSR in src/app.module.ts");
297
+ else if (result === "unchanged") this.info("InertiaModule (with SSR) already configured in app.module.ts");
298
+ else {
299
+ this.warn("InertiaModule is configured but SSR could not be auto-wired.");
300
+ this.info("Add `ssr: { bundle: () => import('./inertia/ssr') }` to your InertiaModule options");
301
+ }
281
302
  } catch (err) {
282
303
  this.warn(`Could not auto-update app.module.ts: ${err.message}`);
283
304
  this.info("Please manually add InertiaModule.forRoot() to your module imports");
@@ -304,7 +325,11 @@ var InertiaInstallCommand = class extends Command {
304
325
  async updateAppModule(modulePath) {
305
326
  const { Project, SyntaxKind } = await import("ts-morph");
306
327
  const sourceFile = new Project({ useInMemoryFileSystem: false }).addSourceFileAtPath(modulePath);
307
- if (sourceFile.getImportDeclaration((decl) => decl.getModuleSpecifierValue() === "@stratal/inertia")) return false;
328
+ if (sourceFile.getImportDeclaration((decl) => decl.getModuleSpecifierValue() === "@stratal/inertia")) {
329
+ const result = this.ensureSsrWiring(sourceFile, SyntaxKind);
330
+ if (result === "ssr-added") await sourceFile.save();
331
+ return result;
332
+ }
308
333
  sourceFile.addImportDeclaration({
309
334
  defaultImport: "rootView",
310
335
  moduleSpecifier: "./inertia/root.html?raw"
@@ -324,15 +349,37 @@ var InertiaInstallCommand = class extends Command {
324
349
  const importsProp = objLiteral.getProperty("imports");
325
350
  if (importsProp) {
326
351
  const arrayLiteral = (importsProp.asKind(SyntaxKind.PropertyAssignment)?.getInitializer())?.asKind(SyntaxKind.ArrayLiteralExpression);
327
- if (arrayLiteral) arrayLiteral.addElement(`InertiaModule.forRoot({\n rootView,\n })`);
352
+ if (arrayLiteral) arrayLiteral.addElement(`InertiaModule.forRoot({\n rootView,\n ssr: { bundle: () => import('./inertia/ssr') },\n })`);
328
353
  } else objLiteral.addPropertyAssignment({
329
354
  name: "imports",
330
- initializer: `[\n InertiaModule.forRoot({\n rootView,\n }),\n ]`
355
+ initializer: `[\n InertiaModule.forRoot({\n rootView,\n ssr: { bundle: () => import('./inertia/ssr') },\n }),\n ]`
331
356
  });
332
357
  break;
333
358
  }
334
359
  await sourceFile.save();
335
- return true;
360
+ return "created";
361
+ }
362
+ /**
363
+ * Ensure an existing `InertiaModule.forRoot({...})` call opts into the streaming
364
+ * SSR bundle. Returns `ssr-added` when the option is inserted, `unchanged` when
365
+ * one is already present, or `unwired` when no plain `forRoot({...})` object
366
+ * literal is found (e.g. `forRootAsync`, or a config passed by reference) — in
367
+ * which case the caller surfaces a manual instruction.
368
+ */
369
+ ensureSsrWiring(sourceFile, syntaxKind) {
370
+ const calls = sourceFile.getDescendantsOfKind(syntaxKind.CallExpression);
371
+ for (const call of calls) {
372
+ if (call.getExpression().getText() !== "InertiaModule.forRoot") continue;
373
+ const objLiteral = call.getArguments()[0]?.asKind(syntaxKind.ObjectLiteralExpression);
374
+ if (!objLiteral) continue;
375
+ if (objLiteral.getProperty("ssr")) return "unchanged";
376
+ objLiteral.addPropertyAssignment({
377
+ name: "ssr",
378
+ initializer: `{ bundle: () => import('./inertia/ssr') }`
379
+ });
380
+ return "ssr-added";
381
+ }
382
+ return "unwired";
336
383
  }
337
384
  };
338
385
  //#endregion