@unhingged/vizu-core 0.1.5 → 0.1.7

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.d.cts CHANGED
@@ -472,6 +472,15 @@ declare class CloudStorageAdapter implements StorageAdapter {
472
472
  */
473
473
  private accessDeniedReason;
474
474
  constructor(opts: CloudStorageOptions);
475
+ /**
476
+ * Pull a token out of the URL fragment if /connect just redirected us
477
+ * back here. Strips the fragment on success so the token doesn't sit
478
+ * in browser history or get shared if the user copies the URL.
479
+ *
480
+ * The fragment is base64-encoded JSON with compact keys; see
481
+ * apps/landing/app/connect/RedirectComplete.tsx for the producer side.
482
+ */
483
+ private readHashToken;
475
484
  /**
476
485
  * Open the sign-in popup right now (or no-op if a valid token is
477
486
  * cached). Vizu calls this on enable() so the user signs in BEFORE
package/dist/index.d.ts CHANGED
@@ -472,6 +472,15 @@ declare class CloudStorageAdapter implements StorageAdapter {
472
472
  */
473
473
  private accessDeniedReason;
474
474
  constructor(opts: CloudStorageOptions);
475
+ /**
476
+ * Pull a token out of the URL fragment if /connect just redirected us
477
+ * back here. Strips the fragment on success so the token doesn't sit
478
+ * in browser history or get shared if the user copies the URL.
479
+ *
480
+ * The fragment is base64-encoded JSON with compact keys; see
481
+ * apps/landing/app/connect/RedirectComplete.tsx for the producer side.
482
+ */
483
+ private readHashToken;
475
484
  /**
476
485
  * Open the sign-in popup right now (or no-op if a valid token is
477
486
  * cached). Vizu calls this on enable() so the user signs in BEFORE
package/dist/index.js CHANGED
@@ -353,11 +353,59 @@ var CloudStorageAdapter = class {
353
353
  this.apiUrl = (opts.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
354
354
  this.autoSignIn = opts.autoSignIn !== false;
355
355
  this.onAuthChanged = opts.onAuthChanged;
356
- this.cachedToken = this.readStoredToken();
356
+ const fromHash = this.readHashToken();
357
+ if (fromHash) {
358
+ this.cachedToken = fromHash;
359
+ this.writeStoredToken(fromHash);
360
+ } else {
361
+ this.cachedToken = this.readStoredToken();
362
+ }
357
363
  if (this.cachedToken && !this.isExpired(this.cachedToken)) {
358
364
  this.fireAuthChanged(this.cachedToken);
359
365
  }
360
366
  }
367
+ /**
368
+ * Pull a token out of the URL fragment if /connect just redirected us
369
+ * back here. Strips the fragment on success so the token doesn't sit
370
+ * in browser history or get shared if the user copies the URL.
371
+ *
372
+ * The fragment is base64-encoded JSON with compact keys; see
373
+ * apps/landing/app/connect/RedirectComplete.tsx for the producer side.
374
+ */
375
+ readHashToken() {
376
+ if (typeof window === "undefined") return null;
377
+ const hash = window.location.hash;
378
+ if (!hash || hash.length < 2) return null;
379
+ const params = new URLSearchParams(hash.slice(1));
380
+ const payload = params.get("vizu_auth");
381
+ if (!payload) return null;
382
+ try {
383
+ const json = JSON.parse(atob(payload));
384
+ if (!json.t || !json.e || !json.u || !json.w) return null;
385
+ if (json.w !== this.workspace) return null;
386
+ const stored = {
387
+ token: json.t,
388
+ expiresAt: json.e,
389
+ userId: json.u,
390
+ user: typeof json.n === "string" ? {
391
+ id: json.u,
392
+ name: json.n,
393
+ avatarUrl: typeof json.a === "string" ? json.a : void 0
394
+ } : null
395
+ };
396
+ params.delete("vizu_auth");
397
+ const remaining = params.toString();
398
+ const newHash = remaining ? `#${remaining}` : "";
399
+ try {
400
+ const newUrl = window.location.pathname + window.location.search + newHash;
401
+ window.history.replaceState(null, "", newUrl);
402
+ } catch {
403
+ }
404
+ return stored;
405
+ } catch {
406
+ return null;
407
+ }
408
+ }
361
409
  /**
362
410
  * Open the sign-in popup right now (or no-op if a valid token is
363
411
  * cached). Vizu calls this on enable() so the user signs in BEFORE
@@ -626,12 +674,19 @@ var CloudStorageAdapter = class {
626
674
  `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},noopener=no,popup=yes`
627
675
  );
628
676
  if (!popup) {
629
- return reject(
630
- makeAuthError(
631
- "popup_blocked",
632
- "Sign-in popup was blocked by the browser. Allow popups for this site and try again."
633
- )
634
- );
677
+ try {
678
+ const returnTo = window.location.href;
679
+ const redirectUrl = this.apiUrl + "/connect?workspace=" + encodeURIComponent(this.workspace) + "&origin=" + encodeURIComponent(hostOrigin) + "&return_to=" + encodeURIComponent(returnTo);
680
+ window.location.assign(redirectUrl);
681
+ return;
682
+ } catch (err) {
683
+ return reject(
684
+ makeAuthError(
685
+ "popup_blocked",
686
+ "Sign-in popup was blocked and redirect fallback failed: " + (err instanceof Error ? err.message : String(err))
687
+ )
688
+ );
689
+ }
635
690
  }
636
691
  let resolved = false;
637
692
  const onMessage = (e) => {
@@ -3125,7 +3180,16 @@ var Vizu = class {
3125
3180
  }
3126
3181
  if (matches(e, this.parsedShortcut)) {
3127
3182
  e.preventDefault();
3183
+ const wasEnabled = this.enabled;
3128
3184
  this.toggle();
3185
+ if (!wasEnabled && this.enabled && this.storage instanceof CloudStorageAdapter) {
3186
+ void this.storage.preflightAuth().catch((err) => {
3187
+ if (err?.code === "auth_canceled" || err?.code === "popup_blocked") return;
3188
+ if (typeof console !== "undefined") {
3189
+ console.warn("[vizu] preflight auth failed:", err);
3190
+ }
3191
+ });
3192
+ }
3129
3193
  }
3130
3194
  };
3131
3195
  /* ===== Reposition on scroll/resize ===== */
@@ -3214,14 +3278,6 @@ var Vizu = class {
3214
3278
  this.enabled = true;
3215
3279
  this.bus.emit("enabled", {});
3216
3280
  this.deferred(() => this.mount());
3217
- if (this.storage instanceof CloudStorageAdapter) {
3218
- void this.storage.preflightAuth().catch((err) => {
3219
- if (err?.code === "auth_canceled" || err?.code === "popup_blocked") return;
3220
- if (typeof console !== "undefined") {
3221
- console.warn("[vizu] preflight auth failed:", err);
3222
- }
3223
- });
3224
- }
3225
3281
  }
3226
3282
  disable() {
3227
3283
  if (!this.enabled) return;