@svsprotocol/solana 0.1.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 (38) hide show
  1. package/LICENSE +158 -0
  2. package/README.md +365 -0
  3. package/dist/action-production-proof-evidence.js +553 -0
  4. package/dist/adapter-catalog.d.ts +29 -0
  5. package/dist/adapter-catalog.js +146 -0
  6. package/dist/adapter-core.d.ts +48 -0
  7. package/dist/adapter-core.js +249 -0
  8. package/dist/approval-signature.js +197 -0
  9. package/dist/base58.js +69 -0
  10. package/dist/bot-auth.js +50 -0
  11. package/dist/bot-certification-evidence.js +342 -0
  12. package/dist/bot-first-action-runbook.js +299 -0
  13. package/dist/bot-integration-contract.js +41 -0
  14. package/dist/certified-submit-status.js +176 -0
  15. package/dist/common.d.ts +1135 -0
  16. package/dist/elizaos.d.ts +43 -0
  17. package/dist/elizaos.js +227 -0
  18. package/dist/goat.d.ts +47 -0
  19. package/dist/goat.js +261 -0
  20. package/dist/index.d.ts +330 -0
  21. package/dist/index.js +128 -0
  22. package/dist/protocol.d.ts +205 -0
  23. package/dist/protocol.js +900 -0
  24. package/dist/receipt.js +51 -0
  25. package/dist/signed-proof-read-protection.js +495 -0
  26. package/dist/solana-agent-kit.d.ts +35 -0
  27. package/dist/solana-agent-kit.js +151 -0
  28. package/dist/svs-client.js +1232 -0
  29. package/dist/vercel-ai.d.ts +47 -0
  30. package/dist/vercel-ai.js +266 -0
  31. package/dist/verified-agent-adoption-kit.js +471 -0
  32. package/dist/verified-agent-profile.js +329 -0
  33. package/dist/verified-agent-registry-consumer.js +421 -0
  34. package/dist/verified-agent-registry.d.ts +36 -0
  35. package/dist/verified-agent-registry.js +826 -0
  36. package/dist/verified-agent-trust-score.js +335 -0
  37. package/dist/webhooks.js +834 -0
  38. package/package.json +72 -0
@@ -0,0 +1,471 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { hashObject } from "./receipt.js";
4
+ import {
5
+ VERIFIED_AGENT_PROFILE_VERSION,
6
+ hashVerifiedAgentProfile
7
+ } from "./verified-agent-profile.js";
8
+ import {
9
+ VERIFIED_AGENT_REGISTRY_VERSION,
10
+ hashVerifiedAgentRegistry
11
+ } from "./verified-agent-registry.js";
12
+
13
+ export const VERIFIED_AGENT_ADOPTION_KIT_VERSION = "svs.verified-agent-adoption-kit.v1";
14
+ export const DEFAULT_VERIFIED_AGENT_ADOPTION_KIT_DIR = "./data/security/verified-agent-adoption-kit";
15
+
16
+ export function createVerifiedAgentAdoptionKit({
17
+ profile,
18
+ registry,
19
+ registryUrl = null,
20
+ expectedRegistryHash = null,
21
+ trustManifestUrl = null,
22
+ registryIndexUrl = null,
23
+ profileUrl = null,
24
+ badgeUrl = null,
25
+ previewReadiness = null,
26
+ consumerEvidence = null,
27
+ protocolId = "svs-protocol",
28
+ generatedAt = new Date()
29
+ } = {}) {
30
+ const generatedAtIso = generatedAt instanceof Date ? generatedAt.toISOString() : new Date(generatedAt).toISOString();
31
+ const botId = profile?.agent?.botId ?? null;
32
+ const effectiveRegistryHash = expectedRegistryHash ?? registry?.registryHash ?? null;
33
+ const registryBase = registryUrl ? getUrlBase(registryUrl) : null;
34
+ const registryAgent = Array.isArray(registry?.agents)
35
+ ? registry.agents.find((agent) => agent.botId === botId) ?? null
36
+ : null;
37
+ const effectiveProfileUrl = profileUrl ??
38
+ deriveUrl(registryBase, registryAgent?.profilePath) ??
39
+ profile?.agent?.profileUrl;
40
+ const effectiveBadgeUrl = badgeUrl ??
41
+ deriveUrl(registryBase, registryAgent?.badgePath) ??
42
+ profile?.agent?.badgeUrl;
43
+ const effectiveTrustManifestUrl = trustManifestUrl ??
44
+ previewReadiness?.routes?.trustManifestUrl ??
45
+ deriveUrl(registryBase, "trust-manifest.json");
46
+ const effectiveRegistryIndexUrl = registryIndexUrl ??
47
+ previewReadiness?.routes?.indexUrl ??
48
+ deriveUrl(registryBase, "index.html");
49
+ const protocolEnv = createProtocolEnv({
50
+ registryUrl,
51
+ registryHash: effectiveRegistryHash,
52
+ botId,
53
+ profileUrl: effectiveProfileUrl,
54
+ badgeUrl: effectiveBadgeUrl,
55
+ protocolId
56
+ });
57
+ const sdkSnippet = createSdkSnippet({
58
+ registryUrl,
59
+ registryHash: effectiveRegistryHash,
60
+ botId
61
+ });
62
+ const verificationCommands = {
63
+ hosted: registryUrl && effectiveRegistryHash
64
+ ? `npm run verify:verified-agent-registry-url -- --url ${registryUrl} --expected-hash ${effectiveRegistryHash}`
65
+ : null,
66
+ local: "npm run verify:verified-agent-registry -- --file ./data/verified-agent-registry/registry.json",
67
+ preview: previewReadiness?.snippets?.checkCommand ?? null
68
+ };
69
+ const adoptionChecklist = [
70
+ "Publish or share the registry directory containing registry.json, trust-manifest.json, index.html, profile JSON, and badge SVG.",
71
+ "Give protocol teams SVS_VERIFIED_AGENT_REGISTRY_URL and SVS_VERIFIED_AGENT_REGISTRY_HASH from this kit.",
72
+ "Require protocols to run the hosted registry verifier or SDK middleware before accepting the bot.",
73
+ "Display the verified-agent badge and profile link in the bot UI or docs.",
74
+ "Regenerate this kit after certification, registry, profile, or preview-readiness evidence changes."
75
+ ];
76
+ const refreshReason = createVerifiedAgentAdoptionKitRefreshReason({
77
+ profile,
78
+ registry,
79
+ expectedRegistryHash: effectiveRegistryHash,
80
+ badgeUrl: effectiveBadgeUrl,
81
+ trustManifestUrl: effectiveTrustManifestUrl,
82
+ previewReadiness,
83
+ consumerEvidence
84
+ });
85
+ const checks = [
86
+ kitCheck("Verified-agent profile version is supported", profile?.version === VERIFIED_AGENT_PROFILE_VERSION, profile?.version ?? "missing"),
87
+ kitCheck("Verified-agent profile hash is valid", profile?.profileHash === hashVerifiedAgentProfile(profile), `declared=${profile?.profileHash ?? "missing"} computed=${hashVerifiedAgentProfile(profile) ?? "missing"}`),
88
+ kitCheck("Verified-agent profile is verified", profile?.status?.ok === true && profile?.status?.value === "verified", profile?.status?.value ?? "missing"),
89
+ kitCheck("Verified-agent registry version is supported", registry?.version === VERIFIED_AGENT_REGISTRY_VERSION, registry?.version ?? "missing"),
90
+ kitCheck("Verified-agent registry hash is valid", registry?.registryHash === hashVerifiedAgentRegistry(registry), `declared=${registry?.registryHash ?? "missing"} computed=${hashVerifiedAgentRegistry(registry) ?? "missing"}`),
91
+ kitCheck("Verified-agent registry hash matches expected hash", !expectedRegistryHash || registry?.registryHash === expectedRegistryHash, `expected=${expectedRegistryHash ?? "none"} actual=${registry?.registryHash ?? "missing"}`),
92
+ kitCheck("Verified-agent registry includes profile bot", Boolean(registryAgent), botId ?? "missing"),
93
+ kitCheck("Verified-agent registry profile hash matches profile", registryAgent?.profileHash === profile?.profileHash, `registry=${registryAgent?.profileHash ?? "missing"} profile=${profile?.profileHash ?? "missing"}`),
94
+ kitCheck("Registry URL is copyable", Boolean(registryUrl), registryUrl ?? "missing"),
95
+ kitCheck("Pinned registry hash is copyable", isSha256(effectiveRegistryHash), effectiveRegistryHash ?? "missing"),
96
+ kitCheck("Profile URL is copyable", Boolean(effectiveProfileUrl), effectiveProfileUrl ?? "missing"),
97
+ kitCheck("Badge URL is copyable", Boolean(effectiveBadgeUrl), effectiveBadgeUrl ?? "missing"),
98
+ kitCheck("Protocol env excludes secret material", !containsSecretMaterial(protocolEnv), "redacted"),
99
+ kitCheck("SDK snippet pins registry URL and hash", Boolean(registryUrl && effectiveRegistryHash && sdkSnippet.includes(registryUrl) && sdkSnippet.includes(effectiveRegistryHash)), "snippet"),
100
+ kitCheck("Preview readiness is ready when provided", !previewReadiness || previewReadiness.ok === true && previewReadiness.status === "ready", previewReadiness?.status ?? "not_provided"),
101
+ kitCheck("Consumer evidence is verified when provided", !consumerEvidence || consumerEvidence.ok === true, consumerEvidence?.status ?? "not_provided")
102
+ ];
103
+ const failedChecks = checks.filter((check) => !check.ok);
104
+ const unsigned = {
105
+ version: VERIFIED_AGENT_ADOPTION_KIT_VERSION,
106
+ ok: failedChecks.length === 0,
107
+ status: failedChecks.length === 0 ? "ready" : "failed",
108
+ generatedAt: generatedAtIso,
109
+ bot: {
110
+ botId,
111
+ name: profile?.agent?.name ?? botId,
112
+ status: profile?.status?.value ?? null,
113
+ badgeText: profile?.display?.badgeText ?? null,
114
+ certificationHash: profile?.certification?.certificationHash ?? registryAgent?.certificationHash ?? null,
115
+ recordId: profile?.certification?.recordId ?? registryAgent?.recordId ?? null,
116
+ qualityTarget: profile?.qualityTarget ?? registryAgent?.qualityTarget ?? null
117
+ },
118
+ registry: {
119
+ title: registry?.title ?? null,
120
+ registryHash: registry?.registryHash ?? null,
121
+ expectedRegistryHash: effectiveRegistryHash,
122
+ profileCount: registry?.profileCount ?? null,
123
+ verifiedAgentCount: Array.isArray(registry?.agents)
124
+ ? registry.agents.filter((agent) => agent.status === "verified" && agent.verification?.ok === true).length
125
+ : null,
126
+ profileHash: profile?.profileHash ?? null,
127
+ trustManifestHash: previewReadiness?.registry?.trustManifestHash ?? null
128
+ },
129
+ urls: {
130
+ registryUrl,
131
+ trustManifestUrl: effectiveTrustManifestUrl,
132
+ registryIndexUrl: effectiveRegistryIndexUrl,
133
+ profileUrl: effectiveProfileUrl,
134
+ badgeUrl: effectiveBadgeUrl
135
+ },
136
+ copy: {
137
+ protocolEnv,
138
+ sdkSnippet,
139
+ verificationCommands,
140
+ adoptionChecklist
141
+ },
142
+ proofs: {
143
+ previewReadinessHash: previewReadiness?.evidenceHash ?? null,
144
+ previewReadinessStatus: previewReadiness?.status ?? null,
145
+ consumerEvidenceHash: consumerEvidence?.evidenceHash ?? null,
146
+ consumerEvidenceStatus: consumerEvidence?.status ?? null
147
+ },
148
+ refreshReason,
149
+ reportSafety: {
150
+ secretsIncluded: false,
151
+ redactedFields: [
152
+ "SVS_BOT_API_KEY",
153
+ "SVS_BOT_REQUEST_SIGNING_SECRET",
154
+ "SVS_BOT_PENDING_REQUEST_SIGNING_SECRET",
155
+ "apiKey",
156
+ "requestSigningSecret",
157
+ "pendingRequestSigningSecret",
158
+ "webhookSecret",
159
+ "svs-request-signature"
160
+ ]
161
+ },
162
+ checkCount: checks.length,
163
+ passedCheckCount: checks.length - failedChecks.length,
164
+ failedCheckCount: failedChecks.length,
165
+ checks,
166
+ failedChecks,
167
+ nextAction: failedChecks.length === 0
168
+ ? {
169
+ code: "share_verified_agent_adoption_kit",
170
+ message: "Share this non-secret kit with bot teams, protocols, or auditors so they can verify the registry, profile, and badge without dashboard access."
171
+ }
172
+ : {
173
+ code: "repair_verified_agent_adoption_kit",
174
+ message: "Regenerate the verified profile and registry, provide hosted URLs, and rerun the adoption kit before sharing it."
175
+ }
176
+ };
177
+
178
+ return {
179
+ ...unsigned,
180
+ adoptionKitHash: hashVerifiedAgentAdoptionKit(unsigned)
181
+ };
182
+ }
183
+
184
+ export function hashVerifiedAgentAdoptionKit(kit) {
185
+ if (!kit || typeof kit !== "object") {
186
+ return null;
187
+ }
188
+
189
+ const { adoptionKitHash: _adoptionKitHash, ...unsigned } = kit;
190
+
191
+ return hashObject(unsigned);
192
+ }
193
+
194
+ export async function persistVerifiedAgentAdoptionKit({
195
+ outputDir = DEFAULT_VERIFIED_AGENT_ADOPTION_KIT_DIR,
196
+ ...options
197
+ } = {}) {
198
+ const kit = createVerifiedAgentAdoptionKit(options);
199
+ const jsonPath = join(outputDir, "adoption-kit.json");
200
+ const readmePath = join(outputDir, "README.md");
201
+
202
+ await mkdir(outputDir, { recursive: true });
203
+ await Promise.all([
204
+ writeFile(jsonPath, `${JSON.stringify(kit, null, 2)}\n`),
205
+ writeFile(readmePath, renderVerifiedAgentAdoptionKitReadme(kit))
206
+ ]);
207
+
208
+ return {
209
+ version: "svs.verified-agent-adoption-kit-persist-result.v1",
210
+ ok: kit.ok,
211
+ status: kit.status,
212
+ outputDir,
213
+ kitPath: jsonPath,
214
+ readmePath,
215
+ adoptionKitHash: kit.adoptionKitHash,
216
+ botId: kit.bot.botId,
217
+ registryHash: kit.registry.registryHash,
218
+ refreshReason: kit.refreshReason,
219
+ nextAction: kit.nextAction,
220
+ kit
221
+ };
222
+ }
223
+
224
+ export function createVerifiedAgentAdoptionKitRefreshReason({
225
+ profile = null,
226
+ registry = null,
227
+ expectedRegistryHash = null,
228
+ badgeUrl = null,
229
+ trustManifestUrl = null,
230
+ previewReadiness = null,
231
+ consumerEvidence = null
232
+ } = {}) {
233
+ const sourcePins = {
234
+ profileHash: profile?.profileHash ?? null,
235
+ registryHash: registry?.registryHash ?? null,
236
+ expectedRegistryHash: expectedRegistryHash ?? registry?.registryHash ?? null,
237
+ trustManifestHash: registry?.trustManifestHash ?? previewReadiness?.registry?.trustManifestHash ?? null,
238
+ badgeUrl: badgeUrl ?? profile?.agent?.badgeUrl ?? null,
239
+ trustManifestUrl,
240
+ previewReadinessHash: previewReadiness?.evidenceHash ?? null,
241
+ consumerEvidenceHash: consumerEvidence?.evidenceHash ?? null,
242
+ certificationHash: profile?.certification?.certificationHash ?? null,
243
+ recordId: profile?.certification?.recordId ?? null
244
+ };
245
+ const refreshTriggers = [
246
+ sourcePins.profileHash ? "profile hash" : null,
247
+ sourcePins.registryHash ? "registry hash" : null,
248
+ sourcePins.trustManifestHash || sourcePins.trustManifestUrl ? "trust manifest" : null,
249
+ sourcePins.badgeUrl ? "badge URL" : null,
250
+ sourcePins.previewReadinessHash ? "preview-readiness proof" : null,
251
+ sourcePins.consumerEvidenceHash ? "consumer verification proof" : null,
252
+ sourcePins.certificationHash || sourcePins.recordId ? "bot certification" : null
253
+ ].filter(Boolean);
254
+
255
+ return {
256
+ version: "svs.verified-agent-adoption-kit-refresh-reason.v1",
257
+ reason: "source_pins_current_at_generation",
258
+ summary: refreshTriggers.length
259
+ ? `Generated from current ${refreshTriggers.join(", ")}. Regenerate when any source pin changes or the export freshness window expires.`
260
+ : "Generated without complete source pins. Regenerate after profile, registry, badge, trust-manifest, preview, or consumer proof changes.",
261
+ refreshTriggers,
262
+ sourcePins,
263
+ operatorAction: "Regenerate the adoption kit after registry, profile, badge, trust-manifest, preview-readiness, consumer-proof, or certification changes before cutting a release."
264
+ };
265
+ }
266
+
267
+ export function compareVerifiedAgentAdoptionKitSourcePins({
268
+ kit = null,
269
+ profile = null,
270
+ registry = null,
271
+ previewReadiness = null,
272
+ consumerEvidence = null,
273
+ expectedRegistryHash = null
274
+ } = {}) {
275
+ const sourcePins = kit?.refreshReason?.sourcePins ?? {};
276
+ const currentPins = {
277
+ profileHash: profile?.profileHash ?? null,
278
+ registryHash: registry?.registryHash ??
279
+ previewReadiness?.registry?.registryHash ??
280
+ previewReadiness?.registryHash ??
281
+ consumerEvidence?.summary?.registryHash ??
282
+ consumerEvidence?.registryHash ??
283
+ null,
284
+ expectedRegistryHash: expectedRegistryHash ??
285
+ registry?.registryHash ??
286
+ previewReadiness?.registry?.registryHash ??
287
+ previewReadiness?.registryHash ??
288
+ consumerEvidence?.summary?.registryHash ??
289
+ consumerEvidence?.registryHash ??
290
+ null,
291
+ trustManifestHash: registry?.trustManifestHash ?? previewReadiness?.registry?.trustManifestHash ?? null,
292
+ previewReadinessHash: previewReadiness?.evidenceHash ?? null,
293
+ consumerEvidenceHash: consumerEvidence?.evidenceHash ?? null,
294
+ certificationHash: profile?.certification?.certificationHash ?? null,
295
+ recordId: profile?.certification?.recordId ?? null
296
+ };
297
+ const comparableFields = [
298
+ "profileHash",
299
+ "registryHash",
300
+ "expectedRegistryHash",
301
+ "trustManifestHash",
302
+ "previewReadinessHash",
303
+ "consumerEvidenceHash",
304
+ "certificationHash",
305
+ "recordId"
306
+ ];
307
+ const checks = comparableFields.map((field) => {
308
+ const pinned = sourcePins[field] ?? null;
309
+ const current = currentPins[field] ?? null;
310
+ const comparable = Boolean(pinned && current);
311
+
312
+ return {
313
+ field,
314
+ ok: comparable ? pinned === current : true,
315
+ comparable,
316
+ pinned,
317
+ current,
318
+ status: comparable ? pinned === current ? "matched" : "drifted" : "not_checked"
319
+ };
320
+ });
321
+ const driftedFields = checks.filter((check) => check.status === "drifted").map((check) => check.field);
322
+ const comparableFieldsChecked = checks.filter((check) => check.comparable).map((check) => check.field);
323
+ const notCheckedFields = checks.filter((check) => !check.comparable).map((check) => check.field);
324
+
325
+ return {
326
+ version: "svs.verified-agent-adoption-kit-source-pin-comparison.v1",
327
+ ok: driftedFields.length === 0,
328
+ status: driftedFields.length === 0 ? "matched" : "drifted",
329
+ sourcePins,
330
+ currentPins,
331
+ comparableFields: comparableFieldsChecked,
332
+ notCheckedFields,
333
+ driftedFields,
334
+ checks,
335
+ summary: driftedFields.length === 0
336
+ ? comparableFieldsChecked.length
337
+ ? `Source pins match current evidence for ${comparableFieldsChecked.join(", ")}.`
338
+ : "No current source evidence was available for source-pin comparison."
339
+ : `Source pin drift detected for ${driftedFields.join(", ")}. Regenerate the adoption kit before release.`
340
+ };
341
+ }
342
+
343
+ export function renderVerifiedAgentAdoptionKitReadme(kit) {
344
+ const commands = kit?.copy?.verificationCommands ?? {};
345
+ const refresh = kit?.refreshReason ?? null;
346
+
347
+ return `# SVS Verified Agent Adoption Kit
348
+
349
+ Bot: ${kit?.bot?.botId ?? "unknown"}
350
+ Status: ${kit?.status ?? "unknown"}
351
+ Registry hash: ${kit?.registry?.registryHash ?? "missing"}
352
+ Adoption kit hash: ${kit?.adoptionKitHash ?? "missing"}
353
+ Refresh reason: ${refresh?.summary ?? "not recorded"}
354
+
355
+ ## Protocol Env
356
+
357
+ \`\`\`sh
358
+ ${kit?.copy?.protocolEnv ?? ""}
359
+ \`\`\`
360
+
361
+ ## SDK Check
362
+
363
+ \`\`\`js
364
+ ${kit?.copy?.sdkSnippet ?? ""}
365
+ \`\`\`
366
+
367
+ ## Verify
368
+
369
+ \`\`\`sh
370
+ ${commands.hosted ?? commands.local ?? ""}
371
+ \`\`\`
372
+
373
+ ## Freshness and Fail-Closed Export
374
+
375
+ This kit is a portable handoff for protocols, bot teams, and auditors. It must stay current with the registry, trust manifest, agent profile, badge, and preview-readiness proof that it points to. Deployment-ready verification sets can enforce \`verifiedAgentAdoptionKitStaleAfterMs\`; when that policy is required, export and verifier checks fail closed if the embedded kit is too old or no longer matches the pinned registry/profile proof. Regenerate the kit after registry, profile, badge, trust-manifest, or preview-proof changes before cutting a release.
376
+
377
+ Refresh trigger summary: ${refresh?.summary ?? "not recorded"}
378
+
379
+ Pinned refresh inputs:
380
+
381
+ - Profile hash: ${refresh?.sourcePins?.profileHash ?? "missing"}
382
+ - Registry hash: ${refresh?.sourcePins?.registryHash ?? "missing"}
383
+ - Trust manifest hash: ${refresh?.sourcePins?.trustManifestHash ?? "missing"}
384
+ - Badge URL: ${refresh?.sourcePins?.badgeUrl ?? "missing"}
385
+ - Preview-readiness proof: ${refresh?.sourcePins?.previewReadinessHash ?? "missing"}
386
+ - Consumer verification proof: ${refresh?.sourcePins?.consumerEvidenceHash ?? "missing"}
387
+ - Bot certification: ${refresh?.sourcePins?.certificationHash ?? "missing"}
388
+
389
+ ## Links
390
+
391
+ - Registry: ${kit?.urls?.registryUrl ?? "missing"}
392
+ - Trust manifest: ${kit?.urls?.trustManifestUrl ?? "missing"}
393
+ - Profile: ${kit?.urls?.profileUrl ?? "missing"}
394
+ - Badge: ${kit?.urls?.badgeUrl ?? "missing"}
395
+
396
+ ## Checklist
397
+
398
+ ${(kit?.copy?.adoptionChecklist ?? []).map((item) => `- ${item}`).join("\n")}
399
+
400
+ ## Safety
401
+
402
+ This handoff is designed to be non-secret. It should contain public registry URLs, hashes, profile links, badge links, verifier commands, and protocol snippets only.
403
+ `;
404
+ }
405
+
406
+ function createProtocolEnv({
407
+ registryUrl,
408
+ registryHash,
409
+ botId,
410
+ profileUrl,
411
+ badgeUrl,
412
+ protocolId
413
+ }) {
414
+ return [
415
+ `SVS_PROTOCOL_ID=${protocolId}`,
416
+ `SVS_AGENT_BOT_ID=${botId ?? "REPLACE_WITH_BOT_ID"}`,
417
+ `SVS_VERIFIED_AGENT_REGISTRY_URL=${registryUrl ?? "REPLACE_WITH_REGISTRY_JSON_URL"}`,
418
+ `SVS_VERIFIED_AGENT_REGISTRY_HASH=${registryHash ?? "REPLACE_WITH_REGISTRY_HASH"}`,
419
+ `SVS_VERIFIED_AGENT_PROFILE_URL=${profileUrl ?? "REPLACE_WITH_PROFILE_JSON_URL"}`,
420
+ `SVS_VERIFIED_AGENT_BADGE_URL=${badgeUrl ?? "REPLACE_WITH_BADGE_SVG_URL"}`
421
+ ].join("\n");
422
+ }
423
+
424
+ function createSdkSnippet({ registryUrl, registryHash, botId }) {
425
+ return `import { createHostedVerifiedAgentRegistryMiddleware } from "@svsprotocol/solana/protocol";
426
+
427
+ const requireSvsAgent = createHostedVerifiedAgentRegistryMiddleware({
428
+ registryUrl: "${registryUrl ?? "REPLACE_WITH_REGISTRY_JSON_URL"}",
429
+ expectedRegistryHash: "${registryHash ?? "REPLACE_WITH_REGISTRY_HASH"}"
430
+ });
431
+
432
+ await requireSvsAgent({ botId: "${botId ?? "REPLACE_WITH_BOT_ID"}" });`;
433
+ }
434
+
435
+ function deriveUrl(baseUrl, relativePath) {
436
+ if (!baseUrl || !relativePath) {
437
+ return null;
438
+ }
439
+
440
+ try {
441
+ return new URL(relativePath, baseUrl).toString();
442
+ } catch {
443
+ return null;
444
+ }
445
+ }
446
+
447
+ function getUrlBase(url) {
448
+ try {
449
+ return new URL(".", url.endsWith("/") ? url : url).toString();
450
+ } catch {
451
+ return null;
452
+ }
453
+ }
454
+
455
+ function kitCheck(name, ok, detail = null) {
456
+ return {
457
+ name,
458
+ ok: ok === true,
459
+ detail
460
+ };
461
+ }
462
+
463
+ function isSha256(value) {
464
+ return typeof value === "string" && /^[a-f0-9]{64}$/i.test(value);
465
+ }
466
+
467
+ function containsSecretMaterial(value) {
468
+ const text = typeof value === "string" ? value : JSON.stringify(value ?? "");
469
+
470
+ return /(SVS_BOT_API_KEY|SVS_BOT_REQUEST_SIGNING_SECRET|requestSigningSecret|pendingRequestSigningSecret|webhookSecret|svs-request-signature)\s*=/i.test(text);
471
+ }