@cross-deck/web 1.12.1 → 1.13.0
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/CHANGELOG.md +10 -0
- package/README.md +35 -0
- package/dist/crossdeck.umd.min.js +2 -2
- package/dist/crossdeck.umd.min.js.map +1 -1
- package/dist/error-codes.json +1 -1
- package/dist/index.cjs +150 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.mjs +147 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +186 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.mts +40 -2
- package/dist/react.d.ts +40 -2
- package/dist/react.mjs +184 -3
- package/dist/react.mjs.map +1 -1
- package/dist/trust-C0RcpR5I.d.mts +91 -0
- package/dist/trust-C0RcpR5I.d.ts +91 -0
- package/dist/vue.cjs +168 -3
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.mts +25 -1
- package/dist/vue.d.ts +25 -1
- package/dist/vue.mjs +166 -2
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crossdeck Trust — the human-proof panel, native to the SDK.
|
|
3
|
+
*
|
|
4
|
+
* This is the browser half of Crossdeck Trust wired THROUGH the SDK the customer
|
|
5
|
+
* already runs, not bolted on beside it. It renders the SAME cross-origin iframe
|
|
6
|
+
* served from trust.cross-deck.com — the un-restylable, browser-enforced brand
|
|
7
|
+
* panel — and hands the minted attestation back PROGRAMMATICALLY (a Promise + an
|
|
8
|
+
* `onToken` callback) instead of the hidden-field/DOM handshake the raw
|
|
9
|
+
* `embed.js` loader uses. The iframe is the bouncer; the SDK is the premium front
|
|
10
|
+
* door to it. You pass the token to your server, which verifies it at the gate
|
|
11
|
+
* (`crossdeck.trust.gate(...)` in @cross-deck/node, or a raw POST /v1/trust/gate).
|
|
12
|
+
*
|
|
13
|
+
* Non-negotiables baked in (Stripe / Cloudflare / bank grade):
|
|
14
|
+
* - ISOLATED — every DOM / postMessage touch is wrapped; a stumble here can never
|
|
15
|
+
* throw into the host app, the rest of the SDK, or the customer's signup form.
|
|
16
|
+
* - FAIL-OPEN, never fail-allow — if the panel can't mint (adblocker, our outage,
|
|
17
|
+
* offline, timeout), `ready` resolves with NO token. The signup proceeds; the
|
|
18
|
+
* SERVER gate scores the ABSENCE. We never wave a tokenless request through, and
|
|
19
|
+
* we never block the form because our panel had a bad day. Failing CLOSED would
|
|
20
|
+
* hand an attacker a site-wide-outage weapon — so we never do.
|
|
21
|
+
* - ORIGIN-LOCKED — we only trust messages from OUR panel origin AND from this
|
|
22
|
+
* exact iframe's window. Nothing on the host page can forge a token.
|
|
23
|
+
* - The token is minted INSIDE our origin; the host page (even an XSS on it) never
|
|
24
|
+
* participates in the mint, it only receives the finished token.
|
|
25
|
+
*/
|
|
26
|
+
/** The origin that serves the branded, un-restylable Trust panel. */
|
|
27
|
+
declare const TRUST_PANEL_ORIGIN = "https://trust.cross-deck.com";
|
|
28
|
+
/** A minted human-proof attestation. Pass `token` to your gate call. */
|
|
29
|
+
interface TrustToken {
|
|
30
|
+
/** The single-use, project-bound attestation to send to your server as `token`. */
|
|
31
|
+
token: string;
|
|
32
|
+
/** Epoch ms at which the token expires (mint fresh per signup attempt), or null. */
|
|
33
|
+
expiresAt: number | null;
|
|
34
|
+
}
|
|
35
|
+
/** Resolution of a panel that failed open — a token never minted. Not an error. */
|
|
36
|
+
interface TrustUnavailable {
|
|
37
|
+
token: null;
|
|
38
|
+
expiresAt: null;
|
|
39
|
+
/** Why no token was minted (for your logs) — e.g. "timeout", "blocked", "offline". */
|
|
40
|
+
reason: string;
|
|
41
|
+
}
|
|
42
|
+
type TrustResult = TrustToken | TrustUnavailable;
|
|
43
|
+
/** Lifecycle of a panel driven by a framework binding: pending → ready | unavailable. */
|
|
44
|
+
type TrustTokenStatus = "pending" | "ready" | "unavailable";
|
|
45
|
+
interface MountTrustPanelOptions {
|
|
46
|
+
/** The project's publishable key (cd_pub_…). The SDK client supplies this for you. */
|
|
47
|
+
publicKey: string;
|
|
48
|
+
/** Where to render the panel — an element or a selector resolved at mount time. */
|
|
49
|
+
target: HTMLElement | string;
|
|
50
|
+
/** Called once when a token is minted. Optional — you can await `ready` instead. */
|
|
51
|
+
onToken?: (t: TrustToken) => void;
|
|
52
|
+
/**
|
|
53
|
+
* Called if the panel could not mint (blocked, offline, timeout, our outage).
|
|
54
|
+
* INFORMATIONAL for your logs — NOT an error you must handle: `ready` still
|
|
55
|
+
* resolves and your signup proceeds. Fail-open is the contract.
|
|
56
|
+
*/
|
|
57
|
+
onUnavailable?: (reason: string) => void;
|
|
58
|
+
/** Override the panel origin (tests / self-host). Defaults to production. */
|
|
59
|
+
origin?: string;
|
|
60
|
+
/** Max wait for a mint before failing open, in ms. Default 15000. */
|
|
61
|
+
timeoutMs?: number;
|
|
62
|
+
}
|
|
63
|
+
interface TrustPanelHandle {
|
|
64
|
+
/** The iframe we mounted — for layout/measurement only; never reach inside it. */
|
|
65
|
+
readonly frame: HTMLIFrameElement | null;
|
|
66
|
+
/**
|
|
67
|
+
* Resolves EXACTLY once: the token on success, or a {@link TrustUnavailable} if
|
|
68
|
+
* the panel failed open. NEVER rejects — a rejection would tempt callers to block
|
|
69
|
+
* the signup, which is precisely what fail-open forbids.
|
|
70
|
+
*/
|
|
71
|
+
readonly ready: Promise<TrustResult>;
|
|
72
|
+
/** Tear down: remove the iframe + listeners. Idempotent. */
|
|
73
|
+
destroy(): void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Options for `Crossdeck.trust.panel(...)` — the same as {@link MountTrustPanelOptions}
|
|
77
|
+
* but the SDK client injects `publicKey` from your `init()`, so you omit it.
|
|
78
|
+
*/
|
|
79
|
+
type TrustPanelInput = Omit<MountTrustPanelOptions, "publicKey">;
|
|
80
|
+
/** The `Crossdeck.trust` namespace surfaced on the SDK client. */
|
|
81
|
+
interface CrossdeckTrustNamespace {
|
|
82
|
+
/** Render the branded Trust panel and mint an attestation. See {@link mountTrustPanel}. */
|
|
83
|
+
panel(input: TrustPanelInput): TrustPanelHandle;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Mount the Crossdeck Trust panel and mint an attestation. Framework-agnostic and
|
|
87
|
+
* guaranteed not to throw — any construction failure resolves `ready` fail-open.
|
|
88
|
+
*/
|
|
89
|
+
declare function mountTrustPanel(opts: MountTrustPanelOptions): TrustPanelHandle;
|
|
90
|
+
|
|
91
|
+
export { type CrossdeckTrustNamespace as C, type MountTrustPanelOptions as M, TRUST_PANEL_ORIGIN as T, type TrustPanelHandle as a, type TrustPanelInput as b, type TrustResult as c, type TrustToken as d, type TrustTokenStatus as e, type TrustUnavailable as f, mountTrustPanel as m };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crossdeck Trust — the human-proof panel, native to the SDK.
|
|
3
|
+
*
|
|
4
|
+
* This is the browser half of Crossdeck Trust wired THROUGH the SDK the customer
|
|
5
|
+
* already runs, not bolted on beside it. It renders the SAME cross-origin iframe
|
|
6
|
+
* served from trust.cross-deck.com — the un-restylable, browser-enforced brand
|
|
7
|
+
* panel — and hands the minted attestation back PROGRAMMATICALLY (a Promise + an
|
|
8
|
+
* `onToken` callback) instead of the hidden-field/DOM handshake the raw
|
|
9
|
+
* `embed.js` loader uses. The iframe is the bouncer; the SDK is the premium front
|
|
10
|
+
* door to it. You pass the token to your server, which verifies it at the gate
|
|
11
|
+
* (`crossdeck.trust.gate(...)` in @cross-deck/node, or a raw POST /v1/trust/gate).
|
|
12
|
+
*
|
|
13
|
+
* Non-negotiables baked in (Stripe / Cloudflare / bank grade):
|
|
14
|
+
* - ISOLATED — every DOM / postMessage touch is wrapped; a stumble here can never
|
|
15
|
+
* throw into the host app, the rest of the SDK, or the customer's signup form.
|
|
16
|
+
* - FAIL-OPEN, never fail-allow — if the panel can't mint (adblocker, our outage,
|
|
17
|
+
* offline, timeout), `ready` resolves with NO token. The signup proceeds; the
|
|
18
|
+
* SERVER gate scores the ABSENCE. We never wave a tokenless request through, and
|
|
19
|
+
* we never block the form because our panel had a bad day. Failing CLOSED would
|
|
20
|
+
* hand an attacker a site-wide-outage weapon — so we never do.
|
|
21
|
+
* - ORIGIN-LOCKED — we only trust messages from OUR panel origin AND from this
|
|
22
|
+
* exact iframe's window. Nothing on the host page can forge a token.
|
|
23
|
+
* - The token is minted INSIDE our origin; the host page (even an XSS on it) never
|
|
24
|
+
* participates in the mint, it only receives the finished token.
|
|
25
|
+
*/
|
|
26
|
+
/** The origin that serves the branded, un-restylable Trust panel. */
|
|
27
|
+
declare const TRUST_PANEL_ORIGIN = "https://trust.cross-deck.com";
|
|
28
|
+
/** A minted human-proof attestation. Pass `token` to your gate call. */
|
|
29
|
+
interface TrustToken {
|
|
30
|
+
/** The single-use, project-bound attestation to send to your server as `token`. */
|
|
31
|
+
token: string;
|
|
32
|
+
/** Epoch ms at which the token expires (mint fresh per signup attempt), or null. */
|
|
33
|
+
expiresAt: number | null;
|
|
34
|
+
}
|
|
35
|
+
/** Resolution of a panel that failed open — a token never minted. Not an error. */
|
|
36
|
+
interface TrustUnavailable {
|
|
37
|
+
token: null;
|
|
38
|
+
expiresAt: null;
|
|
39
|
+
/** Why no token was minted (for your logs) — e.g. "timeout", "blocked", "offline". */
|
|
40
|
+
reason: string;
|
|
41
|
+
}
|
|
42
|
+
type TrustResult = TrustToken | TrustUnavailable;
|
|
43
|
+
/** Lifecycle of a panel driven by a framework binding: pending → ready | unavailable. */
|
|
44
|
+
type TrustTokenStatus = "pending" | "ready" | "unavailable";
|
|
45
|
+
interface MountTrustPanelOptions {
|
|
46
|
+
/** The project's publishable key (cd_pub_…). The SDK client supplies this for you. */
|
|
47
|
+
publicKey: string;
|
|
48
|
+
/** Where to render the panel — an element or a selector resolved at mount time. */
|
|
49
|
+
target: HTMLElement | string;
|
|
50
|
+
/** Called once when a token is minted. Optional — you can await `ready` instead. */
|
|
51
|
+
onToken?: (t: TrustToken) => void;
|
|
52
|
+
/**
|
|
53
|
+
* Called if the panel could not mint (blocked, offline, timeout, our outage).
|
|
54
|
+
* INFORMATIONAL for your logs — NOT an error you must handle: `ready` still
|
|
55
|
+
* resolves and your signup proceeds. Fail-open is the contract.
|
|
56
|
+
*/
|
|
57
|
+
onUnavailable?: (reason: string) => void;
|
|
58
|
+
/** Override the panel origin (tests / self-host). Defaults to production. */
|
|
59
|
+
origin?: string;
|
|
60
|
+
/** Max wait for a mint before failing open, in ms. Default 15000. */
|
|
61
|
+
timeoutMs?: number;
|
|
62
|
+
}
|
|
63
|
+
interface TrustPanelHandle {
|
|
64
|
+
/** The iframe we mounted — for layout/measurement only; never reach inside it. */
|
|
65
|
+
readonly frame: HTMLIFrameElement | null;
|
|
66
|
+
/**
|
|
67
|
+
* Resolves EXACTLY once: the token on success, or a {@link TrustUnavailable} if
|
|
68
|
+
* the panel failed open. NEVER rejects — a rejection would tempt callers to block
|
|
69
|
+
* the signup, which is precisely what fail-open forbids.
|
|
70
|
+
*/
|
|
71
|
+
readonly ready: Promise<TrustResult>;
|
|
72
|
+
/** Tear down: remove the iframe + listeners. Idempotent. */
|
|
73
|
+
destroy(): void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Options for `Crossdeck.trust.panel(...)` — the same as {@link MountTrustPanelOptions}
|
|
77
|
+
* but the SDK client injects `publicKey` from your `init()`, so you omit it.
|
|
78
|
+
*/
|
|
79
|
+
type TrustPanelInput = Omit<MountTrustPanelOptions, "publicKey">;
|
|
80
|
+
/** The `Crossdeck.trust` namespace surfaced on the SDK client. */
|
|
81
|
+
interface CrossdeckTrustNamespace {
|
|
82
|
+
/** Render the branded Trust panel and mint an attestation. See {@link mountTrustPanel}. */
|
|
83
|
+
panel(input: TrustPanelInput): TrustPanelHandle;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Mount the Crossdeck Trust panel and mint an attestation. Framework-agnostic and
|
|
87
|
+
* guaranteed not to throw — any construction failure resolves `ready` fail-open.
|
|
88
|
+
*/
|
|
89
|
+
declare function mountTrustPanel(opts: MountTrustPanelOptions): TrustPanelHandle;
|
|
90
|
+
|
|
91
|
+
export { type CrossdeckTrustNamespace as C, type MountTrustPanelOptions as M, TRUST_PANEL_ORIGIN as T, type TrustPanelHandle as a, type TrustPanelInput as b, type TrustResult as c, type TrustToken as d, type TrustTokenStatus as e, type TrustUnavailable as f, mountTrustPanel as m };
|
package/dist/vue.cjs
CHANGED
|
@@ -21,7 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var vue_exports = {};
|
|
22
22
|
__export(vue_exports, {
|
|
23
23
|
useEntitlement: () => useEntitlement,
|
|
24
|
-
useEntitlements: () => useEntitlements
|
|
24
|
+
useEntitlements: () => useEntitlements,
|
|
25
|
+
useTrustToken: () => useTrustToken
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(vue_exports);
|
|
27
28
|
var import_vue = require("vue");
|
|
@@ -97,7 +98,7 @@ function typeMapForStatus(status) {
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
// src/_version.ts
|
|
100
|
-
var SDK_VERSION = "1.
|
|
101
|
+
var SDK_VERSION = "1.13.0";
|
|
101
102
|
var SDK_NAME = "@cross-deck/web";
|
|
102
103
|
|
|
103
104
|
// src/http.ts
|
|
@@ -354,6 +355,125 @@ function randomChars(count) {
|
|
|
354
355
|
return out.join("");
|
|
355
356
|
}
|
|
356
357
|
|
|
358
|
+
// src/trust.ts
|
|
359
|
+
var TRUST_PANEL_ORIGIN = "https://trust.cross-deck.com";
|
|
360
|
+
var MAX_WIDTH_PX = 360;
|
|
361
|
+
var INITIAL_HEIGHT_PX = 132;
|
|
362
|
+
var MIN_HEIGHT_PX = 96;
|
|
363
|
+
var MAX_HEIGHT_PX = 220;
|
|
364
|
+
var DEFAULT_TIMEOUT_MS2 = 15e3;
|
|
365
|
+
function mountTrustPanel(opts) {
|
|
366
|
+
const origin = normalizeOrigin(opts.origin) || TRUST_PANEL_ORIGIN;
|
|
367
|
+
const timeoutMs = clampInt(opts.timeoutMs, DEFAULT_TIMEOUT_MS2, 1e3, 12e4);
|
|
368
|
+
let settled = false;
|
|
369
|
+
let onMessage = null;
|
|
370
|
+
let timer = null;
|
|
371
|
+
let frame = null;
|
|
372
|
+
let resolveReady;
|
|
373
|
+
const ready = new Promise((res) => {
|
|
374
|
+
resolveReady = res;
|
|
375
|
+
});
|
|
376
|
+
function settle(result, reason) {
|
|
377
|
+
if (settled) return;
|
|
378
|
+
settled = true;
|
|
379
|
+
if (timer) safe(() => clearTimeout(timer));
|
|
380
|
+
if (onMessage) safe(() => window.removeEventListener("message", onMessage));
|
|
381
|
+
if (result) {
|
|
382
|
+
safe(() => opts.onToken?.(result));
|
|
383
|
+
resolveReady(result);
|
|
384
|
+
} else {
|
|
385
|
+
const why = reason || "unavailable";
|
|
386
|
+
safe(() => opts.onUnavailable?.(why));
|
|
387
|
+
resolveReady({ token: null, expiresAt: null, reason: why });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
try {
|
|
391
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
392
|
+
queueMicrotask(() => settle(null, "no_dom"));
|
|
393
|
+
return makeHandle();
|
|
394
|
+
}
|
|
395
|
+
const host = resolveTarget(opts.target);
|
|
396
|
+
frame = createFrame(origin, opts.publicKey);
|
|
397
|
+
if (!host) {
|
|
398
|
+
queueMicrotask(() => settle(null, "no_mount_target"));
|
|
399
|
+
return makeHandle();
|
|
400
|
+
}
|
|
401
|
+
onMessage = (ev) => {
|
|
402
|
+
if (ev.origin !== origin) return;
|
|
403
|
+
if (!ev.data || !frame || ev.source !== frame.contentWindow) return;
|
|
404
|
+
const d = ev.data;
|
|
405
|
+
if (d.type === "cd-trust-size" && typeof d.height === "number") {
|
|
406
|
+
safe(() => {
|
|
407
|
+
if (frame) frame.style.height = clampInt(d.height, INITIAL_HEIGHT_PX, MIN_HEIGHT_PX, MAX_HEIGHT_PX) + "px";
|
|
408
|
+
});
|
|
409
|
+
} else if (d.type === "cd-trust-token" && typeof d.token === "string") {
|
|
410
|
+
settle({ token: d.token, expiresAt: typeof d.expMs === "number" ? d.expMs : null });
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
window.addEventListener("message", onMessage);
|
|
414
|
+
host.appendChild(frame);
|
|
415
|
+
timer = setTimeout(() => settle(null, "timeout"), timeoutMs);
|
|
416
|
+
} catch (err) {
|
|
417
|
+
queueMicrotask(() => settle(null, "mount_error:" + safeMessage(err)));
|
|
418
|
+
}
|
|
419
|
+
return makeHandle();
|
|
420
|
+
function makeHandle() {
|
|
421
|
+
return {
|
|
422
|
+
frame,
|
|
423
|
+
ready,
|
|
424
|
+
destroy() {
|
|
425
|
+
if (onMessage) safe(() => window.removeEventListener("message", onMessage));
|
|
426
|
+
if (timer) safe(() => clearTimeout(timer));
|
|
427
|
+
safe(() => frame?.parentNode?.removeChild(frame));
|
|
428
|
+
settle(null, "destroyed");
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function createFrame(origin, publicKey) {
|
|
434
|
+
const frame = document.createElement("iframe");
|
|
435
|
+
frame.title = "Protected by Crossdeck Trust";
|
|
436
|
+
frame.setAttribute("aria-label", "Protected by Crossdeck Trust");
|
|
437
|
+
frame.setAttribute("scrolling", "no");
|
|
438
|
+
frame.setAttribute("allowtransparency", "true");
|
|
439
|
+
frame.style.cssText = "border:0;display:block;width:100%;max-width:" + MAX_WIDTH_PX + "px;height:" + INITIAL_HEIGHT_PX + "px;margin:0;background:transparent;color-scheme:light;";
|
|
440
|
+
frame.src = origin + "/panel?k=" + encodeURIComponent(publicKey || "");
|
|
441
|
+
return frame;
|
|
442
|
+
}
|
|
443
|
+
function resolveTarget(target) {
|
|
444
|
+
try {
|
|
445
|
+
if (typeof target === "string") return document.querySelector(target);
|
|
446
|
+
return target || null;
|
|
447
|
+
} catch {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
function normalizeOrigin(o) {
|
|
452
|
+
if (!o || typeof o !== "string") return null;
|
|
453
|
+
try {
|
|
454
|
+
return new URL(o).origin;
|
|
455
|
+
} catch {
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
function clampInt(v, fallback, min, max) {
|
|
460
|
+
const n = typeof v === "number" && isFinite(v) ? v : fallback;
|
|
461
|
+
return Math.min(Math.max(n, min), max);
|
|
462
|
+
}
|
|
463
|
+
function safe(fn) {
|
|
464
|
+
try {
|
|
465
|
+
fn();
|
|
466
|
+
} catch {
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
function safeMessage(err) {
|
|
470
|
+
try {
|
|
471
|
+
return err instanceof Error ? err.message : String(err);
|
|
472
|
+
} catch {
|
|
473
|
+
return "unknown";
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
357
477
|
// src/hash.ts
|
|
358
478
|
var K = new Uint32Array([
|
|
359
479
|
1116352408,
|
|
@@ -5816,6 +5936,30 @@ var CrossdeckClient = class {
|
|
|
5816
5936
|
getAnonymousId() {
|
|
5817
5937
|
return this.state ? this.state.identity.anonymousId : null;
|
|
5818
5938
|
}
|
|
5939
|
+
/**
|
|
5940
|
+
* **Crossdeck Trust** — human-proof at your signup, native to the SDK.
|
|
5941
|
+
*
|
|
5942
|
+
* `Crossdeck.trust.panel({ target, onToken })` renders the branded, un-restylable
|
|
5943
|
+
* Trust panel (the same cross-origin iframe on every install) and mints a
|
|
5944
|
+
* single-use attestation. Hand the token to your server and verify it at the gate
|
|
5945
|
+
* (`crossdeck.trust.gate(...)` in @cross-deck/node). The publishable key is taken
|
|
5946
|
+
* from your `init()` — you don't pass it again.
|
|
5947
|
+
*
|
|
5948
|
+
* Fail-open by contract: if the panel can't mint (adblocker, offline, our outage),
|
|
5949
|
+
* `ready` resolves with `{ token: null }` and your signup proceeds — the server
|
|
5950
|
+
* scores the missing token. It never throws and never blocks your form.
|
|
5951
|
+
*
|
|
5952
|
+
* @example
|
|
5953
|
+
* const { ready } = Crossdeck.trust.panel({ target: "#cd-trust" });
|
|
5954
|
+
* const result = await ready; // { token, expiresAt } | { token: null }
|
|
5955
|
+
* await createUser({ email, cdTrustToken: result.token });
|
|
5956
|
+
*/
|
|
5957
|
+
get trust() {
|
|
5958
|
+
const publicKey = this.state ? this.state.options.publicKey : "";
|
|
5959
|
+
return {
|
|
5960
|
+
panel: (input) => mountTrustPanel({ ...input, publicKey })
|
|
5961
|
+
};
|
|
5962
|
+
}
|
|
5819
5963
|
// ---------- private helpers ----------
|
|
5820
5964
|
requireStarted() {
|
|
5821
5965
|
if (!this.state) {
|
|
@@ -5975,6 +6119,26 @@ function useEntitlements() {
|
|
|
5975
6119
|
});
|
|
5976
6120
|
return r;
|
|
5977
6121
|
}
|
|
6122
|
+
function useTrustToken() {
|
|
6123
|
+
const el = (0, import_vue.ref)(null);
|
|
6124
|
+
const token = (0, import_vue.ref)(null);
|
|
6125
|
+
const status = (0, import_vue.ref)("pending");
|
|
6126
|
+
(0, import_vue.onMounted)(() => {
|
|
6127
|
+
if (!el.value) return;
|
|
6128
|
+
const handle = Crossdeck.trust.panel({
|
|
6129
|
+
target: el.value,
|
|
6130
|
+
onToken: (t) => {
|
|
6131
|
+
token.value = t.token;
|
|
6132
|
+
status.value = "ready";
|
|
6133
|
+
},
|
|
6134
|
+
onUnavailable: () => {
|
|
6135
|
+
status.value = "unavailable";
|
|
6136
|
+
}
|
|
6137
|
+
});
|
|
6138
|
+
(0, import_vue.onScopeDispose)(() => handle.destroy());
|
|
6139
|
+
});
|
|
6140
|
+
return { el, token, status };
|
|
6141
|
+
}
|
|
5978
6142
|
function safeIsEntitled(key) {
|
|
5979
6143
|
try {
|
|
5980
6144
|
return Crossdeck.isEntitled(key);
|
|
@@ -5992,6 +6156,7 @@ function safeListKeys() {
|
|
|
5992
6156
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5993
6157
|
0 && (module.exports = {
|
|
5994
6158
|
useEntitlement,
|
|
5995
|
-
useEntitlements
|
|
6159
|
+
useEntitlements,
|
|
6160
|
+
useTrustToken
|
|
5996
6161
|
});
|
|
5997
6162
|
//# sourceMappingURL=vue.cjs.map
|