@storyblok/astro 7.4.0-alpha.0 → 8.0.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/dist/types.d.ts CHANGED
@@ -8,4 +8,4 @@ ISbStoriesParams, // previously StoriesParams
8
8
  ISbStory, // previously Story
9
9
  ISbStoryData, // previously StoryData
10
10
  ISbStoryParams, // previously StoryParams
11
- MarkTypes, SbBlokData, SbBlokKeyDataTypes, SbPluginFactory, SbSDKOptions, StoryblokBridgeConfigV2, StoryblokBridgeV2, StoryblokClient, StoryblokComponentType, StoryblokRichTextDocumentNode, StoryblokRichTextImageOptimizationOptions, StoryblokRichTextNode, StoryblokRichTextNodeResolver, StoryblokRichTextNodeTypes, StoryblokRichTextOptions, StoryblokRichTextResolvers, TextTypes, } from '@storyblok/js';
11
+ MarkTypes, SbBlokData, SbBlokKeyDataTypes, SbPluginFactory, SbSDKOptions, StoryblokBridgeConfigV2, StoryblokBridgeV2, StoryblokClient, StoryblokComponentType, StoryblokRichTextDocumentNode, StoryblokRichTextImageOptimizationOptions, StoryblokRichTextNode, StoryblokRichTextNodeTypes, StoryblokRichTextOptions, TextTypes, } from '@storyblok/js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@storyblok/astro",
3
3
  "type": "module",
4
- "version": "7.4.0-alpha.0",
4
+ "version": "8.0.0",
5
5
  "private": false,
6
6
  "description": "Official Astro integration for the Storyblok Headless CMS",
7
7
  "author": "Storyblok",
@@ -39,8 +39,7 @@
39
39
  },
40
40
  "./client": "./dist/lib/client.ts",
41
41
  "./FallbackComponent.astro": "./dist/components/FallbackComponent.astro",
42
- "./StoryblokComponent.astro": "./dist/components/StoryblokComponent.astro",
43
- "./StoryblokServerData.astro": "./dist/components/StoryblokServerData.astro"
42
+ "./StoryblokComponent.astro": "./dist/components/StoryblokComponent.astro"
44
43
  },
45
44
  "main": "./dist/storyblok-astro.es.js",
46
45
  "module": "./dist/storyblok-astro.js",
@@ -54,8 +53,7 @@
54
53
  },
55
54
  "dependencies": {
56
55
  "camelcase": "^8.0.0",
57
- "morphdom": "^2.7.8",
58
- "@storyblok/js": "4.4.4"
56
+ "@storyblok/js": "5.0.0"
59
57
  },
60
58
  "devDependencies": {
61
59
  "@cypress/vite-dev-server": "^6.0.3",
@@ -76,7 +74,7 @@
76
74
  "vite-plugin-dts": "^4.5.3",
77
75
  "vite-plugin-static-copy": "^2.2.0",
78
76
  "vitest": "^3.1.3",
79
- "@storyblok/eslint-config": "0.4.1"
77
+ "@storyblok/eslint-config": "0.4.2"
80
78
  },
81
79
  "eslintConfig": {
82
80
  "env": {
@@ -1,29 +0,0 @@
1
- ---
2
- /**
3
- * StoryblokServerData Component
4
- *
5
- * Pass server-side data to the client that persists across live preview updates.
6
- * All props passed to this component will be serialized as JSON and available
7
- * to the client via the extraData parameter in getLiveStory().
8
- *
9
- * Data is automatically sanitized to prevent XSS attacks and script injection.
10
- *
11
- * @example
12
- * ```astro
13
- * ---
14
- * import { StoryblokServerData } from '@storyblok/astro';
15
- * const users = await getUsers();
16
- * const config = { apiUrl: 'https://api.example.com' };
17
- * ---
18
- *
19
- * <StoryblokServerData users={users} config={config} />
20
- * ```
21
- */
22
-
23
- import { sanitizeJSON } from '@storyblok/astro';
24
-
25
- const props = Astro.props;
26
- const safeJson = sanitizeJSON(props);
27
- ---
28
-
29
- <script is:inline id="__STORYBLOK_SERVERDATA__" type="application/json" set:html={safeJson} />
@@ -1,103 +0,0 @@
1
- import {
2
- richTextResolver,
3
- type StoryblokRichTextNode,
4
- type StoryblokRichTextResolvers,
5
- } from '@storyblok/js';
6
- import { experimental_AstroContainer } from 'astro/container';
7
- import StoryblokComponent from '@storyblok/astro/StoryblokComponent.astro';
8
-
9
- // Lazily initialized Astro container (for rendering blok components)
10
- let container: null | experimental_AstroContainer = null;
11
-
12
- /**
13
- * @experimental Converts a Storyblok RichText field into an HTML string.
14
- *
15
- * This API is still under development and may change in future releases.
16
- * It also relies on Astro’s experimental
17
- * [experimental_AstroContainer](https://docs.astro.build/en/reference/container-reference/) feature.
18
- *
19
- * @async
20
- * @param {StoryblokRichTextNode} richTextField - The root RichText node to convert.
21
- * @param {StoryblokRichTextResolvers} [customResolvers] - Optional custom resolvers
22
- * for customizing how specific nodes or marks are transformed into HTML.
23
- * @returns {Promise<string>} A promise that resolves to the HTML string representation
24
- * of the provided RichText content.
25
- *
26
- * @example
27
- * ```astro
28
- * ---
29
- * import { richTextToHTML } from '@storyblok/astro/client';
30
- * const { blok } = Astro.props;
31
- * const renderedRichText = await richTextToHTML(blok.text);
32
- * ---
33
- *
34
- * <div set:html={renderedRichText} />
35
- * ```
36
- */
37
- export const richTextToHTML = async (
38
- richTextField: StoryblokRichTextNode,
39
- customResolvers?: StoryblokRichTextResolvers,
40
- ): Promise<string> => {
41
- // Create Astro container only once
42
- if (!container) {
43
- container = await experimental_AstroContainer.create();
44
- }
45
-
46
- // Collect async render results keyed by placeholder ID
47
- const asyncReplacements: Promise<{ id: string; result: string }>[] = [];
48
- // Build the resolvers object
49
- const resolvers: StoryblokRichTextResolvers = {
50
- // Handle async components
51
- blok: (node) => {
52
- const componentBody = node.attrs?.body;
53
- if (!Array.isArray(componentBody)) {
54
- return '';
55
- }
56
-
57
- return componentBody
58
- .map((blok) => {
59
- if (!blok || typeof blok !== 'object' || !container) {
60
- return '';
61
- }
62
-
63
- // Generate unique placeholder ID
64
- const id = crypto.randomUUID();
65
- const placeholder = `<!--ASYNC-${id}-->`;
66
-
67
- // Queue async render
68
- const promise = container
69
- .renderToString(StoryblokComponent, {
70
- props: { blok },
71
- })
72
- .then(result => ({ id, result }))
73
- .catch((err) => {
74
- console.error('Component rendering failed:', err);
75
- return { id, result: '<!-- Component render error -->' };
76
- });
77
-
78
- asyncReplacements.push(promise);
79
- return placeholder;
80
- })
81
- .join('\n');
82
- },
83
-
84
- // Add custom resolvers if provided
85
- ...customResolvers,
86
- };
87
-
88
- const resolver = richTextResolver({ resolvers });
89
-
90
- let html = resolver.render(richTextField);
91
- // Wait for all async renders
92
- const results = await Promise.all(asyncReplacements);
93
- const replacements = new Map(
94
- results.map(({ id, result }) => [id, result ?? '']),
95
- );
96
-
97
- // Single-pass replacement using regex
98
- html = html.replace(/<!--ASYNC-([\w-]+)-->/g, (_, id: string) => {
99
- return replacements.get(id) ?? '';
100
- });
101
-
102
- return html;
103
- };
@@ -1,30 +0,0 @@
1
- /**
2
- * Safely serializes data to JSON and escapes characters that could break out of a script tag
3
- * or execute malicious code when embedded in HTML.
4
- *
5
- * This prevents XSS attacks by escaping:
6
- * - `</script>` tags that could close the script tag early
7
- * - `<!--` and `-->` HTML comment sequences
8
- * - Line separator (U+2028) and paragraph separator (U+2029) which are valid JSON but can break JS
9
- * - Other potentially dangerous Unicode characters
10
- *
11
- * @param data - The data to serialize
12
- * @returns A safe JSON string that can be embedded in HTML
13
- *
14
- * @example
15
- * ```ts
16
- * const safeJSON = sanitizeJSON({
17
- * message: '</script><script>alert("XSS")</script>'
18
- * });
19
- * // Returns escaped version that won't execute
20
- * ```
21
- */
22
- export declare function sanitizeJSON(data: unknown): string;
23
- /**
24
- * Parses JSON that was sanitized with sanitizeJSON()
25
- * This is just JSON.parse but provided for symmetry and clarity
26
- *
27
- * @param json - The sanitized JSON string
28
- * @returns The parsed data
29
- */
30
- export declare function parseSanitizedJSON<T = unknown>(json: string): T;
@@ -1,41 +0,0 @@
1
- /**
2
- * Options for validating Storyblok Visual Editor requests.
3
- */
4
- interface StoryblokValidationOptions {
5
- /**
6
- * Optional space ID to validate against the request.
7
- * If provided, the request must match this space ID to be considered valid.
8
- */
9
- spaceId?: string;
10
- }
11
- /**
12
- * Validates whether a given URL is a legitimate request from the Storyblok Visual Editor.
13
- *
14
- * This function performs a multi-layered validation to ensure the request originates from
15
- * the Storyblok Visual Editor by checking for required query parameters and optionally
16
- * validating the space ID.
17
- *
18
- * @param url - The URL object to validate.
19
- * @param options - Optional validation configuration.
20
- * @param options.spaceId - If provided, validates that the request's space ID matches this value.
21
- *
22
- * @returns `true` if the URL contains all required Storyblok Visual Editor parameters
23
- * and passes optional space ID validation; `false` otherwise.
24
- *
25
- * @example
26
- * ```typescript
27
- * const url = new URL('https://example.com/?_storyblok=123&_storyblok_c=456&_storyblok_tk[space_id]=789');
28
- *
29
- * // Basic validation
30
- * if (isEditorRequest(url)) {
31
- * console.log('Valid Storyblok editor request');
32
- * }
33
- *
34
- * // Validation with space ID check
35
- * if (isEditorRequest(url, { spaceId: '789' })) {
36
- * console.log('Valid request for specific space');
37
- * }
38
- * ```
39
- */
40
- export declare function isEditorRequest(url: URL, options?: StoryblokValidationOptions): boolean;
41
- export {};