@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 +62 -4
- package/dist/auto.cjs.map +1 -1
- package/dist/auto.js +62 -4
- package/dist/auto.js.map +1 -1
- package/dist/index.cjs +62 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +62 -4
- package/dist/index.js.map +1 -1
- package/dist/vizu.min.js +11 -11
- package/dist/vizu.min.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -465,16 +465,39 @@ interface CloudStorageOptions {
|
|
|
465
465
|
apiUrl?: string;
|
|
466
466
|
/** Open the sign-in popup automatically on the first auth-needed write. Defaults to true. */
|
|
467
467
|
autoSignIn?: boolean;
|
|
468
|
+
/**
|
|
469
|
+
* Fired whenever the cached host-token transitions to authenticated —
|
|
470
|
+
* either freshly from the popup or rehydrated from sessionStorage.
|
|
471
|
+
* Vizu wires this to `setUser()` so comments attributed after sign-in
|
|
472
|
+
* carry the proper display name + avatar.
|
|
473
|
+
*/
|
|
474
|
+
onAuthChanged?: (info: {
|
|
475
|
+
userId: string;
|
|
476
|
+
user: VizuUser | null;
|
|
477
|
+
}) => void;
|
|
468
478
|
}
|
|
469
479
|
declare class CloudStorageAdapter implements StorageAdapter {
|
|
470
480
|
private readonly apiUrl;
|
|
471
481
|
private readonly workspace;
|
|
472
482
|
private readonly autoSignIn;
|
|
483
|
+
private onAuthChanged;
|
|
473
484
|
/** Cached current-tab token. Mirrored to sessionStorage. */
|
|
474
485
|
private cachedToken;
|
|
475
486
|
/** Single-flight: at most one popup at a time. Subsequent requests await this. */
|
|
476
487
|
private pendingAuth;
|
|
488
|
+
/** Whether we've already fired onAuthChanged for the current token. */
|
|
489
|
+
private lastNotifiedTokenId;
|
|
477
490
|
constructor(opts: CloudStorageOptions);
|
|
491
|
+
/**
|
|
492
|
+
* Open the sign-in popup right now (or no-op if a valid token is
|
|
493
|
+
* cached). Vizu calls this on enable() so the user signs in BEFORE
|
|
494
|
+
* trying to leave a comment — no surprise modal mid-comment.
|
|
495
|
+
*
|
|
496
|
+
* Throws auth_canceled if the user closes the popup. Caller can
|
|
497
|
+
* decide whether to disable the surface or leave it in a read-only
|
|
498
|
+
* state.
|
|
499
|
+
*/
|
|
500
|
+
preflightAuth(): Promise<void>;
|
|
478
501
|
load(_namespace: string): Promise<VizuComment[]>;
|
|
479
502
|
addComment(_namespace: string, comment: VizuComment): Promise<void>;
|
|
480
503
|
updateComment(_namespace: string, id: string, patch: Partial<VizuComment>): Promise<VizuComment | null>;
|
|
@@ -512,6 +535,12 @@ declare class CloudStorageAdapter implements StorageAdapter {
|
|
|
512
535
|
* a friendly message instead of a blank failure.
|
|
513
536
|
*/
|
|
514
537
|
private resolveToken;
|
|
538
|
+
/**
|
|
539
|
+
* Notify the host that the authenticated identity changed. De-duped
|
|
540
|
+
* via the token string so multiple resolveToken() hits with the same
|
|
541
|
+
* cached token don't re-call setUser on every fetch.
|
|
542
|
+
*/
|
|
543
|
+
private fireAuthChanged;
|
|
515
544
|
private openSignInPopup;
|
|
516
545
|
/**
|
|
517
546
|
* Perform an authenticated fetch with one-shot retry on 401 (re-opens
|
package/dist/index.d.ts
CHANGED
|
@@ -465,16 +465,39 @@ interface CloudStorageOptions {
|
|
|
465
465
|
apiUrl?: string;
|
|
466
466
|
/** Open the sign-in popup automatically on the first auth-needed write. Defaults to true. */
|
|
467
467
|
autoSignIn?: boolean;
|
|
468
|
+
/**
|
|
469
|
+
* Fired whenever the cached host-token transitions to authenticated —
|
|
470
|
+
* either freshly from the popup or rehydrated from sessionStorage.
|
|
471
|
+
* Vizu wires this to `setUser()` so comments attributed after sign-in
|
|
472
|
+
* carry the proper display name + avatar.
|
|
473
|
+
*/
|
|
474
|
+
onAuthChanged?: (info: {
|
|
475
|
+
userId: string;
|
|
476
|
+
user: VizuUser | null;
|
|
477
|
+
}) => void;
|
|
468
478
|
}
|
|
469
479
|
declare class CloudStorageAdapter implements StorageAdapter {
|
|
470
480
|
private readonly apiUrl;
|
|
471
481
|
private readonly workspace;
|
|
472
482
|
private readonly autoSignIn;
|
|
483
|
+
private onAuthChanged;
|
|
473
484
|
/** Cached current-tab token. Mirrored to sessionStorage. */
|
|
474
485
|
private cachedToken;
|
|
475
486
|
/** Single-flight: at most one popup at a time. Subsequent requests await this. */
|
|
476
487
|
private pendingAuth;
|
|
488
|
+
/** Whether we've already fired onAuthChanged for the current token. */
|
|
489
|
+
private lastNotifiedTokenId;
|
|
477
490
|
constructor(opts: CloudStorageOptions);
|
|
491
|
+
/**
|
|
492
|
+
* Open the sign-in popup right now (or no-op if a valid token is
|
|
493
|
+
* cached). Vizu calls this on enable() so the user signs in BEFORE
|
|
494
|
+
* trying to leave a comment — no surprise modal mid-comment.
|
|
495
|
+
*
|
|
496
|
+
* Throws auth_canceled if the user closes the popup. Caller can
|
|
497
|
+
* decide whether to disable the surface or leave it in a read-only
|
|
498
|
+
* state.
|
|
499
|
+
*/
|
|
500
|
+
preflightAuth(): Promise<void>;
|
|
478
501
|
load(_namespace: string): Promise<VizuComment[]>;
|
|
479
502
|
addComment(_namespace: string, comment: VizuComment): Promise<void>;
|
|
480
503
|
updateComment(_namespace: string, id: string, patch: Partial<VizuComment>): Promise<VizuComment | null>;
|
|
@@ -512,6 +535,12 @@ declare class CloudStorageAdapter implements StorageAdapter {
|
|
|
512
535
|
* a friendly message instead of a blank failure.
|
|
513
536
|
*/
|
|
514
537
|
private resolveToken;
|
|
538
|
+
/**
|
|
539
|
+
* Notify the host that the authenticated identity changed. De-duped
|
|
540
|
+
* via the token string so multiple resolveToken() hits with the same
|
|
541
|
+
* cached token don't re-call setUser on every fetch.
|
|
542
|
+
*/
|
|
543
|
+
private fireAuthChanged;
|
|
515
544
|
private openSignInPopup;
|
|
516
545
|
/**
|
|
517
546
|
* Perform an authenticated fetch with one-shot retry on 401 (re-opens
|
package/dist/index.js
CHANGED
|
@@ -342,10 +342,28 @@ 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();
|
|
349
367
|
}
|
|
350
368
|
/* ─── StorageAdapter v2 ───────────────────────────────────────────── */
|
|
351
369
|
async load(_namespace) {
|
|
@@ -534,6 +552,7 @@ var CloudStorageAdapter = class {
|
|
|
534
552
|
const fresh = this.readStoredToken();
|
|
535
553
|
if (fresh) {
|
|
536
554
|
this.cachedToken = fresh;
|
|
555
|
+
this.fireAuthChanged(fresh);
|
|
537
556
|
return fresh;
|
|
538
557
|
}
|
|
539
558
|
if (!this.autoSignIn) {
|
|
@@ -542,6 +561,7 @@ var CloudStorageAdapter = class {
|
|
|
542
561
|
if (!this.pendingAuth) {
|
|
543
562
|
this.pendingAuth = this.openSignInPopup().then((t) => {
|
|
544
563
|
this.writeStoredToken(t);
|
|
564
|
+
this.fireAuthChanged(t);
|
|
545
565
|
return t;
|
|
546
566
|
}).finally(() => {
|
|
547
567
|
this.pendingAuth = null;
|
|
@@ -549,6 +569,22 @@ var CloudStorageAdapter = class {
|
|
|
549
569
|
}
|
|
550
570
|
return this.pendingAuth;
|
|
551
571
|
}
|
|
572
|
+
/**
|
|
573
|
+
* Notify the host that the authenticated identity changed. De-duped
|
|
574
|
+
* via the token string so multiple resolveToken() hits with the same
|
|
575
|
+
* cached token don't re-call setUser on every fetch.
|
|
576
|
+
*/
|
|
577
|
+
fireAuthChanged(token) {
|
|
578
|
+
if (this.lastNotifiedTokenId === token.token) return;
|
|
579
|
+
this.lastNotifiedTokenId = token.token;
|
|
580
|
+
try {
|
|
581
|
+
this.onAuthChanged?.({ userId: token.userId, user: token.user });
|
|
582
|
+
} catch (err) {
|
|
583
|
+
if (typeof console !== "undefined") {
|
|
584
|
+
console.warn("[vizu/cloud] onAuthChanged callback threw", err);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
552
588
|
openSignInPopup() {
|
|
553
589
|
return new Promise((resolve, reject) => {
|
|
554
590
|
if (typeof window === "undefined") {
|
|
@@ -581,7 +617,13 @@ var CloudStorageAdapter = class {
|
|
|
581
617
|
if (typeof data.token !== "string" || typeof data.expiresAt !== "string" || typeof data.userId !== "string") return;
|
|
582
618
|
resolved = true;
|
|
583
619
|
cleanup();
|
|
584
|
-
|
|
620
|
+
const userPayload = data.user;
|
|
621
|
+
const user = userPayload && typeof userPayload.name === "string" ? {
|
|
622
|
+
id: typeof userPayload.id === "string" ? userPayload.id : data.userId,
|
|
623
|
+
name: userPayload.name,
|
|
624
|
+
avatarUrl: typeof userPayload.avatarUrl === "string" ? userPayload.avatarUrl : void 0
|
|
625
|
+
} : null;
|
|
626
|
+
resolve({ token: data.token, expiresAt: data.expiresAt, userId: data.userId, user });
|
|
585
627
|
};
|
|
586
628
|
const onPoll = window.setInterval(() => {
|
|
587
629
|
if (popup.closed) {
|
|
@@ -2676,7 +2718,7 @@ var DEFAULTS = {
|
|
|
2676
2718
|
namespace: "default",
|
|
2677
2719
|
accent: "#FF6647"
|
|
2678
2720
|
};
|
|
2679
|
-
function resolveStorage(storage, cloud, defaultMode) {
|
|
2721
|
+
function resolveStorage(storage, cloud, defaultMode, onAuthChanged) {
|
|
2680
2722
|
if (cloud) {
|
|
2681
2723
|
if (storage && typeof console !== "undefined") {
|
|
2682
2724
|
console.warn("[vizu] Both `cloud` and `storage` set; `cloud` wins. Drop `storage` to silence this.");
|
|
@@ -2684,7 +2726,8 @@ function resolveStorage(storage, cloud, defaultMode) {
|
|
|
2684
2726
|
return new CloudStorageAdapter({
|
|
2685
2727
|
workspace: cloud.workspace,
|
|
2686
2728
|
apiUrl: cloud.apiUrl,
|
|
2687
|
-
autoSignIn: cloud.autoSignIn
|
|
2729
|
+
autoSignIn: cloud.autoSignIn,
|
|
2730
|
+
onAuthChanged
|
|
2688
2731
|
});
|
|
2689
2732
|
}
|
|
2690
2733
|
if (!storage) return defaultMode === "local" ? new LocalStorageAdapter() : new InMemoryStorageAdapter();
|
|
@@ -2790,7 +2833,14 @@ var Vizu = class {
|
|
|
2790
2833
|
this.opts.namespace = options.namespace ?? DEFAULTS.namespace;
|
|
2791
2834
|
this.opts.accent = options.accent ?? DEFAULTS.accent;
|
|
2792
2835
|
this.parsedShortcut = parseShortcut(this.opts.shortcut);
|
|
2793
|
-
this.storage = resolveStorage(
|
|
2836
|
+
this.storage = resolveStorage(
|
|
2837
|
+
options.storage,
|
|
2838
|
+
options.cloud,
|
|
2839
|
+
_defaultStorage,
|
|
2840
|
+
(info) => {
|
|
2841
|
+
if (info.user) this.setUser(info.user);
|
|
2842
|
+
}
|
|
2843
|
+
);
|
|
2794
2844
|
this.user = options.user ?? null;
|
|
2795
2845
|
if (options.actions) this.actions = [...options.actions];
|
|
2796
2846
|
if (options.onCommentAdded) this.bus.on("comment:added", (p) => options.onCommentAdded(p.comment));
|
|
@@ -2836,6 +2886,14 @@ var Vizu = class {
|
|
|
2836
2886
|
this.enabled = true;
|
|
2837
2887
|
this.bus.emit("enabled", {});
|
|
2838
2888
|
this.deferred(() => this.mount());
|
|
2889
|
+
if (this.storage instanceof CloudStorageAdapter) {
|
|
2890
|
+
void this.storage.preflightAuth().catch((err) => {
|
|
2891
|
+
if (err?.code === "auth_canceled" || err?.code === "popup_blocked") return;
|
|
2892
|
+
if (typeof console !== "undefined") {
|
|
2893
|
+
console.warn("[vizu] preflight auth failed:", err);
|
|
2894
|
+
}
|
|
2895
|
+
});
|
|
2896
|
+
}
|
|
2839
2897
|
}
|
|
2840
2898
|
disable() {
|
|
2841
2899
|
if (!this.enabled) return;
|