Spaces:
Running
Running
Harden Space analytics attribution and privacy
Browse files- hf-shell-app.js +129 -2
- index.html +124 -9
- space-auth.js +71 -1
hf-shell-app.js
CHANGED
|
@@ -1275,6 +1275,28 @@
|
|
| 1275 |
"hfviewer_actor",
|
| 1276 |
];
|
| 1277 |
const TRACKING_ACTOR_LABEL_QUERY_KEY = "tracking_actor_label";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1278 |
const HFVIEWER_INTERNAL_TRACKING_STORAGE_KEY = "hfviewer:internalTracking:v1";
|
| 1279 |
const HFVIEWER_INTERNAL_TRACKING_COOKIE_NAME = "hfviewer_internal";
|
| 1280 |
const HFVIEWER_INTERNAL_ANALYTICS_EMAILS = new Set([
|
|
@@ -6729,6 +6751,7 @@
|
|
| 6729 |
TRACKING_ACTOR_QUERY_KEYS.forEach((key) => url.searchParams.delete(key));
|
| 6730 |
url.searchParams.delete(TRACKING_ACTOR_LABEL_QUERY_KEY);
|
| 6731 |
url.searchParams.delete("codex_ts");
|
|
|
|
| 6732 |
return url;
|
| 6733 |
}
|
| 6734 |
|
|
@@ -6749,6 +6772,56 @@
|
|
| 6749 |
}
|
| 6750 |
}
|
| 6751 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6752 |
const HFVIEWER_FIRST_TOUCH_ATTRIBUTION_KEY = "hfviewer:firstTouchAttribution:v1";
|
| 6753 |
const HFVIEWER_ATTRIBUTION_VISIT_ID_KEY = "hfviewer:attributionVisitId:v1";
|
| 6754 |
const ATTRIBUTION_QUERY_KEYS = [
|
|
@@ -6765,6 +6838,8 @@
|
|
| 6765 |
"ttclid",
|
| 6766 |
"li_fat_id",
|
| 6767 |
"mcp_token",
|
|
|
|
|
|
|
| 6768 |
];
|
| 6769 |
let cachedAttributionPayload = null;
|
| 6770 |
|
|
@@ -6903,6 +6978,7 @@
|
|
| 6903 |
page_title: document.title,
|
| 6904 |
page_path: sanitizedAnalyticsPagePath(),
|
| 6905 |
page_location: sanitizedAnalyticsUrl(),
|
|
|
|
| 6906 |
...params,
|
| 6907 |
...(tracking
|
| 6908 |
? {
|
|
@@ -7197,6 +7273,23 @@
|
|
| 7197 |
hfviewer_hf_name: identity.name || undefined,
|
| 7198 |
hfviewer_last_identified_source: source || "hf_oauth_session",
|
| 7199 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7200 |
}
|
| 7201 |
trackPendingHfOauthReturnFromSession(payload, source);
|
| 7202 |
return internalMatch;
|
|
@@ -7368,6 +7461,9 @@
|
|
| 7368 |
ads_allowed: hasAdsConsent,
|
| 7369 |
allowed_all: Boolean(consent?.allowed),
|
| 7370 |
};
|
|
|
|
|
|
|
|
|
|
| 7371 |
const categories = consent?.categories || {};
|
| 7372 |
const categoryEntries = Object.entries(categories)
|
| 7373 |
.filter(([, value]) => typeof value === "boolean")
|
|
@@ -7511,7 +7607,7 @@
|
|
| 7511 |
}
|
| 7512 |
} catch {}
|
| 7513 |
}
|
| 7514 |
-
return event;
|
| 7515 |
},
|
| 7516 |
disable_session_recording:
|
| 7517 |
disableMobileSessionRecording || Boolean(internalAutomationLabel),
|
|
@@ -7533,6 +7629,7 @@
|
|
| 7533 |
window.posthog.register?.({
|
| 7534 |
hfviewer_surface: "top_level_shell",
|
| 7535 |
is_visualizer_frame: false,
|
|
|
|
| 7536 |
anonymous_persistence_scope: latestAnalyticsConsentState.analytics_allowed
|
| 7537 |
? "durable_consented"
|
| 7538 |
: "session_tab",
|
|
@@ -7886,6 +7983,36 @@
|
|
| 7886 |
// and property sanitizer as the rest of the first-party shell.
|
| 7887 |
window.hfviewerTrackPostHogEvent = trackPostHogEvent;
|
| 7888 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7889 |
function identifyPostHogUserByEmail(email, personProperties = {}) {
|
| 7890 |
const normalizedEmail = normalizeAnalyticsEmail(email);
|
| 7891 |
if (!normalizedEmail || shouldSuppressPostHogForInternalTracking()) {
|
|
@@ -58606,4 +58733,4 @@ ${shouldInstallBridge ? `<script>${bridgeScript}</scr${"ipt"}>` : ""}
|
|
| 58606 |
scheduleCommunityShowcasePermalinkScroll();
|
| 58607 |
});
|
| 58608 |
syncLandingModelCardButton();
|
| 58609 |
-
|
|
|
|
| 1275 |
"hfviewer_actor",
|
| 1276 |
];
|
| 1277 |
const TRACKING_ACTOR_LABEL_QUERY_KEY = "tracking_actor_label";
|
| 1278 |
+
const SENSITIVE_ANALYTICS_QUERY_KEYS = new Set([
|
| 1279 |
+
"__sign",
|
| 1280 |
+
"access_token",
|
| 1281 |
+
"auth_token",
|
| 1282 |
+
"code",
|
| 1283 |
+
"id_token",
|
| 1284 |
+
"state",
|
| 1285 |
+
"token",
|
| 1286 |
+
]);
|
| 1287 |
+
const HFVIEWER_PRODUCT_CONTEXT = (() => {
|
| 1288 |
+
const configured =
|
| 1289 |
+
window.HFVIEWER_PRODUCT_CONTEXT &&
|
| 1290 |
+
typeof window.HFVIEWER_PRODUCT_CONTEXT === "object"
|
| 1291 |
+
? window.HFVIEWER_PRODUCT_CONTEXT
|
| 1292 |
+
: {};
|
| 1293 |
+
const text = (value, maxLength = 120) => `${value || ""}`.trim().slice(0, maxLength);
|
| 1294 |
+
return Object.freeze({
|
| 1295 |
+
product_surface: text(configured.product_surface) || "website",
|
| 1296 |
+
space_repo: text(configured.space_repo),
|
| 1297 |
+
space_revision: text(configured.space_revision),
|
| 1298 |
+
});
|
| 1299 |
+
})();
|
| 1300 |
const HFVIEWER_INTERNAL_TRACKING_STORAGE_KEY = "hfviewer:internalTracking:v1";
|
| 1301 |
const HFVIEWER_INTERNAL_TRACKING_COOKIE_NAME = "hfviewer_internal";
|
| 1302 |
const HFVIEWER_INTERNAL_ANALYTICS_EMAILS = new Set([
|
|
|
|
| 6751 |
TRACKING_ACTOR_QUERY_KEYS.forEach((key) => url.searchParams.delete(key));
|
| 6752 |
url.searchParams.delete(TRACKING_ACTOR_LABEL_QUERY_KEY);
|
| 6753 |
url.searchParams.delete("codex_ts");
|
| 6754 |
+
SENSITIVE_ANALYTICS_QUERY_KEYS.forEach((key) => url.searchParams.delete(key));
|
| 6755 |
return url;
|
| 6756 |
}
|
| 6757 |
|
|
|
|
| 6772 |
}
|
| 6773 |
}
|
| 6774 |
|
| 6775 |
+
const POSTHOG_URL_PROPERTY_KEYS = new Set([
|
| 6776 |
+
"$current_url",
|
| 6777 |
+
"$initial_current_url",
|
| 6778 |
+
"$initial_referrer",
|
| 6779 |
+
"$referrer",
|
| 6780 |
+
"client_referrer_url",
|
| 6781 |
+
"first_touch_landing_url",
|
| 6782 |
+
"first_touch_referrer_url",
|
| 6783 |
+
"href",
|
| 6784 |
+
"page_location",
|
| 6785 |
+
]);
|
| 6786 |
+
const POSTHOG_PATH_PROPERTY_KEYS = new Set([
|
| 6787 |
+
"$pathname",
|
| 6788 |
+
"first_touch_landing_path",
|
| 6789 |
+
"outer_page_path",
|
| 6790 |
+
"page_path",
|
| 6791 |
+
]);
|
| 6792 |
+
|
| 6793 |
+
function sanitizePostHogAutomaticUrlProperties(event) {
|
| 6794 |
+
const containers = [
|
| 6795 |
+
event?.properties,
|
| 6796 |
+
event?.properties?.$set,
|
| 6797 |
+
event?.properties?.$set_once,
|
| 6798 |
+
];
|
| 6799 |
+
containers.forEach((container) => {
|
| 6800 |
+
if (!container || typeof container !== "object") {
|
| 6801 |
+
return;
|
| 6802 |
+
}
|
| 6803 |
+
POSTHOG_URL_PROPERTY_KEYS.forEach((key) => {
|
| 6804 |
+
if (typeof container[key] === "string") {
|
| 6805 |
+
container[key] = sanitizedAnalyticsUrl(container[key]);
|
| 6806 |
+
}
|
| 6807 |
+
});
|
| 6808 |
+
POSTHOG_PATH_PROPERTY_KEYS.forEach((key) => {
|
| 6809 |
+
if (typeof container[key] !== "string") {
|
| 6810 |
+
return;
|
| 6811 |
+
}
|
| 6812 |
+
try {
|
| 6813 |
+
const url = stripInternalTrackingParams(
|
| 6814 |
+
new URL(container[key], window.location.origin)
|
| 6815 |
+
);
|
| 6816 |
+
container[key] = `${url.pathname}${url.search}`;
|
| 6817 |
+
} catch {
|
| 6818 |
+
// Preserve malformed values rather than breaking analytics.
|
| 6819 |
+
}
|
| 6820 |
+
});
|
| 6821 |
+
});
|
| 6822 |
+
return event;
|
| 6823 |
+
}
|
| 6824 |
+
|
| 6825 |
const HFVIEWER_FIRST_TOUCH_ATTRIBUTION_KEY = "hfviewer:firstTouchAttribution:v1";
|
| 6826 |
const HFVIEWER_ATTRIBUTION_VISIT_ID_KEY = "hfviewer:attributionVisitId:v1";
|
| 6827 |
const ATTRIBUTION_QUERY_KEYS = [
|
|
|
|
| 6838 |
"ttclid",
|
| 6839 |
"li_fat_id",
|
| 6840 |
"mcp_token",
|
| 6841 |
+
"space_journey_id",
|
| 6842 |
+
"space_interaction",
|
| 6843 |
];
|
| 6844 |
let cachedAttributionPayload = null;
|
| 6845 |
|
|
|
|
| 6978 |
page_title: document.title,
|
| 6979 |
page_path: sanitizedAnalyticsPagePath(),
|
| 6980 |
page_location: sanitizedAnalyticsUrl(),
|
| 6981 |
+
...HFVIEWER_PRODUCT_CONTEXT,
|
| 6982 |
...params,
|
| 6983 |
...(tracking
|
| 6984 |
? {
|
|
|
|
| 7273 |
hfviewer_hf_name: identity.name || undefined,
|
| 7274 |
hfviewer_last_identified_source: source || "hf_oauth_session",
|
| 7275 |
});
|
| 7276 |
+
} else if (identity.hfUsername && !internalMatch && !shouldSuppressPostHogForInternalTracking()) {
|
| 7277 |
+
void loadPostHogClient().then((client) => {
|
| 7278 |
+
try {
|
| 7279 |
+
const distinctId = `hf:${identity.hfUsername}`;
|
| 7280 |
+
const personProperties = {
|
| 7281 |
+
hfviewer_authenticated: true,
|
| 7282 |
+
hfviewer_auth_provider: "hugging_face",
|
| 7283 |
+
hfviewer_hf_username: identity.hfUsername,
|
| 7284 |
+
hfviewer_hf_name: identity.name || undefined,
|
| 7285 |
+
hfviewer_last_identified_source: source || "hf_oauth_session",
|
| 7286 |
+
};
|
| 7287 |
+
client?.identify?.(distinctId, personProperties);
|
| 7288 |
+
latestPostHogIdentity = { email: "", personProperties };
|
| 7289 |
+
} catch {
|
| 7290 |
+
// Analytics identity is best-effort only.
|
| 7291 |
+
}
|
| 7292 |
+
});
|
| 7293 |
}
|
| 7294 |
trackPendingHfOauthReturnFromSession(payload, source);
|
| 7295 |
return internalMatch;
|
|
|
|
| 7461 |
ads_allowed: hasAdsConsent,
|
| 7462 |
allowed_all: Boolean(consent?.allowed),
|
| 7463 |
};
|
| 7464 |
+
if (hasAnalyticsConsent) {
|
| 7465 |
+
flushPendingExternalHfAnalyticsIdentity();
|
| 7466 |
+
}
|
| 7467 |
const categories = consent?.categories || {};
|
| 7468 |
const categoryEntries = Object.entries(categories)
|
| 7469 |
.filter(([, value]) => typeof value === "boolean")
|
|
|
|
| 7607 |
}
|
| 7608 |
} catch {}
|
| 7609 |
}
|
| 7610 |
+
return sanitizePostHogAutomaticUrlProperties(event);
|
| 7611 |
},
|
| 7612 |
disable_session_recording:
|
| 7613 |
disableMobileSessionRecording || Boolean(internalAutomationLabel),
|
|
|
|
| 7629 |
window.posthog.register?.({
|
| 7630 |
hfviewer_surface: "top_level_shell",
|
| 7631 |
is_visualizer_frame: false,
|
| 7632 |
+
...HFVIEWER_PRODUCT_CONTEXT,
|
| 7633 |
anonymous_persistence_scope: latestAnalyticsConsentState.analytics_allowed
|
| 7634 |
? "durable_consented"
|
| 7635 |
: "session_tab",
|
|
|
|
| 7983 |
// and property sanitizer as the rest of the first-party shell.
|
| 7984 |
window.hfviewerTrackPostHogEvent = trackPostHogEvent;
|
| 7985 |
|
| 7986 |
+
let pendingExternalHfAnalyticsIdentity = null;
|
| 7987 |
+
|
| 7988 |
+
function identifyExternalHfAnalyticsIdentity(payload, source = "external_hf_oauth") {
|
| 7989 |
+
if (!payload || payload.authenticated === false) {
|
| 7990 |
+
return false;
|
| 7991 |
+
}
|
| 7992 |
+
if (!latestAnalyticsConsentState.analytics_allowed) {
|
| 7993 |
+
pendingExternalHfAnalyticsIdentity = { payload, source };
|
| 7994 |
+
return false;
|
| 7995 |
+
}
|
| 7996 |
+
pendingExternalHfAnalyticsIdentity = null;
|
| 7997 |
+
identifyHfViewerPostHogUserFromSession(payload, source);
|
| 7998 |
+
return true;
|
| 7999 |
+
}
|
| 8000 |
+
|
| 8001 |
+
function flushPendingExternalHfAnalyticsIdentity() {
|
| 8002 |
+
if (!pendingExternalHfAnalyticsIdentity) {
|
| 8003 |
+
return false;
|
| 8004 |
+
}
|
| 8005 |
+
const pending = pendingExternalHfAnalyticsIdentity;
|
| 8006 |
+
return identifyExternalHfAnalyticsIdentity(pending.payload, pending.source);
|
| 8007 |
+
}
|
| 8008 |
+
|
| 8009 |
+
window.hfviewerAnalyticsBridge = Object.freeze({
|
| 8010 |
+
capture: trackPostHogEvent,
|
| 8011 |
+
hasAnalyticsConsent: () => latestAnalyticsConsentState.analytics_allowed === true,
|
| 8012 |
+
identifyHfSession: identifyExternalHfAnalyticsIdentity,
|
| 8013 |
+
productContext: () => ({ ...HFVIEWER_PRODUCT_CONTEXT }),
|
| 8014 |
+
});
|
| 8015 |
+
|
| 8016 |
function identifyPostHogUserByEmail(email, personProperties = {}) {
|
| 8017 |
const normalizedEmail = normalizeAnalyticsEmail(email);
|
| 8018 |
if (!normalizedEmail || shouldSuppressPostHogForInternalTracking()) {
|
|
|
|
| 58733 |
scheduleCommunityShowcasePermalinkScroll();
|
| 58734 |
});
|
| 58735 |
syncLandingModelCardButton();
|
| 58736 |
+
|
index.html
CHANGED
|
@@ -184,7 +184,53 @@
|
|
| 184 |
}
|
| 185 |
}
|
| 186 |
</script>
|
| 187 |
-
<script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
<style>
|
| 189 |
/* --- injected by build_space_landing.py: sections stripped for the HF space --- */
|
| 190 |
header.nav,
|
|
@@ -10102,7 +10148,6 @@ body.sx-viewer-open { overflow: hidden; }
|
|
| 10102 |
<script>
|
| 10103 |
(function () {
|
| 10104 |
var SITE = "https://hfviewer.com";
|
| 10105 |
-
var UTM = "utm_source=hf_space&utm_medium=referral&utm_campaign=space-explorer";
|
| 10106 |
var SITE_SECTIONS = ["models", "glossary", "timeline", "blog", "family", "compare", "model-card-embed", "share", "api", "assets", "visualizer", "next"];
|
| 10107 |
var MODEL_RE = /^\/([\w.-]+)\/([\w.-]+)\/?$/;
|
| 10108 |
var overlay = document.getElementById("sx-viewer-overlay");
|
|
@@ -10111,17 +10156,64 @@ body.sx-viewer-open { overflow: hidden; }
|
|
| 10111 |
var back = document.getElementById("sx-back");
|
| 10112 |
var openFull = document.getElementById("sx-open");
|
| 10113 |
var currentPath = null;
|
|
|
|
| 10114 |
|
| 10115 |
-
function
|
| 10116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10117 |
}
|
| 10118 |
|
| 10119 |
function openModel(path) {
|
| 10120 |
if (currentPath === path) { showOverlay(); return; }
|
| 10121 |
currentPath = path;
|
|
|
|
| 10122 |
loading.classList.remove("hidden");
|
| 10123 |
-
frame.src = siteUrl(path);
|
| 10124 |
-
openFull.href = siteUrl(path);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10125 |
showOverlay();
|
| 10126 |
try {
|
| 10127 |
var u = new URL(window.location.href);
|
|
@@ -10140,7 +10232,8 @@ body.sx-viewer-open { overflow: hidden; }
|
|
| 10140 |
overlay.classList.remove("open");
|
| 10141 |
document.body.classList.remove("sx-viewer-open");
|
| 10142 |
back.style.display = "none";
|
| 10143 |
-
|
|
|
|
| 10144 |
try {
|
| 10145 |
var u = new URL(window.location.href);
|
| 10146 |
u.searchParams.delete("model");
|
|
@@ -10148,7 +10241,17 @@ body.sx-viewer-open { overflow: hidden; }
|
|
| 10148 |
} catch (e) { /* ignore */ }
|
| 10149 |
}
|
| 10150 |
|
| 10151 |
-
frame.addEventListener("load", function () {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10152 |
back.addEventListener("click", closeOverlay);
|
| 10153 |
|
| 10154 |
// window CAPTURE phase: fires before the shell's document-level handlers,
|
|
@@ -10165,6 +10268,18 @@ body.sx-viewer-open { overflow: hidden; }
|
|
| 10165 |
var isSite = url.origin === SITE || url.origin === window.location.origin;
|
| 10166 |
if (!isSite) return; // external links (HF, X, ...) behave normally
|
| 10167 |
var path = url.pathname;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10168 |
if (path === "/" || path === "") {
|
| 10169 |
e.preventDefault();
|
| 10170 |
e.stopPropagation();
|
|
@@ -10182,7 +10297,7 @@ body.sx-viewer-open { overflow: hidden; }
|
|
| 10182 |
// genuine site page: open the real site in a new tab, utm-tagged
|
| 10183 |
e.preventDefault();
|
| 10184 |
e.stopPropagation();
|
| 10185 |
-
|
| 10186 |
}
|
| 10187 |
}, true);
|
| 10188 |
|
|
|
|
| 184 |
}
|
| 185 |
}
|
| 186 |
</script>
|
| 187 |
+
<script>
|
| 188 |
+
window.dataLayer = window.dataLayer || [];
|
| 189 |
+
window.gtag = function () {};
|
| 190 |
+
window.VIEWMYMODEL_HF_API_BASE = "https://hfviewer.com/api";
|
| 191 |
+
window.HFVIEWER_PRODUCT_CONTEXT = Object.freeze({
|
| 192 |
+
product_surface: "hf_space",
|
| 193 |
+
space_repo: "embedl/hfviewer",
|
| 194 |
+
space_revision: "hf-space-2e4848474064",
|
| 195 |
+
});
|
| 196 |
+
try {
|
| 197 |
+
var initialUrl = new URL(window.location.href);
|
| 198 |
+
var initialModel = initialUrl.searchParams.get("model");
|
| 199 |
+
if (initialModel) {
|
| 200 |
+
window.__SX_DEEP_MODEL = initialModel;
|
| 201 |
+
initialUrl.searchParams.delete("model");
|
| 202 |
+
window.history.replaceState(null, "", initialUrl.toString());
|
| 203 |
+
}
|
| 204 |
+
var signedAccess = initialUrl.searchParams.get("__sign") || "";
|
| 205 |
+
var signedPayloadPart = signedAccess.split(".")[1] || "";
|
| 206 |
+
if (signedPayloadPart) {
|
| 207 |
+
signedPayloadPart = signedPayloadPart.replace(/-/g, "+").replace(/_/g, "/");
|
| 208 |
+
while (signedPayloadPart.length % 4) signedPayloadPart += "=";
|
| 209 |
+
var signedPayload = JSON.parse(atob(signedPayloadPart));
|
| 210 |
+
var signedUsername = String(signedPayload?.onBehalfOf?.user || "")
|
| 211 |
+
.trim()
|
| 212 |
+
.replace(/^@+/, "")
|
| 213 |
+
.toLowerCase();
|
| 214 |
+
if (signedUsername === "hannesvonessen") {
|
| 215 |
+
window.localStorage?.setItem(
|
| 216 |
+
"hfviewer:internalTracking:v1",
|
| 217 |
+
JSON.stringify({
|
| 218 |
+
tracking_actor: "internal",
|
| 219 |
+
tracking_actor_label: "allowlisted_hf_username:hannesvonessen",
|
| 220 |
+
hfviewer_internal: true,
|
| 221 |
+
hfviewer_staff: true,
|
| 222 |
+
hfviewer_internal_reason: "allowlisted_hf_username",
|
| 223 |
+
hf_username: signedUsername,
|
| 224 |
+
source: "hf_space_signed_access",
|
| 225 |
+
set_at: new Date().toISOString(),
|
| 226 |
+
})
|
| 227 |
+
);
|
| 228 |
+
}
|
| 229 |
+
}
|
| 230 |
+
} catch (error) {
|
| 231 |
+
// Space access hints and cosmetic deep links are best effort only.
|
| 232 |
+
}
|
| 233 |
+
</script>
|
| 234 |
<style>
|
| 235 |
/* --- injected by build_space_landing.py: sections stripped for the HF space --- */
|
| 236 |
header.nav,
|
|
|
|
| 10148 |
<script>
|
| 10149 |
(function () {
|
| 10150 |
var SITE = "https://hfviewer.com";
|
|
|
|
| 10151 |
var SITE_SECTIONS = ["models", "glossary", "timeline", "blog", "family", "compare", "model-card-embed", "share", "api", "assets", "visualizer", "next"];
|
| 10152 |
var MODEL_RE = /^\/([\w.-]+)\/([\w.-]+)\/?$/;
|
| 10153 |
var overlay = document.getElementById("sx-viewer-overlay");
|
|
|
|
| 10156 |
var back = document.getElementById("sx-back");
|
| 10157 |
var openFull = document.getElementById("sx-open");
|
| 10158 |
var currentPath = null;
|
| 10159 |
+
var currentEmbedJourneyId = null;
|
| 10160 |
|
| 10161 |
+
function createJourneyId() {
|
| 10162 |
+
try {
|
| 10163 |
+
if (window.crypto && typeof window.crypto.randomUUID === "function") {
|
| 10164 |
+
return window.crypto.randomUUID();
|
| 10165 |
+
}
|
| 10166 |
+
} catch (error) { /* fall through */ }
|
| 10167 |
+
return "space-" + Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 10);
|
| 10168 |
+
}
|
| 10169 |
+
|
| 10170 |
+
function trackSpaceEvent(eventName, properties) {
|
| 10171 |
+
try {
|
| 10172 |
+
window.hfviewerAnalyticsBridge?.capture?.(eventName, Object.assign({
|
| 10173 |
+
product_surface: "hf_space",
|
| 10174 |
+
space_repo: "embedl/hfviewer",
|
| 10175 |
+
space_revision: "hf-space-2e4848474064",
|
| 10176 |
+
}, properties || {}));
|
| 10177 |
+
} catch (error) { /* analytics must never break navigation */ }
|
| 10178 |
+
}
|
| 10179 |
+
|
| 10180 |
+
function siteUrl(path, interaction, journeyId) {
|
| 10181 |
+
var url = new URL(path || "/", SITE);
|
| 10182 |
+
url.searchParams.set("utm_source", "hf_space");
|
| 10183 |
+
url.searchParams.set("utm_medium", "referral");
|
| 10184 |
+
url.searchParams.set("utm_campaign", "space-explorer");
|
| 10185 |
+
url.searchParams.set("utm_content", interaction);
|
| 10186 |
+
url.searchParams.set("space_interaction", interaction);
|
| 10187 |
+
url.searchParams.set("space_journey_id", journeyId);
|
| 10188 |
+
return url.toString();
|
| 10189 |
+
}
|
| 10190 |
+
|
| 10191 |
+
function openWebsite(path, source) {
|
| 10192 |
+
var journeyId = createJourneyId();
|
| 10193 |
+
var destination = siteUrl(path, "open_website", journeyId);
|
| 10194 |
+
trackSpaceEvent("space_to_hfviewer_clicked", {
|
| 10195 |
+
space_journey_id: journeyId,
|
| 10196 |
+
space_interaction: "open_website",
|
| 10197 |
+
destination_path: new URL(destination).pathname,
|
| 10198 |
+
source: source || "space_link",
|
| 10199 |
+
embedded_model_path: currentPath || undefined,
|
| 10200 |
+
});
|
| 10201 |
+
window.open(destination, "_blank", "noopener");
|
| 10202 |
}
|
| 10203 |
|
| 10204 |
function openModel(path) {
|
| 10205 |
if (currentPath === path) { showOverlay(); return; }
|
| 10206 |
currentPath = path;
|
| 10207 |
+
currentEmbedJourneyId = createJourneyId();
|
| 10208 |
loading.classList.remove("hidden");
|
| 10209 |
+
frame.src = siteUrl(path, "embedded_viewer", currentEmbedJourneyId);
|
| 10210 |
+
openFull.href = siteUrl(path, "open_website", currentEmbedJourneyId);
|
| 10211 |
+
trackSpaceEvent("space_model_opened", {
|
| 10212 |
+
space_journey_id: currentEmbedJourneyId,
|
| 10213 |
+
space_interaction: "embedded_viewer",
|
| 10214 |
+
model_repo_id: path.replace(/^\//, ""),
|
| 10215 |
+
destination_path: path,
|
| 10216 |
+
});
|
| 10217 |
showOverlay();
|
| 10218 |
try {
|
| 10219 |
var u = new URL(window.location.href);
|
|
|
|
| 10232 |
overlay.classList.remove("open");
|
| 10233 |
document.body.classList.remove("sx-viewer-open");
|
| 10234 |
back.style.display = "none";
|
| 10235 |
+
currentEmbedJourneyId = null;
|
| 10236 |
+
openFull.href = siteUrl("/", "open_website", createJourneyId());
|
| 10237 |
try {
|
| 10238 |
var u = new URL(window.location.href);
|
| 10239 |
u.searchParams.delete("model");
|
|
|
|
| 10241 |
} catch (e) { /* ignore */ }
|
| 10242 |
}
|
| 10243 |
|
| 10244 |
+
frame.addEventListener("load", function () {
|
| 10245 |
+
loading.classList.add("hidden");
|
| 10246 |
+
if (currentPath && currentEmbedJourneyId) {
|
| 10247 |
+
trackSpaceEvent("space_embedded_viewer_loaded", {
|
| 10248 |
+
space_journey_id: currentEmbedJourneyId,
|
| 10249 |
+
space_interaction: "embedded_viewer",
|
| 10250 |
+
model_repo_id: currentPath.replace(/^\//, ""),
|
| 10251 |
+
destination_path: currentPath,
|
| 10252 |
+
});
|
| 10253 |
+
}
|
| 10254 |
+
});
|
| 10255 |
back.addEventListener("click", closeOverlay);
|
| 10256 |
|
| 10257 |
// window CAPTURE phase: fires before the shell's document-level handlers,
|
|
|
|
| 10268 |
var isSite = url.origin === SITE || url.origin === window.location.origin;
|
| 10269 |
if (!isSite) return; // external links (HF, X, ...) behave normally
|
| 10270 |
var path = url.pathname;
|
| 10271 |
+
if (a === openFull) {
|
| 10272 |
+
e.preventDefault();
|
| 10273 |
+
e.stopPropagation();
|
| 10274 |
+
openWebsite(currentPath || "/", "viewer_header");
|
| 10275 |
+
return;
|
| 10276 |
+
}
|
| 10277 |
+
if (a.classList.contains("sx-brand")) {
|
| 10278 |
+
e.preventDefault();
|
| 10279 |
+
e.stopPropagation();
|
| 10280 |
+
openWebsite("/", "space_header_brand");
|
| 10281 |
+
return;
|
| 10282 |
+
}
|
| 10283 |
if (path === "/" || path === "") {
|
| 10284 |
e.preventDefault();
|
| 10285 |
e.stopPropagation();
|
|
|
|
| 10297 |
// genuine site page: open the real site in a new tab, utm-tagged
|
| 10298 |
e.preventDefault();
|
| 10299 |
e.stopPropagation();
|
| 10300 |
+
openWebsite(path + url.search, "space_content_link");
|
| 10301 |
}
|
| 10302 |
}, true);
|
| 10303 |
|
space-auth.js
CHANGED
|
@@ -40,9 +40,46 @@ function userFromResult(result) {
|
|
| 40 |
name: String(raw.name || username).trim(),
|
| 41 |
picture: String(raw.picture || raw.avatar_url || raw.avatarUrl || "").trim(),
|
| 42 |
profile: String(raw.profile || `https://huggingface.co/${encodeURIComponent(username)}`).trim(),
|
|
|
|
|
|
|
| 43 |
};
|
| 44 |
}
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
function keepReleasePills() {
|
| 47 |
if (!authHost) return [];
|
| 48 |
return Array.from(authHost.children).filter((element) =>
|
|
@@ -76,7 +113,13 @@ function makeLoggedOutControl() {
|
|
| 76 |
link.href = loginUrl || "#";
|
| 77 |
if (!loginUrl) link.setAttribute("aria-disabled", "true");
|
| 78 |
link.addEventListener("click", (event) => {
|
| 79 |
-
if (!loginUrl)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
});
|
| 81 |
return link;
|
| 82 |
}
|
|
@@ -107,6 +150,11 @@ function makeLoggedInControl(user) {
|
|
| 107 |
profile.rel = "noopener";
|
| 108 |
profile.textContent = "Hugging Face profile";
|
| 109 |
profile.setAttribute("role", "menuitem");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
const logout = document.createElement("button");
|
| 112 |
logout.type = "button";
|
|
@@ -114,6 +162,9 @@ function makeLoggedInControl(user) {
|
|
| 114 |
logout.textContent = "Log out";
|
| 115 |
logout.setAttribute("role", "menuitem");
|
| 116 |
logout.addEventListener("click", () => {
|
|
|
|
|
|
|
|
|
|
| 117 |
oauthResult = null;
|
| 118 |
writeStoredResult(null);
|
| 119 |
renderAuth();
|
|
@@ -161,6 +212,7 @@ function cleanCallbackQuery() {
|
|
| 161 |
|
| 162 |
async function initialize() {
|
| 163 |
renderAuth();
|
|
|
|
| 164 |
try {
|
| 165 |
const callbackResult = await oauthHandleRedirectIfPresent();
|
| 166 |
if (callbackResult) {
|
|
@@ -168,9 +220,22 @@ async function initialize() {
|
|
| 168 |
writeStoredResult(callbackResult);
|
| 169 |
cleanCallbackQuery();
|
| 170 |
renderAuth();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
}
|
| 172 |
} catch (error) {
|
| 173 |
console.warn("Hugging Face Space login callback failed", error);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
}
|
| 175 |
|
| 176 |
try {
|
|
@@ -178,6 +243,11 @@ async function initialize() {
|
|
| 178 |
loginUrl = await oauthLoginUrl(scopes ? { scopes } : undefined);
|
| 179 |
} catch (error) {
|
| 180 |
console.warn("Could not prepare Hugging Face Space login", error);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
}
|
| 182 |
renderAuth();
|
| 183 |
}
|
|
|
|
| 40 |
name: String(raw.name || username).trim(),
|
| 41 |
picture: String(raw.picture || raw.avatar_url || raw.avatarUrl || "").trim(),
|
| 42 |
profile: String(raw.profile || `https://huggingface.co/${encodeURIComponent(username)}`).trim(),
|
| 43 |
+
subject: String(raw.sub || raw.id || "").trim(),
|
| 44 |
+
email: String(raw.email || "").trim().toLowerCase(),
|
| 45 |
};
|
| 46 |
}
|
| 47 |
|
| 48 |
+
function trackAuthEvent(eventName, properties = {}) {
|
| 49 |
+
try {
|
| 50 |
+
window.hfviewerAnalyticsBridge?.capture?.(eventName, {
|
| 51 |
+
product_surface: "hf_space",
|
| 52 |
+
space_repo: "embedl/hfviewer",
|
| 53 |
+
space_revision: "hf-space-2e4848474064",
|
| 54 |
+
auth_provider: "hugging_face",
|
| 55 |
+
...properties,
|
| 56 |
+
});
|
| 57 |
+
} catch {
|
| 58 |
+
// Authentication must remain independent of analytics availability.
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
function identifyAuthenticatedUser(user, source) {
|
| 63 |
+
if (!user?.username) return;
|
| 64 |
+
try {
|
| 65 |
+
window.hfviewerAnalyticsBridge?.identifyHfSession?.(
|
| 66 |
+
{
|
| 67 |
+
authenticated: true,
|
| 68 |
+
email: user.email || "",
|
| 69 |
+
user: {
|
| 70 |
+
id: user.subject || "",
|
| 71 |
+
username: user.username,
|
| 72 |
+
name: user.name || user.username,
|
| 73 |
+
email: user.email || "",
|
| 74 |
+
},
|
| 75 |
+
},
|
| 76 |
+
source || "hf_space_native_oauth"
|
| 77 |
+
);
|
| 78 |
+
} catch {
|
| 79 |
+
// Consent-gated identity is best effort only.
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
function keepReleasePills() {
|
| 84 |
if (!authHost) return [];
|
| 85 |
return Array.from(authHost.children).filter((element) =>
|
|
|
|
| 113 |
link.href = loginUrl || "#";
|
| 114 |
if (!loginUrl) link.setAttribute("aria-disabled", "true");
|
| 115 |
link.addEventListener("click", (event) => {
|
| 116 |
+
if (!loginUrl) {
|
| 117 |
+
event.preventDefault();
|
| 118 |
+
return;
|
| 119 |
+
}
|
| 120 |
+
trackAuthEvent("space_hf_login_clicked", {
|
| 121 |
+
component: "space_nav",
|
| 122 |
+
});
|
| 123 |
});
|
| 124 |
return link;
|
| 125 |
}
|
|
|
|
| 150 |
profile.rel = "noopener";
|
| 151 |
profile.textContent = "Hugging Face profile";
|
| 152 |
profile.setAttribute("role", "menuitem");
|
| 153 |
+
profile.addEventListener("click", () => {
|
| 154 |
+
trackAuthEvent("space_hf_profile_opened", {
|
| 155 |
+
component: "space_nav",
|
| 156 |
+
});
|
| 157 |
+
});
|
| 158 |
|
| 159 |
const logout = document.createElement("button");
|
| 160 |
logout.type = "button";
|
|
|
|
| 162 |
logout.textContent = "Log out";
|
| 163 |
logout.setAttribute("role", "menuitem");
|
| 164 |
logout.addEventListener("click", () => {
|
| 165 |
+
trackAuthEvent("space_hf_logout", {
|
| 166 |
+
component: "space_nav",
|
| 167 |
+
});
|
| 168 |
oauthResult = null;
|
| 169 |
writeStoredResult(null);
|
| 170 |
renderAuth();
|
|
|
|
| 212 |
|
| 213 |
async function initialize() {
|
| 214 |
renderAuth();
|
| 215 |
+
identifyAuthenticatedUser(userFromResult(oauthResult), "hf_space_native_oauth_restored");
|
| 216 |
try {
|
| 217 |
const callbackResult = await oauthHandleRedirectIfPresent();
|
| 218 |
if (callbackResult) {
|
|
|
|
| 220 |
writeStoredResult(callbackResult);
|
| 221 |
cleanCallbackQuery();
|
| 222 |
renderAuth();
|
| 223 |
+
const user = userFromResult(callbackResult);
|
| 224 |
+
identifyAuthenticatedUser(user, "hf_space_native_oauth_callback");
|
| 225 |
+
trackAuthEvent("space_hf_login_completed", {
|
| 226 |
+
component: "space_nav",
|
| 227 |
+
username_present: !!user?.username,
|
| 228 |
+
subject_present: !!user?.subject,
|
| 229 |
+
email_present: !!user?.email,
|
| 230 |
+
});
|
| 231 |
}
|
| 232 |
} catch (error) {
|
| 233 |
console.warn("Hugging Face Space login callback failed", error);
|
| 234 |
+
trackAuthEvent("space_hf_login_failed", {
|
| 235 |
+
component: "space_nav",
|
| 236 |
+
failure_stage: "oauth_callback",
|
| 237 |
+
error_name: String(error?.name || "Error").slice(0, 80),
|
| 238 |
+
});
|
| 239 |
}
|
| 240 |
|
| 241 |
try {
|
|
|
|
| 243 |
loginUrl = await oauthLoginUrl(scopes ? { scopes } : undefined);
|
| 244 |
} catch (error) {
|
| 245 |
console.warn("Could not prepare Hugging Face Space login", error);
|
| 246 |
+
trackAuthEvent("space_hf_login_failed", {
|
| 247 |
+
component: "space_nav",
|
| 248 |
+
failure_stage: "login_url",
|
| 249 |
+
error_name: String(error?.name || "Error").slice(0, 80),
|
| 250 |
+
});
|
| 251 |
}
|
| 252 |
renderAuth();
|
| 253 |
}
|