@unhingged/vizu-core 0.1.0 → 0.1.2
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 +330 -180
- package/dist/auto.cjs.map +1 -1
- package/dist/auto.js +94 -11
- package/dist/auto.js.map +1 -1
- package/dist/index.cjs +330 -180
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +94 -11
- package/dist/index.js.map +1 -1
- package/dist/{live-collab-IRUNFAPE.js → live-collab-BVLNJ5QI.js} +237 -172
- package/dist/live-collab-BVLNJ5QI.js.map +1 -0
- package/dist/vizu.min.js +107 -109
- package/dist/vizu.min.js.map +1 -1
- package/package.json +24 -27
- package/dist/live-collab-IRUNFAPE.js.map +0 -1
package/dist/auto.js
CHANGED
|
@@ -342,10 +342,40 @@ var CloudStorageAdapter = class {
|
|
|
342
342
|
this.cachedToken = null;
|
|
343
343
|
/** Single-flight: at most one popup at a time. Subsequent requests await this. */
|
|
344
344
|
this.pendingAuth = null;
|
|
345
|
+
/** Whether we've already fired onAuthChanged for the current token. */
|
|
346
|
+
this.lastNotifiedTokenId = null;
|
|
345
347
|
this.workspace = opts.workspace;
|
|
346
348
|
this.apiUrl = (opts.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
347
349
|
this.autoSignIn = opts.autoSignIn !== false;
|
|
350
|
+
this.onAuthChanged = opts.onAuthChanged;
|
|
348
351
|
this.cachedToken = this.readStoredToken();
|
|
352
|
+
if (this.cachedToken && !this.isExpired(this.cachedToken)) {
|
|
353
|
+
this.fireAuthChanged(this.cachedToken);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Open the sign-in popup right now (or no-op if a valid token is
|
|
358
|
+
* cached). Vizu calls this on enable() so the user signs in BEFORE
|
|
359
|
+
* trying to leave a comment — no surprise modal mid-comment.
|
|
360
|
+
*
|
|
361
|
+
* Throws auth_canceled if the user closes the popup. Caller can
|
|
362
|
+
* decide whether to disable the surface or leave it in a read-only
|
|
363
|
+
* state.
|
|
364
|
+
*/
|
|
365
|
+
async preflightAuth() {
|
|
366
|
+
await this.resolveToken();
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Synchronous accessor for the currently cached bearer token, used
|
|
370
|
+
* by sibling modules that need to authenticate against the same
|
|
371
|
+
* backend (live-collab cross-origin polling). Returns null when no
|
|
372
|
+
* valid token is cached — callers fall back to credentials:'include'
|
|
373
|
+
* for same-origin or just disable themselves.
|
|
374
|
+
*/
|
|
375
|
+
getCachedAuthToken() {
|
|
376
|
+
if (!this.cachedToken) return null;
|
|
377
|
+
if (this.isExpired(this.cachedToken)) return null;
|
|
378
|
+
return this.cachedToken.token;
|
|
349
379
|
}
|
|
350
380
|
/* ─── StorageAdapter v2 ───────────────────────────────────────────── */
|
|
351
381
|
async load(_namespace) {
|
|
@@ -519,7 +549,7 @@ var CloudStorageAdapter = class {
|
|
|
519
549
|
}
|
|
520
550
|
}
|
|
521
551
|
sessionKey() {
|
|
522
|
-
return `vizu:cloud-token:${this.workspace}`;
|
|
552
|
+
return `vizu:cloud-token:v2:${this.workspace}`;
|
|
523
553
|
}
|
|
524
554
|
/**
|
|
525
555
|
* Resolve a valid token, opening the popup if needed.
|
|
@@ -534,6 +564,7 @@ var CloudStorageAdapter = class {
|
|
|
534
564
|
const fresh = this.readStoredToken();
|
|
535
565
|
if (fresh) {
|
|
536
566
|
this.cachedToken = fresh;
|
|
567
|
+
this.fireAuthChanged(fresh);
|
|
537
568
|
return fresh;
|
|
538
569
|
}
|
|
539
570
|
if (!this.autoSignIn) {
|
|
@@ -542,6 +573,7 @@ var CloudStorageAdapter = class {
|
|
|
542
573
|
if (!this.pendingAuth) {
|
|
543
574
|
this.pendingAuth = this.openSignInPopup().then((t) => {
|
|
544
575
|
this.writeStoredToken(t);
|
|
576
|
+
this.fireAuthChanged(t);
|
|
545
577
|
return t;
|
|
546
578
|
}).finally(() => {
|
|
547
579
|
this.pendingAuth = null;
|
|
@@ -549,6 +581,22 @@ var CloudStorageAdapter = class {
|
|
|
549
581
|
}
|
|
550
582
|
return this.pendingAuth;
|
|
551
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* Notify the host that the authenticated identity changed. De-duped
|
|
586
|
+
* via the token string so multiple resolveToken() hits with the same
|
|
587
|
+
* cached token don't re-call setUser on every fetch.
|
|
588
|
+
*/
|
|
589
|
+
fireAuthChanged(token) {
|
|
590
|
+
if (this.lastNotifiedTokenId === token.token) return;
|
|
591
|
+
this.lastNotifiedTokenId = token.token;
|
|
592
|
+
try {
|
|
593
|
+
this.onAuthChanged?.({ userId: token.userId, user: token.user });
|
|
594
|
+
} catch (err) {
|
|
595
|
+
if (typeof console !== "undefined") {
|
|
596
|
+
console.warn("[vizu/cloud] onAuthChanged callback threw", err);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
552
600
|
openSignInPopup() {
|
|
553
601
|
return new Promise((resolve, reject) => {
|
|
554
602
|
if (typeof window === "undefined") {
|
|
@@ -581,7 +629,13 @@ var CloudStorageAdapter = class {
|
|
|
581
629
|
if (typeof data.token !== "string" || typeof data.expiresAt !== "string" || typeof data.userId !== "string") return;
|
|
582
630
|
resolved = true;
|
|
583
631
|
cleanup();
|
|
584
|
-
|
|
632
|
+
const userPayload = data.user;
|
|
633
|
+
const user = userPayload && typeof userPayload.name === "string" ? {
|
|
634
|
+
id: typeof userPayload.id === "string" ? userPayload.id : data.userId,
|
|
635
|
+
name: userPayload.name,
|
|
636
|
+
avatarUrl: typeof userPayload.avatarUrl === "string" ? userPayload.avatarUrl : void 0
|
|
637
|
+
} : null;
|
|
638
|
+
resolve({ token: data.token, expiresAt: data.expiresAt, userId: data.userId, user });
|
|
585
639
|
};
|
|
586
640
|
const onPoll = window.setInterval(() => {
|
|
587
641
|
if (popup.closed) {
|
|
@@ -2676,7 +2730,7 @@ var DEFAULTS = {
|
|
|
2676
2730
|
namespace: "default",
|
|
2677
2731
|
accent: "#FF6647"
|
|
2678
2732
|
};
|
|
2679
|
-
function resolveStorage(storage, cloud, defaultMode) {
|
|
2733
|
+
function resolveStorage(storage, cloud, defaultMode, onAuthChanged) {
|
|
2680
2734
|
if (cloud) {
|
|
2681
2735
|
if (storage && typeof console !== "undefined") {
|
|
2682
2736
|
console.warn("[vizu] Both `cloud` and `storage` set; `cloud` wins. Drop `storage` to silence this.");
|
|
@@ -2684,7 +2738,8 @@ function resolveStorage(storage, cloud, defaultMode) {
|
|
|
2684
2738
|
return new CloudStorageAdapter({
|
|
2685
2739
|
workspace: cloud.workspace,
|
|
2686
2740
|
apiUrl: cloud.apiUrl,
|
|
2687
|
-
autoSignIn: cloud.autoSignIn
|
|
2741
|
+
autoSignIn: cloud.autoSignIn,
|
|
2742
|
+
onAuthChanged
|
|
2688
2743
|
});
|
|
2689
2744
|
}
|
|
2690
2745
|
if (!storage) return defaultMode === "local" ? new LocalStorageAdapter() : new InMemoryStorageAdapter();
|
|
@@ -2790,19 +2845,39 @@ var Vizu = class {
|
|
|
2790
2845
|
this.opts.namespace = options.namespace ?? DEFAULTS.namespace;
|
|
2791
2846
|
this.opts.accent = options.accent ?? DEFAULTS.accent;
|
|
2792
2847
|
this.parsedShortcut = parseShortcut(this.opts.shortcut);
|
|
2793
|
-
this.storage = resolveStorage(
|
|
2848
|
+
this.storage = resolveStorage(
|
|
2849
|
+
options.storage,
|
|
2850
|
+
options.cloud,
|
|
2851
|
+
_defaultStorage,
|
|
2852
|
+
(info) => {
|
|
2853
|
+
if (info.user) this.setUser(info.user);
|
|
2854
|
+
}
|
|
2855
|
+
);
|
|
2794
2856
|
this.user = options.user ?? null;
|
|
2795
2857
|
if (options.actions) this.actions = [...options.actions];
|
|
2796
2858
|
if (options.onCommentAdded) this.bus.on("comment:added", (p) => options.onCommentAdded(p.comment));
|
|
2797
2859
|
if (options.onCommentRemoved) this.bus.on("comment:removed", (p) => options.onCommentRemoved(p.id));
|
|
2798
|
-
if (options.
|
|
2799
|
-
const live = options.liveblocks;
|
|
2860
|
+
if (options.cloud) {
|
|
2800
2861
|
const cloud = options.cloud;
|
|
2801
|
-
|
|
2862
|
+
const apiUrl = (cloud.apiUrl ?? "https://vizu.unhingged.com").replace(/\/$/, "");
|
|
2863
|
+
void import("./live-collab-BVLNJ5QI.js").then(({ LiveCollab }) => {
|
|
2802
2864
|
this.liveCollab = new LiveCollab({
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2865
|
+
workspaceSlug: cloud.workspace,
|
|
2866
|
+
apiUrl,
|
|
2867
|
+
getAuthHeader: async () => {
|
|
2868
|
+
if (typeof window === "undefined") return null;
|
|
2869
|
+
try {
|
|
2870
|
+
if (new URL(apiUrl).origin === window.location.origin) return null;
|
|
2871
|
+
} catch {
|
|
2872
|
+
return null;
|
|
2873
|
+
}
|
|
2874
|
+
const adapter = this.storage;
|
|
2875
|
+
if (adapter instanceof CloudStorageAdapter) {
|
|
2876
|
+
const token = adapter.getCachedAuthToken();
|
|
2877
|
+
if (token) return { Authorization: `Bearer ${token}` };
|
|
2878
|
+
}
|
|
2879
|
+
return null;
|
|
2880
|
+
}
|
|
2806
2881
|
});
|
|
2807
2882
|
void this.liveCollab.start();
|
|
2808
2883
|
});
|
|
@@ -2836,6 +2911,14 @@ var Vizu = class {
|
|
|
2836
2911
|
this.enabled = true;
|
|
2837
2912
|
this.bus.emit("enabled", {});
|
|
2838
2913
|
this.deferred(() => this.mount());
|
|
2914
|
+
if (this.storage instanceof CloudStorageAdapter) {
|
|
2915
|
+
void this.storage.preflightAuth().catch((err) => {
|
|
2916
|
+
if (err?.code === "auth_canceled" || err?.code === "popup_blocked") return;
|
|
2917
|
+
if (typeof console !== "undefined") {
|
|
2918
|
+
console.warn("[vizu] preflight auth failed:", err);
|
|
2919
|
+
}
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2839
2922
|
}
|
|
2840
2923
|
disable() {
|
|
2841
2924
|
if (!this.enabled) return;
|