@splitlabio/nextjs-orchestrator 0.2.1

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/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ Splitlab.io License
2
+
3
+ Copyright (c) Splitlab.io. All rights reserved.
4
+
5
+ This software is proprietary and confidential to Splitlab.io.
6
+ Unauthorized copying, modification, distribution, or use of this software,
7
+ in whole or in part, is strictly prohibited without the prior written
8
+ consent of Splitlab.io.
package/README.md ADDED
@@ -0,0 +1,286 @@
1
+ # @splitlabio/nextjs-orchestrator
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@splitlabio/nextjs-orchestrator.svg)](https://www.npmjs.com/package/@splitlabio/nextjs-orchestrator)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@splitlabio/nextjs-orchestrator.svg)](https://www.npmjs.com/package/@splitlabio/nextjs-orchestrator)
5
+ [![License](https://img.shields.io/npm/l/@splitlabio/nextjs-orchestrator.svg)](LICENSE)
6
+
7
+ React SDK for integrating the Splitlab CDN engine into Next.js applications with anti-flicker support.
8
+
9
+ > **Renamed:** this package was previously published as `@mvtlab/nextjs-orchestrator`.
10
+ > It is now `@splitlabio/nextjs-orchestrator`; the old package is deprecated and points here.
11
+ > The public API is unchanged — component names (`MVTScripts`, `MVTOrchestrator`), the
12
+ > `orchestratorKey` prop, and the `data-mvt-*` engine attributes are kept as-is because the
13
+ > deployed CDN engine matches on them.
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @splitlabio/nextjs-orchestrator
21
+ # or
22
+ yarn add @splitlabio/nextjs-orchestrator
23
+ ```
24
+
25
+ **Requirements:** Next.js >= 13.0.0, React >= 18.0.0
26
+
27
+ ---
28
+
29
+ ## Quick Start
30
+
31
+ ### Recommended — App Router (SSR-safe, no flicker)
32
+
33
+ Use `MVTScripts` in your root `layout.tsx`. It is a **Server Component** — no `'use client'`
34
+ needed — so the anti-flicker style and engine script are injected into the server-rendered
35
+ HTML and execute before React hydration, preventing any content flash.
36
+
37
+ ```tsx
38
+ // app/layout.tsx
39
+ import { MVTScripts } from '@splitlabio/nextjs-orchestrator';
40
+
41
+ export default function RootLayout({ children }) {
42
+ return (
43
+ <html lang="en">
44
+ <body>
45
+ <MVTScripts orchestratorKey="YOUR_PROJECT_KEY" />
46
+ {children}
47
+ </body>
48
+ </html>
49
+ );
50
+ }
51
+ ```
52
+
53
+ That's it. No `'use client'` required.
54
+
55
+ ### Pages Router
56
+
57
+ ```tsx
58
+ // pages/_app.tsx
59
+ import { MVTOrchestrator } from '@splitlabio/nextjs-orchestrator';
60
+
61
+ export default function MyApp({ Component, pageProps }) {
62
+ return (
63
+ <MVTOrchestrator orchestratorKey="YOUR_PROJECT_KEY">
64
+ <Component {...pageProps} />
65
+ </MVTOrchestrator>
66
+ );
67
+ }
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Components
73
+
74
+ ### `MVTScripts` — Server Component ✅ Recommended
75
+
76
+ Place once at the top of `<body>` in your root `layout.tsx`.
77
+
78
+ Renders two script tags directly into the server HTML:
79
+
80
+ 1. An **inline anti-flicker script** that sets `body { opacity: 0 }` and exposes
81
+ `window.rmfk()` — runs synchronously before any page content is visible.
82
+ 2. The **Splitlab engine `<script async>`** that loads the CDN, applies variant changes,
83
+ then calls `window.rmfk()` to reveal the page.
84
+
85
+ ```tsx
86
+ import { MVTScripts } from '@splitlabio/nextjs-orchestrator';
87
+
88
+ <MVTScripts
89
+ orchestratorKey="YOUR_PROJECT_KEY"
90
+ antiFlickerEnabled={true} // default
91
+ antiFlickerTimeoutMs={3000} // default
92
+ />
93
+ ```
94
+
95
+ | Prop | Type | Default | Description |
96
+ | --- | --- | --- | --- |
97
+ | `orchestratorKey` | `string` | — | Splitlab project key |
98
+ | `antiFlickerEnabled` | `boolean` | `true` | Inject `body{opacity:0}` before hydration |
99
+ | `antiFlickerTimeoutMs` | `number` | `3000` | Fallback timeout to reveal page if engine stalls |
100
+ | `engineUrl` | `string` | `https://cdn.splitlab.io/cdn/engine.js` | Override engine script URL (e.g. point at `https://staging-svc.splitlab.io/scripts/engine.js` for staging) |
101
+
102
+ ### `MVTOrchestrator` — Client Component
103
+
104
+ A `'use client'` component that handles script injection client-side and enforces a single
105
+ project key per page. Use this for **Pages Router** apps or when you cannot modify `layout.tsx`.
106
+
107
+ > **Note:** When used without `MVTScripts` in layout, the anti-flicker fires after React
108
+ > hydration and will not prevent the initial SSR content flash. For full flicker prevention
109
+ > use `MVTScripts` in `layout.tsx`.
110
+ >
111
+ > When used **together with `MVTScripts`**, `MVTOrchestrator` automatically detects the
112
+ > server-injected script and skips re-injection — no duplicate scripts.
113
+
114
+ ```tsx
115
+ import { MVTOrchestrator } from '@splitlabio/nextjs-orchestrator';
116
+
117
+ <MVTOrchestrator
118
+ orchestratorKey="YOUR_PROJECT_KEY"
119
+ antiFlickerEnabled={true} // default
120
+ antiFlickerTimeoutMs={3000} // default
121
+ >
122
+ {children}
123
+ </MVTOrchestrator>
124
+ ```
125
+
126
+ | Prop | Type | Default | Description |
127
+ | --- | --- | --- | --- |
128
+ | `orchestratorKey` | `string` | — | Splitlab project key |
129
+ | `children` | `ReactNode` | — | App content to wrap |
130
+ | `antiFlickerEnabled` | `boolean` | `true` | Enable anti-flicker |
131
+ | `antiFlickerTimeoutMs` | `number` | `3000` | Fallback timeout |
132
+ | `engineUrl` | `string` | `https://cdn.splitlab.io/cdn/engine.js` | Override engine script URL (e.g. point at `https://staging-svc.splitlab.io/scripts/engine.js` for staging) |
133
+
134
+ ---
135
+
136
+ ## Usage Examples
137
+
138
+ ### With environment variable
139
+
140
+ ```tsx
141
+ // .env.local
142
+ NEXT_PUBLIC_SPLITLAB_PROJECT_KEY=your_key_here
143
+ ```
144
+
145
+ ```tsx
146
+ <MVTScripts orchestratorKey={process.env.NEXT_PUBLIC_SPLITLAB_PROJECT_KEY!} />
147
+ ```
148
+
149
+ ### Point at staging
150
+
151
+ ```tsx
152
+ <MVTScripts
153
+ orchestratorKey="abc123xyz"
154
+ engineUrl="https://staging-svc.splitlab.io/scripts/engine.js"
155
+ />
156
+ ```
157
+
158
+ ### Disable anti-flicker
159
+
160
+ ```tsx
161
+ <MVTScripts orchestratorKey="abc123xyz" antiFlickerEnabled={false} />
162
+ ```
163
+
164
+ ### Custom timeout
165
+
166
+ ```tsx
167
+ <MVTScripts orchestratorKey="abc123xyz" antiFlickerTimeoutMs={5000} />
168
+ ```
169
+
170
+ ### TypeScript
171
+
172
+ ```tsx
173
+ import type { MVTScriptsProps, MVTOrchestratorProps } from '@splitlabio/nextjs-orchestrator';
174
+ ```
175
+
176
+ ---
177
+
178
+ ## How It Works
179
+
180
+ ### `MVTScripts` (Server Component)
181
+
182
+ Server-renders two `<script>` tags into the HTML response:
183
+
184
+ ```html
185
+ <!-- Anti-flicker: runs synchronously before any content is shown -->
186
+ <script id="mvt-anti-flicker">
187
+ var timeout=3000;!(function(h,i,d,e){ ... body{opacity:0} ... window.rmfk ... })(...)
188
+ </script>
189
+
190
+ <!-- Engine: async, loads CDN, applies variants, calls window.rmfk() -->
191
+ <script
192
+ id="mvt-engine-script"
193
+ src="https://cdn.splitlab.io/cdn/engine.js"
194
+ data-project-key="YOUR_KEY"
195
+ data-mvt="engine"
196
+ data-mvt-engine="true"
197
+ data-flicker-class="abtest-hidden"
198
+ crossorigin="anonymous"
199
+ async
200
+ ></script>
201
+ ```
202
+
203
+ Sequence: **body hidden → engine loads → variants applied → body revealed**
204
+
205
+ ### `MVTOrchestrator` (Client Component)
206
+
207
+ Injects the same scripts via `useEffect` (after hydration). Detects if `MVTScripts` already
208
+ ran (`id="mvt-engine-script"` present) and skips re-injection.
209
+
210
+ Sequence when standalone: **SSR renders → hydration → useEffect → scripts injected**
211
+
212
+ ### Anti-Flicker Detail
213
+
214
+ - `<style id="abhide">body{opacity:0}</style>` is injected into `<head>`
215
+ - `window.rmfk()` is defined to remove that style element
216
+ - The engine calls `window.rmfk()` once variants are applied
217
+ - A safety timeout removes the style if the engine never responds
218
+
219
+ ---
220
+
221
+ ## Troubleshooting
222
+
223
+ **Engine not loading?**
224
+
225
+ - Verify `orchestratorKey` is the correct project key from your Splitlab dashboard
226
+ - Check the Network tab for the `engine.js` request — it should return **200 from `cdn.splitlab.io`**.
227
+ A failed request to `staging-svc.mvtlab.io` means you are on an old release (< 0.2.1); upgrade or set `engineUrl`.
228
+ - Ensure the project's domain matches the `websiteUrl` configured in Splitlab
229
+
230
+ **Anti-flicker not working (page flashes)?**
231
+
232
+ - Switch from `MVTOrchestrator` to `MVTScripts` in `layout.tsx` — the client-side approach cannot prevent the initial SSR flash
233
+ - Confirm `antiFlickerEnabled={true}` (default)
234
+
235
+ **Duplicate scripts in DOM?**
236
+
237
+ - Use `MVTScripts` or `MVTOrchestrator` once at root, not both independently
238
+ - If using both together, `MVTOrchestrator` auto-detects `MVTScripts` and skips injection
239
+
240
+ **Pages Router / no layout.tsx?**
241
+
242
+ - Use `MVTOrchestrator` in `pages/_app.tsx`
243
+
244
+ ---
245
+
246
+ ## FAQ
247
+
248
+ **Do I need `'use client'` with `MVTScripts`?**
249
+ No. `MVTScripts` is a Server Component. Add it directly to your `layout.tsx` without any directive.
250
+
251
+ **Can I use `MVTScripts` and `MVTOrchestrator` together?**
252
+ Yes. Put `MVTScripts` in `layout.tsx` for correct timing and use `MVTOrchestrator` elsewhere for
253
+ client-side key enforcement. The orchestrator detects the server-injected script and won't duplicate it.
254
+
255
+ **Can I use multiple project keys?**
256
+ No. Use one `orchestratorKey` for the entire site. Different keys on the same page will log an error.
257
+
258
+ **What if the engine fails to load?**
259
+ The timeout (default 3000ms) removes the anti-flicker style so the page becomes visible.
260
+ Experiment variants won't be applied.
261
+
262
+ **TypeScript support?**
263
+ Full type definitions included. Both `MVTScriptsProps` and `MVTOrchestratorProps` are exported.
264
+
265
+ **Browser support?**
266
+ Modern browsers with ES2019+, React 18+, and standard DOM APIs.
267
+
268
+ ---
269
+
270
+ ## License
271
+
272
+ Licensed under Splitlab.io. Copyright © Splitlab.io. All rights reserved.
273
+
274
+ See [LICENSE](LICENSE) for details.
275
+
276
+ ---
277
+
278
+ ## Support
279
+
280
+ - **Splitlab:** Contact your representative or check your Splitlab dashboard.
281
+
282
+ ---
283
+
284
+ *`MVTScripts` renders the standard Splitlab HTML snippet server-side so it runs before
285
+ hydration. `MVTOrchestrator` translates the same snippet into React hooks for client-side
286
+ or Pages Router use.*
@@ -0,0 +1,34 @@
1
+ import React, { ReactNode } from 'react';
2
+ export type MVTOrchestratorProps = {
3
+ /**
4
+ * Project key used by the MVT engine.
5
+ * This will be passed as data-project-key to the engine script.
6
+ */
7
+ orchestratorKey: string;
8
+ /**
9
+ * Enable or disable the anti-flicker style injection.
10
+ * When enabled and MVTScripts is NOT present in layout.tsx, a temporary
11
+ * style is applied client-side to hide the body until the engine removes it.
12
+ * Note: when used standalone (without MVTScripts), anti-flicker fires after
13
+ * React hydration and will not prevent the initial SSR content flash.
14
+ * For full flicker prevention use MVTScripts in your root layout.tsx instead.
15
+ * Defaults to true.
16
+ */
17
+ antiFlickerEnabled?: boolean;
18
+ /**
19
+ * Timeout in milliseconds to automatically remove the anti-flicker style.
20
+ * Defaults to 3000ms.
21
+ */
22
+ antiFlickerTimeoutMs?: number;
23
+ /**
24
+ * Custom engine script URL.
25
+ * Defaults to the live production CDN endpoint. Point this at
26
+ * https://staging-svc.splitlab.io/scripts/engine.js for staging.
27
+ */
28
+ engineUrl?: string;
29
+ /**
30
+ * Children that will be rendered inside the orchestrator.
31
+ */
32
+ children: ReactNode;
33
+ };
34
+ export declare const MVTOrchestrator: React.FC<MVTOrchestratorProps>;
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import { useEffect } from 'react';
4
+ const DEFAULT_ENGINE_URL = 'https://cdn.splitlab.io/cdn/engine.js';
5
+ const ANTI_FLICKER_STYLE_ID = 'abhide';
6
+ export const MVTOrchestrator = ({ orchestratorKey, antiFlickerEnabled = true, antiFlickerTimeoutMs = 3000, engineUrl = DEFAULT_ENGINE_URL, children, }) => {
7
+ useEffect(() => {
8
+ if (typeof window === 'undefined' || typeof document === 'undefined') {
9
+ return;
10
+ }
11
+ // Cancel the pending safety timeout on unmount or before the effect re-runs
12
+ // (e.g. antiFlickerTimeoutMs changed), so a stale timer can't fire after
13
+ // unmount or let an earlier timeout win over a newly intended one.
14
+ let safetyTimeoutId;
15
+ const cleanup = () => {
16
+ if (safetyTimeoutId !== undefined) {
17
+ window.clearTimeout(safetyTimeoutId);
18
+ }
19
+ };
20
+ // Detect whether MVTScripts server component already injected the engine.
21
+ // If the <script id="mvt-engine-script"> is present, the server-side path
22
+ // ran (correct timing). We skip script injection but still ensure window.rmfk
23
+ // is available for the engine to call and set the timeout fallback.
24
+ const engineAlreadyInjected = !!document.getElementById('mvt-engine-script');
25
+ // Anti-flicker: only inject client-side when MVTScripts was NOT used.
26
+ // When MVTScripts is in layout.tsx the anti-flicker script is server-rendered
27
+ // and window.rmfk is already defined — we just need to set the timeout fallback.
28
+ if (antiFlickerEnabled) {
29
+ if (!engineAlreadyInjected) {
30
+ // Standalone mode: inject anti-flicker client-side (fires after hydration —
31
+ // does not prevent the initial SSR flash, but still protects against variant
32
+ // flicker on client-side navigations).
33
+ const existing = document.getElementById(ANTI_FLICKER_STYLE_ID);
34
+ if (!existing) {
35
+ const style = document.createElement('style');
36
+ style.id = ANTI_FLICKER_STYLE_ID;
37
+ style.innerHTML = 'body{opacity:0}';
38
+ document.head.appendChild(style);
39
+ }
40
+ }
41
+ // Expose window.rmfk so the engine can remove the anti-flicker style.
42
+ // MVTScripts also defines this via the inline script; redefining here is safe.
43
+ window.rmfk = function rmfk() {
44
+ const el = document.getElementById(ANTI_FLICKER_STYLE_ID);
45
+ if (el && el.parentNode) {
46
+ el.parentNode.removeChild(el);
47
+ }
48
+ };
49
+ // Safety timeout: remove anti-flicker if the engine never calls rmfk.
50
+ safetyTimeoutId = window.setTimeout(() => {
51
+ const rmfk = window.rmfk;
52
+ if (typeof rmfk === 'function') {
53
+ rmfk();
54
+ }
55
+ }, antiFlickerTimeoutMs);
56
+ }
57
+ const w = window;
58
+ if (w.__mvtOrchestratorKey && w.__mvtOrchestratorKey !== orchestratorKey) {
59
+ // eslint-disable-next-line no-console
60
+ console.error('[MVTOrchestrator] Multiple different project keys on the same page are not supported. ' +
61
+ `Existing key: "${w.__mvtOrchestratorKey}", new key: "${orchestratorKey}".`);
62
+ return cleanup;
63
+ }
64
+ w.__mvtOrchestratorKey = orchestratorKey;
65
+ // Inject the engine script only when MVTScripts did not already do so.
66
+ if (!engineAlreadyInjected) {
67
+ const script = document.createElement('script');
68
+ script.id = 'mvt-engine-script';
69
+ script.src = engineUrl;
70
+ script.async = true;
71
+ script.crossOrigin = 'anonymous';
72
+ script.setAttribute('data-project-key', orchestratorKey);
73
+ script.setAttribute('data-mvt', 'engine');
74
+ script.setAttribute('data-mvt-engine', 'true');
75
+ script.setAttribute('data-flicker-class', 'abtest-hidden');
76
+ document.head.appendChild(script);
77
+ }
78
+ return cleanup;
79
+ }, [orchestratorKey, antiFlickerEnabled, antiFlickerTimeoutMs, engineUrl]);
80
+ return _jsx(_Fragment, { children: children });
81
+ };
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ export type MVTScriptsProps = {
3
+ /**
4
+ * Project key used by the MVT engine.
5
+ */
6
+ orchestratorKey: string;
7
+ /**
8
+ * Enable or disable the anti-flicker style injection.
9
+ * Defaults to true.
10
+ */
11
+ antiFlickerEnabled?: boolean;
12
+ /**
13
+ * Timeout in milliseconds to automatically remove the anti-flicker style
14
+ * if the engine never calls window.rmfk(). Defaults to 3000ms.
15
+ */
16
+ antiFlickerTimeoutMs?: number;
17
+ /**
18
+ * Custom engine script URL.
19
+ * Defaults to the live production CDN endpoint. Point this at
20
+ * https://staging-svc.splitlab.io/scripts/engine.js for staging.
21
+ */
22
+ engineUrl?: string;
23
+ };
24
+ /**
25
+ * Server Component — place at the top of your root layout.tsx <body>.
26
+ *
27
+ * Renders the anti-flicker inline script and the MVT engine <script> tag
28
+ * directly into the server-generated HTML so they execute before React
29
+ * hydration, eliminating the content flash that useEffect-based injection
30
+ * cannot prevent.
31
+ *
32
+ * Usage in app/layout.tsx:
33
+ *
34
+ * import { MVTScripts } from '@splitlabio/nextjs-orchestrator';
35
+ *
36
+ * export default function RootLayout({ children }) {
37
+ * return (
38
+ * <html>
39
+ * <body>
40
+ * <MVTScripts orchestratorKey="YOUR_PROJECT_KEY" />
41
+ * {children}
42
+ * </body>
43
+ * </html>
44
+ * );
45
+ * }
46
+ */
47
+ export declare const MVTScripts: React.FC<MVTScriptsProps>;
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const DEFAULT_ENGINE_URL = 'https://cdn.splitlab.io/cdn/engine.js';
3
+ /**
4
+ * Server Component — place at the top of your root layout.tsx <body>.
5
+ *
6
+ * Renders the anti-flicker inline script and the MVT engine <script> tag
7
+ * directly into the server-generated HTML so they execute before React
8
+ * hydration, eliminating the content flash that useEffect-based injection
9
+ * cannot prevent.
10
+ *
11
+ * Usage in app/layout.tsx:
12
+ *
13
+ * import { MVTScripts } from '@splitlabio/nextjs-orchestrator';
14
+ *
15
+ * export default function RootLayout({ children }) {
16
+ * return (
17
+ * <html>
18
+ * <body>
19
+ * <MVTScripts orchestratorKey="YOUR_PROJECT_KEY" />
20
+ * {children}
21
+ * </body>
22
+ * </html>
23
+ * );
24
+ * }
25
+ */
26
+ export const MVTScripts = ({ orchestratorKey, antiFlickerEnabled = true, antiFlickerTimeoutMs = 3000, engineUrl = DEFAULT_ENGINE_URL, }) => {
27
+ // Matches the exact anti-flicker snippet used in the plain HTML pages:
28
+ // hides body{opacity:0}, exposes window.rmfk() for the engine to call,
29
+ // and falls back to auto-removal after the timeout.
30
+ const antiFlickerHtml = `var timeout=${antiFlickerTimeoutMs};!(function(h,i,d,e){var t,n=h.createElement("style");(n.id=e),(n.innerHTML="body{opacity:0}"),h.head.appendChild(n),(t=d),(i.rmfk=function(){var t=h.getElementById(e);t&&t.parentNode.removeChild(t)}),setTimeout(i.rmfk,t)})(document,window,timeout,"abhide");`;
31
+ return (_jsxs(_Fragment, { children: [antiFlickerEnabled && (
32
+ // eslint-disable-next-line react/no-danger
33
+ _jsx("script", { id: "mvt-anti-flicker", dangerouslySetInnerHTML: { __html: antiFlickerHtml } })), _jsx("script", { id: "mvt-engine-script", src: engineUrl, "data-project-key": orchestratorKey, "data-mvt": "engine", "data-mvt-engine": "true", "data-flicker-class": "abtest-hidden", crossOrigin: "anonymous", async: true })] }));
34
+ };
@@ -0,0 +1,2 @@
1
+ export * from './MVTOrchestrator.js';
2
+ export * from './MVTScripts.js';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './MVTOrchestrator.js';
2
+ export * from './MVTScripts.js';
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@splitlabio/nextjs-orchestrator",
3
+ "version": "0.2.1",
4
+ "description": "Next.js SDK to integrate the Splitlab CDN engine with optional anti-flicker support.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.build.json"
22
+ },
23
+ "peerDependencies": {
24
+ "next": ">=13.0.0",
25
+ "react": ">=18.0.0",
26
+ "react-dom": ">=18.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/react": "^18.0.0",
30
+ "@types/react-dom": "^18.0.0",
31
+ "typescript": "^5.6.0"
32
+ },
33
+ "keywords": [
34
+ "nextjs",
35
+ "splitlab",
36
+ "ab-testing",
37
+ "multivariate-testing",
38
+ "cdn-engine"
39
+ ],
40
+ "author": "Splitlab",
41
+ "license": "Splitlab.io",
42
+ "packageManager": "yarn@4.12.0"
43
+ }