@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/vue.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Ref } from 'vue';
2
+ import { e as TrustTokenStatus } from './trust-C0RcpR5I.mjs';
2
3
 
3
4
  /**
4
5
  * @cross-deck/web/vue — Vue 3 composables for the Crossdeck SDK.
@@ -33,5 +34,28 @@ declare function useEntitlement(key: string): Ref<boolean>;
33
34
  * mutation. Useful for rendering a "you have unlocked: ..." block.
34
35
  */
35
36
  declare function useEntitlements(): Ref<readonly string[]>;
37
+ /**
38
+ * Crossdeck Trust — the human-proof panel as a Vue composable.
39
+ *
40
+ * Bind `el` to the element the panel mounts into; read `token` / `status`
41
+ * reactively. Sits on `Crossdeck.trust.panel(...)`, takes the publishable key
42
+ * from `init()`, and is fail-open (can't mint → status "unavailable", signup
43
+ * still proceeds, server scores the absent token). Never throws.
44
+ *
45
+ * @example
46
+ * <script setup>
47
+ * import { useTrustToken } from "@cross-deck/web/vue";
48
+ * const { el, token, status } = useTrustToken();
49
+ * </script>
50
+ * <template><div ref="el" /></template>
51
+ */
52
+ declare function useTrustToken(): {
53
+ /** Template ref — bind to the mount element: `<div ref="el" />`. */
54
+ el: Ref<HTMLElement | null>;
55
+ /** The minted token, or null until it mints (or if the panel failed open). */
56
+ token: Ref<string | null>;
57
+ /** Lifecycle: pending → ready (minted) or unavailable (failed open). */
58
+ status: Ref<TrustTokenStatus>;
59
+ };
36
60
 
37
- export { useEntitlement, useEntitlements };
61
+ export { TrustTokenStatus, useEntitlement, useEntitlements, useTrustToken };
package/dist/vue.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Ref } from 'vue';
2
+ import { e as TrustTokenStatus } from './trust-C0RcpR5I.js';
2
3
 
3
4
  /**
4
5
  * @cross-deck/web/vue — Vue 3 composables for the Crossdeck SDK.
@@ -33,5 +34,28 @@ declare function useEntitlement(key: string): Ref<boolean>;
33
34
  * mutation. Useful for rendering a "you have unlocked: ..." block.
34
35
  */
35
36
  declare function useEntitlements(): Ref<readonly string[]>;
37
+ /**
38
+ * Crossdeck Trust — the human-proof panel as a Vue composable.
39
+ *
40
+ * Bind `el` to the element the panel mounts into; read `token` / `status`
41
+ * reactively. Sits on `Crossdeck.trust.panel(...)`, takes the publishable key
42
+ * from `init()`, and is fail-open (can't mint → status "unavailable", signup
43
+ * still proceeds, server scores the absent token). Never throws.
44
+ *
45
+ * @example
46
+ * <script setup>
47
+ * import { useTrustToken } from "@cross-deck/web/vue";
48
+ * const { el, token, status } = useTrustToken();
49
+ * </script>
50
+ * <template><div ref="el" /></template>
51
+ */
52
+ declare function useTrustToken(): {
53
+ /** Template ref — bind to the mount element: `<div ref="el" />`. */
54
+ el: Ref<HTMLElement | null>;
55
+ /** The minted token, or null until it mints (or if the panel failed open). */
56
+ token: Ref<string | null>;
57
+ /** Lifecycle: pending → ready (minted) or unavailable (failed open). */
58
+ status: Ref<TrustTokenStatus>;
59
+ };
36
60
 
37
- export { useEntitlement, useEntitlements };
61
+ export { TrustTokenStatus, useEntitlement, useEntitlements, useTrustToken };
package/dist/vue.mjs CHANGED
@@ -72,7 +72,7 @@ function typeMapForStatus(status) {
72
72
  }
73
73
 
74
74
  // src/_version.ts
75
- var SDK_VERSION = "1.12.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) {
@@ -5950,6 +6093,26 @@ function useEntitlements() {
5950
6093
  });
5951
6094
  return r;
5952
6095
  }
6096
+ function useTrustToken() {
6097
+ const el = ref(null);
6098
+ const token = ref(null);
6099
+ const status = ref("pending");
6100
+ onMounted(() => {
6101
+ if (!el.value) return;
6102
+ const handle = Crossdeck.trust.panel({
6103
+ target: el.value,
6104
+ onToken: (t) => {
6105
+ token.value = t.token;
6106
+ status.value = "ready";
6107
+ },
6108
+ onUnavailable: () => {
6109
+ status.value = "unavailable";
6110
+ }
6111
+ });
6112
+ onScopeDispose(() => handle.destroy());
6113
+ });
6114
+ return { el, token, status };
6115
+ }
5953
6116
  function safeIsEntitled(key) {
5954
6117
  try {
5955
6118
  return Crossdeck.isEntitled(key);
@@ -5966,6 +6129,7 @@ function safeListKeys() {
5966
6129
  }
5967
6130
  export {
5968
6131
  useEntitlement,
5969
- useEntitlements
6132
+ useEntitlements,
6133
+ useTrustToken
5970
6134
  };
5971
6135
  //# sourceMappingURL=vue.mjs.map