@demokit-ai/next 0.2.0 → 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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/provider.tsx","../src/client/hooks.ts","../src/client/banner.tsx"],"names":["useState","useEffect","useMemo","jsx","DemoKitProvider","useDemoMode","useRouter","useSearchParams","useCallback","DemoModeBanner"],"mappings":"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","file":"client.cjs","sourcesContent":["'use client'\n\nimport { useEffect, useState, useMemo } from 'react'\nimport { DemoKitProvider, type DemoKitProviderProps } from '@demokit-ai/react'\nimport type { DemoKitNextProviderProps } from '../types'\n\n/**\n * Get initial demo mode state from cookie\n */\nfunction getDemoModeFromCookie(cookieName: string): boolean {\n if (typeof document === 'undefined') return false\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n return demoCookie !== undefined\n}\n\n/**\n * Get scenario from cookie\n */\nfunction getScenarioFromCookie(cookieName: string): string | null {\n if (typeof document === 'undefined') return null\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n if (!demoCookie) return null\n\n const value = demoCookie.split('=')[1]?.trim()\n if (!value || value === 'true') return null\n\n return value\n}\n\n/**\n * Next.js-aware DemoKit provider\n *\n * This provider:\n * - Reads initial state from cookies (set by middleware)\n * - Supports scenario switching\n * - Works with both App Router and Pages Router\n *\n * @example\n * // app/providers.tsx\n * 'use client'\n *\n * import { DemoKitNextProvider } from '@demokit-ai/next/client'\n * import { fixtures, scenarios } from '@/lib/demo-fixtures'\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return (\n * <DemoKitNextProvider\n * fixtures={fixtures}\n * scenarios={scenarios}\n * >\n * {children}\n * </DemoKitNextProvider>\n * )\n * }\n */\nexport function DemoKitNextProvider({\n children,\n fixtures,\n scenarios = {},\n storageKey = 'demokit-mode',\n cookieName = 'demokit-mode',\n initialEnabled,\n baseUrl,\n}: DemoKitNextProviderProps) {\n const [isHydrated, setIsHydrated] = useState(false)\n const [scenario, setScenario] = useState<string | null>(null)\n\n // Read initial state from cookie on mount\n useEffect(() => {\n const cookieEnabled = getDemoModeFromCookie(cookieName)\n const cookieScenario = getScenarioFromCookie(cookieName)\n setScenario(cookieScenario)\n setIsHydrated(true)\n }, [cookieName])\n\n // Merge fixtures with scenario fixtures\n const activeFixtures = useMemo(() => {\n if (scenario && scenarios[scenario]) {\n return { ...fixtures, ...scenarios[scenario] }\n }\n return fixtures\n }, [fixtures, scenarios, scenario])\n\n // Determine initial enabled state\n const enabled = useMemo(() => {\n if (initialEnabled !== undefined) {\n return initialEnabled\n }\n if (!isHydrated) {\n return false\n }\n return getDemoModeFromCookie(cookieName)\n }, [initialEnabled, isHydrated, cookieName])\n\n return (\n <DemoKitProvider\n fixtures={activeFixtures}\n storageKey={storageKey}\n initialEnabled={enabled}\n baseUrl={baseUrl}\n >\n {children}\n </DemoKitProvider>\n )\n}\n","'use client'\n\nimport { useCallback } from 'react'\nimport { useDemoMode } from '@demokit-ai/react'\nimport { useRouter, useSearchParams } from 'next/navigation'\n\n/**\n * Hook for Next.js-specific demo mode controls\n *\n * Extends useDemoMode with URL-based scenario switching\n *\n * @example\n * function DemoControls() {\n * const { isDemoMode, enableWithScenario, disableDemo, currentScenario } = useNextDemoMode()\n *\n * return (\n * <div>\n * <button onClick={() => enableWithScenario('empty-state')}>\n * Empty State Demo\n * </button>\n * <button onClick={() => enableWithScenario('error-state')}>\n * Error State Demo\n * </button>\n * <button onClick={disableDemo}>\n * Exit Demo\n * </button>\n * {currentScenario && <span>Scenario: {currentScenario}</span>}\n * </div>\n * )\n * }\n */\nexport function useNextDemoMode(options: { urlParam?: string } = {}) {\n const { urlParam = 'demo' } = options\n const demoMode = useDemoMode()\n const router = useRouter()\n const searchParams = useSearchParams()\n\n /**\n * Enable demo mode with a specific scenario via URL\n */\n const enableWithScenario = useCallback(\n (scenario: string) => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, scenario)\n router.push(`?${params.toString()}`)\n },\n [router, searchParams, urlParam]\n )\n\n /**\n * Enable demo mode without a scenario\n */\n const enableDemo = useCallback(() => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'true')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam])\n\n /**\n * Disable demo mode via URL\n */\n const disableDemo = useCallback(() => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'false')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam])\n\n /**\n * Get current scenario from URL\n */\n const currentScenario = searchParams.get(urlParam)\n const isScenario =\n currentScenario !== null &&\n currentScenario !== 'true' &&\n currentScenario !== 'false' &&\n currentScenario !== '1' &&\n currentScenario !== '0'\n\n return {\n ...demoMode,\n enableWithScenario,\n enableDemo,\n disableDemo,\n currentScenario: isScenario ? currentScenario : null,\n }\n}\n\n/**\n * Hook to check if we're in demo mode on the client\n * Shorthand for useNextDemoMode().isDemoMode\n */\nexport function useIsNextDemoMode(): boolean {\n return useNextDemoMode().isDemoMode\n}\n\n// Re-export base hooks from @demokit-ai/react\nexport { useDemoMode, useIsDemoMode, useIsHydrated, useDemoSession } from '@demokit-ai/react'\n","'use client'\n\nimport { DemoModeBanner, type DemoModeBannerProps } from '@demokit-ai/react'\nimport { useNextDemoMode } from './hooks'\n\nexport interface NextDemoModeBannerProps extends Omit<DemoModeBannerProps, 'onExit'> {\n /**\n * Whether to include the current scenario in the banner\n * @default true\n */\n showScenario?: boolean\n\n /**\n * Custom exit handler\n * If not provided, will use URL-based navigation\n */\n onExit?: () => void\n}\n\n/**\n * Demo mode banner for Next.js\n *\n * Extends DemoModeBanner with scenario display and URL-based exit\n *\n * @example\n * // In your layout\n * <NextDemoModeBanner />\n *\n * // With custom labels\n * <NextDemoModeBanner\n * demoLabel=\"Preview Mode\"\n * exitLabel=\"Exit Preview\"\n * showScenario={true}\n * />\n */\nexport function NextDemoModeBanner({\n showScenario = true,\n onExit,\n description,\n ...props\n}: NextDemoModeBannerProps) {\n const { currentScenario, disableDemo, isDemoMode, isHydrated } = useNextDemoMode()\n\n // Don't render if not hydrated or not in demo mode\n if (!isHydrated || !isDemoMode) {\n return null\n }\n\n // Build description with scenario\n let bannerDescription = description ?? 'Changes are simulated and not saved'\n if (showScenario && currentScenario) {\n bannerDescription = `Scenario: ${currentScenario} • ${bannerDescription}`\n }\n\n return (\n <DemoModeBanner\n {...props}\n description={bannerDescription}\n onExit={onExit ?? disableDemo}\n />\n )\n}\n\n// Re-export base banner\nexport { DemoModeBanner } from '@demokit-ai/react'\n"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/client/provider.tsx","../src/client/hooks.ts","../src/client/banner.tsx"],"sourcesContent":["/**\n * Client-side exports for @demokit-ai/next\n *\n * Import from '@demokit-ai/next/client' for client components.\n *\n * @example\n * 'use client'\n * import { DemoKitNextProvider, useNextDemoMode, NextDemoModeBanner } from '@demokit-ai/next/client'\n */\n\nexport * from './client/index'\n","'use client'\n\nimport { useEffect, useState, useMemo } from 'react'\nimport { DemoKitProvider, type DemoKitProviderProps } from '@demokit-ai/react'\nimport type { FixtureMap } from '@demokit-ai/core'\nimport type { DemoKitNextProviderProps } from '../types'\n\n/**\n * Get initial demo mode state from cookie\n */\nfunction getDemoModeFromCookie(cookieName: string): boolean {\n if (typeof document === 'undefined') return false\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n return demoCookie !== undefined\n}\n\n/**\n * Get scenario from cookie\n */\nfunction getScenarioFromCookie(cookieName: string): string | null {\n if (typeof document === 'undefined') return null\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n if (!demoCookie) return null\n\n const value = demoCookie.split('=')[1]?.trim()\n if (!value || value === 'true') return null\n\n return value\n}\n\n/**\n * Next.js-aware DemoKit provider\n *\n * This provider:\n * - Reads initial state from cookies (set by middleware)\n * - Supports scenario switching\n * - Works with both App Router and Pages Router\n *\n * @example\n * // app/providers.tsx\n * 'use client'\n *\n * import { DemoKitNextProvider } from '@demokit-ai/next/client'\n * import { fixtures, scenarios } from '@/lib/demo-fixtures'\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return (\n * <DemoKitNextProvider\n * fixtures={fixtures}\n * scenarios={scenarios}\n * >\n * {children}\n * </DemoKitNextProvider>\n * )\n * }\n */\nexport function DemoKitNextProvider({\n children,\n fixtures,\n scenarios = {},\n storageKey = 'demokit-mode',\n cookieName = 'demokit-mode',\n initialEnabled,\n baseUrl,\n source,\n}: DemoKitNextProviderProps) {\n // Debug: log source prop on every render\n console.log('[DemoKit Provider] source prop received:', source)\n\n const [isHydrated, setIsHydrated] = useState(false)\n const [scenario, setScenario] = useState<string | null>(null)\n const [remoteFixtures, setRemoteFixtures] = useState<FixtureMap | null>(null)\n const [remoteError, setRemoteError] = useState<Error | null>(null)\n const [sourceMode, setSourceMode] = useState<'local' | 'remote' | 'auto'>('auto')\n\n // Check URL for source parameter on mount\n useEffect(() => {\n if (typeof window === 'undefined') return\n const params = new URLSearchParams(window.location.search)\n const sourceParam = params.get('source')\n if (sourceParam === 'local' || sourceParam === 'remote') {\n setSourceMode(sourceParam)\n console.log('[DemoKit] Source mode from URL:', sourceParam)\n }\n }, [])\n\n // Fetch remote fixtures from DemoKit Cloud if configured\n useEffect(() => {\n const apiKey = source?.apiKey\n const apiUrl = source?.apiUrl\n\n console.log('[DemoKit] Remote config check:', { apiKey: !!apiKey, apiUrl, sourceMode })\n\n // Skip if source=local is set\n if (sourceMode === 'local') {\n console.log('[DemoKit] Skipping remote fetch - source=local')\n return\n }\n\n if (!apiKey || !apiUrl) {\n console.log('[DemoKit] Missing apiKey or apiUrl, skipping remote fetch')\n return\n }\n\n const fetchRemoteFixtures = async () => {\n try {\n console.log('[DemoKit] Fetching remote fixtures from:', apiUrl)\n const response = await fetch(`${apiUrl}/fixtures`, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch fixtures: ${response.status} ${response.statusText}`)\n }\n\n const data = await response.json()\n console.log('[DemoKit] Received remote fixtures:', data)\n\n // Convert remote fixture data to FixtureMap handlers\n const fixtureMap: FixtureMap = {}\n for (const [pattern, fixtureData] of Object.entries(data.fixtures || data)) {\n fixtureMap[pattern] = () => fixtureData\n }\n\n setRemoteFixtures(fixtureMap)\n } catch (error) {\n console.error('[DemoKit] Failed to fetch remote fixtures:', error)\n setRemoteError(error instanceof Error ? error : new Error(String(error)))\n }\n }\n\n fetchRemoteFixtures()\n }, [source, sourceMode])\n\n // Read initial state from cookie on mount\n useEffect(() => {\n const cookieEnabled = getDemoModeFromCookie(cookieName)\n const cookieScenario = getScenarioFromCookie(cookieName)\n setScenario(cookieScenario)\n setIsHydrated(true)\n }, [cookieName])\n\n // Merge fixtures with scenario fixtures and remote fixtures\n const activeFixtures = useMemo(() => {\n let result: FixtureMap\n\n // Determine which fixtures to use based on source mode\n if (sourceMode === 'local') {\n // Force local only\n result = fixtures\n console.log('[DemoKit Provider] Using LOCAL fixtures (forced)')\n } else if (sourceMode === 'remote' && remoteFixtures) {\n // Force remote only (if available)\n result = remoteFixtures\n console.log('[DemoKit Provider] Using REMOTE fixtures (forced)')\n } else if (remoteFixtures) {\n // Auto mode: merge local + remote (remote overrides)\n result = { ...fixtures, ...remoteFixtures }\n console.log('[DemoKit Provider] Using MERGED fixtures (local + remote)')\n } else {\n // No remote fixtures available, use local\n result = fixtures\n console.log('[DemoKit Provider] Using LOCAL fixtures (remote not available)')\n }\n\n // Apply scenario overrides\n if (scenario && scenarios[scenario]) {\n result = { ...result, ...scenarios[scenario] }\n }\n\n console.log('[DemoKit Provider] Active fixtures:', Object.keys(result))\n console.log('[DemoKit Provider] Scenario:', scenario)\n console.log('[DemoKit Provider] Source mode:', sourceMode)\n if (remoteError) {\n console.warn('[DemoKit Provider] Remote fixture error:', remoteError.message)\n }\n return result\n }, [fixtures, scenarios, scenario, remoteFixtures, remoteError, sourceMode])\n\n // Determine initial enabled state from cookie\n const enabled = useMemo(() => {\n if (initialEnabled !== undefined) {\n return initialEnabled\n }\n if (!isHydrated) {\n return false // Will be updated once hydrated\n }\n const cookieValue = getDemoModeFromCookie(cookieName)\n console.log('[DemoKit Next Provider] Demo mode from cookie:', { cookieName, enabled: cookieValue })\n return cookieValue\n }, [initialEnabled, isHydrated, cookieName])\n\n // Use key to force DemoKitProvider to re-mount when hydration completes\n // This ensures it initializes with the correct cookie value\n const providerKey = isHydrated ? `hydrated-${enabled}` : 'pre-hydration'\n\n return (\n <DemoKitProvider\n key={providerKey}\n fixtures={activeFixtures}\n storageKey={storageKey}\n initialEnabled={enabled}\n baseUrl={baseUrl}\n >\n {children}\n </DemoKitProvider>\n )\n}\n","'use client'\n\nimport { useCallback } from 'react'\nimport { useDemoMode } from '@demokit-ai/react'\nimport { useRouter, useSearchParams } from 'next/navigation'\n\n/**\n * Hook for Next.js-specific demo mode controls\n *\n * Extends useDemoMode with URL-based scenario switching\n *\n * @example\n * function DemoControls() {\n * const { isDemoMode, enableWithScenario, disableDemo, currentScenario } = useNextDemoMode()\n *\n * return (\n * <div>\n * <button onClick={() => enableWithScenario('empty-state')}>\n * Empty State Demo\n * </button>\n * <button onClick={() => enableWithScenario('error-state')}>\n * Error State Demo\n * </button>\n * <button onClick={disableDemo}>\n * Exit Demo\n * </button>\n * {currentScenario && <span>Scenario: {currentScenario}</span>}\n * </div>\n * )\n * }\n */\nexport function useNextDemoMode(options: { urlParam?: string } = {}) {\n const { urlParam = 'demo' } = options\n const demoMode = useDemoMode()\n const router = useRouter()\n const searchParams = useSearchParams()\n\n /**\n * Enable demo mode with a specific scenario via URL\n */\n const enableWithScenario = useCallback(\n (scenario: string) => {\n // Enable demo mode in the interceptor\n demoMode.enable()\n // Update URL for persistence and middleware\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, scenario)\n router.push(`?${params.toString()}`)\n },\n [router, searchParams, urlParam, demoMode]\n )\n\n /**\n * Enable demo mode without a scenario\n */\n const enableDemo = useCallback(() => {\n // Enable demo mode in the interceptor\n demoMode.enable()\n // Update URL for persistence and middleware\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'true')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam, demoMode])\n\n /**\n * Disable demo mode via URL\n */\n const disableDemo = useCallback(() => {\n // Disable demo mode in the interceptor\n demoMode.disable()\n // Update URL for persistence and middleware\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'false')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam, demoMode])\n\n /**\n * Get current scenario from URL\n */\n const currentScenario = searchParams.get(urlParam)\n const isScenario =\n currentScenario !== null &&\n currentScenario !== 'true' &&\n currentScenario !== 'false' &&\n currentScenario !== '1' &&\n currentScenario !== '0'\n\n return {\n ...demoMode,\n enableWithScenario,\n enableDemo,\n disableDemo,\n currentScenario: isScenario ? currentScenario : null,\n }\n}\n\n/**\n * Hook to check if we're in demo mode on the client\n * Shorthand for useNextDemoMode().isDemoMode\n */\nexport function useIsNextDemoMode(): boolean {\n return useNextDemoMode().isDemoMode\n}\n\n// Re-export base hooks from @demokit-ai/react\nexport { useDemoMode, useIsDemoMode, useIsHydrated, useDemoSession } from '@demokit-ai/react'\n","'use client'\n\nimport { DemoModeBanner, type DemoModeBannerProps } from '@demokit-ai/react'\nimport { useNextDemoMode } from './hooks'\n\nexport interface NextDemoModeBannerProps extends Omit<DemoModeBannerProps, 'onExit'> {\n /**\n * Whether to include the current scenario in the banner\n * @default true\n */\n showScenario?: boolean\n\n /**\n * Custom exit handler\n * If not provided, will use URL-based navigation\n */\n onExit?: () => void\n}\n\n/**\n * Demo mode banner for Next.js\n *\n * Extends DemoModeBanner with scenario display and URL-based exit\n *\n * @example\n * // In your layout\n * <NextDemoModeBanner />\n *\n * // With custom labels\n * <NextDemoModeBanner\n * demoLabel=\"Preview Mode\"\n * exitLabel=\"Exit Preview\"\n * showScenario={true}\n * />\n */\nexport function NextDemoModeBanner({\n showScenario = true,\n onExit,\n description,\n ...props\n}: NextDemoModeBannerProps) {\n const { currentScenario, disableDemo, isDemoMode, isHydrated } = useNextDemoMode()\n\n // Don't render if not hydrated or not in demo mode\n if (!isHydrated || !isDemoMode) {\n return null\n }\n\n // Build description with scenario\n let bannerDescription = description ?? 'Changes are simulated and not saved'\n if (showScenario && currentScenario) {\n bannerDescription = `Scenario: ${currentScenario} • ${bannerDescription}`\n }\n\n return (\n <DemoModeBanner\n {...props}\n description={bannerDescription}\n onExit={onExit ?? disableDemo}\n />\n )\n}\n\n// Re-export base banner\nexport { DemoModeBanner } from '@demokit-ai/react'\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_jsx_runtime"]}
package/dist/client.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { b as DemoKitNextProviderProps } from './types-Cvq5JUP1.cjs';
2
+ import { b as DemoKitNextProviderProps } from './types-Brt8EaFz.cjs';
3
3
  import * as _demokit_ai_core from '@demokit-ai/core';
4
4
  import { DemoModeBannerProps } from '@demokit-ai/react';
5
5
  export { DemoModeBanner, useDemoMode, useDemoSession, useIsDemoMode, useIsHydrated } from '@demokit-ai/react';
@@ -32,7 +32,7 @@ import 'next/server';
32
32
  * )
33
33
  * }
34
34
  */
35
- declare function DemoKitNextProvider({ children, fixtures, scenarios, storageKey, cookieName, initialEnabled, baseUrl, }: DemoKitNextProviderProps): react_jsx_runtime.JSX.Element;
35
+ declare function DemoKitNextProvider({ children, fixtures, scenarios, storageKey, cookieName, initialEnabled, baseUrl, source, }: DemoKitNextProviderProps): react_jsx_runtime.JSX.Element;
36
36
 
37
37
  /**
38
38
  * Hook for Next.js-specific demo mode controls
@@ -68,12 +68,17 @@ declare function useNextDemoMode(options?: {
68
68
  currentScenario: string | null;
69
69
  isDemoMode: boolean;
70
70
  isHydrated: boolean;
71
+ isPublicDemo: boolean;
72
+ isLoading: boolean;
73
+ remoteError: Error | null;
74
+ remoteVersion: string | null;
71
75
  enable(): void;
72
- disable(): void;
76
+ disable(): boolean | string;
73
77
  toggle(): void;
74
78
  setDemoMode(enabled: boolean): void;
75
79
  resetSession(): void;
76
80
  getSession(): _demokit_ai_core.SessionState | null;
81
+ refetch(): Promise<void>;
77
82
  };
78
83
  /**
79
84
  * Hook to check if we're in demo mode on the client
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { b as DemoKitNextProviderProps } from './types-Cvq5JUP1.js';
2
+ import { b as DemoKitNextProviderProps } from './types-Brt8EaFz.js';
3
3
  import * as _demokit_ai_core from '@demokit-ai/core';
4
4
  import { DemoModeBannerProps } from '@demokit-ai/react';
5
5
  export { DemoModeBanner, useDemoMode, useDemoSession, useIsDemoMode, useIsHydrated } from '@demokit-ai/react';
@@ -32,7 +32,7 @@ import 'next/server';
32
32
  * )
33
33
  * }
34
34
  */
35
- declare function DemoKitNextProvider({ children, fixtures, scenarios, storageKey, cookieName, initialEnabled, baseUrl, }: DemoKitNextProviderProps): react_jsx_runtime.JSX.Element;
35
+ declare function DemoKitNextProvider({ children, fixtures, scenarios, storageKey, cookieName, initialEnabled, baseUrl, source, }: DemoKitNextProviderProps): react_jsx_runtime.JSX.Element;
36
36
 
37
37
  /**
38
38
  * Hook for Next.js-specific demo mode controls
@@ -68,12 +68,17 @@ declare function useNextDemoMode(options?: {
68
68
  currentScenario: string | null;
69
69
  isDemoMode: boolean;
70
70
  isHydrated: boolean;
71
+ isPublicDemo: boolean;
72
+ isLoading: boolean;
73
+ remoteError: Error | null;
74
+ remoteVersion: string | null;
71
75
  enable(): void;
72
- disable(): void;
76
+ disable(): boolean | string;
73
77
  toggle(): void;
74
78
  setDemoMode(enabled: boolean): void;
75
79
  resetSession(): void;
76
80
  getSession(): _demokit_ai_core.SessionState | null;
81
+ refetch(): Promise<void>;
77
82
  };
78
83
  /**
79
84
  * Hook to check if we're in demo mode on the client
package/dist/client.js CHANGED
@@ -1,10 +1,7 @@
1
- import { useState, useEffect, useMemo, useCallback } from 'react';
2
- import { DemoKitProvider, useDemoMode, DemoModeBanner } from '@demokit-ai/react';
3
- export { DemoModeBanner, useDemoMode, useDemoSession, useIsDemoMode, useIsHydrated } from '@demokit-ai/react';
4
- import { jsx } from 'react/jsx-runtime';
5
- import { useRouter, useSearchParams } from 'next/navigation';
6
-
7
1
  // src/client/provider.tsx
2
+ import { useEffect, useState, useMemo } from "react";
3
+ import { DemoKitProvider } from "@demokit-ai/react";
4
+ import { jsx } from "react/jsx-runtime";
8
5
  function getDemoModeFromCookie(cookieName) {
9
6
  if (typeof document === "undefined") return false;
10
7
  const cookies = document.cookie.split(";");
@@ -27,22 +24,94 @@ function DemoKitNextProvider({
27
24
  storageKey = "demokit-mode",
28
25
  cookieName = "demokit-mode",
29
26
  initialEnabled,
30
- baseUrl
27
+ baseUrl,
28
+ source
31
29
  }) {
30
+ console.log("[DemoKit Provider] source prop received:", source);
32
31
  const [isHydrated, setIsHydrated] = useState(false);
33
32
  const [scenario, setScenario] = useState(null);
33
+ const [remoteFixtures, setRemoteFixtures] = useState(null);
34
+ const [remoteError, setRemoteError] = useState(null);
35
+ const [sourceMode, setSourceMode] = useState("auto");
36
+ useEffect(() => {
37
+ if (typeof window === "undefined") return;
38
+ const params = new URLSearchParams(window.location.search);
39
+ const sourceParam = params.get("source");
40
+ if (sourceParam === "local" || sourceParam === "remote") {
41
+ setSourceMode(sourceParam);
42
+ console.log("[DemoKit] Source mode from URL:", sourceParam);
43
+ }
44
+ }, []);
34
45
  useEffect(() => {
35
- getDemoModeFromCookie(cookieName);
46
+ const apiKey = source?.apiKey;
47
+ const apiUrl = source?.apiUrl;
48
+ console.log("[DemoKit] Remote config check:", { apiKey: !!apiKey, apiUrl, sourceMode });
49
+ if (sourceMode === "local") {
50
+ console.log("[DemoKit] Skipping remote fetch - source=local");
51
+ return;
52
+ }
53
+ if (!apiKey || !apiUrl) {
54
+ console.log("[DemoKit] Missing apiKey or apiUrl, skipping remote fetch");
55
+ return;
56
+ }
57
+ const fetchRemoteFixtures = async () => {
58
+ try {
59
+ console.log("[DemoKit] Fetching remote fixtures from:", apiUrl);
60
+ const response = await fetch(`${apiUrl}/fixtures`, {
61
+ headers: {
62
+ Authorization: `Bearer ${apiKey}`,
63
+ "Content-Type": "application/json"
64
+ }
65
+ });
66
+ if (!response.ok) {
67
+ throw new Error(`Failed to fetch fixtures: ${response.status} ${response.statusText}`);
68
+ }
69
+ const data = await response.json();
70
+ console.log("[DemoKit] Received remote fixtures:", data);
71
+ const fixtureMap = {};
72
+ for (const [pattern, fixtureData] of Object.entries(data.fixtures || data)) {
73
+ fixtureMap[pattern] = () => fixtureData;
74
+ }
75
+ setRemoteFixtures(fixtureMap);
76
+ } catch (error) {
77
+ console.error("[DemoKit] Failed to fetch remote fixtures:", error);
78
+ setRemoteError(error instanceof Error ? error : new Error(String(error)));
79
+ }
80
+ };
81
+ fetchRemoteFixtures();
82
+ }, [source, sourceMode]);
83
+ useEffect(() => {
84
+ const cookieEnabled = getDemoModeFromCookie(cookieName);
36
85
  const cookieScenario = getScenarioFromCookie(cookieName);
37
86
  setScenario(cookieScenario);
38
87
  setIsHydrated(true);
39
88
  }, [cookieName]);
40
89
  const activeFixtures = useMemo(() => {
90
+ let result;
91
+ if (sourceMode === "local") {
92
+ result = fixtures;
93
+ console.log("[DemoKit Provider] Using LOCAL fixtures (forced)");
94
+ } else if (sourceMode === "remote" && remoteFixtures) {
95
+ result = remoteFixtures;
96
+ console.log("[DemoKit Provider] Using REMOTE fixtures (forced)");
97
+ } else if (remoteFixtures) {
98
+ result = { ...fixtures, ...remoteFixtures };
99
+ console.log("[DemoKit Provider] Using MERGED fixtures (local + remote)");
100
+ } else {
101
+ result = fixtures;
102
+ console.log("[DemoKit Provider] Using LOCAL fixtures (remote not available)");
103
+ }
41
104
  if (scenario && scenarios[scenario]) {
42
- return { ...fixtures, ...scenarios[scenario] };
105
+ result = { ...result, ...scenarios[scenario] };
43
106
  }
44
- return fixtures;
45
- }, [fixtures, scenarios, scenario]);
107
+ console.log("[DemoKit Provider] Active fixtures:", Object.keys(result));
108
+ console.log("[DemoKit Provider] Scenario:", scenario);
109
+ console.log("[DemoKit Provider] Source mode:", sourceMode);
110
+ if (remoteError) {
111
+ console.warn("[DemoKit Provider] Remote fixture error:", remoteError.message);
112
+ }
113
+ return result;
114
+ }, [fixtures, scenarios, scenario, remoteFixtures, remoteError, sourceMode]);
46
115
  const enabled = useMemo(() => {
47
116
  if (initialEnabled !== void 0) {
48
117
  return initialEnabled;
@@ -50,8 +119,11 @@ function DemoKitNextProvider({
50
119
  if (!isHydrated) {
51
120
  return false;
52
121
  }
53
- return getDemoModeFromCookie(cookieName);
122
+ const cookieValue = getDemoModeFromCookie(cookieName);
123
+ console.log("[DemoKit Next Provider] Demo mode from cookie:", { cookieName, enabled: cookieValue });
124
+ return cookieValue;
54
125
  }, [initialEnabled, isHydrated, cookieName]);
126
+ const providerKey = isHydrated ? `hydrated-${enabled}` : "pre-hydration";
55
127
  return /* @__PURE__ */ jsx(
56
128
  DemoKitProvider,
57
129
  {
@@ -60,9 +132,16 @@ function DemoKitNextProvider({
60
132
  initialEnabled: enabled,
61
133
  baseUrl,
62
134
  children
63
- }
135
+ },
136
+ providerKey
64
137
  );
65
138
  }
139
+
140
+ // src/client/hooks.ts
141
+ import { useCallback } from "react";
142
+ import { useDemoMode } from "@demokit-ai/react";
143
+ import { useRouter, useSearchParams } from "next/navigation";
144
+ import { useDemoMode as useDemoMode2, useIsDemoMode, useIsHydrated, useDemoSession } from "@demokit-ai/react";
66
145
  function useNextDemoMode(options = {}) {
67
146
  const { urlParam = "demo" } = options;
68
147
  const demoMode = useDemoMode();
@@ -70,22 +149,25 @@ function useNextDemoMode(options = {}) {
70
149
  const searchParams = useSearchParams();
71
150
  const enableWithScenario = useCallback(
72
151
  (scenario) => {
152
+ demoMode.enable();
73
153
  const params = new URLSearchParams(searchParams.toString());
74
154
  params.set(urlParam, scenario);
75
155
  router.push(`?${params.toString()}`);
76
156
  },
77
- [router, searchParams, urlParam]
157
+ [router, searchParams, urlParam, demoMode]
78
158
  );
79
159
  const enableDemo = useCallback(() => {
160
+ demoMode.enable();
80
161
  const params = new URLSearchParams(searchParams.toString());
81
162
  params.set(urlParam, "true");
82
163
  router.push(`?${params.toString()}`);
83
- }, [router, searchParams, urlParam]);
164
+ }, [router, searchParams, urlParam, demoMode]);
84
165
  const disableDemo = useCallback(() => {
166
+ demoMode.disable();
85
167
  const params = new URLSearchParams(searchParams.toString());
86
168
  params.set(urlParam, "false");
87
169
  router.push(`?${params.toString()}`);
88
- }, [router, searchParams, urlParam]);
170
+ }, [router, searchParams, urlParam, demoMode]);
89
171
  const currentScenario = searchParams.get(urlParam);
90
172
  const isScenario = currentScenario !== null && currentScenario !== "true" && currentScenario !== "false" && currentScenario !== "1" && currentScenario !== "0";
91
173
  return {
@@ -99,6 +181,11 @@ function useNextDemoMode(options = {}) {
99
181
  function useIsNextDemoMode() {
100
182
  return useNextDemoMode().isDemoMode;
101
183
  }
184
+
185
+ // src/client/banner.tsx
186
+ import { DemoModeBanner } from "@demokit-ai/react";
187
+ import { DemoModeBanner as DemoModeBanner2 } from "@demokit-ai/react";
188
+ import { jsx as jsx2 } from "react/jsx-runtime";
102
189
  function NextDemoModeBanner({
103
190
  showScenario = true,
104
191
  onExit,
@@ -113,7 +200,7 @@ function NextDemoModeBanner({
113
200
  if (showScenario && currentScenario) {
114
201
  bannerDescription = `Scenario: ${currentScenario} \u2022 ${bannerDescription}`;
115
202
  }
116
- return /* @__PURE__ */ jsx(
203
+ return /* @__PURE__ */ jsx2(
117
204
  DemoModeBanner,
118
205
  {
119
206
  ...props,
@@ -122,7 +209,15 @@ function NextDemoModeBanner({
122
209
  }
123
210
  );
124
211
  }
125
-
126
- export { DemoKitNextProvider, NextDemoModeBanner, useIsNextDemoMode, useNextDemoMode };
127
- //# sourceMappingURL=client.js.map
212
+ export {
213
+ DemoKitNextProvider,
214
+ DemoModeBanner2 as DemoModeBanner,
215
+ NextDemoModeBanner,
216
+ useDemoMode2 as useDemoMode,
217
+ useDemoSession,
218
+ useIsDemoMode,
219
+ useIsHydrated,
220
+ useIsNextDemoMode,
221
+ useNextDemoMode
222
+ };
128
223
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/provider.tsx","../src/client/hooks.ts","../src/client/banner.tsx"],"names":["jsx"],"mappings":"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","file":"client.js","sourcesContent":["'use client'\n\nimport { useEffect, useState, useMemo } from 'react'\nimport { DemoKitProvider, type DemoKitProviderProps } from '@demokit-ai/react'\nimport type { DemoKitNextProviderProps } from '../types'\n\n/**\n * Get initial demo mode state from cookie\n */\nfunction getDemoModeFromCookie(cookieName: string): boolean {\n if (typeof document === 'undefined') return false\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n return demoCookie !== undefined\n}\n\n/**\n * Get scenario from cookie\n */\nfunction getScenarioFromCookie(cookieName: string): string | null {\n if (typeof document === 'undefined') return null\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n if (!demoCookie) return null\n\n const value = demoCookie.split('=')[1]?.trim()\n if (!value || value === 'true') return null\n\n return value\n}\n\n/**\n * Next.js-aware DemoKit provider\n *\n * This provider:\n * - Reads initial state from cookies (set by middleware)\n * - Supports scenario switching\n * - Works with both App Router and Pages Router\n *\n * @example\n * // app/providers.tsx\n * 'use client'\n *\n * import { DemoKitNextProvider } from '@demokit-ai/next/client'\n * import { fixtures, scenarios } from '@/lib/demo-fixtures'\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return (\n * <DemoKitNextProvider\n * fixtures={fixtures}\n * scenarios={scenarios}\n * >\n * {children}\n * </DemoKitNextProvider>\n * )\n * }\n */\nexport function DemoKitNextProvider({\n children,\n fixtures,\n scenarios = {},\n storageKey = 'demokit-mode',\n cookieName = 'demokit-mode',\n initialEnabled,\n baseUrl,\n}: DemoKitNextProviderProps) {\n const [isHydrated, setIsHydrated] = useState(false)\n const [scenario, setScenario] = useState<string | null>(null)\n\n // Read initial state from cookie on mount\n useEffect(() => {\n const cookieEnabled = getDemoModeFromCookie(cookieName)\n const cookieScenario = getScenarioFromCookie(cookieName)\n setScenario(cookieScenario)\n setIsHydrated(true)\n }, [cookieName])\n\n // Merge fixtures with scenario fixtures\n const activeFixtures = useMemo(() => {\n if (scenario && scenarios[scenario]) {\n return { ...fixtures, ...scenarios[scenario] }\n }\n return fixtures\n }, [fixtures, scenarios, scenario])\n\n // Determine initial enabled state\n const enabled = useMemo(() => {\n if (initialEnabled !== undefined) {\n return initialEnabled\n }\n if (!isHydrated) {\n return false\n }\n return getDemoModeFromCookie(cookieName)\n }, [initialEnabled, isHydrated, cookieName])\n\n return (\n <DemoKitProvider\n fixtures={activeFixtures}\n storageKey={storageKey}\n initialEnabled={enabled}\n baseUrl={baseUrl}\n >\n {children}\n </DemoKitProvider>\n )\n}\n","'use client'\n\nimport { useCallback } from 'react'\nimport { useDemoMode } from '@demokit-ai/react'\nimport { useRouter, useSearchParams } from 'next/navigation'\n\n/**\n * Hook for Next.js-specific demo mode controls\n *\n * Extends useDemoMode with URL-based scenario switching\n *\n * @example\n * function DemoControls() {\n * const { isDemoMode, enableWithScenario, disableDemo, currentScenario } = useNextDemoMode()\n *\n * return (\n * <div>\n * <button onClick={() => enableWithScenario('empty-state')}>\n * Empty State Demo\n * </button>\n * <button onClick={() => enableWithScenario('error-state')}>\n * Error State Demo\n * </button>\n * <button onClick={disableDemo}>\n * Exit Demo\n * </button>\n * {currentScenario && <span>Scenario: {currentScenario}</span>}\n * </div>\n * )\n * }\n */\nexport function useNextDemoMode(options: { urlParam?: string } = {}) {\n const { urlParam = 'demo' } = options\n const demoMode = useDemoMode()\n const router = useRouter()\n const searchParams = useSearchParams()\n\n /**\n * Enable demo mode with a specific scenario via URL\n */\n const enableWithScenario = useCallback(\n (scenario: string) => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, scenario)\n router.push(`?${params.toString()}`)\n },\n [router, searchParams, urlParam]\n )\n\n /**\n * Enable demo mode without a scenario\n */\n const enableDemo = useCallback(() => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'true')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam])\n\n /**\n * Disable demo mode via URL\n */\n const disableDemo = useCallback(() => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'false')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam])\n\n /**\n * Get current scenario from URL\n */\n const currentScenario = searchParams.get(urlParam)\n const isScenario =\n currentScenario !== null &&\n currentScenario !== 'true' &&\n currentScenario !== 'false' &&\n currentScenario !== '1' &&\n currentScenario !== '0'\n\n return {\n ...demoMode,\n enableWithScenario,\n enableDemo,\n disableDemo,\n currentScenario: isScenario ? currentScenario : null,\n }\n}\n\n/**\n * Hook to check if we're in demo mode on the client\n * Shorthand for useNextDemoMode().isDemoMode\n */\nexport function useIsNextDemoMode(): boolean {\n return useNextDemoMode().isDemoMode\n}\n\n// Re-export base hooks from @demokit-ai/react\nexport { useDemoMode, useIsDemoMode, useIsHydrated, useDemoSession } from '@demokit-ai/react'\n","'use client'\n\nimport { DemoModeBanner, type DemoModeBannerProps } from '@demokit-ai/react'\nimport { useNextDemoMode } from './hooks'\n\nexport interface NextDemoModeBannerProps extends Omit<DemoModeBannerProps, 'onExit'> {\n /**\n * Whether to include the current scenario in the banner\n * @default true\n */\n showScenario?: boolean\n\n /**\n * Custom exit handler\n * If not provided, will use URL-based navigation\n */\n onExit?: () => void\n}\n\n/**\n * Demo mode banner for Next.js\n *\n * Extends DemoModeBanner with scenario display and URL-based exit\n *\n * @example\n * // In your layout\n * <NextDemoModeBanner />\n *\n * // With custom labels\n * <NextDemoModeBanner\n * demoLabel=\"Preview Mode\"\n * exitLabel=\"Exit Preview\"\n * showScenario={true}\n * />\n */\nexport function NextDemoModeBanner({\n showScenario = true,\n onExit,\n description,\n ...props\n}: NextDemoModeBannerProps) {\n const { currentScenario, disableDemo, isDemoMode, isHydrated } = useNextDemoMode()\n\n // Don't render if not hydrated or not in demo mode\n if (!isHydrated || !isDemoMode) {\n return null\n }\n\n // Build description with scenario\n let bannerDescription = description ?? 'Changes are simulated and not saved'\n if (showScenario && currentScenario) {\n bannerDescription = `Scenario: ${currentScenario} • ${bannerDescription}`\n }\n\n return (\n <DemoModeBanner\n {...props}\n description={bannerDescription}\n onExit={onExit ?? disableDemo}\n />\n )\n}\n\n// Re-export base banner\nexport { DemoModeBanner } from '@demokit-ai/react'\n"]}
1
+ {"version":3,"sources":["../src/client/provider.tsx","../src/client/hooks.ts","../src/client/banner.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState, useMemo } from 'react'\nimport { DemoKitProvider, type DemoKitProviderProps } from '@demokit-ai/react'\nimport type { FixtureMap } from '@demokit-ai/core'\nimport type { DemoKitNextProviderProps } from '../types'\n\n/**\n * Get initial demo mode state from cookie\n */\nfunction getDemoModeFromCookie(cookieName: string): boolean {\n if (typeof document === 'undefined') return false\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n return demoCookie !== undefined\n}\n\n/**\n * Get scenario from cookie\n */\nfunction getScenarioFromCookie(cookieName: string): string | null {\n if (typeof document === 'undefined') return null\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n if (!demoCookie) return null\n\n const value = demoCookie.split('=')[1]?.trim()\n if (!value || value === 'true') return null\n\n return value\n}\n\n/**\n * Next.js-aware DemoKit provider\n *\n * This provider:\n * - Reads initial state from cookies (set by middleware)\n * - Supports scenario switching\n * - Works with both App Router and Pages Router\n *\n * @example\n * // app/providers.tsx\n * 'use client'\n *\n * import { DemoKitNextProvider } from '@demokit-ai/next/client'\n * import { fixtures, scenarios } from '@/lib/demo-fixtures'\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return (\n * <DemoKitNextProvider\n * fixtures={fixtures}\n * scenarios={scenarios}\n * >\n * {children}\n * </DemoKitNextProvider>\n * )\n * }\n */\nexport function DemoKitNextProvider({\n children,\n fixtures,\n scenarios = {},\n storageKey = 'demokit-mode',\n cookieName = 'demokit-mode',\n initialEnabled,\n baseUrl,\n source,\n}: DemoKitNextProviderProps) {\n // Debug: log source prop on every render\n console.log('[DemoKit Provider] source prop received:', source)\n\n const [isHydrated, setIsHydrated] = useState(false)\n const [scenario, setScenario] = useState<string | null>(null)\n const [remoteFixtures, setRemoteFixtures] = useState<FixtureMap | null>(null)\n const [remoteError, setRemoteError] = useState<Error | null>(null)\n const [sourceMode, setSourceMode] = useState<'local' | 'remote' | 'auto'>('auto')\n\n // Check URL for source parameter on mount\n useEffect(() => {\n if (typeof window === 'undefined') return\n const params = new URLSearchParams(window.location.search)\n const sourceParam = params.get('source')\n if (sourceParam === 'local' || sourceParam === 'remote') {\n setSourceMode(sourceParam)\n console.log('[DemoKit] Source mode from URL:', sourceParam)\n }\n }, [])\n\n // Fetch remote fixtures from DemoKit Cloud if configured\n useEffect(() => {\n const apiKey = source?.apiKey\n const apiUrl = source?.apiUrl\n\n console.log('[DemoKit] Remote config check:', { apiKey: !!apiKey, apiUrl, sourceMode })\n\n // Skip if source=local is set\n if (sourceMode === 'local') {\n console.log('[DemoKit] Skipping remote fetch - source=local')\n return\n }\n\n if (!apiKey || !apiUrl) {\n console.log('[DemoKit] Missing apiKey or apiUrl, skipping remote fetch')\n return\n }\n\n const fetchRemoteFixtures = async () => {\n try {\n console.log('[DemoKit] Fetching remote fixtures from:', apiUrl)\n const response = await fetch(`${apiUrl}/fixtures`, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch fixtures: ${response.status} ${response.statusText}`)\n }\n\n const data = await response.json()\n console.log('[DemoKit] Received remote fixtures:', data)\n\n // Convert remote fixture data to FixtureMap handlers\n const fixtureMap: FixtureMap = {}\n for (const [pattern, fixtureData] of Object.entries(data.fixtures || data)) {\n fixtureMap[pattern] = () => fixtureData\n }\n\n setRemoteFixtures(fixtureMap)\n } catch (error) {\n console.error('[DemoKit] Failed to fetch remote fixtures:', error)\n setRemoteError(error instanceof Error ? error : new Error(String(error)))\n }\n }\n\n fetchRemoteFixtures()\n }, [source, sourceMode])\n\n // Read initial state from cookie on mount\n useEffect(() => {\n const cookieEnabled = getDemoModeFromCookie(cookieName)\n const cookieScenario = getScenarioFromCookie(cookieName)\n setScenario(cookieScenario)\n setIsHydrated(true)\n }, [cookieName])\n\n // Merge fixtures with scenario fixtures and remote fixtures\n const activeFixtures = useMemo(() => {\n let result: FixtureMap\n\n // Determine which fixtures to use based on source mode\n if (sourceMode === 'local') {\n // Force local only\n result = fixtures\n console.log('[DemoKit Provider] Using LOCAL fixtures (forced)')\n } else if (sourceMode === 'remote' && remoteFixtures) {\n // Force remote only (if available)\n result = remoteFixtures\n console.log('[DemoKit Provider] Using REMOTE fixtures (forced)')\n } else if (remoteFixtures) {\n // Auto mode: merge local + remote (remote overrides)\n result = { ...fixtures, ...remoteFixtures }\n console.log('[DemoKit Provider] Using MERGED fixtures (local + remote)')\n } else {\n // No remote fixtures available, use local\n result = fixtures\n console.log('[DemoKit Provider] Using LOCAL fixtures (remote not available)')\n }\n\n // Apply scenario overrides\n if (scenario && scenarios[scenario]) {\n result = { ...result, ...scenarios[scenario] }\n }\n\n console.log('[DemoKit Provider] Active fixtures:', Object.keys(result))\n console.log('[DemoKit Provider] Scenario:', scenario)\n console.log('[DemoKit Provider] Source mode:', sourceMode)\n if (remoteError) {\n console.warn('[DemoKit Provider] Remote fixture error:', remoteError.message)\n }\n return result\n }, [fixtures, scenarios, scenario, remoteFixtures, remoteError, sourceMode])\n\n // Determine initial enabled state from cookie\n const enabled = useMemo(() => {\n if (initialEnabled !== undefined) {\n return initialEnabled\n }\n if (!isHydrated) {\n return false // Will be updated once hydrated\n }\n const cookieValue = getDemoModeFromCookie(cookieName)\n console.log('[DemoKit Next Provider] Demo mode from cookie:', { cookieName, enabled: cookieValue })\n return cookieValue\n }, [initialEnabled, isHydrated, cookieName])\n\n // Use key to force DemoKitProvider to re-mount when hydration completes\n // This ensures it initializes with the correct cookie value\n const providerKey = isHydrated ? `hydrated-${enabled}` : 'pre-hydration'\n\n return (\n <DemoKitProvider\n key={providerKey}\n fixtures={activeFixtures}\n storageKey={storageKey}\n initialEnabled={enabled}\n baseUrl={baseUrl}\n >\n {children}\n </DemoKitProvider>\n )\n}\n","'use client'\n\nimport { useCallback } from 'react'\nimport { useDemoMode } from '@demokit-ai/react'\nimport { useRouter, useSearchParams } from 'next/navigation'\n\n/**\n * Hook for Next.js-specific demo mode controls\n *\n * Extends useDemoMode with URL-based scenario switching\n *\n * @example\n * function DemoControls() {\n * const { isDemoMode, enableWithScenario, disableDemo, currentScenario } = useNextDemoMode()\n *\n * return (\n * <div>\n * <button onClick={() => enableWithScenario('empty-state')}>\n * Empty State Demo\n * </button>\n * <button onClick={() => enableWithScenario('error-state')}>\n * Error State Demo\n * </button>\n * <button onClick={disableDemo}>\n * Exit Demo\n * </button>\n * {currentScenario && <span>Scenario: {currentScenario}</span>}\n * </div>\n * )\n * }\n */\nexport function useNextDemoMode(options: { urlParam?: string } = {}) {\n const { urlParam = 'demo' } = options\n const demoMode = useDemoMode()\n const router = useRouter()\n const searchParams = useSearchParams()\n\n /**\n * Enable demo mode with a specific scenario via URL\n */\n const enableWithScenario = useCallback(\n (scenario: string) => {\n // Enable demo mode in the interceptor\n demoMode.enable()\n // Update URL for persistence and middleware\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, scenario)\n router.push(`?${params.toString()}`)\n },\n [router, searchParams, urlParam, demoMode]\n )\n\n /**\n * Enable demo mode without a scenario\n */\n const enableDemo = useCallback(() => {\n // Enable demo mode in the interceptor\n demoMode.enable()\n // Update URL for persistence and middleware\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'true')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam, demoMode])\n\n /**\n * Disable demo mode via URL\n */\n const disableDemo = useCallback(() => {\n // Disable demo mode in the interceptor\n demoMode.disable()\n // Update URL for persistence and middleware\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'false')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam, demoMode])\n\n /**\n * Get current scenario from URL\n */\n const currentScenario = searchParams.get(urlParam)\n const isScenario =\n currentScenario !== null &&\n currentScenario !== 'true' &&\n currentScenario !== 'false' &&\n currentScenario !== '1' &&\n currentScenario !== '0'\n\n return {\n ...demoMode,\n enableWithScenario,\n enableDemo,\n disableDemo,\n currentScenario: isScenario ? currentScenario : null,\n }\n}\n\n/**\n * Hook to check if we're in demo mode on the client\n * Shorthand for useNextDemoMode().isDemoMode\n */\nexport function useIsNextDemoMode(): boolean {\n return useNextDemoMode().isDemoMode\n}\n\n// Re-export base hooks from @demokit-ai/react\nexport { useDemoMode, useIsDemoMode, useIsHydrated, useDemoSession } from '@demokit-ai/react'\n","'use client'\n\nimport { DemoModeBanner, type DemoModeBannerProps } from '@demokit-ai/react'\nimport { useNextDemoMode } from './hooks'\n\nexport interface NextDemoModeBannerProps extends Omit<DemoModeBannerProps, 'onExit'> {\n /**\n * Whether to include the current scenario in the banner\n * @default true\n */\n showScenario?: boolean\n\n /**\n * Custom exit handler\n * If not provided, will use URL-based navigation\n */\n onExit?: () => void\n}\n\n/**\n * Demo mode banner for Next.js\n *\n * Extends DemoModeBanner with scenario display and URL-based exit\n *\n * @example\n * // In your layout\n * <NextDemoModeBanner />\n *\n * // With custom labels\n * <NextDemoModeBanner\n * demoLabel=\"Preview Mode\"\n * exitLabel=\"Exit Preview\"\n * showScenario={true}\n * />\n */\nexport function NextDemoModeBanner({\n showScenario = true,\n onExit,\n description,\n ...props\n}: NextDemoModeBannerProps) {\n const { currentScenario, disableDemo, isDemoMode, isHydrated } = useNextDemoMode()\n\n // Don't render if not hydrated or not in demo mode\n if (!isHydrated || !isDemoMode) {\n return null\n }\n\n // Build description with scenario\n let bannerDescription = description ?? 'Changes are simulated and not saved'\n if (showScenario && currentScenario) {\n bannerDescription = `Scenario: ${currentScenario} • ${bannerDescription}`\n }\n\n return (\n <DemoModeBanner\n {...props}\n description={bannerDescription}\n onExit={onExit ?? disableDemo}\n />\n )\n}\n\n// Re-export base banner\nexport { DemoModeBanner } from '@demokit-ai/react'\n"],"mappings":"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","names":["useDemoMode","DemoModeBanner","jsx"]}
package/dist/index.cjs CHANGED
@@ -1,4 +1,33 @@
1
- 'use strict';
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ createDemoConfig: () => createDemoConfig,
24
+ createRemoteSource: () => createRemoteSource,
25
+ createScenario: () => createScenario,
26
+ defineFixtures: () => defineFixtures,
27
+ defineScenarios: () => defineScenarios,
28
+ mergeFixtures: () => mergeFixtures
29
+ });
30
+ module.exports = __toCommonJS(src_exports);
2
31
 
3
32
  // src/config.ts
4
33
  function defineFixtures(fixtures) {
@@ -21,11 +50,21 @@ function createDemoConfig(config) {
21
50
  ...config
22
51
  };
23
52
  }
24
-
25
- exports.createDemoConfig = createDemoConfig;
26
- exports.createScenario = createScenario;
27
- exports.defineFixtures = defineFixtures;
28
- exports.defineScenarios = defineScenarios;
29
- exports.mergeFixtures = mergeFixtures;
30
- //# sourceMappingURL=index.cjs.map
53
+ function createRemoteSource(config) {
54
+ return {
55
+ timeout: 1e4,
56
+ retry: true,
57
+ maxRetries: 3,
58
+ ...config
59
+ };
60
+ }
61
+ // Annotate the CommonJS export names for ESM import in node:
62
+ 0 && (module.exports = {
63
+ createDemoConfig,
64
+ createRemoteSource,
65
+ createScenario,
66
+ defineFixtures,
67
+ defineScenarios,
68
+ mergeFixtures
69
+ });
31
70
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts"],"names":[],"mappings":";;;AAqBO,SAAS,eAAqC,QAAA,EAAgB;AACnE,EAAA,OAAO,QAAA;AACT;AAuBO,SAAS,gBAAsD,SAAA,EAAiB;AACrF,EAAA,OAAO,SAAA;AACT;AAcO,SAAS,eAAe,QAAA,EAAsC;AACnE,EAAA,OAAO,QAAA;AACT;AAYO,SAAS,iBAAiB,WAAA,EAAuC;AACtE,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAC,EAAG,GAAG,WAAW,CAAA;AACzC;AAkBO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,cAAA;AAAA,IACZ,UAAA,EAAY,cAAA;AAAA,IACZ,QAAA,EAAU,MAAA;AAAA,IACV,GAAG;AAAA,GACL;AACF","file":"index.cjs","sourcesContent":["import type { FixtureMap, FixtureHandler } from '@demokit-ai/core'\nimport type { DemoKitNextConfig, DemoScenario } from './types'\n\n/**\n * Helper to define fixtures with type safety\n *\n * @example\n * const fixtures = defineFixtures({\n * 'GET /api/users': () => [\n * { id: '1', name: 'Demo User' },\n * ],\n * 'GET /api/users/:id': ({ params }) => ({\n * id: params.id,\n * name: `User ${params.id}`,\n * }),\n * 'POST /api/users': async ({ body }) => ({\n * id: crypto.randomUUID(),\n * ...body,\n * }),\n * })\n */\nexport function defineFixtures<T extends FixtureMap>(fixtures: T): T {\n return fixtures\n}\n\n/**\n * Helper to define scenarios with type safety\n *\n * @example\n * const scenarios = defineScenarios({\n * 'empty-state': {\n * 'GET /api/users': () => [],\n * 'GET /api/projects': () => [],\n * },\n * 'error-state': {\n * 'GET /api/users': () => {\n * throw new Error('API Error')\n * },\n * },\n * 'new-user': {\n * 'GET /api/users': () => [\n * { id: '1', name: 'Welcome, New User!', isNew: true },\n * ],\n * },\n * })\n */\nexport function defineScenarios<T extends Record<string, FixtureMap>>(scenarios: T): T {\n return scenarios\n}\n\n/**\n * Helper to create a scenario object\n *\n * @example\n * const emptyStateScenario = createScenario({\n * name: 'empty-state',\n * description: 'Shows the app with no data',\n * fixtures: {\n * 'GET /api/users': () => [],\n * },\n * })\n */\nexport function createScenario(scenario: DemoScenario): DemoScenario {\n return scenario\n}\n\n/**\n * Merge multiple fixture maps\n *\n * @example\n * const allFixtures = mergeFixtures(\n * baseFixtures,\n * usersFixtures,\n * projectsFixtures\n * )\n */\nexport function mergeFixtures(...fixtureMaps: FixtureMap[]): FixtureMap {\n return Object.assign({}, ...fixtureMaps)\n}\n\n/**\n * Create a complete DemoKit Next.js configuration\n *\n * @example\n * // lib/demo.ts\n * import { createDemoConfig, defineFixtures, defineScenarios } from '@demokit-ai/next'\n *\n * export const demoConfig = createDemoConfig({\n * fixtures: defineFixtures({\n * 'GET /api/users': () => [{ id: '1', name: 'Demo User' }],\n * }),\n * scenarios: defineScenarios({\n * 'empty': { 'GET /api/users': () => [] },\n * }),\n * })\n */\nexport function createDemoConfig(config: DemoKitNextConfig): DemoKitNextConfig {\n return {\n storageKey: 'demokit-mode',\n cookieName: 'demokit-mode',\n urlParam: 'demo',\n ...config,\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts"],"sourcesContent":["/**\n * @demokit-ai/next\n *\n * Next.js adapter for DemoKit.\n * Full integration with App Router, middleware, and API routes.\n *\n * @example\n * // 1. Define your fixtures and scenarios\n * import { defineFixtures, defineScenarios, createDemoConfig } from '@demokit-ai/next'\n *\n * export const demoConfig = createDemoConfig({\n * fixtures: defineFixtures({\n * 'GET /api/users': () => [{ id: '1', name: 'Demo User' }],\n * }),\n * scenarios: defineScenarios({\n * 'empty': { 'GET /api/users': () => [] },\n * }),\n * })\n *\n * // 2. Add middleware (middleware.ts)\n * import { demoMiddleware } from '@demokit-ai/next/middleware'\n * export const middleware = demoMiddleware()\n *\n * // 3. Wrap your app (app/providers.tsx)\n * import { DemoKitNextProvider } from '@demokit-ai/next/client'\n * import { demoConfig } from '@/lib/demo'\n *\n * export function Providers({ children }) {\n * return (\n * <DemoKitNextProvider {...demoConfig}>\n * {children}\n * </DemoKitNextProvider>\n * )\n * }\n *\n * // 4. Enable demo mode via URL: ?demo=true or ?demo=scenario-name\n *\n * @packageDocumentation\n */\n\n// Configuration helpers\nexport {\n defineFixtures,\n defineScenarios,\n createScenario,\n mergeFixtures,\n createDemoConfig,\n createRemoteSource,\n} from './config'\n\n// Types\nexport type {\n DemoKitNextConfig,\n DemoKitNextProviderProps,\n DemoMiddlewareConfig,\n MiddlewareResult,\n DemoScenario,\n DefineFixtures,\n DefineScenarios,\n RemoteSourceConfig,\n} from './types'\n\n// Re-export core types\nexport type { FixtureMap, FixtureHandler, RequestContext } from '@demokit-ai/core'\n","import type { FixtureMap } from '@demokit-ai/core'\nimport type { DemoKitNextConfig, DemoScenario, RemoteSourceConfig } from './types'\n\n/**\n * Helper to define fixtures with type safety\n *\n * @example\n * const fixtures = defineFixtures({\n * 'GET /api/users': () => [\n * { id: '1', name: 'Demo User' },\n * ],\n * 'GET /api/users/:id': ({ params }) => ({\n * id: params.id,\n * name: `User ${params.id}`,\n * }),\n * 'POST /api/users': async ({ body }) => ({\n * id: crypto.randomUUID(),\n * ...body,\n * }),\n * })\n */\nexport function defineFixtures<T extends FixtureMap>(fixtures: T): T {\n return fixtures\n}\n\n/**\n * Helper to define scenarios with type safety\n *\n * @example\n * const scenarios = defineScenarios({\n * 'empty-state': {\n * 'GET /api/users': () => [],\n * 'GET /api/projects': () => [],\n * },\n * 'error-state': {\n * 'GET /api/users': () => {\n * throw new Error('API Error')\n * },\n * },\n * 'new-user': {\n * 'GET /api/users': () => [\n * { id: '1', name: 'Welcome, New User!', isNew: true },\n * ],\n * },\n * })\n */\nexport function defineScenarios<T extends Record<string, FixtureMap>>(scenarios: T): T {\n return scenarios\n}\n\n/**\n * Helper to create a scenario object\n *\n * @example\n * const emptyStateScenario = createScenario({\n * name: 'empty-state',\n * description: 'Shows the app with no data',\n * fixtures: {\n * 'GET /api/users': () => [],\n * },\n * })\n */\nexport function createScenario(scenario: DemoScenario): DemoScenario {\n return scenario\n}\n\n/**\n * Merge multiple fixture maps\n *\n * @example\n * const allFixtures = mergeFixtures(\n * baseFixtures,\n * usersFixtures,\n * projectsFixtures\n * )\n */\nexport function mergeFixtures(...fixtureMaps: FixtureMap[]): FixtureMap {\n return Object.assign({}, ...fixtureMaps)\n}\n\n/**\n * Create a complete DemoKit Next.js configuration\n *\n * @example\n * // lib/demo.ts\n * import { createDemoConfig, defineFixtures, defineScenarios } from '@demokit-ai/next'\n *\n * export const demoConfig = createDemoConfig({\n * fixtures: defineFixtures({\n * 'GET /api/users': () => [{ id: '1', name: 'Demo User' }],\n * }),\n * scenarios: defineScenarios({\n * 'empty': { 'GET /api/users': () => [] },\n * }),\n * })\n */\nexport function createDemoConfig(config: DemoKitNextConfig): DemoKitNextConfig {\n return {\n storageKey: 'demokit-mode',\n cookieName: 'demokit-mode',\n urlParam: 'demo',\n ...config,\n }\n}\n\n/**\n * Create a remote source configuration for fetching fixtures from DemoKit Cloud\n *\n * The SDK appends `/fixtures` to your apiUrl, so provide the versioned base URL.\n *\n * @example\n * ```typescript\n * // lib/demokit-config.ts\n * import { createRemoteSource } from '@demokit-ai/next'\n *\n * // .env.local:\n * // NEXT_PUBLIC_DEMOKIT_API_URL=https://demokit-cloud.kasava.dev/api\n * // NEXT_PUBLIC_DEMOKIT_API_KEY=dk_live_xxxx\n *\n * export const demokitSource = createRemoteSource({\n * apiUrl: process.env.NEXT_PUBLIC_DEMOKIT_API_URL!,\n * apiKey: process.env.NEXT_PUBLIC_DEMOKIT_API_KEY!,\n * })\n *\n * // Then in providers.tsx:\n * import { demokitSource } from '@/lib/demokit-config'\n *\n * <DemoKitNextProvider source={demokitSource}>\n * {children}\n * </DemoKitNextProvider>\n * ```\n */\nexport function createRemoteSource(config: RemoteSourceConfig): RemoteSourceConfig {\n return {\n timeout: 10000,\n retry: true,\n maxRetries: 3,\n ...config,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqBO,SAAS,eAAqC,UAAgB;AACnE,SAAO;AACT;AAuBO,SAAS,gBAAsD,WAAiB;AACrF,SAAO;AACT;AAcO,SAAS,eAAe,UAAsC;AACnE,SAAO;AACT;AAYO,SAAS,iBAAiB,aAAuC;AACtE,SAAO,OAAO,OAAO,CAAC,GAAG,GAAG,WAAW;AACzC;AAkBO,SAAS,iBAAiB,QAA8C;AAC7E,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,GAAG;AAAA,EACL;AACF;AA6BO,SAAS,mBAAmB,QAAgD;AACjF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,GAAG;AAAA,EACL;AACF;","names":[]}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { FixtureMap } from '@demokit-ai/core';
2
2
  export { FixtureHandler, FixtureMap, RequestContext } from '@demokit-ai/core';
3
- import { D as DemoScenario, a as DemoKitNextConfig } from './types-Cvq5JUP1.cjs';
4
- export { d as DefineFixtures, e as DefineScenarios, b as DemoKitNextProviderProps, c as DemoMiddlewareConfig, M as MiddlewareResult } from './types-Cvq5JUP1.cjs';
3
+ import { D as DemoScenario, a as DemoKitNextConfig, R as RemoteSourceConfig } from './types-Brt8EaFz.cjs';
4
+ export { d as DefineFixtures, e as DefineScenarios, b as DemoKitNextProviderProps, c as DemoMiddlewareConfig, M as MiddlewareResult } from './types-Brt8EaFz.cjs';
5
5
  import 'react';
6
6
  import 'next/server';
7
7
 
@@ -87,5 +87,33 @@ declare function mergeFixtures(...fixtureMaps: FixtureMap[]): FixtureMap;
87
87
  * })
88
88
  */
89
89
  declare function createDemoConfig(config: DemoKitNextConfig): DemoKitNextConfig;
90
+ /**
91
+ * Create a remote source configuration for fetching fixtures from DemoKit Cloud
92
+ *
93
+ * The SDK appends `/fixtures` to your apiUrl, so provide the versioned base URL.
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * // lib/demokit-config.ts
98
+ * import { createRemoteSource } from '@demokit-ai/next'
99
+ *
100
+ * // .env.local:
101
+ * // NEXT_PUBLIC_DEMOKIT_API_URL=https://demokit-cloud.kasava.dev/api
102
+ * // NEXT_PUBLIC_DEMOKIT_API_KEY=dk_live_xxxx
103
+ *
104
+ * export const demokitSource = createRemoteSource({
105
+ * apiUrl: process.env.NEXT_PUBLIC_DEMOKIT_API_URL!,
106
+ * apiKey: process.env.NEXT_PUBLIC_DEMOKIT_API_KEY!,
107
+ * })
108
+ *
109
+ * // Then in providers.tsx:
110
+ * import { demokitSource } from '@/lib/demokit-config'
111
+ *
112
+ * <DemoKitNextProvider source={demokitSource}>
113
+ * {children}
114
+ * </DemoKitNextProvider>
115
+ * ```
116
+ */
117
+ declare function createRemoteSource(config: RemoteSourceConfig): RemoteSourceConfig;
90
118
 
91
- export { DemoKitNextConfig, DemoScenario, createDemoConfig, createScenario, defineFixtures, defineScenarios, mergeFixtures };
119
+ export { DemoKitNextConfig, DemoScenario, RemoteSourceConfig, createDemoConfig, createRemoteSource, createScenario, defineFixtures, defineScenarios, mergeFixtures };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { FixtureMap } from '@demokit-ai/core';
2
2
  export { FixtureHandler, FixtureMap, RequestContext } from '@demokit-ai/core';
3
- import { D as DemoScenario, a as DemoKitNextConfig } from './types-Cvq5JUP1.js';
4
- export { d as DefineFixtures, e as DefineScenarios, b as DemoKitNextProviderProps, c as DemoMiddlewareConfig, M as MiddlewareResult } from './types-Cvq5JUP1.js';
3
+ import { D as DemoScenario, a as DemoKitNextConfig, R as RemoteSourceConfig } from './types-Brt8EaFz.js';
4
+ export { d as DefineFixtures, e as DefineScenarios, b as DemoKitNextProviderProps, c as DemoMiddlewareConfig, M as MiddlewareResult } from './types-Brt8EaFz.js';
5
5
  import 'react';
6
6
  import 'next/server';
7
7
 
@@ -87,5 +87,33 @@ declare function mergeFixtures(...fixtureMaps: FixtureMap[]): FixtureMap;
87
87
  * })
88
88
  */
89
89
  declare function createDemoConfig(config: DemoKitNextConfig): DemoKitNextConfig;
90
+ /**
91
+ * Create a remote source configuration for fetching fixtures from DemoKit Cloud
92
+ *
93
+ * The SDK appends `/fixtures` to your apiUrl, so provide the versioned base URL.
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * // lib/demokit-config.ts
98
+ * import { createRemoteSource } from '@demokit-ai/next'
99
+ *
100
+ * // .env.local:
101
+ * // NEXT_PUBLIC_DEMOKIT_API_URL=https://demokit-cloud.kasava.dev/api
102
+ * // NEXT_PUBLIC_DEMOKIT_API_KEY=dk_live_xxxx
103
+ *
104
+ * export const demokitSource = createRemoteSource({
105
+ * apiUrl: process.env.NEXT_PUBLIC_DEMOKIT_API_URL!,
106
+ * apiKey: process.env.NEXT_PUBLIC_DEMOKIT_API_KEY!,
107
+ * })
108
+ *
109
+ * // Then in providers.tsx:
110
+ * import { demokitSource } from '@/lib/demokit-config'
111
+ *
112
+ * <DemoKitNextProvider source={demokitSource}>
113
+ * {children}
114
+ * </DemoKitNextProvider>
115
+ * ```
116
+ */
117
+ declare function createRemoteSource(config: RemoteSourceConfig): RemoteSourceConfig;
90
118
 
91
- export { DemoKitNextConfig, DemoScenario, createDemoConfig, createScenario, defineFixtures, defineScenarios, mergeFixtures };
119
+ export { DemoKitNextConfig, DemoScenario, RemoteSourceConfig, createDemoConfig, createRemoteSource, createScenario, defineFixtures, defineScenarios, mergeFixtures };
package/dist/index.js CHANGED
@@ -19,7 +19,20 @@ function createDemoConfig(config) {
19
19
  ...config
20
20
  };
21
21
  }
22
-
23
- export { createDemoConfig, createScenario, defineFixtures, defineScenarios, mergeFixtures };
24
- //# sourceMappingURL=index.js.map
22
+ function createRemoteSource(config) {
23
+ return {
24
+ timeout: 1e4,
25
+ retry: true,
26
+ maxRetries: 3,
27
+ ...config
28
+ };
29
+ }
30
+ export {
31
+ createDemoConfig,
32
+ createRemoteSource,
33
+ createScenario,
34
+ defineFixtures,
35
+ defineScenarios,
36
+ mergeFixtures
37
+ };
25
38
  //# sourceMappingURL=index.js.map