qlara 0.1.8 → 0.1.9

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/dist/aws.cjs CHANGED
@@ -562,7 +562,7 @@ async function bundleEdgeHandler(config) {
562
562
  });
563
563
  return createZip(outfile, "edge-handler.js");
564
564
  }
565
- async function bundleRenderer(routeFile, cacheTtl = 3600) {
565
+ async function bundleRenderer(routeFile, cacheTtl = 3600, framework) {
566
566
  (0, import_node_fs2.mkdirSync)(BUNDLE_DIR, { recursive: true });
567
567
  const outfile = (0, import_node_path2.join)(BUNDLE_DIR, "renderer.js");
568
568
  const alias = {};
@@ -584,7 +584,8 @@ async function bundleRenderer(routeFile, cacheTtl = 3600) {
584
584
  minify: true,
585
585
  alias,
586
586
  define: {
587
- __QLARA_CACHE_TTL__: String(cacheTtl)
587
+ __QLARA_CACHE_TTL__: String(cacheTtl),
588
+ __QLARA_FRAMEWORK__: JSON.stringify(framework || "")
588
589
  },
589
590
  external: []
590
591
  });
@@ -964,7 +965,7 @@ function aws(awsConfig = {}) {
964
965
  const cf = new import_client_cloudfront.CloudFrontClient({ region: res.region });
965
966
  await updateCloudFrontEdgeVersion(cf, res.distributionId, newVersionArn);
966
967
  console.log("[qlara/aws] Bundling renderer...");
967
- const rendererZip = await bundleRenderer(config.routeFile, cacheTtl);
968
+ const rendererZip = await bundleRenderer(config.routeFile, cacheTtl, config.framework);
968
969
  await (0, import_client_lambda.waitUntilFunctionUpdatedV2)(
969
970
  { client: lambda, maxWaitTime: 120 },
970
971
  { FunctionName: res.rendererFunctionArn }
package/dist/aws.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as ProviderResources, Q as QlaraProvider } from './types-gl2xFqEX.cjs';
1
+ import { P as ProviderResources, Q as QlaraProvider } from './types--KPPgCtc.cjs';
2
2
 
3
3
  interface AwsConfig {
4
4
  stackName?: string;
package/dist/aws.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as ProviderResources, Q as QlaraProvider } from './types-gl2xFqEX.js';
1
+ import { P as ProviderResources, Q as QlaraProvider } from './types--KPPgCtc.js';
2
2
 
3
3
  interface AwsConfig {
4
4
  stackName?: string;
package/dist/aws.js CHANGED
@@ -558,7 +558,7 @@ async function bundleEdgeHandler(config) {
558
558
  });
559
559
  return createZip(outfile, "edge-handler.js");
560
560
  }
561
- async function bundleRenderer(routeFile, cacheTtl = 3600) {
561
+ async function bundleRenderer(routeFile, cacheTtl = 3600, framework) {
562
562
  mkdirSync(BUNDLE_DIR, { recursive: true });
563
563
  const outfile = join2(BUNDLE_DIR, "renderer.js");
564
564
  const alias = {};
@@ -580,7 +580,8 @@ async function bundleRenderer(routeFile, cacheTtl = 3600) {
580
580
  minify: true,
581
581
  alias,
582
582
  define: {
583
- __QLARA_CACHE_TTL__: String(cacheTtl)
583
+ __QLARA_CACHE_TTL__: String(cacheTtl),
584
+ __QLARA_FRAMEWORK__: JSON.stringify(framework || "")
584
585
  },
585
586
  external: []
586
587
  });
@@ -960,7 +961,7 @@ function aws(awsConfig = {}) {
960
961
  const cf = new CloudFrontClient({ region: res.region });
961
962
  await updateCloudFrontEdgeVersion(cf, res.distributionId, newVersionArn);
962
963
  console.log("[qlara/aws] Bundling renderer...");
963
- const rendererZip = await bundleRenderer(config.routeFile, cacheTtl);
964
+ const rendererZip = await bundleRenderer(config.routeFile, cacheTtl, config.framework);
964
965
  await waitUntilFunctionUpdatedV2(
965
966
  { client: lambda, maxWaitTime: 120 },
966
967
  { FunctionName: res.rendererFunctionArn }
package/dist/cli.js CHANGED
@@ -569,7 +569,7 @@ async function bundleEdgeHandler(config) {
569
569
  });
570
570
  return createZip(outfile, "edge-handler.js");
571
571
  }
572
- async function bundleRenderer(routeFile, cacheTtl = 3600) {
572
+ async function bundleRenderer(routeFile, cacheTtl = 3600, framework) {
573
573
  mkdirSync(BUNDLE_DIR, { recursive: true });
574
574
  const outfile = join2(BUNDLE_DIR, "renderer.js");
575
575
  const alias = {};
@@ -591,7 +591,8 @@ async function bundleRenderer(routeFile, cacheTtl = 3600) {
591
591
  minify: true,
592
592
  alias,
593
593
  define: {
594
- __QLARA_CACHE_TTL__: String(cacheTtl)
594
+ __QLARA_CACHE_TTL__: String(cacheTtl),
595
+ __QLARA_FRAMEWORK__: JSON.stringify(framework || "")
595
596
  },
596
597
  external: []
597
598
  });
@@ -968,7 +969,7 @@ function aws(awsConfig = {}) {
968
969
  const cf = new CloudFrontClient({ region: res.region });
969
970
  await updateCloudFrontEdgeVersion(cf, res.distributionId, newVersionArn);
970
971
  console.log("[qlara/aws] Bundling renderer...");
971
- const rendererZip = await bundleRenderer(config.routeFile, cacheTtl);
972
+ const rendererZip = await bundleRenderer(config.routeFile, cacheTtl, config.framework);
972
973
  await waitUntilFunctionUpdatedV2(
973
974
  { client: lambda, maxWaitTime: 120 },
974
975
  { FunctionName: res.rendererFunctionArn }
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as QlaraPluginConfig, b as QlaraRoute, c as QlaraManifest, M as ManifestRoute, R as RouteMatch } from './types-gl2xFqEX.cjs';
2
- export { P as ProviderResources, d as QlaraAlternateLinkDescriptor, e as QlaraAlternateURLs, f as QlaraAppLinks, g as QlaraAppLinksAndroid, h as QlaraAppLinksApple, i as QlaraAppLinksWeb, j as QlaraAppLinksWindows, k as QlaraAppleImage, l as QlaraAppleImageDescriptor, m as QlaraAppleWebApp, n as QlaraAuthor, o as QlaraDeployConfig, p as QlaraFacebook, q as QlaraFormatDetection, r as QlaraIcon, s as QlaraIconDescriptor, t as QlaraIcons, u as QlaraItunesApp, v as QlaraMetaDataGenerator, w as QlaraMetadata, x as QlaraOGAudio, y as QlaraOGAudioDescriptor, z as QlaraOGImage, A as QlaraOGImageDescriptor, B as QlaraOGVideo, C as QlaraOGVideoDescriptor, D as QlaraOpenGraph, E as QlaraOpenGraphArticle, F as QlaraOpenGraphBase, G as QlaraOpenGraphBook, H as QlaraOpenGraphMusicAlbum, I as QlaraOpenGraphMusicPlaylist, J as QlaraOpenGraphMusicRadioStation, K as QlaraOpenGraphMusicSong, L as QlaraOpenGraphProfile, N as QlaraOpenGraphVideoEpisode, O as QlaraOpenGraphVideoMovie, S as QlaraOpenGraphVideoOther, T as QlaraOpenGraphVideoTVShow, U as QlaraOpenGraphWebsite, V as QlaraPinterest, Q as QlaraProvider, W as QlaraReferrer, X as QlaraRobots, Y as QlaraRobotsInfo, Z as QlaraRouteDefinition, _ as QlaraRoutes, $ as QlaraTwitter, a0 as QlaraTwitterApp, a1 as QlaraTwitterAppDescriptor, a2 as QlaraTwitterBase, a3 as QlaraTwitterImage, a4 as QlaraTwitterImageDescriptor, a5 as QlaraTwitterPlayer, a6 as QlaraTwitterPlayerDescriptor, a7 as QlaraTwitterSummary, a8 as QlaraTwitterSummaryLargeImage, a9 as QlaraVerification } from './types-gl2xFqEX.cjs';
1
+ import { a as QlaraPluginConfig, b as QlaraRoute, c as QlaraManifest, M as ManifestRoute, R as RouteMatch } from './types--KPPgCtc.cjs';
2
+ export { P as ProviderResources, d as QlaraAlternateLinkDescriptor, e as QlaraAlternateURLs, f as QlaraAppLinks, g as QlaraAppLinksAndroid, h as QlaraAppLinksApple, i as QlaraAppLinksWeb, j as QlaraAppLinksWindows, k as QlaraAppleImage, l as QlaraAppleImageDescriptor, m as QlaraAppleWebApp, n as QlaraAuthor, o as QlaraDeployConfig, p as QlaraFacebook, q as QlaraFormatDetection, r as QlaraIcon, s as QlaraIconDescriptor, t as QlaraIcons, u as QlaraItunesApp, v as QlaraMetaDataGenerator, w as QlaraMetadata, x as QlaraOGAudio, y as QlaraOGAudioDescriptor, z as QlaraOGImage, A as QlaraOGImageDescriptor, B as QlaraOGVideo, C as QlaraOGVideoDescriptor, D as QlaraOpenGraph, E as QlaraOpenGraphArticle, F as QlaraOpenGraphBase, G as QlaraOpenGraphBook, H as QlaraOpenGraphMusicAlbum, I as QlaraOpenGraphMusicPlaylist, J as QlaraOpenGraphMusicRadioStation, K as QlaraOpenGraphMusicSong, L as QlaraOpenGraphProfile, N as QlaraOpenGraphVideoEpisode, O as QlaraOpenGraphVideoMovie, S as QlaraOpenGraphVideoOther, T as QlaraOpenGraphVideoTVShow, U as QlaraOpenGraphWebsite, V as QlaraPinterest, Q as QlaraProvider, W as QlaraReferrer, X as QlaraRobots, Y as QlaraRobotsInfo, Z as QlaraRouteDefinition, _ as QlaraRoutes, $ as QlaraTwitter, a0 as QlaraTwitterApp, a1 as QlaraTwitterAppDescriptor, a2 as QlaraTwitterBase, a3 as QlaraTwitterImage, a4 as QlaraTwitterImageDescriptor, a5 as QlaraTwitterPlayer, a6 as QlaraTwitterPlayerDescriptor, a7 as QlaraTwitterSummary, a8 as QlaraTwitterSummaryLargeImage, a9 as QlaraVerification } from './types--KPPgCtc.cjs';
3
3
 
4
4
  declare function validateConfig(config: QlaraPluginConfig, routes: QlaraRoute[]): void;
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as QlaraPluginConfig, b as QlaraRoute, c as QlaraManifest, M as ManifestRoute, R as RouteMatch } from './types-gl2xFqEX.js';
2
- export { P as ProviderResources, d as QlaraAlternateLinkDescriptor, e as QlaraAlternateURLs, f as QlaraAppLinks, g as QlaraAppLinksAndroid, h as QlaraAppLinksApple, i as QlaraAppLinksWeb, j as QlaraAppLinksWindows, k as QlaraAppleImage, l as QlaraAppleImageDescriptor, m as QlaraAppleWebApp, n as QlaraAuthor, o as QlaraDeployConfig, p as QlaraFacebook, q as QlaraFormatDetection, r as QlaraIcon, s as QlaraIconDescriptor, t as QlaraIcons, u as QlaraItunesApp, v as QlaraMetaDataGenerator, w as QlaraMetadata, x as QlaraOGAudio, y as QlaraOGAudioDescriptor, z as QlaraOGImage, A as QlaraOGImageDescriptor, B as QlaraOGVideo, C as QlaraOGVideoDescriptor, D as QlaraOpenGraph, E as QlaraOpenGraphArticle, F as QlaraOpenGraphBase, G as QlaraOpenGraphBook, H as QlaraOpenGraphMusicAlbum, I as QlaraOpenGraphMusicPlaylist, J as QlaraOpenGraphMusicRadioStation, K as QlaraOpenGraphMusicSong, L as QlaraOpenGraphProfile, N as QlaraOpenGraphVideoEpisode, O as QlaraOpenGraphVideoMovie, S as QlaraOpenGraphVideoOther, T as QlaraOpenGraphVideoTVShow, U as QlaraOpenGraphWebsite, V as QlaraPinterest, Q as QlaraProvider, W as QlaraReferrer, X as QlaraRobots, Y as QlaraRobotsInfo, Z as QlaraRouteDefinition, _ as QlaraRoutes, $ as QlaraTwitter, a0 as QlaraTwitterApp, a1 as QlaraTwitterAppDescriptor, a2 as QlaraTwitterBase, a3 as QlaraTwitterImage, a4 as QlaraTwitterImageDescriptor, a5 as QlaraTwitterPlayer, a6 as QlaraTwitterPlayerDescriptor, a7 as QlaraTwitterSummary, a8 as QlaraTwitterSummaryLargeImage, a9 as QlaraVerification } from './types-gl2xFqEX.js';
1
+ import { a as QlaraPluginConfig, b as QlaraRoute, c as QlaraManifest, M as ManifestRoute, R as RouteMatch } from './types--KPPgCtc.js';
2
+ export { P as ProviderResources, d as QlaraAlternateLinkDescriptor, e as QlaraAlternateURLs, f as QlaraAppLinks, g as QlaraAppLinksAndroid, h as QlaraAppLinksApple, i as QlaraAppLinksWeb, j as QlaraAppLinksWindows, k as QlaraAppleImage, l as QlaraAppleImageDescriptor, m as QlaraAppleWebApp, n as QlaraAuthor, o as QlaraDeployConfig, p as QlaraFacebook, q as QlaraFormatDetection, r as QlaraIcon, s as QlaraIconDescriptor, t as QlaraIcons, u as QlaraItunesApp, v as QlaraMetaDataGenerator, w as QlaraMetadata, x as QlaraOGAudio, y as QlaraOGAudioDescriptor, z as QlaraOGImage, A as QlaraOGImageDescriptor, B as QlaraOGVideo, C as QlaraOGVideoDescriptor, D as QlaraOpenGraph, E as QlaraOpenGraphArticle, F as QlaraOpenGraphBase, G as QlaraOpenGraphBook, H as QlaraOpenGraphMusicAlbum, I as QlaraOpenGraphMusicPlaylist, J as QlaraOpenGraphMusicRadioStation, K as QlaraOpenGraphMusicSong, L as QlaraOpenGraphProfile, N as QlaraOpenGraphVideoEpisode, O as QlaraOpenGraphVideoMovie, S as QlaraOpenGraphVideoOther, T as QlaraOpenGraphVideoTVShow, U as QlaraOpenGraphWebsite, V as QlaraPinterest, Q as QlaraProvider, W as QlaraReferrer, X as QlaraRobots, Y as QlaraRobotsInfo, Z as QlaraRouteDefinition, _ as QlaraRoutes, $ as QlaraTwitter, a0 as QlaraTwitterApp, a1 as QlaraTwitterAppDescriptor, a2 as QlaraTwitterBase, a3 as QlaraTwitterImage, a4 as QlaraTwitterImageDescriptor, a5 as QlaraTwitterPlayer, a6 as QlaraTwitterPlayerDescriptor, a7 as QlaraTwitterSummary, a8 as QlaraTwitterSummaryLargeImage, a9 as QlaraVerification } from './types--KPPgCtc.js';
3
3
 
4
4
  declare function validateConfig(config: QlaraPluginConfig, routes: QlaraRoute[]): void;
5
5
 
@@ -153,7 +153,8 @@ function withQlara(qlaraConfig) {
153
153
  },
154
154
  outputDir,
155
155
  routeFile: (0, import_node_path.resolve)(qlaraConfig.routeFile),
156
- env
156
+ env,
157
+ framework: "next"
157
158
  };
158
159
  (0, import_node_fs.mkdirSync)(QLARA_DIR, { recursive: true });
159
160
  (0, import_node_fs.writeFileSync)(
@@ -1,5 +1,5 @@
1
1
  import { NextConfig } from 'next';
2
- import { a as QlaraPluginConfig } from '../types-gl2xFqEX.cjs';
2
+ import { a as QlaraPluginConfig } from '../types--KPPgCtc.cjs';
3
3
 
4
4
  /**
5
5
  * Wrap a Next.js config with Qlara.
@@ -1,5 +1,5 @@
1
1
  import { NextConfig } from 'next';
2
- import { a as QlaraPluginConfig } from '../types-gl2xFqEX.js';
2
+ import { a as QlaraPluginConfig } from '../types--KPPgCtc.js';
3
3
 
4
4
  /**
5
5
  * Wrap a Next.js config with Qlara.
@@ -84,7 +84,8 @@ function withQlara(qlaraConfig) {
84
84
  },
85
85
  outputDir,
86
86
  routeFile: resolve(qlaraConfig.routeFile),
87
- env
87
+ env,
88
+ framework: "next"
88
89
  };
89
90
  mkdirSync(QLARA_DIR, { recursive: true });
90
91
  writeFileSync(
@@ -368,6 +368,12 @@ interface QlaraPluginConfig {
368
368
  provider: QlaraProvider;
369
369
  /** Env var names to forward to the renderer Lambda (values read from process.env at build time) */
370
370
  env?: string[];
371
+ /**
372
+ * The framework identifier. Set automatically by framework plugins (e.g. 'next' by withQlara).
373
+ * Used by the renderer to enable framework-specific post-render behavior
374
+ * (e.g. generating .txt RSC flight data files for Next.js client-side navigation).
375
+ */
376
+ framework?: string;
371
377
  }
372
378
  interface QlaraProvider {
373
379
  name: string;
@@ -394,6 +400,11 @@ interface QlaraDeployConfig {
394
400
  routeFile: string;
395
401
  /** Environment variables for the renderer Lambda (key-value pairs resolved at build time) */
396
402
  env?: Record<string, string>;
403
+ /**
404
+ * The framework identifier (e.g. 'next'). Set by framework plugins.
405
+ * Passed to the renderer to enable framework-specific post-render behavior.
406
+ */
407
+ framework?: string;
397
408
  }
398
409
  interface QlaraManifest {
399
410
  version: 1;
@@ -368,6 +368,12 @@ interface QlaraPluginConfig {
368
368
  provider: QlaraProvider;
369
369
  /** Env var names to forward to the renderer Lambda (values read from process.env at build time) */
370
370
  env?: string[];
371
+ /**
372
+ * The framework identifier. Set automatically by framework plugins (e.g. 'next' by withQlara).
373
+ * Used by the renderer to enable framework-specific post-render behavior
374
+ * (e.g. generating .txt RSC flight data files for Next.js client-side navigation).
375
+ */
376
+ framework?: string;
371
377
  }
372
378
  interface QlaraProvider {
373
379
  name: string;
@@ -394,6 +400,11 @@ interface QlaraDeployConfig {
394
400
  routeFile: string;
395
401
  /** Environment variables for the renderer Lambda (key-value pairs resolved at build time) */
396
402
  env?: Record<string, string>;
403
+ /**
404
+ * The framework identifier (e.g. 'next'). Set by framework plugins.
405
+ * Passed to the renderer to enable framework-specific post-render behavior.
406
+ */
407
+ framework?: string;
397
408
  }
398
409
  interface QlaraManifest {
399
410
  version: 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qlara",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Runtime ISR for static React apps — dynamic routing and SEO metadata for statically exported Next.js apps on AWS",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -54,6 +54,7 @@ import type {
54
54
  // At bundle time: '__qlara_routes__' → './qlara.routes.ts' (or wherever the dev put it)
55
55
  // Injected at bundle time by esbuild define
56
56
  declare const __QLARA_CACHE_TTL__: number;
57
+ declare const __QLARA_FRAMEWORK__: string;
57
58
 
58
59
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
59
60
  // @ts-ignore — resolved at bundle time by esbuild alias
@@ -759,6 +760,34 @@ function metadataToRscEntries(metadata: QlaraMetadata): string {
759
760
  return entries.join('');
760
761
  }
761
762
 
763
+ /**
764
+ * Extract RSC flight data from rendered HTML (Next.js-specific).
765
+ *
766
+ * Next.js embeds RSC data inside <script>self.__next_f.push([1,"..."])</script> blocks.
767
+ * The .txt file is these payloads concatenated with JSON string escapes resolved.
768
+ * Next.js's client-side router fetches the .txt file for client-side navigation
769
+ * instead of the full .html — so we must generate it for renderer-created pages.
770
+ *
771
+ * Only called when __QLARA_FRAMEWORK__ === 'next'.
772
+ */
773
+ function extractRscFlightData(html: string): string | null {
774
+ const chunks: string[] = [];
775
+ const regex = /self\.__next_f\.push\(\[1,"((?:[^"\\]|\\.)*)"\]\)/g;
776
+ let match;
777
+
778
+ while ((match = regex.exec(html)) !== null) {
779
+ // Unescape the JSON string: \" → ", \\ → \, \n → newline
780
+ const unescaped = match[1]
781
+ .replace(/\\n/g, '\n')
782
+ .replace(/\\"/g, '"')
783
+ .replace(/\\\\/g, '\\');
784
+ chunks.push(unescaped);
785
+ }
786
+
787
+ if (chunks.length === 0) return null;
788
+ return chunks.join('');
789
+ }
790
+
762
791
  export async function handler(event: RendererEvent & { warmup?: boolean }): Promise<RendererResult> {
763
792
  // Warmup invocation — just initialize the runtime and return
764
793
  if (event.warmup) {
@@ -825,7 +854,7 @@ export async function handler(event: RendererEvent & { warmup?: boolean }): Prom
825
854
  }
826
855
  }
827
856
 
828
- // 5. Upload to S3
857
+ // 5. Upload HTML to S3
829
858
  await s3.send(
830
859
  new PutObjectCommand({
831
860
  Bucket: bucket,
@@ -836,6 +865,26 @@ export async function handler(event: RendererEvent & { warmup?: boolean }): Prom
836
865
  })
837
866
  );
838
867
 
868
+ // 6. Framework-specific post-render uploads
869
+ // Next.js: extract RSC flight data and upload as .txt for client-side navigation.
870
+ // Next.js fetches .txt instead of .html when using <Link> / client-side nav.
871
+ // Without this, client-side nav falls back to a full page reload (slow).
872
+ if (__QLARA_FRAMEWORK__ === 'next') {
873
+ const rscData = extractRscFlightData(html);
874
+ if (rscData) {
875
+ const txtKey = s3Key.replace(/\.html$/, '.txt');
876
+ await s3.send(
877
+ new PutObjectCommand({
878
+ Bucket: bucket,
879
+ Key: txtKey,
880
+ Body: rscData,
881
+ ContentType: 'text/plain; charset=utf-8',
882
+ CacheControl: `public, max-age=0, s-maxage=${__QLARA_CACHE_TTL__}, stale-while-revalidate=60`,
883
+ })
884
+ );
885
+ }
886
+ }
887
+
839
888
  return {
840
889
  statusCode: 200,
841
890
  body: JSON.stringify({
package/src/types.ts CHANGED
@@ -513,6 +513,12 @@ export interface QlaraPluginConfig {
513
513
  provider: QlaraProvider;
514
514
  /** Env var names to forward to the renderer Lambda (values read from process.env at build time) */
515
515
  env?: string[];
516
+ /**
517
+ * The framework identifier. Set automatically by framework plugins (e.g. 'next' by withQlara).
518
+ * Used by the renderer to enable framework-specific post-render behavior
519
+ * (e.g. generating .txt RSC flight data files for Next.js client-side navigation).
520
+ */
521
+ framework?: string;
516
522
  }
517
523
 
518
524
  export interface QlaraProvider {
@@ -542,6 +548,11 @@ export interface QlaraDeployConfig {
542
548
  routeFile: string;
543
549
  /** Environment variables for the renderer Lambda (key-value pairs resolved at build time) */
544
550
  env?: Record<string, string>;
551
+ /**
552
+ * The framework identifier (e.g. 'next'). Set by framework plugins.
553
+ * Passed to the renderer to enable framework-specific post-render behavior.
554
+ */
555
+ framework?: string;
545
556
  }
546
557
 
547
558
  export interface QlaraManifest {