@neus/sdk 1.1.0 → 1.1.2

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/mcp-hosts.js ADDED
@@ -0,0 +1,121 @@
1
+ /**
2
+ * MCP host install constants shared by the `neus` CLI and product UI.
3
+ * Browser-safe: no Node-only APIs except the Buffer fallback for non-browser tests.
4
+ */
5
+
6
+ export const NEUS_MCP_SERVER_NAME = 'neus';
7
+ export const NEUS_MCP_URL = 'https://mcp.neus.network/mcp';
8
+ export const NEUS_SETUP_CLI = 'npx -y -p @neus/sdk neus setup';
9
+ export const NEUS_AUTH_CLI = 'npx -y -p @neus/sdk neus auth';
10
+ export const NEUS_MCP_SETUP_DOCS_URL = 'https://docs.neus.network/mcp/ide-plugin';
11
+
12
+ /** CLI `neus setup --client` values. */
13
+ export const MCP_INSTALL_CLIENTS = ['claude', 'codex', 'cursor', 'vscode'];
14
+
15
+ /** Product Profile "Open in" hosts. */
16
+ export const MCP_INSTALL_HOSTS = ['cursor', 'claude', 'codex'];
17
+
18
+ export const IDE_HOST_LABELS = {
19
+ cursor: 'Cursor',
20
+ claude: 'Claude Code',
21
+ codex: 'Codex'
22
+ };
23
+
24
+ export const IDE_HOST_BRAND_LOGOS = {
25
+ cursor: '/images/brandLogos/cursor.svg',
26
+ claude: '/images/brandLogos/anthropic.svg',
27
+ codex: '/images/brandLogos/openai.svg'
28
+ };
29
+
30
+ /**
31
+ * @param {string | null | undefined} accessKey
32
+ * @returns {{ type: 'http'; url: string; headers?: { Authorization: string } }}
33
+ */
34
+ export function buildNeusMcpHttpConfig(accessKey) {
35
+ const key = String(accessKey || '').trim();
36
+ return {
37
+ type: 'http',
38
+ url: NEUS_MCP_URL,
39
+ ...(key ? { headers: { Authorization: `Bearer ${key}` } } : {})
40
+ };
41
+ }
42
+
43
+ /**
44
+ * @param {unknown} value
45
+ * @returns {string}
46
+ */
47
+ function encodeBase64Json(value) {
48
+ const json = JSON.stringify(value);
49
+ if (typeof globalThis.btoa === 'function') {
50
+ return globalThis.btoa(json);
51
+ }
52
+ return Buffer.from(json, 'utf8').toString('base64');
53
+ }
54
+
55
+ /**
56
+ * @param {string | null | undefined} accessKey
57
+ * @returns {string}
58
+ */
59
+ export function buildCursorMcpInstallUrl(accessKey) {
60
+ const config = buildNeusMcpHttpConfig(accessKey);
61
+ const encoded = encodeBase64Json(config);
62
+ return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(NEUS_MCP_SERVER_NAME)}&config=${encodeURIComponent(encoded)}`;
63
+ }
64
+
65
+ /**
66
+ * @param {string | null | undefined} accessKey
67
+ * @returns {string}
68
+ */
69
+ export function buildVsCodeMcpInstallUrl(accessKey) {
70
+ const payload = {
71
+ name: NEUS_MCP_SERVER_NAME,
72
+ ...buildNeusMcpHttpConfig(accessKey)
73
+ };
74
+ return `vscode:mcp/install?${encodeURIComponent(JSON.stringify(payload))}`;
75
+ }
76
+
77
+ /**
78
+ * @param {'claude' | 'codex' | 'cursor' | 'vscode'} client
79
+ * @returns {string}
80
+ */
81
+ export function buildAuthCommandForClient(client) {
82
+ if (client === 'codex') {
83
+ return `${NEUS_AUTH_CLI} --client codex`;
84
+ }
85
+ return NEUS_AUTH_CLI;
86
+ }
87
+
88
+ /**
89
+ * @param {'claude' | 'codex' | 'cursor' | 'vscode'} client
90
+ * @param {string | null | undefined} accessKey
91
+ * @returns {string}
92
+ */
93
+ export function buildSetupCommandForClient(client, accessKey) {
94
+ const key = String(accessKey || '').trim();
95
+ const setup = key
96
+ ? `${NEUS_SETUP_CLI} --client ${client} --access-key ${key}`
97
+ : `${NEUS_SETUP_CLI} --client ${client}`;
98
+ if (key) return setup;
99
+ return `${setup}\n${buildAuthCommandForClient(client)}`;
100
+ }
101
+
102
+ /**
103
+ * @param {'cursor' | 'claude' | 'codex'} host
104
+ * @param {string | null | undefined} accessKey
105
+ * @returns {string}
106
+ */
107
+ export function buildSetupCommandForHost(host, accessKey) {
108
+ return buildSetupCommandForClient(host, accessKey);
109
+ }
110
+
111
+ /**
112
+ * Cursor supports MCP install deeplinks; Codex uses CLI, not VS Code deeplinks.
113
+ * @param {'cursor' | 'claude' | 'codex'} host
114
+ * @returns {boolean}
115
+ */
116
+ export function supportsMcpInstallDeeplink(host) {
117
+ if (host !== 'cursor') return false;
118
+ if (typeof navigator === 'undefined') return false;
119
+ const ua = navigator.userAgent || '';
120
+ return !/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
121
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neus/sdk",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
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"
@@ -31,6 +31,10 @@
31
31
  "import": "./gates.js",
32
32
  "require": "./cjs/gates.cjs"
33
33
  },
34
+ "./mcp-hosts": {
35
+ "import": "./mcp-hosts.js",
36
+ "require": "./cjs/mcp-hosts.cjs"
37
+ },
34
38
  "./widgets": {
35
39
  "types": "./types.d.ts",
36
40
  "import": "./widgets/index.js",
@@ -49,8 +53,8 @@
49
53
  "lint": "eslint . --ignore-pattern widgets/verify-gate/dist/**",
50
54
  "format": "prettier --write \"**/*.js\"",
51
55
  "build": "npm run build:widgets && npm run build:cjs",
52
- "build:widgets": "npx esbuild widgets/verify-gate/VerifyGate.jsx widgets/verify-gate/ProofBadge.jsx --bundle --platform=browser --format=esm --outdir=widgets/verify-gate/dist --jsx=automatic --legal-comments=none --loader:.svg=dataurl --external:react --external:react-dom --external:react/jsx-runtime --external:@neus/sdk/client",
53
- "build:cjs": "npx esbuild index.js client.js utils.js errors.js gates.js --bundle --platform=node --format=cjs --outdir=cjs --out-extension:.js=.cjs --legal-comments=none --external:ethers --external:@zkpassport/sdk --external:react --external:react-dom --external:react/jsx-runtime",
56
+ "build:widgets": "npx esbuild widgets/verify-gate/VerifyGate.jsx widgets/verify-gate/ProofBadge.jsx --bundle --platform=browser --format=esm --outdir=widgets/verify-gate/dist --jsx=automatic --legal-comments=none --external:react --external:react-dom --external:react/jsx-runtime --external:@neus/sdk/client",
57
+ "build:cjs": "npx esbuild index.js client.js utils.js errors.js gates.js mcp-hosts.js --bundle --platform=node --format=cjs --outdir=cjs --out-extension:.js=.cjs --legal-comments=none --external:ethers --external:@zkpassport/sdk --external:react --external:react-dom --external:react/jsx-runtime",
54
58
  "prepack": "npm run build",
55
59
  "prepublishOnly": "npm run lint && npm test && npm run build"
56
60
  },
@@ -122,19 +126,19 @@
122
126
  },
123
127
  "files": [
124
128
  "cli/neus.mjs",
129
+ "mcp-hosts.js",
125
130
  "index.js",
126
131
  "client.js",
127
132
  "utils.js",
128
133
  "errors.js",
129
134
  "gates.js",
135
+ "sponsor.js",
130
136
  "cjs/**",
131
137
  "widgets.cjs",
132
138
  "types.d.ts",
133
139
  "README.md",
134
- "CHANGELOG.md",
135
140
  "SECURITY.md",
136
141
  "LICENSE",
137
- "neus-logo.svg",
138
142
  "widgets/index.js",
139
143
  "widgets/verify-gate/index.js",
140
144
  "widgets/verify-gate/dist/VerifyGate.js",
package/sponsor.js ADDED
@@ -0,0 +1,95 @@
1
+ import { ValidationError, ApiError, NetworkError } from './errors.js';
2
+
3
+ /**
4
+ * Request short-lived billing authorization so verification usage bills the app owner.
5
+ * Requires a completed app registration (`sponsor-grants` delegation) on orgWallet.
6
+ */
7
+ export async function fetchSponsorGrant(params = {}) {
8
+ const {
9
+ apiUrl = 'https://api.neus.network',
10
+ appId,
11
+ orgWallet,
12
+ verifierIds = [],
13
+ targetChains = [],
14
+ origin,
15
+ expiresInSeconds = 900,
16
+ fetchImpl = fetch
17
+ } = params;
18
+
19
+ const normalizedAppId = typeof appId === 'string' ? appId.trim() : '';
20
+ const normalizedOrg = typeof orgWallet === 'string' ? orgWallet.trim().toLowerCase() : '';
21
+ if (!normalizedAppId) {
22
+ throw new ValidationError('appId is required for sponsor grant');
23
+ }
24
+ if (!normalizedOrg || !/^0x[a-f0-9]{40}$/.test(normalizedOrg)) {
25
+ throw new ValidationError('orgWallet must be a valid EVM address');
26
+ }
27
+
28
+ let base = String(apiUrl || 'https://api.neus.network').replace(/\/+$/, '');
29
+ try {
30
+ const url = new URL(base);
31
+ if (url.hostname.endsWith('neus.network') && url.protocol === 'http:') {
32
+ url.protocol = 'https:';
33
+ }
34
+ base = url.toString().replace(/\/+$/, '');
35
+ } catch {
36
+ void 0;
37
+ }
38
+
39
+ const headers = {
40
+ 'Content-Type': 'application/json',
41
+ Accept: 'application/json',
42
+ 'X-Neus-App': normalizedAppId,
43
+ 'X-Neus-Sdk': 'js'
44
+ };
45
+ if (typeof origin === 'string' && origin.trim()) {
46
+ headers.Origin = origin.trim();
47
+ }
48
+
49
+ const body = {
50
+ orgWallet: normalizedOrg,
51
+ scope: 'sponsored-verification',
52
+ expiresInSeconds,
53
+ ...(Array.isArray(verifierIds) && verifierIds.length > 0
54
+ ? { verifierIds: verifierIds.map((v) => String(v).trim()).filter(Boolean).slice(0, 25) }
55
+ : {}),
56
+ ...(Array.isArray(targetChains) && targetChains.length > 0
57
+ ? { targetChains: targetChains.filter((n) => Number.isFinite(Number(n))).slice(0, 25) }
58
+ : {})
59
+ };
60
+
61
+ let response;
62
+ try {
63
+ response = await fetchImpl(`${base}/api/v1/sponsor/grant`, {
64
+ method: 'POST',
65
+ headers,
66
+ body: JSON.stringify(body)
67
+ });
68
+ } catch (error) {
69
+ throw new NetworkError(`Sponsor grant request failed: ${error?.message || String(error)}`);
70
+ }
71
+
72
+ let payload;
73
+ try {
74
+ payload = await response.json();
75
+ } catch {
76
+ payload = { success: false, error: { message: 'Invalid JSON response' } };
77
+ }
78
+
79
+ if (!response.ok || payload?.success !== true) {
80
+ throw ApiError.fromResponse(response, payload);
81
+ }
82
+
83
+ const token = payload?.data?.sponsorGrant;
84
+ if (!token || typeof token !== 'string') {
85
+ throw new ApiError('Sponsor grant response missing sponsorGrant token', payload?.error);
86
+ }
87
+
88
+ return {
89
+ sponsorGrant: token,
90
+ exp: payload?.data?.exp,
91
+ orgWallet: payload?.data?.orgWallet || normalizedOrg,
92
+ appId: payload?.data?.appId || normalizedAppId,
93
+ maxCredits: payload?.data?.maxCredits
94
+ };
95
+ }
package/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- declare module '@neus/sdk' {
1
+ declare module '@neus/sdk' {
2
2
  export interface Eip1193Provider {
3
3
  request(args: { method: string; params?: unknown[] | Record<string, unknown> }): Promise<unknown>;
4
4
  }
@@ -57,9 +57,18 @@ declare module '@neus/sdk' {
57
57
 
58
58
  export interface NeusClientConfig {
59
59
  apiUrl?: string;
60
+ /** Optional server profile key — MCP/CI only; not required for VerifyGate or gateCheck. */
60
61
  apiKey?: string;
62
+ /** Public app attribution id (non-secret). */
61
63
  appId?: string;
62
- /** Optional: only when using legacy `delegationQHash` on verify requests. App-linked servers rely on `appId` + Origin + stored delegation. */
64
+ /** Hub wallet that pays for user verification checks (your NEUS account). */
65
+ billingWallet?: string;
66
+ /** Alias for billingWallet. */
67
+ sponsorOrgWallet?: string;
68
+ orgWallet?: string;
69
+ /** Site origin used when issuing billing authorization (defaults to browser origin). */
70
+ appOrigin?: string;
71
+ /** Advanced server path only; use appId + billingWallet for the default app flow. */
63
72
  appLinkQHash?: string;
64
73
  paymentSignature?: string;
65
74
  extraHeaders?: Record<string, string>;
@@ -68,6 +77,26 @@ declare module '@neus/sdk' {
68
77
  enableLogging?: boolean;
69
78
  }
70
79
 
80
+ export interface FetchSponsorGrantParams {
81
+ apiUrl?: string;
82
+ appId: string;
83
+ orgWallet: string;
84
+ verifierIds?: string[];
85
+ targetChains?: number[];
86
+ origin?: string;
87
+ expiresInSeconds?: number;
88
+ }
89
+
90
+ export interface FetchSponsorGrantResult {
91
+ sponsorGrant: string;
92
+ exp?: number;
93
+ orgWallet: string;
94
+ appId: string;
95
+ maxCredits?: number;
96
+ }
97
+
98
+ export function fetchSponsorGrant(params: FetchSponsorGrantParams): Promise<FetchSponsorGrantResult>;
99
+
71
100
  export interface VerificationOptions {
72
101
  privacyLevel?: PrivacyLevel;
73
102
  enableIpfs?: boolean;
@@ -450,6 +479,7 @@ declare module '@neus/sdk' {
450
479
  export interface GetProofsOptions {
451
480
  limit?: number;
452
481
  offset?: number;
482
+ cursor?: string;
453
483
  chain?: string;
454
484
  signatureMethod?: string;
455
485
  }
@@ -460,6 +490,8 @@ declare module '@neus/sdk' {
460
490
  totalCount: number;
461
491
  hasMore: boolean;
462
492
  nextOffset?: number | null;
493
+ /** Keyset continuation when the API returns cursor paging (preferred over deep offsets). */
494
+ nextCursor?: string | null;
463
495
  }
464
496
 
465
497
  export interface GateRequirement {
@@ -485,6 +517,8 @@ declare module '@neus/sdk' {
485
517
 
486
518
  export interface GateCheckApiParams {
487
519
  address: string;
520
+ /** Published gate handle; resolves checks server-side (preferred public path). */
521
+ gateId?: string;
488
522
  verifierIds?: string[] | string;
489
523
  requireAll?: boolean;
490
524
  minCount?: number;
@@ -850,6 +884,8 @@ declare module '@neus/sdk' {
850
884
 
851
885
  declare module '@neus/sdk/widgets' {
852
886
  export interface VerifyGateProps {
887
+ /** Published gate checkout handle (default integration path). */
888
+ gateId?: string;
853
889
  requiredVerifiers?: string[];
854
890
  onVerified?: (result: {
855
891
  qHash: string;
@@ -881,12 +917,8 @@ declare module '@neus/sdk/widgets' {
881
917
  oauthProvider?: string;
882
918
  style?: Record<string, any>;
883
919
  children?: any;
884
- verifierOptions?: Record<string, any>;
885
- verifierData?: Record<string, any>;
886
- proofOptions?: Record<string, any>;
887
920
  strategy?: 'reuse-or-create' | 'reuse' | 'fresh';
888
921
  checkExisting?: boolean;
889
- maxProofAgeMs?: number;
890
922
  allowPrivateReuse?: boolean;
891
923
  showBrand?: boolean;
892
924
  disabled?: boolean;
@@ -967,3 +999,31 @@ declare module '@neus/sdk/widgets/verify-gate' {
967
999
  declare module '@neus/sdk/client' {
968
1000
  export { NeusClient } from '@neus/sdk';
969
1001
  }
1002
+
1003
+ declare module '@neus/sdk/mcp-hosts' {
1004
+ export type McpInstallClient = 'claude' | 'codex' | 'cursor' | 'vscode';
1005
+ export type McpInstallHost = 'cursor' | 'claude' | 'codex';
1006
+
1007
+ export const NEUS_MCP_SERVER_NAME: string;
1008
+ export const NEUS_MCP_URL: string;
1009
+ export const NEUS_SETUP_CLI: string;
1010
+ export const NEUS_AUTH_CLI: string;
1011
+ export const NEUS_MCP_SETUP_DOCS_URL: string;
1012
+ export const MCP_INSTALL_CLIENTS: McpInstallClient[];
1013
+ export const MCP_INSTALL_HOSTS: McpInstallHost[];
1014
+ export const IDE_HOST_LABELS: Record<McpInstallHost, string>;
1015
+ export const IDE_HOST_BRAND_LOGOS: Record<McpInstallHost, string>;
1016
+
1017
+ export function buildNeusMcpHttpConfig(accessKey?: string | null): {
1018
+ type: 'http';
1019
+ url: string;
1020
+ headers?: { Authorization: string };
1021
+ };
1022
+
1023
+ export function buildCursorMcpInstallUrl(accessKey?: string | null): string;
1024
+ export function buildVsCodeMcpInstallUrl(accessKey?: string | null): string;
1025
+ export function buildAuthCommandForClient(client: McpInstallClient): string;
1026
+ export function buildSetupCommandForClient(client: McpInstallClient, accessKey?: string | null): string;
1027
+ export function buildSetupCommandForHost(host: McpInstallHost, accessKey?: string | null): string;
1028
+ export function supportsMcpInstallDeeplink(host: McpInstallHost): boolean;
1029
+ }
package/utils.js CHANGED
@@ -1023,6 +1023,8 @@ export function getHostedCheckoutUrl(opts = {}) {
1023
1023
  if (opts.intent) params.set('intent', String(opts.intent));
1024
1024
  if (opts.origin) params.set('origin', String(opts.origin));
1025
1025
  if (opts.oauthProvider) params.set('oauthProvider', String(opts.oauthProvider));
1026
+ if (opts.appId) params.set('appId', String(opts.appId));
1027
+ if (opts.billingWallet) params.set('billingWallet', String(opts.billingWallet).trim().toLowerCase());
1026
1028
  const qs = params.toString();
1027
1029
  return qs ? `${base}?${qs}` : base;
1028
1030
  }
package/widgets/README.md CHANGED
@@ -10,22 +10,18 @@ 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 need public visibility for link-based or public checks.
13
+ Create mode opens Hosted Verify. The published gate owns verifier inputs, pricing, and checkout policy.
14
14
 
15
15
  ```jsx
16
16
  import { VerifyGate } from '@neus/sdk/widgets';
17
17
 
18
18
  export function Page() {
19
19
  return (
20
- <VerifyGate
21
- appId="your-app-id"
22
- requiredVerifiers={['nft-ownership']}
23
- verifierData={{
24
- 'nft-ownership': { contractAddress: '0x...', tokenId: '1', chainId: 8453 }
25
- }}
26
- >
27
- <div>Unlocked</div>
28
- </VerifyGate>
20
+ <VerifyGate
21
+ gateId="gate_abc123"
22
+ >
23
+ <div>Unlocked</div>
24
+ </VerifyGate>
29
25
  );
30
26
  }
31
27
  ```
@@ -35,7 +31,7 @@ export function Page() {
35
31
  ```jsx
36
32
  import { ProofBadge } from '@neus/sdk/widgets';
37
33
 
38
- <ProofBadge qHash="0x..." showChains />
34
+ <ProofBadge qHash={proof.qHash} showChains />
39
35
  ```
40
36
 
41
37
  ## Docs