@contentful/experiences-svelte 0.3.7 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,3 +1,45 @@
1
+ ## 0.4.0 (2026-08-05)
2
+
3
+ ### 🚀 Features
4
+
5
+ - ⚠️ replace isPreview with top-level debug mode [AIS-243] ([#98](https://github.com/contentful/experiences/pull/98))
6
+
7
+ ### ⚠️ Breaking Changes
8
+
9
+ - replace isPreview with top-level debug mode [AIS-243] ([#98](https://github.com/contentful/experiences/pull/98))
10
+ `isPreview` is removed from the render context and the nested
11
+ `context` option is gone. Pass `metadata` and `debug` as top-level options on
12
+ `fetchExperience`/`resolveExperience` and as props on the renderers.
13
+ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
14
+ * refactor: derive metadata once in sveltekit apps
15
+ Extract a single `metadata` object in the loaders and thread it through
16
+ both fetchExperience and the renderer, instead of duplicating the
17
+ `{ slug }` literal in +page.svelte. Addresses PR review feedback.
18
+ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
19
+ * refactor: mount DebugExperience above the tree and aggregate resolveData timing
20
+ Move the auto-mounted <DebugExperience> panel above the rendered tree in
21
+ both React and Svelte renderers (client + server) so the debug dump is
22
+ visible without scrolling past the experience. Update the doc comments
23
+ and README to match.
24
+ Replace per-node resolveData timing lines with a single aggregate span
25
+ over the whole fan-out — keeps the timing signal without emitting a log
26
+ line per node, which gets noisy on large trees.
27
+ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
28
+
29
+ ### 🧱 Updated Dependencies
30
+
31
+ - Updated client to 0.2.0
32
+ - Updated design to 0.6.0
33
+ - Updated core to 0.6.0
34
+
35
+ ## 0.3.8 (2026-08-04)
36
+
37
+ ### 🧱 Updated Dependencies
38
+
39
+ - Updated client to 0.1.8
40
+ - Updated design to 0.5.6
41
+ - Updated core to 0.5.6
42
+
1
43
  ## 0.3.7 (2026-08-03)
2
44
 
3
45
  ### 🧱 Updated Dependencies
package/README.md CHANGED
@@ -44,7 +44,7 @@ useActiveViewport; // Rune-backed reactive object; you'll rarely need it directl
44
44
  ```ts
45
45
  getDesignValues<T>(); // Resolved design values for the current node; read in a $derived to stay reactive
46
46
  toCss(design, options?); // Turns a design record into a plain style object, keeping only real CSS keys
47
- getExperience(); // RenderContext: isPreview, metadata, viewports, activeViewport
47
+ getExperience(); // RenderContext: debug, metadata, viewports, activeViewport
48
48
  getContentfulComponent(); // Raw payload for the enclosing node (or undefined)
49
49
  getContentfulTemplate(); // Same, for the page-level template
50
50
  type ToCssOptions;
@@ -11,6 +11,7 @@
11
11
  <script lang="ts">
12
12
  import type { ExperienceContext, ViewportDef } from '@contentful/experiences-sdk-core';
13
13
 
14
+ import DebugExperience from './DebugExperience.svelte';
14
15
  import MissingComponent from './MissingComponent.svelte';
15
16
  import NodesRenderer from './NodesRenderer.svelte';
16
17
  import WrapWithTemplate from './WrapWithTemplate.svelte';
@@ -20,7 +21,7 @@
20
21
  import { useActiveViewport } from './use-active-viewport.svelte.js';
21
22
 
22
23
  const DEFAULT_CONTEXT: ExperienceContext = {
23
- isPreview: false,
24
+ debug: false,
24
25
  metadata: {},
25
26
  viewports: [],
26
27
  };
@@ -36,7 +37,8 @@
36
37
  experience,
37
38
  config,
38
39
  initialViewportId,
39
- context,
40
+ metadata,
41
+ debug = false,
40
42
  renderUnknown = MissingComponent,
41
43
  }: ClientExperienceRendererProps = $props();
42
44
 
@@ -47,8 +49,8 @@
47
49
  // reactive across viewport changes. The fields update in an $effect below.
48
50
  const liveContext = $state<RenderContext>({
49
51
  ...DEFAULT_CONTEXT,
50
- ...context,
51
- metadata: { ...DEFAULT_CONTEXT.metadata, ...(context?.metadata ?? {}) },
52
+ debug,
53
+ metadata: { ...DEFAULT_CONTEXT.metadata, ...(metadata ?? {}) },
52
54
  viewports: experience?.viewports ?? [],
53
55
  activeViewport: experience?.viewports[0] ?? FALLBACK_VIEWPORT,
54
56
  activeViewportIndex: 0,
@@ -62,12 +64,15 @@
62
64
  liveContext.viewports = experience.viewports;
63
65
  liveContext.activeViewport = experience.viewports[idx] ?? FALLBACK_VIEWPORT;
64
66
  liveContext.activeViewportIndex = idx;
65
- liveContext.isPreview = context?.isPreview ?? false;
66
- liveContext.metadata = { ...DEFAULT_CONTEXT.metadata, ...(context?.metadata ?? {}) };
67
+ liveContext.debug = debug;
68
+ liveContext.metadata = { ...DEFAULT_CONTEXT.metadata, ...(metadata ?? {}) };
67
69
  });
68
70
  </script>
69
71
 
70
72
  {#if experience}
73
+ {#if debug}
74
+ <DebugExperience {experience} />
75
+ {/if}
71
76
  <WrapWithTemplate template={experience.template} {config} experience={liveContext}>
72
77
  {#snippet children()}
73
78
  <NodesRenderer
@@ -1 +1 @@
1
- {"version":3,"file":"ClientExperienceRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/ClientExperienceRenderer.svelte.ts"],"names":[],"mappings":"AAmFA,QAAA,MAAM,wBAAwB,kGAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
1
+ {"version":3,"file":"ClientExperienceRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/ClientExperienceRenderer.svelte.ts"],"names":[],"mappings":"AAyFA,QAAA,MAAM,wBAAwB,kGAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
@@ -0,0 +1,65 @@
1
+ <!--
2
+ * First-party debug panel. Renders the resolved Experience plan as pretty
3
+ * JSON so a customer can see exactly what the SDK interpreted from the payload
4
+ * — node tree, registrations, resolved props, viewports.
5
+ *
6
+ * Two ways to use it:
7
+ * - Auto-mounted by the renderers when `debug` is on (above the tree).
8
+ * - Mounted manually anywhere: `<DebugExperience experience={plan} />`.
9
+ *
10
+ * v1 is just the JSON dump wrapped in a native <details> so it collapses
11
+ * without any extra JS. Room to grow into a node-tree explorer, viewport
12
+ * indicator, and resolveData timing panel — kept deliberately small for now.
13
+ -->
14
+ <script lang="ts">
15
+ import type { DebugExperienceProps } from './component-props.js';
16
+
17
+ let { experience, defaultOpen = false }: DebugExperienceProps = $props();
18
+
19
+ const nodeCount = $derived(experience.nodes.length);
20
+ const summary = $derived(
21
+ `Experience debug — ${nodeCount} top-level node${nodeCount === 1 ? '' : 's'}${
22
+ experience.template ? `, template: ${experience.template.templateId}` : ''
23
+ }`
24
+ );
25
+
26
+ // JSON.stringify with a circular-reference guard: a customer's resolveData
27
+ // could stash a non-serializable value on props.resolved — degrade to a
28
+ // placeholder rather than throwing inside a debug panel.
29
+ function safeStringify(value: unknown): string {
30
+ const seen = new WeakSet<object>();
31
+ try {
32
+ return JSON.stringify(
33
+ value,
34
+ (_key, val) => {
35
+ if (typeof val === 'object' && val !== null) {
36
+ if (seen.has(val)) return '[Circular]';
37
+ seen.add(val);
38
+ }
39
+ if (typeof val === 'function') return `[Function ${val.name || 'anonymous'}]`;
40
+ if (typeof val === 'undefined') return '[undefined]';
41
+ return val;
42
+ },
43
+ 2
44
+ );
45
+ } catch (err) {
46
+ return `[DebugExperience: could not serialize plan — ${(err as Error).message}]`;
47
+ }
48
+ }
49
+
50
+ const json = $derived(safeStringify(experience));
51
+ </script>
52
+
53
+ <details
54
+ open={defaultOpen}
55
+ data-experiences-debug
56
+ style="margin: 1rem 0; border: 1px solid #6b7280; border-radius: 6px; background: #0b1021; color: #e2e8f0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.75rem; overflow: hidden;"
57
+ >
58
+ <summary
59
+ style="cursor: pointer; padding: 0.5rem 0.75rem; background: #111827; user-select: none;"
60
+ >
61
+ {summary}
62
+ </summary>
63
+ <pre
64
+ style="margin: 0; padding: 0.75rem; overflow: auto; max-height: 32rem; white-space: pre-wrap; word-break: break-word;">{json}</pre>
65
+ </details>
@@ -0,0 +1,5 @@
1
+ import type { DebugExperienceProps } from './component-props.js';
2
+ declare const DebugExperience: import("svelte").Component<DebugExperienceProps, {}, "">;
3
+ type DebugExperience = ReturnType<typeof DebugExperience>;
4
+ export default DebugExperience;
5
+ //# sourceMappingURL=DebugExperience.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DebugExperience.svelte.d.ts","sourceRoot":"","sources":["../src/DebugExperience.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAmDjE,QAAA,MAAM,eAAe,0DAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=DebugExperience.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DebugExperience.test.d.ts","sourceRoot":"","sources":["../src/DebugExperience.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ import { render } from '@testing-library/svelte';
2
+ import { describe, expect, it } from 'vitest';
3
+ import DebugExperience from './DebugExperience.svelte';
4
+ const emptyPlan = { nodes: [], viewports: [] };
5
+ function node(componentTypeId, content = {}) {
6
+ return {
7
+ registration: { componentTypeId },
8
+ props: { content, design: {} },
9
+ slots: {},
10
+ };
11
+ }
12
+ describe('DebugExperience.svelte', () => {
13
+ it('renders a collapsible details panel with the debug marker, collapsed by default', () => {
14
+ const { container } = render(DebugExperience, { props: { experience: emptyPlan } });
15
+ const details = container.querySelector('details[data-experiences-debug]');
16
+ expect(details).not.toBeNull();
17
+ expect(details.open).toBe(false);
18
+ });
19
+ it('expands on first paint when defaultOpen is set', () => {
20
+ const { container } = render(DebugExperience, {
21
+ props: { experience: emptyPlan, defaultOpen: true },
22
+ });
23
+ expect(container.querySelector('details').open).toBe(true);
24
+ });
25
+ it('summarizes the node count, pluralizing correctly', () => {
26
+ const { container: zero } = render(DebugExperience, { props: { experience: emptyPlan } });
27
+ expect(zero.innerHTML).toContain('Experience debug — 0 top-level nodes');
28
+ const one = { viewports: [], nodes: [node('button')] };
29
+ const { container } = render(DebugExperience, { props: { experience: one } });
30
+ expect(container.innerHTML).toContain('Experience debug — 1 top-level node');
31
+ });
32
+ it('names the template in the summary when present', () => {
33
+ const plan = {
34
+ viewports: [],
35
+ nodes: [],
36
+ template: { templateId: 'page', props: { content: {}, design: {} } },
37
+ };
38
+ const { container } = render(DebugExperience, { props: { experience: plan } });
39
+ expect(container.innerHTML).toContain('template: page');
40
+ });
41
+ it('dumps the plan as pretty JSON', () => {
42
+ const plan = {
43
+ viewports: [],
44
+ nodes: [node('button', { label: 'Go' })],
45
+ };
46
+ const { container } = render(DebugExperience, { props: { experience: plan } });
47
+ expect(container.innerHTML).toContain('componentTypeId');
48
+ expect(container.innerHTML).toContain('button');
49
+ expect(container.innerHTML).toContain('Go');
50
+ });
51
+ it('degrades a circular reference to a placeholder instead of throwing', () => {
52
+ const n = node('button');
53
+ n.props.resolved = { self: n.props };
54
+ const plan = { viewports: [], nodes: [n] };
55
+ expect(() => render(DebugExperience, { props: { experience: plan } })).not.toThrow();
56
+ const { container } = render(DebugExperience, { props: { experience: plan } });
57
+ expect(container.innerHTML).toContain('[Circular]');
58
+ });
59
+ });
@@ -2,7 +2,8 @@
2
2
  * Default fallback rendered when an instance references a component type
3
3
  * not present in the Config.
4
4
  *
5
- * Behavior: a visible red error box in preview, silent null in production.
5
+ * Behavior: a visible debug box when `debug` is on, silent null otherwise.
6
+ * The console.warn fires either way so the miss is never fully silent.
6
7
  * Customers can override per-render via <ServerExperienceRenderer renderUnknown=... />.
7
8
  -->
8
9
  <script lang="ts">
@@ -22,14 +23,20 @@
22
23
  });
23
24
  </script>
24
25
 
25
- {#if experience.isPreview}
26
+ {#if experience.debug}
26
27
  <div
27
- style="border: 2px solid red; padding: 1rem; color: red; background: #fff;"
28
+ style="border: 2px solid red; padding: 1rem; color: red; background: #fff; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.8125rem;"
28
29
  data-experiences-missing={componentTypeId}
29
30
  >
30
31
  <strong>Missing component &lsquo;{componentTypeId}&rsquo;</strong>
31
- <p>
32
+ <p style="margin: 0.5rem 0;">
32
33
  This component is referenced by the Experience payload but is not registered in the Config.
34
+ Register it under this key in your <code>components</code> map:
33
35
  </p>
36
+ <pre style="margin: 0; white-space: pre-wrap;">{JSON.stringify(
37
+ { componentTypeId, nodeId: nodeId ?? null },
38
+ null,
39
+ 2
40
+ )}</pre>
34
41
  </div>
35
42
  {/if}
@@ -1 +1 @@
1
- {"version":3,"file":"MissingComponent.svelte.d.ts","sourceRoot":"","sources":["../src/MissingComponent.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAgClE,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"MissingComponent.svelte.d.ts","sourceRoot":"","sources":["../src/MissingComponent.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAsClE,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
@@ -11,6 +11,7 @@
11
11
  import type { ExperienceContext, ViewportDef } from '@contentful/experiences-sdk-core';
12
12
  import { getViewportIndex } from '@contentful/experiences-design';
13
13
 
14
+ import DebugExperience from './DebugExperience.svelte';
14
15
  import MissingComponent from './MissingComponent.svelte';
15
16
  import NodesRenderer from './NodesRenderer.svelte';
16
17
  import WrapWithTemplate from './WrapWithTemplate.svelte';
@@ -19,7 +20,7 @@
19
20
  import type { RenderContext } from './types.js';
20
21
 
21
22
  const DEFAULT_CONTEXT: ExperienceContext = {
22
- isPreview: false,
23
+ debug: false,
23
24
  metadata: {},
24
25
  viewports: [],
25
26
  };
@@ -35,7 +36,8 @@
35
36
  experience,
36
37
  config,
37
38
  initialViewportId,
38
- context,
39
+ metadata,
40
+ debug = false,
39
41
  renderUnknown = MissingComponent,
40
42
  }: ServerExperienceRendererProps = $props();
41
43
 
@@ -44,8 +46,8 @@
44
46
  const idx = experience ? getViewportIndex(experience.viewports, initialViewportId) : 0;
45
47
  return {
46
48
  ...DEFAULT_CONTEXT,
47
- ...context,
48
- metadata: { ...DEFAULT_CONTEXT.metadata, ...(context?.metadata ?? {}) },
49
+ debug,
50
+ metadata: { ...DEFAULT_CONTEXT.metadata, ...(metadata ?? {}) },
49
51
  viewports,
50
52
  activeViewport: experience?.viewports[idx] ?? FALLBACK_VIEWPORT,
51
53
  activeViewportIndex: idx,
@@ -57,6 +59,9 @@
57
59
  </script>
58
60
 
59
61
  {#if experience}
62
+ {#if debug}
63
+ <DebugExperience {experience} />
64
+ {/if}
60
65
  <WrapWithTemplate template={experience.template} {config} experience={renderContext}>
61
66
  {#snippet children()}
62
67
  <NodesRenderer
@@ -1 +1 @@
1
- {"version":3,"file":"ServerExperienceRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/ServerExperienceRenderer.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAgE1E,QAAA,MAAM,wBAAwB,mEAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
1
+ {"version":3,"file":"ServerExperienceRenderer.svelte.d.ts","sourceRoot":"","sources":["../src/ServerExperienceRenderer.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAqE1E,QAAA,MAAM,wBAAwB,mEAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
@@ -1,11 +1,21 @@
1
1
  import type { Component } from 'svelte';
2
- import type { ExperienceContext, PortableRenderPlan } from '@contentful/experiences-sdk-core';
2
+ import type { PortableRenderPlan } from '@contentful/experiences-sdk-core';
3
3
  import type { Config } from './types.js';
4
4
  export interface ServerExperienceRendererProps {
5
5
  experience: PortableRenderPlan | null | undefined;
6
6
  config: Config;
7
7
  initialViewportId?: string;
8
- context?: Partial<ExperienceContext>;
8
+ /**
9
+ * Arbitrary per-render metadata, readable by descendants via
10
+ * `getExperience()` and by resolvers via `ctx.experience.metadata`.
11
+ */
12
+ metadata?: Record<string, unknown>;
13
+ /**
14
+ * Observability switch. When on: renders the visible missing-component box,
15
+ * turns the default `renderUnknown` fallback into the debug component, and
16
+ * auto-mounts `<DebugExperience>` after the tree.
17
+ */
18
+ debug?: boolean;
9
19
  renderUnknown?: RenderUnknown;
10
20
  }
11
21
  export type ClientExperienceRendererProps = ServerExperienceRendererProps;
@@ -15,4 +25,10 @@ export interface MissingComponentProps {
15
25
  nodeId?: string;
16
26
  }
17
27
  export type RenderUnknown = Component<MissingComponentProps>;
28
+ export interface DebugExperienceProps {
29
+ /** The resolved plan to inspect (what a renderer receives as `experience`). */
30
+ experience: PortableRenderPlan;
31
+ /** Start expanded. Defaults to collapsed to stay out of the way. */
32
+ defaultOpen?: boolean;
33
+ }
18
34
  //# sourceMappingURL=component-props.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"component-props.d.ts","sourceRoot":"","sources":["../src/component-props.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAE9F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,MAAM,6BAA6B,GAAG,6BAA6B,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,qBAAqB,CAAC,CAAC"}
1
+ {"version":3,"file":"component-props.d.ts","sourceRoot":"","sources":["../src/component-props.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAE3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,MAAM,6BAA6B,GAAG,6BAA6B,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,qBAAqB,CAAC,CAAC;AAE7D,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,UAAU,EAAE,kBAAkB,CAAC;IAC/B,oEAAoE;IACpE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { default as ClientExperienceRenderer } from './ClientExperienceRenderer.
2
2
  export { default as ExperienceRenderer } from './ClientExperienceRenderer.svelte';
3
3
  export { default as ServerExperienceRenderer } from './ServerExperienceRenderer.svelte';
4
4
  export { default as MissingComponent } from './MissingComponent.svelte';
5
+ export { default as DebugExperience } from './DebugExperience.svelte';
5
6
  export { default as NodesRenderer } from './NodesRenderer.svelte';
6
7
  export { useActiveViewport } from './use-active-viewport.svelte.js';
7
8
  export type { UseActiveViewportResult } from './use-active-viewport.svelte.js';
@@ -9,7 +10,7 @@ export { getExperience, getContentfulComponent, getContentfulTemplate } from './
9
10
  export { getDesignValues } from './get-design-values.js';
10
11
  export { toCss } from './design-utils.js';
11
12
  export type { ToCssOptions } from './design-utils.js';
12
- export type { ClientExperienceRendererProps, ClientExperienceRendererProps as ExperienceRendererProps, MissingComponentProps, RenderUnknown, ServerExperienceRendererProps, } from './component-props.js';
13
+ export type { ClientExperienceRendererProps, ClientExperienceRendererProps as ExperienceRendererProps, DebugExperienceProps, MissingComponentProps, RenderUnknown, ServerExperienceRendererProps, } from './component-props.js';
13
14
  export { defineComponent, defineTemplate, normalizeComponentRegistration, normalizeTemplateRegistration, } from './types.js';
14
15
  export type { ComponentConfig, Components, Config, ContentfulComponent, ContentfulTemplate, Registration, RenderContext, ResolveToken, TemplateConfig, TemplateRegistration, Templates, } from './types.js';
15
16
  export { resolveExperience } from '@contentful/experiences-sdk-core';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAIxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,YAAY,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAG/E,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD,YAAY,EACV,6BAA6B,EAC7B,6BAA6B,IAAI,uBAAuB,EACxD,qBAAqB,EACrB,aAAa,EACb,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,cAAc,EACd,8BAA8B,EAC9B,6BAA6B,GAC9B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,eAAe,EACf,UAAU,EACV,MAAM,EACN,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,SAAS,GACV,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAGjG,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,WAAW,GACZ,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,uBAAuB,EACvB,QAAQ,EACR,eAAe,GAChB,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,GACf,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAItE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,YAAY,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAG/E,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD,YAAY,EACV,6BAA6B,EAC7B,6BAA6B,IAAI,uBAAuB,EACxD,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,EACb,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,cAAc,EACd,8BAA8B,EAC9B,6BAA6B,GAC9B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,eAAe,EACf,UAAU,EACV,MAAM,EACN,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,SAAS,GACV,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAGjG,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,WAAW,GACZ,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,uBAAuB,EACvB,QAAQ,EACR,eAAe,GAChB,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,GACf,MAAM,gCAAgC,CAAC"}
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export { default as ClientExperienceRenderer } from './ClientExperienceRenderer.
16
16
  export { default as ExperienceRenderer } from './ClientExperienceRenderer.svelte';
17
17
  export { default as ServerExperienceRenderer } from './ServerExperienceRenderer.svelte';
18
18
  export { default as MissingComponent } from './MissingComponent.svelte';
19
+ export { default as DebugExperience } from './DebugExperience.svelte';
19
20
  // Exposed so advanced customers can render non-`children` slots manually:
20
21
  // e.g. `<NodesRenderer nodes={contentful.slots.header as PortableRenderNode[]} ... />`.
21
22
  export { default as NodesRenderer } from './NodesRenderer.svelte';
@@ -146,7 +146,7 @@ describe('ServerExperienceRenderer', () => {
146
146
  expect(ctx.activeViewportIndex).toBe(2);
147
147
  expect(ctx.activeViewport).toBe(VIEWPORTS[2]);
148
148
  });
149
- it('renders missing-component fallback in preview mode', () => {
149
+ it('renders missing-component fallback in debug mode', () => {
150
150
  const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
151
151
  const justContainer = {
152
152
  components: { 'contentful-container': ContainerFixture },
@@ -171,20 +171,41 @@ describe('ServerExperienceRenderer', () => {
171
171
  },
172
172
  ],
173
173
  };
174
- const { container: previewContainer } = render(ServerExperienceRenderer, {
174
+ const { container: debugContainer } = render(ServerExperienceRenderer, {
175
175
  props: {
176
176
  experience: planWithMissing,
177
177
  config: justContainer,
178
- context: { isPreview: true },
178
+ debug: true,
179
179
  },
180
180
  });
181
- expect(previewContainer.innerHTML).toContain('data-experiences-missing="NotRegistered"');
181
+ expect(debugContainer.innerHTML).toContain('data-experiences-missing="NotRegistered"');
182
182
  const { container: prodContainer } = render(ServerExperienceRenderer, {
183
183
  props: { experience: planWithMissing, config: justContainer },
184
184
  });
185
185
  expect(prodContainer.innerHTML).not.toContain('data-experiences-missing');
186
186
  warn.mockRestore();
187
187
  });
188
+ it('auto-mounts DebugExperience only when debug is on', async () => {
189
+ const captureConfig = { components: { capture: CapturingComponent } };
190
+ const plan = await resolveExperience({ viewports: VIEWPORTS, nodes: [componentNode('capture', { id: 'c' })] }, captureConfig);
191
+ const { container: off } = render(ServerExperienceRenderer, {
192
+ props: { experience: plan, config: captureConfig },
193
+ });
194
+ expect(off.innerHTML).not.toContain('data-experiences-debug');
195
+ const { container: on } = render(ServerExperienceRenderer, {
196
+ props: { experience: plan, config: captureConfig, debug: true },
197
+ });
198
+ expect(on.innerHTML).toContain('data-experiences-debug');
199
+ expect(on.innerHTML).toContain('Experience debug');
200
+ });
201
+ it('threads top-level metadata into getExperience()', async () => {
202
+ const captureConfig = { components: { capture: CapturingComponent } };
203
+ const plan = await resolveExperience({ viewports: VIEWPORTS, nodes: [componentNode('capture', { id: 'c' })] }, captureConfig);
204
+ render(ServerExperienceRenderer, {
205
+ props: { experience: plan, config: captureConfig, metadata: { slug: 'home' } },
206
+ });
207
+ expect(captureSink[0].experience.metadata).toEqual({ slug: 'home' });
208
+ });
188
209
  it('merges defaults beneath content (content wins)', async () => {
189
210
  const itemConfig = {
190
211
  components: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experiences-svelte",
3
- "version": "0.3.7",
3
+ "version": "0.4.0",
4
4
  "description": "Svelte adapter for Contentful Experiences — Server and Client renderers over a PortableRenderPlan",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,9 +35,9 @@
35
35
  "check": "svelte-check --tsconfig ./tsconfig.json"
36
36
  },
37
37
  "dependencies": {
38
- "@contentful/experiences-client": "0.1.7",
39
- "@contentful/experiences-sdk-core": "0.5.5",
40
- "@contentful/experiences-design": "0.5.5"
38
+ "@contentful/experiences-client": "0.2.0",
39
+ "@contentful/experiences-sdk-core": "0.6.0",
40
+ "@contentful/experiences-design": "0.6.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "svelte": "^5.55.7"
@@ -49,7 +49,7 @@
49
49
  "@testing-library/svelte": "^5.4.2",
50
50
  "jsdom": "^29.1.1",
51
51
  "publint": "^0.3.22",
52
- "svelte": "^5.55.7",
52
+ "svelte": "^5.56.8",
53
53
  "svelte-check": "^4.7.2"
54
54
  }
55
55
  }