@neus/sdk 1.0.9 → 1.0.12
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 +161 -57
- package/SECURITY.md +1 -1
- package/cjs/client.cjs +67 -7
- package/cjs/index.cjs +67 -7
- package/cli/neus.mjs +113 -4
- package/client.js +96 -13
- package/errors.js +1 -1
- package/package.json +2 -2
- package/types.d.ts +18 -1
- package/widgets/README.md +1 -1
- package/widgets/verify-gate/dist/VerifyGate.js +9 -9
package/README.md
CHANGED
|
@@ -1,104 +1,208 @@
|
|
|
1
1
|
# @neus/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Create, check, and reuse NEUS trust receipts from apps and backends. The same package ships the **`neus`** CLI for wiring **hosted NEUS MCP** into editors and agents.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
NEUS makes trust portable across the internet so people, apps, and AI agents can prove what is real before access, payout, or execution.
|
|
6
6
|
|
|
7
|
-
## Install
|
|
7
|
+
## Install (library)
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install @neus/sdk
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Connect editors and assistants (MCP)
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
import { getHostedCheckoutUrl } from '@neus/sdk';
|
|
15
|
+
Use one command to merge NEUS into Cursor, VS Code, and Claude Code when those tools are detected. No separate NEUS editor extension is required.
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
returnUrl: 'https://myapp.com/neus/callback',
|
|
21
|
-
});
|
|
17
|
+
```bash
|
|
18
|
+
npx -y -p @neus/sdk neus setup
|
|
22
19
|
```
|
|
23
20
|
|
|
24
|
-
|
|
21
|
+
Add your NEUS Profile access key in the same step (needed for account-aware tools such as `neus_me`):
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
```bash
|
|
24
|
+
npx -y -p @neus/sdk neus setup --access-key <npk_...>
|
|
25
|
+
```
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
import { NeusClient } from '@neus/sdk';
|
|
27
|
+
Check configuration and connectivity:
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
```bash
|
|
30
|
+
npx -y -p @neus/sdk neus doctor
|
|
31
|
+
```
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
Create keys under **Profile → Account → Access keys** on [neus.network](https://neus.network/profile?tab=account). Never put access keys in browser bundles or public repos.
|
|
34
|
+
|
|
35
|
+
| Topic | Link |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| Setup, JSON snippets, and headers | [MCP setup](https://docs.neus.network/mcp/setup) |
|
|
38
|
+
| Tools and session order | [MCP overview](https://docs.neus.network/mcp/overview) |
|
|
39
|
+
| Discovery URLs | [Discovery and endpoints](https://docs.neus.network/mcp/endpoints) |
|
|
40
|
+
| Optional Claude Code plugin + skill | [NEUS for Claude Code](https://docs.neus.network/mcp/claude-code-marketplace) |
|
|
41
|
+
|
|
42
|
+
Prefer `neus setup` over hand-editing config files so every host stays on **`https://mcp.neus.network/mcp`**.
|
|
43
|
+
|
|
44
|
+
## What you can build
|
|
45
|
+
|
|
46
|
+
- Issue a proof that a user, wallet, org, app, file, release, profile, or result belongs to someone
|
|
47
|
+
- Store the returned `qHash` as a durable trust receipt ID
|
|
48
|
+
- Check receipts later for access, eligibility, provenance, or display
|
|
49
|
+
- Add proof-gated UX with React widgets
|
|
50
|
+
- Connect IDEs and agents through optional MCP
|
|
51
|
+
|
|
52
|
+
## Fastest path: Hosted Verify
|
|
53
|
+
|
|
54
|
+
Use Hosted Verify when you want NEUS to handle the signing/verification flow outside your app UI.
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
import { getHostedCheckoutUrl } from '@neus/sdk';
|
|
58
|
+
|
|
59
|
+
const url = getHostedCheckoutUrl({
|
|
60
|
+
verifiers: ['ownership-basic'],
|
|
61
|
+
returnUrl: 'https://yourapp.com/auth/callback'
|
|
36
62
|
});
|
|
63
|
+
|
|
64
|
+
window.location.assign(url);
|
|
37
65
|
```
|
|
38
66
|
|
|
39
|
-
|
|
67
|
+
After completion, NEUS redirects back with a `qHash`.
|
|
68
|
+
|
|
69
|
+
Store that `qHash` with your user record.
|
|
40
70
|
|
|
41
|
-
|
|
71
|
+
## Create a signed receipt directly
|
|
42
72
|
|
|
43
|
-
|
|
73
|
+
When your app handles signing. This example is EVM. For non-EVM wallets, pass the provider explicitly and include `chain` as a CAIP-2 value; see the CAIP-380 standards page in the docs.
|
|
74
|
+
|
|
75
|
+
```js
|
|
44
76
|
import { NeusClient } from '@neus/sdk';
|
|
45
77
|
|
|
46
|
-
const client = new NeusClient({
|
|
78
|
+
const client = new NeusClient({
|
|
79
|
+
appId: 'your-app-id'
|
|
80
|
+
});
|
|
47
81
|
|
|
48
82
|
const proof = await client.verify({
|
|
49
83
|
verifier: 'ownership-basic',
|
|
50
|
-
|
|
51
|
-
|
|
84
|
+
data: {
|
|
85
|
+
owner: '0x...',
|
|
86
|
+
contentType: 'application/json',
|
|
87
|
+
content: JSON.stringify({
|
|
88
|
+
title: 'Verified claim',
|
|
89
|
+
type: 'project-update',
|
|
90
|
+
summary: 'Public summary of what is being proven.'
|
|
91
|
+
}),
|
|
92
|
+
reference: {
|
|
93
|
+
type: 'url',
|
|
94
|
+
id: 'https://example.com/source',
|
|
95
|
+
title: 'Source record'
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
wallet: window.ethereum // EVM provider
|
|
52
99
|
});
|
|
53
|
-
const qHash = proof.qHash;
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Core methods
|
|
57
100
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
| `client.getProof()` | Fetch by `qHash` |
|
|
62
|
-
| `client.pollProofStatus()` | Wait for async completion |
|
|
63
|
-
| `client.gateCheck()` | **Server eligibility** (use for real gates) |
|
|
64
|
-
| `client.checkGate()` | Local preview only |
|
|
65
|
-
| `getHostedCheckoutUrl()` | Hosted verify URL |
|
|
66
|
-
| `client.createWalletLinkData()` | Build advanced direct wallet-link payload |
|
|
101
|
+
console.log(proof.qHash);
|
|
102
|
+
console.log(proof.proofUrl);
|
|
103
|
+
```
|
|
67
104
|
|
|
68
|
-
##
|
|
105
|
+
## React widget
|
|
69
106
|
|
|
70
|
-
|
|
107
|
+
Use `VerifyGate` when you want a drop-in verification flow in React.
|
|
71
108
|
|
|
72
109
|
```jsx
|
|
73
110
|
import { VerifyGate } from '@neus/sdk/widgets';
|
|
74
111
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
112
|
+
export function Page() {
|
|
113
|
+
return (
|
|
114
|
+
<VerifyGate
|
|
115
|
+
appId="your-app-id"
|
|
116
|
+
requiredVerifiers={['ownership-basic']}
|
|
117
|
+
verifierData={{
|
|
118
|
+
'ownership-basic': {
|
|
119
|
+
owner: '0x...',
|
|
120
|
+
contentType: 'application/json',
|
|
121
|
+
content: JSON.stringify({
|
|
122
|
+
title: 'Verified claim',
|
|
123
|
+
summary: 'Public summary of what is being proven.'
|
|
124
|
+
}),
|
|
125
|
+
reference: {
|
|
126
|
+
type: 'url',
|
|
127
|
+
id: 'https://example.com/source'
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}}
|
|
131
|
+
onVerified={(result) => {
|
|
132
|
+
console.log(result.qHash || result.qHashes);
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Check receipts
|
|
140
|
+
|
|
141
|
+
Use `gateCheck` from trusted server code when you need allow/deny or eligibility checks.
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
import { NeusClient } from '@neus/sdk';
|
|
145
|
+
|
|
146
|
+
const client = new NeusClient({
|
|
147
|
+
appId: 'your-app-id'
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const result = await client.gateCheck({
|
|
151
|
+
address: '0x...',
|
|
152
|
+
verifierIds: ['ownership-basic']
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (!result.data?.eligible) {
|
|
156
|
+
throw new Error('Access denied');
|
|
157
|
+
}
|
|
78
158
|
```
|
|
79
159
|
|
|
80
|
-
|
|
160
|
+
Never ship access keys in browser code.
|
|
161
|
+
|
|
162
|
+
## Core methods
|
|
163
|
+
|
|
164
|
+
| Method | Use it for |
|
|
165
|
+
| ------------------------------- | ------------------------------------------- |
|
|
166
|
+
| `getHostedCheckoutUrl()` | Send a user to Hosted Verify |
|
|
167
|
+
| `client.verify()` | Create a proof |
|
|
168
|
+
| `client.getProof()` | Fetch a proof by `qHash` |
|
|
169
|
+
| `client.pollProofStatus()` | Wait for async completion |
|
|
170
|
+
| `client.gateCheck()` | Server-side eligibility checks |
|
|
171
|
+
| `client.checkGate()` | Local preview against already-loaded proofs |
|
|
172
|
+
| `client.createWalletLinkData()` | Advanced wallet-link payloads |
|
|
81
173
|
|
|
82
|
-
##
|
|
174
|
+
## Configuration
|
|
83
175
|
|
|
84
|
-
```
|
|
176
|
+
```js
|
|
85
177
|
const client = new NeusClient({
|
|
86
178
|
apiUrl: 'https://api.neus.network',
|
|
87
|
-
appId: '
|
|
88
|
-
timeout: 30000
|
|
179
|
+
appId: 'your-app-id',
|
|
180
|
+
timeout: 30000
|
|
89
181
|
});
|
|
90
182
|
```
|
|
91
183
|
|
|
92
|
-
|
|
184
|
+
`appId` is public attribution for your app.
|
|
185
|
+
`apiKey` / `npk_*` is optional and server-side only.
|
|
186
|
+
|
|
187
|
+
## MCP: step-by-step (alternative to `setup`)
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npx -y -p @neus/sdk neus init
|
|
191
|
+
```
|
|
93
192
|
|
|
94
|
-
|
|
95
|
-
- [Examples](https://docs.neus.network/examples) — start with the [trust receipts showcase](https://github.com/neus/network/tree/main/examples/trust-receipts-showcase) locally; [live demo](https://neus.network/demo) on the product site
|
|
96
|
-
- [SDK](https://docs.neus.network/sdks/javascript)
|
|
97
|
-
- [MCP](https://docs.neus.network/mcp/overview) for IDEs and assistants
|
|
98
|
-
- [Widgets](https://docs.neus.network/widgets/overview)
|
|
99
|
-
- [API](https://docs.neus.network/api/overview)
|
|
100
|
-
- [Hosted Verify](https://docs.neus.network/cookbook/auth-hosted-verify)
|
|
193
|
+
Add or rotate a Profile access key on an existing install:
|
|
101
194
|
|
|
102
|
-
|
|
195
|
+
```bash
|
|
196
|
+
npx -y -p @neus/sdk neus auth --access-key <npk_...>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Claude Code (optional): add marketplace `https://github.com/neus/network`, install **`neus-mcp@neus`**, then run **`neus setup`** so your key matches every editor. See [NEUS for Claude Code](https://docs.neus.network/mcp/claude-code-marketplace).
|
|
200
|
+
|
|
201
|
+
## Docs
|
|
103
202
|
|
|
104
|
-
|
|
203
|
+
- Quickstart: https://docs.neus.network/quickstart
|
|
204
|
+
- JavaScript SDK: https://docs.neus.network/sdks/javascript
|
|
205
|
+
- Ownership Basic: https://docs.neus.network/verification/ownership-basic
|
|
206
|
+
- Widgets: https://docs.neus.network/widgets/overview
|
|
207
|
+
- MCP: https://docs.neus.network/mcp/overview
|
|
208
|
+
- API: https://docs.neus.network/api/overview
|
package/SECURITY.md
CHANGED
|
@@ -20,7 +20,7 @@ Treat **wallet signatures** and **API keys** as secrets. Do not log them, expose
|
|
|
20
20
|
|
|
21
21
|
**`VerifyGate`** create mode also defaults to **private**.
|
|
22
22
|
|
|
23
|
-
Use public visibility only when you
|
|
23
|
+
Use public visibility only when you need proof reuse without owner-authenticated access:
|
|
24
24
|
|
|
25
25
|
- unlisted public: `privacyLevel: 'public'`, `publicDisplay: false`
|
|
26
26
|
- listed public: `privacyLevel: 'public'`, `publicDisplay: true`
|
package/cjs/client.cjs
CHANGED
|
@@ -421,6 +421,11 @@ function normalizeBrowserSignerString(raw) {
|
|
|
421
421
|
}
|
|
422
422
|
return null;
|
|
423
423
|
}
|
|
424
|
+
function isPlaceholderNeusSignature(signature) {
|
|
425
|
+
const s = typeof signature === "string" ? signature.trim() : "";
|
|
426
|
+
if (!s) return true;
|
|
427
|
+
return /^0x0+$/i.test(s);
|
|
428
|
+
}
|
|
424
429
|
var validateVerifierData = (verifierId, data) => {
|
|
425
430
|
if (!data || typeof data !== "object") {
|
|
426
431
|
return { valid: false, error: "Data object is required" };
|
|
@@ -797,7 +802,7 @@ var NeusClient = class {
|
|
|
797
802
|
}
|
|
798
803
|
_getDefaultBrowserWallet() {
|
|
799
804
|
if (typeof window === "undefined") return null;
|
|
800
|
-
return window.ethereum ||
|
|
805
|
+
return window.ethereum || null;
|
|
801
806
|
}
|
|
802
807
|
async _buildPrivateGateAuth({ address, wallet, chain, signatureMethod } = {}) {
|
|
803
808
|
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
@@ -922,8 +927,57 @@ var NeusClient = class {
|
|
|
922
927
|
...label ? { label } : {}
|
|
923
928
|
};
|
|
924
929
|
}
|
|
930
|
+
async verifyFromApp(params) {
|
|
931
|
+
if (!params || typeof params !== "object") {
|
|
932
|
+
throw new ValidationError("verifyFromApp requires a params object");
|
|
933
|
+
}
|
|
934
|
+
const {
|
|
935
|
+
user,
|
|
936
|
+
verifier = "ownership-basic",
|
|
937
|
+
content,
|
|
938
|
+
data: explicitData = null,
|
|
939
|
+
options = {}
|
|
940
|
+
} = params;
|
|
941
|
+
if (!user || typeof user !== "object") {
|
|
942
|
+
throw new ValidationError("verifyFromApp requires user object");
|
|
943
|
+
}
|
|
944
|
+
const walletAddress = user.walletAddress || user.address || user.identity;
|
|
945
|
+
if (!walletAddress || typeof walletAddress !== "string") {
|
|
946
|
+
throw new ValidationError("verifyFromApp requires user.walletAddress");
|
|
947
|
+
}
|
|
948
|
+
const delegationQHash = this.config.appLinkQHash || typeof process !== "undefined" && process.env && process.env.NEUS_APP_LINK_QHASH || null;
|
|
949
|
+
let data;
|
|
950
|
+
if (explicitData && typeof explicitData === "object") {
|
|
951
|
+
data = { owner: walletAddress, ...explicitData };
|
|
952
|
+
} else if (content && typeof content === "object") {
|
|
953
|
+
data = {
|
|
954
|
+
owner: walletAddress,
|
|
955
|
+
content: JSON.stringify(content),
|
|
956
|
+
contentType: typeof content.contentType === "string" ? content.contentType : "application/json",
|
|
957
|
+
reference: content.reference || { type: "other" }
|
|
958
|
+
};
|
|
959
|
+
} else if (typeof content === "string") {
|
|
960
|
+
data = {
|
|
961
|
+
owner: walletAddress,
|
|
962
|
+
content,
|
|
963
|
+
reference: { type: "other" }
|
|
964
|
+
};
|
|
965
|
+
} else {
|
|
966
|
+
data = { owner: walletAddress, reference: { type: "other" } };
|
|
967
|
+
}
|
|
968
|
+
const signedTimestamp = Date.now();
|
|
969
|
+
const verifierIds = [verifier];
|
|
970
|
+
return this.verify({
|
|
971
|
+
verifierIds,
|
|
972
|
+
data,
|
|
973
|
+
walletAddress,
|
|
974
|
+
signedTimestamp,
|
|
975
|
+
...delegationQHash ? { delegationQHash } : {},
|
|
976
|
+
options
|
|
977
|
+
});
|
|
978
|
+
}
|
|
925
979
|
async verify(params) {
|
|
926
|
-
if ((!params?.signature || !params?.walletAddress) && (params?.verifier || params?.content || params?.data)) {
|
|
980
|
+
if ((isPlaceholderNeusSignature(params?.signature) || !params?.signature || !params?.walletAddress) && (params?.verifier || params?.content || params?.data)) {
|
|
927
981
|
const { content, verifier = "ownership-basic", data: data2 = null, wallet = null, options: options2 = {} } = params;
|
|
928
982
|
if (verifier === "ownership-basic" && !data2 && (!content || typeof content !== "string")) {
|
|
929
983
|
throw new ValidationError("content is required and must be a string (or use data param with owner + reference)");
|
|
@@ -976,7 +1030,7 @@ var NeusClient = class {
|
|
|
976
1030
|
}
|
|
977
1031
|
} else {
|
|
978
1032
|
if (typeof window === "undefined" || !window.ethereum) {
|
|
979
|
-
throw new ConfigurationError("No
|
|
1033
|
+
throw new ConfigurationError("No EVM browser wallet detected. Provide wallet explicitly for non-EVM flows and include chain as a CAIP-2 value.");
|
|
980
1034
|
}
|
|
981
1035
|
await window.ethereum.request({ method: "eth_requestAccounts" });
|
|
982
1036
|
provider = window.ethereum;
|
|
@@ -1264,13 +1318,15 @@ ${bytes.length}`;
|
|
|
1264
1318
|
verifierIds,
|
|
1265
1319
|
data,
|
|
1266
1320
|
walletAddress,
|
|
1267
|
-
signature,
|
|
1321
|
+
signature: rawSignature,
|
|
1268
1322
|
signedTimestamp,
|
|
1269
1323
|
chainId,
|
|
1270
1324
|
chain,
|
|
1271
1325
|
signatureMethod,
|
|
1326
|
+
delegationQHash,
|
|
1272
1327
|
options = {}
|
|
1273
1328
|
} = params;
|
|
1329
|
+
const signature = isPlaceholderNeusSignature(rawSignature) ? void 0 : rawSignature;
|
|
1274
1330
|
const resolvedChainId = chainId || (chain ? null : NEUS_CONSTANTS.HUB_CHAIN_ID);
|
|
1275
1331
|
const normalizeVerifierId = (id) => {
|
|
1276
1332
|
if (typeof id !== "string") return id;
|
|
@@ -1287,8 +1343,11 @@ ${bytes.length}`;
|
|
|
1287
1343
|
if (!walletAddress || typeof walletAddress !== "string") {
|
|
1288
1344
|
throw new ValidationError("walletAddress is required");
|
|
1289
1345
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1346
|
+
const hasAppAttribution = typeof this.config.appId === "string" && this.config.appId.trim().length > 0;
|
|
1347
|
+
if (!signature && !delegationQHash && !hasAppAttribution) {
|
|
1348
|
+
throw new ValidationError(
|
|
1349
|
+
"signature, delegationQHash, or NeusClient config appId (sent as X-Neus-App) is required"
|
|
1350
|
+
);
|
|
1292
1351
|
}
|
|
1293
1352
|
if (!signedTimestamp || typeof signedTimestamp !== "number") {
|
|
1294
1353
|
throw new ValidationError("signedTimestamp is required");
|
|
@@ -1314,11 +1373,12 @@ ${bytes.length}`;
|
|
|
1314
1373
|
verifierIds: normalizedVerifierIds,
|
|
1315
1374
|
data,
|
|
1316
1375
|
walletAddress,
|
|
1317
|
-
signature,
|
|
1376
|
+
...signature ? { signature } : {},
|
|
1318
1377
|
signedTimestamp,
|
|
1319
1378
|
...resolvedChainId !== null && { chainId: resolvedChainId },
|
|
1320
1379
|
...chain && { chain },
|
|
1321
1380
|
...signatureMethod && { signatureMethod },
|
|
1381
|
+
...delegationQHash && { delegationQHash },
|
|
1322
1382
|
options: optionsPayload
|
|
1323
1383
|
};
|
|
1324
1384
|
const response = await this._makeRequest("POST", "/api/v1/verification", requestData);
|
package/cjs/index.cjs
CHANGED
|
@@ -1081,6 +1081,11 @@ function normalizeBrowserSignerString(raw) {
|
|
|
1081
1081
|
}
|
|
1082
1082
|
return null;
|
|
1083
1083
|
}
|
|
1084
|
+
function isPlaceholderNeusSignature(signature) {
|
|
1085
|
+
const s = typeof signature === "string" ? signature.trim() : "";
|
|
1086
|
+
if (!s) return true;
|
|
1087
|
+
return /^0x0+$/i.test(s);
|
|
1088
|
+
}
|
|
1084
1089
|
var FALLBACK_PUBLIC_VERIFIER_CATALOG, EVM_ADDRESS_RE, WALLET_LINK_RELATIONSHIP_TYPES, validateVerifierData, NeusClient;
|
|
1085
1090
|
var init_client = __esm({
|
|
1086
1091
|
"client.js"() {
|
|
@@ -1481,7 +1486,7 @@ var init_client = __esm({
|
|
|
1481
1486
|
}
|
|
1482
1487
|
_getDefaultBrowserWallet() {
|
|
1483
1488
|
if (typeof window === "undefined") return null;
|
|
1484
|
-
return window.ethereum ||
|
|
1489
|
+
return window.ethereum || null;
|
|
1485
1490
|
}
|
|
1486
1491
|
async _buildPrivateGateAuth({ address, wallet, chain, signatureMethod } = {}) {
|
|
1487
1492
|
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
@@ -1606,8 +1611,57 @@ var init_client = __esm({
|
|
|
1606
1611
|
...label ? { label } : {}
|
|
1607
1612
|
};
|
|
1608
1613
|
}
|
|
1614
|
+
async verifyFromApp(params) {
|
|
1615
|
+
if (!params || typeof params !== "object") {
|
|
1616
|
+
throw new ValidationError("verifyFromApp requires a params object");
|
|
1617
|
+
}
|
|
1618
|
+
const {
|
|
1619
|
+
user,
|
|
1620
|
+
verifier = "ownership-basic",
|
|
1621
|
+
content,
|
|
1622
|
+
data: explicitData = null,
|
|
1623
|
+
options = {}
|
|
1624
|
+
} = params;
|
|
1625
|
+
if (!user || typeof user !== "object") {
|
|
1626
|
+
throw new ValidationError("verifyFromApp requires user object");
|
|
1627
|
+
}
|
|
1628
|
+
const walletAddress = user.walletAddress || user.address || user.identity;
|
|
1629
|
+
if (!walletAddress || typeof walletAddress !== "string") {
|
|
1630
|
+
throw new ValidationError("verifyFromApp requires user.walletAddress");
|
|
1631
|
+
}
|
|
1632
|
+
const delegationQHash = this.config.appLinkQHash || typeof process !== "undefined" && process.env && process.env.NEUS_APP_LINK_QHASH || null;
|
|
1633
|
+
let data;
|
|
1634
|
+
if (explicitData && typeof explicitData === "object") {
|
|
1635
|
+
data = { owner: walletAddress, ...explicitData };
|
|
1636
|
+
} else if (content && typeof content === "object") {
|
|
1637
|
+
data = {
|
|
1638
|
+
owner: walletAddress,
|
|
1639
|
+
content: JSON.stringify(content),
|
|
1640
|
+
contentType: typeof content.contentType === "string" ? content.contentType : "application/json",
|
|
1641
|
+
reference: content.reference || { type: "other" }
|
|
1642
|
+
};
|
|
1643
|
+
} else if (typeof content === "string") {
|
|
1644
|
+
data = {
|
|
1645
|
+
owner: walletAddress,
|
|
1646
|
+
content,
|
|
1647
|
+
reference: { type: "other" }
|
|
1648
|
+
};
|
|
1649
|
+
} else {
|
|
1650
|
+
data = { owner: walletAddress, reference: { type: "other" } };
|
|
1651
|
+
}
|
|
1652
|
+
const signedTimestamp = Date.now();
|
|
1653
|
+
const verifierIds = [verifier];
|
|
1654
|
+
return this.verify({
|
|
1655
|
+
verifierIds,
|
|
1656
|
+
data,
|
|
1657
|
+
walletAddress,
|
|
1658
|
+
signedTimestamp,
|
|
1659
|
+
...delegationQHash ? { delegationQHash } : {},
|
|
1660
|
+
options
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1609
1663
|
async verify(params) {
|
|
1610
|
-
if ((!params?.signature || !params?.walletAddress) && (params?.verifier || params?.content || params?.data)) {
|
|
1664
|
+
if ((isPlaceholderNeusSignature(params?.signature) || !params?.signature || !params?.walletAddress) && (params?.verifier || params?.content || params?.data)) {
|
|
1611
1665
|
const { content, verifier = "ownership-basic", data: data2 = null, wallet = null, options: options2 = {} } = params;
|
|
1612
1666
|
if (verifier === "ownership-basic" && !data2 && (!content || typeof content !== "string")) {
|
|
1613
1667
|
throw new ValidationError("content is required and must be a string (or use data param with owner + reference)");
|
|
@@ -1660,7 +1714,7 @@ var init_client = __esm({
|
|
|
1660
1714
|
}
|
|
1661
1715
|
} else {
|
|
1662
1716
|
if (typeof window === "undefined" || !window.ethereum) {
|
|
1663
|
-
throw new ConfigurationError("No
|
|
1717
|
+
throw new ConfigurationError("No EVM browser wallet detected. Provide wallet explicitly for non-EVM flows and include chain as a CAIP-2 value.");
|
|
1664
1718
|
}
|
|
1665
1719
|
await window.ethereum.request({ method: "eth_requestAccounts" });
|
|
1666
1720
|
provider = window.ethereum;
|
|
@@ -1948,13 +2002,15 @@ ${bytes.length}`;
|
|
|
1948
2002
|
verifierIds,
|
|
1949
2003
|
data,
|
|
1950
2004
|
walletAddress,
|
|
1951
|
-
signature,
|
|
2005
|
+
signature: rawSignature,
|
|
1952
2006
|
signedTimestamp,
|
|
1953
2007
|
chainId,
|
|
1954
2008
|
chain,
|
|
1955
2009
|
signatureMethod,
|
|
2010
|
+
delegationQHash,
|
|
1956
2011
|
options = {}
|
|
1957
2012
|
} = params;
|
|
2013
|
+
const signature = isPlaceholderNeusSignature(rawSignature) ? void 0 : rawSignature;
|
|
1958
2014
|
const resolvedChainId = chainId || (chain ? null : NEUS_CONSTANTS.HUB_CHAIN_ID);
|
|
1959
2015
|
const normalizeVerifierId = (id) => {
|
|
1960
2016
|
if (typeof id !== "string") return id;
|
|
@@ -1971,8 +2027,11 @@ ${bytes.length}`;
|
|
|
1971
2027
|
if (!walletAddress || typeof walletAddress !== "string") {
|
|
1972
2028
|
throw new ValidationError("walletAddress is required");
|
|
1973
2029
|
}
|
|
1974
|
-
|
|
1975
|
-
|
|
2030
|
+
const hasAppAttribution = typeof this.config.appId === "string" && this.config.appId.trim().length > 0;
|
|
2031
|
+
if (!signature && !delegationQHash && !hasAppAttribution) {
|
|
2032
|
+
throw new ValidationError(
|
|
2033
|
+
"signature, delegationQHash, or NeusClient config appId (sent as X-Neus-App) is required"
|
|
2034
|
+
);
|
|
1976
2035
|
}
|
|
1977
2036
|
if (!signedTimestamp || typeof signedTimestamp !== "number") {
|
|
1978
2037
|
throw new ValidationError("signedTimestamp is required");
|
|
@@ -1998,11 +2057,12 @@ ${bytes.length}`;
|
|
|
1998
2057
|
verifierIds: normalizedVerifierIds,
|
|
1999
2058
|
data,
|
|
2000
2059
|
walletAddress,
|
|
2001
|
-
signature,
|
|
2060
|
+
...signature ? { signature } : {},
|
|
2002
2061
|
signedTimestamp,
|
|
2003
2062
|
...resolvedChainId !== null && { chainId: resolvedChainId },
|
|
2004
2063
|
...chain && { chain },
|
|
2005
2064
|
...signatureMethod && { signatureMethod },
|
|
2065
|
+
...delegationQHash && { delegationQHash },
|
|
2006
2066
|
options: optionsPayload
|
|
2007
2067
|
};
|
|
2008
2068
|
const response = await this._makeRequest("POST", "/api/v1/verification", requestData);
|
package/cli/neus.mjs
CHANGED
|
@@ -203,16 +203,18 @@ function printUsage(exitCode = 0) {
|
|
|
203
203
|
'Usage: neus <command> [options]',
|
|
204
204
|
'',
|
|
205
205
|
'Commands:',
|
|
206
|
+
' setup One-command: run init, then auth if --access-key is provided',
|
|
206
207
|
' init Configure supported MCP clients automatically',
|
|
207
208
|
' auth Add or update a personal access key for NEUS MCP',
|
|
208
209
|
' status Show current NEUS MCP setup',
|
|
210
|
+
' doctor Deep check: config status, profile connection, agent verification',
|
|
209
211
|
' help Show this message',
|
|
210
212
|
'',
|
|
211
213
|
'Options:',
|
|
212
214
|
' --client <name[,name]> Limit setup to claude, cursor, or vscode',
|
|
213
215
|
' --project Write shared project config instead of user config',
|
|
214
216
|
' --access-key <npk_...> Configure Bearer auth for personal account tools',
|
|
215
|
-
' --json
|
|
217
|
+
' --json Print JSON output',
|
|
216
218
|
' --dry-run Preview changes without writing files',
|
|
217
219
|
];
|
|
218
220
|
const stream = exitCode === 0 ? process.stdout : process.stderr;
|
|
@@ -246,8 +248,8 @@ function ensureClientSelection(scope, clients) {
|
|
|
246
248
|
}
|
|
247
249
|
|
|
248
250
|
function ensureSafeAuth(command, scope, accessKey) {
|
|
249
|
-
if (command === 'auth' && scope !== 'user') {
|
|
250
|
-
throw new Error('`neus
|
|
251
|
+
if ((command === 'auth' || command === 'setup') && scope !== 'user') {
|
|
252
|
+
throw new Error('`neus ${command}` only supports user scope so access keys never land in shared project config.');
|
|
251
253
|
}
|
|
252
254
|
if (scope === 'project' && accessKey) {
|
|
253
255
|
throw new Error('Access keys are only supported in user scope. Remove --project or omit --access-key.');
|
|
@@ -256,7 +258,7 @@ function ensureSafeAuth(command, scope, accessKey) {
|
|
|
256
258
|
|
|
257
259
|
function buildCursorServer(accessKey) {
|
|
258
260
|
return {
|
|
259
|
-
type: '
|
|
261
|
+
type: 'http',
|
|
260
262
|
url: NEUS_MCP_URL,
|
|
261
263
|
...(accessKey ? { headers: { Authorization: `Bearer ${accessKey}` } } : {}),
|
|
262
264
|
};
|
|
@@ -548,6 +550,14 @@ function printResultSummary(command, scope, results, accessKey) {
|
|
|
548
550
|
if (command === 'init' && !accessKey) {
|
|
549
551
|
lines.push(`Account tools stay optional. Add personal auth later with: neus auth --access-key <npk_...>`);
|
|
550
552
|
}
|
|
553
|
+
if (command === 'init' || command === 'setup') {
|
|
554
|
+
lines.push(
|
|
555
|
+
'Claude Code (optional): plugin neus-mcp@neus + docs — https://docs.neus.network/mcp/claude-code-marketplace',
|
|
556
|
+
);
|
|
557
|
+
lines.push(
|
|
558
|
+
'Cursor / VS Code: same command when those apps are detected (local MCP config) — https://docs.neus.network/mcp/setup',
|
|
559
|
+
);
|
|
560
|
+
}
|
|
551
561
|
if ((command === 'init' || command === 'auth') && accessKey) {
|
|
552
562
|
lines.push('Personal account tools are enabled where the client supports user-scope auth setup.');
|
|
553
563
|
}
|
|
@@ -659,6 +669,97 @@ function runStatus(options) {
|
|
|
659
669
|
printResultSummary('status', scope, inspected, '');
|
|
660
670
|
}
|
|
661
671
|
|
|
672
|
+
function runSetup(options) {
|
|
673
|
+
const scope = resolveScope(options);
|
|
674
|
+
ensureSafeAuth('setup', scope, options.accessKey);
|
|
675
|
+
const cwd = process.cwd();
|
|
676
|
+
if (options.project && options.accessKey) {
|
|
677
|
+
throw new Error('Access keys are only supported in user scope. Remove --project or omit --access-key.');
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const clients = resolveClients(scope, options.clients);
|
|
681
|
+
ensureClientSelection(scope, clients);
|
|
682
|
+
|
|
683
|
+
const initResults = runClientOperations(
|
|
684
|
+
clients,
|
|
685
|
+
scope,
|
|
686
|
+
cwd,
|
|
687
|
+
options.dryRun,
|
|
688
|
+
(client) => installClient(client, scope, options.accessKey, options.dryRun, cwd),
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
const payload = {
|
|
692
|
+
command: 'setup',
|
|
693
|
+
scope,
|
|
694
|
+
detectedClients: defaultUserClients(),
|
|
695
|
+
clients,
|
|
696
|
+
accessKeyConfigured: Boolean(options.accessKey),
|
|
697
|
+
results: initResults,
|
|
698
|
+
hasErrors: initResults.some((result) => result.error),
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
if (options.json) {
|
|
702
|
+
printJson(payload);
|
|
703
|
+
} else {
|
|
704
|
+
printResultSummary('setup', scope, initResults, options.accessKey);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (payload.hasErrors) {
|
|
708
|
+
process.exitCode = 1;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
function runDoctor(options) {
|
|
713
|
+
const scope = resolveScope(options);
|
|
714
|
+
const cwd = process.cwd();
|
|
715
|
+
const clients = resolveClients(scope, options.clients);
|
|
716
|
+
ensureClientSelection(scope, clients);
|
|
717
|
+
|
|
718
|
+
const inspected = runClientOperations(clients, scope, cwd, options.dryRun, (client) =>
|
|
719
|
+
inspectClient(client, scope, cwd),
|
|
720
|
+
);
|
|
721
|
+
const configuredClients = inspected.filter((r) => r.configured);
|
|
722
|
+
const payload = {
|
|
723
|
+
command: 'doctor',
|
|
724
|
+
scope,
|
|
725
|
+
clients: inspected,
|
|
726
|
+
configuredCount: configuredClients.length,
|
|
727
|
+
accessKeyPresent: Boolean(options.accessKey),
|
|
728
|
+
profileConnectable: false,
|
|
729
|
+
agentVerified: false,
|
|
730
|
+
summary: '',
|
|
731
|
+
hasErrors: inspected.some((result) => result.error),
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
if (options.json) {
|
|
735
|
+
printJson(payload);
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
printResultSummary('doctor', scope, inspected, '');
|
|
740
|
+
|
|
741
|
+
const lines = [];
|
|
742
|
+
if (configuredClients.length > 0) {
|
|
743
|
+
lines.push(`MCP reachable: ${configuredClients.map((r) => r.client).join(', ')} ready at ${NEUS_MCP_URL}.`);
|
|
744
|
+
} else {
|
|
745
|
+
lines.push('MCP reachable: No clients configured. Run `neus setup` or `neus init` first.');
|
|
746
|
+
process.stdout.write(`\n${lines.join('\n')}\n`);
|
|
747
|
+
process.exit(1);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (options.accessKey) {
|
|
751
|
+
lines.push('Profile connection: auth header present. Connect to the MCP endpoint and run `neus_me` to confirm.');
|
|
752
|
+
} else {
|
|
753
|
+
lines.push(`Profile connection: No access key found. Run \`neus auth --access-key <npk_...>\` (create one at ${NEUS_ACCESS_KEYS_URL}) and reconnect.`);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
lines.push('Agent verification: Run `neus_agent_link` and `neus_proofs_check` inside the MCP-connected client to verify agent identity and delegation proofs.');
|
|
757
|
+
lines.push('');
|
|
758
|
+
lines.push('Next: Open your editor/IDE, connect to the NEUS MCP endpoint, and run `neus_context`.');
|
|
759
|
+
|
|
760
|
+
process.stdout.write(`\n${lines.join('\n')}\n`);
|
|
761
|
+
}
|
|
762
|
+
|
|
662
763
|
function main() {
|
|
663
764
|
try {
|
|
664
765
|
const { command, options } = parseArgs(process.argv.slice(2));
|
|
@@ -679,6 +780,14 @@ function main() {
|
|
|
679
780
|
runStatus(options);
|
|
680
781
|
return;
|
|
681
782
|
}
|
|
783
|
+
if (command === 'setup') {
|
|
784
|
+
runSetup(options);
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
if (command === 'doctor') {
|
|
788
|
+
runDoctor(options);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
682
791
|
|
|
683
792
|
process.stderr.write(`Unknown subcommand: ${command}\n`);
|
|
684
793
|
printUsage(1);
|
package/client.js
CHANGED
|
@@ -48,6 +48,13 @@ function normalizeBrowserSignerString(raw) {
|
|
|
48
48
|
return null;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/** Treats SDK placeholder signatures as absent so the protocol can use session or app-link delegation. */
|
|
52
|
+
function isPlaceholderNeusSignature(signature) {
|
|
53
|
+
const s = typeof signature === 'string' ? signature.trim() : '';
|
|
54
|
+
if (!s) return true;
|
|
55
|
+
return /^0x0+$/i.test(s);
|
|
56
|
+
}
|
|
57
|
+
|
|
51
58
|
const validateVerifierData = (verifierId, data) => {
|
|
52
59
|
if (!data || typeof data !== 'object') {
|
|
53
60
|
return { valid: false, error: 'Data object is required' };
|
|
@@ -450,10 +457,12 @@ export class NeusClient {
|
|
|
450
457
|
throw new ConfigurationError('Invalid wallet provider');
|
|
451
458
|
}
|
|
452
459
|
|
|
453
|
-
_getDefaultBrowserWallet() {
|
|
454
|
-
if (typeof window === 'undefined') return null;
|
|
455
|
-
|
|
456
|
-
|
|
460
|
+
_getDefaultBrowserWallet() {
|
|
461
|
+
if (typeof window === 'undefined') return null;
|
|
462
|
+
// Legacy convenience fallback only. Non-EVM wallets must be passed explicitly
|
|
463
|
+
// with CAIP-2 chain context so the SDK does not route them through EVM RPC.
|
|
464
|
+
return window.ethereum || null;
|
|
465
|
+
}
|
|
457
466
|
|
|
458
467
|
async _buildPrivateGateAuth({ address, wallet, chain, signatureMethod } = {}) {
|
|
459
468
|
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
@@ -595,8 +604,74 @@ export class NeusClient {
|
|
|
595
604
|
};
|
|
596
605
|
}
|
|
597
606
|
|
|
607
|
+
async verifyFromApp(params) {
|
|
608
|
+
if (!params || typeof params !== 'object') {
|
|
609
|
+
throw new ValidationError('verifyFromApp requires a params object');
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
const {
|
|
613
|
+
user,
|
|
614
|
+
verifier = 'ownership-basic',
|
|
615
|
+
content,
|
|
616
|
+
data: explicitData = null,
|
|
617
|
+
options = {}
|
|
618
|
+
} = params;
|
|
619
|
+
|
|
620
|
+
if (!user || typeof user !== 'object') {
|
|
621
|
+
throw new ValidationError('verifyFromApp requires user object');
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const walletAddress =
|
|
625
|
+
user.walletAddress ||
|
|
626
|
+
user.address ||
|
|
627
|
+
user.identity;
|
|
628
|
+
if (!walletAddress || typeof walletAddress !== 'string') {
|
|
629
|
+
throw new ValidationError('verifyFromApp requires user.walletAddress');
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const delegationQHash =
|
|
633
|
+
this.config.appLinkQHash ||
|
|
634
|
+
(typeof process !== 'undefined' && process.env && process.env.NEUS_APP_LINK_QHASH) ||
|
|
635
|
+
null;
|
|
636
|
+
|
|
637
|
+
let data;
|
|
638
|
+
if (explicitData && typeof explicitData === 'object') {
|
|
639
|
+
data = { owner: walletAddress, ...explicitData };
|
|
640
|
+
} else if (content && typeof content === 'object') {
|
|
641
|
+
data = {
|
|
642
|
+
owner: walletAddress,
|
|
643
|
+
content: JSON.stringify(content),
|
|
644
|
+
contentType: typeof content.contentType === 'string' ? content.contentType : 'application/json',
|
|
645
|
+
reference: content.reference || { type: 'other' }
|
|
646
|
+
};
|
|
647
|
+
} else if (typeof content === 'string') {
|
|
648
|
+
data = {
|
|
649
|
+
owner: walletAddress,
|
|
650
|
+
content,
|
|
651
|
+
reference: { type: 'other' }
|
|
652
|
+
};
|
|
653
|
+
} else {
|
|
654
|
+
data = { owner: walletAddress, reference: { type: 'other' } };
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const signedTimestamp = Date.now();
|
|
658
|
+
const verifierIds = [verifier];
|
|
659
|
+
|
|
660
|
+
return this.verify({
|
|
661
|
+
verifierIds,
|
|
662
|
+
data,
|
|
663
|
+
walletAddress,
|
|
664
|
+
signedTimestamp,
|
|
665
|
+
...(delegationQHash ? { delegationQHash } : {}),
|
|
666
|
+
options
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
|
|
598
670
|
async verify(params) {
|
|
599
|
-
if (
|
|
671
|
+
if (
|
|
672
|
+
(isPlaceholderNeusSignature(params?.signature) || !params?.signature || !params?.walletAddress) &&
|
|
673
|
+
(params?.verifier || params?.content || params?.data)
|
|
674
|
+
) {
|
|
600
675
|
const { content, verifier = 'ownership-basic', data = null, wallet = null, options = {} } = params;
|
|
601
676
|
|
|
602
677
|
if (verifier === 'ownership-basic' && !data && (!content || typeof content !== 'string')) {
|
|
@@ -657,10 +732,10 @@ export class NeusClient {
|
|
|
657
732
|
walletAddress = Array.isArray(accounts) && accounts.length > 0 ? accounts[0] : null;
|
|
658
733
|
}
|
|
659
734
|
}
|
|
660
|
-
} else {
|
|
661
|
-
if (typeof window === 'undefined' || !window.ethereum) {
|
|
662
|
-
throw new ConfigurationError('No
|
|
663
|
-
}
|
|
735
|
+
} else {
|
|
736
|
+
if (typeof window === 'undefined' || !window.ethereum) {
|
|
737
|
+
throw new ConfigurationError('No EVM browser wallet detected. Provide wallet explicitly for non-EVM flows and include chain as a CAIP-2 value.');
|
|
738
|
+
}
|
|
664
739
|
await window.ethereum.request({ method: 'eth_requestAccounts' });
|
|
665
740
|
provider = window.ethereum;
|
|
666
741
|
const accounts = await provider.request({ method: 'eth_accounts' });
|
|
@@ -962,14 +1037,17 @@ export class NeusClient {
|
|
|
962
1037
|
verifierIds,
|
|
963
1038
|
data,
|
|
964
1039
|
walletAddress,
|
|
965
|
-
signature,
|
|
1040
|
+
signature: rawSignature,
|
|
966
1041
|
signedTimestamp,
|
|
967
1042
|
chainId,
|
|
968
1043
|
chain,
|
|
969
1044
|
signatureMethod,
|
|
1045
|
+
delegationQHash,
|
|
970
1046
|
options = {}
|
|
971
1047
|
} = params;
|
|
972
1048
|
|
|
1049
|
+
const signature = isPlaceholderNeusSignature(rawSignature) ? undefined : rawSignature;
|
|
1050
|
+
|
|
973
1051
|
const resolvedChainId = chainId || (chain ? null : NEUS_CONSTANTS.HUB_CHAIN_ID);
|
|
974
1052
|
|
|
975
1053
|
const normalizeVerifierId = (id) => {
|
|
@@ -988,8 +1066,12 @@ export class NeusClient {
|
|
|
988
1066
|
if (!walletAddress || typeof walletAddress !== 'string') {
|
|
989
1067
|
throw new ValidationError('walletAddress is required');
|
|
990
1068
|
}
|
|
991
|
-
|
|
992
|
-
|
|
1069
|
+
const hasAppAttribution =
|
|
1070
|
+
typeof this.config.appId === 'string' && this.config.appId.trim().length > 0;
|
|
1071
|
+
if (!signature && !delegationQHash && !hasAppAttribution) {
|
|
1072
|
+
throw new ValidationError(
|
|
1073
|
+
'signature, delegationQHash, or NeusClient config appId (sent as X-Neus-App) is required'
|
|
1074
|
+
);
|
|
993
1075
|
}
|
|
994
1076
|
if (!signedTimestamp || typeof signedTimestamp !== 'number') {
|
|
995
1077
|
throw new ValidationError('signedTimestamp is required');
|
|
@@ -1019,11 +1101,12 @@ export class NeusClient {
|
|
|
1019
1101
|
verifierIds: normalizedVerifierIds,
|
|
1020
1102
|
data,
|
|
1021
1103
|
walletAddress,
|
|
1022
|
-
signature,
|
|
1104
|
+
...(signature ? { signature } : {}),
|
|
1023
1105
|
signedTimestamp,
|
|
1024
1106
|
...(resolvedChainId !== null && { chainId: resolvedChainId }),
|
|
1025
1107
|
...(chain && { chain }),
|
|
1026
1108
|
...(signatureMethod && { signatureMethod }),
|
|
1109
|
+
...(delegationQHash && { delegationQHash }),
|
|
1027
1110
|
options: optionsPayload
|
|
1028
1111
|
};
|
|
1029
1112
|
|
package/errors.js
CHANGED
|
@@ -79,7 +79,7 @@ export class NetworkError extends SDKError {
|
|
|
79
79
|
super(message, code);
|
|
80
80
|
this.name = 'NetworkError';
|
|
81
81
|
this.originalError = originalError;
|
|
82
|
-
this.isRetryable = true; // Network errors are
|
|
82
|
+
this.isRetryable = true; // Network errors are retryable
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
static isNetworkError(error) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neus/sdk",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.12",
|
|
4
|
+
"description": "NEUS makes trust portable across the internet — so people, apps, and AI agents can prove what is real before access, payout, or execution.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"neus": "cli/neus.mjs"
|
|
7
7
|
},
|
package/types.d.ts
CHANGED
|
@@ -7,7 +7,9 @@ declare module '@neus/sdk' {
|
|
|
7
7
|
|
|
8
8
|
export class NeusClient {
|
|
9
9
|
constructor(config?: NeusClientConfig);
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
verifyFromApp(params: VerifyFromAppParams): Promise<VerificationResult>;
|
|
12
|
+
|
|
11
13
|
verify(params: VerifyParams): Promise<VerificationResult>;
|
|
12
14
|
|
|
13
15
|
getProof(qHash: string): Promise<StatusResult>;
|
|
@@ -57,6 +59,8 @@ declare module '@neus/sdk' {
|
|
|
57
59
|
apiUrl?: string;
|
|
58
60
|
apiKey?: string;
|
|
59
61
|
appId?: string;
|
|
62
|
+
/** Optional: only when using legacy `delegationQHash` on verify requests. App-linked servers rely on `appId` + Origin + stored delegation. */
|
|
63
|
+
appLinkQHash?: string;
|
|
60
64
|
paymentSignature?: string;
|
|
61
65
|
extraHeaders?: Record<string, string>;
|
|
62
66
|
timeout?: number;
|
|
@@ -92,6 +96,18 @@ declare module '@neus/sdk' {
|
|
|
92
96
|
meta?: Record<string, any>;
|
|
93
97
|
}
|
|
94
98
|
|
|
99
|
+
export interface VerifyFromAppParams {
|
|
100
|
+
user: {
|
|
101
|
+
walletAddress?: string;
|
|
102
|
+
address?: string;
|
|
103
|
+
identity?: string;
|
|
104
|
+
};
|
|
105
|
+
verifier?: VerifierId;
|
|
106
|
+
content?: string | Record<string, any>;
|
|
107
|
+
data?: VerificationData;
|
|
108
|
+
options?: VerifyOptions;
|
|
109
|
+
}
|
|
110
|
+
|
|
95
111
|
export interface VerifyParams {
|
|
96
112
|
verifier?: VerifierId;
|
|
97
113
|
content?: string;
|
|
@@ -105,6 +121,7 @@ declare module '@neus/sdk' {
|
|
|
105
121
|
chainId?: number;
|
|
106
122
|
chain?: string;
|
|
107
123
|
signatureMethod?: string;
|
|
124
|
+
delegationQHash?: string;
|
|
108
125
|
wallet?: WalletLike;
|
|
109
126
|
}
|
|
110
127
|
|
package/widgets/README.md
CHANGED
|
@@ -10,7 +10,7 @@ npm install @neus/sdk react react-dom
|
|
|
10
10
|
|
|
11
11
|
## VerifyGate
|
|
12
12
|
|
|
13
|
-
Create mode defaults to **private**. Override `proofOptions` only when you
|
|
13
|
+
Create mode defaults to **private**. Override `proofOptions` only when you need public visibility for link-based or public checks.
|
|
14
14
|
|
|
15
15
|
```jsx
|
|
16
16
|
import { VerifyGate } from '@neus/sdk/widgets';
|
|
@@ -307,7 +307,7 @@ function VerifyGate({
|
|
|
307
307
|
return provider.address;
|
|
308
308
|
}
|
|
309
309
|
if (typeof provider.request !== "function") {
|
|
310
|
-
throw new Error("
|
|
310
|
+
throw new Error("Connect a wallet and try again.");
|
|
311
311
|
}
|
|
312
312
|
let accounts = await provider.request({ method: "eth_accounts" });
|
|
313
313
|
if (!accounts || accounts.length === 0) {
|
|
@@ -315,7 +315,7 @@ function VerifyGate({
|
|
|
315
315
|
accounts = await provider.request({ method: "eth_accounts" });
|
|
316
316
|
}
|
|
317
317
|
if (!accounts || accounts.length === 0) {
|
|
318
|
-
throw new Error("
|
|
318
|
+
throw new Error("Connect a wallet and try again.");
|
|
319
319
|
}
|
|
320
320
|
return accounts[0];
|
|
321
321
|
}, [wallet]);
|
|
@@ -388,7 +388,7 @@ function VerifyGate({
|
|
|
388
388
|
}, [client, buildGateRequirements, wallet, inferChainFromAddress, signatureMethod]);
|
|
389
389
|
const launchHostedCheckout = useCallback(async () => {
|
|
390
390
|
if (typeof window === "undefined") {
|
|
391
|
-
throw new Error("
|
|
391
|
+
throw new Error("Open this in a browser to verify.");
|
|
392
392
|
}
|
|
393
393
|
const origin = window.location.origin;
|
|
394
394
|
const returnUrl = window.location.href;
|
|
@@ -446,7 +446,7 @@ function VerifyGate({
|
|
|
446
446
|
completed = true;
|
|
447
447
|
cleanup();
|
|
448
448
|
if (payload?.eligible === false) {
|
|
449
|
-
reject(new Error("
|
|
449
|
+
reject(new Error("Verification could not be completed."));
|
|
450
450
|
return;
|
|
451
451
|
}
|
|
452
452
|
resolve(payload);
|
|
@@ -573,7 +573,7 @@ function VerifyGate({
|
|
|
573
573
|
const buildDataForVerifier = (verifierId) => {
|
|
574
574
|
if (!CREATABLE_VERIFIERS.has(verifierId)) {
|
|
575
575
|
throw new Error(
|
|
576
|
-
|
|
576
|
+
"This check requires the hosted verifier."
|
|
577
577
|
);
|
|
578
578
|
}
|
|
579
579
|
const explicit = verifierData && verifierData[verifierId];
|
|
@@ -587,12 +587,12 @@ function VerifyGate({
|
|
|
587
587
|
if (verifierId === "wallet-link") {
|
|
588
588
|
if (!explicit?.secondaryWalletAddress || !explicit?.signature || !explicit?.chain || !explicit?.signatureMethod) {
|
|
589
589
|
throw new Error(
|
|
590
|
-
"
|
|
590
|
+
"Missing required wallet details."
|
|
591
591
|
);
|
|
592
592
|
}
|
|
593
593
|
return explicit;
|
|
594
594
|
}
|
|
595
|
-
throw new Error(
|
|
595
|
+
throw new Error("Missing required verification details.");
|
|
596
596
|
};
|
|
597
597
|
const verifyOne = async (verifierId) => {
|
|
598
598
|
const dataForVerifier = buildDataForVerifier(verifierId);
|
|
@@ -616,7 +616,7 @@ function VerifyGate({
|
|
|
616
616
|
const verifiedVerifiers = final?.data?.verifiedVerifiers || [];
|
|
617
617
|
const verifierResult = verifiedVerifiers.find((v) => v.verifierId === verifierId);
|
|
618
618
|
if (!verifierResult || verifierResult.verified !== true) {
|
|
619
|
-
throw new Error(
|
|
619
|
+
throw new Error("Verification could not be completed.");
|
|
620
620
|
}
|
|
621
621
|
const hubTx = final?.data?.hubTransaction || {};
|
|
622
622
|
const crosschain = final?.data?.crosschain || {};
|
|
@@ -849,7 +849,7 @@ function VerifyGate({
|
|
|
849
849
|
textUnderlineOffset: "2px",
|
|
850
850
|
opacity: disabled || isProcessing ? 0.6 : 0.9
|
|
851
851
|
},
|
|
852
|
-
children: "Already verified?
|
|
852
|
+
children: "Already verified? Reuse your proof."
|
|
853
853
|
}
|
|
854
854
|
),
|
|
855
855
|
error && /* @__PURE__ */ jsx("div", { style: {
|