@cascade-fyi/sati-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.
package/dist/index.cjs CHANGED
@@ -3832,9 +3832,19 @@ var SATILightClientImpl = class {
3832
3832
  };
3833
3833
  }
3834
3834
  async queryAttestations(filter, deserializer) {
3835
+ const memcmpFilters = [];
3836
+ memcmpFilters.push({
3837
+ offset: BORSH_OFFSETS.SAS_SCHEMA,
3838
+ bytes: filter.sasSchema
3839
+ });
3840
+ if (filter.agentMint) memcmpFilters.push({
3841
+ offset: BORSH_OFFSETS.AGENT_MINT,
3842
+ bytes: filter.agentMint
3843
+ });
3835
3844
  const result = await this.rpc.getCompressedAccountsByOwner(this.programId, {
3836
3845
  cursor: filter.cursor,
3837
- limit: filter.limit
3846
+ limit: filter.limit,
3847
+ filters: memcmpFilters
3838
3848
  });
3839
3849
  const attestations = [];
3840
3850
  for (const account of result.items) {
@@ -3842,8 +3852,8 @@ var SATILightClientImpl = class {
3842
3852
  try {
3843
3853
  const parsed = this.parseAttestation(account, deserializer);
3844
3854
  if (!parsed) continue;
3845
- if (parsed.attestation.sasSchema !== filter.sasSchema) continue;
3846
- if (filter.agentMint && parsed.attestation.agentMint !== filter.agentMint) continue;
3855
+ if (filter.counterparty && parsed.data.counterparty !== filter.counterparty) continue;
3856
+ if (filter.outcome !== void 0 && parsed.data.outcome !== filter.outcome) continue;
3847
3857
  attestations.push(parsed);
3848
3858
  } catch {}
3849
3859
  }
@@ -4629,6 +4639,81 @@ function deserializeEncryptedPayload(bytes) {
4629
4639
  };
4630
4640
  }
4631
4641
 
4642
+ //#endregion
4643
+ //#region src/uploaders.ts
4644
+ const SATI_UPLOAD_URL = "https://sati.cascade.fyi/api/upload-metadata";
4645
+ /**
4646
+ * Create a hosted SATI metadata uploader.
4647
+ *
4648
+ * Uploads JSON to the SATI Identity Service which pins it to IPFS via Pinata.
4649
+ * No API keys needed - zero-config alternative to `createPinataUploader()`.
4650
+ *
4651
+ * @returns MetadataUploader that uploads via sati.cascade.fyi
4652
+ *
4653
+ * @example
4654
+ * ```typescript
4655
+ * const uploader = createSatiUploader();
4656
+ * const uri = await uploader.upload({ name: "MyAgent" });
4657
+ * // "ipfs://QmXyz..."
4658
+ * ```
4659
+ */
4660
+ function createSatiUploader() {
4661
+ return { async upload(data) {
4662
+ const response = await fetch(SATI_UPLOAD_URL, {
4663
+ method: "POST",
4664
+ headers: { "Content-Type": "application/json" },
4665
+ body: JSON.stringify(data)
4666
+ });
4667
+ if (!response.ok) {
4668
+ const text = await response.text();
4669
+ throw new Error(`Metadata upload failed (${response.status}): ${text}`);
4670
+ }
4671
+ return (await response.json()).uri;
4672
+ } };
4673
+ }
4674
+ /**
4675
+ * Create a Pinata IPFS uploader using the v3 Files API.
4676
+ *
4677
+ * @param jwt - Pinata API JWT token (requires `files:write` permission)
4678
+ * @returns MetadataUploader that pins JSON to public IPFS via Pinata
4679
+ *
4680
+ * @example
4681
+ * ```typescript
4682
+ * const uploader = createPinataUploader(process.env.PINATA_JWT!);
4683
+ * const uri = await uploader.upload({ name: "MyAgent" });
4684
+ * // "ipfs://QmXyz..."
4685
+ * ```
4686
+ */
4687
+ function createPinataUploader(jwt) {
4688
+ return { async upload(data) {
4689
+ const jsonStr = JSON.stringify(data, null, 2);
4690
+ const blob = new Blob([jsonStr], { type: "application/json" });
4691
+ const formData = new FormData();
4692
+ formData.append("file", blob, "registration.json");
4693
+ formData.append("network", "public");
4694
+ const response = await fetch("https://uploads.pinata.cloud/v3/files", {
4695
+ method: "POST",
4696
+ headers: { Authorization: `Bearer ${jwt}` },
4697
+ body: formData
4698
+ });
4699
+ if (!response.ok) {
4700
+ const text = await response.text();
4701
+ throw new Error(`IPFS upload failed (${response.status}): ${text}`);
4702
+ }
4703
+ const result = await response.json();
4704
+ const cid = result.data?.cid;
4705
+ if (!cid) throw new Error(`No CID returned from Pinata. Response: ${JSON.stringify(result)}`);
4706
+ try {
4707
+ const verifyResponse = await fetch(`https://gateway.pinata.cloud/ipfs/${cid}`, { signal: AbortSignal.timeout(5e3) });
4708
+ if (!verifyResponse.ok && verifyResponse.status !== 429) throw new Error(`Pinata returned CID ${cid} but content not accessible on gateway (HTTP ${verifyResponse.status})`);
4709
+ } catch (verifyError) {
4710
+ if (verifyError instanceof Error && !verifyError.message.includes("not accessible")) console.warn(`[SATI] Pinata gateway verification skipped for ${cid}: ${verifyError.message}`);
4711
+ else throw verifyError;
4712
+ }
4713
+ return `ipfs://${cid}`;
4714
+ } };
4715
+ }
4716
+
4632
4717
  //#endregion
4633
4718
  //#region src/deployed/devnet.json
4634
4719
  var config$1 = {
@@ -4691,6 +4776,221 @@ function getDeployedNetworks() {
4691
4776
  return Object.entries(configs).filter(([_, config$2]) => config$2 !== null).map(([network]) => network);
4692
4777
  }
4693
4778
 
4779
+ //#endregion
4780
+ //#region src/registration.ts
4781
+ /**
4782
+ * SATI Registration File
4783
+ *
4784
+ * Helpers for building, fetching, and working with ERC-8004 + Phantom
4785
+ * compatible registration files.
4786
+ *
4787
+ * @example
4788
+ * ```typescript
4789
+ * import {
4790
+ * buildRegistrationFile,
4791
+ * fetchRegistrationFile,
4792
+ * getImageUrl,
4793
+ * } from "@cascade-fyi/sati-sdk";
4794
+ *
4795
+ * // Build a registration file
4796
+ * const file = buildRegistrationFile({
4797
+ * name: "MyAgent",
4798
+ * description: "AI assistant",
4799
+ * image: "https://example.com/avatar.png",
4800
+ * });
4801
+ *
4802
+ * // Fetch from URI
4803
+ * const metadata = await fetchRegistrationFile(uri);
4804
+ * const imageUrl = getImageUrl(metadata);
4805
+ * ```
4806
+ */
4807
+ const PropertyFileSchema = zod.object({
4808
+ uri: zod.url(),
4809
+ type: zod.string()
4810
+ });
4811
+ const PropertiesSchema = zod.object({
4812
+ files: zod.array(PropertyFileSchema).min(1),
4813
+ category: zod.enum([
4814
+ "image",
4815
+ "video",
4816
+ "audio"
4817
+ ]).optional()
4818
+ });
4819
+ const EndpointSchema = zod.object({
4820
+ name: zod.string(),
4821
+ endpoint: zod.string(),
4822
+ version: zod.string().optional(),
4823
+ mcpTools: zod.array(zod.string()).optional(),
4824
+ mcpPrompts: zod.array(zod.string()).optional(),
4825
+ mcpResources: zod.array(zod.string()).optional(),
4826
+ a2aSkills: zod.array(zod.string()).optional(),
4827
+ skills: zod.array(zod.string()).optional(),
4828
+ domains: zod.array(zod.string()).optional()
4829
+ });
4830
+ const RegistrationEntrySchema = zod.object({
4831
+ agentId: zod.union([zod.string(), zod.number()]),
4832
+ agentRegistry: zod.string()
4833
+ });
4834
+ const TrustMechanismSchema = zod.enum([
4835
+ "reputation",
4836
+ "crypto-economic",
4837
+ "tee-attestation"
4838
+ ]);
4839
+ const RegistrationFileSchema = zod.object({
4840
+ type: zod.literal("https://eips.ethereum.org/EIPS/eip-8004#registration-v1"),
4841
+ name: zod.string().min(1),
4842
+ description: zod.string().min(1),
4843
+ image: zod.url(),
4844
+ properties: PropertiesSchema,
4845
+ external_url: zod.url().optional(),
4846
+ endpoints: zod.array(EndpointSchema).optional(),
4847
+ registrations: zod.array(RegistrationEntrySchema).optional(),
4848
+ supportedTrust: zod.array(TrustMechanismSchema).optional(),
4849
+ active: zod.boolean().optional().default(true),
4850
+ x402support: zod.boolean().optional()
4851
+ });
4852
+ const MIME_TYPES = {
4853
+ png: "image/png",
4854
+ jpg: "image/jpeg",
4855
+ jpeg: "image/jpeg",
4856
+ gif: "image/gif",
4857
+ webp: "image/webp",
4858
+ svg: "image/svg+xml"
4859
+ };
4860
+ /**
4861
+ * Infer MIME type from image URL extension.
4862
+ * Returns "image/png" as default if unrecognized.
4863
+ */
4864
+ function inferMimeType(url) {
4865
+ return MIME_TYPES[url.split(".").pop()?.toLowerCase().split("?")[0] ?? ""] ?? "image/png";
4866
+ }
4867
+ /**
4868
+ * Build a registration file from parameters.
4869
+ *
4870
+ * Automatically:
4871
+ * - Sets the ERC-8004 type identifier
4872
+ * - Generates properties.files from image URL
4873
+ * - Infers MIME type from extension
4874
+ * - Sets active to true by default
4875
+ *
4876
+ * @throws Error if required fields are missing or invalid
4877
+ */
4878
+ function buildRegistrationFile(params) {
4879
+ const mimeType = params.imageMimeType ?? inferMimeType(params.image);
4880
+ const file = {
4881
+ type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
4882
+ name: params.name,
4883
+ description: params.description,
4884
+ image: params.image,
4885
+ properties: {
4886
+ files: [{
4887
+ uri: params.image,
4888
+ type: mimeType
4889
+ }],
4890
+ category: "image"
4891
+ },
4892
+ ...params.externalUrl && { external_url: params.externalUrl },
4893
+ ...params.endpoints?.length && { endpoints: params.endpoints },
4894
+ ...params.registrations?.length && { registrations: params.registrations },
4895
+ ...params.supportedTrust?.length && { supportedTrust: params.supportedTrust },
4896
+ active: params.active ?? true,
4897
+ ...params.x402support !== void 0 && { x402support: params.x402support }
4898
+ };
4899
+ return RegistrationFileSchema.parse(file);
4900
+ }
4901
+ /**
4902
+ * Fetch and parse a registration file from URI.
4903
+ *
4904
+ * - Returns null on network errors or invalid URIs
4905
+ * - Validates structure, logs warnings for non-conforming files
4906
+ * - Never throws
4907
+ */
4908
+ async function fetchRegistrationFile(uri) {
4909
+ if (!uri) return null;
4910
+ let url = uri;
4911
+ if (uri.startsWith("ipfs://")) url = `https://ipfs.io/ipfs/${uri.slice(7)}`;
4912
+ else if (uri.startsWith("ar://")) url = `https://arweave.net/${uri.slice(5)}`;
4913
+ else if (!uri.startsWith("http://") && !uri.startsWith("https://")) return null;
4914
+ try {
4915
+ const response = await fetch(url);
4916
+ if (!response.ok) {
4917
+ console.warn(`[SATI] Failed to fetch metadata from ${url}: ${response.status}`);
4918
+ return null;
4919
+ }
4920
+ const data = await response.json();
4921
+ const result = RegistrationFileSchema.safeParse(data);
4922
+ if (!result.success) {
4923
+ console.warn(`[SATI] Registration file validation issues:`, result.error.issues);
4924
+ return data;
4925
+ }
4926
+ return result.data;
4927
+ } catch (error) {
4928
+ console.warn(`[SATI] Failed to fetch metadata from ${uri}:`, error);
4929
+ return null;
4930
+ }
4931
+ }
4932
+ /**
4933
+ * Extract image URL from a registration file.
4934
+ *
4935
+ * Prefers properties.files (Phantom format), falls back to image field.
4936
+ * Handles IPFS/Arweave URI conversion.
4937
+ */
4938
+ function getImageUrl(file) {
4939
+ if (!file) return null;
4940
+ const uri = file.properties?.files?.[0]?.uri ?? file.image;
4941
+ if (!uri) return null;
4942
+ if (uri.startsWith("ipfs://")) return `https://ipfs.io/ipfs/${uri.slice(7)}`;
4943
+ if (uri.startsWith("ar://")) return `https://arweave.net/${uri.slice(5)}`;
4944
+ if (uri.startsWith("http://") || uri.startsWith("https://")) return uri;
4945
+ return null;
4946
+ }
4947
+ /**
4948
+ * Serialize a registration file to JSON string.
4949
+ */
4950
+ function stringifyRegistrationFile(file, space = 2) {
4951
+ return JSON.stringify(file, null, space);
4952
+ }
4953
+ /** CAIP-2 chain identifier for Solana mainnet */
4954
+ const SATI_CHAIN_ID = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
4955
+ /** SATI program ID */
4956
+ const SATI_PROGRAM_ID = "satiRkxEiwZ51cv8PRu8UMzuaqeaNU9jABo6oAFMsLe";
4957
+ /**
4958
+ * Build a registrations[] entry for linking a SATI agent to an off-chain registration file.
4959
+ *
4960
+ * @param agentMint - SATI agent mint address
4961
+ * @returns RegistrationEntry for the registrations[] array
4962
+ *
4963
+ * @example
4964
+ * ```typescript
4965
+ * const entry = buildSatiRegistrationEntry("AgentMint...");
4966
+ * // { agentId: "AgentMint...", agentRegistry: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:satiR3q7..." }
4967
+ * ```
4968
+ */
4969
+ function buildSatiRegistrationEntry(agentMint) {
4970
+ return {
4971
+ agentId: agentMint,
4972
+ agentRegistry: `${SATI_CHAIN_ID}:${SATI_PROGRAM_ID}`
4973
+ };
4974
+ }
4975
+ /**
4976
+ * Check if a registration file contains a SATI registration.
4977
+ *
4978
+ * @param file - Registration file to check
4979
+ * @returns true if file contains at least one SATI registration
4980
+ */
4981
+ function hasSatiRegistration(file) {
4982
+ return file.registrations?.some((r) => typeof r.agentRegistry === "string" && r.agentRegistry.startsWith(SATI_CHAIN_ID)) ?? false;
4983
+ }
4984
+ /**
4985
+ * Find SATI agent IDs from a registration file.
4986
+ *
4987
+ * @param file - Registration file to search
4988
+ * @returns Array of SATI agent mint addresses
4989
+ */
4990
+ function getSatiAgentIds(file) {
4991
+ return file.registrations?.filter((r) => typeof r.agentRegistry === "string" && r.agentRegistry.startsWith(SATI_CHAIN_ID)).map((r) => String(r.agentId)) ?? [];
4992
+ }
4993
+
4694
4994
  //#endregion
4695
4995
  //#region src/client.ts
4696
4996
  /**
@@ -4717,6 +5017,11 @@ const WS_URLS = {
4717
5017
  devnet: "wss://api.devnet.solana.com",
4718
5018
  localnet: "ws://127.0.0.1:8900"
4719
5019
  };
5020
+ const PHOTON_URLS = {
5021
+ mainnet: "https://sati.cascade.fyi/api/photon/mainnet",
5022
+ devnet: "https://sati.cascade.fyi/api/photon/devnet",
5023
+ localnet: "http://127.0.0.1:8899"
5024
+ };
4720
5025
  /**
4721
5026
  * Convert an Address to Base58EncodedBytes for RPC memcmp filters.
4722
5027
  */
@@ -4789,7 +5094,7 @@ var Sati = class {
4789
5094
  rpc: this.rpc,
4790
5095
  rpcSubscriptions: this.rpcSubscriptions
4791
5096
  });
4792
- this.lightClient = createSATILightClient(options.photonRpcUrl ?? rpcUrl);
5097
+ this.lightClient = createSATILightClient(options.photonRpcUrl ?? PHOTON_URLS[options.network]);
4793
5098
  }
4794
5099
  /** @internal */
4795
5100
  getRpc() {
@@ -4842,6 +5147,25 @@ var Sati = class {
4842
5147
  };
4843
5148
  }
4844
5149
  /**
5150
+ * Build a registration file from params, upload it via the provided uploader,
5151
+ * and return the resulting URI.
5152
+ *
5153
+ * @example
5154
+ * ```typescript
5155
+ * import { createPinataUploader } from "@cascade-fyi/sati-sdk";
5156
+ *
5157
+ * const uploader = createPinataUploader(process.env.PINATA_JWT!);
5158
+ * const uri = await sati.uploadRegistrationFile(
5159
+ * { name: "MyAgent", description: "AI assistant", image: "https://example.com/img.png" },
5160
+ * uploader,
5161
+ * );
5162
+ * ```
5163
+ */
5164
+ async uploadRegistrationFile(params, uploader) {
5165
+ const regFile = buildRegistrationFile(params);
5166
+ return uploader.upload(regFile);
5167
+ }
5168
+ /**
4845
5169
  * Load agent identity from mint address
4846
5170
  */
4847
5171
  async loadAgent(mint) {
@@ -5892,215 +6216,6 @@ var Sati = class {
5892
6216
  }
5893
6217
  };
5894
6218
 
5895
- //#endregion
5896
- //#region src/registration.ts
5897
- /**
5898
- * SATI Registration File
5899
- *
5900
- * Helpers for building, fetching, and working with ERC-8004 + Phantom
5901
- * compatible registration files.
5902
- *
5903
- * @example
5904
- * ```typescript
5905
- * import {
5906
- * buildRegistrationFile,
5907
- * fetchRegistrationFile,
5908
- * getImageUrl,
5909
- * } from "@cascade-fyi/sati-sdk";
5910
- *
5911
- * // Build a registration file
5912
- * const file = buildRegistrationFile({
5913
- * name: "MyAgent",
5914
- * description: "AI assistant",
5915
- * image: "https://example.com/avatar.png",
5916
- * });
5917
- *
5918
- * // Fetch from URI
5919
- * const metadata = await fetchRegistrationFile(uri);
5920
- * const imageUrl = getImageUrl(metadata);
5921
- * ```
5922
- */
5923
- const PropertyFileSchema = zod.object({
5924
- uri: zod.url(),
5925
- type: zod.string()
5926
- });
5927
- const PropertiesSchema = zod.object({
5928
- files: zod.array(PropertyFileSchema).min(1),
5929
- category: zod.enum([
5930
- "image",
5931
- "video",
5932
- "audio"
5933
- ]).optional()
5934
- });
5935
- const EndpointSchema = zod.object({
5936
- name: zod.string(),
5937
- endpoint: zod.string(),
5938
- version: zod.string().optional()
5939
- });
5940
- const RegistrationEntrySchema = zod.object({
5941
- agentId: zod.union([zod.string(), zod.number()]),
5942
- agentRegistry: zod.string()
5943
- });
5944
- const TrustMechanismSchema = zod.enum([
5945
- "reputation",
5946
- "crypto-economic",
5947
- "tee-attestation"
5948
- ]);
5949
- const RegistrationFileSchema = zod.object({
5950
- type: zod.literal("https://eips.ethereum.org/EIPS/eip-8004#registration-v1"),
5951
- name: zod.string().min(1),
5952
- description: zod.string().min(1),
5953
- image: zod.url(),
5954
- properties: PropertiesSchema,
5955
- external_url: zod.url().optional(),
5956
- endpoints: zod.array(EndpointSchema).optional(),
5957
- registrations: zod.array(RegistrationEntrySchema).optional(),
5958
- supportedTrust: zod.array(TrustMechanismSchema).optional(),
5959
- active: zod.boolean().optional().default(true),
5960
- x402support: zod.boolean().optional()
5961
- });
5962
- const MIME_TYPES = {
5963
- png: "image/png",
5964
- jpg: "image/jpeg",
5965
- jpeg: "image/jpeg",
5966
- gif: "image/gif",
5967
- webp: "image/webp",
5968
- svg: "image/svg+xml"
5969
- };
5970
- /**
5971
- * Infer MIME type from image URL extension.
5972
- * Returns "image/png" as default if unrecognized.
5973
- */
5974
- function inferMimeType(url) {
5975
- return MIME_TYPES[url.split(".").pop()?.toLowerCase().split("?")[0] ?? ""] ?? "image/png";
5976
- }
5977
- /**
5978
- * Build a registration file from parameters.
5979
- *
5980
- * Automatically:
5981
- * - Sets the ERC-8004 type identifier
5982
- * - Generates properties.files from image URL
5983
- * - Infers MIME type from extension
5984
- * - Sets active to true by default
5985
- *
5986
- * @throws Error if required fields are missing or invalid
5987
- */
5988
- function buildRegistrationFile(params) {
5989
- const mimeType = params.imageMimeType ?? inferMimeType(params.image);
5990
- const file = {
5991
- type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
5992
- name: params.name,
5993
- description: params.description,
5994
- image: params.image,
5995
- properties: {
5996
- files: [{
5997
- uri: params.image,
5998
- type: mimeType
5999
- }],
6000
- category: "image"
6001
- },
6002
- ...params.externalUrl && { external_url: params.externalUrl },
6003
- ...params.endpoints?.length && { endpoints: params.endpoints },
6004
- ...params.registrations?.length && { registrations: params.registrations },
6005
- ...params.supportedTrust?.length && { supportedTrust: params.supportedTrust },
6006
- active: params.active ?? true,
6007
- ...params.x402support !== void 0 && { x402support: params.x402support }
6008
- };
6009
- return RegistrationFileSchema.parse(file);
6010
- }
6011
- /**
6012
- * Fetch and parse a registration file from URI.
6013
- *
6014
- * - Returns null on network errors or invalid URIs
6015
- * - Validates structure, logs warnings for non-conforming files
6016
- * - Never throws
6017
- */
6018
- async function fetchRegistrationFile(uri) {
6019
- if (!uri) return null;
6020
- let url = uri;
6021
- if (uri.startsWith("ipfs://")) url = `https://ipfs.io/ipfs/${uri.slice(7)}`;
6022
- else if (uri.startsWith("ar://")) url = `https://arweave.net/${uri.slice(5)}`;
6023
- else if (!uri.startsWith("http://") && !uri.startsWith("https://")) return null;
6024
- try {
6025
- const response = await fetch(url);
6026
- if (!response.ok) {
6027
- console.warn(`[SATI] Failed to fetch metadata from ${url}: ${response.status}`);
6028
- return null;
6029
- }
6030
- const data = await response.json();
6031
- const result = RegistrationFileSchema.safeParse(data);
6032
- if (!result.success) {
6033
- console.warn(`[SATI] Registration file validation issues:`, result.error.issues);
6034
- return data;
6035
- }
6036
- return result.data;
6037
- } catch (error) {
6038
- console.warn(`[SATI] Failed to fetch metadata from ${uri}:`, error);
6039
- return null;
6040
- }
6041
- }
6042
- /**
6043
- * Extract image URL from a registration file.
6044
- *
6045
- * Prefers properties.files (Phantom format), falls back to image field.
6046
- * Handles IPFS/Arweave URI conversion.
6047
- */
6048
- function getImageUrl(file) {
6049
- if (!file) return null;
6050
- const uri = file.properties?.files?.[0]?.uri ?? file.image;
6051
- if (!uri) return null;
6052
- if (uri.startsWith("ipfs://")) return `https://ipfs.io/ipfs/${uri.slice(7)}`;
6053
- if (uri.startsWith("ar://")) return `https://arweave.net/${uri.slice(5)}`;
6054
- if (uri.startsWith("http://") || uri.startsWith("https://")) return uri;
6055
- return null;
6056
- }
6057
- /**
6058
- * Serialize a registration file to JSON string.
6059
- */
6060
- function stringifyRegistrationFile(file, space = 2) {
6061
- return JSON.stringify(file, null, space);
6062
- }
6063
- /** CAIP-2 chain identifier for Solana mainnet */
6064
- const SATI_CHAIN_ID = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
6065
- /** SATI program ID */
6066
- const SATI_PROGRAM_ID = "satiRkxEiwZ51cv8PRu8UMzuaqeaNU9jABo6oAFMsLe";
6067
- /**
6068
- * Build a registrations[] entry for linking a SATI agent to an off-chain registration file.
6069
- *
6070
- * @param agentMint - SATI agent mint address
6071
- * @returns RegistrationEntry for the registrations[] array
6072
- *
6073
- * @example
6074
- * ```typescript
6075
- * const entry = buildSatiRegistrationEntry("AgentMint...");
6076
- * // { agentId: "AgentMint...", agentRegistry: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:satiR3q7..." }
6077
- * ```
6078
- */
6079
- function buildSatiRegistrationEntry(agentMint) {
6080
- return {
6081
- agentId: agentMint,
6082
- agentRegistry: `${SATI_CHAIN_ID}:${SATI_PROGRAM_ID}`
6083
- };
6084
- }
6085
- /**
6086
- * Check if a registration file contains a SATI registration.
6087
- *
6088
- * @param file - Registration file to check
6089
- * @returns true if file contains at least one SATI registration
6090
- */
6091
- function hasSatiRegistration(file) {
6092
- return file.registrations?.some((r) => typeof r.agentRegistry === "string" && r.agentRegistry.startsWith(SATI_CHAIN_ID)) ?? false;
6093
- }
6094
- /**
6095
- * Find SATI agent IDs from a registration file.
6096
- *
6097
- * @param file - Registration file to search
6098
- * @returns Array of SATI agent mint addresses
6099
- */
6100
- function getSatiAgentIds(file) {
6101
- return file.registrations?.filter((r) => typeof r.agentRegistry === "string" && r.agentRegistry.startsWith(SATI_CHAIN_ID)).map((r) => String(r.agentId)) ?? [];
6102
- }
6103
-
6104
6219
  //#endregion
6105
6220
  //#region src/errors.ts
6106
6221
  /** Base class for all SATI SDK errors */
@@ -6398,7 +6513,9 @@ exports.computeReputationNonce = computeReputationNonce;
6398
6513
  exports.createBatchEd25519Instruction = createBatchEd25519Instruction;
6399
6514
  exports.createEd25519Instruction = createEd25519Instruction;
6400
6515
  exports.createJsonContent = createJsonContent;
6516
+ exports.createPinataUploader = createPinataUploader;
6401
6517
  exports.createSATILightClient = createSATILightClient;
6518
+ exports.createSatiUploader = createSatiUploader;
6402
6519
  exports.decodeAgentIndex = decodeAgentIndex;
6403
6520
  exports.decodeRegistryConfig = decodeRegistryConfig;
6404
6521
  exports.decodeSchemaConfig = decodeSchemaConfig;