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