@oobe-protocol-labs/synapse-sap-sdk 0.4.2 → 0.6.0

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.
Files changed (75) hide show
  1. package/dist/cjs/constants/index.js +4 -1
  2. package/dist/cjs/constants/index.js.map +1 -1
  3. package/dist/cjs/constants/network.js +81 -0
  4. package/dist/cjs/constants/network.js.map +1 -0
  5. package/dist/cjs/index.js +36 -2
  6. package/dist/cjs/index.js.map +1 -1
  7. package/dist/cjs/registries/x402.js +8 -3
  8. package/dist/cjs/registries/x402.js.map +1 -1
  9. package/dist/cjs/types/endpoint.js +15 -0
  10. package/dist/cjs/types/endpoint.js.map +1 -0
  11. package/dist/cjs/utils/endpoint-validator.js +232 -0
  12. package/dist/cjs/utils/endpoint-validator.js.map +1 -0
  13. package/dist/cjs/utils/index.js +30 -1
  14. package/dist/cjs/utils/index.js.map +1 -1
  15. package/dist/cjs/utils/network-normalizer.js +236 -0
  16. package/dist/cjs/utils/network-normalizer.js.map +1 -0
  17. package/dist/cjs/utils/rpc-strategy.js +239 -0
  18. package/dist/cjs/utils/rpc-strategy.js.map +1 -0
  19. package/dist/cjs/utils/schemas.js +331 -0
  20. package/dist/cjs/utils/schemas.js.map +1 -0
  21. package/dist/esm/constants/index.js +2 -0
  22. package/dist/esm/constants/index.js.map +1 -1
  23. package/dist/esm/constants/network.js +78 -0
  24. package/dist/esm/constants/network.js.map +1 -0
  25. package/dist/esm/index.js +9 -1
  26. package/dist/esm/index.js.map +1 -1
  27. package/dist/esm/registries/x402.js +8 -3
  28. package/dist/esm/registries/x402.js.map +1 -1
  29. package/dist/esm/types/endpoint.js +14 -0
  30. package/dist/esm/types/endpoint.js.map +1 -0
  31. package/dist/esm/utils/endpoint-validator.js +226 -0
  32. package/dist/esm/utils/endpoint-validator.js.map +1 -0
  33. package/dist/esm/utils/index.js +5 -0
  34. package/dist/esm/utils/index.js.map +1 -1
  35. package/dist/esm/utils/network-normalizer.js +229 -0
  36. package/dist/esm/utils/network-normalizer.js.map +1 -0
  37. package/dist/esm/utils/rpc-strategy.js +231 -0
  38. package/dist/esm/utils/rpc-strategy.js.map +1 -0
  39. package/dist/esm/utils/schemas.js +320 -0
  40. package/dist/esm/utils/schemas.js.map +1 -0
  41. package/dist/types/constants/index.d.ts +2 -0
  42. package/dist/types/constants/index.d.ts.map +1 -1
  43. package/dist/types/constants/network.d.ts +81 -0
  44. package/dist/types/constants/network.d.ts.map +1 -0
  45. package/dist/types/index.d.ts +9 -2
  46. package/dist/types/index.d.ts.map +1 -1
  47. package/dist/types/plugin/schemas.d.ts +6 -6
  48. package/dist/types/registries/x402.d.ts +35 -2
  49. package/dist/types/registries/x402.d.ts.map +1 -1
  50. package/dist/types/types/endpoint.d.ts +161 -0
  51. package/dist/types/types/endpoint.d.ts.map +1 -0
  52. package/dist/types/types/index.d.ts +1 -0
  53. package/dist/types/types/index.d.ts.map +1 -1
  54. package/dist/types/utils/endpoint-validator.d.ts +110 -0
  55. package/dist/types/utils/endpoint-validator.d.ts.map +1 -0
  56. package/dist/types/utils/index.d.ts +6 -0
  57. package/dist/types/utils/index.d.ts.map +1 -1
  58. package/dist/types/utils/network-normalizer.d.ts +120 -0
  59. package/dist/types/utils/network-normalizer.d.ts.map +1 -0
  60. package/dist/types/utils/rpc-strategy.d.ts +172 -0
  61. package/dist/types/utils/rpc-strategy.d.ts.map +1 -0
  62. package/dist/types/utils/schemas.d.ts +351 -0
  63. package/dist/types/utils/schemas.d.ts.map +1 -0
  64. package/package.json +1 -1
  65. package/src/constants/index.ts +4 -0
  66. package/src/constants/network.ts +89 -0
  67. package/src/index.ts +50 -0
  68. package/src/registries/x402.ts +43 -4
  69. package/src/types/endpoint.ts +181 -0
  70. package/src/types/index.ts +9 -0
  71. package/src/utils/endpoint-validator.ts +300 -0
  72. package/src/utils/index.ts +39 -0
  73. package/src/utils/network-normalizer.ts +240 -0
  74. package/src/utils/rpc-strategy.ts +322 -0
  75. package/src/utils/schemas.ts +359 -0
@@ -0,0 +1,226 @@
1
+ /**
2
+ * @module utils/endpoint-validator
3
+ * @description Endpoint validation utilities for SAP agent discovery.
4
+ *
5
+ * Fetches advertised endpoints and verifies they respond with JSON,
6
+ * proper CORS headers, and SAP-compatible behavior. Designed to
7
+ * fail fast when an endpoint 404s, requires CSRF tokens, or
8
+ * serves HTML instead of JSON.
9
+ *
10
+ * Used by:
11
+ * - CLI `discovery validate` command
12
+ * - SDK programmatic validation before x402 calls
13
+ * - Integration test harnesses
14
+ *
15
+ * @category Utils
16
+ * @since v0.6.0
17
+ */
18
+ // ═══════════════════════════════════════════════════════════════════
19
+ // Core Validator
20
+ // ═══════════════════════════════════════════════════════════════════
21
+ /**
22
+ * @name validateEndpoint
23
+ * @description Validate a single endpoint URL for SAP compatibility.
24
+ *
25
+ * Performs the following checks:
26
+ * 1. URL is reachable (no 4xx/5xx)
27
+ * 2. Response Content-Type is JSON
28
+ * 3. CORS headers are present (if checkCors enabled)
29
+ * 4. No redirect to HTML login pages
30
+ * 5. Measures response latency
31
+ *
32
+ * @param url - The endpoint URL to validate.
33
+ * @param opts - Validation options.
34
+ * @returns An {@link EndpointValidationResult} with detailed check results.
35
+ *
36
+ * @category Utils
37
+ * @since v0.6.0
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const result = await validateEndpoint("https://api.example.com/x402");
42
+ * if (!result.reachable) console.error(result.error);
43
+ * ```
44
+ */
45
+ export async function validateEndpoint(url, opts = {}) {
46
+ const timeoutMs = opts.timeoutMs ?? 10_000;
47
+ const retries = opts.retries ?? 1;
48
+ const method = opts.method ?? "HEAD";
49
+ const warnings = [];
50
+ let lastError;
51
+ for (let attempt = 0; attempt <= retries; attempt++) {
52
+ try {
53
+ const controller = new AbortController();
54
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
55
+ const start = Date.now();
56
+ const response = await fetch(url, {
57
+ method,
58
+ signal: controller.signal,
59
+ headers: {
60
+ Accept: "application/json",
61
+ ...(opts.headers ?? {}),
62
+ },
63
+ redirect: "follow",
64
+ });
65
+ clearTimeout(timer);
66
+ const latencyMs = Date.now() - start;
67
+ const contentType = response.headers.get("content-type") ?? "";
68
+ const isJson = contentType.includes("application/json") || contentType.includes("text/json");
69
+ const hasCors = !!response.headers.get("access-control-allow-origin");
70
+ // Check for HTML responses (login pages, CSRF gates)
71
+ if (contentType.includes("text/html")) {
72
+ warnings.push("Endpoint returns HTML — may require CSRF or browser session");
73
+ }
74
+ // Check for redirect chains
75
+ if (response.redirected) {
76
+ warnings.push(`Endpoint redirected to ${response.url}`);
77
+ }
78
+ // Check for common error statuses
79
+ if (response.status === 403) {
80
+ warnings.push("403 Forbidden — may require authentication or CSRF tokens");
81
+ }
82
+ if (response.status === 404) {
83
+ warnings.push("404 Not Found — endpoint URL may be incorrect");
84
+ }
85
+ if (response.status === 405) {
86
+ warnings.push(`405 Method Not Allowed — endpoint may not accept ${method}`);
87
+ }
88
+ // Determine SAP capability
89
+ const isSapCapable = isJson &&
90
+ response.status < 400 &&
91
+ !contentType.includes("text/html");
92
+ // CORS check if requested
93
+ if (opts.checkCors && !hasCors) {
94
+ warnings.push("No CORS headers — cross-origin requests will fail");
95
+ }
96
+ return {
97
+ url,
98
+ reachable: response.status < 500,
99
+ statusCode: response.status,
100
+ latencyMs,
101
+ isJson,
102
+ hasCors,
103
+ isSapCapable,
104
+ error: response.status >= 400
105
+ ? `HTTP ${response.status}: ${response.statusText}`
106
+ : undefined,
107
+ warnings,
108
+ };
109
+ }
110
+ catch (err) {
111
+ lastError =
112
+ err instanceof Error ? err.message : String(err);
113
+ if (attempt < retries)
114
+ continue;
115
+ }
116
+ }
117
+ return {
118
+ url,
119
+ reachable: false,
120
+ statusCode: 0,
121
+ latencyMs: 0,
122
+ isJson: false,
123
+ hasCors: false,
124
+ isSapCapable: false,
125
+ error: lastError ?? "Unknown error",
126
+ warnings,
127
+ };
128
+ }
129
+ /**
130
+ * @name validateEndpointDescriptor
131
+ * @description Validate an {@link EndpointDescriptor} with context-aware checks.
132
+ *
133
+ * Uses the descriptor's method, auth requirements, and other metadata to
134
+ * perform a more targeted validation than raw URL checking.
135
+ *
136
+ * @param descriptor - The endpoint descriptor to validate.
137
+ * @param opts - Additional options.
138
+ * @returns An {@link EndpointValidationResult}.
139
+ *
140
+ * @category Utils
141
+ * @since v0.6.0
142
+ */
143
+ export async function validateEndpointDescriptor(descriptor, opts = {}) {
144
+ const headers = {
145
+ ...(opts.headers ?? {}),
146
+ ...(descriptor.requiredHeaders ?? {}),
147
+ };
148
+ // Use the descriptor's method, falling back to HEAD for safety
149
+ const method = opts.method ?? (descriptor.method === "GET" ? "GET" : "HEAD");
150
+ const result = await validateEndpoint(descriptor.url, {
151
+ ...opts,
152
+ method,
153
+ headers,
154
+ });
155
+ // Add descriptor-specific warnings
156
+ const warnings = [...result.warnings];
157
+ if (descriptor.requiresCSRF) {
158
+ warnings.push("Endpoint declares requiresCSRF — automated calls may need token management");
159
+ }
160
+ if (descriptor.requiresCookies) {
161
+ warnings.push("Endpoint declares requiresCookies — stateless calls may fail");
162
+ }
163
+ if (descriptor.requiresAuth && !descriptor.authType) {
164
+ warnings.push("Endpoint requires auth but no authType specified");
165
+ }
166
+ return { ...result, warnings };
167
+ }
168
+ /**
169
+ * @name validateHealthCheck
170
+ * @description Validate an agent's health-check endpoint.
171
+ *
172
+ * @param health - The health-check descriptor.
173
+ * @returns An {@link EndpointValidationResult}.
174
+ *
175
+ * @category Utils
176
+ * @since v0.6.0
177
+ */
178
+ export async function validateHealthCheck(health) {
179
+ const result = await validateEndpoint(health.url, {
180
+ timeoutMs: health.timeoutMs,
181
+ method: health.method ?? "GET",
182
+ });
183
+ const warnings = [...result.warnings];
184
+ if (result.reachable && result.statusCode !== health.expectedStatus) {
185
+ warnings.push(`Expected status ${health.expectedStatus}, got ${result.statusCode}`);
186
+ }
187
+ return {
188
+ ...result,
189
+ isSapCapable: result.reachable && result.statusCode === health.expectedStatus,
190
+ warnings,
191
+ };
192
+ }
193
+ /**
194
+ * @name validateAgentEndpoints
195
+ * @description Validate all endpoints for an agent (primary + health + tool overrides).
196
+ *
197
+ * @param params - Object containing the endpoints to validate.
198
+ * @param params.endpoint - Primary endpoint descriptor.
199
+ * @param params.healthCheck - Optional health-check descriptor.
200
+ * @param params.toolEndpoints - Optional array of tool-specific endpoint overrides.
201
+ * @param opts - Validation options.
202
+ * @returns A map of `label → EndpointValidationResult`.
203
+ *
204
+ * @category Utils
205
+ * @since v0.6.0
206
+ */
207
+ export async function validateAgentEndpoints(params, opts = {}) {
208
+ const results = new Map();
209
+ // Validate primary endpoint
210
+ const primary = await validateEndpointDescriptor(params.endpoint, opts);
211
+ results.set("primary", primary);
212
+ // Validate health check
213
+ if (params.healthCheck) {
214
+ const health = await validateHealthCheck(params.healthCheck);
215
+ results.set("health", health);
216
+ }
217
+ // Validate tool-specific endpoints
218
+ if (params.toolEndpoints) {
219
+ for (const { name, endpoint } of params.toolEndpoints) {
220
+ const toolResult = await validateEndpointDescriptor(endpoint, opts);
221
+ results.set(`tool:${name}`, toolResult);
222
+ }
223
+ }
224
+ return results;
225
+ }
226
+ //# sourceMappingURL=endpoint-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-validator.js","sourceRoot":"","sources":["../../../src/utils/endpoint-validator.ts"],"names":[],"mappings":"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"}
@@ -16,4 +16,9 @@
16
16
  export { sha256, hashToArray } from "./hash";
17
17
  export { assert } from "./validation";
18
18
  export { serializeAccount, serializeValue } from "./serialization";
19
+ // ── v0.6.0 Hardening utilities ─────────────────────
20
+ export { normalizeNetworkId, isNetworkEquivalent, getNetworkGenesisHash, getNetworkClusterName, isKnownNetwork, } from "./network-normalizer";
21
+ export { validateEndpoint, validateEndpointDescriptor, validateHealthCheck, validateAgentEndpoints, } from "./endpoint-validator";
22
+ export { getRpcUrl, getFallbackRpcUrl, createDualConnection, findATA, classifyAnchorError, extractAnchorErrorCode, } from "./rpc-strategy";
23
+ export { createEnvSchema, createEndpointDescriptorSchema, createHealthCheckSchema, createToolManifestEntrySchema, createAgentManifestSchema, createPreparePaymentSchema, createRegisterAgentSchema, createCallArgsSchema, validateOrThrow, } from "./schemas";
19
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEnE,uDAAuD;AACvD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,oBAAoB,EACpB,OAAO,EACP,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,eAAe,EACf,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,EACpB,eAAe,GAChB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * @module utils/network-normalizer
3
+ * @description Network identifier normalization for x402 payment headers.
4
+ *
5
+ * Solves the canonical-string mismatch between SAP clients and servers:
6
+ * some providers accept `solana:mainnet-beta` while others require
7
+ * the genesis-hash form `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`.
8
+ *
9
+ * This module provides a single source of truth for normalizing
10
+ * network identifiers so that both clients and agents canonicalize
11
+ * before comparing. Catches the Kamiyo "sap network mismatch" error
12
+ * at the SDK level.
13
+ *
14
+ * @category Utils
15
+ * @since v0.6.0
16
+ */
17
+ import { SapNetwork } from "../constants/network";
18
+ // ═══════════════════════════════════════════════════════════════════
19
+ // Canonical Mapping
20
+ // ═══════════════════════════════════════════════════════════════════
21
+ /**
22
+ * Bidirectional alias map: for every known network string, stores the
23
+ * canonical SapNetworkId it resolves to, plus all known aliases.
24
+ */
25
+ const NETWORK_ALIASES = new Map([
26
+ // ── Mainnet ───────────────────────────────
27
+ // Canonical: genesis-hash form
28
+ ["solana:mainnet-beta", SapNetwork.SOLANA_MAINNET],
29
+ ["solana:mainnet", SapNetwork.SOLANA_MAINNET],
30
+ ["mainnet-beta", SapNetwork.SOLANA_MAINNET],
31
+ ["mainnet", SapNetwork.SOLANA_MAINNET],
32
+ ["solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", SapNetwork.SOLANA_MAINNET_GENESIS],
33
+ ["5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", SapNetwork.SOLANA_MAINNET_GENESIS],
34
+ // ── Devnet ────────────────────────────────
35
+ ["solana:devnet", SapNetwork.SOLANA_DEVNET_NAMED],
36
+ ["devnet", SapNetwork.SOLANA_DEVNET_NAMED],
37
+ ["solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", SapNetwork.SOLANA_DEVNET],
38
+ ["EtWTRABZaYq6iMfeYKouRu166VU2xqa1", SapNetwork.SOLANA_DEVNET],
39
+ ]);
40
+ /**
41
+ * Mainnet equivalence set: all strings that refer to Solana mainnet-beta,
42
+ * regardless of format.
43
+ */
44
+ const MAINNET_EQUIVALENTS = new Set([
45
+ SapNetwork.SOLANA_MAINNET,
46
+ SapNetwork.SOLANA_MAINNET_GENESIS,
47
+ "solana:mainnet",
48
+ "mainnet-beta",
49
+ "mainnet",
50
+ "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
51
+ ]);
52
+ /**
53
+ * Devnet equivalence set.
54
+ */
55
+ const DEVNET_EQUIVALENTS = new Set([
56
+ SapNetwork.SOLANA_DEVNET,
57
+ SapNetwork.SOLANA_DEVNET_NAMED,
58
+ "devnet",
59
+ "EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
60
+ ]);
61
+ // ═══════════════════════════════════════════════════════════════════
62
+ // Public API
63
+ // ═══════════════════════════════════════════════════════════════════
64
+ /**
65
+ * @name normalizeNetworkId
66
+ * @description Normalize a raw network identifier string to its canonical
67
+ * {@link SapNetworkId} form.
68
+ *
69
+ * Handles:
70
+ * - Case-insensitive matching
71
+ * - Stripping whitespace
72
+ * - Resolving genesis-hash vs. cluster-name aliases
73
+ * - Unknown strings are returned as-is (passthrough)
74
+ *
75
+ * @param raw - Raw network identifier string from headers, env vars, or config.
76
+ * @returns The canonical {@link SapNetworkId}, or the trimmed input if unknown.
77
+ *
78
+ * @category Utils
79
+ * @since v0.6.0
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * import { normalizeNetworkId } from "@synapse-sap/sdk";
84
+ *
85
+ * normalizeNetworkId("solana:mainnet-beta");
86
+ * // → "solana:mainnet-beta"
87
+ *
88
+ * normalizeNetworkId("5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp");
89
+ * // → "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
90
+ *
91
+ * normalizeNetworkId(" MAINNET ");
92
+ * // → "solana:mainnet-beta"
93
+ * ```
94
+ */
95
+ export function normalizeNetworkId(raw) {
96
+ const trimmed = raw.trim();
97
+ // Exact match first
98
+ const exact = NETWORK_ALIASES.get(trimmed);
99
+ if (exact)
100
+ return exact;
101
+ // Case-insensitive lookup
102
+ const lower = trimmed.toLowerCase();
103
+ for (const [alias, canonical] of NETWORK_ALIASES) {
104
+ if (alias.toLowerCase() === lower)
105
+ return canonical;
106
+ }
107
+ // Passthrough for unknown networks (custom chains, etc.)
108
+ return trimmed;
109
+ }
110
+ /**
111
+ * @name isNetworkEquivalent
112
+ * @description Check if two network identifier strings refer to the same network,
113
+ * even if they use different formats (cluster-name vs. genesis-hash).
114
+ *
115
+ * This is the key function that prevents the Kamiyo "sap network mismatch"
116
+ * error — instead of comparing strings literally, we compare their
117
+ * canonical equivalence class.
118
+ *
119
+ * @param a - First network identifier.
120
+ * @param b - Second network identifier.
121
+ * @returns `true` if both identifiers refer to the same Solana network.
122
+ *
123
+ * @category Utils
124
+ * @since v0.6.0
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * import { isNetworkEquivalent } from "@synapse-sap/sdk";
129
+ *
130
+ * isNetworkEquivalent("solana:mainnet-beta", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp");
131
+ * // → true
132
+ *
133
+ * isNetworkEquivalent("solana:devnet", "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1");
134
+ * // → true
135
+ *
136
+ * isNetworkEquivalent("solana:mainnet-beta", "solana:devnet");
137
+ * // → false
138
+ * ```
139
+ */
140
+ export function isNetworkEquivalent(a, b) {
141
+ const normA = a.trim();
142
+ const normB = b.trim();
143
+ // Fast path: identical strings
144
+ if (normA === normB)
145
+ return true;
146
+ // Check if both are in the same equivalence set
147
+ if (MAINNET_EQUIVALENTS.has(normA) && MAINNET_EQUIVALENTS.has(normB))
148
+ return true;
149
+ if (DEVNET_EQUIVALENTS.has(normA) && DEVNET_EQUIVALENTS.has(normB))
150
+ return true;
151
+ // Case-insensitive match
152
+ const lowerA = normA.toLowerCase();
153
+ const lowerB = normB.toLowerCase();
154
+ if (lowerA === lowerB)
155
+ return true;
156
+ // Resolve both to canonical and compare
157
+ const canonA = normalizeNetworkId(normA);
158
+ const canonB = normalizeNetworkId(normB);
159
+ if (canonA === canonB)
160
+ return true;
161
+ // Final check: both resolve to the same equivalence set
162
+ if (MAINNET_EQUIVALENTS.has(canonA) && MAINNET_EQUIVALENTS.has(canonB))
163
+ return true;
164
+ if (DEVNET_EQUIVALENTS.has(canonA) && DEVNET_EQUIVALENTS.has(canonB))
165
+ return true;
166
+ return false;
167
+ }
168
+ /**
169
+ * @name getNetworkGenesisHash
170
+ * @description Get the genesis-hash form of a network identifier.
171
+ * Returns the genesis-hash variant for known networks, or the input as-is.
172
+ *
173
+ * Useful for agents that require the genesis-hash form (Kamiyo, Helius x402).
174
+ *
175
+ * @param networkId - Any network identifier.
176
+ * @returns The genesis-hash form, or the input if unknown.
177
+ *
178
+ * @category Utils
179
+ * @since v0.6.0
180
+ */
181
+ export function getNetworkGenesisHash(networkId) {
182
+ const norm = normalizeNetworkId(networkId);
183
+ if (MAINNET_EQUIVALENTS.has(networkId) || MAINNET_EQUIVALENTS.has(norm)) {
184
+ return SapNetwork.SOLANA_MAINNET_GENESIS;
185
+ }
186
+ if (DEVNET_EQUIVALENTS.has(networkId) || DEVNET_EQUIVALENTS.has(norm)) {
187
+ return SapNetwork.SOLANA_DEVNET;
188
+ }
189
+ return norm;
190
+ }
191
+ /**
192
+ * @name getNetworkClusterName
193
+ * @description Get the cluster-name form of a network identifier.
194
+ * Returns the human-readable cluster name for known networks.
195
+ *
196
+ * Useful for providers that accept cluster names (Coinbase, Phantom).
197
+ *
198
+ * @param networkId - Any network identifier.
199
+ * @returns The cluster-name form, or the input if unknown.
200
+ *
201
+ * @category Utils
202
+ * @since v0.6.0
203
+ */
204
+ export function getNetworkClusterName(networkId) {
205
+ const norm = normalizeNetworkId(networkId);
206
+ if (MAINNET_EQUIVALENTS.has(networkId) || MAINNET_EQUIVALENTS.has(norm)) {
207
+ return SapNetwork.SOLANA_MAINNET;
208
+ }
209
+ if (DEVNET_EQUIVALENTS.has(networkId) || DEVNET_EQUIVALENTS.has(norm)) {
210
+ return SapNetwork.SOLANA_DEVNET_NAMED;
211
+ }
212
+ return norm;
213
+ }
214
+ /**
215
+ * @name isKnownNetwork
216
+ * @description Check if a network identifier is recognized by the SDK.
217
+ *
218
+ * @param networkId - The network identifier to check.
219
+ * @returns `true` if the identifier maps to a known Solana network.
220
+ *
221
+ * @category Utils
222
+ * @since v0.6.0
223
+ */
224
+ export function isKnownNetwork(networkId) {
225
+ const trimmed = networkId.trim();
226
+ return MAINNET_EQUIVALENTS.has(trimmed) || DEVNET_EQUIVALENTS.has(trimmed) ||
227
+ NETWORK_ALIASES.has(trimmed);
228
+ }
229
+ //# sourceMappingURL=network-normalizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-normalizer.js","sourceRoot":"","sources":["../../../src/utils/network-normalizer.ts"],"names":[],"mappings":"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"}