@fluid-app/portal-sdk 0.1.702 → 0.1.703

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.
Files changed (53) hide show
  1. package/dist/{EmbedWidget-CREvR9bi.cjs → EmbedWidget-K8DXyQW9.cjs} +1 -1
  2. package/dist/{EmbedWidget-BN2NzUFb.cjs → EmbedWidget-N7gbpIsk.cjs} +3 -2
  3. package/dist/EmbedWidget-N7gbpIsk.cjs.map +1 -0
  4. package/dist/{EmbedWidget-HcePfAaJ.mjs → EmbedWidget-sFKQDIP2.mjs} +3 -2
  5. package/dist/EmbedWidget-sFKQDIP2.mjs.map +1 -0
  6. package/dist/{FluidProvider-DzDVN81i.cjs → FluidProvider-D5SBAVxZ.cjs} +3 -3
  7. package/dist/{FluidProvider-DzDVN81i.cjs.map → FluidProvider-D5SBAVxZ.cjs.map} +1 -1
  8. package/dist/{FluidProvider-C-LKXW12.mjs → FluidProvider-UjEVLcb-.mjs} +3 -3
  9. package/dist/{FluidProvider-C-LKXW12.mjs.map → FluidProvider-UjEVLcb-.mjs.map} +1 -1
  10. package/dist/{MessagingScreen-CvcuHnq2.mjs → MessagingScreen-BwaiU8I-.mjs} +4 -4
  11. package/dist/{MessagingScreen-CcSOWCPv.cjs → MessagingScreen-C99KM-A3.cjs} +4 -4
  12. package/dist/{MessagingScreen-B40A2W1_.mjs → MessagingScreen-DcXPirhF.mjs} +2 -2
  13. package/dist/{MessagingScreen-B40A2W1_.mjs.map → MessagingScreen-DcXPirhF.mjs.map} +1 -1
  14. package/dist/{MessagingScreen-BFn7qMah.cjs → MessagingScreen-ldoQD8ac.cjs} +2 -2
  15. package/dist/{MessagingScreen-BFn7qMah.cjs.map → MessagingScreen-ldoQD8ac.cjs.map} +1 -1
  16. package/dist/{OrdersScreen-BL6B3tJa.cjs → OrdersScreen-BMzCmWDW.cjs} +4 -4
  17. package/dist/{OrdersScreen-D9t3iv3F.mjs → OrdersScreen-BcgLbHiG.mjs} +4 -4
  18. package/dist/{OrdersScreen-B8FzkqSR.mjs → OrdersScreen-CvmYNngV.mjs} +3 -3
  19. package/dist/{OrdersScreen-B8FzkqSR.mjs.map → OrdersScreen-CvmYNngV.mjs.map} +1 -1
  20. package/dist/{OrdersScreen-PyDEy-yZ.cjs → OrdersScreen-KmH4WsUH.cjs} +3 -3
  21. package/dist/{OrdersScreen-PyDEy-yZ.cjs.map → OrdersScreen-KmH4WsUH.cjs.map} +1 -1
  22. package/dist/{ProfileScreen-CSPBjkf6.mjs → ProfileScreen-B1VI3mOv.mjs} +5 -5
  23. package/dist/{ProfileScreen-DMpZ_-iR.cjs → ProfileScreen-B7PcofoC.cjs} +3 -3
  24. package/dist/{ProfileScreen-DMpZ_-iR.cjs.map → ProfileScreen-B7PcofoC.cjs.map} +1 -1
  25. package/dist/{ProfileScreen-CF4kkcBY.cjs → ProfileScreen-CZhxhc1k.cjs} +5 -5
  26. package/dist/{ProfileScreen-DNSP8_ro.mjs → ProfileScreen-FJkGR9ju.mjs} +3 -3
  27. package/dist/{ProfileScreen-DNSP8_ro.mjs.map → ProfileScreen-FJkGR9ju.mjs.map} +1 -1
  28. package/dist/{SubscriptionsScreen-ItqG6s33.mjs → SubscriptionsScreen--HqR8rTw.mjs} +4 -4
  29. package/dist/{SubscriptionsScreen-ItqG6s33.mjs.map → SubscriptionsScreen--HqR8rTw.mjs.map} +1 -1
  30. package/dist/{SubscriptionsScreen-DYSMji9L.mjs → SubscriptionsScreen-Cmd62x7H.mjs} +5 -5
  31. package/dist/{SubscriptionsScreen-CIkibUgF.cjs → SubscriptionsScreen-CpczYDXh.cjs} +5 -5
  32. package/dist/{SubscriptionsScreen-Bpn0T_T-.cjs → SubscriptionsScreen-Vb_Dq0xL.cjs} +4 -4
  33. package/dist/{SubscriptionsScreen-Bpn0T_T-.cjs.map → SubscriptionsScreen-Vb_Dq0xL.cjs.map} +1 -1
  34. package/dist/{build-widget-registry-DA8EVXi6.mjs → build-widget-registry-B7NQLCeT.mjs} +3 -3
  35. package/dist/{build-widget-registry-DA8EVXi6.mjs.map → build-widget-registry-B7NQLCeT.mjs.map} +1 -1
  36. package/dist/{build-widget-registry-DGA6LUJ8.cjs → build-widget-registry-Cg-eGUbu.cjs} +3 -3
  37. package/dist/{build-widget-registry-DGA6LUJ8.cjs.map → build-widget-registry-Cg-eGUbu.cjs.map} +1 -1
  38. package/dist/index.cjs +16 -16
  39. package/dist/index.d.cts.map +1 -1
  40. package/dist/index.d.mts.map +1 -1
  41. package/dist/index.mjs +16 -16
  42. package/dist/styles/remote-widget-shadow.css +2 -2
  43. package/dist/{use-portal-card-add-3ds-flow-XZalgZ3f.mjs → use-portal-card-add-3ds-flow-BxoozcEQ.mjs} +3 -3
  44. package/dist/{use-portal-card-add-3ds-flow-XZalgZ3f.mjs.map → use-portal-card-add-3ds-flow-BxoozcEQ.mjs.map} +1 -1
  45. package/dist/{use-portal-card-add-3ds-flow-6I7sugpw.cjs → use-portal-card-add-3ds-flow-CF-LpQwR.cjs} +3 -3
  46. package/dist/{use-portal-card-add-3ds-flow-6I7sugpw.cjs.map → use-portal-card-add-3ds-flow-CF-LpQwR.cjs.map} +1 -1
  47. package/dist/utils/build-remote-widget-plugin-manifests.cjs +2 -2
  48. package/dist/utils/build-remote-widget-plugin-manifests.mjs +2 -2
  49. package/dist/utils/build-widget-registry.cjs +2 -2
  50. package/dist/utils/build-widget-registry.mjs +2 -2
  51. package/package.json +1 -1
  52. package/dist/EmbedWidget-BN2NzUFb.cjs.map +0 -1
  53. package/dist/EmbedWidget-HcePfAaJ.mjs.map +0 -1
@@ -4,7 +4,7 @@ require("./RepUserContext-DNaWZklF.cjs");
4
4
  require("./WidgetRenderStateContext-CXln9BOZ.cjs");
5
5
  require("./translation-api-context-factory-DBglTwgf.cjs");
6
6
  require("./shell-translation-api-context-HMGFSW56.cjs");
7
- const require_EmbedWidget = require("./EmbedWidget-BN2NzUFb.cjs");
7
+ const require_EmbedWidget = require("./EmbedWidget-N7gbpIsk.cjs");
8
8
  require("./registries-C-rw-ddG.cjs");
9
9
  require("./fields-Wyz1XW-8.cjs");
10
10
  exports.embedWidgetPropertySchema = require_EmbedWidget.embedWidgetPropertySchema;
@@ -417,6 +417,7 @@ function getVideoIframeAllow(allowFullscreen) {
417
417
  ...allowFullscreen ? ["fullscreen"] : []
418
418
  ].join("; ");
419
419
  }
420
+ const NON_VIDEO_IFRAME_ALLOW = "web-share";
420
421
  function getEmbedOrigin(url) {
421
422
  try {
422
423
  return new URL(url).origin;
@@ -652,7 +653,7 @@ function EmbedWidget({ url = "", appBridge, shareViewerIdentity = false, title =
652
653
  const { t } = require_shell_translation_api_context.useShellTranslation();
653
654
  const { normalizedUrl, isValidUrl, iframeSrc } = useEmbedUrl(url, publicId);
654
655
  const isVideoEmbed = isKnownVideoEmbedUrl(iframeSrc);
655
- const iframeAllow = isVideoEmbed ? getVideoIframeAllow(allowFullscreen) : void 0;
656
+ const iframeAllow = isVideoEmbed ? getVideoIframeAllow(allowFullscreen) : NON_VIDEO_IFRAME_ALLOW;
656
657
  useEmbedPostMessageBridge({
657
658
  iframeRef,
658
659
  normalizedUrl,
@@ -1284,4 +1285,4 @@ Object.defineProperty(exports, "embedWidgetPropertySchema", {
1284
1285
  }
1285
1286
  });
1286
1287
 
1287
- //# sourceMappingURL=EmbedWidget-BN2NzUFb.cjs.map
1288
+ //# sourceMappingURL=EmbedWidget-N7gbpIsk.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmbedWidget-N7gbpIsk.cjs","names":["BookmarkIcon","GraduationCap","useWidgetRenderState","useRepUser","useOptionalStore","useShellTranslation","Globe","borderWidthClasses","borderColorClasses","RotateCw","Maximize2","ExternalLink","X","getHeightField","getColorField","getBorderRadiusField","getBorderWidthField","getBorderColorField"],"sources":["../../core/src/embed-token-context.ts","../../../platform/app-bridge/src/errors.ts","../../../platform/app-bridge/src/protocol.ts","../../../platform/app-bridge/src/host.ts","../../../platform/app-bridge/src/session-token-api.ts","../../core/src/embed-framing-context.ts","../../widgets/src/lib/embed-token-handshake.ts","../../widgets/src/widgets/EmbedWidget.tsx"],"sourcesContent":["/**\n * How an Embed widget obtains a signed embed context token for a droplet.\n *\n * The token proves to the framed droplet which member is viewing it. Minting\n * needs the signed-in member's session, which only the host holds, so the host\n * supplies the minter and the widget never learns how it authenticates. A host\n * with no minter (admin preview, scaffolded portals) provides nothing, and the\n * widget answers a droplet's request with an error instead of a token.\n */\n\nimport { createContext, useContext } from \"react\";\n\nexport type EmbedToken = {\n token: string;\n /** ISO 8601 expiry of the token. */\n expiresAt: string;\n};\n\n/**\n * Thrown by a minter when there is no usable session for the viewer (expired\n * or missing sign-in). The widget tells the droplet `unavailable`, not a\n * mint failure.\n */\nexport class EmbedTokenUnavailableError extends Error {\n constructor(message = \"Embed token unavailable\") {\n super(message);\n this.name = \"EmbedTokenUnavailableError\";\n }\n}\n\n/**\n * Mints a fresh token bound to the origin of `embedUrl`. Rejects when there is\n * no signed-in member or the server refuses; never returns a cached token.\n */\nexport type EmbedTokenMinter = (embedUrl: string) => Promise<EmbedToken>;\n\nconst EmbedTokenMinterContext = createContext<EmbedTokenMinter | null>(null);\n\nexport const EmbedTokenMinterProvider = EmbedTokenMinterContext.Provider;\n\n/** The host's minter, or `null` when it does not offer one. */\nexport function useEmbedTokenMinter(): EmbedTokenMinter | null {\n return useContext(EmbedTokenMinterContext);\n}\n","export type FluidBridgeErrorCode =\n | \"configuration_error\"\n | \"host_unavailable\"\n | \"handshake_timeout\"\n | \"incompatible_version\"\n | \"token_mint_failed\"\n | \"unauthorized\"\n | \"forbidden_origin\"\n | \"invalid_context\"\n | \"request_timeout\"\n | \"fetch_target_not_allowed\"\n | \"network_error\"\n | \"failed_authentication\";\n\nexport class FluidBridgeError extends Error {\n readonly code: FluidBridgeErrorCode;\n readonly details?: unknown;\n\n constructor(code: FluidBridgeErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = \"FluidBridgeError\";\n this.code = code;\n this.details = details;\n }\n}\n\nexport class FluidBridgeConfigurationError extends FluidBridgeError {\n constructor(message: string, details?: unknown) {\n super(\"configuration_error\", message, details);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class FluidBridgeHostUnavailableError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host is unavailable\",\n details?: unknown,\n ) {\n super(\"host_unavailable\", message, details);\n this.name = \"HostUnavailableError\";\n }\n}\n\nexport class FluidBridgeHandshakeTimeoutError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host did not respond before the handshake timed out\",\n details?: unknown,\n ) {\n super(\"handshake_timeout\", message, details);\n this.name = \"HandshakeTimeoutError\";\n }\n}\n\nexport class FluidBridgeIncompatibleVersionError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge SDK is not compatible with the host\",\n details?: unknown,\n ) {\n super(\"incompatible_version\", message, details);\n this.name = \"IncompatibleVersionError\";\n }\n}\n\nexport class FluidBridgeTokenMintError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host could not mint a session token\",\n details?: unknown,\n ) {\n super(\"token_mint_failed\", message, details);\n this.name = \"TokenMintFailedError\";\n }\n}\n\nexport class FluidBridgeUnauthorizedError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge request is unauthorized\",\n details?: unknown,\n ) {\n super(\"unauthorized\", message, details);\n this.name = \"UnauthorizedError\";\n }\n}\n\nexport class FluidBridgeForbiddenOriginError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host origin is forbidden\",\n details?: unknown,\n ) {\n super(\"forbidden_origin\", message, details);\n this.name = \"ForbiddenOriginError\";\n }\n}\n\nexport class FluidBridgeInvalidContextError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge context is invalid\",\n details?: unknown,\n ) {\n super(\"invalid_context\", message, details);\n this.name = \"InvalidContextError\";\n }\n}\n\nexport class FluidBridgeRequestTimeoutError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge request timed out\",\n details?: unknown,\n ) {\n super(\"request_timeout\", message, details);\n this.name = \"RequestTimeoutError\";\n }\n}\n\nexport class FluidBridgeFetchTargetError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge fetch target is not allowed\",\n details?: unknown,\n ) {\n super(\"fetch_target_not_allowed\", message, details);\n this.name = \"FetchTargetNotAllowedError\";\n }\n}\n\nexport class FluidBridgeNetworkError extends FluidBridgeError {\n constructor(message = \"Fluid App Bridge fetch failed\", details?: unknown) {\n super(\"network_error\", message, details);\n this.name = \"NetworkError\";\n }\n}\n\nexport class FluidBridgeFailedAuthenticationError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge authentication failed\",\n details?: unknown,\n ) {\n super(\"failed_authentication\", message, details);\n this.name = \"FailedAuthenticationError\";\n }\n}\n","export const FLUID_BRIDGE_PROTOCOL_VERSION = \"2026-07\";\nexport const APP_BRIDGE_SDK_NAME = \"@fluid-app/droplet-bridge\";\nexport const APP_BRIDGE_SDK_VERSION = \"0.1.0\";\n\nexport const FluidBridgeMessageType = {\n SessionTokenRequest: \"FLUID::SESSION_TOKEN_REQUEST\",\n SessionTokenRespond: \"FLUID::SESSION_TOKEN_RESPOND\",\n ContextRequest: \"FLUID::CONTEXT_REQUEST\",\n ContextRespond: \"FLUID::CONTEXT_RESPOND\",\n FailedAuthentication: \"FLUID::ERROR::FAILED_AUTHENTICATION\",\n Unauthorized: \"FLUID::ERROR::UNAUTHORIZED\",\n IncompatibleVersion: \"FLUID::ERROR::INCOMPATIBLE_VERSION\",\n TokenMintFailed: \"FLUID::ERROR::TOKEN_MINT_FAILED\",\n InvalidContext: \"FLUID::ERROR::INVALID_CONTEXT\",\n} as const;\n\nexport type FluidBridgeMessageTypeValue =\n (typeof FluidBridgeMessageType)[keyof typeof FluidBridgeMessageType];\n\nexport type BridgeActorType = \"admin\" | \"member\" | \"customer\" | \"anonymous\";\nexport type BridgeEntryType =\n | \"droplet\"\n | \"drop_zone\"\n | \"mobile_embed\"\n | \"portal_embed\"\n | \"app_extension\";\n\nexport interface BridgeResource {\n type: string;\n id: string;\n}\n\nexport interface BridgeContext {\n protocol: typeof FLUID_BRIDGE_PROTOCOL_VERSION;\n app: { clientId: string };\n store: { subdomain: string; url: string; uuid?: string; name?: string };\n actor?: {\n type: BridgeActorType;\n uuid?: string;\n roles?: string[];\n permissions?: string[];\n memberType?: string;\n };\n entry: { type: BridgeEntryType; name?: string };\n resources: BridgeResource[];\n fetch: { allowedOrigins: string[] };\n sdk: { minVersion: string; recommendedVersion?: string };\n}\n\nexport interface BridgeEnvelope<TType extends string, TPayload> {\n id: string;\n type: TType;\n payload: TPayload;\n}\n","import {\n FLUID_BRIDGE_PROTOCOL_VERSION,\n FluidBridgeMessageType,\n type BridgeContext,\n type BridgeEnvelope,\n} from \"./protocol\";\nimport {\n FluidBridgeFailedAuthenticationError,\n FluidBridgeForbiddenOriginError,\n FluidBridgeIncompatibleVersionError,\n FluidBridgeInvalidContextError,\n FluidBridgeTokenMintError,\n FluidBridgeUnauthorizedError,\n type FluidBridgeErrorCode,\n} from \"./errors\";\n\ntype RequestPayload = {\n clientId: string;\n protocol: typeof FLUID_BRIDGE_PROTOCOL_VERSION;\n};\n\ntype HostErrorPayload = {\n code: FluidBridgeErrorCode;\n message: string;\n details?: unknown;\n};\n\nexport interface CreateFluidBridgeHostOptions {\n iframe: HTMLIFrameElement;\n appOrigin: string;\n clientId: string;\n getContext: () => BridgeContext | Promise<BridgeContext>;\n getSessionToken: (context: BridgeContext) => string | Promise<string>;\n targetWindow?: Window;\n}\n\nexport interface FluidBridgeHost {\n destroy: () => void;\n}\n\nexport function createFluidBridgeHost(\n options: CreateFluidBridgeHostOptions,\n): FluidBridgeHost {\n const targetWindow = options.targetWindow ?? window;\n const appOrigin = normalizeOrigin(options.appOrigin);\n\n const handleMessage = (event: MessageEvent<unknown>): void => {\n if (event.origin !== appOrigin) return;\n if (event.source !== options.iframe.contentWindow) return;\n if (!isBridgeEnvelope(event.data)) return;\n\n void respondToBridgeMessage(options, event.data, appOrigin);\n };\n\n targetWindow.addEventListener(\"message\", handleMessage);\n\n return {\n destroy: () => targetWindow.removeEventListener(\"message\", handleMessage),\n };\n}\n\nasync function respondToBridgeMessage(\n options: CreateFluidBridgeHostOptions,\n envelope: BridgeEnvelope<string, unknown>,\n appOrigin: string,\n): Promise<void> {\n const childWindow = options.iframe.contentWindow;\n if (!childWindow) return;\n\n try {\n validateRequestPayload(envelope.payload, options.clientId);\n\n switch (envelope.type) {\n case FluidBridgeMessageType.ContextRequest: {\n const context = await options.getContext();\n childWindow.postMessage(\n {\n id: envelope.id,\n type: FluidBridgeMessageType.ContextRespond,\n payload: context,\n } satisfies BridgeEnvelope<\n typeof FluidBridgeMessageType.ContextRespond,\n BridgeContext\n >,\n appOrigin,\n );\n return;\n }\n case FluidBridgeMessageType.SessionTokenRequest: {\n const context = await options.getContext();\n const sessionToken = await options.getSessionToken(context);\n if (sessionToken.length === 0) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge host returned an empty session token\",\n );\n }\n childWindow.postMessage(\n {\n id: envelope.id,\n type: FluidBridgeMessageType.SessionTokenRespond,\n payload: { sessionToken },\n } satisfies BridgeEnvelope<\n typeof FluidBridgeMessageType.SessionTokenRespond,\n { sessionToken: string }\n >,\n appOrigin,\n );\n return;\n }\n default:\n throw new FluidBridgeForbiddenOriginError(\n \"Fluid App Bridge host received an unsupported message type\",\n { type: envelope.type },\n );\n }\n } catch (error) {\n childWindow.postMessage(\n {\n id: envelope.id,\n type: errorTypeFor(error),\n payload: errorPayloadFor(error),\n } satisfies BridgeEnvelope<string, HostErrorPayload>,\n appOrigin,\n );\n }\n}\n\nfunction validateRequestPayload(\n value: unknown,\n clientId: string,\n): RequestPayload {\n if (typeof value !== \"object\" || value === null) {\n throw new FluidBridgeInvalidContextError(\n \"Fluid App Bridge request payload is invalid\",\n );\n }\n if (!(\"clientId\" in value) || value.clientId !== clientId) {\n throw new FluidBridgeFailedAuthenticationError(\n \"Fluid App Bridge request client ID does not match the host context\",\n );\n }\n if (\n !(\"protocol\" in value) ||\n value.protocol !== FLUID_BRIDGE_PROTOCOL_VERSION\n ) {\n throw new FluidBridgeIncompatibleVersionError();\n }\n return value as RequestPayload;\n}\n\nfunction isBridgeEnvelope(\n value: unknown,\n): value is BridgeEnvelope<string, unknown> {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n return (\n \"id\" in value &&\n \"type\" in value &&\n \"payload\" in value &&\n typeof value.id === \"string\" &&\n typeof value.type === \"string\"\n );\n}\n\nfunction errorTypeFor(error: unknown): string {\n if (error instanceof FluidBridgeFailedAuthenticationError) {\n return FluidBridgeMessageType.FailedAuthentication;\n }\n if (error instanceof FluidBridgeIncompatibleVersionError) {\n return FluidBridgeMessageType.IncompatibleVersion;\n }\n if (error instanceof FluidBridgeUnauthorizedError) {\n return FluidBridgeMessageType.Unauthorized;\n }\n if (error instanceof FluidBridgeTokenMintError) {\n return FluidBridgeMessageType.TokenMintFailed;\n }\n if (error instanceof FluidBridgeInvalidContextError) {\n return FluidBridgeMessageType.InvalidContext;\n }\n if (error instanceof FluidBridgeForbiddenOriginError) {\n return FluidBridgeMessageType.InvalidContext;\n }\n return FluidBridgeMessageType.TokenMintFailed;\n}\n\nfunction errorPayloadFor(error: unknown): HostErrorPayload {\n if (\n error instanceof Error &&\n \"code\" in error &&\n typeof error.code === \"string\"\n ) {\n return {\n code: error.code as FluidBridgeErrorCode,\n message: error.message,\n details: \"details\" in error ? error.details : undefined,\n };\n }\n return {\n code: \"token_mint_failed\",\n message: \"Fluid App Bridge host could not complete the request\",\n details: error,\n };\n}\n\nfunction normalizeOrigin(origin: string): string {\n return new URL(origin).origin;\n}\n","import {\n APP_BRIDGE_SDK_NAME,\n APP_BRIDGE_SDK_VERSION,\n FLUID_BRIDGE_PROTOCOL_VERSION,\n type BridgeContext,\n} from \"./protocol\";\nimport {\n FluidBridgeFailedAuthenticationError,\n FluidBridgeIncompatibleVersionError,\n FluidBridgeTokenMintError,\n FluidBridgeUnauthorizedError,\n} from \"./errors\";\n\nexport interface AppBridgeSessionTokenRequest {\n clientId: string;\n entry: BridgeContext[\"entry\"];\n resources?: BridgeContext[\"resources\"];\n allowedOrigins?: string[];\n sessionId?: string;\n}\n\nexport interface MintAppBridgeSessionTokenOptions {\n request: AppBridgeSessionTokenRequest;\n apiBaseUrl?: string;\n authToken?: string;\n fetch?: typeof fetch;\n}\n\ninterface SessionTokenSuccessResponse {\n session_token: string;\n}\n\ninterface LegacyErrorResponse {\n error?: {\n message?: string;\n details?: unknown;\n };\n}\n\nconst DEFAULT_SESSION_TOKEN_PATH = \"api/v2025-06/app_bridge/session_token\";\n\nexport async function mintAppBridgeSessionToken({\n request,\n apiBaseUrl,\n authToken,\n fetch: fetchImplementation = globalThis.fetch?.bind(globalThis),\n}: MintAppBridgeSessionTokenOptions): Promise<string> {\n if (!fetchImplementation) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge host requires a fetch implementation to mint session tokens\",\n );\n }\n\n const response = await fetchImplementation(\n resolveSessionTokenUrl(apiBaseUrl),\n {\n method: \"POST\",\n headers: sessionTokenHeaders(authToken),\n body: JSON.stringify(sessionTokenRequestBody(request)),\n },\n );\n\n const body: unknown = await response.json().catch(() => null);\n\n if (!response.ok) {\n throw errorForTokenResponse(response.status, body);\n }\n\n if (!isSessionTokenSuccessResponse(body) || body.session_token.length === 0) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge backend returned an invalid session token response\",\n { body },\n );\n }\n\n return body.session_token;\n}\n\nexport function sessionTokenRequestFromContext(\n context: BridgeContext,\n sessionId?: string,\n): AppBridgeSessionTokenRequest {\n return {\n clientId: context.app.clientId,\n entry: context.entry,\n resources: context.resources,\n allowedOrigins: context.fetch.allowedOrigins,\n ...(sessionId ? { sessionId } : {}),\n };\n}\n\nfunction sessionTokenHeaders(authToken: string | undefined): Headers {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n \"X-Fluid-App-Bridge-Protocol\": FLUID_BRIDGE_PROTOCOL_VERSION,\n \"X-Fluid-App-Bridge-Version\": APP_BRIDGE_SDK_VERSION,\n \"X-Fluid-App-Bridge-Sdk\": APP_BRIDGE_SDK_NAME,\n });\n\n if (authToken) {\n headers.set(\"Authorization\", `Bearer ${authToken}`);\n }\n\n return headers;\n}\n\nfunction sessionTokenRequestBody(\n request: AppBridgeSessionTokenRequest,\n): Record<string, unknown> {\n return {\n client_id: request.clientId,\n entry: request.entry,\n resources: request.resources ?? [],\n allowed_origins: request.allowedOrigins ?? [],\n ...(request.sessionId ? { session_id: request.sessionId } : {}),\n };\n}\n\nfunction resolveSessionTokenUrl(apiBaseUrl: string | undefined): string {\n if (!apiBaseUrl) {\n return `/${DEFAULT_SESSION_TOKEN_PATH}`;\n }\n return new URL(\n DEFAULT_SESSION_TOKEN_PATH,\n ensureTrailingSlash(apiBaseUrl),\n ).toString();\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.endsWith(\"/\") ? url : `${url}/`;\n}\n\nfunction isSessionTokenSuccessResponse(\n value: unknown,\n): value is SessionTokenSuccessResponse {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"session_token\" in value &&\n typeof value.session_token === \"string\"\n );\n}\n\nfunction errorForTokenResponse(status: number, body: unknown): Error {\n const errorBody = isLegacyErrorResponse(body) ? body.error : undefined;\n const message =\n errorBody?.message ??\n \"Fluid App Bridge backend rejected the session-token request\";\n const details = errorBody?.details ?? body;\n\n if (status === 401) {\n return new FluidBridgeUnauthorizedError(message, details);\n }\n if (status === 403) {\n return new FluidBridgeFailedAuthenticationError(message, details);\n }\n if (status === 422) {\n return new FluidBridgeIncompatibleVersionError(message, details);\n }\n return new FluidBridgeTokenMintError(message, details);\n}\n\nfunction isLegacyErrorResponse(value: unknown): value is LegacyErrorResponse {\n return typeof value === \"object\" && value !== null && \"error\" in value;\n}\n","/**\n * How an Embed widget asks whether a site will let itself be framed.\n *\n * The check needs a server: reading `X-Frame-Options` and `frame-ancestors`\n * means fetching the target, which a browser cannot do cross-origin. Fluid\n * Admin answers it with a Next route at `/api/embed-can-frame`, and the widget\n * used to call that path directly.\n *\n * That hard-coded path is why the same widget behaves differently depending on\n * who renders it. In admin the probe answers and a refused site gets an\n * explanatory card naming the URL. Anywhere else — Mist's portal preview, a\n * scaffolded portal — the path 404s, the state falls back to \"unknown\", and the\n * author gets a silently empty box that looks identical to a bug in the host.\n *\n * So the host supplies the probe. Admin keeps its route, Mist answers from its\n * main process where no CSP or CORS applies, and a host with no way to check\n * simply provides nothing and gets today's behaviour.\n */\n\nimport { createContext, useContext } from \"react\";\n\n/**\n * Resolves true/false when the answer is known, or `null` when it cannot be\n * determined — a failed request, a host without a probe, an aborted check.\n *\n * `null` is not \"blocked\". The verdict is a hint shown to an author, never a\n * gate: the iframe is attempted regardless and the browser has the last word.\n */\nexport type EmbedFramingProbe = (\n url: string,\n signal: AbortSignal,\n) => Promise<boolean | null>;\n\nconst EmbedFramingProbeContext = createContext<EmbedFramingProbe | null>(null);\n\nexport const EmbedFramingProbeProvider = EmbedFramingProbeContext.Provider;\n\n/**\n * The host's probe, or `null` when it does not offer one.\n *\n * Deliberately not throwing on a missing provider, unlike the domain API hooks:\n * an Embed widget renders perfectly well without an embeddability hint, and\n * every host that predates this context has none.\n */\nexport function useEmbedFramingProbe(): EmbedFramingProbe | null {\n return useContext(EmbedFramingProbeContext);\n}\n","/**\n * The postMessage handshake a framed droplet uses to get a signed embed\n * context token from the Portal.\n *\n * The token never travels in the URL (it would land in logs and referrers).\n * The droplet asks, the Portal checks who is asking, and answers only to that\n * origin:\n *\n * iframe -> parent { type: \"fluid:embed-token:request\", nonce }\n * parent -> iframe { type: \"fluid:embed-token\", nonce, token, expiresAt }\n * or { type: \"fluid:embed-token:error\", nonce, reason }\n *\n * Every request mints a new token; the droplet asks again for each sensitive\n * action rather than holding one.\n */\n\nimport {\n EmbedTokenUnavailableError,\n type EmbedTokenMinter,\n} from \"@fluid-app/portal-core/embed-token-context\";\n\nexport const EMBED_TOKEN_REQUEST = \"fluid:embed-token:request\";\nexport const EMBED_TOKEN_RESPONSE = \"fluid:embed-token\";\nexport const EMBED_TOKEN_ERROR = \"fluid:embed-token:error\";\n\nexport type EmbedTokenErrorReason =\n | \"unavailable\"\n | \"rate_limited\"\n | \"mint_failed\";\n\nconst MAX_NONCE_LENGTH = 128;\nexport const EMBED_TOKEN_MIN_INTERVAL_MS = 1000;\n\ntype MessageLike = {\n source: unknown;\n origin: string;\n data: unknown;\n};\n\nexport type EmbedTokenHandlerOptions = {\n /** The iframe's current window, or null when it is gone. */\n getFrameWindow: () => Window | null;\n /** Origin of the iframe src. Only this origin is answered. */\n expectedOrigin: string;\n /** The URL the Portal framed; the server binds the token to its origin. */\n embedUrl: string;\n /** Null when no signed-in member / no host minter is available. */\n mint: EmbedTokenMinter | null;\n now?: () => number;\n minIntervalMs?: number;\n};\n\nfunction parseRequest(data: unknown): { nonce: string } | null {\n if (typeof data !== \"object\" || data === null) return null;\n const { type, nonce } = data as { type?: unknown; nonce?: unknown };\n if (type !== EMBED_TOKEN_REQUEST) return null;\n if (typeof nonce !== \"string\") return null;\n if (nonce.length === 0 || nonce.length > MAX_NONCE_LENGTH) return null;\n return { nonce };\n}\n\nexport function createEmbedTokenHandler({\n getFrameWindow,\n expectedOrigin,\n embedUrl,\n mint,\n now = Date.now,\n minIntervalMs = EMBED_TOKEN_MIN_INTERVAL_MS,\n}: EmbedTokenHandlerOptions): (event: MessageLike) => void {\n let lastRequestAt = Number.NEGATIVE_INFINITY;\n\n return (event) => {\n const frameWindow = getFrameWindow();\n if (!frameWindow) return;\n if (event.source !== frameWindow) return;\n if (event.origin !== expectedOrigin) return;\n\n const request = parseRequest(event.data);\n if (!request) return;\n const { nonce } = request;\n\n const reply = (message: Record<string, unknown>) => {\n // Only detects the iframe going away. It cannot detect navigation:\n // contentWindow is the same object across navigations. What keeps a\n // token from a later page is the pinned target origin below.\n if (getFrameWindow() !== frameWindow) return;\n frameWindow.postMessage({ ...message, nonce }, expectedOrigin);\n };\n const fail = (reason: EmbedTokenErrorReason) =>\n reply({ type: EMBED_TOKEN_ERROR, reason });\n\n const at = now();\n if (at - lastRequestAt < minIntervalMs) return fail(\"rate_limited\");\n lastRequestAt = at;\n\n if (!mint) return fail(\"unavailable\");\n\n mint(embedUrl).then(\n ({ token, expiresAt }) =>\n reply({ type: EMBED_TOKEN_RESPONSE, token, expiresAt }),\n (error: unknown) =>\n fail(\n error instanceof EmbedTokenUnavailableError\n ? \"unavailable\"\n : \"mint_failed\",\n ),\n );\n };\n}\n\n/**\n * Which iframes take part. Cover mode only ever mounts its iframe inside the\n * modal, and that one uses the primary ref; the inline modal has its own ref.\n * Only embeds that opted in to sharing the viewer's identity, or declare an\n * app bridge client, and never while the builder is editing.\n */\nexport function embedTokenHandshakeTargets({\n shareViewerIdentity,\n hasAppBridgeClient,\n editMode,\n modalOpen,\n}: {\n shareViewerIdentity: boolean;\n hasAppBridgeClient: boolean;\n editMode: boolean;\n modalOpen: boolean;\n}): { primary: boolean; modal: boolean } {\n const answers = (shareViewerIdentity || hasAppBridgeClient) && !editMode;\n return { primary: answers, modal: answers && modalOpen };\n}\n\n/**\n * Listens on `eventTarget` and returns the cleanup. Once cleaned up, a mint\n * still in flight never replies.\n */\nexport function attachEmbedTokenHandshake({\n eventTarget,\n getFrameWindow,\n ...options\n}: Omit<EmbedTokenHandlerOptions, \"now\" | \"minIntervalMs\"> & {\n eventTarget: Pick<Window, \"addEventListener\" | \"removeEventListener\">;\n}): () => void {\n let active = true;\n const handler = createEmbedTokenHandler({\n ...options,\n getFrameWindow: () => (active ? getFrameWindow() : null),\n });\n const listener = (event: MessageEvent) => handler(event);\n eventTarget.addEventListener(\"message\", listener);\n return () => {\n active = false;\n eventTarget.removeEventListener(\"message\", listener);\n };\n}\n","import {\n APP_BRIDGE_SDK_VERSION,\n FLUID_BRIDGE_PROTOCOL_VERSION,\n createFluidBridgeHost,\n mintAppBridgeSessionToken,\n sessionTokenRequestFromContext,\n type BridgeContext,\n type BridgeEntryType,\n type BridgeResource,\n} from \"@fluid-app/droplet-bridge\";\nimport {\n Bell,\n BookmarkIcon,\n BookOpen,\n Calendar,\n ExternalLink,\n Gift,\n Globe,\n GraduationCap,\n Heart,\n Maximize2,\n RotateCw,\n ShoppingBag,\n Sparkles,\n Star,\n Trophy,\n User,\n Video,\n X,\n Zap,\n type LucideIcon,\n} from \"lucide-react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type RefObject,\n} from \"react\";\nimport type React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n getBorderRadiusField,\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport {\n useEmbedFramingProbe,\n type EmbedFramingProbe,\n} from \"@fluid-app/portal-core/embed-framing-context\";\nimport { useEmbedTokenMinter } from \"@fluid-app/portal-core/embed-token-context\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n ShareableItem,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getBorderWidthField,\n getBorderColorField,\n getColorField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport {\n attachEmbedTokenHandshake,\n embedTokenHandshakeTargets,\n} from \"../lib/embed-token-handshake\";\nimport { useRepUser } from \"../contexts/RepUserContext\";\nimport { useWidgetRenderState } from \"../contexts/WidgetRenderStateContext\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\n\ntype EmbedWidgetMessage = {\n type: \"OPEN_FULL_SCREEN_WEBVIEW\";\n url: string;\n};\n\nexport type EmbedWidgetAppBridgeConfig = {\n clientId?: string;\n appOrigins?: string[];\n entryType?: BridgeEntryType;\n entryName?: string;\n resources?: BridgeResource[];\n};\n\ntype DisplayMode = \"inline\" | \"cover\";\n\ntype EmbedUrlState = {\n normalizedUrl: string;\n isValidUrl: boolean;\n iframeSrc: string;\n};\n\nfunction isValidHttpUrl(urlString: string): boolean {\n try {\n const parsed = new URL(urlString);\n return parsed.protocol === \"https:\" || parsed.protocol === \"http:\";\n } catch {\n return false;\n }\n}\n\nfunction useEmbedUrl(url: string, publicId: string | undefined): EmbedUrlState {\n return useMemo(() => {\n const normalizedUrl =\n url && (url.startsWith(\"http://\") || url.startsWith(\"https://\"))\n ? url\n : url\n ? `https://${url}`\n : \"\";\n\n let isValidUrl = false;\n if (normalizedUrl) {\n try {\n const parsed = new URL(normalizedUrl);\n isValidUrl =\n (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") &&\n (parsed.hostname.includes(\".\") || parsed.hostname === \"localhost\");\n } catch {\n // invalid URL\n }\n }\n\n if (!isValidUrl) {\n return { normalizedUrl, isValidUrl, iframeSrc: normalizedUrl };\n }\n\n const urlObj = new URL(normalizedUrl);\n applyInlineVideoEmbedDefaults(urlObj);\n if (publicId) urlObj.searchParams.set(\"public_id\", publicId);\n return { normalizedUrl, isValidUrl, iframeSrc: urlObj.toString() };\n }, [url, publicId]);\n}\n\nfunction isYouTubeHost(hostname: string): boolean {\n const normalized = hostname.replace(/^www\\./, \"\").toLowerCase();\n return (\n normalized === \"youtube.com\" ||\n normalized.endsWith(\".youtube.com\") ||\n normalized === \"youtube-nocookie.com\" ||\n normalized.endsWith(\".youtube-nocookie.com\") ||\n normalized === \"youtu.be\"\n );\n}\n\nfunction isVimeoHost(hostname: string): boolean {\n const normalized = hostname.replace(/^www\\./, \"\").toLowerCase();\n return (\n normalized === \"vimeo.com\" ||\n normalized.endsWith(\".vimeo.com\") ||\n normalized === \"player.vimeo.com\"\n );\n}\n\nfunction isKnownVideoEmbedUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return isYouTubeHost(parsed.hostname) || isVimeoHost(parsed.hostname);\n } catch {\n return false;\n }\n}\n\nfunction applyInlineVideoEmbedDefaults(url: URL): void {\n if (!isYouTubeHost(url.hostname) && !isVimeoHost(url.hostname)) return;\n url.searchParams.set(\"autoplay\", \"0\");\n url.searchParams.set(\"playsinline\", \"1\");\n}\n\nfunction getVideoIframeAllow(allowFullscreen: boolean): string {\n return [\n \"clipboard-write\",\n \"encrypted-media\",\n \"picture-in-picture\",\n \"web-share\",\n ...(allowFullscreen ? [\"fullscreen\"] : []),\n ].join(\"; \");\n}\n\nconst NON_VIDEO_IFRAME_ALLOW = \"web-share\";\n\ntype UseEmbedPostMessageBridgeProps = {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n normalizedUrl: string;\n isValidUrl: boolean;\n editMode: boolean;\n};\n\nfunction getEmbedOrigin(url: string): string | null {\n try {\n return new URL(url).origin;\n } catch {\n return null;\n }\n}\n\nfunction useEmbedPostMessageBridge({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n editMode,\n}: UseEmbedPostMessageBridgeProps): void {\n useEffect(() => {\n if (!isValidUrl || editMode) return;\n\n const expectedOrigin = new URL(normalizedUrl).origin;\n\n function handleMessage(event: MessageEvent) {\n if (event.origin !== expectedOrigin) return;\n if (event.source !== iframeRef.current?.contentWindow) return;\n\n let data: unknown;\n if (typeof event.data === \"string\") {\n try {\n data = JSON.parse(event.data);\n } catch {\n return;\n }\n } else {\n data = event.data;\n }\n\n if (\n typeof data === \"object\" &&\n data !== null &&\n \"type\" in data &&\n (data as EmbedWidgetMessage).type === \"OPEN_FULL_SCREEN_WEBVIEW\"\n ) {\n const messageUrl = (data as EmbedWidgetMessage).url;\n if (messageUrl && isValidHttpUrl(messageUrl)) {\n window.open(messageUrl, \"_blank\", \"noopener,noreferrer\");\n }\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [iframeRef, normalizedUrl, isValidUrl, editMode]);\n}\n\n/**\n * Answers a droplet's `fluid:embed-token:request` with a freshly minted\n * context token. Only droplet embeds (those declaring an app bridge client)\n * take part; every other embed never sees the message handled.\n */\nfunction useEmbedTokenHandshake({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n enabled,\n}: {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n normalizedUrl: string;\n isValidUrl: boolean;\n enabled: boolean;\n}): void {\n const mint = useEmbedTokenMinter();\n\n useEffect(() => {\n if (!enabled || !isValidUrl) return;\n const expectedOrigin = getEmbedOrigin(normalizedUrl);\n if (!expectedOrigin) return;\n\n return attachEmbedTokenHandshake({\n eventTarget: window,\n getFrameWindow: () => iframeRef.current?.contentWindow ?? null,\n expectedOrigin,\n embedUrl: normalizedUrl,\n mint,\n });\n }, [enabled, iframeRef, isValidUrl, mint, normalizedUrl]);\n}\n\ntype EmbedabilityState = \"idle\" | \"checking\" | \"embeddable\" | \"blocked\";\n\n/**\n * The default probe: Fluid Admin's own route, reached relatively.\n *\n * Correct only where that route exists. Everywhere else it 404s and the answer\n * is \"unknown\" — which is why hosts outside admin supply their own through\n * {@link useEmbedFramingProbe} rather than inheriting this.\n */\nconst probeViaAdminRoute: EmbedFramingProbe = async (url, signal) => {\n const res = await fetch(\n `/api/embed-can-frame?url=${encodeURIComponent(url)}`,\n { signal },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { canFrame?: boolean } | null;\n return typeof data?.canFrame === \"boolean\" ? data.canFrame : null;\n};\n\nfunction useEmbedability(\n normalizedUrl: string,\n isValidUrl: boolean,\n editMode: boolean,\n): EmbedabilityState {\n const [state, setState] = useState<EmbedabilityState>(\"idle\");\n const hostProbe = useEmbedFramingProbe();\n\n // Who is the audience for a \"this site refuses to be embedded\" card? An\n // author, never a member — so it must not appear on a live portal.\n //\n // `editMode` alone was the wrong test for that. It is true on the admin\n // canvas and FALSE in Mist's portal preview, which renders read-only, so the\n // one host that supplies a probe was the one host that never ran it. A\n // supplied probe is itself the signal: a host installs one precisely because\n // it wants the diagnosis. The live portal installs none and falls back to the\n // admin route, which 404s there and yields \"cannot tell\".\n const wantsEmbedabilityHint = editMode || hostProbe !== null;\n\n useEffect(() => {\n if (!wantsEmbedabilityHint || !isValidUrl) {\n setState(\"idle\");\n return;\n }\n setState(\"checking\");\n const controller = new AbortController();\n const probe = hostProbe ?? probeViaAdminRoute;\n const timer = setTimeout(() => {\n probe(normalizedUrl, controller.signal)\n .then((canFrame) => {\n if (controller.signal.aborted) return;\n // null is \"could not tell\", which must not read as \"blocked\" — the\n // iframe is still attempted and the browser decides.\n setState(\n canFrame === null ? \"idle\" : canFrame ? \"embeddable\" : \"blocked\",\n );\n })\n .catch(() => {\n if (!controller.signal.aborted) {\n setState(\"idle\");\n }\n });\n }, 400);\n\n return () => {\n controller.abort();\n clearTimeout(timer);\n };\n }, [normalizedUrl, isValidUrl, wantsEmbedabilityHint, hostProbe]);\n\n return state;\n}\n\nfunction useModalBodyScrollLock(isOpen: boolean): void {\n useEffect(() => {\n if (!isOpen) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [isOpen]);\n}\n\nfunction useModalEscapeClose(isOpen: boolean, onClose: () => void): void {\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, onClose]);\n}\n\nfunction useDialogFocusRestore(dialogRef: RefObject<HTMLElement | null>): void {\n useEffect(() => {\n const previouslyFocused =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n dialogRef.current?.focus();\n return () => {\n previouslyFocused?.focus();\n };\n }, [dialogRef]);\n}\n\n// header icon registry\n\nconst HEADER_ICON_MAP: Record<string, LucideIcon> = {\n GraduationCap,\n Video,\n BookOpen,\n Globe,\n User,\n Star,\n Heart,\n Trophy,\n Sparkles,\n Zap,\n Gift,\n ShoppingBag,\n Bell,\n Calendar,\n Bookmark: BookmarkIcon,\n};\n\nconst HEADER_ICON_OPTIONS: Array<{ label: string; value: string }> = [\n { label: \"Graduation Cap\", value: \"GraduationCap\" },\n { label: \"Video\", value: \"Video\" },\n { label: \"Book\", value: \"BookOpen\" },\n { label: \"Globe\", value: \"Globe\" },\n { label: \"User\", value: \"User\" },\n { label: \"Star\", value: \"Star\" },\n { label: \"Heart\", value: \"Heart\" },\n { label: \"Trophy\", value: \"Trophy\" },\n { label: \"Sparkles\", value: \"Sparkles\" },\n { label: \"Zap / Lightning\", value: \"Zap\" },\n { label: \"Gift\", value: \"Gift\" },\n { label: \"Shopping Bag\", value: \"ShoppingBag\" },\n { label: \"Bell\", value: \"Bell\" },\n { label: \"Calendar\", value: \"Calendar\" },\n { label: \"Bookmark\", value: \"Bookmark\" },\n];\n\nconst getHeaderIcon = (name: string | undefined): LucideIcon => {\n if (!name) return GraduationCap;\n return HEADER_ICON_MAP[name] ?? GraduationCap;\n};\n\ntype EmbedWidgetProps = ComponentProps<\"div\"> & {\n url?: string;\n appBridge?: EmbedWidgetAppBridgeConfig;\n /** Answer the embed's requests for a signed viewer identity token. */\n shareViewerIdentity?: boolean;\n title?: string;\n height?: string;\n fullScreen?: boolean;\n allowFullscreen?: boolean;\n loading?: \"eager\" | \"lazy\";\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n // Builder render state is provided by WidgetRenderStateContext.\n editMode?: boolean;\n // Builder render state is provided by WidgetRenderStateContext.\n isSelected?: boolean;\n\n // Cover-mode additions (all optional — inline mode ignores these)\n displayMode?: DisplayMode;\n coverResource?: ShareableItem;\n coverUseCustomUrl?: boolean;\n coverImageUrl?: string;\n coverTitle?: string;\n coverMeta?: string;\n coverShowHeader?: boolean;\n coverHeaderIcon?: string;\n coverHeaderIconColor?: ColorOptions;\n coverHeight?: string;\n};\n\nexport function EmbedWidget({\n url = \"\",\n appBridge,\n shareViewerIdentity = false,\n title = \"Embedded Content\",\n height = \"400px\",\n fullScreen = false,\n allowFullscreen = true,\n loading = \"lazy\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n editMode: _editMode,\n isSelected: _isSelected,\n\n displayMode = \"inline\",\n coverResource,\n coverUseCustomUrl = false,\n coverImageUrl = \"\",\n coverTitle = \"\",\n coverMeta = \"\",\n coverShowHeader = true,\n coverHeaderIcon = \"GraduationCap\",\n coverHeaderIconColor = \"primary\",\n coverHeight = \"320px\",\n\n className,\n ...props\n}: EmbedWidgetProps): React.JSX.Element {\n const renderState = useWidgetRenderState();\n const editMode = _editMode ?? renderState.editMode;\n const isSelected = _isSelected ?? renderState.isSelected;\n const isFullScreen = fullScreen;\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const modalIframeRef = useRef<HTMLIFrameElement>(null);\n const repUser = useRepUser();\n const publicId = repUser?.publicId;\n const { data: store } = useOptionalStore();\n\n const [modalOpen, setModalOpen] = useState(false);\n const [coverReloadKey, setCoverReloadKey] = useState(0);\n const [iframeReloadKey, setIframeReloadKey] = useState(0);\n\n const closeModal = useCallback(() => setModalOpen(false), []);\n const { t } = useShellTranslation();\n\n const { normalizedUrl, isValidUrl, iframeSrc } = useEmbedUrl(url, publicId);\n const isVideoEmbed = isKnownVideoEmbedUrl(iframeSrc);\n const iframeAllow = isVideoEmbed\n ? getVideoIframeAllow(allowFullscreen)\n : NON_VIDEO_IFRAME_ALLOW;\n useEmbedPostMessageBridge({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n editMode,\n });\n\n const appBridgeClientId = appBridge?.clientId;\n const handshakeTargets = embedTokenHandshakeTargets({\n shareViewerIdentity,\n hasAppBridgeClient: Boolean(appBridge?.clientId),\n editMode,\n modalOpen,\n });\n useEmbedTokenHandshake({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n enabled: handshakeTargets.primary,\n });\n useEmbedTokenHandshake({\n iframeRef: modalIframeRef,\n normalizedUrl,\n isValidUrl,\n enabled: handshakeTargets.modal,\n });\n const appBridgeEntryType = appBridge?.entryType;\n const appBridgeEntryName = appBridge?.entryName;\n const appBridgeResources = appBridge?.resources;\n const appBridgeAppOrigins = appBridge?.appOrigins;\n\n const appBridgeContext = useMemo<BridgeContext | null>(() => {\n if (!appBridgeClientId || !store || !isValidUrl) return null;\n\n return {\n protocol: FLUID_BRIDGE_PROTOCOL_VERSION,\n app: { clientId: appBridgeClientId },\n store: {\n subdomain: store.subdomain,\n url: `https://${store.subdomain}.fluid.app`,\n name: store.name,\n },\n ...(repUser\n ? {\n actor: {\n type: \"member\" as const,\n ...(repUser.publicId ? { uuid: repUser.publicId } : {}),\n roles: [],\n permissions: [],\n },\n }\n : {}),\n entry: {\n type: appBridgeEntryType ?? \"portal_embed\",\n name: appBridgeEntryName ?? title,\n },\n resources: appBridgeResources ?? [],\n fetch: {\n allowedOrigins: [\n getEmbedOrigin(normalizedUrl),\n ...(appBridgeAppOrigins ?? []),\n ].filter((origin): origin is string => Boolean(origin)),\n },\n sdk: { minVersion: APP_BRIDGE_SDK_VERSION },\n };\n }, [\n appBridgeAppOrigins,\n appBridgeClientId,\n appBridgeEntryName,\n appBridgeEntryType,\n appBridgeResources,\n isValidUrl,\n normalizedUrl,\n repUser,\n store,\n title,\n ]);\n const appBridgeContextRef = useRef<BridgeContext | null>(null);\n const appBridgeContextReady = appBridgeContext !== null;\n\n useEffect(() => {\n appBridgeContextRef.current = appBridgeContext;\n }, [appBridgeContext]);\n\n const getAppBridgeContext = useCallback(() => {\n if (!appBridgeContextRef.current) {\n throw new Error(\"App Bridge context is unavailable\");\n }\n return appBridgeContextRef.current;\n }, []);\n\n const getAppBridgeSessionToken = useCallback(\n (bridgeContext: BridgeContext) =>\n mintAppBridgeSessionToken({\n request: sessionTokenRequestFromContext(bridgeContext),\n }),\n [],\n );\n\n useEffect(() => {\n if (!appBridgeClientId || !appBridgeContextReady || editMode) return;\n\n const iframe = iframeRef.current;\n const appOrigin = getEmbedOrigin(normalizedUrl);\n if (!iframe || !appOrigin) return;\n\n const host = createFluidBridgeHost({\n iframe,\n appOrigin,\n clientId: appBridgeClientId,\n getContext: getAppBridgeContext,\n getSessionToken: getAppBridgeSessionToken,\n });\n\n return () => host.destroy();\n }, [\n appBridgeClientId,\n appBridgeContextReady,\n editMode,\n getAppBridgeContext,\n getAppBridgeSessionToken,\n iframeReloadKey,\n modalOpen,\n normalizedUrl,\n ]);\n useModalBodyScrollLock(modalOpen);\n useModalEscapeClose(modalOpen, closeModal);\n const embedability = useEmbedability(\n normalizedUrl,\n isValidUrl,\n editMode && displayMode !== \"cover\",\n );\n\n // Empty/invalid URL states\n\n if (!url || !isValidUrl) {\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${className ?? \"\"}`}\n {...props}\n style={\n isFullScreen\n ? {\n height:\n \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\",\n }\n : { height: displayMode === \"cover\" ? coverHeight : height }\n }\n >\n <div className=\"flex flex-col items-center gap-2 p-6 text-center\">\n <Globe className=\"size-12 opacity-50\" />\n <p className=\"text-sm font-medium\">\n Enter a URL to embed external content\n </p>\n <p className=\"text-xs opacity-75\">\n Configure the URL in the properties panel\n </p>\n </div>\n </div>\n );\n }\n\n // Cover mode\n\n if (displayMode === \"cover\") {\n const resolvedCoverImage = coverUseCustomUrl\n ? coverImageUrl\n : coverResource?.imageUrl || coverResource?.image_url || coverImageUrl;\n\n const effectiveTitle = coverTitle || title;\n const HeaderIcon = getHeaderIcon(coverHeaderIcon);\n\n const handleOpenModal = () => {\n if (editMode) return;\n setModalOpen(true);\n };\n\n const handleReload = () => {\n if (editMode) return;\n setCoverReloadKey((key) => key + 1);\n };\n\n const handleOpenNewTab = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (editMode) return;\n window.open(iframeSrc, \"_blank\", \"noopener,noreferrer\");\n };\n\n return (\n <>\n <div\n className={`relative w-full overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-background ${className ?? \"\"}`}\n style={{\n boxShadow:\n \"0 1px 2px color-mix(in oklch, var(--color-foreground) 5%, transparent), 0 12px 32px -16px color-mix(in oklch, var(--color-foreground) 10%, transparent)\",\n }}\n {...props}\n >\n {/* Inset hairline ring */}\n <div\n aria-hidden=\"true\"\n className={`pointer-events-none absolute inset-0 z-[1] rounded-${borderRadius}`}\n style={{\n boxShadow:\n \"inset 0 0 0 1px color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }}\n />\n {coverShowHeader && (\n <div className=\"relative z-[2] flex items-center gap-3 px-5 py-3\">\n <span\n aria-hidden=\"true\"\n className={`text-${coverHeaderIconColor}-foreground flex size-7 shrink-0 items-center justify-center rounded-${borderRadius}`}\n style={{\n background: `linear-gradient(135deg, color-mix(in oklch, var(--color-${coverHeaderIconColor}) 75%, white 25%) 0%, var(--color-${coverHeaderIconColor}) 100%)`,\n boxShadow: `\n inset 0 1px 0 rgba(255,255,255,0.25),\n inset 0 -1px 0 rgba(0,0,0,0.08),\n 0 1px 2px color-mix(in oklch, var(--color-${coverHeaderIconColor}) 25%, transparent)\n `,\n }}\n >\n <HeaderIcon className=\"size-3.5\" strokeWidth={2.25} />\n </span>\n\n <div className=\"min-w-0 flex-1\">\n {effectiveTitle && (\n <h3 className=\"text-foreground truncate text-[15px] leading-tight font-semibold tracking-tight\">\n {effectiveTitle}\n </h3>\n )}\n {coverMeta && (\n <p className=\"text-foreground/40 mt-0.5 truncate text-[11px] font-medium tracking-[0.08em] uppercase\">\n {coverMeta}\n </p>\n )}\n </div>\n\n <div className=\"bg-foreground/5 flex shrink-0 items-center rounded-lg p-0.5\">\n <HeaderIconButton\n Icon={RotateCw}\n label=\"Reload\"\n onClick={(e) => {\n e.stopPropagation();\n handleReload();\n }}\n />\n <HeaderIconButton\n Icon={Maximize2}\n label=\"Open\"\n onClick={(e) => {\n e.stopPropagation();\n handleOpenModal();\n }}\n />\n <HeaderIconButton\n Icon={ExternalLink}\n label=\"Open in new tab\"\n onClick={handleOpenNewTab}\n />\n </div>\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={handleOpenModal}\n disabled={editMode}\n className={`relative block w-full overflow-hidden ${editMode ? \"cursor-default\" : \"cursor-pointer\"}`}\n style={{ height: coverHeight }}\n aria-label={`Open ${effectiveTitle || title}`}\n >\n {resolvedCoverImage ? (\n <img\n key={`cover-${coverReloadKey}`}\n src={resolvedCoverImage}\n alt={effectiveTitle || title}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"bg-muted flex h-full w-full items-center justify-center\">\n <Globe className=\"text-muted-foreground/40 size-16\" />\n </div>\n )}\n </button>\n {editMode && !isSelected && <div className=\"absolute inset-0 z-10\" />}\n </div>\n\n {modalOpen && (\n <EmbedModal\n key={`modal-${iframeReloadKey}`}\n src={iframeSrc}\n title={effectiveTitle || title}\n allowFullscreen={allowFullscreen}\n iframeAllow={iframeAllow}\n iframeRef={iframeRef}\n onClose={closeModal}\n onReload={() => setIframeReloadKey((key) => key + 1)}\n />\n )}\n </>\n );\n }\n\n // Inline mode (original behavior)\n\n // When the probe confirms the URL blocks embedding, show a warning card\n // instead of a blank iframe. Otherwise render the iframe — embeddable\n // sites (YouTube /embed/, Calendly, Vimeo, etc.) render live in the builder.\n //\n // The state is the gate. `useEmbedability` leaves \"idle\" untouched unless a\n // hint was wanted — an author on the admin canvas, or a host that installed a\n // probe — so \"blocked\" cannot occur on a live portal and no second condition\n // is needed.\n if (embedability === \"blocked\") {\n let displayUrl = normalizedUrl;\n try {\n const parsed = new URL(normalizedUrl);\n displayUrl = `${parsed.host}${parsed.pathname === \"/\" ? \"\" : parsed.pathname}`;\n } catch {\n // fall through with the normalized URL\n }\n const inlineHeight = isFullScreen\n ? \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\"\n : height;\n\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-destructive/40 bg-destructive/5 text-destructive border-2 border-dashed ${className ?? \"\"}`}\n {...props}\n style={{ height: inlineHeight }}\n >\n <div className=\"flex flex-col items-center gap-2 p-6 text-center\">\n <Globe className=\"h-12 w-12 opacity-50\" />\n <p className=\"text-sm font-medium\">{t(\"embed_blocked_title\")}</p>\n <p className=\"max-w-xs truncate text-xs opacity-75\">{displayUrl}</p>\n <p className=\"text-xs opacity-60\">{t(\"embed_blocked_hint\")}</p>\n </div>\n </div>\n );\n }\n\n const showInlineExpandAction =\n isVideoEmbed && allowFullscreen && !isFullScreen && !editMode;\n\n return (\n <>\n <div\n className={`relative w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className ?? \"\"}`}\n {...props}\n style={\n isFullScreen\n ? {\n height:\n \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\",\n }\n : undefined\n }\n >\n {showInlineExpandAction && (\n <div className=\"bg-background/90 absolute top-2 right-2 z-20 rounded-lg p-0.5 shadow-sm backdrop-blur-sm\">\n <HeaderIconButton\n Icon={Maximize2}\n label=\"Expand video\"\n onClick={(event) => {\n event.stopPropagation();\n setModalOpen(true);\n }}\n />\n </div>\n )}\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n title={title}\n width=\"100%\"\n style={isFullScreen ? { height: \"100%\" } : { height }}\n loading={loading}\n allow={iframeAllow}\n allowFullScreen={allowFullscreen}\n className={`rounded-${borderRadius} border-border border`}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads\"\n />\n {editMode && !isSelected && <div className=\"absolute inset-0 z-10\" />}\n </div>\n {modalOpen && (\n <EmbedModal\n key={`inline-modal-${iframeReloadKey}`}\n src={iframeSrc}\n title={title}\n allowFullscreen={allowFullscreen}\n iframeAllow={iframeAllow}\n iframeRef={modalIframeRef}\n onClose={closeModal}\n onReload={() => setIframeReloadKey((key) => key + 1)}\n />\n )}\n </>\n );\n}\n\n// Header icon button\n\ntype HeaderIconButtonProps = {\n Icon: LucideIcon;\n label: string;\n onClick: (e: React.MouseEvent) => void;\n};\n\nfunction HeaderIconButton({\n Icon,\n label,\n onClick,\n}: HeaderIconButtonProps): React.JSX.Element {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className=\"text-foreground/45 hover:text-foreground hover:bg-background flex size-7 items-center justify-center rounded-md transition-colors\"\n >\n <Icon className=\"size-3.5\" strokeWidth={2.25} />\n </button>\n );\n}\n\n// Modal\n\ntype EmbedModalProps = {\n src: string;\n title: string;\n allowFullscreen: boolean;\n iframeAllow: string | undefined;\n iframeRef: RefObject<HTMLIFrameElement | null>;\n onClose: () => void;\n onReload: () => void;\n};\n\nfunction EmbedModal({\n src,\n title,\n allowFullscreen,\n iframeAllow,\n iframeRef,\n onClose,\n onReload,\n}: EmbedModalProps): React.JSX.Element {\n const dialogRef = useRef<HTMLDivElement>(null);\n\n useDialogFocusRestore(dialogRef);\n\n // Portal to document.body so the fixed-position dialog isn't clipped by\n // a transformed widget container on the live canvas (CSS transforms make\n // descendants the containing block for `position: fixed`).\n return createPortal(\n <div\n ref={dialogRef}\n tabIndex={-1}\n className=\"fixed inset-0 z-[100] flex items-center justify-center p-4 focus:outline-none sm:p-8\"\n style={{\n background: \"color-mix(in oklch, var(--color-foreground) 80%, black)\",\n }}\n onClick={onClose}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div\n className=\"bg-background relative flex h-full max-h-[95vh] w-full max-w-[1400px] flex-col overflow-hidden rounded-2xl shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between gap-4 px-5 py-3\"\n style={{\n borderBottom:\n \"1px solid color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }}\n >\n <h3 className=\"text-foreground truncate text-sm font-semibold tracking-tight\">\n {title}\n </h3>\n <div className=\"flex shrink-0 items-center gap-1\">\n <HeaderIconButton\n Icon={RotateCw}\n label=\"Reload\"\n onClick={(e) => {\n e.stopPropagation();\n onReload();\n }}\n />\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"text-foreground/60 hover:text-foreground hover:bg-foreground/5 flex size-9 shrink-0 items-center justify-center rounded-full transition-colors\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n </div>\n <iframe\n ref={iframeRef}\n src={src}\n title={title}\n className=\"flex-1 border-0\"\n allow={iframeAllow}\n allowFullScreen={allowFullscreen}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads\"\n />\n </div>\n </div>,\n document.body,\n );\n}\n\n// Schema\n\nexport const embedWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"EmbedWidget\",\n displayName: \"Embed\",\n fields: [\n // Content\n {\n key: \"url\",\n label: \"URL\",\n type: \"text\",\n description: \"The URL of the external site to embed\",\n placeholder: \"https://example.com\",\n defaultValue: \"\",\n group: \"Content\",\n },\n {\n key: \"title\",\n label: \"Screen Reader Label\",\n type: \"text\",\n description:\n \"Describes the embed for screen readers and assistive tech. Not visible on the page.\",\n defaultValue: \"Embedded Content\",\n group: \"Content\",\n },\n\n // Display Mode\n {\n key: \"displayMode\",\n label: \"Display Mode\",\n type: \"buttonGroup\",\n description:\n \"Inline: iframe renders directly. Cover: shows a card that opens the embed in a full-screen modal.\",\n defaultValue: \"inline\",\n options: [\n { label: \"Inline\", value: \"inline\" },\n { label: \"Cover + Modal\", value: \"cover\" },\n ],\n group: \"Display Mode\",\n },\n\n // Cover fields — all gated behind displayMode=cover\n {\n key: \"coverResource\",\n label: \"Cover Image\",\n type: \"image\",\n description: \"Select the image shown before the embed opens\",\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverUseCustomUrl\",\n label: \"Use Custom URL\",\n type: \"boolean\",\n description: \"Enter a custom image URL instead of selecting media\",\n defaultValue: false,\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverImageUrl\",\n label: \"Cover Image URL\",\n type: \"text\",\n description: \"Direct URL to the cover image\",\n placeholder: \"https://example.com/cover.jpg\",\n defaultValue: \"\",\n group: \"Cover\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverUseCustomUrl\", value: true },\n ],\n },\n getHeightField({\n key: \"coverHeight\",\n label: \"Cover Height\",\n description: \"Height of the cover image area\",\n defaultValue: \"320px\",\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n }),\n\n // Cover header (optional)\n {\n key: \"coverShowHeader\",\n label: \"Show Card Header\",\n type: \"boolean\",\n description: \"Show the header with icon, title, and action buttons\",\n defaultValue: true,\n group: \"Cover Header\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverHeaderIcon\",\n label: \"Header Icon\",\n type: \"select\",\n description: \"Icon displayed in the colored badge on the left\",\n options: HEADER_ICON_OPTIONS,\n defaultValue: \"GraduationCap\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n },\n getColorField({\n key: \"coverHeaderIconColor\",\n label: \"Icon Badge Color\",\n description: \"Background color of the icon badge\",\n defaultValue: \"primary\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n }),\n {\n key: \"coverTitle\",\n label: \"Header Title\",\n type: \"text\",\n description:\n \"Title shown in the card header and modal (falls back to the widget Title if empty). Available even when the card header is hidden so the modal still has a meaningful title.\",\n defaultValue: \"\",\n group: \"Cover Header\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverMeta\",\n label: \"Meta Text\",\n type: \"text\",\n description:\n \"Small uppercase meta line below the title (e.g. 'APR 16 · COACHING THE HOSTESS')\",\n defaultValue: \"\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n },\n\n // Design\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the embed container\",\n defaultValue: \"md\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n group: \"Design\",\n }),\n {\n key: \"fullScreen\",\n label: \"Full Screen\",\n type: \"boolean\",\n description:\n \"Inline mode: fill the available space instead of a fixed height\",\n defaultValue: false,\n group: \"Design\",\n requiresKeyValue: { key: \"displayMode\", value: \"inline\" },\n },\n getHeightField({\n key: \"height\",\n label: \"Height\",\n description: \"Height of the inline embed iframe\",\n defaultValue: \"400px\",\n group: \"Design\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"inline\" },\n { key: \"fullScreen\", value: false },\n ],\n }),\n\n // Settings\n {\n key: \"allowFullscreen\",\n label: \"Allow Fullscreen\",\n type: \"boolean\",\n description:\n \"Allow embedded video/content to use fullscreen mode and show the inline expand control when available\",\n defaultValue: true,\n group: \"Settings\",\n },\n {\n key: \"loading\",\n label: \"Loading\",\n type: \"select\",\n description: \"When to load the embedded content (inline mode only)\",\n options: [\n { label: \"Lazy (on scroll)\", value: \"lazy\" },\n { label: \"Eager (immediately)\", value: \"eager\" },\n ],\n defaultValue: \"lazy\",\n group: \"Settings\",\n requiresKeyValue: { key: \"displayMode\", value: \"inline\" },\n },\n {\n key: \"shareViewerIdentity\",\n label: \"Share verified viewer identity with this embed\",\n type: \"boolean\",\n description:\n \"When the embedded page asks, send it a short-lived signed token naming the signed-in member and company, bound to the embed's origin. Turn on only for sites you trust with who is viewing.\",\n defaultValue: false,\n group: \"Settings\",\n },\n ],\n};\n"],"mappings":"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"}
@@ -421,6 +421,7 @@ function getVideoIframeAllow(allowFullscreen) {
421
421
  ...allowFullscreen ? ["fullscreen"] : []
422
422
  ].join("; ");
423
423
  }
424
+ const NON_VIDEO_IFRAME_ALLOW = "web-share";
424
425
  function getEmbedOrigin(url) {
425
426
  try {
426
427
  return new URL(url).origin;
@@ -656,7 +657,7 @@ function EmbedWidget({ url = "", appBridge, shareViewerIdentity = false, title =
656
657
  const { t } = useShellTranslation();
657
658
  const { normalizedUrl, isValidUrl, iframeSrc } = useEmbedUrl(url, publicId);
658
659
  const isVideoEmbed = isKnownVideoEmbedUrl(iframeSrc);
659
- const iframeAllow = isVideoEmbed ? getVideoIframeAllow(allowFullscreen) : void 0;
660
+ const iframeAllow = isVideoEmbed ? getVideoIframeAllow(allowFullscreen) : NON_VIDEO_IFRAME_ALLOW;
660
661
  useEmbedPostMessageBridge({
661
662
  iframeRef,
662
663
  normalizedUrl,
@@ -1265,4 +1266,4 @@ const embedWidgetPropertySchema = {
1265
1266
  //#endregion
1266
1267
  export { EmbedTokenUnavailableError as a, EmbedTokenMinterProvider as i, EmbedWidget_exports as n, embedWidgetPropertySchema as r, EmbedWidget as t };
1267
1268
 
1268
- //# sourceMappingURL=EmbedWidget-HcePfAaJ.mjs.map
1269
+ //# sourceMappingURL=EmbedWidget-sFKQDIP2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmbedWidget-sFKQDIP2.mjs","names":[],"sources":["../../core/src/embed-token-context.ts","../../../platform/app-bridge/src/errors.ts","../../../platform/app-bridge/src/protocol.ts","../../../platform/app-bridge/src/host.ts","../../../platform/app-bridge/src/session-token-api.ts","../../core/src/embed-framing-context.ts","../../widgets/src/lib/embed-token-handshake.ts","../../widgets/src/widgets/EmbedWidget.tsx"],"sourcesContent":["/**\n * How an Embed widget obtains a signed embed context token for a droplet.\n *\n * The token proves to the framed droplet which member is viewing it. Minting\n * needs the signed-in member's session, which only the host holds, so the host\n * supplies the minter and the widget never learns how it authenticates. A host\n * with no minter (admin preview, scaffolded portals) provides nothing, and the\n * widget answers a droplet's request with an error instead of a token.\n */\n\nimport { createContext, useContext } from \"react\";\n\nexport type EmbedToken = {\n token: string;\n /** ISO 8601 expiry of the token. */\n expiresAt: string;\n};\n\n/**\n * Thrown by a minter when there is no usable session for the viewer (expired\n * or missing sign-in). The widget tells the droplet `unavailable`, not a\n * mint failure.\n */\nexport class EmbedTokenUnavailableError extends Error {\n constructor(message = \"Embed token unavailable\") {\n super(message);\n this.name = \"EmbedTokenUnavailableError\";\n }\n}\n\n/**\n * Mints a fresh token bound to the origin of `embedUrl`. Rejects when there is\n * no signed-in member or the server refuses; never returns a cached token.\n */\nexport type EmbedTokenMinter = (embedUrl: string) => Promise<EmbedToken>;\n\nconst EmbedTokenMinterContext = createContext<EmbedTokenMinter | null>(null);\n\nexport const EmbedTokenMinterProvider = EmbedTokenMinterContext.Provider;\n\n/** The host's minter, or `null` when it does not offer one. */\nexport function useEmbedTokenMinter(): EmbedTokenMinter | null {\n return useContext(EmbedTokenMinterContext);\n}\n","export type FluidBridgeErrorCode =\n | \"configuration_error\"\n | \"host_unavailable\"\n | \"handshake_timeout\"\n | \"incompatible_version\"\n | \"token_mint_failed\"\n | \"unauthorized\"\n | \"forbidden_origin\"\n | \"invalid_context\"\n | \"request_timeout\"\n | \"fetch_target_not_allowed\"\n | \"network_error\"\n | \"failed_authentication\";\n\nexport class FluidBridgeError extends Error {\n readonly code: FluidBridgeErrorCode;\n readonly details?: unknown;\n\n constructor(code: FluidBridgeErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = \"FluidBridgeError\";\n this.code = code;\n this.details = details;\n }\n}\n\nexport class FluidBridgeConfigurationError extends FluidBridgeError {\n constructor(message: string, details?: unknown) {\n super(\"configuration_error\", message, details);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class FluidBridgeHostUnavailableError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host is unavailable\",\n details?: unknown,\n ) {\n super(\"host_unavailable\", message, details);\n this.name = \"HostUnavailableError\";\n }\n}\n\nexport class FluidBridgeHandshakeTimeoutError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host did not respond before the handshake timed out\",\n details?: unknown,\n ) {\n super(\"handshake_timeout\", message, details);\n this.name = \"HandshakeTimeoutError\";\n }\n}\n\nexport class FluidBridgeIncompatibleVersionError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge SDK is not compatible with the host\",\n details?: unknown,\n ) {\n super(\"incompatible_version\", message, details);\n this.name = \"IncompatibleVersionError\";\n }\n}\n\nexport class FluidBridgeTokenMintError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host could not mint a session token\",\n details?: unknown,\n ) {\n super(\"token_mint_failed\", message, details);\n this.name = \"TokenMintFailedError\";\n }\n}\n\nexport class FluidBridgeUnauthorizedError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge request is unauthorized\",\n details?: unknown,\n ) {\n super(\"unauthorized\", message, details);\n this.name = \"UnauthorizedError\";\n }\n}\n\nexport class FluidBridgeForbiddenOriginError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host origin is forbidden\",\n details?: unknown,\n ) {\n super(\"forbidden_origin\", message, details);\n this.name = \"ForbiddenOriginError\";\n }\n}\n\nexport class FluidBridgeInvalidContextError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge context is invalid\",\n details?: unknown,\n ) {\n super(\"invalid_context\", message, details);\n this.name = \"InvalidContextError\";\n }\n}\n\nexport class FluidBridgeRequestTimeoutError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge request timed out\",\n details?: unknown,\n ) {\n super(\"request_timeout\", message, details);\n this.name = \"RequestTimeoutError\";\n }\n}\n\nexport class FluidBridgeFetchTargetError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge fetch target is not allowed\",\n details?: unknown,\n ) {\n super(\"fetch_target_not_allowed\", message, details);\n this.name = \"FetchTargetNotAllowedError\";\n }\n}\n\nexport class FluidBridgeNetworkError extends FluidBridgeError {\n constructor(message = \"Fluid App Bridge fetch failed\", details?: unknown) {\n super(\"network_error\", message, details);\n this.name = \"NetworkError\";\n }\n}\n\nexport class FluidBridgeFailedAuthenticationError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge authentication failed\",\n details?: unknown,\n ) {\n super(\"failed_authentication\", message, details);\n this.name = \"FailedAuthenticationError\";\n }\n}\n","export const FLUID_BRIDGE_PROTOCOL_VERSION = \"2026-07\";\nexport const APP_BRIDGE_SDK_NAME = \"@fluid-app/droplet-bridge\";\nexport const APP_BRIDGE_SDK_VERSION = \"0.1.0\";\n\nexport const FluidBridgeMessageType = {\n SessionTokenRequest: \"FLUID::SESSION_TOKEN_REQUEST\",\n SessionTokenRespond: \"FLUID::SESSION_TOKEN_RESPOND\",\n ContextRequest: \"FLUID::CONTEXT_REQUEST\",\n ContextRespond: \"FLUID::CONTEXT_RESPOND\",\n FailedAuthentication: \"FLUID::ERROR::FAILED_AUTHENTICATION\",\n Unauthorized: \"FLUID::ERROR::UNAUTHORIZED\",\n IncompatibleVersion: \"FLUID::ERROR::INCOMPATIBLE_VERSION\",\n TokenMintFailed: \"FLUID::ERROR::TOKEN_MINT_FAILED\",\n InvalidContext: \"FLUID::ERROR::INVALID_CONTEXT\",\n} as const;\n\nexport type FluidBridgeMessageTypeValue =\n (typeof FluidBridgeMessageType)[keyof typeof FluidBridgeMessageType];\n\nexport type BridgeActorType = \"admin\" | \"member\" | \"customer\" | \"anonymous\";\nexport type BridgeEntryType =\n | \"droplet\"\n | \"drop_zone\"\n | \"mobile_embed\"\n | \"portal_embed\"\n | \"app_extension\";\n\nexport interface BridgeResource {\n type: string;\n id: string;\n}\n\nexport interface BridgeContext {\n protocol: typeof FLUID_BRIDGE_PROTOCOL_VERSION;\n app: { clientId: string };\n store: { subdomain: string; url: string; uuid?: string; name?: string };\n actor?: {\n type: BridgeActorType;\n uuid?: string;\n roles?: string[];\n permissions?: string[];\n memberType?: string;\n };\n entry: { type: BridgeEntryType; name?: string };\n resources: BridgeResource[];\n fetch: { allowedOrigins: string[] };\n sdk: { minVersion: string; recommendedVersion?: string };\n}\n\nexport interface BridgeEnvelope<TType extends string, TPayload> {\n id: string;\n type: TType;\n payload: TPayload;\n}\n","import {\n FLUID_BRIDGE_PROTOCOL_VERSION,\n FluidBridgeMessageType,\n type BridgeContext,\n type BridgeEnvelope,\n} from \"./protocol\";\nimport {\n FluidBridgeFailedAuthenticationError,\n FluidBridgeForbiddenOriginError,\n FluidBridgeIncompatibleVersionError,\n FluidBridgeInvalidContextError,\n FluidBridgeTokenMintError,\n FluidBridgeUnauthorizedError,\n type FluidBridgeErrorCode,\n} from \"./errors\";\n\ntype RequestPayload = {\n clientId: string;\n protocol: typeof FLUID_BRIDGE_PROTOCOL_VERSION;\n};\n\ntype HostErrorPayload = {\n code: FluidBridgeErrorCode;\n message: string;\n details?: unknown;\n};\n\nexport interface CreateFluidBridgeHostOptions {\n iframe: HTMLIFrameElement;\n appOrigin: string;\n clientId: string;\n getContext: () => BridgeContext | Promise<BridgeContext>;\n getSessionToken: (context: BridgeContext) => string | Promise<string>;\n targetWindow?: Window;\n}\n\nexport interface FluidBridgeHost {\n destroy: () => void;\n}\n\nexport function createFluidBridgeHost(\n options: CreateFluidBridgeHostOptions,\n): FluidBridgeHost {\n const targetWindow = options.targetWindow ?? window;\n const appOrigin = normalizeOrigin(options.appOrigin);\n\n const handleMessage = (event: MessageEvent<unknown>): void => {\n if (event.origin !== appOrigin) return;\n if (event.source !== options.iframe.contentWindow) return;\n if (!isBridgeEnvelope(event.data)) return;\n\n void respondToBridgeMessage(options, event.data, appOrigin);\n };\n\n targetWindow.addEventListener(\"message\", handleMessage);\n\n return {\n destroy: () => targetWindow.removeEventListener(\"message\", handleMessage),\n };\n}\n\nasync function respondToBridgeMessage(\n options: CreateFluidBridgeHostOptions,\n envelope: BridgeEnvelope<string, unknown>,\n appOrigin: string,\n): Promise<void> {\n const childWindow = options.iframe.contentWindow;\n if (!childWindow) return;\n\n try {\n validateRequestPayload(envelope.payload, options.clientId);\n\n switch (envelope.type) {\n case FluidBridgeMessageType.ContextRequest: {\n const context = await options.getContext();\n childWindow.postMessage(\n {\n id: envelope.id,\n type: FluidBridgeMessageType.ContextRespond,\n payload: context,\n } satisfies BridgeEnvelope<\n typeof FluidBridgeMessageType.ContextRespond,\n BridgeContext\n >,\n appOrigin,\n );\n return;\n }\n case FluidBridgeMessageType.SessionTokenRequest: {\n const context = await options.getContext();\n const sessionToken = await options.getSessionToken(context);\n if (sessionToken.length === 0) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge host returned an empty session token\",\n );\n }\n childWindow.postMessage(\n {\n id: envelope.id,\n type: FluidBridgeMessageType.SessionTokenRespond,\n payload: { sessionToken },\n } satisfies BridgeEnvelope<\n typeof FluidBridgeMessageType.SessionTokenRespond,\n { sessionToken: string }\n >,\n appOrigin,\n );\n return;\n }\n default:\n throw new FluidBridgeForbiddenOriginError(\n \"Fluid App Bridge host received an unsupported message type\",\n { type: envelope.type },\n );\n }\n } catch (error) {\n childWindow.postMessage(\n {\n id: envelope.id,\n type: errorTypeFor(error),\n payload: errorPayloadFor(error),\n } satisfies BridgeEnvelope<string, HostErrorPayload>,\n appOrigin,\n );\n }\n}\n\nfunction validateRequestPayload(\n value: unknown,\n clientId: string,\n): RequestPayload {\n if (typeof value !== \"object\" || value === null) {\n throw new FluidBridgeInvalidContextError(\n \"Fluid App Bridge request payload is invalid\",\n );\n }\n if (!(\"clientId\" in value) || value.clientId !== clientId) {\n throw new FluidBridgeFailedAuthenticationError(\n \"Fluid App Bridge request client ID does not match the host context\",\n );\n }\n if (\n !(\"protocol\" in value) ||\n value.protocol !== FLUID_BRIDGE_PROTOCOL_VERSION\n ) {\n throw new FluidBridgeIncompatibleVersionError();\n }\n return value as RequestPayload;\n}\n\nfunction isBridgeEnvelope(\n value: unknown,\n): value is BridgeEnvelope<string, unknown> {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n return (\n \"id\" in value &&\n \"type\" in value &&\n \"payload\" in value &&\n typeof value.id === \"string\" &&\n typeof value.type === \"string\"\n );\n}\n\nfunction errorTypeFor(error: unknown): string {\n if (error instanceof FluidBridgeFailedAuthenticationError) {\n return FluidBridgeMessageType.FailedAuthentication;\n }\n if (error instanceof FluidBridgeIncompatibleVersionError) {\n return FluidBridgeMessageType.IncompatibleVersion;\n }\n if (error instanceof FluidBridgeUnauthorizedError) {\n return FluidBridgeMessageType.Unauthorized;\n }\n if (error instanceof FluidBridgeTokenMintError) {\n return FluidBridgeMessageType.TokenMintFailed;\n }\n if (error instanceof FluidBridgeInvalidContextError) {\n return FluidBridgeMessageType.InvalidContext;\n }\n if (error instanceof FluidBridgeForbiddenOriginError) {\n return FluidBridgeMessageType.InvalidContext;\n }\n return FluidBridgeMessageType.TokenMintFailed;\n}\n\nfunction errorPayloadFor(error: unknown): HostErrorPayload {\n if (\n error instanceof Error &&\n \"code\" in error &&\n typeof error.code === \"string\"\n ) {\n return {\n code: error.code as FluidBridgeErrorCode,\n message: error.message,\n details: \"details\" in error ? error.details : undefined,\n };\n }\n return {\n code: \"token_mint_failed\",\n message: \"Fluid App Bridge host could not complete the request\",\n details: error,\n };\n}\n\nfunction normalizeOrigin(origin: string): string {\n return new URL(origin).origin;\n}\n","import {\n APP_BRIDGE_SDK_NAME,\n APP_BRIDGE_SDK_VERSION,\n FLUID_BRIDGE_PROTOCOL_VERSION,\n type BridgeContext,\n} from \"./protocol\";\nimport {\n FluidBridgeFailedAuthenticationError,\n FluidBridgeIncompatibleVersionError,\n FluidBridgeTokenMintError,\n FluidBridgeUnauthorizedError,\n} from \"./errors\";\n\nexport interface AppBridgeSessionTokenRequest {\n clientId: string;\n entry: BridgeContext[\"entry\"];\n resources?: BridgeContext[\"resources\"];\n allowedOrigins?: string[];\n sessionId?: string;\n}\n\nexport interface MintAppBridgeSessionTokenOptions {\n request: AppBridgeSessionTokenRequest;\n apiBaseUrl?: string;\n authToken?: string;\n fetch?: typeof fetch;\n}\n\ninterface SessionTokenSuccessResponse {\n session_token: string;\n}\n\ninterface LegacyErrorResponse {\n error?: {\n message?: string;\n details?: unknown;\n };\n}\n\nconst DEFAULT_SESSION_TOKEN_PATH = \"api/v2025-06/app_bridge/session_token\";\n\nexport async function mintAppBridgeSessionToken({\n request,\n apiBaseUrl,\n authToken,\n fetch: fetchImplementation = globalThis.fetch?.bind(globalThis),\n}: MintAppBridgeSessionTokenOptions): Promise<string> {\n if (!fetchImplementation) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge host requires a fetch implementation to mint session tokens\",\n );\n }\n\n const response = await fetchImplementation(\n resolveSessionTokenUrl(apiBaseUrl),\n {\n method: \"POST\",\n headers: sessionTokenHeaders(authToken),\n body: JSON.stringify(sessionTokenRequestBody(request)),\n },\n );\n\n const body: unknown = await response.json().catch(() => null);\n\n if (!response.ok) {\n throw errorForTokenResponse(response.status, body);\n }\n\n if (!isSessionTokenSuccessResponse(body) || body.session_token.length === 0) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge backend returned an invalid session token response\",\n { body },\n );\n }\n\n return body.session_token;\n}\n\nexport function sessionTokenRequestFromContext(\n context: BridgeContext,\n sessionId?: string,\n): AppBridgeSessionTokenRequest {\n return {\n clientId: context.app.clientId,\n entry: context.entry,\n resources: context.resources,\n allowedOrigins: context.fetch.allowedOrigins,\n ...(sessionId ? { sessionId } : {}),\n };\n}\n\nfunction sessionTokenHeaders(authToken: string | undefined): Headers {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n \"X-Fluid-App-Bridge-Protocol\": FLUID_BRIDGE_PROTOCOL_VERSION,\n \"X-Fluid-App-Bridge-Version\": APP_BRIDGE_SDK_VERSION,\n \"X-Fluid-App-Bridge-Sdk\": APP_BRIDGE_SDK_NAME,\n });\n\n if (authToken) {\n headers.set(\"Authorization\", `Bearer ${authToken}`);\n }\n\n return headers;\n}\n\nfunction sessionTokenRequestBody(\n request: AppBridgeSessionTokenRequest,\n): Record<string, unknown> {\n return {\n client_id: request.clientId,\n entry: request.entry,\n resources: request.resources ?? [],\n allowed_origins: request.allowedOrigins ?? [],\n ...(request.sessionId ? { session_id: request.sessionId } : {}),\n };\n}\n\nfunction resolveSessionTokenUrl(apiBaseUrl: string | undefined): string {\n if (!apiBaseUrl) {\n return `/${DEFAULT_SESSION_TOKEN_PATH}`;\n }\n return new URL(\n DEFAULT_SESSION_TOKEN_PATH,\n ensureTrailingSlash(apiBaseUrl),\n ).toString();\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.endsWith(\"/\") ? url : `${url}/`;\n}\n\nfunction isSessionTokenSuccessResponse(\n value: unknown,\n): value is SessionTokenSuccessResponse {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"session_token\" in value &&\n typeof value.session_token === \"string\"\n );\n}\n\nfunction errorForTokenResponse(status: number, body: unknown): Error {\n const errorBody = isLegacyErrorResponse(body) ? body.error : undefined;\n const message =\n errorBody?.message ??\n \"Fluid App Bridge backend rejected the session-token request\";\n const details = errorBody?.details ?? body;\n\n if (status === 401) {\n return new FluidBridgeUnauthorizedError(message, details);\n }\n if (status === 403) {\n return new FluidBridgeFailedAuthenticationError(message, details);\n }\n if (status === 422) {\n return new FluidBridgeIncompatibleVersionError(message, details);\n }\n return new FluidBridgeTokenMintError(message, details);\n}\n\nfunction isLegacyErrorResponse(value: unknown): value is LegacyErrorResponse {\n return typeof value === \"object\" && value !== null && \"error\" in value;\n}\n","/**\n * How an Embed widget asks whether a site will let itself be framed.\n *\n * The check needs a server: reading `X-Frame-Options` and `frame-ancestors`\n * means fetching the target, which a browser cannot do cross-origin. Fluid\n * Admin answers it with a Next route at `/api/embed-can-frame`, and the widget\n * used to call that path directly.\n *\n * That hard-coded path is why the same widget behaves differently depending on\n * who renders it. In admin the probe answers and a refused site gets an\n * explanatory card naming the URL. Anywhere else — Mist's portal preview, a\n * scaffolded portal — the path 404s, the state falls back to \"unknown\", and the\n * author gets a silently empty box that looks identical to a bug in the host.\n *\n * So the host supplies the probe. Admin keeps its route, Mist answers from its\n * main process where no CSP or CORS applies, and a host with no way to check\n * simply provides nothing and gets today's behaviour.\n */\n\nimport { createContext, useContext } from \"react\";\n\n/**\n * Resolves true/false when the answer is known, or `null` when it cannot be\n * determined — a failed request, a host without a probe, an aborted check.\n *\n * `null` is not \"blocked\". The verdict is a hint shown to an author, never a\n * gate: the iframe is attempted regardless and the browser has the last word.\n */\nexport type EmbedFramingProbe = (\n url: string,\n signal: AbortSignal,\n) => Promise<boolean | null>;\n\nconst EmbedFramingProbeContext = createContext<EmbedFramingProbe | null>(null);\n\nexport const EmbedFramingProbeProvider = EmbedFramingProbeContext.Provider;\n\n/**\n * The host's probe, or `null` when it does not offer one.\n *\n * Deliberately not throwing on a missing provider, unlike the domain API hooks:\n * an Embed widget renders perfectly well without an embeddability hint, and\n * every host that predates this context has none.\n */\nexport function useEmbedFramingProbe(): EmbedFramingProbe | null {\n return useContext(EmbedFramingProbeContext);\n}\n","/**\n * The postMessage handshake a framed droplet uses to get a signed embed\n * context token from the Portal.\n *\n * The token never travels in the URL (it would land in logs and referrers).\n * The droplet asks, the Portal checks who is asking, and answers only to that\n * origin:\n *\n * iframe -> parent { type: \"fluid:embed-token:request\", nonce }\n * parent -> iframe { type: \"fluid:embed-token\", nonce, token, expiresAt }\n * or { type: \"fluid:embed-token:error\", nonce, reason }\n *\n * Every request mints a new token; the droplet asks again for each sensitive\n * action rather than holding one.\n */\n\nimport {\n EmbedTokenUnavailableError,\n type EmbedTokenMinter,\n} from \"@fluid-app/portal-core/embed-token-context\";\n\nexport const EMBED_TOKEN_REQUEST = \"fluid:embed-token:request\";\nexport const EMBED_TOKEN_RESPONSE = \"fluid:embed-token\";\nexport const EMBED_TOKEN_ERROR = \"fluid:embed-token:error\";\n\nexport type EmbedTokenErrorReason =\n | \"unavailable\"\n | \"rate_limited\"\n | \"mint_failed\";\n\nconst MAX_NONCE_LENGTH = 128;\nexport const EMBED_TOKEN_MIN_INTERVAL_MS = 1000;\n\ntype MessageLike = {\n source: unknown;\n origin: string;\n data: unknown;\n};\n\nexport type EmbedTokenHandlerOptions = {\n /** The iframe's current window, or null when it is gone. */\n getFrameWindow: () => Window | null;\n /** Origin of the iframe src. Only this origin is answered. */\n expectedOrigin: string;\n /** The URL the Portal framed; the server binds the token to its origin. */\n embedUrl: string;\n /** Null when no signed-in member / no host minter is available. */\n mint: EmbedTokenMinter | null;\n now?: () => number;\n minIntervalMs?: number;\n};\n\nfunction parseRequest(data: unknown): { nonce: string } | null {\n if (typeof data !== \"object\" || data === null) return null;\n const { type, nonce } = data as { type?: unknown; nonce?: unknown };\n if (type !== EMBED_TOKEN_REQUEST) return null;\n if (typeof nonce !== \"string\") return null;\n if (nonce.length === 0 || nonce.length > MAX_NONCE_LENGTH) return null;\n return { nonce };\n}\n\nexport function createEmbedTokenHandler({\n getFrameWindow,\n expectedOrigin,\n embedUrl,\n mint,\n now = Date.now,\n minIntervalMs = EMBED_TOKEN_MIN_INTERVAL_MS,\n}: EmbedTokenHandlerOptions): (event: MessageLike) => void {\n let lastRequestAt = Number.NEGATIVE_INFINITY;\n\n return (event) => {\n const frameWindow = getFrameWindow();\n if (!frameWindow) return;\n if (event.source !== frameWindow) return;\n if (event.origin !== expectedOrigin) return;\n\n const request = parseRequest(event.data);\n if (!request) return;\n const { nonce } = request;\n\n const reply = (message: Record<string, unknown>) => {\n // Only detects the iframe going away. It cannot detect navigation:\n // contentWindow is the same object across navigations. What keeps a\n // token from a later page is the pinned target origin below.\n if (getFrameWindow() !== frameWindow) return;\n frameWindow.postMessage({ ...message, nonce }, expectedOrigin);\n };\n const fail = (reason: EmbedTokenErrorReason) =>\n reply({ type: EMBED_TOKEN_ERROR, reason });\n\n const at = now();\n if (at - lastRequestAt < minIntervalMs) return fail(\"rate_limited\");\n lastRequestAt = at;\n\n if (!mint) return fail(\"unavailable\");\n\n mint(embedUrl).then(\n ({ token, expiresAt }) =>\n reply({ type: EMBED_TOKEN_RESPONSE, token, expiresAt }),\n (error: unknown) =>\n fail(\n error instanceof EmbedTokenUnavailableError\n ? \"unavailable\"\n : \"mint_failed\",\n ),\n );\n };\n}\n\n/**\n * Which iframes take part. Cover mode only ever mounts its iframe inside the\n * modal, and that one uses the primary ref; the inline modal has its own ref.\n * Only embeds that opted in to sharing the viewer's identity, or declare an\n * app bridge client, and never while the builder is editing.\n */\nexport function embedTokenHandshakeTargets({\n shareViewerIdentity,\n hasAppBridgeClient,\n editMode,\n modalOpen,\n}: {\n shareViewerIdentity: boolean;\n hasAppBridgeClient: boolean;\n editMode: boolean;\n modalOpen: boolean;\n}): { primary: boolean; modal: boolean } {\n const answers = (shareViewerIdentity || hasAppBridgeClient) && !editMode;\n return { primary: answers, modal: answers && modalOpen };\n}\n\n/**\n * Listens on `eventTarget` and returns the cleanup. Once cleaned up, a mint\n * still in flight never replies.\n */\nexport function attachEmbedTokenHandshake({\n eventTarget,\n getFrameWindow,\n ...options\n}: Omit<EmbedTokenHandlerOptions, \"now\" | \"minIntervalMs\"> & {\n eventTarget: Pick<Window, \"addEventListener\" | \"removeEventListener\">;\n}): () => void {\n let active = true;\n const handler = createEmbedTokenHandler({\n ...options,\n getFrameWindow: () => (active ? getFrameWindow() : null),\n });\n const listener = (event: MessageEvent) => handler(event);\n eventTarget.addEventListener(\"message\", listener);\n return () => {\n active = false;\n eventTarget.removeEventListener(\"message\", listener);\n };\n}\n","import {\n APP_BRIDGE_SDK_VERSION,\n FLUID_BRIDGE_PROTOCOL_VERSION,\n createFluidBridgeHost,\n mintAppBridgeSessionToken,\n sessionTokenRequestFromContext,\n type BridgeContext,\n type BridgeEntryType,\n type BridgeResource,\n} from \"@fluid-app/droplet-bridge\";\nimport {\n Bell,\n BookmarkIcon,\n BookOpen,\n Calendar,\n ExternalLink,\n Gift,\n Globe,\n GraduationCap,\n Heart,\n Maximize2,\n RotateCw,\n ShoppingBag,\n Sparkles,\n Star,\n Trophy,\n User,\n Video,\n X,\n Zap,\n type LucideIcon,\n} from \"lucide-react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type RefObject,\n} from \"react\";\nimport type React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n getBorderRadiusField,\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport {\n useEmbedFramingProbe,\n type EmbedFramingProbe,\n} from \"@fluid-app/portal-core/embed-framing-context\";\nimport { useEmbedTokenMinter } from \"@fluid-app/portal-core/embed-token-context\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n ShareableItem,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getBorderWidthField,\n getBorderColorField,\n getColorField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport {\n attachEmbedTokenHandshake,\n embedTokenHandshakeTargets,\n} from \"../lib/embed-token-handshake\";\nimport { useRepUser } from \"../contexts/RepUserContext\";\nimport { useWidgetRenderState } from \"../contexts/WidgetRenderStateContext\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\n\ntype EmbedWidgetMessage = {\n type: \"OPEN_FULL_SCREEN_WEBVIEW\";\n url: string;\n};\n\nexport type EmbedWidgetAppBridgeConfig = {\n clientId?: string;\n appOrigins?: string[];\n entryType?: BridgeEntryType;\n entryName?: string;\n resources?: BridgeResource[];\n};\n\ntype DisplayMode = \"inline\" | \"cover\";\n\ntype EmbedUrlState = {\n normalizedUrl: string;\n isValidUrl: boolean;\n iframeSrc: string;\n};\n\nfunction isValidHttpUrl(urlString: string): boolean {\n try {\n const parsed = new URL(urlString);\n return parsed.protocol === \"https:\" || parsed.protocol === \"http:\";\n } catch {\n return false;\n }\n}\n\nfunction useEmbedUrl(url: string, publicId: string | undefined): EmbedUrlState {\n return useMemo(() => {\n const normalizedUrl =\n url && (url.startsWith(\"http://\") || url.startsWith(\"https://\"))\n ? url\n : url\n ? `https://${url}`\n : \"\";\n\n let isValidUrl = false;\n if (normalizedUrl) {\n try {\n const parsed = new URL(normalizedUrl);\n isValidUrl =\n (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") &&\n (parsed.hostname.includes(\".\") || parsed.hostname === \"localhost\");\n } catch {\n // invalid URL\n }\n }\n\n if (!isValidUrl) {\n return { normalizedUrl, isValidUrl, iframeSrc: normalizedUrl };\n }\n\n const urlObj = new URL(normalizedUrl);\n applyInlineVideoEmbedDefaults(urlObj);\n if (publicId) urlObj.searchParams.set(\"public_id\", publicId);\n return { normalizedUrl, isValidUrl, iframeSrc: urlObj.toString() };\n }, [url, publicId]);\n}\n\nfunction isYouTubeHost(hostname: string): boolean {\n const normalized = hostname.replace(/^www\\./, \"\").toLowerCase();\n return (\n normalized === \"youtube.com\" ||\n normalized.endsWith(\".youtube.com\") ||\n normalized === \"youtube-nocookie.com\" ||\n normalized.endsWith(\".youtube-nocookie.com\") ||\n normalized === \"youtu.be\"\n );\n}\n\nfunction isVimeoHost(hostname: string): boolean {\n const normalized = hostname.replace(/^www\\./, \"\").toLowerCase();\n return (\n normalized === \"vimeo.com\" ||\n normalized.endsWith(\".vimeo.com\") ||\n normalized === \"player.vimeo.com\"\n );\n}\n\nfunction isKnownVideoEmbedUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return isYouTubeHost(parsed.hostname) || isVimeoHost(parsed.hostname);\n } catch {\n return false;\n }\n}\n\nfunction applyInlineVideoEmbedDefaults(url: URL): void {\n if (!isYouTubeHost(url.hostname) && !isVimeoHost(url.hostname)) return;\n url.searchParams.set(\"autoplay\", \"0\");\n url.searchParams.set(\"playsinline\", \"1\");\n}\n\nfunction getVideoIframeAllow(allowFullscreen: boolean): string {\n return [\n \"clipboard-write\",\n \"encrypted-media\",\n \"picture-in-picture\",\n \"web-share\",\n ...(allowFullscreen ? [\"fullscreen\"] : []),\n ].join(\"; \");\n}\n\nconst NON_VIDEO_IFRAME_ALLOW = \"web-share\";\n\ntype UseEmbedPostMessageBridgeProps = {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n normalizedUrl: string;\n isValidUrl: boolean;\n editMode: boolean;\n};\n\nfunction getEmbedOrigin(url: string): string | null {\n try {\n return new URL(url).origin;\n } catch {\n return null;\n }\n}\n\nfunction useEmbedPostMessageBridge({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n editMode,\n}: UseEmbedPostMessageBridgeProps): void {\n useEffect(() => {\n if (!isValidUrl || editMode) return;\n\n const expectedOrigin = new URL(normalizedUrl).origin;\n\n function handleMessage(event: MessageEvent) {\n if (event.origin !== expectedOrigin) return;\n if (event.source !== iframeRef.current?.contentWindow) return;\n\n let data: unknown;\n if (typeof event.data === \"string\") {\n try {\n data = JSON.parse(event.data);\n } catch {\n return;\n }\n } else {\n data = event.data;\n }\n\n if (\n typeof data === \"object\" &&\n data !== null &&\n \"type\" in data &&\n (data as EmbedWidgetMessage).type === \"OPEN_FULL_SCREEN_WEBVIEW\"\n ) {\n const messageUrl = (data as EmbedWidgetMessage).url;\n if (messageUrl && isValidHttpUrl(messageUrl)) {\n window.open(messageUrl, \"_blank\", \"noopener,noreferrer\");\n }\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [iframeRef, normalizedUrl, isValidUrl, editMode]);\n}\n\n/**\n * Answers a droplet's `fluid:embed-token:request` with a freshly minted\n * context token. Only droplet embeds (those declaring an app bridge client)\n * take part; every other embed never sees the message handled.\n */\nfunction useEmbedTokenHandshake({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n enabled,\n}: {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n normalizedUrl: string;\n isValidUrl: boolean;\n enabled: boolean;\n}): void {\n const mint = useEmbedTokenMinter();\n\n useEffect(() => {\n if (!enabled || !isValidUrl) return;\n const expectedOrigin = getEmbedOrigin(normalizedUrl);\n if (!expectedOrigin) return;\n\n return attachEmbedTokenHandshake({\n eventTarget: window,\n getFrameWindow: () => iframeRef.current?.contentWindow ?? null,\n expectedOrigin,\n embedUrl: normalizedUrl,\n mint,\n });\n }, [enabled, iframeRef, isValidUrl, mint, normalizedUrl]);\n}\n\ntype EmbedabilityState = \"idle\" | \"checking\" | \"embeddable\" | \"blocked\";\n\n/**\n * The default probe: Fluid Admin's own route, reached relatively.\n *\n * Correct only where that route exists. Everywhere else it 404s and the answer\n * is \"unknown\" — which is why hosts outside admin supply their own through\n * {@link useEmbedFramingProbe} rather than inheriting this.\n */\nconst probeViaAdminRoute: EmbedFramingProbe = async (url, signal) => {\n const res = await fetch(\n `/api/embed-can-frame?url=${encodeURIComponent(url)}`,\n { signal },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { canFrame?: boolean } | null;\n return typeof data?.canFrame === \"boolean\" ? data.canFrame : null;\n};\n\nfunction useEmbedability(\n normalizedUrl: string,\n isValidUrl: boolean,\n editMode: boolean,\n): EmbedabilityState {\n const [state, setState] = useState<EmbedabilityState>(\"idle\");\n const hostProbe = useEmbedFramingProbe();\n\n // Who is the audience for a \"this site refuses to be embedded\" card? An\n // author, never a member — so it must not appear on a live portal.\n //\n // `editMode` alone was the wrong test for that. It is true on the admin\n // canvas and FALSE in Mist's portal preview, which renders read-only, so the\n // one host that supplies a probe was the one host that never ran it. A\n // supplied probe is itself the signal: a host installs one precisely because\n // it wants the diagnosis. The live portal installs none and falls back to the\n // admin route, which 404s there and yields \"cannot tell\".\n const wantsEmbedabilityHint = editMode || hostProbe !== null;\n\n useEffect(() => {\n if (!wantsEmbedabilityHint || !isValidUrl) {\n setState(\"idle\");\n return;\n }\n setState(\"checking\");\n const controller = new AbortController();\n const probe = hostProbe ?? probeViaAdminRoute;\n const timer = setTimeout(() => {\n probe(normalizedUrl, controller.signal)\n .then((canFrame) => {\n if (controller.signal.aborted) return;\n // null is \"could not tell\", which must not read as \"blocked\" — the\n // iframe is still attempted and the browser decides.\n setState(\n canFrame === null ? \"idle\" : canFrame ? \"embeddable\" : \"blocked\",\n );\n })\n .catch(() => {\n if (!controller.signal.aborted) {\n setState(\"idle\");\n }\n });\n }, 400);\n\n return () => {\n controller.abort();\n clearTimeout(timer);\n };\n }, [normalizedUrl, isValidUrl, wantsEmbedabilityHint, hostProbe]);\n\n return state;\n}\n\nfunction useModalBodyScrollLock(isOpen: boolean): void {\n useEffect(() => {\n if (!isOpen) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [isOpen]);\n}\n\nfunction useModalEscapeClose(isOpen: boolean, onClose: () => void): void {\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, onClose]);\n}\n\nfunction useDialogFocusRestore(dialogRef: RefObject<HTMLElement | null>): void {\n useEffect(() => {\n const previouslyFocused =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n dialogRef.current?.focus();\n return () => {\n previouslyFocused?.focus();\n };\n }, [dialogRef]);\n}\n\n// header icon registry\n\nconst HEADER_ICON_MAP: Record<string, LucideIcon> = {\n GraduationCap,\n Video,\n BookOpen,\n Globe,\n User,\n Star,\n Heart,\n Trophy,\n Sparkles,\n Zap,\n Gift,\n ShoppingBag,\n Bell,\n Calendar,\n Bookmark: BookmarkIcon,\n};\n\nconst HEADER_ICON_OPTIONS: Array<{ label: string; value: string }> = [\n { label: \"Graduation Cap\", value: \"GraduationCap\" },\n { label: \"Video\", value: \"Video\" },\n { label: \"Book\", value: \"BookOpen\" },\n { label: \"Globe\", value: \"Globe\" },\n { label: \"User\", value: \"User\" },\n { label: \"Star\", value: \"Star\" },\n { label: \"Heart\", value: \"Heart\" },\n { label: \"Trophy\", value: \"Trophy\" },\n { label: \"Sparkles\", value: \"Sparkles\" },\n { label: \"Zap / Lightning\", value: \"Zap\" },\n { label: \"Gift\", value: \"Gift\" },\n { label: \"Shopping Bag\", value: \"ShoppingBag\" },\n { label: \"Bell\", value: \"Bell\" },\n { label: \"Calendar\", value: \"Calendar\" },\n { label: \"Bookmark\", value: \"Bookmark\" },\n];\n\nconst getHeaderIcon = (name: string | undefined): LucideIcon => {\n if (!name) return GraduationCap;\n return HEADER_ICON_MAP[name] ?? GraduationCap;\n};\n\ntype EmbedWidgetProps = ComponentProps<\"div\"> & {\n url?: string;\n appBridge?: EmbedWidgetAppBridgeConfig;\n /** Answer the embed's requests for a signed viewer identity token. */\n shareViewerIdentity?: boolean;\n title?: string;\n height?: string;\n fullScreen?: boolean;\n allowFullscreen?: boolean;\n loading?: \"eager\" | \"lazy\";\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n // Builder render state is provided by WidgetRenderStateContext.\n editMode?: boolean;\n // Builder render state is provided by WidgetRenderStateContext.\n isSelected?: boolean;\n\n // Cover-mode additions (all optional — inline mode ignores these)\n displayMode?: DisplayMode;\n coverResource?: ShareableItem;\n coverUseCustomUrl?: boolean;\n coverImageUrl?: string;\n coverTitle?: string;\n coverMeta?: string;\n coverShowHeader?: boolean;\n coverHeaderIcon?: string;\n coverHeaderIconColor?: ColorOptions;\n coverHeight?: string;\n};\n\nexport function EmbedWidget({\n url = \"\",\n appBridge,\n shareViewerIdentity = false,\n title = \"Embedded Content\",\n height = \"400px\",\n fullScreen = false,\n allowFullscreen = true,\n loading = \"lazy\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n editMode: _editMode,\n isSelected: _isSelected,\n\n displayMode = \"inline\",\n coverResource,\n coverUseCustomUrl = false,\n coverImageUrl = \"\",\n coverTitle = \"\",\n coverMeta = \"\",\n coverShowHeader = true,\n coverHeaderIcon = \"GraduationCap\",\n coverHeaderIconColor = \"primary\",\n coverHeight = \"320px\",\n\n className,\n ...props\n}: EmbedWidgetProps): React.JSX.Element {\n const renderState = useWidgetRenderState();\n const editMode = _editMode ?? renderState.editMode;\n const isSelected = _isSelected ?? renderState.isSelected;\n const isFullScreen = fullScreen;\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const modalIframeRef = useRef<HTMLIFrameElement>(null);\n const repUser = useRepUser();\n const publicId = repUser?.publicId;\n const { data: store } = useOptionalStore();\n\n const [modalOpen, setModalOpen] = useState(false);\n const [coverReloadKey, setCoverReloadKey] = useState(0);\n const [iframeReloadKey, setIframeReloadKey] = useState(0);\n\n const closeModal = useCallback(() => setModalOpen(false), []);\n const { t } = useShellTranslation();\n\n const { normalizedUrl, isValidUrl, iframeSrc } = useEmbedUrl(url, publicId);\n const isVideoEmbed = isKnownVideoEmbedUrl(iframeSrc);\n const iframeAllow = isVideoEmbed\n ? getVideoIframeAllow(allowFullscreen)\n : NON_VIDEO_IFRAME_ALLOW;\n useEmbedPostMessageBridge({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n editMode,\n });\n\n const appBridgeClientId = appBridge?.clientId;\n const handshakeTargets = embedTokenHandshakeTargets({\n shareViewerIdentity,\n hasAppBridgeClient: Boolean(appBridge?.clientId),\n editMode,\n modalOpen,\n });\n useEmbedTokenHandshake({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n enabled: handshakeTargets.primary,\n });\n useEmbedTokenHandshake({\n iframeRef: modalIframeRef,\n normalizedUrl,\n isValidUrl,\n enabled: handshakeTargets.modal,\n });\n const appBridgeEntryType = appBridge?.entryType;\n const appBridgeEntryName = appBridge?.entryName;\n const appBridgeResources = appBridge?.resources;\n const appBridgeAppOrigins = appBridge?.appOrigins;\n\n const appBridgeContext = useMemo<BridgeContext | null>(() => {\n if (!appBridgeClientId || !store || !isValidUrl) return null;\n\n return {\n protocol: FLUID_BRIDGE_PROTOCOL_VERSION,\n app: { clientId: appBridgeClientId },\n store: {\n subdomain: store.subdomain,\n url: `https://${store.subdomain}.fluid.app`,\n name: store.name,\n },\n ...(repUser\n ? {\n actor: {\n type: \"member\" as const,\n ...(repUser.publicId ? { uuid: repUser.publicId } : {}),\n roles: [],\n permissions: [],\n },\n }\n : {}),\n entry: {\n type: appBridgeEntryType ?? \"portal_embed\",\n name: appBridgeEntryName ?? title,\n },\n resources: appBridgeResources ?? [],\n fetch: {\n allowedOrigins: [\n getEmbedOrigin(normalizedUrl),\n ...(appBridgeAppOrigins ?? []),\n ].filter((origin): origin is string => Boolean(origin)),\n },\n sdk: { minVersion: APP_BRIDGE_SDK_VERSION },\n };\n }, [\n appBridgeAppOrigins,\n appBridgeClientId,\n appBridgeEntryName,\n appBridgeEntryType,\n appBridgeResources,\n isValidUrl,\n normalizedUrl,\n repUser,\n store,\n title,\n ]);\n const appBridgeContextRef = useRef<BridgeContext | null>(null);\n const appBridgeContextReady = appBridgeContext !== null;\n\n useEffect(() => {\n appBridgeContextRef.current = appBridgeContext;\n }, [appBridgeContext]);\n\n const getAppBridgeContext = useCallback(() => {\n if (!appBridgeContextRef.current) {\n throw new Error(\"App Bridge context is unavailable\");\n }\n return appBridgeContextRef.current;\n }, []);\n\n const getAppBridgeSessionToken = useCallback(\n (bridgeContext: BridgeContext) =>\n mintAppBridgeSessionToken({\n request: sessionTokenRequestFromContext(bridgeContext),\n }),\n [],\n );\n\n useEffect(() => {\n if (!appBridgeClientId || !appBridgeContextReady || editMode) return;\n\n const iframe = iframeRef.current;\n const appOrigin = getEmbedOrigin(normalizedUrl);\n if (!iframe || !appOrigin) return;\n\n const host = createFluidBridgeHost({\n iframe,\n appOrigin,\n clientId: appBridgeClientId,\n getContext: getAppBridgeContext,\n getSessionToken: getAppBridgeSessionToken,\n });\n\n return () => host.destroy();\n }, [\n appBridgeClientId,\n appBridgeContextReady,\n editMode,\n getAppBridgeContext,\n getAppBridgeSessionToken,\n iframeReloadKey,\n modalOpen,\n normalizedUrl,\n ]);\n useModalBodyScrollLock(modalOpen);\n useModalEscapeClose(modalOpen, closeModal);\n const embedability = useEmbedability(\n normalizedUrl,\n isValidUrl,\n editMode && displayMode !== \"cover\",\n );\n\n // Empty/invalid URL states\n\n if (!url || !isValidUrl) {\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${className ?? \"\"}`}\n {...props}\n style={\n isFullScreen\n ? {\n height:\n \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\",\n }\n : { height: displayMode === \"cover\" ? coverHeight : height }\n }\n >\n <div className=\"flex flex-col items-center gap-2 p-6 text-center\">\n <Globe className=\"size-12 opacity-50\" />\n <p className=\"text-sm font-medium\">\n Enter a URL to embed external content\n </p>\n <p className=\"text-xs opacity-75\">\n Configure the URL in the properties panel\n </p>\n </div>\n </div>\n );\n }\n\n // Cover mode\n\n if (displayMode === \"cover\") {\n const resolvedCoverImage = coverUseCustomUrl\n ? coverImageUrl\n : coverResource?.imageUrl || coverResource?.image_url || coverImageUrl;\n\n const effectiveTitle = coverTitle || title;\n const HeaderIcon = getHeaderIcon(coverHeaderIcon);\n\n const handleOpenModal = () => {\n if (editMode) return;\n setModalOpen(true);\n };\n\n const handleReload = () => {\n if (editMode) return;\n setCoverReloadKey((key) => key + 1);\n };\n\n const handleOpenNewTab = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (editMode) return;\n window.open(iframeSrc, \"_blank\", \"noopener,noreferrer\");\n };\n\n return (\n <>\n <div\n className={`relative w-full overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-background ${className ?? \"\"}`}\n style={{\n boxShadow:\n \"0 1px 2px color-mix(in oklch, var(--color-foreground) 5%, transparent), 0 12px 32px -16px color-mix(in oklch, var(--color-foreground) 10%, transparent)\",\n }}\n {...props}\n >\n {/* Inset hairline ring */}\n <div\n aria-hidden=\"true\"\n className={`pointer-events-none absolute inset-0 z-[1] rounded-${borderRadius}`}\n style={{\n boxShadow:\n \"inset 0 0 0 1px color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }}\n />\n {coverShowHeader && (\n <div className=\"relative z-[2] flex items-center gap-3 px-5 py-3\">\n <span\n aria-hidden=\"true\"\n className={`text-${coverHeaderIconColor}-foreground flex size-7 shrink-0 items-center justify-center rounded-${borderRadius}`}\n style={{\n background: `linear-gradient(135deg, color-mix(in oklch, var(--color-${coverHeaderIconColor}) 75%, white 25%) 0%, var(--color-${coverHeaderIconColor}) 100%)`,\n boxShadow: `\n inset 0 1px 0 rgba(255,255,255,0.25),\n inset 0 -1px 0 rgba(0,0,0,0.08),\n 0 1px 2px color-mix(in oklch, var(--color-${coverHeaderIconColor}) 25%, transparent)\n `,\n }}\n >\n <HeaderIcon className=\"size-3.5\" strokeWidth={2.25} />\n </span>\n\n <div className=\"min-w-0 flex-1\">\n {effectiveTitle && (\n <h3 className=\"text-foreground truncate text-[15px] leading-tight font-semibold tracking-tight\">\n {effectiveTitle}\n </h3>\n )}\n {coverMeta && (\n <p className=\"text-foreground/40 mt-0.5 truncate text-[11px] font-medium tracking-[0.08em] uppercase\">\n {coverMeta}\n </p>\n )}\n </div>\n\n <div className=\"bg-foreground/5 flex shrink-0 items-center rounded-lg p-0.5\">\n <HeaderIconButton\n Icon={RotateCw}\n label=\"Reload\"\n onClick={(e) => {\n e.stopPropagation();\n handleReload();\n }}\n />\n <HeaderIconButton\n Icon={Maximize2}\n label=\"Open\"\n onClick={(e) => {\n e.stopPropagation();\n handleOpenModal();\n }}\n />\n <HeaderIconButton\n Icon={ExternalLink}\n label=\"Open in new tab\"\n onClick={handleOpenNewTab}\n />\n </div>\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={handleOpenModal}\n disabled={editMode}\n className={`relative block w-full overflow-hidden ${editMode ? \"cursor-default\" : \"cursor-pointer\"}`}\n style={{ height: coverHeight }}\n aria-label={`Open ${effectiveTitle || title}`}\n >\n {resolvedCoverImage ? (\n <img\n key={`cover-${coverReloadKey}`}\n src={resolvedCoverImage}\n alt={effectiveTitle || title}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"bg-muted flex h-full w-full items-center justify-center\">\n <Globe className=\"text-muted-foreground/40 size-16\" />\n </div>\n )}\n </button>\n {editMode && !isSelected && <div className=\"absolute inset-0 z-10\" />}\n </div>\n\n {modalOpen && (\n <EmbedModal\n key={`modal-${iframeReloadKey}`}\n src={iframeSrc}\n title={effectiveTitle || title}\n allowFullscreen={allowFullscreen}\n iframeAllow={iframeAllow}\n iframeRef={iframeRef}\n onClose={closeModal}\n onReload={() => setIframeReloadKey((key) => key + 1)}\n />\n )}\n </>\n );\n }\n\n // Inline mode (original behavior)\n\n // When the probe confirms the URL blocks embedding, show a warning card\n // instead of a blank iframe. Otherwise render the iframe — embeddable\n // sites (YouTube /embed/, Calendly, Vimeo, etc.) render live in the builder.\n //\n // The state is the gate. `useEmbedability` leaves \"idle\" untouched unless a\n // hint was wanted — an author on the admin canvas, or a host that installed a\n // probe — so \"blocked\" cannot occur on a live portal and no second condition\n // is needed.\n if (embedability === \"blocked\") {\n let displayUrl = normalizedUrl;\n try {\n const parsed = new URL(normalizedUrl);\n displayUrl = `${parsed.host}${parsed.pathname === \"/\" ? \"\" : parsed.pathname}`;\n } catch {\n // fall through with the normalized URL\n }\n const inlineHeight = isFullScreen\n ? \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\"\n : height;\n\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-destructive/40 bg-destructive/5 text-destructive border-2 border-dashed ${className ?? \"\"}`}\n {...props}\n style={{ height: inlineHeight }}\n >\n <div className=\"flex flex-col items-center gap-2 p-6 text-center\">\n <Globe className=\"h-12 w-12 opacity-50\" />\n <p className=\"text-sm font-medium\">{t(\"embed_blocked_title\")}</p>\n <p className=\"max-w-xs truncate text-xs opacity-75\">{displayUrl}</p>\n <p className=\"text-xs opacity-60\">{t(\"embed_blocked_hint\")}</p>\n </div>\n </div>\n );\n }\n\n const showInlineExpandAction =\n isVideoEmbed && allowFullscreen && !isFullScreen && !editMode;\n\n return (\n <>\n <div\n className={`relative w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className ?? \"\"}`}\n {...props}\n style={\n isFullScreen\n ? {\n height:\n \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\",\n }\n : undefined\n }\n >\n {showInlineExpandAction && (\n <div className=\"bg-background/90 absolute top-2 right-2 z-20 rounded-lg p-0.5 shadow-sm backdrop-blur-sm\">\n <HeaderIconButton\n Icon={Maximize2}\n label=\"Expand video\"\n onClick={(event) => {\n event.stopPropagation();\n setModalOpen(true);\n }}\n />\n </div>\n )}\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n title={title}\n width=\"100%\"\n style={isFullScreen ? { height: \"100%\" } : { height }}\n loading={loading}\n allow={iframeAllow}\n allowFullScreen={allowFullscreen}\n className={`rounded-${borderRadius} border-border border`}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads\"\n />\n {editMode && !isSelected && <div className=\"absolute inset-0 z-10\" />}\n </div>\n {modalOpen && (\n <EmbedModal\n key={`inline-modal-${iframeReloadKey}`}\n src={iframeSrc}\n title={title}\n allowFullscreen={allowFullscreen}\n iframeAllow={iframeAllow}\n iframeRef={modalIframeRef}\n onClose={closeModal}\n onReload={() => setIframeReloadKey((key) => key + 1)}\n />\n )}\n </>\n );\n}\n\n// Header icon button\n\ntype HeaderIconButtonProps = {\n Icon: LucideIcon;\n label: string;\n onClick: (e: React.MouseEvent) => void;\n};\n\nfunction HeaderIconButton({\n Icon,\n label,\n onClick,\n}: HeaderIconButtonProps): React.JSX.Element {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className=\"text-foreground/45 hover:text-foreground hover:bg-background flex size-7 items-center justify-center rounded-md transition-colors\"\n >\n <Icon className=\"size-3.5\" strokeWidth={2.25} />\n </button>\n );\n}\n\n// Modal\n\ntype EmbedModalProps = {\n src: string;\n title: string;\n allowFullscreen: boolean;\n iframeAllow: string | undefined;\n iframeRef: RefObject<HTMLIFrameElement | null>;\n onClose: () => void;\n onReload: () => void;\n};\n\nfunction EmbedModal({\n src,\n title,\n allowFullscreen,\n iframeAllow,\n iframeRef,\n onClose,\n onReload,\n}: EmbedModalProps): React.JSX.Element {\n const dialogRef = useRef<HTMLDivElement>(null);\n\n useDialogFocusRestore(dialogRef);\n\n // Portal to document.body so the fixed-position dialog isn't clipped by\n // a transformed widget container on the live canvas (CSS transforms make\n // descendants the containing block for `position: fixed`).\n return createPortal(\n <div\n ref={dialogRef}\n tabIndex={-1}\n className=\"fixed inset-0 z-[100] flex items-center justify-center p-4 focus:outline-none sm:p-8\"\n style={{\n background: \"color-mix(in oklch, var(--color-foreground) 80%, black)\",\n }}\n onClick={onClose}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div\n className=\"bg-background relative flex h-full max-h-[95vh] w-full max-w-[1400px] flex-col overflow-hidden rounded-2xl shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between gap-4 px-5 py-3\"\n style={{\n borderBottom:\n \"1px solid color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }}\n >\n <h3 className=\"text-foreground truncate text-sm font-semibold tracking-tight\">\n {title}\n </h3>\n <div className=\"flex shrink-0 items-center gap-1\">\n <HeaderIconButton\n Icon={RotateCw}\n label=\"Reload\"\n onClick={(e) => {\n e.stopPropagation();\n onReload();\n }}\n />\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"text-foreground/60 hover:text-foreground hover:bg-foreground/5 flex size-9 shrink-0 items-center justify-center rounded-full transition-colors\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n </div>\n <iframe\n ref={iframeRef}\n src={src}\n title={title}\n className=\"flex-1 border-0\"\n allow={iframeAllow}\n allowFullScreen={allowFullscreen}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads\"\n />\n </div>\n </div>,\n document.body,\n );\n}\n\n// Schema\n\nexport const embedWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"EmbedWidget\",\n displayName: \"Embed\",\n fields: [\n // Content\n {\n key: \"url\",\n label: \"URL\",\n type: \"text\",\n description: \"The URL of the external site to embed\",\n placeholder: \"https://example.com\",\n defaultValue: \"\",\n group: \"Content\",\n },\n {\n key: \"title\",\n label: \"Screen Reader Label\",\n type: \"text\",\n description:\n \"Describes the embed for screen readers and assistive tech. Not visible on the page.\",\n defaultValue: \"Embedded Content\",\n group: \"Content\",\n },\n\n // Display Mode\n {\n key: \"displayMode\",\n label: \"Display Mode\",\n type: \"buttonGroup\",\n description:\n \"Inline: iframe renders directly. Cover: shows a card that opens the embed in a full-screen modal.\",\n defaultValue: \"inline\",\n options: [\n { label: \"Inline\", value: \"inline\" },\n { label: \"Cover + Modal\", value: \"cover\" },\n ],\n group: \"Display Mode\",\n },\n\n // Cover fields — all gated behind displayMode=cover\n {\n key: \"coverResource\",\n label: \"Cover Image\",\n type: \"image\",\n description: \"Select the image shown before the embed opens\",\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverUseCustomUrl\",\n label: \"Use Custom URL\",\n type: \"boolean\",\n description: \"Enter a custom image URL instead of selecting media\",\n defaultValue: false,\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverImageUrl\",\n label: \"Cover Image URL\",\n type: \"text\",\n description: \"Direct URL to the cover image\",\n placeholder: \"https://example.com/cover.jpg\",\n defaultValue: \"\",\n group: \"Cover\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverUseCustomUrl\", value: true },\n ],\n },\n getHeightField({\n key: \"coverHeight\",\n label: \"Cover Height\",\n description: \"Height of the cover image area\",\n defaultValue: \"320px\",\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n }),\n\n // Cover header (optional)\n {\n key: \"coverShowHeader\",\n label: \"Show Card Header\",\n type: \"boolean\",\n description: \"Show the header with icon, title, and action buttons\",\n defaultValue: true,\n group: \"Cover Header\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverHeaderIcon\",\n label: \"Header Icon\",\n type: \"select\",\n description: \"Icon displayed in the colored badge on the left\",\n options: HEADER_ICON_OPTIONS,\n defaultValue: \"GraduationCap\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n },\n getColorField({\n key: \"coverHeaderIconColor\",\n label: \"Icon Badge Color\",\n description: \"Background color of the icon badge\",\n defaultValue: \"primary\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n }),\n {\n key: \"coverTitle\",\n label: \"Header Title\",\n type: \"text\",\n description:\n \"Title shown in the card header and modal (falls back to the widget Title if empty). Available even when the card header is hidden so the modal still has a meaningful title.\",\n defaultValue: \"\",\n group: \"Cover Header\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverMeta\",\n label: \"Meta Text\",\n type: \"text\",\n description:\n \"Small uppercase meta line below the title (e.g. 'APR 16 · COACHING THE HOSTESS')\",\n defaultValue: \"\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n },\n\n // Design\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the embed container\",\n defaultValue: \"md\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n group: \"Design\",\n }),\n {\n key: \"fullScreen\",\n label: \"Full Screen\",\n type: \"boolean\",\n description:\n \"Inline mode: fill the available space instead of a fixed height\",\n defaultValue: false,\n group: \"Design\",\n requiresKeyValue: { key: \"displayMode\", value: \"inline\" },\n },\n getHeightField({\n key: \"height\",\n label: \"Height\",\n description: \"Height of the inline embed iframe\",\n defaultValue: \"400px\",\n group: \"Design\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"inline\" },\n { key: \"fullScreen\", value: false },\n ],\n }),\n\n // Settings\n {\n key: \"allowFullscreen\",\n label: \"Allow Fullscreen\",\n type: \"boolean\",\n description:\n \"Allow embedded video/content to use fullscreen mode and show the inline expand control when available\",\n defaultValue: true,\n group: \"Settings\",\n },\n {\n key: \"loading\",\n label: \"Loading\",\n type: \"select\",\n description: \"When to load the embedded content (inline mode only)\",\n options: [\n { label: \"Lazy (on scroll)\", value: \"lazy\" },\n { label: \"Eager (immediately)\", value: \"eager\" },\n ],\n defaultValue: \"lazy\",\n group: \"Settings\",\n requiresKeyValue: { key: \"displayMode\", value: \"inline\" },\n },\n {\n key: \"shareViewerIdentity\",\n label: \"Share verified viewer identity with this embed\",\n type: \"boolean\",\n description:\n \"When the embedded page asks, send it a short-lived signed token naming the signed-in member and company, bound to the embed's origin. Turn on only for sites you trust with who is viewing.\",\n defaultValue: false,\n group: \"Settings\",\n },\n ],\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-9hOWP6kD.cjs");
2
- const require_build_widget_registry = require("./build-widget-registry-DGA6LUJ8.cjs");
2
+ const require_build_widget_registry = require("./build-widget-registry-Cg-eGUbu.cjs");
3
3
  const require_fetch_client = require("./fetch-client-BG7NeNDx.cjs");
4
4
  const require_ContactsTranslationBridge = require("./ContactsTranslationBridge-DKkj4FOG.cjs");
5
5
  const require_ScreenRenderer = require("./ScreenRenderer-Cu4G11xt.cjs");
@@ -15,7 +15,7 @@ const require_static_dict_adapter = require("./static-dict-adapter-DYw6cHJh.cjs"
15
15
  const require_SearchSort = require("./SearchSort-BQW3m7K9.cjs");
16
16
  const require_shell_translation_api_context = require("./shell-translation-api-context-HMGFSW56.cjs");
17
17
  const require_widgets_api_context = require("./widgets-api-context-P7czyCsa.cjs");
18
- const require_EmbedWidget = require("./EmbedWidget-BN2NzUFb.cjs");
18
+ const require_EmbedWidget = require("./EmbedWidget-N7gbpIsk.cjs");
19
19
  const require_PointsWidget = require("./PointsWidget-VvE4H5Sw.cjs");
20
20
  const require_translation_api_context = require("./translation-api-context-D0ifyqUK.cjs");
21
21
  const require_translation_adapter = require("./translation-adapter-CDL_Hdzn.cjs");
@@ -21966,4 +21966,4 @@ Object.defineProperty(exports, "useThemeContext", {
21966
21966
  }
21967
21967
  });
21968
21968
 
21969
- //# sourceMappingURL=FluidProvider-DzDVN81i.cjs.map
21969
+ //# sourceMappingURL=FluidProvider-D5SBAVxZ.cjs.map