@proveanything/smartlinks-auth-ui 0.3.1 → 0.3.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.esm.js CHANGED
@@ -14311,6 +14311,291 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14311
14311
  }, className: "auth-button button-secondary", children: "Cancel" })] })] }))] }))] }));
14312
14312
  };
14313
14313
 
14314
+ /**
14315
+ * Helper functions for SmartlinksFrame
14316
+ * Separated to avoid circular dependencies
14317
+ */
14318
+ /**
14319
+ * Compute admin status from collection/proof roles.
14320
+ */
14321
+ function isAdminFromRoles(user, collection, proof) {
14322
+ if (!user?.uid)
14323
+ return false;
14324
+ const proofRole = proof?.roles?.[user.uid];
14325
+ if (proofRole === 'admin' || proofRole === 'owner')
14326
+ return true;
14327
+ const collectionRole = collection?.roles?.[user.uid];
14328
+ if (collectionRole === 'admin' || collectionRole === 'owner')
14329
+ return true;
14330
+ return false;
14331
+ }
14332
+ /**
14333
+ * Build iframe src URL with query parameters.
14334
+ */
14335
+ function buildIframeSrc(baseUrl, params) {
14336
+ const url = new URL(baseUrl);
14337
+ Object.entries(params).forEach(([key, value]) => {
14338
+ if (value !== undefined) {
14339
+ url.searchParams.set(key, value);
14340
+ }
14341
+ });
14342
+ return url.toString();
14343
+ }
14344
+
14345
+ /**
14346
+ * SmartlinksFrame - React wrapper for embedding SmartLinks microapps.
14347
+ *
14348
+ * This component handles iframe creation and message passing for SmartLinks apps.
14349
+ * It requires only collectionId and appId - the SDK handles URL discovery and API proxying.
14350
+ *
14351
+ * @example
14352
+ * ```tsx
14353
+ * // Simple usage - SDK resolves app URL automatically
14354
+ * <SmartlinksFrame
14355
+ * collectionId="my-collection"
14356
+ * appId="warranty-app"
14357
+ * />
14358
+ *
14359
+ * // With optional product context
14360
+ * <SmartlinksFrame
14361
+ * collectionId="my-collection"
14362
+ * appId="warranty-app"
14363
+ * productId="product-123"
14364
+ * />
14365
+ * ```
14366
+ */
14367
+ const SmartlinksFrame = ({ collectionId, appId, productId, proofId, version = 'stable', collection, product: _product, // Destructured but currently unused - kept for cache optimization
14368
+ proof, initialPath, onRouteChange, autoResize = true, minHeight, maxHeight, onReady, onError, className, style, }) => {
14369
+ const iframeRef = useRef(null);
14370
+ const [src, setSrc] = useState(null);
14371
+ const [height, setHeight] = useState(minHeight || 400);
14372
+ const [error, setError] = useState(null);
14373
+ const [isLoading, setIsLoading] = useState(true);
14374
+ // Get auth context if available (optional - works without AuthProvider)
14375
+ const authContext = useContext(AuthContext);
14376
+ const user = authContext?.user ?? null;
14377
+ // Compute isAdmin from collection/proof roles
14378
+ const isAdmin = isAdminFromRoles(user ? { uid: user.uid } : null, collection, proof);
14379
+ // Handle messages from iframe
14380
+ const handleMessage = useCallback((event) => {
14381
+ const data = event.data;
14382
+ if (!data || typeof data !== 'object')
14383
+ return;
14384
+ // Handle resize messages
14385
+ if (data.type === 'smartlinks:resize' && autoResize) {
14386
+ let newHeight = data.payload?.height || data.height;
14387
+ if (typeof newHeight === 'number') {
14388
+ if (minHeight)
14389
+ newHeight = Math.max(newHeight, minHeight);
14390
+ if (maxHeight)
14391
+ newHeight = Math.min(newHeight, maxHeight);
14392
+ setHeight(newHeight);
14393
+ }
14394
+ }
14395
+ // Handle route change messages
14396
+ if (data.type === 'smartlinks-route-change' && onRouteChange) {
14397
+ onRouteChange(data.path || '/', data.state || {});
14398
+ }
14399
+ // Handle ready message
14400
+ if (data.type === 'smartlinks:ready') {
14401
+ setIsLoading(false);
14402
+ onReady?.();
14403
+ }
14404
+ }, [autoResize, minHeight, maxHeight, onRouteChange, onReady]);
14405
+ // Set up message listener
14406
+ useEffect(() => {
14407
+ window.addEventListener('message', handleMessage);
14408
+ return () => window.removeEventListener('message', handleMessage);
14409
+ }, [handleMessage]);
14410
+ // Resolve app URL and set iframe src
14411
+ useEffect(() => {
14412
+ setError(null);
14413
+ setIsLoading(true);
14414
+ setSrc(null);
14415
+ // Try to get app URL from collection apps config
14416
+ const resolveAppUrl = async () => {
14417
+ try {
14418
+ // Use SDK to get collection data which may include apps config
14419
+ const collectionData = await smartlinks.collection.get(collectionId);
14420
+ const collectionAsAny = collectionData;
14421
+ const apps = collectionAsAny.apps ?? [];
14422
+ const app = apps.find((a) => a.id === appId);
14423
+ if (!app?.url) {
14424
+ throw new Error(`App "${appId}" not found in collection "${collectionId}"`);
14425
+ }
14426
+ // Get the appropriate URL based on version
14427
+ let baseUrl = app.url;
14428
+ if (version === 'development' && app.versions?.development) {
14429
+ baseUrl = app.versions.development;
14430
+ }
14431
+ else if (version === 'stable' && app.versions?.stable) {
14432
+ baseUrl = app.versions.stable;
14433
+ }
14434
+ // Build iframe URL with context params
14435
+ const iframeSrc = buildIframeSrc(baseUrl, {
14436
+ collectionId,
14437
+ appId,
14438
+ productId,
14439
+ proofId,
14440
+ isAdmin: isAdmin ? '1' : '0',
14441
+ dark: document.documentElement.classList.contains('dark') ? '1' : '0',
14442
+ });
14443
+ // Add initial path if provided
14444
+ const finalSrc = initialPath
14445
+ ? `${iframeSrc}#${initialPath}`
14446
+ : iframeSrc;
14447
+ setSrc(finalSrc);
14448
+ setIsLoading(false);
14449
+ }
14450
+ catch (err) {
14451
+ const errorMsg = err instanceof Error ? err.message : 'Failed to resolve app URL';
14452
+ console.error('[SmartlinksFrame] Error:', errorMsg);
14453
+ setError(errorMsg);
14454
+ setIsLoading(false);
14455
+ onError?.(err instanceof Error ? err : new Error(errorMsg));
14456
+ }
14457
+ };
14458
+ resolveAppUrl();
14459
+ }, [collectionId, appId, productId, proofId, version, initialPath, isAdmin, onError]);
14460
+ // Calculate container style
14461
+ const containerStyle = {
14462
+ position: 'relative',
14463
+ height: autoResize ? `${height}px` : '100%',
14464
+ width: '100%',
14465
+ ...style,
14466
+ };
14467
+ return (jsxs("div", { className: className, style: containerStyle, children: [error && (jsxs("div", { style: {
14468
+ padding: '0.5rem 1rem',
14469
+ backgroundColor: '#fee2e2',
14470
+ color: '#dc2626',
14471
+ borderBottom: '1px solid #fecaca',
14472
+ fontSize: '0.875rem',
14473
+ }, children: ["Error: ", error] })), isLoading && !error && (jsx("div", { style: {
14474
+ display: 'flex',
14475
+ alignItems: 'center',
14476
+ justifyContent: 'center',
14477
+ height: '100%',
14478
+ minHeight: minHeight || 200,
14479
+ color: '#6b7280',
14480
+ }, children: "Loading..." })), src && (jsx("iframe", { ref: iframeRef, src: src, frameBorder: 0, width: "100%", height: "100%", allow: "camera;microphone;fullscreen;geolocation;identity-credentials-get", style: {
14481
+ display: isLoading ? 'none' : 'block',
14482
+ width: '100%',
14483
+ height: autoResize ? `${height}px` : '100%',
14484
+ border: 'none',
14485
+ } }))] }));
14486
+ };
14487
+
14488
+ /**
14489
+ * Hook to detect if the current user is an admin of the collection or proof.
14490
+ *
14491
+ * Admin status is determined by checking if the user's UID exists in the
14492
+ * `roles` object of either the collection or proof.
14493
+ *
14494
+ * @param collection - Collection object with optional roles
14495
+ * @param proof - Proof object with optional roles
14496
+ * @param user - Current authenticated user
14497
+ * @returns boolean indicating admin status
14498
+ */
14499
+ function useAdminDetection(collection, proof, user) {
14500
+ return useMemo(() => {
14501
+ if (!user?.uid)
14502
+ return false;
14503
+ // Check collection roles
14504
+ if (collection?.roles && collection.roles[user.uid]) {
14505
+ return true;
14506
+ }
14507
+ // Check proof roles (for proof-level admin)
14508
+ if (proof?.roles && proof.roles[user.uid]) {
14509
+ return true;
14510
+ }
14511
+ return false;
14512
+ }, [collection?.roles, proof?.roles, user?.uid]);
14513
+ }
14514
+
14515
+ /**
14516
+ * Hook to handle iframe height management.
14517
+ *
14518
+ * Supports two modes:
14519
+ * 1. Viewport-based: Calculates height based on iframe position and viewport
14520
+ * 2. Content-based: Listens for smartlinks:resize messages from the iframe
14521
+ *
14522
+ * @param iframeRef - Ref to the iframe element
14523
+ * @param options - Resize configuration options
14524
+ * @returns Current calculated height in pixels
14525
+ */
14526
+ function useIframeResize(iframeRef, options = {}) {
14527
+ const { autoResize = true, minHeight, maxHeight } = options;
14528
+ const [height, setHeight] = useState(0);
14529
+ // Calculate height based on viewport position
14530
+ const calculateHeight = useCallback(() => {
14531
+ const iframe = iframeRef.current;
14532
+ if (!iframe)
14533
+ return;
14534
+ const container = iframe.parentElement;
14535
+ if (!container)
14536
+ return;
14537
+ const rect = container.getBoundingClientRect();
14538
+ const viewportHeight = window.innerHeight;
14539
+ let calculatedHeight = Math.max(0, viewportHeight - rect.top);
14540
+ // Apply constraints
14541
+ if (minHeight !== undefined) {
14542
+ calculatedHeight = Math.max(calculatedHeight, minHeight);
14543
+ }
14544
+ if (maxHeight !== undefined) {
14545
+ calculatedHeight = Math.min(calculatedHeight, maxHeight);
14546
+ }
14547
+ setHeight(calculatedHeight);
14548
+ }, [minHeight, maxHeight, iframeRef]);
14549
+ // Handle viewport resize events
14550
+ useEffect(() => {
14551
+ if (!autoResize)
14552
+ return;
14553
+ // Initial calculation with multiple retries for late layout
14554
+ calculateHeight();
14555
+ const t1 = setTimeout(calculateHeight, 10);
14556
+ const t2 = setTimeout(calculateHeight, 100);
14557
+ const t3 = setTimeout(calculateHeight, 500);
14558
+ const handleResize = () => calculateHeight();
14559
+ window.addEventListener('resize', handleResize);
14560
+ window.addEventListener('orientationchange', handleResize);
14561
+ return () => {
14562
+ clearTimeout(t1);
14563
+ clearTimeout(t2);
14564
+ clearTimeout(t3);
14565
+ window.removeEventListener('resize', handleResize);
14566
+ window.removeEventListener('orientationchange', handleResize);
14567
+ };
14568
+ }, [autoResize, calculateHeight]);
14569
+ // Listen for content-based resize messages from iframe
14570
+ useEffect(() => {
14571
+ const handleMessage = (event) => {
14572
+ // Validate source is our iframe
14573
+ if (iframeRef.current && event.source !== iframeRef.current.contentWindow) {
14574
+ return;
14575
+ }
14576
+ const data = event.data;
14577
+ // Handle smartlinks:resize message
14578
+ if (data?._smartlinksIframeMessage && data?.type === 'smartlinks:resize') {
14579
+ const contentHeight = data.payload?.height;
14580
+ if (typeof contentHeight === 'number' && contentHeight > 0) {
14581
+ let newHeight = contentHeight;
14582
+ // Apply constraints
14583
+ if (minHeight !== undefined) {
14584
+ newHeight = Math.max(newHeight, minHeight);
14585
+ }
14586
+ if (maxHeight !== undefined) {
14587
+ newHeight = Math.min(newHeight, maxHeight);
14588
+ }
14589
+ setHeight(newHeight);
14590
+ }
14591
+ }
14592
+ };
14593
+ window.addEventListener('message', handleMessage);
14594
+ return () => window.removeEventListener('message', handleMessage);
14595
+ }, [iframeRef, minHeight, maxHeight]);
14596
+ return height;
14597
+ }
14598
+
14314
14599
  // Re-import the constant since we can't import from types
14315
14600
  const KNOWN_PARAMS = new Set([
14316
14601
  'collectionId',
@@ -14381,12 +14666,12 @@ function useIframeMessages(iframeRef, options) {
14381
14666
  // Filter out known iframe params, keep only app-specific state
14382
14667
  const filteredState = {};
14383
14668
  Object.entries(context).forEach(([key, value]) => {
14384
- if (value != null && !KNOWN_PARAMS.has(key)) {
14669
+ if (value != null && !KNOWN_PARAMS.has(key) && typeof value === 'string') {
14385
14670
  filteredState[key] = value;
14386
14671
  }
14387
14672
  });
14388
14673
  Object.entries(state).forEach(([key, value]) => {
14389
- if (value != null && !KNOWN_PARAMS.has(key)) {
14674
+ if (value != null && !KNOWN_PARAMS.has(key) && typeof value === 'string') {
14390
14675
  filteredState[key] = value;
14391
14676
  }
14392
14677
  });
@@ -14402,7 +14687,7 @@ function useIframeMessages(iframeRef, options) {
14402
14687
  if ('_smartlinksCustomProxyRequest' in data && data._smartlinksCustomProxyRequest) {
14403
14688
  if (data.request === 'REDIRECT') {
14404
14689
  const url = data.params?.url;
14405
- if (url) {
14690
+ if (typeof url === 'string') {
14406
14691
  window.location.href = url;
14407
14692
  }
14408
14693
  response.data = { success: true };
@@ -14524,9 +14809,20 @@ function useIframeMessages(iframeRef, options) {
14524
14809
  try {
14525
14810
  // Validate token using SDK
14526
14811
  console.log('[SmartlinksFrame] Validating auth token...');
14527
- await smartlinks.auth.verifyToken(token);
14812
+ if (typeof token === 'string') {
14813
+ await smartlinks.auth.verifyToken(token);
14814
+ }
14815
+ // Cast user to expected shape
14816
+ const userPayload = iframeUser;
14817
+ // Validate user object has required properties
14818
+ const authUser = {
14819
+ uid: userPayload?.uid || '',
14820
+ email: userPayload?.email,
14821
+ displayName: userPayload?.displayName,
14822
+ accountData: accountData || userPayload?.accountData,
14823
+ };
14528
14824
  // Use AuthProvider's login to persist session
14529
- await loginRef.current(token, iframeUser, accountData);
14825
+ await loginRef.current(token, authUser, accountData);
14530
14826
  // Send acknowledgment
14531
14827
  sendResponse(event.source, event.origin, {
14532
14828
  type: 'smartlinks:authkit:login-acknowledged',
@@ -14682,257 +14978,6 @@ function useIframeMessages(iframeRef, options) {
14682
14978
  }, [iframeRef, handleRouteChange, handleStandardMessage, handleUpload, handleProxyRequest]);
14683
14979
  }
14684
14980
 
14685
- /**
14686
- * Hook to handle iframe height management.
14687
- *
14688
- * Supports two modes:
14689
- * 1. Viewport-based: Calculates height based on iframe position and viewport
14690
- * 2. Content-based: Listens for smartlinks:resize messages from the iframe
14691
- *
14692
- * @param iframeRef - Ref to the iframe element
14693
- * @param options - Resize configuration options
14694
- * @returns Current calculated height in pixels
14695
- */
14696
- function useIframeResize(iframeRef, options = {}) {
14697
- const { autoResize = true, minHeight, maxHeight } = options;
14698
- const [height, setHeight] = useState(0);
14699
- // Calculate height based on viewport position
14700
- const calculateHeight = useCallback(() => {
14701
- const iframe = iframeRef.current;
14702
- if (!iframe)
14703
- return;
14704
- const container = iframe.parentElement;
14705
- if (!container)
14706
- return;
14707
- const rect = container.getBoundingClientRect();
14708
- const viewportHeight = window.innerHeight;
14709
- let calculatedHeight = Math.max(0, viewportHeight - rect.top);
14710
- // Apply constraints
14711
- if (minHeight !== undefined) {
14712
- calculatedHeight = Math.max(calculatedHeight, minHeight);
14713
- }
14714
- if (maxHeight !== undefined) {
14715
- calculatedHeight = Math.min(calculatedHeight, maxHeight);
14716
- }
14717
- setHeight(calculatedHeight);
14718
- }, [minHeight, maxHeight, iframeRef]);
14719
- // Handle viewport resize events
14720
- useEffect(() => {
14721
- if (!autoResize)
14722
- return;
14723
- // Initial calculation with multiple retries for late layout
14724
- calculateHeight();
14725
- const t1 = setTimeout(calculateHeight, 10);
14726
- const t2 = setTimeout(calculateHeight, 100);
14727
- const t3 = setTimeout(calculateHeight, 500);
14728
- const handleResize = () => calculateHeight();
14729
- window.addEventListener('resize', handleResize);
14730
- window.addEventListener('orientationchange', handleResize);
14731
- return () => {
14732
- clearTimeout(t1);
14733
- clearTimeout(t2);
14734
- clearTimeout(t3);
14735
- window.removeEventListener('resize', handleResize);
14736
- window.removeEventListener('orientationchange', handleResize);
14737
- };
14738
- }, [autoResize, calculateHeight]);
14739
- // Listen for content-based resize messages from iframe
14740
- useEffect(() => {
14741
- const handleMessage = (event) => {
14742
- // Validate source is our iframe
14743
- if (iframeRef.current && event.source !== iframeRef.current.contentWindow) {
14744
- return;
14745
- }
14746
- const data = event.data;
14747
- // Handle smartlinks:resize message
14748
- if (data?._smartlinksIframeMessage && data?.type === 'smartlinks:resize') {
14749
- const contentHeight = data.payload?.height;
14750
- if (typeof contentHeight === 'number' && contentHeight > 0) {
14751
- let newHeight = contentHeight;
14752
- // Apply constraints
14753
- if (minHeight !== undefined) {
14754
- newHeight = Math.max(newHeight, minHeight);
14755
- }
14756
- if (maxHeight !== undefined) {
14757
- newHeight = Math.min(newHeight, maxHeight);
14758
- }
14759
- setHeight(newHeight);
14760
- }
14761
- }
14762
- };
14763
- window.addEventListener('message', handleMessage);
14764
- return () => window.removeEventListener('message', handleMessage);
14765
- }, [iframeRef, minHeight, maxHeight]);
14766
- return height;
14767
- }
14768
-
14769
- /**
14770
- * Hook to detect if the current user is an admin of the collection or proof.
14771
- *
14772
- * Admin status is determined by checking if the user's UID exists in the
14773
- * `roles` object of either the collection or proof.
14774
- *
14775
- * @param collection - Collection object with optional roles
14776
- * @param proof - Proof object with optional roles
14777
- * @param user - Current authenticated user
14778
- * @returns boolean indicating admin status
14779
- */
14780
- function useAdminDetection(collection, proof, user) {
14781
- return useMemo(() => {
14782
- if (!user?.uid)
14783
- return false;
14784
- // Check collection roles
14785
- if (collection?.roles && collection.roles[user.uid]) {
14786
- return true;
14787
- }
14788
- // Check proof roles (for proof-level admin)
14789
- if (proof?.roles && proof.roles[user.uid]) {
14790
- return true;
14791
- }
14792
- return false;
14793
- }, [collection?.roles, proof?.roles, user?.uid]);
14794
- }
14795
-
14796
- /**
14797
- * SmartlinksFrame - Parent-side iframe wrapper for embedding SmartLinks microapps.
14798
- *
14799
- * This component handles all bidirectional communication with the embedded iframe:
14800
- * - API proxy requests (with optional caching)
14801
- * - Authentication state synchronization (when inside AuthProvider)
14802
- * - Deep linking / route changes
14803
- * - Resize management
14804
- * - File upload proxying
14805
- *
14806
- * Can be used with or without AuthProvider - authentication is optional.
14807
- *
14808
- * @example
14809
- * ```tsx
14810
- * // With authentication
14811
- * <AuthProvider collectionId="my-collection">
14812
- * <SmartlinksFrame
14813
- * collectionId="my-collection"
14814
- * appId="warranty-app"
14815
- * appUrl="https://warranty.lovable.app"
14816
- * collection={collectionData}
14817
- * />
14818
- * </AuthProvider>
14819
- *
14820
- * // Without authentication (public/anonymous access)
14821
- * <SmartlinksFrame
14822
- * collectionId="my-collection"
14823
- * appId="info-app"
14824
- * appUrl="https://info-app.lovable.app"
14825
- * />
14826
- * ```
14827
- */
14828
- const SmartlinksFrame = ({ collectionId, appId, productId, proofId, appUrl, version = 'stable', collection, product, proof, initialPath, onRouteChange, autoResize = true, minHeight, maxHeight, onReady, onError, className, style, }) => {
14829
- const iframeRef = useRef(null);
14830
- // Get auth context if available (optional - SmartlinksFrame works without AuthProvider)
14831
- const authContext = useContext(AuthContext);
14832
- const user = authContext?.user ?? null;
14833
- const login = authContext?.login;
14834
- const logout = authContext?.logout;
14835
- // Compute isAdmin from collection/proof roles
14836
- const isAdmin = useAdminDetection(collection, proof, user);
14837
- // Handle resize
14838
- const height = useIframeResize(iframeRef, { autoResize, minHeight, maxHeight });
14839
- // Handle all iframe messages
14840
- useIframeMessages(iframeRef, {
14841
- collectionId,
14842
- productId,
14843
- proofId,
14844
- cachedData: { collection, product, proof, user },
14845
- login,
14846
- logout,
14847
- onRouteChange,
14848
- onError,
14849
- });
14850
- // Build iframe URL with all context params
14851
- const frameSrc = useMemo(() => {
14852
- const params = new URLSearchParams();
14853
- // Required context
14854
- params.set('collectionId', collectionId);
14855
- params.set('appId', appId);
14856
- // Optional context
14857
- if (productId)
14858
- params.set('productId', productId);
14859
- if (proofId)
14860
- params.set('proofId', proofId);
14861
- if (isAdmin)
14862
- params.set('isAdmin', 'true');
14863
- // Dark mode from collection
14864
- const isDark = collection?.dark ?? false;
14865
- params.set('dark', isDark ? '1' : '0');
14866
- // Include parent URL for downstream redirects/context
14867
- try {
14868
- params.set('parentUrl', window.location.href);
14869
- }
14870
- catch {
14871
- // Ignore if can't access location
14872
- }
14873
- // Encode theme from collection if available
14874
- if (collection) {
14875
- try {
14876
- const themeData = {
14877
- p: collection.primaryColor,
14878
- s: collection.secondaryColor,
14879
- m: collection.dark ? 'd' : 'l',
14880
- };
14881
- // Only include if we have meaningful data
14882
- if (themeData.p || themeData.s) {
14883
- params.set('theme', btoa(JSON.stringify(themeData)));
14884
- }
14885
- }
14886
- catch {
14887
- // Ignore encoding errors
14888
- }
14889
- }
14890
- // Determine base URL
14891
- let base = appUrl;
14892
- // If appUrl doesn't look like a full URL, construct from smartlinks.app
14893
- if (!appUrl.startsWith('http')) {
14894
- base = `https://smartlinks.app/apps/${appId}/${version}`;
14895
- }
14896
- // Clean up base URL
14897
- base = base.replace(/#\/?$/, ''); // Remove trailing hash
14898
- if (base.endsWith('/')) {
14899
- base = base.slice(0, -1);
14900
- }
14901
- // Build hash path
14902
- let hashPath = initialPath || '';
14903
- if (hashPath && !hashPath.startsWith('/')) {
14904
- hashPath = '/' + hashPath;
14905
- }
14906
- if (hashPath === '/') {
14907
- hashPath = '';
14908
- }
14909
- // Construct final URL: base#/path?params
14910
- return `${base}/#/${hashPath}?${params.toString()}`.replace('/#//', '/#/');
14911
- }, [
14912
- collectionId,
14913
- appId,
14914
- productId,
14915
- proofId,
14916
- appUrl,
14917
- version,
14918
- initialPath,
14919
- isAdmin,
14920
- collection,
14921
- ]);
14922
- // Calculate container style
14923
- const containerStyle = {
14924
- height: autoResize && height > 0 ? `${height}px` : '100%',
14925
- width: '100%',
14926
- ...style,
14927
- };
14928
- return (jsx("div", { className: className, style: containerStyle, children: jsx("iframe", { ref: iframeRef, src: frameSrc, frameBorder: 0, width: "100%", height: "100%", allow: "camera;microphone;fullscreen;geolocation;identity-credentials-get", onLoad: onReady, style: {
14929
- display: 'block',
14930
- width: '100%',
14931
- height: '100%',
14932
- border: 0,
14933
- } }) }));
14934
- };
14935
-
14936
14981
  const ProtectedRoute = ({ children, fallback, redirectTo, }) => {
14937
14982
  const { isAuthenticated, isLoading } = useAuth();
14938
14983
  // Show loading state
@@ -15003,5 +15048,5 @@ async function setDefaultAuthKitId(collectionId, authKitId) {
15003
15048
  });
15004
15049
  }
15005
15050
 
15006
- export { AccountManagement, AuthProvider, AuthUIPreview, SmartlinksAuthUI as FirebaseAuthUI, ProtectedRoute, SchemaFieldRenderer, SmartlinksAuthUI, SmartlinksFrame, getDefaultAuthKitId, getEditableFields, getErrorCode, getErrorStatusCode, getFriendlyErrorMessage, getRegistrationFields, isAuthError, isConflictError, isRateLimitError, isServerError, setDefaultAuthKitId, sortFieldsByPlacement, tokenStorage, useAdminDetection, useAuth, useIframeMessages, useIframeResize };
15051
+ export { AccountManagement, AuthProvider, AuthUIPreview, SmartlinksAuthUI as FirebaseAuthUI, ProtectedRoute, SchemaFieldRenderer, SmartlinksAuthUI, SmartlinksFrame, buildIframeSrc, getDefaultAuthKitId, getEditableFields, getErrorCode, getErrorStatusCode, getFriendlyErrorMessage, getRegistrationFields, isAdminFromRoles, isAuthError, isConflictError, isRateLimitError, isServerError, setDefaultAuthKitId, sortFieldsByPlacement, tokenStorage, useAdminDetection, useAuth, useIframeMessages, useIframeResize };
15007
15052
  //# sourceMappingURL=index.esm.js.map