@pracht/core 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jovi De Croock
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.mts CHANGED
@@ -157,6 +157,9 @@ type LoaderData<TLoader extends LoaderLike> = TLoader extends ((...args: any[])
157
157
  interface HeadArgs<TLoader extends LoaderLike = undefined, TContext = any> extends BaseRouteArgs<TContext> {
158
158
  data: LoaderData<TLoader>;
159
159
  }
160
+ interface HeadersArgs<TLoader extends LoaderLike = undefined, TContext = any> extends BaseRouteArgs<TContext> {
161
+ data: LoaderData<TLoader>;
162
+ }
160
163
  interface RouteComponentProps<TLoader extends LoaderLike = undefined> {
161
164
  data: LoaderData<TLoader>;
162
165
  params: RouteParams;
@@ -171,6 +174,7 @@ type LoaderFn<TContext = any, TData = unknown> = (args: LoaderArgs<TContext>) =>
171
174
  interface RouteModule<TContext = any, TLoader extends LoaderLike = undefined> {
172
175
  loader?: LoaderFn<TContext>;
173
176
  head?: (args: HeadArgs<TLoader, TContext>) => MaybePromise<HeadMetadata>;
177
+ headers?: (args: HeadersArgs<TLoader, TContext>) => MaybePromise<HeadersInit>;
174
178
  Component?: FunctionComponent<RouteComponentProps<TLoader>>;
175
179
  default?: FunctionComponent<RouteComponentProps<TLoader>>;
176
180
  ErrorBoundary?: FunctionComponent<ErrorBoundaryProps>;
@@ -180,6 +184,7 @@ interface ShellModule<TContext = any> {
180
184
  Shell: FunctionComponent<ShellProps>;
181
185
  Loading?: FunctionComponent;
182
186
  head?: (args: BaseRouteArgs<TContext>) => MaybePromise<HeadMetadata>;
187
+ headers?: (args: BaseRouteArgs<TContext>) => MaybePromise<HeadersInit>;
183
188
  }
184
189
  type MiddlewareResult<TContext = any> = void | Response | {
185
190
  redirect: string;
@@ -351,6 +356,7 @@ declare function applyDefaultSecurityHeaders(headers: Headers): Headers;
351
356
  interface PrerenderResult {
352
357
  path: string;
353
358
  html: string;
359
+ headers?: Record<string, string>;
354
360
  }
355
361
  interface ISGManifestEntry {
356
362
  revalidate: RouteRevalidate;
@@ -397,4 +403,4 @@ interface InitClientRouterOptions {
397
403
  }
398
404
  declare function initClientRouter(options: InitClientRouterOptions): Promise<void>;
399
405
  //#endregion
400
- export { type ApiConfig, type ApiRouteArgs, type ApiRouteHandler, type ApiRouteMatch, type ApiRouteModule, type BaseRouteArgs, type DataModule, type ErrorBoundaryProps, Form, type FormProps, type GroupDefinition, type GroupMeta, type HandlePrachtRequestOptions, type HeadArgs, type HeadMetadata, type HttpMethod, type ISGManifestEntry, type InitClientRouterOptions, type LoaderArgs, type LoaderData, type LoaderFn, type Location, type MiddlewareArgs, type MiddlewareFn, type MiddlewareModule, type MiddlewareResult, type ModuleImporter, type ModuleRef, type ModuleRegistry, type NavigateFn, type PrachtApp, type PrachtAppConfig, PrachtHttpError, type PrachtHydrationState, type PrachtRuntimeDiagnosticPhase, type PrachtRuntimeDiagnostics, PrachtRuntimeProvider, type PrefetchStrategy, type PrerenderAppOptions, type PrerenderAppResult, type PrerenderResult, type Register, type RenderMode, type ResolvedApiRoute, type ResolvedPrachtApp, type ResolvedRoute, type RouteComponentProps, type RouteConfig, type RouteDefinition, type RouteMatch, type RouteMeta, type RouteModule, type RouteParams, type RouteRevalidate, type RouteStateResult, type RouteTreeNode, type SerializedRouteError, type ShellModule, type ShellProps, type StartAppOptions, Suspense, type TimeRevalidatePolicy, applyDefaultSecurityHeaders, buildPathFromSegments, defineApp, forwardRef, group, handlePrachtRequest, initClientRouter, lazy, matchApiRoute, matchAppRoute, prerenderApp, readHydrationState, resolveApiRoutes, resolveApp, route, startApp, timeRevalidate, useIsHydrated, useLocation, useNavigate, useParams, useRevalidate, useRevalidateRoute, useRouteData };
406
+ export { type ApiConfig, type ApiRouteArgs, type ApiRouteHandler, type ApiRouteMatch, type ApiRouteModule, type BaseRouteArgs, type DataModule, type ErrorBoundaryProps, Form, type FormProps, type GroupDefinition, type GroupMeta, type HandlePrachtRequestOptions, type HeadArgs, type HeadMetadata, type HeadersArgs, type HttpMethod, type ISGManifestEntry, type InitClientRouterOptions, type LoaderArgs, type LoaderData, type LoaderFn, type Location, type MiddlewareArgs, type MiddlewareFn, type MiddlewareModule, type MiddlewareResult, type ModuleImporter, type ModuleRef, type ModuleRegistry, type NavigateFn, type PrachtApp, type PrachtAppConfig, PrachtHttpError, type PrachtHydrationState, type PrachtRuntimeDiagnosticPhase, type PrachtRuntimeDiagnostics, PrachtRuntimeProvider, type PrefetchStrategy, type PrerenderAppOptions, type PrerenderAppResult, type PrerenderResult, type Register, type RenderMode, type ResolvedApiRoute, type ResolvedPrachtApp, type ResolvedRoute, type RouteComponentProps, type RouteConfig, type RouteDefinition, type RouteMatch, type RouteMeta, type RouteModule, type RouteParams, type RouteRevalidate, type RouteStateResult, type RouteTreeNode, type SerializedRouteError, type ShellModule, type ShellProps, type StartAppOptions, Suspense, type TimeRevalidatePolicy, applyDefaultSecurityHeaders, buildPathFromSegments, defineApp, forwardRef, group, handlePrachtRequest, initClientRouter, lazy, matchApiRoute, matchAppRoute, prerenderApp, readHydrationState, resolveApiRoutes, resolveApp, route, startApp, timeRevalidate, useIsHydrated, useLocation, useNavigate, useParams, useRevalidate, useRevalidateRoute, useRouteData };
package/dist/index.mjs CHANGED
@@ -333,6 +333,7 @@ async function handlePrachtRequest(options) {
333
333
  currentPhase = "render";
334
334
  shellModule = match.route.shellFile ? await resolveRegistryModule(registry.shellModules, match.route.shellFile) : void 0;
335
335
  const head = await mergeHeadMetadata(shellModule, routeModule, routeArgs, data);
336
+ const documentHeaders = await mergeDocumentHeaders(shellModule, routeModule, routeArgs, data);
336
337
  const cssUrls = resolvePageCssUrls(options, match.route.shellFile, match.route.file);
337
338
  const modulePreloadUrls = resolvePageJsUrls(options, match.route.shellFile, match.route.file);
338
339
  if (match.route.render === "spa") {
@@ -356,7 +357,7 @@ async function handlePrachtRequest(options) {
356
357
  clientEntryUrl: options.clientEntryUrl,
357
358
  cssUrls,
358
359
  modulePreloadUrls
359
- }));
360
+ }), 200, documentHeaders);
360
361
  }
361
362
  const DefaultComponent = typeof routeModule.default === "function" ? routeModule.default : void 0;
362
363
  const Component = routeModule.Component ?? DefaultComponent;
@@ -385,7 +386,7 @@ async function handlePrachtRequest(options) {
385
386
  clientEntryUrl: options.clientEntryUrl,
386
387
  cssUrls,
387
388
  modulePreloadUrls
388
- }));
389
+ }), 200, documentHeaders);
389
390
  } catch (error) {
390
391
  return renderRouteErrorResponse({
391
392
  error,
@@ -596,6 +597,7 @@ async function renderRouteErrorResponse(options) {
596
597
  if (options.isRouteStateRequest) return jsonErrorResponse(routeErrorWithDiagnostics, { isRouteStateRequest: true });
597
598
  const shellModule = options.shellModule ?? (options.shellFile ? await resolveRegistryModule(options.options.registry?.shellModules, options.shellFile) : void 0);
598
599
  const head = shellModule?.head ? await shellModule.head(options.routeArgs) : {};
600
+ const documentHeaders = await mergeDocumentHeaders(shellModule, void 0, options.routeArgs, void 0);
599
601
  const cssUrls = resolvePageCssUrls(options.options, options.shellFile, options.routeArgs.route.file);
600
602
  const modulePreloadUrls = resolvePageJsUrls(options.options, options.shellFile, options.routeArgs.route.file);
601
603
  const renderToString = await getRenderToStringAsync();
@@ -619,7 +621,7 @@ async function renderRouteErrorResponse(options) {
619
621
  clientEntryUrl: options.options.clientEntryUrl,
620
622
  cssUrls,
621
623
  modulePreloadUrls
622
- }), routeErrorWithDiagnostics.status);
624
+ }), routeErrorWithDiagnostics.status, documentHeaders);
623
625
  }
624
626
  async function runMiddlewareChain(options) {
625
627
  let context = options.context;
@@ -681,6 +683,22 @@ async function mergeHeadMetadata(shellModule, routeModule, routeArgs, data) {
681
683
  link: [...shellHead.link ?? [], ...routeHead.link ?? []]
682
684
  };
683
685
  }
686
+ async function mergeDocumentHeaders(shellModule, routeModule, routeArgs, data) {
687
+ const headers = new Headers();
688
+ const shellHeaders = shellModule?.headers ? await shellModule.headers(routeArgs) : void 0;
689
+ if (shellHeaders) applyHeaders(headers, shellHeaders);
690
+ const routeHeaders = routeModule?.headers ? await routeModule.headers({
691
+ ...routeArgs,
692
+ data
693
+ }) : void 0;
694
+ if (routeHeaders) applyHeaders(headers, routeHeaders);
695
+ return headers;
696
+ }
697
+ function applyHeaders(headers, init) {
698
+ new Headers(init).forEach((value, key) => {
699
+ headers.set(key, value);
700
+ });
701
+ }
684
702
  function buildHtmlDocument(options) {
685
703
  const { head, body, hydrationState, clientEntryUrl, cssUrls = [], modulePreloadUrls = [] } = options;
686
704
  const titleTag = head.title ? `<title>${escapeHtml(head.title)}</title>` : "";
@@ -707,8 +725,10 @@ function buildHtmlDocument(options) {
707
725
  </body>
708
726
  </html>`;
709
727
  }
710
- function htmlResponse(html, status = 200) {
711
- const headers = applySecurityAndRouteHeaders(new Headers({ "content-type": "text/html; charset=utf-8" }), { isRouteStateRequest: false });
728
+ function htmlResponse(html, status = 200, initHeaders) {
729
+ const headers = new Headers({ "content-type": "text/html; charset=utf-8" });
730
+ if (initHeaders) applyHeaders(headers, initHeaders);
731
+ applySecurityAndRouteHeaders(headers, { isRouteStateRequest: false });
712
732
  return new Response(html, {
713
733
  status,
714
734
  headers
@@ -796,16 +816,19 @@ async function prerenderApp(options) {
796
816
  console.warn(` Warning: ${item.render.toUpperCase()} route "${item.pathname}" returned status ${response.status}, skipping.`);
797
817
  return null;
798
818
  }
819
+ const html = await response.text();
799
820
  return {
800
- item,
801
- html: await response.text()
821
+ headers: Object.fromEntries(response.headers),
822
+ html,
823
+ item
802
824
  };
803
825
  }));
804
826
  for (const result of batchResults) {
805
827
  if (!result) continue;
806
828
  results.push({
807
829
  path: result.item.pathname,
808
- html: result.html
830
+ html: result.html,
831
+ headers: result.headers
809
832
  });
810
833
  if (result.item.render === "isg" && result.item.revalidate) isgManifest[result.item.pathname] = { revalidate: result.item.revalidate };
811
834
  }
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@pracht/core",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
+ "license": "MIT",
4
5
  "homepage": "https://github.com/JoviDeCroock/pracht/tree/main/packages/framework",
5
6
  "bugs": {
6
7
  "url": "https://github.com/JoviDeCroock/pracht/issues"