@storyblok/astro 6.0.0-next.2 → 6.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/README.md +73 -65
- package/dist/lib/helpers.d.ts +1 -1
- package/dist/live-preview/middleware.ts +1 -1
- package/dist/storyblok-astro.es.js +10 -12
- package/dist/storyblok-astro.umd.js +10 -12
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ npm install @storyblok/astro
|
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
> [!NOTE]
|
|
49
|
-
> With pnpm, hoist Storyblok dependencies publicly with `.npmrc`. For more information,
|
|
49
|
+
> With pnpm, hoist Storyblok dependencies publicly with `.npmrc`. For more information, please refer to the [pnpm documentation](https://pnpm.io/npmrc).
|
|
50
50
|
|
|
51
51
|
Add the following code to `astro.config.mjs` and replace the `accessToken` with the preview API token of your Storyblok space.
|
|
52
52
|
|
|
@@ -110,15 +110,15 @@ storyblok({
|
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
> [!WARNING]
|
|
113
|
-
>
|
|
113
|
+
> The `region` parameter **must** be specified unless the space was created in the EU.
|
|
114
114
|
|
|
115
115
|
## Getting started
|
|
116
116
|
|
|
117
117
|
### 1. Creating and linking your components to the Storyblok Visual Editor
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
Link your Astro components to their equivalents created in Storyblok with the following steps.
|
|
120
120
|
|
|
121
|
-
First,
|
|
121
|
+
First, load the components globally by specifying their name and their path in `astro.config.mjs`:
|
|
122
122
|
|
|
123
123
|
```js
|
|
124
124
|
components: {
|
|
@@ -164,7 +164,7 @@ const { blok } = Astro.props
|
|
|
164
164
|
</div>
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
-
Finally, you can use the provided `<StoryblokComponent>` for nested components; it will automatically render them (if they
|
|
167
|
+
Finally, you can use the provided `<StoryblokComponent>` for nested components; it will automatically render them (if they are registered globally):
|
|
168
168
|
|
|
169
169
|
```jsx
|
|
170
170
|
---
|
|
@@ -219,7 +219,7 @@ const story = data.story;
|
|
|
219
219
|
```
|
|
220
220
|
|
|
221
221
|
> [!NOTE]
|
|
222
|
-
> The available methods are described in the [storyblok-js-client]
|
|
222
|
+
> The available methods are described in the [storyblok-js-client](https://github.com/storyblok/storyblok-js-client#method-storyblokget) repository.
|
|
223
223
|
|
|
224
224
|
#### Dynamic Routing
|
|
225
225
|
|
|
@@ -281,13 +281,77 @@ bridge: {
|
|
|
281
281
|
- `resolveLinks` may be needed to resolve link fields.
|
|
282
282
|
|
|
283
283
|
> [!NOTE]
|
|
284
|
-
> `resolveRelations` and `resolveLinks` will
|
|
284
|
+
> `resolveRelations` and `resolveLinks` will only become effective if the live preview feature is used (`getLiveStory()`).
|
|
285
285
|
|
|
286
286
|
The provided options will be used when initializing the Storyblok Bridge. You can find more information about the Storyblok Bridge and its configuration options on the [In Depth Storyblok Bridge guide](https://www.storyblok.com/docs/guide/in-depth/storyblok-latest-js-v2?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-astro).
|
|
287
287
|
|
|
288
288
|
If you want to deploy a dedicated preview environment with the Bridge enabled, allowing users of the Storyblok CMS to see their changes being reflected on the frontend directly without having to rebuild the static site, you can enable Server Side Rendering for that particular use case. More information can be found in the [Astro Docs](https://docs.astro.build/en/guides/server-side-rendering/).
|
|
289
289
|
|
|
290
|
-
|
|
290
|
+
## Enabling Live Preview for Storyblok's Visual Editor
|
|
291
|
+
|
|
292
|
+
The Astro SDK provides a live preview feature, designed to offer real-time editing capabilities for an enhanced user experience in Storyblok's Visual Editor.
|
|
293
|
+
|
|
294
|
+
> [!NOTE]
|
|
295
|
+
> To utilize the Astro Storyblok Live feature, Astro must be configured to run in SSR mode.
|
|
296
|
+
|
|
297
|
+
To activate the live preview feature, follow these steps:
|
|
298
|
+
|
|
299
|
+
1. Set `livePreview` to `true` in your `astro.config.mjs` file.
|
|
300
|
+
|
|
301
|
+
```js
|
|
302
|
+
//astro.config.mjs
|
|
303
|
+
export default defineConfig({
|
|
304
|
+
integrations: [
|
|
305
|
+
storyblok({
|
|
306
|
+
accessToken: "OsvN..",
|
|
307
|
+
livePreview: true,
|
|
308
|
+
}),
|
|
309
|
+
],
|
|
310
|
+
output: "server", // Astro must be configured to run in SSR mode
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
2. Additionally, use `getLiveStory` on your Astro pages.
|
|
315
|
+
|
|
316
|
+
```jsx
|
|
317
|
+
//pages/[...slug].astro
|
|
318
|
+
---
|
|
319
|
+
import { getLiveStory, useStoryblokApi } from '@storyblok/astro';
|
|
320
|
+
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";
|
|
321
|
+
|
|
322
|
+
const { slug } = Astro.params;
|
|
323
|
+
let story = null;
|
|
324
|
+
|
|
325
|
+
const liveStory = await getLiveStory(Astro);
|
|
326
|
+
if (liveStory) {
|
|
327
|
+
story = liveStory;
|
|
328
|
+
} else {
|
|
329
|
+
const sbApi = useStoryblokApi();
|
|
330
|
+
const { data } = await sbApi.get(`cdn/stories/${slug || 'home'}`, {
|
|
331
|
+
version: 'draft',
|
|
332
|
+
resolve_relations: ['featured-articles.posts'],
|
|
333
|
+
});
|
|
334
|
+
story = data?.story;
|
|
335
|
+
}
|
|
336
|
+
// If you are using `resolve_relations` or `resolve_links`, you must also pass them to the Bridge configuration in `astro.config.mjs`.
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
<StoryblokComponent blok={story.content} />
|
|
340
|
+
```
|
|
341
|
+
## Dom update event
|
|
342
|
+
|
|
343
|
+
```js
|
|
344
|
+
//page.astro
|
|
345
|
+
|
|
346
|
+
<script>
|
|
347
|
+
document.addEventListener('storyblok-live-preview-updated', () => {
|
|
348
|
+
// Here is the callback we could run code every time the body is updated via live preview
|
|
349
|
+
console.log('Live preview: body updated');
|
|
350
|
+
// Example regenerated all your css
|
|
351
|
+
});
|
|
352
|
+
</script>
|
|
353
|
+
```
|
|
354
|
+
## Rendering Rich Text
|
|
291
355
|
|
|
292
356
|
> [!NOTE]
|
|
293
357
|
> While @storyblok/astro provides basic richtext rendering capabilities, for advanced use cases, it is highly recommended to use [storyblok-rich-text-astro-renderer](https://github.com/NordSecurity/storyblok-rich-text-astro-renderer).
|
|
@@ -346,62 +410,6 @@ const renderedRichText = renderRichText(blok.text, {
|
|
|
346
410
|
|
|
347
411
|
Returns the instance of the `storyblok-js-client`.
|
|
348
412
|
|
|
349
|
-
## Enabling Live Preview for Storyblok's Visual Editor
|
|
350
|
-
|
|
351
|
-
The Astro SDK now provides a live preview feature, designed to offer real-time editing capabilities for an enhanced user experience in Storyblok's Visual Editor.
|
|
352
|
-
|
|
353
|
-
> [!NOTE]
|
|
354
|
-
> To utilize the Astro Storyblok Live feature, Astro must be configured to run in SSR mode.
|
|
355
|
-
|
|
356
|
-
To activate the experimental live preview feature, follow these steps:
|
|
357
|
-
|
|
358
|
-
1. Set `livePreview` to `true` within your `astro.config.mjs` file.
|
|
359
|
-
|
|
360
|
-
```js
|
|
361
|
-
//astro.config.mjs
|
|
362
|
-
export default defineConfig({
|
|
363
|
-
integrations: [
|
|
364
|
-
storyblok({
|
|
365
|
-
accessToken: "OsvN..",
|
|
366
|
-
livePreview: true,
|
|
367
|
-
}),
|
|
368
|
-
],
|
|
369
|
-
output: "server", // Astro must be configured to run in SSR mode
|
|
370
|
-
});
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
2. Additionally, please use `getLiveStory` on your Astro pages for live story fetching.
|
|
374
|
-
|
|
375
|
-
```jsx
|
|
376
|
-
//pages/[...slug].astro
|
|
377
|
-
---
|
|
378
|
-
import {
|
|
379
|
-
getLiveStory,
|
|
380
|
-
useStoryblokApi,
|
|
381
|
-
type ISbStoryData,
|
|
382
|
-
} from '@storyblok/astro';
|
|
383
|
-
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";
|
|
384
|
-
|
|
385
|
-
const { slug } = Astro.params;
|
|
386
|
-
let story: ISbStoryData | null = null;
|
|
387
|
-
|
|
388
|
-
const liveStory = await getLiveStory(Astro);
|
|
389
|
-
if (liveStory) {
|
|
390
|
-
story = liveStory;
|
|
391
|
-
} else {
|
|
392
|
-
const sbApi = useStoryblokApi();
|
|
393
|
-
const { data } = await sbApi.get(`cdn/stories/${slug || 'home'}`, {
|
|
394
|
-
version: 'draft',
|
|
395
|
-
resolve_relations: ['featured-articles.posts'],
|
|
396
|
-
});
|
|
397
|
-
story = data?.story;
|
|
398
|
-
}
|
|
399
|
-
// If you are using `resolve_relations` or `resolve_links`, you must also pass them to the Bridge configuration in `astro.config.mjs`.
|
|
400
|
-
---
|
|
401
|
-
|
|
402
|
-
<StoryblokComponent blok={story.content} />
|
|
403
|
-
```
|
|
404
|
-
|
|
405
413
|
## The Storyblok JavaScript SDK Ecosystem
|
|
406
414
|
|
|
407
415
|

|
|
@@ -436,4 +444,4 @@ Please review our [Contributing Guidelines](https://github.com/storyblok/.github
|
|
|
436
444
|
|
|
437
445
|
This project employs [semantic-release](https://semantic-release.gitbook.io/semantic-release/) to generate new versions based on commit messages, following the Angular Commit Message Convention.
|
|
438
446
|
|
|
439
|
-
When using playgrounds during development, ensure the build is running in watch mode for an efficient workflow.
|
|
447
|
+
When using playgrounds during development, ensure the build is running in watch mode for an efficient workflow.
|
package/dist/lib/helpers.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ISbRichtext, ISbStoryData, SbRichTextOptions, StoryblokBridgeConfigV2, StoryblokClient } from '../types';
|
|
2
2
|
import { AstroGlobal } from 'astro';
|
|
3
3
|
export declare function useStoryblokApi(): StoryblokClient;
|
|
4
|
-
export declare function getLiveStory(Astro: AstroGlobal): Promise<ISbStoryData<import('@storyblok/js').StoryblokComponentType<string> & {
|
|
4
|
+
export declare function getLiveStory(Astro: Readonly<AstroGlobal>): Promise<ISbStoryData<import('@storyblok/js').StoryblokComponentType<string> & {
|
|
5
5
|
[index: string]: any;
|
|
6
6
|
}> | null>;
|
|
7
7
|
export declare function renderRichText(data?: ISbRichtext, options?: SbRichTextOptions): string;
|
|
@@ -6,7 +6,7 @@ export const onRequest = defineMiddleware(async ({ locals, request }, next) => {
|
|
|
6
6
|
// First do a basic check if its coming from within storyblok
|
|
7
7
|
const isStoryblokRequest
|
|
8
8
|
= url.searchParams.has('_storyblok')
|
|
9
|
-
|
|
9
|
+
&& url.searchParams.has('_storyblok_c');
|
|
10
10
|
|
|
11
11
|
if (isStoryblokRequest) {
|
|
12
12
|
try {
|
|
@@ -609,22 +609,20 @@ function je(r) {
|
|
|
609
609
|
`
|
|
610
610
|
), e.bridge && !e.livePreview && o(
|
|
611
611
|
"page",
|
|
612
|
-
`
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
}
|
|
621
|
-
});
|
|
612
|
+
`import { loadStoryblokBridge } from "@storyblok/astro";
|
|
613
|
+
loadStoryblokBridge().then(() => {
|
|
614
|
+
const { StoryblokBridge, location } = window;
|
|
615
|
+
${t}
|
|
616
|
+
storyblokInstance.on(["published", "change"], (event) => {
|
|
617
|
+
if (!event.slugChanged) {
|
|
618
|
+
location.reload(true);
|
|
619
|
+
}
|
|
622
620
|
});
|
|
621
|
+
});
|
|
623
622
|
`
|
|
624
623
|
), e.livePreview && (o(
|
|
625
624
|
"page",
|
|
626
|
-
`
|
|
627
|
-
import { loadStoryblokBridge, handleStoryblokMessage } from "@storyblok/astro";
|
|
625
|
+
`import { loadStoryblokBridge, handleStoryblokMessage } from "@storyblok/astro";
|
|
628
626
|
loadStoryblokBridge().then(() => {
|
|
629
627
|
const { StoryblokBridge, location } = window;
|
|
630
628
|
${t}
|
|
@@ -43,19 +43,17 @@ Detailed information can be found here: https://github.com/storyblok/storyblok-a
|
|
|
43
43
|
}`),""}optimizeImages(e,t){let o=0,s=0,n="",a="";typeof t!="boolean"&&(typeof t.width=="number"&&t.width>0&&(n+=`width="${t.width}" `,o=t.width),typeof t.height=="number"&&t.height>0&&(n+=`height="${t.height}" `,s=t.height),(t.loading==="lazy"||t.loading==="eager")&&(n+=`loading="${t.loading}" `),typeof t.class=="string"&&t.class.length>0&&(n+=`class="${t.class}" `),t.filters&&(typeof t.filters.blur=="number"&&t.filters.blur>=0&&t.filters.blur<=100&&(a+=`:blur(${t.filters.blur})`),typeof t.filters.brightness=="number"&&t.filters.brightness>=-100&&t.filters.brightness<=100&&(a+=`:brightness(${t.filters.brightness})`),t.filters.fill&&(t.filters.fill.match(/[0-9A-F]{6}/gi)||t.filters.fill==="transparent")&&(a+=`:fill(${t.filters.fill})`),t.filters.format&&["webp","png","jpeg"].includes(t.filters.format)&&(a+=`:format(${t.filters.format})`),typeof t.filters.grayscale=="boolean"&&t.filters.grayscale&&(a+=":grayscale()"),typeof t.filters.quality=="number"&&t.filters.quality>=0&&t.filters.quality<=100&&(a+=`:quality(${t.filters.quality})`),t.filters.rotate&&[90,180,270].includes(t.filters.rotate)&&(a+=`:rotate(${t.filters.rotate})`),a.length>0&&(a=`/filters${a}`))),n.length>0&&(e=e.replace(/<img/g,`<img ${n.trim()}`));const l=o>0||s>0||a.length>0?`${o}x${s}${a}`:"";return e=e.replace(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g,`a.storyblok.com/f/$1/$2.$3/m/${l}`),typeof t!="boolean"&&(t.sizes||t.srcset)&&(e=e.replace(/<img.*?src=["|'](.*?)["|']/g,i=>{var c,d;const f=i.match(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g);if(f&&f.length>0){const h={srcset:(c=t.srcset)==null?void 0:c.map(g=>{if(typeof g=="number")return`//${f}/m/${g}x0${a} ${g}w`;if(typeof g=="object"&&g.length===2){let w=0,R=0;return typeof g[0]=="number"&&(w=g[0]),typeof g[1]=="number"&&(R=g[1]),`//${f}/m/${w}x${R}${a} ${w}w`}return""}).join(", "),sizes:(d=t.sizes)==null?void 0:d.map(g=>g).join(", ")};let k="";return h.srcset&&(k+=`srcset="${h.srcset}" `),h.sizes&&(k+=`sizes="${h.sizes}" `),i.replace(/<img/g,`<img ${k.trim()}`)}return i})),e}renderNode(e){const t=[];e.marks&&e.marks.forEach(s=>{const n=this.getMatchingMark(s);n&&n.tag!==""&&t.push(this.renderOpeningTag(n.tag))});const o=this.getMatchingNode(e);return o&&o.tag&&t.push(this.renderOpeningTag(o.tag)),e.content?e.content.forEach(s=>{t.push(this.renderNode(s))}):e.text?t.push(me(e.text)):o&&o.singleTag?t.push(this.renderTag(o.singleTag," /")):o&&o.html?t.push(o.html):e.type==="emoji"&&t.push(this.renderEmoji(e)),o&&o.tag&&t.push(this.renderClosingTag(o.tag)),e.marks&&e.marks.slice(0).reverse().forEach(s=>{const n=this.getMatchingMark(s);n&&n.tag!==""&&t.push(this.renderClosingTag(n.tag))}),t.join("")}renderTag(e,t){return e.constructor===String?`<${e}${t}>`:e.map(o=>{if(o.constructor===String)return`<${o}${t}>`;{let s=`<${o.tag}`;if(o.attrs){for(const n in o.attrs)if(Object.prototype.hasOwnProperty.call(o.attrs,n)){const a=o.attrs[n];a!==null&&(s+=` ${n}="${a}"`)}}return`${s}${t}>`}}).join("")}renderOpeningTag(e){return this.renderTag(e,"")}renderClosingTag(e){return e.constructor===String?`</${e}>`:e.slice(0).reverse().map(t=>t.constructor===String?`</${t}>`:`</${t.tag}>`).join("")}getMatchingNode(e){const t=this.nodes[e.type];if(typeof t=="function")return t(e)}getMatchingMark(e){const t=this.marks[e.type];if(typeof t=="function")return t(e)}renderEmoji(e){if(e.attrs.emoji)return e.attrs.emoji;const t=[{tag:"img",attrs:{src:e.attrs.fallbackImage,draggable:"false",loading:"lazy",align:"absmiddle"}}];return this.renderTag(t," /")}}const L=ke,we=r=>{if(typeof r!="object"||typeof r._editable>"u")return{};try{const e=JSON.parse(r._editable.replace(/^<!--#storyblok#/,"").replace(/-->$/,""));return e?{"data-blok-c":JSON.stringify(e),"data-blok-uid":e.id+"-"+e.uid}:{}}catch{return{}}};let $e,ve="https://app.storyblok.com/f/storyblok-v2-latest.js";const Ce=(r,e)=>{r.addNode("blok",t=>{let o="";return t.attrs.body.forEach(s=>{o+=e(s.component,s)}),{html:o}})},Se=r=>!r||!(r!=null&&r.content.some(e=>e.content||e.type==="blok"||e.type==="horizontal_rule")),Ie=(r,e,t)=>{let o=t||$e;if(!o){console.error("Please initialize the Storyblok SDK before calling the renderRichText function");return}return Se(r)?"":(e&&(o=new L(e.schema),e.resolver&&Ce(o,e.resolver)),o.render(r,{},!1))},Te=()=>U(ve);function Ae(){if(!(globalThis!=null&&globalThis.storyblokApiInstance))throw new Error("storyblokApiInstance has not been initialized correctly");return globalThis.storyblokApiInstance}async function Ee(r){let e=null;return r&&r.locals._storyblok_preview_data&&(e=r.locals._storyblok_preview_data),e}function Le(r,e){var o;const t=(o=globalThis==null?void 0:globalThis.storyblokApiInstance)==null?void 0:o.richTextResolver;if(!t)throw new Error("Please initialize the Storyblok SDK before calling the renderRichText function");return Ie(r,e,t)}function xe(r){return typeof r=="object"?`const storyblokInstance = new StoryblokBridge(${JSON.stringify(r)});`:"const storyblokInstance = new StoryblokBridge();"}function Re(r){const e={useCustomApi:!1,bridge:!0,componentsDir:"src",enableFallbackComponent:!1,livePreview:!1,...r},t=xe(e.bridge);return{name:"@storyblok/astro",hooks:{"astro:config:setup":({injectScript:o,updateConfig:s,addDevToolbarApp:n,addMiddleware:a,config:l})=>{if(s({vite:{plugins:[F(e.accessToken,e.useCustomApi,e.apiOptions),B(e.componentsDir,e.components,e.enableFallbackComponent,e.customFallbackComponent),D(e)]}}),e.livePreview&&(l==null?void 0:l.output)!=="server")throw new Error("To utilize the Astro Storyblok Live feature, Astro must be configured to run in SSR mode. Please disable this feature or switch Astro to SSR mode.");o("page-ssr",`
|
|
44
44
|
import { storyblokApiInstance } from "virtual:storyblok-init";
|
|
45
45
|
globalThis.storyblokApiInstance = storyblokApiInstance;
|
|
46
|
-
`),e.bridge&&!e.livePreview&&o("page",`
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
});
|
|
46
|
+
`),e.bridge&&!e.livePreview&&o("page",`import { loadStoryblokBridge } from "@storyblok/astro";
|
|
47
|
+
loadStoryblokBridge().then(() => {
|
|
48
|
+
const { StoryblokBridge, location } = window;
|
|
49
|
+
${t}
|
|
50
|
+
storyblokInstance.on(["published", "change"], (event) => {
|
|
51
|
+
if (!event.slugChanged) {
|
|
52
|
+
location.reload(true);
|
|
53
|
+
}
|
|
56
54
|
});
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
});
|
|
56
|
+
`),e.livePreview&&(o("page",`import { loadStoryblokBridge, handleStoryblokMessage } from "@storyblok/astro";
|
|
59
57
|
loadStoryblokBridge().then(() => {
|
|
60
58
|
const { StoryblokBridge, location } = window;
|
|
61
59
|
${t}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storyblok/astro",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "6.0.0
|
|
4
|
+
"version": "6.0.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"packageManager": "pnpm@9.13.2",
|
|
7
7
|
"description": "Official Astro integration for the Storyblok Headless CMS",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"astro": "^3.0.0 || ^4.0.0 || ^5.0.0"
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@storyblok/js": "
|
|
74
|
+
"@storyblok/js": "3.1.9",
|
|
75
75
|
"camelcase": "^8.0.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
"@cypress/vite-dev-server": "^5.2.0",
|
|
81
81
|
"@rollup/plugin-dynamic-import-vars": "^2.1.5",
|
|
82
82
|
"@storyblok/eslint-config": "^0.3.0",
|
|
83
|
+
"@types/lodash.mergewith": "^4.6.9",
|
|
83
84
|
"@types/node": "22.10.2",
|
|
84
85
|
"astro": "^5.0.9",
|
|
85
86
|
"cypress": "^13.15.2",
|