@unhingged/vizu-core 0.1.0 → 0.1.1

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/auto.cjs CHANGED
@@ -1714,10 +1714,28 @@ var CloudStorageAdapter = class {
1714
1714
  this.cachedToken = null;
1715
1715
  /** Single-flight: at most one popup at a time. Subsequent requests await this. */
1716
1716
  this.pendingAuth = null;
1717
+ /** Whether we've already fired onAuthChanged for the current token. */
1718
+ this.lastNotifiedTokenId = null;
1717
1719
  this.workspace = opts.workspace;
1718
1720
  this.apiUrl = (opts.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
1719
1721
  this.autoSignIn = opts.autoSignIn !== false;
1722
+ this.onAuthChanged = opts.onAuthChanged;
1720
1723
  this.cachedToken = this.readStoredToken();
1724
+ if (this.cachedToken && !this.isExpired(this.cachedToken)) {
1725
+ this.fireAuthChanged(this.cachedToken);
1726
+ }
1727
+ }
1728
+ /**
1729
+ * Open the sign-in popup right now (or no-op if a valid token is
1730
+ * cached). Vizu calls this on enable() so the user signs in BEFORE
1731
+ * trying to leave a comment — no surprise modal mid-comment.
1732
+ *
1733
+ * Throws auth_canceled if the user closes the popup. Caller can
1734
+ * decide whether to disable the surface or leave it in a read-only
1735
+ * state.
1736
+ */
1737
+ async preflightAuth() {
1738
+ await this.resolveToken();
1721
1739
  }
1722
1740
  /* ─── StorageAdapter v2 ───────────────────────────────────────────── */
1723
1741
  async load(_namespace) {
@@ -1906,6 +1924,7 @@ var CloudStorageAdapter = class {
1906
1924
  const fresh = this.readStoredToken();
1907
1925
  if (fresh) {
1908
1926
  this.cachedToken = fresh;
1927
+ this.fireAuthChanged(fresh);
1909
1928
  return fresh;
1910
1929
  }
1911
1930
  if (!this.autoSignIn) {
@@ -1914,6 +1933,7 @@ var CloudStorageAdapter = class {
1914
1933
  if (!this.pendingAuth) {
1915
1934
  this.pendingAuth = this.openSignInPopup().then((t) => {
1916
1935
  this.writeStoredToken(t);
1936
+ this.fireAuthChanged(t);
1917
1937
  return t;
1918
1938
  }).finally(() => {
1919
1939
  this.pendingAuth = null;
@@ -1921,6 +1941,22 @@ var CloudStorageAdapter = class {
1921
1941
  }
1922
1942
  return this.pendingAuth;
1923
1943
  }
1944
+ /**
1945
+ * Notify the host that the authenticated identity changed. De-duped
1946
+ * via the token string so multiple resolveToken() hits with the same
1947
+ * cached token don't re-call setUser on every fetch.
1948
+ */
1949
+ fireAuthChanged(token) {
1950
+ if (this.lastNotifiedTokenId === token.token) return;
1951
+ this.lastNotifiedTokenId = token.token;
1952
+ try {
1953
+ this.onAuthChanged?.({ userId: token.userId, user: token.user });
1954
+ } catch (err) {
1955
+ if (typeof console !== "undefined") {
1956
+ console.warn("[vizu/cloud] onAuthChanged callback threw", err);
1957
+ }
1958
+ }
1959
+ }
1924
1960
  openSignInPopup() {
1925
1961
  return new Promise((resolve, reject) => {
1926
1962
  if (typeof window === "undefined") {
@@ -1953,7 +1989,13 @@ var CloudStorageAdapter = class {
1953
1989
  if (typeof data.token !== "string" || typeof data.expiresAt !== "string" || typeof data.userId !== "string") return;
1954
1990
  resolved = true;
1955
1991
  cleanup();
1956
- resolve({ token: data.token, expiresAt: data.expiresAt, userId: data.userId });
1992
+ const userPayload = data.user;
1993
+ const user = userPayload && typeof userPayload.name === "string" ? {
1994
+ id: typeof userPayload.id === "string" ? userPayload.id : data.userId,
1995
+ name: userPayload.name,
1996
+ avatarUrl: typeof userPayload.avatarUrl === "string" ? userPayload.avatarUrl : void 0
1997
+ } : null;
1998
+ resolve({ token: data.token, expiresAt: data.expiresAt, userId: data.userId, user });
1957
1999
  };
1958
2000
  const onPoll = window.setInterval(() => {
1959
2001
  if (popup.closed) {
@@ -4054,7 +4096,7 @@ var DEFAULTS = {
4054
4096
  namespace: "default",
4055
4097
  accent: "#FF6647"
4056
4098
  };
4057
- function resolveStorage(storage, cloud, defaultMode) {
4099
+ function resolveStorage(storage, cloud, defaultMode, onAuthChanged) {
4058
4100
  if (cloud) {
4059
4101
  if (storage && typeof console !== "undefined") {
4060
4102
  console.warn("[vizu] Both `cloud` and `storage` set; `cloud` wins. Drop `storage` to silence this.");
@@ -4062,7 +4104,8 @@ function resolveStorage(storage, cloud, defaultMode) {
4062
4104
  return new CloudStorageAdapter({
4063
4105
  workspace: cloud.workspace,
4064
4106
  apiUrl: cloud.apiUrl,
4065
- autoSignIn: cloud.autoSignIn
4107
+ autoSignIn: cloud.autoSignIn,
4108
+ onAuthChanged
4066
4109
  });
4067
4110
  }
4068
4111
  if (!storage) return defaultMode === "local" ? new LocalStorageAdapter() : new InMemoryStorageAdapter();
@@ -4168,7 +4211,14 @@ var Vizu = class {
4168
4211
  this.opts.namespace = options.namespace ?? DEFAULTS.namespace;
4169
4212
  this.opts.accent = options.accent ?? DEFAULTS.accent;
4170
4213
  this.parsedShortcut = parseShortcut(this.opts.shortcut);
4171
- this.storage = resolveStorage(options.storage, options.cloud, _defaultStorage);
4214
+ this.storage = resolveStorage(
4215
+ options.storage,
4216
+ options.cloud,
4217
+ _defaultStorage,
4218
+ (info) => {
4219
+ if (info.user) this.setUser(info.user);
4220
+ }
4221
+ );
4172
4222
  this.user = options.user ?? null;
4173
4223
  if (options.actions) this.actions = [...options.actions];
4174
4224
  if (options.onCommentAdded) this.bus.on("comment:added", (p) => options.onCommentAdded(p.comment));
@@ -4214,6 +4264,14 @@ var Vizu = class {
4214
4264
  this.enabled = true;
4215
4265
  this.bus.emit("enabled", {});
4216
4266
  this.deferred(() => this.mount());
4267
+ if (this.storage instanceof CloudStorageAdapter) {
4268
+ void this.storage.preflightAuth().catch((err) => {
4269
+ if (err?.code === "auth_canceled" || err?.code === "popup_blocked") return;
4270
+ if (typeof console !== "undefined") {
4271
+ console.warn("[vizu] preflight auth failed:", err);
4272
+ }
4273
+ });
4274
+ }
4217
4275
  }
4218
4276
  disable() {
4219
4277
  if (!this.enabled) return;