{
  "version": 3,
  "sources": ["../../src/environment/getTunnelId.ts", "../../src/environment/domains.ts"],
  "sourcesContent": ["import { getFramerRelease } from \"./getFramerRelease.ts\"\n\nfunction getTunnelIdFromCookie(): string | undefined {\n\tif (typeof document === \"undefined\") return undefined\n\n\tconst cookies = document.cookie.split(\";\")\n\tfor (const cookie of cookies) {\n\t\tconst trimmed = cookie.trim()\n\t\tconst equalIndex = trimmed.indexOf(\"=\")\n\t\tif (equalIndex === -1) continue\n\n\t\tconst name = trimmed.substring(0, equalIndex)\n\t\tconst value = trimmed.substring(equalIndex + 1)\n\n\t\tif (name === \"tunnel\" && value) {\n\t\t\treturn value\n\t\t}\n\t}\n\treturn undefined\n}\n\n/**\n * Gets the tunnel ID synchronously by parsing document.cookie.\n * @returns The tunnel ID, or undefined if not available or not in tunnel mode\n */\nexport function getTunnelId(): string | undefined {\n\tconst release = getFramerRelease(window)\n\tif (release?.override !== \"tunnel\") return undefined\n\treturn getTunnelIdFromCookie()\n}\n", "import { assert, getServiceMap } from \"@framerjs/shared\"\nimport { experiments } from \"app/experiments.ts\"\nimport { getTunnelId } from \"./getTunnelId.ts\"\n\nexport { getServiceMap } from \"@framerjs/shared\"\n\ninterface DomainMap {\n\tapp: string\n\tcanvas: string\n\thttps: boolean\n}\n\nconst desktopLocalhost: DomainMap = {\n\t// Desktop\n\tapp: \"127.0.0.1\",\n\tcanvas: \"127.0.0.1\",\n\thttps: false,\n}\n\nconst desktopLocalhostIPv4: DomainMap = {\n\t// Desktop make dev\n\tapp: \"localhost\",\n\tcanvas: \"localhost\",\n\thttps: false,\n}\n\nconst webLocal: DomainMap = {\n\tapp: \"web.framerlocal.com\",\n\tcanvas: \"web.framerlocal.com\",\n\thttps: false,\n}\n\nconst domainMaps: DomainMap[] = [\n\t{\n\t\t// Web development\n\t\tapp: \"development.framer.com\",\n\t\tcanvas: \"framercanvas.dev\",\n\t\thttps: true,\n\t},\n\t{\n\t\t// Web development branch previews\n\t\tapp: \".development.framer.com\",\n\t\tcanvas: \".framercanvas.dev\",\n\t\thttps: true,\n\t},\n\t{\n\t\t// Web production branch previews\n\t\tapp: \".framer.com\",\n\t\tcanvas: \".framercanvas.com\",\n\t\thttps: true,\n\t},\n\t{\n\t\t// Web production\n\t\tapp: \"framer.com\",\n\t\tcanvas: \"framercanvas.com\",\n\t\thttps: true,\n\t},\n\twebLocal,\n\tdesktopLocalhost,\n\tdesktopLocalhostIPv4,\n]\n\n// Can be set to true for testing only. In the future, this may be read from localStorage.\nexport const hasUnsafeSameOriginSandboxForTesting = false\n\ntype DomainKey = Exclude<keyof DomainMap, \"https\">\n\nfunction domainMapForEnvironment(domain: DomainKey, hostname: string): DomainMap | undefined {\n\t// Figure out the right mappings given the current domain. As far as static resources are concerned, the sandbox\n\t// domains essentially behave as unauthenticated aliases of the primary app domain.\n\tfor (const map of domainMaps) {\n\t\tconst knownHostname = map[domain]\n\t\tif (hostname === knownHostname) {\n\t\t\t// Exact match\n\t\t\treturn map\n\t\t} else if (knownHostname.startsWith(\".\") && hostname.endsWith(knownHostname)) {\n\t\t\t// Any subdomain\n\t\t\treturn map\n\t\t}\n\t}\n\n\treturn undefined\n}\n\ninterface OriginInfo {\n\torigin: string\n\tisCrossOriginProtected: boolean\n}\n\nexport function sandboxAppRelativeToEditor(relativePath: string): { url: string } & OriginInfo {\n\tconst location = window.location\n\n\tconst url = new URL(relativePath, location.href)\n\tif (url.origin !== location.origin) {\n\t\tthrow Error(`Domain lookup requires relative paths. Received ${relativePath}`)\n\t}\n\n\t// Require a trusted environment with correct security\n\tconst domainMap = domainMapForEnvironment(\"app\", location.hostname)\n\tif (!domainMap || (domainMap.https && url.protocol !== \"https:\")) {\n\t\tthrow Error(`Running on unknown app domain: ${url}`)\n\t}\n\n\t// Most environments (such as Web & Desktop), have the canvas domain may specified beforehand.\n\tlet preconfiguredTo: string | undefined\n\ttry {\n\t\tpreconfiguredTo = new URL(getServiceMap().canvas).hostname\n\t} catch {\n\t\t// Ignore missing configuration, we always have the standard domain to fall back on.\n\t}\n\n\t// The canvas domains behave like an alias to the app domain, which means the path can stay the same\n\t// Replacing the hostname provides the wanted security if CORS restrictions are active.\n\tconst from = preconfiguredTo ? url.hostname : domainMap[\"app\"]\n\tconst to = preconfiguredTo ?? domainMap[hasUnsafeSameOriginSandboxForTesting ? \"app\" : \"canvas\"]\n\n\tif (url.hostname.endsWith(from)) {\n\t\turl.hostname = url.hostname.slice(0, -from.length) + to\n\t}\n\n\t// If the editor domain has a tunnel cookie set, we need to forward that to the sandbox.\n\tconst tunnel = getTunnelId()\n\tif (tunnel) {\n\t\turl.searchParams.set(\"tunnel\", tunnel)\n\t} else {\n\t\t// If there is an explicitly empty tunnel param, we need to remove it so\n\t\t// the server clears the cookie in the sandbox too.\n\t\tconst tunnelParam = new URLSearchParams(location.search).get(\"tunnel\")\n\t\tif (tunnelParam === \"\") {\n\t\t\turl.searchParams.set(\"tunnel\", \"\")\n\t\t}\n\t}\n\n\tconst variant = experiments.get(\"prototypeTreeDriver\")\n\turl.searchParams.set(\"experiment\", `prototypeTreeDriver=${variant}`)\n\n\treturn {\n\t\turl: url.href,\n\t\torigin: url.origin,\n\t\tisCrossOriginProtected: from !== to,\n\t}\n}\n\nexport function assertAllowSameOriginForSandboxApp(relativePath: string) {\n\t// FIXME: the sandbox never worked in FramerCommand, but it started interfering with exporting. Just silence it\n\t// until we rip out the whole legacy export system.\n\tif (navigator.userAgent.indexOf(\"FramerCommand\") !== -1) {\n\t\treturn\n\t}\n\n\tconst location = window.location\n\n\tconst { origin, isCrossOriginProtected } = sandboxAppRelativeToEditor(relativePath)\n\tconst isLocalhost = location.hostname === desktopLocalhost.app\n\tconst isLocalhostIPv4 = location.hostname === desktopLocalhostIPv4.app\n\tconst isLocalWeb = location.hostname === webLocal.app // FIXME: remove once we have framercanvaslocal.com\n\tconst hasUnsafeSameOriginForLocalDevelopment =\n\t\tisLocalhost || isLocalhostIPv4 || isLocalWeb || hasUnsafeSameOriginSandboxForTesting\n\n\t// Verify that either the sandbox origin differs from the host to\n\t// ensure we can safely enable the allow-same-origin permission or that\n\t// we are running locally in a development environment.\n\tassert(\n\t\tisCrossOriginProtected || hasUnsafeSameOriginForLocalDevelopment,\n\t\t`Attempt to create unsafe sandboxed app for origin: ${origin} on page with origin: ${location.origin}`,\n\t)\n}\n\nexport function assertEditorApp(href: string | undefined): { origin: string } {\n\tif (!href) {\n\t\t// Fall back to a wildcard if the origin is not available. This is generally\n\t\t// based on the document.referrer, but that is not always available.\n\t\treturn { origin: \"*\" }\n\t}\n\n\tconst location = window.location\n\n\tconst editorURL = new URL(href)\n\tconst domainMap = domainMapForEnvironment(\"app\", editorURL.hostname)\n\tassert(\n\t\teditorURL && editorURL.protocol === location.protocol && domainMap,\n\t\t`Attempt to create secure link from sandboxed app (${location.href}) to unknown editor domain (${href})`,\n\t)\n\n\treturn { origin: editorURL.origin }\n}\n"],
  "mappings": "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",
  "names": []
}
