@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/dist/react.cjs CHANGED
@@ -21,8 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var react_exports = {};
22
22
  __export(react_exports, {
23
23
  CrossdeckProvider: () => CrossdeckProvider,
24
+ CrossdeckTrust: () => CrossdeckTrust,
24
25
  useEntitlement: () => useEntitlement,
25
- useEntitlements: () => useEntitlements
26
+ useEntitlements: () => useEntitlements,
27
+ useTrustToken: () => useTrustToken
26
28
  });
27
29
  module.exports = __toCommonJS(react_exports);
28
30
  var import_react = require("react");
@@ -98,7 +100,7 @@ function typeMapForStatus(status) {
98
100
  }
99
101
 
100
102
  // src/_version.ts
101
- var SDK_VERSION = "1.12.1";
103
+ var SDK_VERSION = "1.13.0";
102
104
  var SDK_NAME = "@cross-deck/web";
103
105
 
104
106
  // src/http.ts
@@ -355,6 +357,125 @@ function randomChars(count) {
355
357
  return out.join("");
356
358
  }
357
359
 
360
+ // src/trust.ts
361
+ var TRUST_PANEL_ORIGIN = "https://trust.cross-deck.com";
362
+ var MAX_WIDTH_PX = 360;
363
+ var INITIAL_HEIGHT_PX = 132;
364
+ var MIN_HEIGHT_PX = 96;
365
+ var MAX_HEIGHT_PX = 220;
366
+ var DEFAULT_TIMEOUT_MS2 = 15e3;
367
+ function mountTrustPanel(opts) {
368
+ const origin = normalizeOrigin(opts.origin) || TRUST_PANEL_ORIGIN;
369
+ const timeoutMs = clampInt(opts.timeoutMs, DEFAULT_TIMEOUT_MS2, 1e3, 12e4);
370
+ let settled = false;
371
+ let onMessage = null;
372
+ let timer = null;
373
+ let frame = null;
374
+ let resolveReady;
375
+ const ready = new Promise((res) => {
376
+ resolveReady = res;
377
+ });
378
+ function settle(result, reason) {
379
+ if (settled) return;
380
+ settled = true;
381
+ if (timer) safe(() => clearTimeout(timer));
382
+ if (onMessage) safe(() => window.removeEventListener("message", onMessage));
383
+ if (result) {
384
+ safe(() => opts.onToken?.(result));
385
+ resolveReady(result);
386
+ } else {
387
+ const why = reason || "unavailable";
388
+ safe(() => opts.onUnavailable?.(why));
389
+ resolveReady({ token: null, expiresAt: null, reason: why });
390
+ }
391
+ }
392
+ try {
393
+ if (typeof window === "undefined" || typeof document === "undefined") {
394
+ queueMicrotask(() => settle(null, "no_dom"));
395
+ return makeHandle();
396
+ }
397
+ const host = resolveTarget(opts.target);
398
+ frame = createFrame(origin, opts.publicKey);
399
+ if (!host) {
400
+ queueMicrotask(() => settle(null, "no_mount_target"));
401
+ return makeHandle();
402
+ }
403
+ onMessage = (ev) => {
404
+ if (ev.origin !== origin) return;
405
+ if (!ev.data || !frame || ev.source !== frame.contentWindow) return;
406
+ const d = ev.data;
407
+ if (d.type === "cd-trust-size" && typeof d.height === "number") {
408
+ safe(() => {
409
+ if (frame) frame.style.height = clampInt(d.height, INITIAL_HEIGHT_PX, MIN_HEIGHT_PX, MAX_HEIGHT_PX) + "px";
410
+ });
411
+ } else if (d.type === "cd-trust-token" && typeof d.token === "string") {
412
+ settle({ token: d.token, expiresAt: typeof d.expMs === "number" ? d.expMs : null });
413
+ }
414
+ };
415
+ window.addEventListener("message", onMessage);
416
+ host.appendChild(frame);
417
+ timer = setTimeout(() => settle(null, "timeout"), timeoutMs);
418
+ } catch (err) {
419
+ queueMicrotask(() => settle(null, "mount_error:" + safeMessage(err)));
420
+ }
421
+ return makeHandle();
422
+ function makeHandle() {
423
+ return {
424
+ frame,
425
+ ready,
426
+ destroy() {
427
+ if (onMessage) safe(() => window.removeEventListener("message", onMessage));
428
+ if (timer) safe(() => clearTimeout(timer));
429
+ safe(() => frame?.parentNode?.removeChild(frame));
430
+ settle(null, "destroyed");
431
+ }
432
+ };
433
+ }
434
+ }
435
+ function createFrame(origin, publicKey) {
436
+ const frame = document.createElement("iframe");
437
+ frame.title = "Protected by Crossdeck Trust";
438
+ frame.setAttribute("aria-label", "Protected by Crossdeck Trust");
439
+ frame.setAttribute("scrolling", "no");
440
+ frame.setAttribute("allowtransparency", "true");
441
+ 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;";
442
+ frame.src = origin + "/panel?k=" + encodeURIComponent(publicKey || "");
443
+ return frame;
444
+ }
445
+ function resolveTarget(target) {
446
+ try {
447
+ if (typeof target === "string") return document.querySelector(target);
448
+ return target || null;
449
+ } catch {
450
+ return null;
451
+ }
452
+ }
453
+ function normalizeOrigin(o) {
454
+ if (!o || typeof o !== "string") return null;
455
+ try {
456
+ return new URL(o).origin;
457
+ } catch {
458
+ return null;
459
+ }
460
+ }
461
+ function clampInt(v, fallback, min, max) {
462
+ const n = typeof v === "number" && isFinite(v) ? v : fallback;
463
+ return Math.min(Math.max(n, min), max);
464
+ }
465
+ function safe(fn) {
466
+ try {
467
+ fn();
468
+ } catch {
469
+ }
470
+ }
471
+ function safeMessage(err) {
472
+ try {
473
+ return err instanceof Error ? err.message : String(err);
474
+ } catch {
475
+ return "unknown";
476
+ }
477
+ }
478
+
358
479
  // src/hash.ts
359
480
  var K = new Uint32Array([
360
481
  1116352408,
@@ -5817,6 +5938,30 @@ var CrossdeckClient = class {
5817
5938
  getAnonymousId() {
5818
5939
  return this.state ? this.state.identity.anonymousId : null;
5819
5940
  }
5941
+ /**
5942
+ * **Crossdeck Trust** — human-proof at your signup, native to the SDK.
5943
+ *
5944
+ * `Crossdeck.trust.panel({ target, onToken })` renders the branded, un-restylable
5945
+ * Trust panel (the same cross-origin iframe on every install) and mints a
5946
+ * single-use attestation. Hand the token to your server and verify it at the gate
5947
+ * (`crossdeck.trust.gate(...)` in @cross-deck/node). The publishable key is taken
5948
+ * from your `init()` — you don't pass it again.
5949
+ *
5950
+ * Fail-open by contract: if the panel can't mint (adblocker, offline, our outage),
5951
+ * `ready` resolves with `{ token: null }` and your signup proceeds — the server
5952
+ * scores the missing token. It never throws and never blocks your form.
5953
+ *
5954
+ * @example
5955
+ * const { ready } = Crossdeck.trust.panel({ target: "#cd-trust" });
5956
+ * const result = await ready; // { token, expiresAt } | { token: null }
5957
+ * await createUser({ email, cdTrustToken: result.token });
5958
+ */
5959
+ get trust() {
5960
+ const publicKey = this.state ? this.state.options.publicKey : "";
5961
+ return {
5962
+ panel: (input) => mountTrustPanel({ ...input, publicKey })
5963
+ };
5964
+ }
5820
5965
  // ---------- private helpers ----------
5821
5966
  requireStarted() {
5822
5967
  if (!this.state) {
@@ -6023,10 +6168,48 @@ function safeListKeys() {
6023
6168
  return [];
6024
6169
  }
6025
6170
  }
6171
+ function CrossdeckTrust(props) {
6172
+ const { onToken, onUnavailable, className, style, id } = props;
6173
+ const hostRef = (0, import_react.useRef)(null);
6174
+ const onTokenRef = (0, import_react.useRef)(onToken);
6175
+ onTokenRef.current = onToken;
6176
+ const onUnavailRef = (0, import_react.useRef)(onUnavailable);
6177
+ onUnavailRef.current = onUnavailable;
6178
+ (0, import_react.useEffect)(() => {
6179
+ if (!hostRef.current) return;
6180
+ const handle = Crossdeck.trust.panel({
6181
+ target: hostRef.current,
6182
+ onToken: (t) => onTokenRef.current?.(t),
6183
+ onUnavailable: (r) => onUnavailRef.current?.(r)
6184
+ });
6185
+ return () => handle.destroy();
6186
+ }, []);
6187
+ return (0, import_react.createElement)("div", { ref: hostRef, className, style, id });
6188
+ }
6189
+ function useTrustToken() {
6190
+ const ref = (0, import_react.useRef)(null);
6191
+ const [token, setToken] = (0, import_react.useState)(null);
6192
+ const [status, setStatus] = (0, import_react.useState)("pending");
6193
+ (0, import_react.useEffect)(() => {
6194
+ if (!ref.current) return;
6195
+ const handle = Crossdeck.trust.panel({
6196
+ target: ref.current,
6197
+ onToken: (t) => {
6198
+ setToken(t.token);
6199
+ setStatus("ready");
6200
+ },
6201
+ onUnavailable: () => setStatus("unavailable")
6202
+ });
6203
+ return () => handle.destroy();
6204
+ }, []);
6205
+ return { ref, token, status };
6206
+ }
6026
6207
  // Annotate the CommonJS export names for ESM import in node:
6027
6208
  0 && (module.exports = {
6028
6209
  CrossdeckProvider,
6210
+ CrossdeckTrust,
6029
6211
  useEntitlement,
6030
- useEntitlements
6212
+ useEntitlements,
6213
+ useTrustToken
6031
6214
  });
6032
6215
  //# sourceMappingURL=react.cjs.map