@keak/sdk 2.2.1 โ†’ 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -2359,6 +2359,117 @@ function detectVariantElements(children) {
2359
2359
  // Cache for memoized snapshot objects to prevent infinite re-renders
2360
2360
  // Key format: "ready-isDesktopProject" โ†’ e.g., "true-false"
2361
2361
  const snapshotCache = new Map();
2362
+ // KeakLoader Component - Page-level middleware that waits for embedded script
2363
+ // Wrap your app/page with this to prevent rendering until variant assignments are ready
2364
+ const KeakLoader = ({ children }) => {
2365
+ console.log(`[Keak SDK] ๐Ÿ”ต KeakLoader rendering started`);
2366
+ const embeddedScriptStatus = React.useSyncExternalStore(
2367
+ // subscribe - called when component mounts
2368
+ (callback) => {
2369
+ console.log(`[Keak SDK] ๐Ÿ“ก KeakLoader subscribe called`);
2370
+ if (typeof window === 'undefined') {
2371
+ return () => { };
2372
+ }
2373
+ // Check if already ready
2374
+ const embeddedData = window.KEAK_EMBEDDED_DATA;
2375
+ const isDesktopProject = !!(embeddedData && embeddedData.projectUuid);
2376
+ const hasComputeFunction = typeof window.KeakAssign?.computeAssignments === 'function';
2377
+ // If not a desktop project AND embedded data exists, no need to wait
2378
+ if (embeddedData && !isDesktopProject) {
2379
+ console.log(`[Keak SDK] โœ… KeakLoader: Not a desktop project - no waiting needed`);
2380
+ return () => { };
2381
+ }
2382
+ // If desktop project and already has compute function, ready immediately
2383
+ if (isDesktopProject && hasComputeFunction) {
2384
+ console.log(`[Keak SDK] โœ… KeakLoader: Embedded script already ready`);
2385
+ return () => { };
2386
+ }
2387
+ // Poll for embedded script to load with shorter timeout (300ms max)
2388
+ console.log(`[Keak SDK] โณ KeakLoader: Starting polling...`);
2389
+ let attempts = 0;
2390
+ const maxAttempts = 10; // 10 * 30ms = 300ms max
2391
+ const pollInterval = setInterval(() => {
2392
+ attempts++;
2393
+ console.log(`[Keak SDK] ๐Ÿ”„ KeakLoader poll attempt ${attempts}/${maxAttempts}`);
2394
+ const currentData = window.KEAK_EMBEDDED_DATA;
2395
+ const currentIsDesktop = !!(currentData && currentData.projectUuid);
2396
+ const currentHasFunc = typeof window.KeakAssign?.computeAssignments === 'function';
2397
+ // If embedded data appears with projectUuid AND compute function is ready
2398
+ if (currentIsDesktop && currentHasFunc) {
2399
+ console.log(`[Keak SDK] โœ… KeakLoader: Desktop project script ready after ${attempts} attempts`);
2400
+ clearInterval(pollInterval);
2401
+ callback(); // Notify React of change
2402
+ }
2403
+ // If embedded data appears but has NO projectUuid (confirmed not a desktop project)
2404
+ else if (currentData && !currentIsDesktop) {
2405
+ console.log(`[Keak SDK] โœ… KeakLoader: Confirmed not a desktop project after ${attempts} attempts`);
2406
+ clearInterval(pollInterval);
2407
+ callback(); // Notify React of change
2408
+ }
2409
+ // Timeout - proceed anyway
2410
+ else if (attempts >= maxAttempts) {
2411
+ console.warn(`[Keak SDK] โฐ KeakLoader: Timeout after 300ms - proceeding anyway`);
2412
+ clearInterval(pollInterval);
2413
+ callback(); // Notify React of change
2414
+ }
2415
+ }, 30); // 30ms interval for faster checks
2416
+ return () => {
2417
+ console.log(`[Keak SDK] ๐Ÿงน KeakLoader cleanup interval`);
2418
+ clearInterval(pollInterval);
2419
+ };
2420
+ },
2421
+ // getSnapshot - called synchronously during render
2422
+ () => {
2423
+ if (typeof window === 'undefined') {
2424
+ const cacheKey = 'true-false';
2425
+ if (!snapshotCache.has(cacheKey)) {
2426
+ snapshotCache.set(cacheKey, { ready: true, isDesktopProject: false });
2427
+ }
2428
+ return snapshotCache.get(cacheKey);
2429
+ }
2430
+ const embeddedData = window.KEAK_EMBEDDED_DATA;
2431
+ const isDesktopProject = !!(embeddedData && embeddedData.projectUuid);
2432
+ const hasComputeFunction = typeof window.KeakAssign?.computeAssignments === 'function';
2433
+ const ready = !isDesktopProject || hasComputeFunction;
2434
+ // Create cache key from the actual values
2435
+ const cacheKey = `${ready}-${isDesktopProject}`;
2436
+ // Return cached snapshot if it exists
2437
+ if (!snapshotCache.has(cacheKey)) {
2438
+ console.log(`[Keak SDK] ๐Ÿ“ธ KeakLoader getSnapshot - Creating new cached snapshot:`, { ready, isDesktopProject });
2439
+ snapshotCache.set(cacheKey, { ready, isDesktopProject });
2440
+ }
2441
+ return snapshotCache.get(cacheKey);
2442
+ },
2443
+ // getServerSnapshot - for SSR
2444
+ () => {
2445
+ if (typeof window === 'undefined') {
2446
+ const cacheKey = 'true-false';
2447
+ if (!snapshotCache.has(cacheKey)) {
2448
+ snapshotCache.set(cacheKey, { ready: true, isDesktopProject: false });
2449
+ }
2450
+ return snapshotCache.get(cacheKey);
2451
+ }
2452
+ // Browser environment - check for embedded data
2453
+ const embeddedData = window.KEAK_EMBEDDED_DATA;
2454
+ const isDesktopProject = !!(embeddedData && embeddedData.projectUuid);
2455
+ const hasComputeFunction = typeof window.KeakAssign?.computeAssignments === 'function';
2456
+ const ready = !isDesktopProject || hasComputeFunction;
2457
+ const cacheKey = `${ready}-${isDesktopProject}`;
2458
+ if (!snapshotCache.has(cacheKey)) {
2459
+ console.log(`[Keak SDK] ๐ŸŒ KeakLoader getServerSnapshot - Creating new cached snapshot:`, { ready, isDesktopProject });
2460
+ snapshotCache.set(cacheKey, { ready, isDesktopProject });
2461
+ }
2462
+ return snapshotCache.get(cacheKey);
2463
+ });
2464
+ console.log(`[Keak SDK] ๐Ÿ” KeakLoader status:`, embeddedScriptStatus);
2465
+ // BLOCKING: Don't render anything until embedded data is ready (for desktop projects)
2466
+ if (embeddedScriptStatus.isDesktopProject && !embeddedScriptStatus.ready) {
2467
+ console.log(`[Keak SDK] ๐Ÿšซ KeakLoader blocking page render - waiting for embedded script`);
2468
+ return null;
2469
+ }
2470
+ console.log(`[Keak SDK] โœ… KeakLoader proceeding with render`);
2471
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: children });
2472
+ };
2362
2473
  // Experiment Component
2363
2474
  const Experiment = ({ name, children, active = true }) => {
2364
2475
  // CRITICAL: For Keak Code desktop projects, wait for embedded script to load
@@ -2371,19 +2482,21 @@ const Experiment = ({ name, children, active = true }) => {
2371
2482
  if (typeof window === 'undefined') {
2372
2483
  return () => { };
2373
2484
  }
2374
- // If already ready, no need to poll
2485
+ // Check if already ready
2375
2486
  const embeddedData = window.KEAK_EMBEDDED_DATA;
2376
- if (!embeddedData || !embeddedData.projectUuid) {
2377
- // Not a desktop project - no waiting needed
2487
+ const isDesktopProject = !!(embeddedData && embeddedData.projectUuid);
2488
+ const hasComputeFunction = typeof window.KeakAssign?.computeAssignments === 'function';
2489
+ // If not a desktop project AND embedded data exists, no need to wait
2490
+ if (embeddedData && !isDesktopProject) {
2378
2491
  console.log(`[Keak SDK] โœ… Not a desktop project for "${name}" - no waiting needed`);
2379
2492
  return () => { };
2380
2493
  }
2381
- if (typeof window.KeakAssign?.computeAssignments === 'function') {
2382
- // Already ready
2494
+ // If desktop project and already has compute function, ready immediately
2495
+ if (isDesktopProject && hasComputeFunction) {
2383
2496
  console.log(`[Keak SDK] โœ… Embedded script already ready for "${name}"`);
2384
2497
  return () => { };
2385
2498
  }
2386
- // Desktop project but script not ready - poll with timeout
2499
+ // Poll for embedded script to load (either waiting for KEAK_EMBEDDED_DATA or computeAssignments)
2387
2500
  console.log(`[Keak SDK] โณ Starting polling for "${name}"...`);
2388
2501
  let attempts = 0;
2389
2502
  const maxAttempts = 10; // 500ms max
@@ -2391,12 +2504,21 @@ const Experiment = ({ name, children, active = true }) => {
2391
2504
  attempts++;
2392
2505
  console.log(`[Keak SDK] ๐Ÿ”„ Poll attempt ${attempts}/${maxAttempts} for "${name}"`);
2393
2506
  const currentData = window.KEAK_EMBEDDED_DATA;
2394
- const hasFunc = typeof window.KeakAssign?.computeAssignments === 'function';
2395
- if (currentData && hasFunc) {
2396
- console.log(`[Keak SDK] โœ… Script ready after ${attempts} attempts for "${name}"`);
2507
+ const currentIsDesktop = !!(currentData && currentData.projectUuid);
2508
+ const currentHasFunc = typeof window.KeakAssign?.computeAssignments === 'function';
2509
+ // If embedded data appears with projectUuid AND compute function is ready
2510
+ if (currentIsDesktop && currentHasFunc) {
2511
+ console.log(`[Keak SDK] โœ… Desktop project script ready after ${attempts} attempts for "${name}"`);
2512
+ clearInterval(pollInterval);
2513
+ callback(); // Notify React of change
2514
+ }
2515
+ // If embedded data appears but has NO projectUuid (confirmed not a desktop project)
2516
+ else if (currentData && !currentIsDesktop) {
2517
+ console.log(`[Keak SDK] โœ… Confirmed not a desktop project after ${attempts} attempts for "${name}"`);
2397
2518
  clearInterval(pollInterval);
2398
2519
  callback(); // Notify React of change
2399
2520
  }
2521
+ // Timeout - proceed anyway
2400
2522
  else if (attempts >= maxAttempts) {
2401
2523
  console.warn(`[Keak SDK] โฐ Timeout after ${maxAttempts} attempts for "${name}" - proceeding anyway`);
2402
2524
  clearInterval(pollInterval);
@@ -2776,6 +2898,7 @@ function initializeToolbar(config) {
2776
2898
 
2777
2899
  exports.Conversion = Conversion;
2778
2900
  exports.Experiment = Experiment;
2901
+ exports.KeakLoader = KeakLoader;
2779
2902
  exports.KeakToolbar = KeakToolbar;
2780
2903
  exports.Variant = Variant;
2781
2904
  exports.buildSourcePathInjection = buildSourcePathInjection;