@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
package/dist/react.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import { ReactNode, CSSProperties, RefObject } from 'react';
|
|
2
2
|
import { C as CrossdeckOptions } from './types-iqtsOTGy.mjs';
|
|
3
|
+
import { d as TrustToken, e as TrustTokenStatus } from './trust-C0RcpR5I.mjs';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @cross-deck/web/react — React hooks for the Crossdeck SDK.
|
|
@@ -87,5 +88,42 @@ declare function useEntitlement(key: string): boolean;
|
|
|
87
88
|
* Same pre-init / SSR semantics as `useEntitlement`.
|
|
88
89
|
*/
|
|
89
90
|
declare function useEntitlements(): readonly string[];
|
|
91
|
+
interface CrossdeckTrustProps {
|
|
92
|
+
/** Called once when the panel mints a token. Pass `t.token` to your gate call. */
|
|
93
|
+
onToken?: (t: TrustToken) => void;
|
|
94
|
+
/**
|
|
95
|
+
* Called if the panel could not mint (adblocker, offline, our outage, timeout).
|
|
96
|
+
* INFORMATIONAL — not an error to handle. The signup should still proceed.
|
|
97
|
+
*/
|
|
98
|
+
onUnavailable?: (reason: string) => void;
|
|
99
|
+
/** Class on the wrapper element the panel mounts into. */
|
|
100
|
+
className?: string;
|
|
101
|
+
/** Inline style on the wrapper element. */
|
|
102
|
+
style?: CSSProperties;
|
|
103
|
+
/** id on the wrapper element. */
|
|
104
|
+
id?: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* `<CrossdeckTrust onToken={setToken} />` — drop it on your signup form. Renders
|
|
108
|
+
* the same cross-origin Trust panel every install gets, mints a single-use
|
|
109
|
+
* attestation, and calls `onToken` with it. SSR-safe (mounts on the client).
|
|
110
|
+
*/
|
|
111
|
+
declare function CrossdeckTrust(props: CrossdeckTrustProps): ReactNode;
|
|
112
|
+
/**
|
|
113
|
+
* Headless Trust — mount the panel and read the token from React state.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* const { ref, token, status } = useTrustToken();
|
|
117
|
+
* return <><input name="email" /><div ref={ref} /></>;
|
|
118
|
+
* // then send `token` to your server; `status` is "pending" | "ready" | "unavailable".
|
|
119
|
+
*/
|
|
120
|
+
declare function useTrustToken(): {
|
|
121
|
+
/** Attach to the element the panel should mount into: `<div ref={ref} />`. */
|
|
122
|
+
ref: RefObject<HTMLDivElement | null>;
|
|
123
|
+
/** The minted token, or null until it mints (or if the panel failed open). */
|
|
124
|
+
token: string | null;
|
|
125
|
+
/** Lifecycle: pending → ready (minted) or unavailable (failed open). */
|
|
126
|
+
status: TrustTokenStatus;
|
|
127
|
+
};
|
|
90
128
|
|
|
91
|
-
export { CrossdeckProvider, useEntitlement, useEntitlements };
|
|
129
|
+
export { CrossdeckProvider, CrossdeckTrust, type CrossdeckTrustProps, TrustTokenStatus, useEntitlement, useEntitlements, useTrustToken };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import { ReactNode, CSSProperties, RefObject } from 'react';
|
|
2
2
|
import { C as CrossdeckOptions } from './types-iqtsOTGy.js';
|
|
3
|
+
import { d as TrustToken, e as TrustTokenStatus } from './trust-C0RcpR5I.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @cross-deck/web/react — React hooks for the Crossdeck SDK.
|
|
@@ -87,5 +88,42 @@ declare function useEntitlement(key: string): boolean;
|
|
|
87
88
|
* Same pre-init / SSR semantics as `useEntitlement`.
|
|
88
89
|
*/
|
|
89
90
|
declare function useEntitlements(): readonly string[];
|
|
91
|
+
interface CrossdeckTrustProps {
|
|
92
|
+
/** Called once when the panel mints a token. Pass `t.token` to your gate call. */
|
|
93
|
+
onToken?: (t: TrustToken) => void;
|
|
94
|
+
/**
|
|
95
|
+
* Called if the panel could not mint (adblocker, offline, our outage, timeout).
|
|
96
|
+
* INFORMATIONAL — not an error to handle. The signup should still proceed.
|
|
97
|
+
*/
|
|
98
|
+
onUnavailable?: (reason: string) => void;
|
|
99
|
+
/** Class on the wrapper element the panel mounts into. */
|
|
100
|
+
className?: string;
|
|
101
|
+
/** Inline style on the wrapper element. */
|
|
102
|
+
style?: CSSProperties;
|
|
103
|
+
/** id on the wrapper element. */
|
|
104
|
+
id?: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* `<CrossdeckTrust onToken={setToken} />` — drop it on your signup form. Renders
|
|
108
|
+
* the same cross-origin Trust panel every install gets, mints a single-use
|
|
109
|
+
* attestation, and calls `onToken` with it. SSR-safe (mounts on the client).
|
|
110
|
+
*/
|
|
111
|
+
declare function CrossdeckTrust(props: CrossdeckTrustProps): ReactNode;
|
|
112
|
+
/**
|
|
113
|
+
* Headless Trust — mount the panel and read the token from React state.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* const { ref, token, status } = useTrustToken();
|
|
117
|
+
* return <><input name="email" /><div ref={ref} /></>;
|
|
118
|
+
* // then send `token` to your server; `status` is "pending" | "ready" | "unavailable".
|
|
119
|
+
*/
|
|
120
|
+
declare function useTrustToken(): {
|
|
121
|
+
/** Attach to the element the panel should mount into: `<div ref={ref} />`. */
|
|
122
|
+
ref: RefObject<HTMLDivElement | null>;
|
|
123
|
+
/** The minted token, or null until it mints (or if the panel failed open). */
|
|
124
|
+
token: string | null;
|
|
125
|
+
/** Lifecycle: pending → ready (minted) or unavailable (failed open). */
|
|
126
|
+
status: TrustTokenStatus;
|
|
127
|
+
};
|
|
90
128
|
|
|
91
|
-
export { CrossdeckProvider, useEntitlement, useEntitlements };
|
|
129
|
+
export { CrossdeckProvider, CrossdeckTrust, type CrossdeckTrustProps, TrustTokenStatus, useEntitlement, useEntitlements, useTrustToken };
|
package/dist/react.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/react.ts
|
|
2
|
-
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { createElement, useEffect, useRef, useState } from "react";
|
|
3
3
|
|
|
4
4
|
// src/errors.ts
|
|
5
5
|
var CrossdeckError = class _CrossdeckError extends Error {
|
|
@@ -72,7 +72,7 @@ function typeMapForStatus(status) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// src/_version.ts
|
|
75
|
-
var SDK_VERSION = "1.
|
|
75
|
+
var SDK_VERSION = "1.13.0";
|
|
76
76
|
var SDK_NAME = "@cross-deck/web";
|
|
77
77
|
|
|
78
78
|
// src/http.ts
|
|
@@ -329,6 +329,125 @@ function randomChars(count) {
|
|
|
329
329
|
return out.join("");
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
// src/trust.ts
|
|
333
|
+
var TRUST_PANEL_ORIGIN = "https://trust.cross-deck.com";
|
|
334
|
+
var MAX_WIDTH_PX = 360;
|
|
335
|
+
var INITIAL_HEIGHT_PX = 132;
|
|
336
|
+
var MIN_HEIGHT_PX = 96;
|
|
337
|
+
var MAX_HEIGHT_PX = 220;
|
|
338
|
+
var DEFAULT_TIMEOUT_MS2 = 15e3;
|
|
339
|
+
function mountTrustPanel(opts) {
|
|
340
|
+
const origin = normalizeOrigin(opts.origin) || TRUST_PANEL_ORIGIN;
|
|
341
|
+
const timeoutMs = clampInt(opts.timeoutMs, DEFAULT_TIMEOUT_MS2, 1e3, 12e4);
|
|
342
|
+
let settled = false;
|
|
343
|
+
let onMessage = null;
|
|
344
|
+
let timer = null;
|
|
345
|
+
let frame = null;
|
|
346
|
+
let resolveReady;
|
|
347
|
+
const ready = new Promise((res) => {
|
|
348
|
+
resolveReady = res;
|
|
349
|
+
});
|
|
350
|
+
function settle(result, reason) {
|
|
351
|
+
if (settled) return;
|
|
352
|
+
settled = true;
|
|
353
|
+
if (timer) safe(() => clearTimeout(timer));
|
|
354
|
+
if (onMessage) safe(() => window.removeEventListener("message", onMessage));
|
|
355
|
+
if (result) {
|
|
356
|
+
safe(() => opts.onToken?.(result));
|
|
357
|
+
resolveReady(result);
|
|
358
|
+
} else {
|
|
359
|
+
const why = reason || "unavailable";
|
|
360
|
+
safe(() => opts.onUnavailable?.(why));
|
|
361
|
+
resolveReady({ token: null, expiresAt: null, reason: why });
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
try {
|
|
365
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
366
|
+
queueMicrotask(() => settle(null, "no_dom"));
|
|
367
|
+
return makeHandle();
|
|
368
|
+
}
|
|
369
|
+
const host = resolveTarget(opts.target);
|
|
370
|
+
frame = createFrame(origin, opts.publicKey);
|
|
371
|
+
if (!host) {
|
|
372
|
+
queueMicrotask(() => settle(null, "no_mount_target"));
|
|
373
|
+
return makeHandle();
|
|
374
|
+
}
|
|
375
|
+
onMessage = (ev) => {
|
|
376
|
+
if (ev.origin !== origin) return;
|
|
377
|
+
if (!ev.data || !frame || ev.source !== frame.contentWindow) return;
|
|
378
|
+
const d = ev.data;
|
|
379
|
+
if (d.type === "cd-trust-size" && typeof d.height === "number") {
|
|
380
|
+
safe(() => {
|
|
381
|
+
if (frame) frame.style.height = clampInt(d.height, INITIAL_HEIGHT_PX, MIN_HEIGHT_PX, MAX_HEIGHT_PX) + "px";
|
|
382
|
+
});
|
|
383
|
+
} else if (d.type === "cd-trust-token" && typeof d.token === "string") {
|
|
384
|
+
settle({ token: d.token, expiresAt: typeof d.expMs === "number" ? d.expMs : null });
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
window.addEventListener("message", onMessage);
|
|
388
|
+
host.appendChild(frame);
|
|
389
|
+
timer = setTimeout(() => settle(null, "timeout"), timeoutMs);
|
|
390
|
+
} catch (err) {
|
|
391
|
+
queueMicrotask(() => settle(null, "mount_error:" + safeMessage(err)));
|
|
392
|
+
}
|
|
393
|
+
return makeHandle();
|
|
394
|
+
function makeHandle() {
|
|
395
|
+
return {
|
|
396
|
+
frame,
|
|
397
|
+
ready,
|
|
398
|
+
destroy() {
|
|
399
|
+
if (onMessage) safe(() => window.removeEventListener("message", onMessage));
|
|
400
|
+
if (timer) safe(() => clearTimeout(timer));
|
|
401
|
+
safe(() => frame?.parentNode?.removeChild(frame));
|
|
402
|
+
settle(null, "destroyed");
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function createFrame(origin, publicKey) {
|
|
408
|
+
const frame = document.createElement("iframe");
|
|
409
|
+
frame.title = "Protected by Crossdeck Trust";
|
|
410
|
+
frame.setAttribute("aria-label", "Protected by Crossdeck Trust");
|
|
411
|
+
frame.setAttribute("scrolling", "no");
|
|
412
|
+
frame.setAttribute("allowtransparency", "true");
|
|
413
|
+
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;";
|
|
414
|
+
frame.src = origin + "/panel?k=" + encodeURIComponent(publicKey || "");
|
|
415
|
+
return frame;
|
|
416
|
+
}
|
|
417
|
+
function resolveTarget(target) {
|
|
418
|
+
try {
|
|
419
|
+
if (typeof target === "string") return document.querySelector(target);
|
|
420
|
+
return target || null;
|
|
421
|
+
} catch {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function normalizeOrigin(o) {
|
|
426
|
+
if (!o || typeof o !== "string") return null;
|
|
427
|
+
try {
|
|
428
|
+
return new URL(o).origin;
|
|
429
|
+
} catch {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function clampInt(v, fallback, min, max) {
|
|
434
|
+
const n = typeof v === "number" && isFinite(v) ? v : fallback;
|
|
435
|
+
return Math.min(Math.max(n, min), max);
|
|
436
|
+
}
|
|
437
|
+
function safe(fn) {
|
|
438
|
+
try {
|
|
439
|
+
fn();
|
|
440
|
+
} catch {
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function safeMessage(err) {
|
|
444
|
+
try {
|
|
445
|
+
return err instanceof Error ? err.message : String(err);
|
|
446
|
+
} catch {
|
|
447
|
+
return "unknown";
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
332
451
|
// src/hash.ts
|
|
333
452
|
var K = new Uint32Array([
|
|
334
453
|
1116352408,
|
|
@@ -5791,6 +5910,30 @@ var CrossdeckClient = class {
|
|
|
5791
5910
|
getAnonymousId() {
|
|
5792
5911
|
return this.state ? this.state.identity.anonymousId : null;
|
|
5793
5912
|
}
|
|
5913
|
+
/**
|
|
5914
|
+
* **Crossdeck Trust** — human-proof at your signup, native to the SDK.
|
|
5915
|
+
*
|
|
5916
|
+
* `Crossdeck.trust.panel({ target, onToken })` renders the branded, un-restylable
|
|
5917
|
+
* Trust panel (the same cross-origin iframe on every install) and mints a
|
|
5918
|
+
* single-use attestation. Hand the token to your server and verify it at the gate
|
|
5919
|
+
* (`crossdeck.trust.gate(...)` in @cross-deck/node). The publishable key is taken
|
|
5920
|
+
* from your `init()` — you don't pass it again.
|
|
5921
|
+
*
|
|
5922
|
+
* Fail-open by contract: if the panel can't mint (adblocker, offline, our outage),
|
|
5923
|
+
* `ready` resolves with `{ token: null }` and your signup proceeds — the server
|
|
5924
|
+
* scores the missing token. It never throws and never blocks your form.
|
|
5925
|
+
*
|
|
5926
|
+
* @example
|
|
5927
|
+
* const { ready } = Crossdeck.trust.panel({ target: "#cd-trust" });
|
|
5928
|
+
* const result = await ready; // { token, expiresAt } | { token: null }
|
|
5929
|
+
* await createUser({ email, cdTrustToken: result.token });
|
|
5930
|
+
*/
|
|
5931
|
+
get trust() {
|
|
5932
|
+
const publicKey = this.state ? this.state.options.publicKey : "";
|
|
5933
|
+
return {
|
|
5934
|
+
panel: (input) => mountTrustPanel({ ...input, publicKey })
|
|
5935
|
+
};
|
|
5936
|
+
}
|
|
5794
5937
|
// ---------- private helpers ----------
|
|
5795
5938
|
requireStarted() {
|
|
5796
5939
|
if (!this.state) {
|
|
@@ -5997,9 +6140,47 @@ function safeListKeys() {
|
|
|
5997
6140
|
return [];
|
|
5998
6141
|
}
|
|
5999
6142
|
}
|
|
6143
|
+
function CrossdeckTrust(props) {
|
|
6144
|
+
const { onToken, onUnavailable, className, style, id } = props;
|
|
6145
|
+
const hostRef = useRef(null);
|
|
6146
|
+
const onTokenRef = useRef(onToken);
|
|
6147
|
+
onTokenRef.current = onToken;
|
|
6148
|
+
const onUnavailRef = useRef(onUnavailable);
|
|
6149
|
+
onUnavailRef.current = onUnavailable;
|
|
6150
|
+
useEffect(() => {
|
|
6151
|
+
if (!hostRef.current) return;
|
|
6152
|
+
const handle = Crossdeck.trust.panel({
|
|
6153
|
+
target: hostRef.current,
|
|
6154
|
+
onToken: (t) => onTokenRef.current?.(t),
|
|
6155
|
+
onUnavailable: (r) => onUnavailRef.current?.(r)
|
|
6156
|
+
});
|
|
6157
|
+
return () => handle.destroy();
|
|
6158
|
+
}, []);
|
|
6159
|
+
return createElement("div", { ref: hostRef, className, style, id });
|
|
6160
|
+
}
|
|
6161
|
+
function useTrustToken() {
|
|
6162
|
+
const ref = useRef(null);
|
|
6163
|
+
const [token, setToken] = useState(null);
|
|
6164
|
+
const [status, setStatus] = useState("pending");
|
|
6165
|
+
useEffect(() => {
|
|
6166
|
+
if (!ref.current) return;
|
|
6167
|
+
const handle = Crossdeck.trust.panel({
|
|
6168
|
+
target: ref.current,
|
|
6169
|
+
onToken: (t) => {
|
|
6170
|
+
setToken(t.token);
|
|
6171
|
+
setStatus("ready");
|
|
6172
|
+
},
|
|
6173
|
+
onUnavailable: () => setStatus("unavailable")
|
|
6174
|
+
});
|
|
6175
|
+
return () => handle.destroy();
|
|
6176
|
+
}, []);
|
|
6177
|
+
return { ref, token, status };
|
|
6178
|
+
}
|
|
6000
6179
|
export {
|
|
6001
6180
|
CrossdeckProvider,
|
|
6181
|
+
CrossdeckTrust,
|
|
6002
6182
|
useEntitlement,
|
|
6003
|
-
useEntitlements
|
|
6183
|
+
useEntitlements,
|
|
6184
|
+
useTrustToken
|
|
6004
6185
|
};
|
|
6005
6186
|
//# sourceMappingURL=react.mjs.map
|