@neus/sdk 1.1.5 → 1.1.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/cjs/client.cjs CHANGED
@@ -1530,6 +1530,11 @@ ${bytes.length}`;
1530
1530
  storeOriginalContent: typeof options?.storeOriginalContent === "boolean" ? options.storeOriginalContent : true
1531
1531
  };
1532
1532
  if (typeof options?.enableIpfs === "boolean") optionsPayload.enableIpfs = options.enableIpfs;
1533
+ if (options?.publishToHub === true) {
1534
+ optionsPayload.publishToHub = true;
1535
+ } else {
1536
+ delete optionsPayload.publishToHub;
1537
+ }
1533
1538
  const requestData = {
1534
1539
  verifierIds: normalizedVerifierIds,
1535
1540
  data,
@@ -1750,18 +1755,39 @@ ${bytes.length}`;
1750
1755
  }
1751
1756
  return true;
1752
1757
  }
1758
+ _buildProofsByWalletQuery(options = {}) {
1759
+ const qs = [];
1760
+ if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1761
+ const cursorRaw = options.cursor !== null && options.cursor !== void 0 ? String(options.cursor).trim() : "";
1762
+ if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
1763
+ else if (options.offset !== void 0 && options.offset !== null) {
1764
+ qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1765
+ }
1766
+ if (options.q) qs.push(`q=${encodeURIComponent(String(options.q))}`);
1767
+ if (options.qHash) qs.push(`qHash=${encodeURIComponent(String(options.qHash).toLowerCase())}`);
1768
+ if (options.verifierId) qs.push(`verifierId=${encodeURIComponent(String(options.verifierId))}`);
1769
+ if (options.verifierIds) qs.push(`verifierIds=${encodeURIComponent(String(options.verifierIds))}`);
1770
+ if (options.tags) qs.push(`tags=${encodeURIComponent(String(options.tags))}`);
1771
+ if (options.tagPrefix) qs.push(`tagPrefix=${encodeURIComponent(String(options.tagPrefix))}`);
1772
+ if (options.tagContains) qs.push(`tagContains=${encodeURIComponent(String(options.tagContains))}`);
1773
+ if (options.tagPrefixesAll) qs.push(`tagPrefixesAll=${encodeURIComponent(String(options.tagPrefixesAll))}`);
1774
+ if (options.status) qs.push(`status=${encodeURIComponent(String(options.status))}`);
1775
+ if (options.appId) qs.push(`appId=${encodeURIComponent(String(options.appId))}`);
1776
+ if (options.chainCoverage) qs.push(`chainCoverage=${encodeURIComponent(String(options.chainCoverage))}`);
1777
+ if (options.privacyLevel) qs.push(`privacyLevel=${encodeURIComponent(String(options.privacyLevel))}`);
1778
+ if (options.includeHistory) qs.push("includeHistory=1");
1779
+ if (options.includeFacets) qs.push(`includeFacets=${encodeURIComponent(String(options.includeFacets))}`);
1780
+ if (options.visibility) qs.push(`visibility=${encodeURIComponent(String(options.visibility))}`);
1781
+ if (options.isPublicRead) qs.push("isPublicRead=1");
1782
+ return qs;
1783
+ }
1753
1784
  async getProofsByWallet(walletAddress, options = {}) {
1754
1785
  if (!walletAddress || typeof walletAddress !== "string") {
1755
1786
  throw new ValidationError("walletAddress is required");
1756
1787
  }
1757
1788
  const id = walletAddress.trim();
1758
1789
  const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
1759
- const qs = [];
1760
- if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1761
- const cursorRaw = options.cursor !== null && options.cursor !== void 0 ? String(options.cursor).trim() : "";
1762
- if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
1763
- else if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1764
- if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
1790
+ const qs = this._buildProofsByWalletQuery(options);
1765
1791
  const query = qs.length ? `?${qs.join("&")}` : "";
1766
1792
  const response = await this._makeRequest(
1767
1793
  "GET",
@@ -1774,10 +1800,11 @@ ${bytes.length}`;
1774
1800
  return {
1775
1801
  success: true,
1776
1802
  proofs: Array.isArray(proofs) ? proofs : [],
1777
- totalCount: response.data?.totalCount ?? proofs.length,
1803
+ totalCount: typeof response.data?.totalCount === "number" ? response.data.totalCount : null,
1778
1804
  hasMore: Boolean(response.data?.hasMore),
1779
1805
  nextOffset: response.data?.nextOffset ?? null,
1780
- nextCursor: typeof response.data?.nextCursor === "string" && response.data.nextCursor.trim() ? response.data.nextCursor.trim() : null
1806
+ nextCursor: typeof response.data?.nextCursor === "string" && response.data.nextCursor.trim() ? response.data.nextCursor.trim() : null,
1807
+ facets: response.data?.facets || null
1781
1808
  };
1782
1809
  }
1783
1810
  async getPrivateProofsByWallet(walletAddress, options = {}, wallet = null) {
@@ -1827,12 +1854,7 @@ ${bytes.length}`;
1827
1854
  }
1828
1855
  throw new ValidationError(`Failed to sign message: ${error.message}`);
1829
1856
  }
1830
- const qs = [];
1831
- if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1832
- const cursorRaw = options.cursor !== null && options.cursor !== void 0 ? String(options.cursor).trim() : "";
1833
- if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
1834
- else if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1835
- if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
1857
+ const qs = this._buildProofsByWalletQuery(options);
1836
1858
  const query = qs.length ? `?${qs.join("&")}` : "";
1837
1859
  const response = await this._makeRequest("GET", `/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`, null, {
1838
1860
  "x-wallet-address": signerWalletAddress,
@@ -1847,7 +1869,7 @@ ${bytes.length}`;
1847
1869
  return {
1848
1870
  success: true,
1849
1871
  proofs: Array.isArray(proofs) ? proofs : [],
1850
- totalCount: response.data?.totalCount ?? proofs.length,
1872
+ totalCount: typeof response.data?.totalCount === "number" ? response.data.totalCount : null,
1851
1873
  hasMore: Boolean(response.data?.hasMore),
1852
1874
  nextOffset: response.data?.nextOffset ?? null,
1853
1875
  nextCursor: typeof response.data?.nextCursor === "string" && response.data.nextCursor.trim() ? response.data.nextCursor.trim() : null
@@ -1964,6 +1986,64 @@ ${bytes.length}`;
1964
1986
  }
1965
1987
  return response;
1966
1988
  }
1989
+ /**
1990
+ * Get the public snapshot of a published gate: requirements, charge, schedule,
1991
+ * checkout plan, and reward presence. Never returns the secret reward value —
1992
+ * that is delivered post-verify via fulfillGate().
1993
+ *
1994
+ * @param {string} gateId Published gate handle
1995
+ * @returns {Promise<object>} Public gate snapshot
1996
+ */
1997
+ async getGate(gateId) {
1998
+ const id = String(gateId || "").trim();
1999
+ if (!id || id.length > 80 || !/^[a-zA-Z0-9:_-]+$/.test(id)) {
2000
+ throw new ValidationError("Valid gateId is required");
2001
+ }
2002
+ const response = await this._makeRequest("GET", `/api/v1/gates/${encodeURIComponent(id)}`);
2003
+ if (!response.success || !response.data?.gate) {
2004
+ throw new ApiError(`Gate lookup failed: ${response.error?.message || "Gate not found"}`, response.error);
2005
+ }
2006
+ return response.data.gate;
2007
+ }
2008
+ /**
2009
+ * Post-verify reward delivery for hosted gate checkout. Requires a verified
2010
+ * proof (qHash) for the gate; paid gates also require payment evidence
2011
+ * (paymentCheckoutSessionId for card, or paymentTxHash for USDC).
2012
+ *
2013
+ * @param {object} params
2014
+ * @param {string} params.gateId Published gate handle
2015
+ * @param {string} params.qHash Verified proof receipt id
2016
+ * @param {string} [params.walletAddress] Wallet bound to the proof (required without a session cookie)
2017
+ * @param {string} [params.paymentCheckoutSessionId] Stripe checkout session id (card rail)
2018
+ * @param {string} [params.paymentTxHash] USDC payment transaction hash (wallet rail)
2019
+ * @returns {Promise<object>} `{ success, data: { gateId, qHash, fulfillment, successReturnUrl? } }`
2020
+ */
2021
+ async fulfillGate(params = {}) {
2022
+ const gateId = String(params.gateId || "").trim();
2023
+ if (!gateId || gateId.length > 80 || !/^[a-zA-Z0-9:_-]+$/.test(gateId)) {
2024
+ throw new ValidationError("Valid gateId is required");
2025
+ }
2026
+ const qHash = String(params.qHash || "").trim();
2027
+ if (!/^0x[a-fA-F0-9]{64}$/.test(qHash)) {
2028
+ throw new ValidationError("Valid qHash is required");
2029
+ }
2030
+ const body = { qHash };
2031
+ const walletAddress = String(params.walletAddress || "").trim();
2032
+ if (walletAddress) body.walletAddress = walletAddress;
2033
+ const paymentCheckoutSessionId = String(params.paymentCheckoutSessionId || "").trim();
2034
+ if (paymentCheckoutSessionId) body.paymentCheckoutSessionId = paymentCheckoutSessionId;
2035
+ const paymentTxHash = String(params.paymentTxHash || "").trim();
2036
+ if (paymentTxHash) body.paymentTxHash = paymentTxHash;
2037
+ const response = await this._makeRequest(
2038
+ "POST",
2039
+ `/api/v1/gates/${encodeURIComponent(gateId)}/fulfill`,
2040
+ body
2041
+ );
2042
+ if (!response.success) {
2043
+ throw new ApiError(`Gate fulfillment failed: ${response.error?.message || "Unknown error"}`, response.error);
2044
+ }
2045
+ return response;
2046
+ }
1967
2047
  async checkGate(params) {
1968
2048
  const { walletAddress, requirements, proofs: preloadedProofs } = params;
1969
2049
  if (!validateUniversalAddress(walletAddress)) {
package/cjs/index.cjs CHANGED
@@ -2223,6 +2223,11 @@ ${bytes.length}`;
2223
2223
  storeOriginalContent: typeof options?.storeOriginalContent === "boolean" ? options.storeOriginalContent : true
2224
2224
  };
2225
2225
  if (typeof options?.enableIpfs === "boolean") optionsPayload.enableIpfs = options.enableIpfs;
2226
+ if (options?.publishToHub === true) {
2227
+ optionsPayload.publishToHub = true;
2228
+ } else {
2229
+ delete optionsPayload.publishToHub;
2230
+ }
2226
2231
  const requestData = {
2227
2232
  verifierIds: normalizedVerifierIds,
2228
2233
  data,
@@ -2443,18 +2448,39 @@ ${bytes.length}`;
2443
2448
  }
2444
2449
  return true;
2445
2450
  }
2451
+ _buildProofsByWalletQuery(options = {}) {
2452
+ const qs = [];
2453
+ if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
2454
+ const cursorRaw = options.cursor !== null && options.cursor !== void 0 ? String(options.cursor).trim() : "";
2455
+ if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
2456
+ else if (options.offset !== void 0 && options.offset !== null) {
2457
+ qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
2458
+ }
2459
+ if (options.q) qs.push(`q=${encodeURIComponent(String(options.q))}`);
2460
+ if (options.qHash) qs.push(`qHash=${encodeURIComponent(String(options.qHash).toLowerCase())}`);
2461
+ if (options.verifierId) qs.push(`verifierId=${encodeURIComponent(String(options.verifierId))}`);
2462
+ if (options.verifierIds) qs.push(`verifierIds=${encodeURIComponent(String(options.verifierIds))}`);
2463
+ if (options.tags) qs.push(`tags=${encodeURIComponent(String(options.tags))}`);
2464
+ if (options.tagPrefix) qs.push(`tagPrefix=${encodeURIComponent(String(options.tagPrefix))}`);
2465
+ if (options.tagContains) qs.push(`tagContains=${encodeURIComponent(String(options.tagContains))}`);
2466
+ if (options.tagPrefixesAll) qs.push(`tagPrefixesAll=${encodeURIComponent(String(options.tagPrefixesAll))}`);
2467
+ if (options.status) qs.push(`status=${encodeURIComponent(String(options.status))}`);
2468
+ if (options.appId) qs.push(`appId=${encodeURIComponent(String(options.appId))}`);
2469
+ if (options.chainCoverage) qs.push(`chainCoverage=${encodeURIComponent(String(options.chainCoverage))}`);
2470
+ if (options.privacyLevel) qs.push(`privacyLevel=${encodeURIComponent(String(options.privacyLevel))}`);
2471
+ if (options.includeHistory) qs.push("includeHistory=1");
2472
+ if (options.includeFacets) qs.push(`includeFacets=${encodeURIComponent(String(options.includeFacets))}`);
2473
+ if (options.visibility) qs.push(`visibility=${encodeURIComponent(String(options.visibility))}`);
2474
+ if (options.isPublicRead) qs.push("isPublicRead=1");
2475
+ return qs;
2476
+ }
2446
2477
  async getProofsByWallet(walletAddress, options = {}) {
2447
2478
  if (!walletAddress || typeof walletAddress !== "string") {
2448
2479
  throw new ValidationError("walletAddress is required");
2449
2480
  }
2450
2481
  const id = walletAddress.trim();
2451
2482
  const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
2452
- const qs = [];
2453
- if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
2454
- const cursorRaw = options.cursor !== null && options.cursor !== void 0 ? String(options.cursor).trim() : "";
2455
- if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
2456
- else if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
2457
- if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
2483
+ const qs = this._buildProofsByWalletQuery(options);
2458
2484
  const query = qs.length ? `?${qs.join("&")}` : "";
2459
2485
  const response = await this._makeRequest(
2460
2486
  "GET",
@@ -2467,10 +2493,11 @@ ${bytes.length}`;
2467
2493
  return {
2468
2494
  success: true,
2469
2495
  proofs: Array.isArray(proofs) ? proofs : [],
2470
- totalCount: response.data?.totalCount ?? proofs.length,
2496
+ totalCount: typeof response.data?.totalCount === "number" ? response.data.totalCount : null,
2471
2497
  hasMore: Boolean(response.data?.hasMore),
2472
2498
  nextOffset: response.data?.nextOffset ?? null,
2473
- nextCursor: typeof response.data?.nextCursor === "string" && response.data.nextCursor.trim() ? response.data.nextCursor.trim() : null
2499
+ nextCursor: typeof response.data?.nextCursor === "string" && response.data.nextCursor.trim() ? response.data.nextCursor.trim() : null,
2500
+ facets: response.data?.facets || null
2474
2501
  };
2475
2502
  }
2476
2503
  async getPrivateProofsByWallet(walletAddress, options = {}, wallet = null) {
@@ -2520,12 +2547,7 @@ ${bytes.length}`;
2520
2547
  }
2521
2548
  throw new ValidationError(`Failed to sign message: ${error.message}`);
2522
2549
  }
2523
- const qs = [];
2524
- if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
2525
- const cursorRaw = options.cursor !== null && options.cursor !== void 0 ? String(options.cursor).trim() : "";
2526
- if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
2527
- else if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
2528
- if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
2550
+ const qs = this._buildProofsByWalletQuery(options);
2529
2551
  const query = qs.length ? `?${qs.join("&")}` : "";
2530
2552
  const response = await this._makeRequest("GET", `/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`, null, {
2531
2553
  "x-wallet-address": signerWalletAddress,
@@ -2540,7 +2562,7 @@ ${bytes.length}`;
2540
2562
  return {
2541
2563
  success: true,
2542
2564
  proofs: Array.isArray(proofs) ? proofs : [],
2543
- totalCount: response.data?.totalCount ?? proofs.length,
2565
+ totalCount: typeof response.data?.totalCount === "number" ? response.data.totalCount : null,
2544
2566
  hasMore: Boolean(response.data?.hasMore),
2545
2567
  nextOffset: response.data?.nextOffset ?? null,
2546
2568
  nextCursor: typeof response.data?.nextCursor === "string" && response.data.nextCursor.trim() ? response.data.nextCursor.trim() : null
@@ -2657,6 +2679,64 @@ ${bytes.length}`;
2657
2679
  }
2658
2680
  return response;
2659
2681
  }
2682
+ /**
2683
+ * Get the public snapshot of a published gate: requirements, charge, schedule,
2684
+ * checkout plan, and reward presence. Never returns the secret reward value —
2685
+ * that is delivered post-verify via fulfillGate().
2686
+ *
2687
+ * @param {string} gateId Published gate handle
2688
+ * @returns {Promise<object>} Public gate snapshot
2689
+ */
2690
+ async getGate(gateId) {
2691
+ const id = String(gateId || "").trim();
2692
+ if (!id || id.length > 80 || !/^[a-zA-Z0-9:_-]+$/.test(id)) {
2693
+ throw new ValidationError("Valid gateId is required");
2694
+ }
2695
+ const response = await this._makeRequest("GET", `/api/v1/gates/${encodeURIComponent(id)}`);
2696
+ if (!response.success || !response.data?.gate) {
2697
+ throw new ApiError(`Gate lookup failed: ${response.error?.message || "Gate not found"}`, response.error);
2698
+ }
2699
+ return response.data.gate;
2700
+ }
2701
+ /**
2702
+ * Post-verify reward delivery for hosted gate checkout. Requires a verified
2703
+ * proof (qHash) for the gate; paid gates also require payment evidence
2704
+ * (paymentCheckoutSessionId for card, or paymentTxHash for USDC).
2705
+ *
2706
+ * @param {object} params
2707
+ * @param {string} params.gateId Published gate handle
2708
+ * @param {string} params.qHash Verified proof receipt id
2709
+ * @param {string} [params.walletAddress] Wallet bound to the proof (required without a session cookie)
2710
+ * @param {string} [params.paymentCheckoutSessionId] Stripe checkout session id (card rail)
2711
+ * @param {string} [params.paymentTxHash] USDC payment transaction hash (wallet rail)
2712
+ * @returns {Promise<object>} `{ success, data: { gateId, qHash, fulfillment, successReturnUrl? } }`
2713
+ */
2714
+ async fulfillGate(params = {}) {
2715
+ const gateId = String(params.gateId || "").trim();
2716
+ if (!gateId || gateId.length > 80 || !/^[a-zA-Z0-9:_-]+$/.test(gateId)) {
2717
+ throw new ValidationError("Valid gateId is required");
2718
+ }
2719
+ const qHash = String(params.qHash || "").trim();
2720
+ if (!/^0x[a-fA-F0-9]{64}$/.test(qHash)) {
2721
+ throw new ValidationError("Valid qHash is required");
2722
+ }
2723
+ const body = { qHash };
2724
+ const walletAddress = String(params.walletAddress || "").trim();
2725
+ if (walletAddress) body.walletAddress = walletAddress;
2726
+ const paymentCheckoutSessionId = String(params.paymentCheckoutSessionId || "").trim();
2727
+ if (paymentCheckoutSessionId) body.paymentCheckoutSessionId = paymentCheckoutSessionId;
2728
+ const paymentTxHash = String(params.paymentTxHash || "").trim();
2729
+ if (paymentTxHash) body.paymentTxHash = paymentTxHash;
2730
+ const response = await this._makeRequest(
2731
+ "POST",
2732
+ `/api/v1/gates/${encodeURIComponent(gateId)}/fulfill`,
2733
+ body
2734
+ );
2735
+ if (!response.success) {
2736
+ throw new ApiError(`Gate fulfillment failed: ${response.error?.message || "Unknown error"}`, response.error);
2737
+ }
2738
+ return response;
2739
+ }
2660
2740
  async checkGate(params) {
2661
2741
  const { walletAddress, requirements, proofs: preloadedProofs } = params;
2662
2742
  if (!validateUniversalAddress(walletAddress)) {
package/cli/neus.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { spawnSync } from 'node:child_process';
2
+ import { exec, spawnSync } from 'node:child_process';
3
3
  import { createHash, randomBytes } from 'node:crypto';
4
4
  import fs from 'node:fs';
5
5
  import os from 'node:os';
@@ -12,6 +12,13 @@ import {
12
12
  } from '../mcp-hosts.js';
13
13
 
14
14
  const __cliDir = path.dirname(fileURLToPath(import.meta.url));
15
+ const CLI_PACKAGE_VERSION = (() => {
16
+ try {
17
+ return JSON.parse(fs.readFileSync(path.join(__cliDir, '..', 'package.json'), 'utf8')).version;
18
+ } catch {
19
+ return '0.0.0';
20
+ }
21
+ })();
15
22
 
16
23
  const NEUS_APP_URL = 'https://neus.network';
17
24
  const NEUS_TOKEN_ENDPOINT = 'https://neus.network/api/v1/auth/mcp/token';
@@ -137,6 +144,7 @@ function describeClientResult(command, result) {
137
144
  }
138
145
  if (result.changed) return 'updated';
139
146
  if (result.authConfigured) return 'signed in';
147
+ if (result.configured) return 'ready';
140
148
  return 'ready';
141
149
  }
142
150
 
@@ -296,6 +304,7 @@ function envAccessKey() {
296
304
 
297
305
  /** --access-key flag, else NEUS_ACCESS_KEY from the environment, else browser sign-in. */
298
306
  function resolveAccessKey(options) {
307
+ if (options?.oauth) return '';
299
308
  const explicit = String(options.accessKey || '').trim();
300
309
  if (explicit) return explicit;
301
310
  return envAccessKey();
@@ -307,6 +316,7 @@ function resolveLiveAccessKey(options, scope, cwd) {
307
316
  if (explicit) return explicit;
308
317
  const installed = readInstalledAccessKey(scope, cwd);
309
318
  if (installed) return installed;
319
+ if (options?.oauth) return '';
310
320
  return envAccessKey();
311
321
  }
312
322
 
@@ -579,7 +589,8 @@ function parseArgs(argv) {
579
589
  live: false,
580
590
  json: false,
581
591
  dryRun: false,
582
- project: false
592
+ project: false,
593
+ oauth: false
583
594
  };
584
595
 
585
596
  for (let index = 1; index < argv.length; index += 1) {
@@ -635,6 +646,10 @@ function parseArgs(argv) {
635
646
  index += 1;
636
647
  continue;
637
648
  }
649
+ if (token === '--oauth') {
650
+ options.oauth = true;
651
+ continue;
652
+ }
638
653
  if (token === '--help' || token === '-h') {
639
654
  return { command: 'help', options };
640
655
  }
@@ -668,6 +683,7 @@ function printUsage(exitCode = 0) {
668
683
  ' --client <name[,name]> Limit setup to claude, codex, cursor, or vscode',
669
684
  ' --project Write shared project config instead of user config',
670
685
  ' --access-key <npk_...> Override profile access key (else uses NEUS_ACCESS_KEY if set)',
686
+ ' --oauth Force browser OAuth (ignore NEUS_ACCESS_KEY in the environment)',
671
687
  ' --from <source> Import source: auto, cursor, claude-code, or claude-desktop',
672
688
  ' --to <format> Export format: manifest or json',
673
689
  ' --output <path> Write exported manifest to a specific path',
@@ -1383,7 +1399,7 @@ async function runLiveMcpDiagnostics(accessKey) {
1383
1399
  params: {
1384
1400
  protocolVersion: '2025-11-25',
1385
1401
  capabilities: {},
1386
- clientInfo: { name: 'neus-cli', version: '1.1.5' }
1402
+ clientInfo: { name: 'neus-cli', version: CLI_PACKAGE_VERSION }
1387
1403
  },
1388
1404
  accessKey,
1389
1405
  signal: controller.signal
@@ -1699,9 +1715,12 @@ async function runAuthBrowser(options) {
1699
1715
  logStep('next', 'wait', 'finish sign-in in the browser');
1700
1716
  }
1701
1717
 
1702
- const { exec } = require('node:child_process');
1703
- const openCmd = process.platform === 'win32' ? 'start' : process.platform === 'darwin' ? 'open' : 'xdg-open';
1704
- exec(`${openCmd} "${authUrl}"`, err => {
1718
+ const openCommand = process.platform === 'win32'
1719
+ ? `cmd /c start "" "${authUrl.replace(/"/g, '\\"')}"`
1720
+ : process.platform === 'darwin'
1721
+ ? `open "${authUrl.replace(/"/g, '\\"')}"`
1722
+ : `xdg-open "${authUrl.replace(/"/g, '\\"')}"`;
1723
+ exec(openCommand, { shell: true }, err => {
1705
1724
  if (err && !options.json) {
1706
1725
  logStep('warn', 'browser', 'open the URL above manually');
1707
1726
  }
@@ -1816,6 +1835,12 @@ async function runSetup(options) {
1816
1835
  }
1817
1836
 
1818
1837
  if (options.json) {
1838
+ payload.authRequired = !accessKey && !options.dryRun;
1839
+ if (payload.authRequired) {
1840
+ payload.nextCommand = clients.length === 1 && clients[0] === 'codex'
1841
+ ? 'neus auth --client codex'
1842
+ : 'neus auth';
1843
+ }
1819
1844
  printJson(payload);
1820
1845
  return payload;
1821
1846
  }
package/client.js CHANGED
@@ -1204,6 +1204,12 @@ export class NeusClient {
1204
1204
  typeof options?.storeOriginalContent === 'boolean' ? options.storeOriginalContent : true
1205
1205
  };
1206
1206
  if (typeof options?.enableIpfs === 'boolean') optionsPayload.enableIpfs = options.enableIpfs;
1207
+ // Receipts persist offchain by default; hub registry anchoring is explicit opt-in.
1208
+ if (options?.publishToHub === true) {
1209
+ optionsPayload.publishToHub = true;
1210
+ } else {
1211
+ delete optionsPayload.publishToHub;
1212
+ }
1207
1213
 
1208
1214
  const requestData = {
1209
1215
  verifierIds: normalizedVerifierIds,
@@ -1471,6 +1477,33 @@ export class NeusClient {
1471
1477
  return true;
1472
1478
  }
1473
1479
 
1480
+ _buildProofsByWalletQuery(options = {}) {
1481
+ const qs = [];
1482
+ if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1483
+ const cursorRaw = options.cursor !== null && options.cursor !== undefined ? String(options.cursor).trim() : '';
1484
+ if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
1485
+ else if (options.offset !== undefined && options.offset !== null) {
1486
+ qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1487
+ }
1488
+ if (options.q) qs.push(`q=${encodeURIComponent(String(options.q))}`);
1489
+ if (options.qHash) qs.push(`qHash=${encodeURIComponent(String(options.qHash).toLowerCase())}`);
1490
+ if (options.verifierId) qs.push(`verifierId=${encodeURIComponent(String(options.verifierId))}`);
1491
+ if (options.verifierIds) qs.push(`verifierIds=${encodeURIComponent(String(options.verifierIds))}`);
1492
+ if (options.tags) qs.push(`tags=${encodeURIComponent(String(options.tags))}`);
1493
+ if (options.tagPrefix) qs.push(`tagPrefix=${encodeURIComponent(String(options.tagPrefix))}`);
1494
+ if (options.tagContains) qs.push(`tagContains=${encodeURIComponent(String(options.tagContains))}`);
1495
+ if (options.tagPrefixesAll) qs.push(`tagPrefixesAll=${encodeURIComponent(String(options.tagPrefixesAll))}`);
1496
+ if (options.status) qs.push(`status=${encodeURIComponent(String(options.status))}`);
1497
+ if (options.appId) qs.push(`appId=${encodeURIComponent(String(options.appId))}`);
1498
+ if (options.chainCoverage) qs.push(`chainCoverage=${encodeURIComponent(String(options.chainCoverage))}`);
1499
+ if (options.privacyLevel) qs.push(`privacyLevel=${encodeURIComponent(String(options.privacyLevel))}`);
1500
+ if (options.includeHistory) qs.push('includeHistory=1');
1501
+ if (options.includeFacets) qs.push(`includeFacets=${encodeURIComponent(String(options.includeFacets))}`);
1502
+ if (options.visibility) qs.push(`visibility=${encodeURIComponent(String(options.visibility))}`);
1503
+ if (options.isPublicRead) qs.push('isPublicRead=1');
1504
+ return qs;
1505
+ }
1506
+
1474
1507
  async getProofsByWallet(walletAddress, options = {}) {
1475
1508
  if (!walletAddress || typeof walletAddress !== 'string') {
1476
1509
  throw new ValidationError('walletAddress is required');
@@ -1479,12 +1512,7 @@ export class NeusClient {
1479
1512
  const id = walletAddress.trim();
1480
1513
  const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
1481
1514
 
1482
- const qs = [];
1483
- if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1484
- const cursorRaw = options.cursor !== null && options.cursor !== undefined ? String(options.cursor).trim() : '';
1485
- if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
1486
- else if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1487
- if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
1515
+ const qs = this._buildProofsByWalletQuery(options);
1488
1516
 
1489
1517
  const query = qs.length ? `?${qs.join('&')}` : '';
1490
1518
  const response = await this._makeRequest(
@@ -1500,13 +1528,14 @@ export class NeusClient {
1500
1528
  return {
1501
1529
  success: true,
1502
1530
  proofs: Array.isArray(proofs) ? proofs : [],
1503
- totalCount: response.data?.totalCount ?? proofs.length,
1531
+ totalCount: typeof response.data?.totalCount === 'number' ? response.data.totalCount : null,
1504
1532
  hasMore: Boolean(response.data?.hasMore),
1505
1533
  nextOffset: response.data?.nextOffset ?? null,
1506
1534
  nextCursor:
1507
1535
  typeof response.data?.nextCursor === 'string' && response.data.nextCursor.trim()
1508
1536
  ? response.data.nextCursor.trim()
1509
- : null
1537
+ : null,
1538
+ facets: response.data?.facets || null,
1510
1539
  };
1511
1540
  }
1512
1541
 
@@ -1569,12 +1598,7 @@ export class NeusClient {
1569
1598
  throw new ValidationError(`Failed to sign message: ${error.message}`);
1570
1599
  }
1571
1600
 
1572
- const qs = [];
1573
- if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1574
- const cursorRaw = options.cursor !== null && options.cursor !== undefined ? String(options.cursor).trim() : '';
1575
- if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
1576
- else if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1577
- if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
1601
+ const qs = this._buildProofsByWalletQuery(options);
1578
1602
  const query = qs.length ? `?${qs.join('&')}` : '';
1579
1603
 
1580
1604
  const response = await this._makeRequest('GET', `/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`, null, {
@@ -1592,7 +1616,7 @@ export class NeusClient {
1592
1616
  return {
1593
1617
  success: true,
1594
1618
  proofs: Array.isArray(proofs) ? proofs : [],
1595
- totalCount: response.data?.totalCount ?? proofs.length,
1619
+ totalCount: typeof response.data?.totalCount === 'number' ? response.data.totalCount : null,
1596
1620
  hasMore: Boolean(response.data?.hasMore),
1597
1621
  nextOffset: response.data?.nextOffset ?? null,
1598
1622
  nextCursor:
@@ -1730,6 +1754,67 @@ export class NeusClient {
1730
1754
  return response;
1731
1755
  }
1732
1756
 
1757
+ /**
1758
+ * Get the public snapshot of a published gate: requirements, charge, schedule,
1759
+ * checkout plan, and reward presence. Never returns the secret reward value —
1760
+ * that is delivered post-verify via fulfillGate().
1761
+ *
1762
+ * @param {string} gateId Published gate handle
1763
+ * @returns {Promise<object>} Public gate snapshot
1764
+ */
1765
+ async getGate(gateId) {
1766
+ const id = String(gateId || '').trim();
1767
+ if (!id || id.length > 80 || !/^[a-zA-Z0-9:_-]+$/.test(id)) {
1768
+ throw new ValidationError('Valid gateId is required');
1769
+ }
1770
+ const response = await this._makeRequest('GET', `/api/v1/gates/${encodeURIComponent(id)}`);
1771
+ if (!response.success || !response.data?.gate) {
1772
+ throw new ApiError(`Gate lookup failed: ${response.error?.message || 'Gate not found'}`, response.error);
1773
+ }
1774
+ return response.data.gate;
1775
+ }
1776
+
1777
+ /**
1778
+ * Post-verify reward delivery for hosted gate checkout. Requires a verified
1779
+ * proof (qHash) for the gate; paid gates also require payment evidence
1780
+ * (paymentCheckoutSessionId for card, or paymentTxHash for USDC).
1781
+ *
1782
+ * @param {object} params
1783
+ * @param {string} params.gateId Published gate handle
1784
+ * @param {string} params.qHash Verified proof receipt id
1785
+ * @param {string} [params.walletAddress] Wallet bound to the proof (required without a session cookie)
1786
+ * @param {string} [params.paymentCheckoutSessionId] Stripe checkout session id (card rail)
1787
+ * @param {string} [params.paymentTxHash] USDC payment transaction hash (wallet rail)
1788
+ * @returns {Promise<object>} `{ success, data: { gateId, qHash, fulfillment, successReturnUrl? } }`
1789
+ */
1790
+ async fulfillGate(params = {}) {
1791
+ const gateId = String(params.gateId || '').trim();
1792
+ if (!gateId || gateId.length > 80 || !/^[a-zA-Z0-9:_-]+$/.test(gateId)) {
1793
+ throw new ValidationError('Valid gateId is required');
1794
+ }
1795
+ const qHash = String(params.qHash || '').trim();
1796
+ if (!/^0x[a-fA-F0-9]{64}$/.test(qHash)) {
1797
+ throw new ValidationError('Valid qHash is required');
1798
+ }
1799
+ const body = { qHash };
1800
+ const walletAddress = String(params.walletAddress || '').trim();
1801
+ if (walletAddress) body.walletAddress = walletAddress;
1802
+ const paymentCheckoutSessionId = String(params.paymentCheckoutSessionId || '').trim();
1803
+ if (paymentCheckoutSessionId) body.paymentCheckoutSessionId = paymentCheckoutSessionId;
1804
+ const paymentTxHash = String(params.paymentTxHash || '').trim();
1805
+ if (paymentTxHash) body.paymentTxHash = paymentTxHash;
1806
+
1807
+ const response = await this._makeRequest(
1808
+ 'POST',
1809
+ `/api/v1/gates/${encodeURIComponent(gateId)}/fulfill`,
1810
+ body
1811
+ );
1812
+ if (!response.success) {
1813
+ throw new ApiError(`Gate fulfillment failed: ${response.error?.message || 'Unknown error'}`, response.error);
1814
+ }
1815
+ return response;
1816
+ }
1817
+
1733
1818
  async checkGate(params) {
1734
1819
  const { walletAddress, requirements, proofs: preloadedProofs } = params;
1735
1820
 
package/package.json CHANGED
@@ -1,147 +1,147 @@
1
- {
2
- "name": "@neus/sdk",
3
- "version": "1.1.5",
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
- "bin": {
6
- "neus": "cli/neus.mjs"
7
- },
8
- "main": "index.js",
9
- "type": "module",
10
- "types": "types.d.ts",
11
- "exports": {
12
- ".": {
13
- "types": "./types.d.ts",
14
- "import": "./index.js",
15
- "require": "./cjs/index.cjs"
16
- },
17
- "./client": {
18
- "types": "./types.d.ts",
19
- "import": "./client.js",
20
- "require": "./cjs/client.cjs"
21
- },
22
- "./utils": {
23
- "import": "./utils.js",
24
- "require": "./cjs/utils.cjs"
25
- },
26
- "./errors": {
27
- "import": "./errors.js",
28
- "require": "./cjs/errors.cjs"
29
- },
30
- "./gates": {
31
- "import": "./gates.js",
32
- "require": "./cjs/gates.cjs"
33
- },
34
- "./mcp-hosts": {
35
- "import": "./mcp-hosts.js",
36
- "require": "./cjs/mcp-hosts.cjs"
37
- },
38
- "./widgets": {
39
- "types": "./types.d.ts",
40
- "import": "./widgets/index.js",
41
- "require": "./widgets.cjs"
42
- },
43
- "./widgets/verify-gate": {
44
- "types": "./types.d.ts",
45
- "import": "./widgets/verify-gate/index.js",
46
- "require": "./widgets.cjs"
47
- }
48
- },
49
- "sideEffects": false,
50
- "scripts": {
51
- "test": "npm run build:cjs && vitest run",
52
- "test:coverage": "vitest run --coverage",
53
- "lint": "eslint . --ignore-pattern widgets/verify-gate/dist/**",
54
- "format": "prettier --write \"**/*.js\"",
55
- "build": "npm run build:widgets && npm run build:cjs",
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",
58
- "prepack": "npm run build",
59
- "prepublishOnly": "npm run lint && npm test && npm run build"
60
- },
61
- "keywords": [
62
- "neus",
63
- "verification",
64
- "cryptographic-proofs",
65
- "identity",
66
- "authentication",
67
- "blockchain",
68
- "cross-chain",
69
- "web3",
70
- "passwordless",
71
- "universal-protocol",
72
- "proof",
73
- "ownership",
74
- "sdk",
75
- "mcp",
76
- "model-context-protocol",
77
- "oauth"
78
- ],
79
- "author": "NEUS Network",
80
- "license": "Apache-2.0",
81
- "repository": {
82
- "type": "git",
83
- "url": "git+https://github.com/neus/network.git",
84
- "directory": "sdk"
85
- },
86
- "bugs": {
87
- "url": "https://github.com/neus/network/issues"
88
- },
89
- "homepage": "https://neus.network",
90
- "publishConfig": {
91
- "access": "public",
92
- "registry": "https://registry.npmjs.org"
93
- },
94
- "engines": {
95
- "node": ">=20.0.0"
96
- },
97
- "peerDependencies": {
98
- "ethers": "^6.0.0",
99
- "react": ">=17.0.0",
100
- "react-dom": ">=17.0.0"
101
- },
102
- "peerDependenciesMeta": {
103
- "@zkpassport/sdk": {
104
- "optional": true
105
- },
106
- "react": {
107
- "optional": true
108
- },
109
- "react-dom": {
110
- "optional": true
111
- }
112
- },
113
- "optionalDependencies": {
114
- "@zkpassport/sdk": "^0.14.0"
115
- },
116
- "dependencies": {
117
- "bs58": "^6.0.0"
118
- },
119
- "devDependencies": {
120
- "@vitest/coverage-v8": "^4.1.3",
121
- "esbuild": "^0.28.0",
122
- "eslint": "^8.56.0",
123
- "eslint-plugin-react": "^7.37.2",
124
- "prettier": "^3.2.0",
125
- "vitest": "^4.1.3"
126
- },
127
- "files": [
128
- "cli/neus.mjs",
129
- "mcp-hosts.js",
130
- "index.js",
131
- "client.js",
132
- "utils.js",
133
- "errors.js",
134
- "gates.js",
135
- "sponsor.js",
136
- "cjs/**",
137
- "widgets.cjs",
138
- "types.d.ts",
139
- "README.md",
140
- "SECURITY.md",
141
- "LICENSE",
142
- "widgets/index.js",
143
- "widgets/verify-gate/index.js",
144
- "widgets/verify-gate/dist/VerifyGate.js",
145
- "widgets/verify-gate/dist/ProofBadge.js"
146
- ]
147
- }
1
+ {
2
+ "name": "@neus/sdk",
3
+ "version": "1.1.6",
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
+ "bin": {
6
+ "neus": "cli/neus.mjs"
7
+ },
8
+ "main": "index.js",
9
+ "type": "module",
10
+ "types": "types.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./types.d.ts",
14
+ "import": "./index.js",
15
+ "require": "./cjs/index.cjs"
16
+ },
17
+ "./client": {
18
+ "types": "./types.d.ts",
19
+ "import": "./client.js",
20
+ "require": "./cjs/client.cjs"
21
+ },
22
+ "./utils": {
23
+ "import": "./utils.js",
24
+ "require": "./cjs/utils.cjs"
25
+ },
26
+ "./errors": {
27
+ "import": "./errors.js",
28
+ "require": "./cjs/errors.cjs"
29
+ },
30
+ "./gates": {
31
+ "import": "./gates.js",
32
+ "require": "./cjs/gates.cjs"
33
+ },
34
+ "./mcp-hosts": {
35
+ "import": "./mcp-hosts.js",
36
+ "require": "./cjs/mcp-hosts.cjs"
37
+ },
38
+ "./widgets": {
39
+ "types": "./types.d.ts",
40
+ "import": "./widgets/index.js",
41
+ "require": "./widgets.cjs"
42
+ },
43
+ "./widgets/verify-gate": {
44
+ "types": "./types.d.ts",
45
+ "import": "./widgets/verify-gate/index.js",
46
+ "require": "./widgets.cjs"
47
+ }
48
+ },
49
+ "sideEffects": false,
50
+ "scripts": {
51
+ "test": "npm run build:cjs && vitest run",
52
+ "test:coverage": "vitest run --coverage",
53
+ "lint": "eslint . --ignore-pattern widgets/verify-gate/dist/**",
54
+ "format": "prettier --write \"**/*.js\"",
55
+ "build": "npm run build:widgets && npm run build:cjs",
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",
58
+ "prepack": "npm run build",
59
+ "prepublishOnly": "npm run lint && npm test && npm run build"
60
+ },
61
+ "keywords": [
62
+ "neus",
63
+ "verification",
64
+ "cryptographic-proofs",
65
+ "identity",
66
+ "authentication",
67
+ "blockchain",
68
+ "cross-chain",
69
+ "web3",
70
+ "passwordless",
71
+ "universal-protocol",
72
+ "proof",
73
+ "ownership",
74
+ "sdk",
75
+ "mcp",
76
+ "model-context-protocol",
77
+ "oauth"
78
+ ],
79
+ "author": "NEUS Network",
80
+ "license": "Apache-2.0",
81
+ "repository": {
82
+ "type": "git",
83
+ "url": "git+https://github.com/neus/network.git",
84
+ "directory": "sdk"
85
+ },
86
+ "bugs": {
87
+ "url": "https://github.com/neus/network/issues"
88
+ },
89
+ "homepage": "https://neus.network",
90
+ "publishConfig": {
91
+ "access": "public",
92
+ "registry": "https://registry.npmjs.org"
93
+ },
94
+ "engines": {
95
+ "node": ">=20.0.0"
96
+ },
97
+ "peerDependencies": {
98
+ "ethers": "^6.0.0",
99
+ "react": ">=17.0.0",
100
+ "react-dom": ">=17.0.0"
101
+ },
102
+ "peerDependenciesMeta": {
103
+ "@zkpassport/sdk": {
104
+ "optional": true
105
+ },
106
+ "react": {
107
+ "optional": true
108
+ },
109
+ "react-dom": {
110
+ "optional": true
111
+ }
112
+ },
113
+ "optionalDependencies": {
114
+ "@zkpassport/sdk": "^0.14.0"
115
+ },
116
+ "dependencies": {
117
+ "bs58": "^6.0.0"
118
+ },
119
+ "devDependencies": {
120
+ "@vitest/coverage-v8": "^4.1.3",
121
+ "esbuild": "^0.28.0",
122
+ "eslint": "^8.56.0",
123
+ "eslint-plugin-react": "^7.37.2",
124
+ "prettier": "^3.2.0",
125
+ "vitest": "^4.1.3"
126
+ },
127
+ "files": [
128
+ "cli/neus.mjs",
129
+ "mcp-hosts.js",
130
+ "index.js",
131
+ "client.js",
132
+ "utils.js",
133
+ "errors.js",
134
+ "gates.js",
135
+ "sponsor.js",
136
+ "cjs/**",
137
+ "widgets.cjs",
138
+ "types.d.ts",
139
+ "README.md",
140
+ "SECURITY.md",
141
+ "LICENSE",
142
+ "widgets/index.js",
143
+ "widgets/verify-gate/index.js",
144
+ "widgets/verify-gate/dist/VerifyGate.js",
145
+ "widgets/verify-gate/dist/ProofBadge.js"
146
+ ]
147
+ }
package/types.d.ts CHANGED
@@ -51,6 +51,12 @@
51
51
 
52
52
  checkGate(params: CheckGateParams): Promise<CheckGateResult>;
53
53
 
54
+ /** Public gate snapshot (requirements, charge, schedule — never the secret reward value). */
55
+ getGate(gateId: string): Promise<PublicGateSnapshot>;
56
+
57
+ /** Post-verify reward delivery for hosted gate checkout (session or wallet-bound). */
58
+ fulfillGate(params: FulfillGateParams): Promise<GateFulfillmentResponse>;
59
+
54
60
  }
55
61
 
56
62
  export type PrivacyLevel = 'public' | 'private';
@@ -102,6 +108,8 @@
102
108
  enableIpfs?: boolean;
103
109
  storeOriginalContent?: boolean;
104
110
  targetChains?: number[];
111
+ /** Anchor the receipt on the hub registry chain. Defaults to false (receipts persist offchain). */
112
+ publishToHub?: boolean;
105
113
  publicDisplay?: boolean;
106
114
  meta?: Record<string, any>;
107
115
  verifierOptions?: Record<string, any>;
@@ -429,12 +437,102 @@
429
437
  scheme: string;
430
438
  label: string;
431
439
  amountUsd: number;
432
- methods: string[];
440
+ /** Payment methods offered to visitors: 'usdc' and/or 'stripe' (card). */
441
+ methods: Array<'usdc' | 'stripe' | string>;
442
+ /** True when the owner can receive card payouts (Stripe Connect ready). */
443
+ cardPayoutReady?: boolean;
433
444
  appliesTo: string;
445
+ /** 'verifyThenCharge' (default) or 'chargeThenVerify'. */
434
446
  executionOrder?: string;
435
447
  recipient?: string;
436
448
  };
437
449
 
450
+ /** One gate requirement row on the wire (protocol shape used by published gates). */
451
+ export interface GateMatchRowWire {
452
+ path: string;
453
+ op?: 'eq' | 'gte' | 'lte' | string;
454
+ value: string;
455
+ }
456
+
457
+ export interface GateRequirementWire {
458
+ verifierId: string;
459
+ match?: GateMatchRowWire[];
460
+ optional?: boolean;
461
+ minCount?: number;
462
+ maxAgeMs?: number;
463
+ }
464
+
465
+ /** Public snapshot returned by GET /api/v1/gates/{gateId} — never includes the secret reward value. */
466
+ export interface PublicGateSnapshot {
467
+ schemaVersion: number;
468
+ gateId: string;
469
+ name?: string;
470
+ status?: string;
471
+ version?: number;
472
+ requirements: GateRequirementWire[];
473
+ policy?: {
474
+ visibility?: string;
475
+ gateFreshnessHours?: number;
476
+ };
477
+ monetization?: {
478
+ charge?: NeusPublicGateCharge | null;
479
+ };
480
+ checkout?: {
481
+ mode?: string;
482
+ flowPlan?: {
483
+ batches?: number;
484
+ hasInteractive?: boolean;
485
+ hasBackground?: boolean;
486
+ };
487
+ description?: string;
488
+ successReturnUrl?: string;
489
+ };
490
+ marketplaceTemplate?: {
491
+ templateId: string;
492
+ label?: string;
493
+ tags?: string[];
494
+ };
495
+ schedule?: {
496
+ startsAt?: string;
497
+ endsAt?: string;
498
+ };
499
+ artifact?: {
500
+ type: string;
501
+ label?: string;
502
+ };
503
+ }
504
+
505
+ export interface FulfillGateParams {
506
+ gateId: string;
507
+ /** Verified proof receipt id for this checkout. */
508
+ qHash: string;
509
+ /** Required when no session cookie binds the wallet. */
510
+ walletAddress?: string;
511
+ /** Stripe checkout session id for paid gates (card rail). */
512
+ paymentCheckoutSessionId?: string;
513
+ /** USDC payment transaction hash for paid gates (wallet rail). */
514
+ paymentTxHash?: string;
515
+ }
516
+
517
+ export interface GateFulfillmentResult {
518
+ delivery: 'access_granted' | 'redirect' | 'download' | 'reveal' | string;
519
+ type?: string;
520
+ value?: string;
521
+ label?: string;
522
+ message?: string;
523
+ }
524
+
525
+ export interface GateFulfillmentResponse {
526
+ success: boolean;
527
+ data?: {
528
+ gateId: string;
529
+ qHash: string;
530
+ fulfillment: GateFulfillmentResult;
531
+ successReturnUrl?: string;
532
+ };
533
+ error?: any;
534
+ }
535
+
438
536
  export const NEUS_CONSTANTS: {
439
537
  HUB_CHAIN_ID: number;
440
538
  TESTNET_CHAINS: number[];
@@ -482,16 +580,36 @@
482
580
  cursor?: string;
483
581
  chain?: string;
484
582
  signatureMethod?: string;
583
+ q?: string;
584
+ qHash?: string;
585
+ verifierId?: string;
586
+ verifierIds?: string;
587
+ tags?: string;
588
+ tagPrefix?: string;
589
+ tagContains?: string;
590
+ tagPrefixesAll?: string;
591
+ status?: string;
592
+ appId?: string;
593
+ chainCoverage?: 'hub-only' | 'cross-chain';
594
+ privacyLevel?: 'public' | 'private';
595
+ includeHistory?: boolean;
596
+ includeFacets?: string;
597
+ visibility?: 'public';
598
+ isPublicRead?: boolean;
485
599
  }
486
600
 
487
601
  export interface ProofsResult {
488
602
  success: boolean;
489
603
  proofs: any[];
490
- totalCount: number;
604
+ totalCount: number | null;
491
605
  hasMore: boolean;
492
606
  nextOffset?: number | null;
493
607
  /** Keyset continuation when the API returns cursor paging (preferred over deep offsets). */
494
608
  nextCursor?: string | null;
609
+ facets?: {
610
+ tags?: string[];
611
+ truncated?: boolean;
612
+ } | null;
495
613
  }
496
614
 
497
615
  export interface GateRequirement {
@@ -499,7 +617,11 @@
499
617
  maxAgeMs?: number;
500
618
  optional?: boolean;
501
619
  minCount?: number;
502
- match?: Record<string, any>;
620
+ /**
621
+ * Either the protocol wire shape (array of { path, op, value } rows — what
622
+ * published gates store) or a flat { path: value } map for client-side checks.
623
+ */
624
+ match?: GateMatchRowWire[] | Record<string, any>;
503
625
  }
504
626
 
505
627
  export interface CheckGateParams {
@@ -577,6 +699,25 @@
577
699
  matchedTags?: string[];
578
700
  projections?: Array<Record<string, any>> | null;
579
701
  criteria?: Record<string, any>;
702
+ /**
703
+ * Per-requirement gate evaluation — present whenever `gateId` was passed.
704
+ * `allRequiredSatisfied === true` is the ONLY readiness signal for gate
705
+ * checkout; `eligible`/`matchedCount` alone are not sufficient.
706
+ */
707
+ gate?: {
708
+ gateId: string | null;
709
+ allRequiredSatisfied: boolean;
710
+ satisfiedVerifierIds: string[];
711
+ missingVerifierIds: string[];
712
+ /** verifierId → qHash map for `options.reusedVerifierProofs` on submit (requires includeQHashes=true). */
713
+ reusedVerifierProofs?: Record<string, string>;
714
+ /** Per-requirement rows (requires includeQHashes=true). */
715
+ rows?: Array<{
716
+ verifierId: string;
717
+ satisfied: boolean;
718
+ qHashes?: string[];
719
+ }>;
720
+ };
580
721
  };
581
722
  error?: any;
582
723
  }
@@ -830,6 +971,8 @@
830
971
 
831
972
  interface VerifyOptions {
832
973
  targetChains?: number[];
974
+ /** Anchor the receipt on the hub registry chain. Defaults to false (receipts persist offchain). */
975
+ publishToHub?: boolean;
833
976
  enableIpfs?: boolean;
834
977
  privacyLevel?: 'private' | 'public';
835
978
  publicDisplay?: boolean;