@fictjs/ssr 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -144,6 +144,7 @@ During server-side rendering, component state is serialized into JSON and inject
144
144
  ```html
145
145
  <script id="__FICT_SNAPSHOT__" type="application/json">
146
146
  {
147
+ "v": 1,
147
148
  "scopes": {
148
149
  "s1": {
149
150
  "id": "s1",
@@ -341,9 +342,23 @@ interface ResumableLoaderOptions {
341
342
  document?: Document
342
343
  snapshotScriptId?: string
343
344
  events?: string[] // Default: DelegatedEvents
345
+ onSnapshotIssue?: (issue: SnapshotIssue) => void
344
346
  prefetch?: PrefetchStrategy | false
345
347
  }
346
348
 
349
+ interface SnapshotIssue {
350
+ code:
351
+ | 'snapshot_parse_error'
352
+ | 'snapshot_invalid_shape'
353
+ | 'snapshot_unsupported_version'
354
+ | 'scope_snapshot_missing'
355
+ message: string
356
+ source: string
357
+ expectedVersion: number
358
+ actualVersion?: number
359
+ scopeId?: string
360
+ }
361
+
347
362
  interface PrefetchStrategy {
348
363
  visibility?: boolean // Default: true
349
364
  visibilityMargin?: string // Default: '200px'
@@ -619,6 +634,7 @@ let dataId = $state(id) // Store ID only, fetch on client
619
634
  - [SSR SEO Guide](../../docs/ssr-seo.md)
620
635
  - [SSR Performance Tuning](../../docs/ssr-performance.md)
621
636
  - [SSR Deployment Guide](../../docs/ssr-deployment.md)
637
+ - [SSR / Resume Stability Contract](../../docs/ssr-resume-stability-contract.md)
622
638
 
623
639
  ## Troubleshooting
624
640
 
package/dist/index.cjs CHANGED
@@ -593,7 +593,7 @@ function splitDocumentHtml(html) {
593
593
  return { head: html.slice(0, idx), tail: html.slice(idx) };
594
594
  }
595
595
  function buildIncrementalSnapshotChunk(state, options) {
596
- const json = JSON.stringify(state);
596
+ const json = serializeSnapshotForScript(state);
597
597
  if (options.snapshotTarget === "head") {
598
598
  const jsonLiteral = JSON.stringify(json);
599
599
  return `<script>(function(){var s=document.createElement('script');s.type='application/json';s.setAttribute('data-fict-snapshot','');s.textContent=${jsonLiteral};(document.head||document.documentElement).appendChild(s);}())</script>`;
@@ -615,7 +615,7 @@ function injectSnapshot(document, container, state, options) {
615
615
  const script = document.createElement("script");
616
616
  script.type = "application/json";
617
617
  script.id = options.snapshotScriptId ?? "__FICT_SNAPSHOT__";
618
- script.textContent = JSON.stringify(state);
618
+ script.textContent = serializeSnapshotForScript(state);
619
619
  if (options.fullDocument) {
620
620
  if (options.snapshotTarget === "head" && document.head) {
621
621
  document.head.appendChild(script);
@@ -637,6 +637,9 @@ function injectSnapshot(document, container, state, options) {
637
637
  }
638
638
  container.appendChild(script);
639
639
  }
640
+ function serializeSnapshotForScript(state) {
641
+ return JSON.stringify(state).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
642
+ }
640
643
  function serializeDoctype(document, override) {
641
644
  if (override === null) return "";
642
645
  if (override !== void 0) return override;
package/dist/index.js CHANGED
@@ -571,7 +571,7 @@ function splitDocumentHtml(html) {
571
571
  return { head: html.slice(0, idx), tail: html.slice(idx) };
572
572
  }
573
573
  function buildIncrementalSnapshotChunk(state, options) {
574
- const json = JSON.stringify(state);
574
+ const json = serializeSnapshotForScript(state);
575
575
  if (options.snapshotTarget === "head") {
576
576
  const jsonLiteral = JSON.stringify(json);
577
577
  return `<script>(function(){var s=document.createElement('script');s.type='application/json';s.setAttribute('data-fict-snapshot','');s.textContent=${jsonLiteral};(document.head||document.documentElement).appendChild(s);}())</script>`;
@@ -593,7 +593,7 @@ function injectSnapshot(document, container, state, options) {
593
593
  const script = document.createElement("script");
594
594
  script.type = "application/json";
595
595
  script.id = options.snapshotScriptId ?? "__FICT_SNAPSHOT__";
596
- script.textContent = JSON.stringify(state);
596
+ script.textContent = serializeSnapshotForScript(state);
597
597
  if (options.fullDocument) {
598
598
  if (options.snapshotTarget === "head" && document.head) {
599
599
  document.head.appendChild(script);
@@ -615,6 +615,9 @@ function injectSnapshot(document, container, state, options) {
615
615
  }
616
616
  container.appendChild(script);
617
617
  }
618
+ function serializeSnapshotForScript(state) {
619
+ return JSON.stringify(state).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
620
+ }
618
621
  function serializeDoctype(document, override) {
619
622
  if (override === null) return "";
620
623
  if (override !== void 0) return override;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fictjs/ssr",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Fict server-side rendering",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -27,7 +27,7 @@
27
27
  ],
28
28
  "dependencies": {
29
29
  "linkedom": "^0.18.12",
30
- "@fictjs/runtime": "0.7.0"
30
+ "@fictjs/runtime": "0.9.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "tsup": "^8.5.1"