@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.
- package/LICENSE +190 -0
- package/dist/chunk-YLBNVWMI.js +109 -0
- package/dist/chunk-YLBNVWMI.js.map +1 -0
- package/dist/client.cjs +161 -55
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +8 -3
- package/dist/client.d.ts +8 -3
- package/dist/client.js +115 -20
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +47 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -3
- package/dist/index.d.ts +31 -3
- package/dist/index.js +16 -3
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +40 -13
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.cts +1 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +11 -104
- package/dist/middleware.js.map +1 -1
- package/dist/server.cjs +62 -24
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +24 -104
- package/dist/server.js.map +1 -1
- package/dist/{types-Cvq5JUP1.d.cts → types-Brt8EaFz.d.cts} +38 -1
- package/dist/{types-Cvq5JUP1.d.ts → types-Brt8EaFz.d.ts} +38 -1
- package/package.json +23 -36
- package/README.md +0 -193
package/dist/client.cjs.map
CHANGED
|
@@ -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-
|
|
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():
|
|
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-
|
|
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():
|
|
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
|
-
|
|
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
|
-
|
|
105
|
+
result = { ...result, ...scenarios[scenario] };
|
|
43
106
|
}
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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__ */
|
|
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
|
-
|
|
127
|
-
|
|
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
|
package/dist/client.js.map
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/
|
|
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-
|
|
4
|
-
export { d as DefineFixtures, e as DefineScenarios, b as DemoKitNextProviderProps, c as DemoMiddlewareConfig, M as MiddlewareResult } from './types-
|
|
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-
|
|
4
|
-
export { d as DefineFixtures, e as DefineScenarios, b as DemoKitNextProviderProps, c as DemoMiddlewareConfig, M as MiddlewareResult } from './types-
|
|
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
|
-
|
|
24
|
-
|
|
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
|