@worldcoin/idkit 4.0.4 → 4.0.6

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/README.md CHANGED
@@ -18,7 +18,11 @@ npm install @worldcoin/idkit
18
18
  ## Basic usage
19
19
 
20
20
  ```tsx
21
- import { useIDKitRequest, orbLegacy, selfieCheck } from "@worldcoin/idkit";
21
+ import {
22
+ useIDKitRequest,
23
+ orbLegacy,
24
+ selfieCheckLegacy,
25
+ } from "@worldcoin/idkit";
22
26
 
23
27
  function Example() {
24
28
  const flow = useIDKitRequest({
@@ -39,7 +43,7 @@ function Example() {
39
43
  }
40
44
  ```
41
45
 
42
- Use `selfieCheck({ signal })` for selfie-check preset requests.
46
+ Use `selfieCheckLegacy({ signal })` for selfie-check preset requests.
43
47
 
44
48
  ```tsx
45
49
  import type { IDKitRequestHookConfig } from "@worldcoin/idkit";
@@ -53,6 +57,45 @@ const config: IDKitRequestHookConfig = {
53
57
  };
54
58
  ```
55
59
 
60
+ ## Widget usage
61
+
62
+ ```tsx
63
+ import { IDKitRequestWidget, orbLegacy } from "@worldcoin/idkit";
64
+
65
+ function WidgetExample() {
66
+ return (
67
+ <IDKitRequestWidget
68
+ open={open}
69
+ onOpenChange={setOpen}
70
+ app_id="app_xxxxx"
71
+ action="my-action"
72
+ rp_context={rpContext}
73
+ allow_legacy_proofs={false}
74
+ preset={orbLegacy({ signal: "user-123" })}
75
+ onSuccess={(result) => {
76
+ // required: runs after verification succeeds
77
+ console.log(result);
78
+ }}
79
+ handleVerify={async (result) => {
80
+ // optional: run host app verification before success screen/callback
81
+ const response = await fetch("/api/verify-proof", {
82
+ method: "POST",
83
+ headers: { "Content-Type": "application/json" },
84
+ body: JSON.stringify(result),
85
+ });
86
+
87
+ if (!response.ok) {
88
+ throw new Error("Proof verification failed");
89
+ }
90
+ }}
91
+ onError={(errorCode) => {
92
+ console.error(errorCode);
93
+ }}
94
+ />
95
+ );
96
+ }
97
+ ```
98
+
56
99
  ## Subpath Exports
57
100
 
58
101
  Pure JS subpath exports for server-side use (no WASM or React required):
package/dist/index.cjs CHANGED
@@ -547,6 +547,7 @@ var WIDGET_STYLES = `
547
547
  animation: idkit-spin 1s linear infinite;
548
548
  }
549
549
  .idkit-spinner svg {
550
+ display: block;
550
551
  width: 24px;
551
552
  height: 24px;
552
553
  }
@@ -719,6 +720,8 @@ var en = {
719
720
  "You've cancelled the request in World App.": "You've cancelled the request in World App.",
720
721
  "Connection lost": "Connection lost",
721
722
  "Please check your connection and try again.": "Please check your connection and try again.",
723
+ "Verification declined": "Verification declined",
724
+ "Failed to verify your credential proof. Please contact the website owner.": "Failed to verify your credential proof. Please contact the website owner.",
722
725
  "We couldn't complete your request. Please try again.": "We couldn't complete your request. Please try again.",
723
726
  "Try Again": "Try Again",
724
727
  "Open World App": "Open World App",
@@ -727,6 +730,7 @@ var en = {
727
730
  "Use phone camera to scan the QR code": "Use phone camera to scan the QR code",
728
731
  "Connecting...": "Connecting...",
729
732
  "Please continue in app": "Please continue in app",
733
+ "Transmitting verification to host app. Please wait...": "Transmitting verification to host app. Please wait...",
730
734
  "You will be redirected to the app, please return to this page once you're done": "You will be redirected to the app, please return to this page once you're done",
731
735
  "Terms & Privacy": "Terms & Privacy"
732
736
  };
@@ -740,6 +744,8 @@ var es = {
740
744
  "You've cancelled the request in World App.": "Has cancelado la solicitud en World App.",
741
745
  "Connection lost": "Conexion perdida",
742
746
  "Please check your connection and try again.": "Por favor verifica tu conexion e intenta de nuevo.",
747
+ "Verification declined": "Verificaci\xF3n rechazada",
748
+ "Failed to verify your credential proof. Please contact the website owner.": "No se pudo verificar tu prueba de credencial. Por favor contacta al propietario del sitio web.",
743
749
  "We couldn't complete your request. Please try again.": "No pudimos completar tu solicitud. Por favor intenta de nuevo.",
744
750
  "Try Again": "Intentar de nuevo",
745
751
  "Open World App": "Abrir World App",
@@ -748,6 +754,7 @@ var es = {
748
754
  "Use phone camera to scan the QR code": "Usa la c\xE1mara del tel\xE9fono para escanear el c\xF3digo QR",
749
755
  "Connecting...": "Conectando...",
750
756
  "Please continue in app": "Por favor contin\xFAa en la aplicaci\xF3n",
757
+ "Transmitting verification to host app. Please wait...": "Enviando verificaci\xF3n a la aplicaci\xF3n anfitriona. Por favor espera...",
751
758
  "You will be redirected to the app, please return to this page once you're done": "Ser\xE1s redirigido a la aplicaci\xF3n, por favor regresa a esta p\xE1gina una vez que hayas terminado",
752
759
  "Terms & Privacy": "T\xE9rminos y privacidad"
753
760
  };
@@ -761,6 +768,8 @@ var th = {
761
768
  "You've cancelled the request in World App.": "\u0E04\u0E38\u0E13\u0E44\u0E14\u0E49\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01\u0E04\u0E33\u0E02\u0E2D\u0E43\u0E19 World App",
762
769
  "Connection lost": "\u0E01\u0E32\u0E23\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D\u0E02\u0E32\u0E14\u0E2B\u0E32\u0E22",
763
770
  "Please check your connection and try again.": "\u0E01\u0E23\u0E38\u0E13\u0E32\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D\u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07",
771
+ "Verification declined": "\u0E01\u0E32\u0E23\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E16\u0E39\u0E01\u0E1B\u0E0F\u0E34\u0E40\u0E2A\u0E18",
772
+ "Failed to verify your credential proof. Please contact the website owner.": "\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E2B\u0E25\u0E31\u0E01\u0E10\u0E32\u0E19\u0E02\u0E2D\u0E07 Credential \u0E44\u0E14\u0E49 \u0E42\u0E1B\u0E23\u0E14\u0E15\u0E34\u0E14\u0E15\u0E48\u0E2D\u0E40\u0E08\u0E49\u0E32\u0E02\u0E2D\u0E07\u0E40\u0E27\u0E47\u0E1A\u0E44\u0E0B\u0E15\u0E4C",
764
773
  "We couldn't complete your request. Please try again.": "\u0E40\u0E23\u0E32\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23\u0E15\u0E32\u0E21\u0E04\u0E33\u0E02\u0E2D\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E44\u0E14\u0E49 \u0E01\u0E23\u0E38\u0E13\u0E32\u0E25\u0E2D\u0E07\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07",
765
774
  "Try Again": "\u0E25\u0E2D\u0E07\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07",
766
775
  "Open World App": "\u0E40\u0E1B\u0E34\u0E14 World App",
@@ -769,6 +778,7 @@ var th = {
769
778
  "Use phone camera to scan the QR code": "\u0E43\u0E0A\u0E49\u0E01\u0E25\u0E49\u0E2D\u0E07\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E2A\u0E41\u0E01\u0E19 QR code",
770
779
  "Connecting...": "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D...",
771
780
  "Please continue in app": "\u0E01\u0E23\u0E38\u0E13\u0E32\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23\u0E15\u0E48\u0E2D\u0E43\u0E19\u0E41\u0E2D\u0E1B",
781
+ "Transmitting verification to host app. Please wait...": "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E2A\u0E48\u0E07\u0E01\u0E32\u0E23\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E44\u0E1B\u0E22\u0E31\u0E07\u0E41\u0E2D\u0E1B\u0E42\u0E2E\u0E2A\u0E15\u0E4C \u0E01\u0E23\u0E38\u0E13\u0E32\u0E23\u0E2D\u0E2A\u0E31\u0E01\u0E04\u0E23\u0E39\u0E48...",
772
782
  "You will be redirected to the app, please return to this page once you're done": "\u0E04\u0E38\u0E13\u0E08\u0E30\u0E16\u0E39\u0E01\u0E19\u0E33\u0E44\u0E1B\u0E22\u0E31\u0E07\u0E41\u0E2D\u0E1B \u0E01\u0E23\u0E38\u0E13\u0E32\u0E01\u0E25\u0E31\u0E1A\u0E21\u0E32\u0E17\u0E35\u0E48\u0E2B\u0E19\u0E49\u0E32\u0E19\u0E35\u0E49\u0E40\u0E21\u0E37\u0E48\u0E2D\u0E40\u0E2A\u0E23\u0E47\u0E08\u0E41\u0E25\u0E49\u0E27",
773
783
  "Terms & Privacy": "\u0E02\u0E49\u0E2D\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E41\u0E25\u0E30\u0E04\u0E27\u0E32\u0E21\u0E40\u0E1B\u0E47\u0E19\u0E2A\u0E48\u0E27\u0E19\u0E15\u0E31\u0E27"
774
784
  };
@@ -1522,9 +1532,9 @@ function WarningIcon(props) {
1522
1532
  var errorCodeVariants = {
1523
1533
  [idkitCore.IDKitErrorCodes.UserRejected]: "cancelled",
1524
1534
  [idkitCore.IDKitErrorCodes.VerificationRejected]: "cancelled",
1525
- [idkitCore.IDKitErrorCodes.FailedByHostApp]: "cancelled",
1526
1535
  [idkitCore.IDKitErrorCodes.Cancelled]: "cancelled",
1527
- [idkitCore.IDKitErrorCodes.ConnectionFailed]: "connection"
1536
+ [idkitCore.IDKitErrorCodes.ConnectionFailed]: "connection",
1537
+ [idkitCore.IDKitErrorCodes.FailedByHostApp]: "host_verification"
1528
1538
  };
1529
1539
  var variantConfig = {
1530
1540
  cancelled: {
@@ -1538,6 +1548,11 @@ var variantConfig = {
1538
1548
  Icon: ErrorIcon
1539
1549
  // placeholder — swap for WifiOffIcon later
1540
1550
  },
1551
+ host_verification: {
1552
+ title: "Verification declined",
1553
+ message: "Failed to verify your credential proof. Please contact the website owner.",
1554
+ Icon: ErrorIcon
1555
+ },
1541
1556
  generic: {
1542
1557
  title: "Something went wrong",
1543
1558
  message: "We couldn't complete your request. Please try again.",
@@ -1574,26 +1589,60 @@ function ErrorState({
1574
1589
  }
1575
1590
  );
1576
1591
  }
1577
- function getVisualStage(isSuccess, isError) {
1578
- if (isSuccess) {
1579
- return "success";
1580
- }
1581
- if (isError) {
1582
- return "error";
1583
- }
1592
+ function HostAppVerificationState({
1593
+ onVerify,
1594
+ onPass,
1595
+ onFail
1596
+ }) {
1597
+ react.useEffect(() => {
1598
+ let cancelled = false;
1599
+ void Promise.resolve(onVerify()).then(() => {
1600
+ if (!cancelled) onPass();
1601
+ }).catch(() => {
1602
+ if (!cancelled) onFail();
1603
+ });
1604
+ return () => {
1605
+ cancelled = true;
1606
+ };
1607
+ }, []);
1608
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1609
+ "div",
1610
+ {
1611
+ style: {
1612
+ display: "flex",
1613
+ flexDirection: "column",
1614
+ alignItems: "center",
1615
+ textAlign: "center"
1616
+ },
1617
+ children: [
1618
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "idkit-spinner", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingIcon, {}) }),
1619
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "idkit-subtext", children: __("Transmitting verification to host app. Please wait...") })
1620
+ ]
1621
+ }
1622
+ );
1623
+ }
1624
+ function getVisualStage(isSuccess, isError, isHostVerifying) {
1625
+ if (isError) return "error";
1626
+ if (isHostVerifying) return "host_verification";
1627
+ if (isSuccess) return "success";
1584
1628
  return "worldid";
1585
1629
  }
1586
1630
  function IDKitRequestWidget({
1587
1631
  open,
1588
1632
  onOpenChange,
1633
+ handleVerify,
1589
1634
  onSuccess,
1590
1635
  onError,
1591
1636
  autoClose = true,
1592
1637
  language,
1593
1638
  ...config
1594
1639
  }) {
1640
+ if (typeof onSuccess !== "function") {
1641
+ throw new Error("IDKitRequestWidget requires an onSuccess callback.");
1642
+ }
1595
1643
  const flow = useIDKitRequest(config);
1596
1644
  const { open: openFlow, reset: resetFlow } = flow;
1645
+ const [hostVerifyResult, setHostVerifyResult] = react.useState(null);
1597
1646
  const lastResultRef = react.useRef(null);
1598
1647
  const lastErrorCodeRef = react.useRef(null);
1599
1648
  react.useEffect(() => {
@@ -1603,34 +1652,42 @@ function IDKitRequestWidget({
1603
1652
  }, [language]);
1604
1653
  react.useEffect(() => {
1605
1654
  if (open) {
1655
+ setHostVerifyResult(null);
1606
1656
  openFlow();
1607
1657
  return;
1608
1658
  }
1659
+ setHostVerifyResult(null);
1660
+ lastResultRef.current = null;
1661
+ lastErrorCodeRef.current = null;
1609
1662
  resetFlow();
1610
1663
  }, [open, openFlow, resetFlow]);
1664
+ const isSuccess = flow.isSuccess && (!handleVerify || hostVerifyResult === "passed");
1665
+ const isError = flow.isError || hostVerifyResult === "failed";
1666
+ const isHostVerifying = flow.isSuccess && Boolean(handleVerify) && hostVerifyResult === null;
1667
+ const effectiveErrorCode = flow.errorCode ?? (hostVerifyResult === "failed" ? idkitCore.IDKitErrorCodes.FailedByHostApp : null);
1611
1668
  react.useEffect(() => {
1612
- if (!flow.result || flow.result === lastResultRef.current) {
1669
+ if (!isSuccess || !flow.result || flow.result === lastResultRef.current) {
1613
1670
  return;
1614
1671
  }
1615
1672
  lastResultRef.current = flow.result;
1616
- void Promise.resolve(onSuccess?.(flow.result)).catch(() => {
1673
+ void Promise.resolve(onSuccess(flow.result)).catch(() => {
1617
1674
  });
1618
- }, [onSuccess, flow.result]);
1675
+ }, [flow.result, isSuccess, onSuccess]);
1619
1676
  react.useEffect(() => {
1620
- if (!flow.errorCode || flow.errorCode === lastErrorCodeRef.current) {
1677
+ if (!effectiveErrorCode || effectiveErrorCode === lastErrorCodeRef.current) {
1621
1678
  return;
1622
1679
  }
1623
- lastErrorCodeRef.current = flow.errorCode;
1624
- void Promise.resolve(onError?.(flow.errorCode)).catch(() => {
1680
+ lastErrorCodeRef.current = effectiveErrorCode;
1681
+ void Promise.resolve(onError?.(effectiveErrorCode)).catch(() => {
1625
1682
  });
1626
- }, [flow.errorCode, onError]);
1683
+ }, [effectiveErrorCode, onError]);
1627
1684
  react.useEffect(() => {
1628
- if (flow.isSuccess && autoClose) {
1685
+ if (isSuccess && autoClose) {
1629
1686
  const timer = setTimeout(() => onOpenChange(false), 2500);
1630
1687
  return () => clearTimeout(timer);
1631
1688
  }
1632
- }, [flow.isSuccess, autoClose, onOpenChange]);
1633
- const stage = getVisualStage(flow.isSuccess, flow.isError);
1689
+ }, [isSuccess, autoClose, onOpenChange]);
1690
+ const stage = getVisualStage(isSuccess, isError, isHostVerifying);
1634
1691
  const showSimulatorCallout = config.environment === "staging";
1635
1692
  return /* @__PURE__ */ jsxRuntime.jsxs(IDKitModal, { open, onOpenChange, children: [
1636
1693
  stage === "worldid" && /* @__PURE__ */ jsxRuntime.jsx(
@@ -1641,12 +1698,23 @@ function IDKitRequestWidget({
1641
1698
  showSimulatorCallout
1642
1699
  }
1643
1700
  ),
1701
+ stage === "host_verification" && /* @__PURE__ */ jsxRuntime.jsx(
1702
+ HostAppVerificationState,
1703
+ {
1704
+ onVerify: () => handleVerify(flow.result),
1705
+ onPass: () => setHostVerifyResult("passed"),
1706
+ onFail: () => setHostVerifyResult("failed")
1707
+ }
1708
+ ),
1644
1709
  stage === "success" && /* @__PURE__ */ jsxRuntime.jsx(SuccessState, {}),
1645
1710
  stage === "error" && /* @__PURE__ */ jsxRuntime.jsx(
1646
1711
  ErrorState,
1647
1712
  {
1648
- errorCode: flow.errorCode,
1713
+ errorCode: effectiveErrorCode,
1649
1714
  onRetry: () => {
1715
+ setHostVerifyResult(null);
1716
+ lastResultRef.current = null;
1717
+ lastErrorCodeRef.current = null;
1650
1718
  resetFlow();
1651
1719
  openFlow();
1652
1720
  }
@@ -1675,9 +1743,9 @@ Object.defineProperty(exports, "secureDocumentLegacy", {
1675
1743
  enumerable: true,
1676
1744
  get: function () { return idkitCore.secureDocumentLegacy; }
1677
1745
  });
1678
- Object.defineProperty(exports, "selfieCheck", {
1746
+ Object.defineProperty(exports, "selfieCheckLegacy", {
1679
1747
  enumerable: true,
1680
- get: function () { return idkitCore.selfieCheck; }
1748
+ get: function () { return idkitCore.selfieCheckLegacy; }
1681
1749
  });
1682
1750
  Object.defineProperty(exports, "signRequest", {
1683
1751
  enumerable: true,