@unhingged/vizu-core 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -389,11 +389,59 @@ var CloudStorageAdapter = class {
389
389
  this.apiUrl = (opts.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
390
390
  this.autoSignIn = opts.autoSignIn !== false;
391
391
  this.onAuthChanged = opts.onAuthChanged;
392
- this.cachedToken = this.readStoredToken();
392
+ const fromHash = this.readHashToken();
393
+ if (fromHash) {
394
+ this.cachedToken = fromHash;
395
+ this.writeStoredToken(fromHash);
396
+ } else {
397
+ this.cachedToken = this.readStoredToken();
398
+ }
393
399
  if (this.cachedToken && !this.isExpired(this.cachedToken)) {
394
400
  this.fireAuthChanged(this.cachedToken);
395
401
  }
396
402
  }
403
+ /**
404
+ * Pull a token out of the URL fragment if /connect just redirected us
405
+ * back here. Strips the fragment on success so the token doesn't sit
406
+ * in browser history or get shared if the user copies the URL.
407
+ *
408
+ * The fragment is base64-encoded JSON with compact keys; see
409
+ * apps/landing/app/connect/RedirectComplete.tsx for the producer side.
410
+ */
411
+ readHashToken() {
412
+ if (typeof window === "undefined") return null;
413
+ const hash = window.location.hash;
414
+ if (!hash || hash.length < 2) return null;
415
+ const params = new URLSearchParams(hash.slice(1));
416
+ const payload = params.get("vizu_auth");
417
+ if (!payload) return null;
418
+ try {
419
+ const json = JSON.parse(atob(payload));
420
+ if (!json.t || !json.e || !json.u || !json.w) return null;
421
+ if (json.w !== this.workspace) return null;
422
+ const stored = {
423
+ token: json.t,
424
+ expiresAt: json.e,
425
+ userId: json.u,
426
+ user: typeof json.n === "string" ? {
427
+ id: json.u,
428
+ name: json.n,
429
+ avatarUrl: typeof json.a === "string" ? json.a : void 0
430
+ } : null
431
+ };
432
+ params.delete("vizu_auth");
433
+ const remaining = params.toString();
434
+ const newHash = remaining ? `#${remaining}` : "";
435
+ try {
436
+ const newUrl = window.location.pathname + window.location.search + newHash;
437
+ window.history.replaceState(null, "", newUrl);
438
+ } catch {
439
+ }
440
+ return stored;
441
+ } catch {
442
+ return null;
443
+ }
444
+ }
397
445
  /**
398
446
  * Open the sign-in popup right now (or no-op if a valid token is
399
447
  * cached). Vizu calls this on enable() so the user signs in BEFORE
@@ -662,12 +710,19 @@ var CloudStorageAdapter = class {
662
710
  `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},noopener=no,popup=yes`
663
711
  );
664
712
  if (!popup) {
665
- return reject(
666
- makeAuthError(
667
- "popup_blocked",
668
- "Sign-in popup was blocked by the browser. Allow popups for this site and try again."
669
- )
670
- );
713
+ try {
714
+ const returnTo = window.location.href;
715
+ const redirectUrl = this.apiUrl + "/connect?workspace=" + encodeURIComponent(this.workspace) + "&origin=" + encodeURIComponent(hostOrigin) + "&return_to=" + encodeURIComponent(returnTo);
716
+ window.location.assign(redirectUrl);
717
+ return;
718
+ } catch (err) {
719
+ return reject(
720
+ makeAuthError(
721
+ "popup_blocked",
722
+ "Sign-in popup was blocked and redirect fallback failed: " + (err instanceof Error ? err.message : String(err))
723
+ )
724
+ );
725
+ }
671
726
  }
672
727
  let resolved = false;
673
728
  const onMessage = (e) => {