@worldcoin/idkit-core 4.0.1-dev.123c6a8 → 4.0.1-dev.370b7c0

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
@@ -1,186 +1,112 @@
1
1
  # @worldcoin/idkit-core
2
2
 
3
- Core bridge logic for IDKit (World ID SDK) powered by Rust/WASM.
3
+ World ID verification SDK for JavaScript/TypeScript. Zero dependencies, WASM-powered.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
8
  npm install @worldcoin/idkit-core
9
- # or
10
- pnpm add @worldcoin/idkit-core
11
9
  ```
12
10
 
13
- ## Quick Start
11
+ ## Backend: Generate RP Signature
12
+
13
+ The RP signature authenticates your verification requests. Generate it server-side using the `/signing` subpath (pure JS, no WASM init needed):
14
14
 
15
15
  ```typescript
16
- import { useWorldBridgeStore } from "@worldcoin/idkit-core";
16
+ import { signRequest } from "@worldcoin/idkit-core/signing";
17
17
 
18
- // 1. Get store instance
19
- const store = useWorldBridgeStore();
18
+ // Never expose RP_SIGNING_KEY to clients
19
+ const sig = signRequest("my-action", process.env.RP_SIGNING_KEY);
20
20
 
21
- // 2. Create client with explicit requests
22
- const client = await store.createClient({
23
- app_id: "app_staging_xxxxx",
24
- action: "my-action",
25
- requests: [{ credential_type: "orb", signal: "user-id-123" }],
21
+ // Return to client
22
+ res.json({
23
+ sig: sig.sig,
24
+ nonce: sig.nonce,
25
+ created_at: sig.createdAt,
26
+ expires_at: sig.expiresAt,
26
27
  });
27
-
28
- // 3. Display QR code for World App
29
- console.log("Scan this:", client.connectorURI);
30
-
31
- // 4. Poll for proof (handles polling automatically)
32
- try {
33
- const proof = await client.pollForUpdates();
34
- console.log("Success:", proof);
35
- } catch (error) {
36
- console.error("Verification failed:", error);
37
- }
38
28
  ```
39
29
 
40
- ## Multiple Credential Types
41
-
42
- You can request verification with multiple credential types. The user can satisfy the request with any of them:
43
-
44
- ```typescript
45
- const client = await store.createClient({
46
- app_id: "app_staging_xxxxx",
47
- action: "my-action",
48
- requests: [
49
- { credential_type: "orb", signal: "user-id-123" },
50
- { credential_type: "device", signal: "user-id-123" },
51
- ],
52
- });
53
- ```
30
+ ## Client: Create Verification Request
54
31
 
55
- ## Credential Types
32
+ ### Using Presets
56
33
 
57
- - `orb` - Verified via Orb biometric scan (highest trust)
58
- - `face` - Verified via Face ID
59
- - `device` - Verified via device binding
60
- - `document` - Verified via document scan
61
- - `secure_document` - Verified via secure document scan
62
-
63
- ## API Reference
64
-
65
- ### Creating a Client
66
-
67
- ```typescript
68
- const client = await store.createClient(config);
69
- ```
70
-
71
- **Config:**
34
+ For common verification scenarios with World ID 3.0 backward compatibility:
72
35
 
73
36
  ```typescript
74
- interface IDKitConfig {
75
- app_id: `app_${string}`; // Your World ID app ID
76
- action: string; // Action identifier
77
- requests: RequestConfig[]; // Required: credential type requests
78
- bridge_url?: string; // Custom bridge URL (optional)
79
- partner?: boolean; // Partner mode (optional)
80
- }
37
+ import { IDKit, orbLegacy } from "@worldcoin/idkit-core";
81
38
 
82
- interface RequestConfig {
83
- credential_type: CredentialType;
84
- signal?: string | AbiEncodedValue; // Optional signal for this request
85
- }
39
+ // Fetch signature from your backend
40
+ const rpSig = await fetch("/api/rp-signature").then((r) => r.json());
86
41
 
87
- type CredentialType =
88
- | "orb"
89
- | "face"
90
- | "device"
91
- | "document"
92
- | "secure_document";
42
+ const request = await IDKit.request({
43
+ app_id: "app_xxxxx",
44
+ action: "my-action",
45
+ rp_context: {
46
+ rp_id: "rp_xxxxx",
47
+ nonce: rpSig.nonce,
48
+ created_at: rpSig.created_at,
49
+ expires_at: rpSig.expires_at,
50
+ signature: rpSig.sig,
51
+ },
52
+ allow_legacy_proofs: false,
53
+ }).preset(orbLegacy({ signal: "user-123" }));
54
+
55
+ // Display QR code for World App
56
+ const qrUrl = request.connectorURI;
93
57
  ```
94
58
 
95
- **Client Properties:**
96
-
97
- - `connectorURI: string` - QR code URL for World App
98
- - `requestId: string` - Unique request ID
59
+ **Available presets:** `orbLegacy`, `documentLegacy`, `secureDocumentLegacy`
99
60
 
100
- **Client Methods:**
61
+ ## Handling the Result
101
62
 
102
- - `pollForUpdates(options?: WaitOptions): Promise<ISuccessResult>` - Poll for proof (auto-polls)
103
- - `pollOnce(): Promise<Status>` - Poll once for status (manual polling)
104
-
105
- **WaitOptions:**
63
+ Poll for the verification proof, then verify it server-side:
106
64
 
107
65
  ```typescript
108
- interface WaitOptions {
109
- pollInterval?: number; // ms between polls (default: 1000)
110
- timeout?: number; // total timeout ms (default: 300000 = 5min)
111
- signal?: AbortSignal; // for cancellation
112
- }
113
- ```
66
+ // Wait for the user to scan and approve
67
+ const completion = await request.pollUntilCompletion({
68
+ pollInterval: 2000,
69
+ timeout: 120_000,
70
+ });
114
71
 
115
- ### Store
72
+ if (!completion.success) {
73
+ console.error("Verification failed:", completion.error);
74
+ return;
75
+ }
116
76
 
117
- ```typescript
118
- const store = useWorldBridgeStore();
77
+ // Send proof to your backend for verification
78
+ const verified = await fetch("/api/verify-proof", {
79
+ method: "POST",
80
+ headers: { "Content-Type": "application/json" },
81
+ body: JSON.stringify(completion.result),
82
+ }).then((r) => r.json());
119
83
  ```
120
84
 
121
- **Methods:**
122
-
123
- - `createClient(config: IDKitConfig): Promise<WorldBridgeClient>` - Create new client
124
- - `reset(): void` - Clear state and start over
125
-
126
- **State (for reactive frameworks):**
127
-
128
- - `verificationState: VerificationState` - Current verification state
129
- - `connectorURI: string | null` - QR code URL for World App
130
- - `result: ISuccessResult | null` - Proof data when verified
131
- - `errorCode: AppErrorCodes | null` - Error code if failed
132
-
133
- ### Result Types
85
+ On your backend, forward the result to the Developer Portal:
134
86
 
135
87
  ```typescript
136
- interface ISuccessResult {
137
- proof: string;
138
- merkle_root: string;
139
- nullifier_hash: string;
140
- verification_level: CredentialType; // The credential type used
141
- }
88
+ const response = await fetch(
89
+ `https://developer.worldcoin.org/api/v4/verify/${RP_ID}`,
90
+ {
91
+ method: "POST",
92
+ headers: { "Content-Type": "application/json" },
93
+ body: JSON.stringify(req.body),
94
+ },
95
+ );
96
+
97
+ const { success } = await response.json();
142
98
  ```
143
99
 
144
- ## React Integration
145
-
146
- ```tsx
147
- import { useWorldBridgeStore, IDKitWidget } from "@worldcoin/idkit-core";
148
-
149
- function MyComponent() {
150
- const handleSuccess = (result) => {
151
- console.log("Verified:", result);
152
- };
153
-
154
- return (
155
- <IDKitWidget
156
- app_id="app_staging_xxxxx"
157
- action="my-action"
158
- requests={[{ credential_type: "orb", signal: "user-123" }]}
159
- onSuccess={handleSuccess}
160
- >
161
- {({ open }) => <button onClick={open}>Verify with World ID</button>}
162
- </IDKitWidget>
163
- );
164
- }
165
- ```
166
-
167
- ## Examples
168
-
169
- See [examples/browser](../../examples/browser) for a complete working example.
100
+ ## Subpath Exports
170
101
 
171
- ## Building from Source
102
+ Pure JS subpath exports are available for server-side use without WASM initialization:
172
103
 
173
- ```bash
174
- # Build WASM module
175
- npm run build:wasm
176
-
177
- # Build TypeScript
178
- npm run build:ts
104
+ | Subpath | Exports |
105
+ | ---------- | ---------------------------------------------------------------- |
106
+ | `/signing` | `signRequest`, `computeRpSignatureMessage`, `RpSignature` (type) |
107
+ | `/hashing` | `hashSignal` |
179
108
 
180
- # Or both
181
- npm run build
109
+ ```typescript
110
+ import { signRequest } from "@worldcoin/idkit-core/signing";
111
+ import { hashSignal } from "@worldcoin/idkit-core/hashing";
182
112
  ```
183
-
184
- ## License
185
-
186
- MIT
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ var sha3 = require('@noble/hashes/sha3');
4
+ var utils = require('@noble/hashes/utils');
5
+
6
+ // src/lib/hashing.ts
7
+ function hashToField(input) {
8
+ const hash = BigInt("0x" + utils.bytesToHex(sha3.keccak_256(input))) >> 8n;
9
+ return utils.hexToBytes(hash.toString(16).padStart(64, "0"));
10
+ }
11
+ function hashSignal(signal) {
12
+ let input;
13
+ if (signal instanceof Uint8Array) {
14
+ input = signal;
15
+ } else if (signal.startsWith("0x") && isValidHex(signal.slice(2))) {
16
+ input = utils.hexToBytes(signal.slice(2));
17
+ } else {
18
+ input = new TextEncoder().encode(signal);
19
+ }
20
+ return "0x" + utils.bytesToHex(hashToField(input));
21
+ }
22
+ function isValidHex(s) {
23
+ if (s.length === 0) return false;
24
+ if (s.length % 2 !== 0) return false;
25
+ return /^[0-9a-fA-F]+$/.test(s);
26
+ }
27
+
28
+ exports.hashSignal = hashSignal;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Hashes a signal to its field element hex representation.
3
+ *
4
+ * @param signal - The signal to hash (string or Uint8Array)
5
+ * @returns 0x-prefixed hex string representing the signal hash
6
+ */
7
+ declare function hashSignal(signal: string | Uint8Array): string;
8
+
9
+ export { hashSignal };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Hashes a signal to its field element hex representation.
3
+ *
4
+ * @param signal - The signal to hash (string or Uint8Array)
5
+ * @returns 0x-prefixed hex string representing the signal hash
6
+ */
7
+ declare function hashSignal(signal: string | Uint8Array): string;
8
+
9
+ export { hashSignal };
@@ -0,0 +1,26 @@
1
+ import { keccak_256 } from '@noble/hashes/sha3';
2
+ import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
3
+
4
+ // src/lib/hashing.ts
5
+ function hashToField(input) {
6
+ const hash = BigInt("0x" + bytesToHex(keccak_256(input))) >> 8n;
7
+ return hexToBytes(hash.toString(16).padStart(64, "0"));
8
+ }
9
+ function hashSignal(signal) {
10
+ let input;
11
+ if (signal instanceof Uint8Array) {
12
+ input = signal;
13
+ } else if (signal.startsWith("0x") && isValidHex(signal.slice(2))) {
14
+ input = hexToBytes(signal.slice(2));
15
+ } else {
16
+ input = new TextEncoder().encode(signal);
17
+ }
18
+ return "0x" + bytesToHex(hashToField(input));
19
+ }
20
+ function isValidHex(s) {
21
+ if (s.length === 0) return false;
22
+ if (s.length % 2 !== 0) return false;
23
+ return /^[0-9a-fA-F]+$/.test(s);
24
+ }
25
+
26
+ export { hashSignal };
Binary file