@hashgraphonline/standards-agent-kit 0.2.124 → 0.2.127

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.
@@ -1,15 +1,21 @@
1
1
  import { z } from "zod";
2
2
  import { BaseInscriberQueryTool } from "./standards-agent-kit.es33.js";
3
3
  const inscribeFromUrlSchema = z.object({
4
- url: z.string().url().describe("ONLY direct file download URLs with file extensions (.pdf, .jpg, .png, .json, .zip). NEVER use for web pages, articles, or when you already have content to inscribe."),
4
+ url: z.string().url().describe(
5
+ "ONLY direct file download URLs with file extensions (.pdf, .jpg, .png, .json, .zip). NEVER use for web pages, articles, or when you already have content to inscribe."
6
+ ),
5
7
  mode: z.enum(["file", "hashinal"]).optional().describe("Inscription mode: file or hashinal NFT"),
6
8
  metadata: z.record(z.unknown()).optional().describe("Metadata to attach to the inscription"),
7
9
  tags: z.array(z.string()).optional().describe("Tags to categorize the inscription"),
8
10
  chunkSize: z.number().int().positive().optional().describe("Chunk size for large files"),
9
11
  waitForConfirmation: z.boolean().optional().describe("Whether to wait for inscription confirmation"),
10
- timeoutMs: z.number().int().positive().optional().describe("Timeout in milliseconds for inscription (default: no timeout - waits until completion)"),
12
+ timeoutMs: z.number().int().positive().optional().describe(
13
+ "Timeout in milliseconds for inscription (default: no timeout - waits until completion)"
14
+ ),
11
15
  apiKey: z.string().optional().describe("API key for inscription service"),
12
- quoteOnly: z.boolean().optional().default(false).describe("If true, returns a cost quote instead of executing the inscription")
16
+ quoteOnly: z.boolean().optional().default(false).describe(
17
+ "If true, returns a cost quote instead of executing the inscription"
18
+ )
13
19
  });
14
20
  class InscribeFromUrlTool extends BaseInscriberQueryTool {
15
21
  constructor() {
@@ -21,25 +27,35 @@ class InscribeFromUrlTool extends BaseInscriberQueryTool {
21
27
  return inscribeFromUrlSchema;
22
28
  }
23
29
  async executeQuery(params, _runManager) {
24
- console.log(`[DEBUG] InscribeFromUrlTool.executeQuery called with URL: ${params.url}`);
30
+ console.log(
31
+ `[DEBUG] InscribeFromUrlTool.executeQuery called with URL: ${params.url}`
32
+ );
25
33
  if (!params.url || params.url.trim() === "") {
26
34
  throw new Error("URL cannot be empty. Please provide a valid URL.");
27
35
  }
28
36
  try {
29
37
  const urlObj = new URL(params.url);
30
38
  if (!urlObj.protocol || !urlObj.host) {
31
- throw new Error("Invalid URL format. Please provide a complete URL with protocol (http/https).");
39
+ throw new Error(
40
+ "Invalid URL format. Please provide a complete URL with protocol (http/https)."
41
+ );
32
42
  }
33
43
  if (!["http:", "https:"].includes(urlObj.protocol)) {
34
- throw new Error("Only HTTP and HTTPS URLs are supported for inscription.");
44
+ throw new Error(
45
+ "Only HTTP and HTTPS URLs are supported for inscription."
46
+ );
35
47
  }
36
48
  } catch (error) {
37
49
  if (error instanceof Error && error.message.includes("Cannot inscribe content from")) {
38
50
  throw error;
39
51
  }
40
- throw new Error(`Invalid URL: ${params.url}. Please provide a valid URL.`);
52
+ throw new Error(
53
+ `Invalid URL: ${params.url}. Please provide a valid URL.`
54
+ );
41
55
  }
42
- console.log(`[InscribeFromUrlTool] Validating URL content before inscription...`);
56
+ console.log(
57
+ `[InscribeFromUrlTool] Validating URL content before inscription...`
58
+ );
43
59
  try {
44
60
  const controller = new AbortController();
45
61
  const timeoutId = setTimeout(() => controller.abort(), 1e4);
@@ -50,7 +66,9 @@ class InscribeFromUrlTool extends BaseInscriberQueryTool {
50
66
  });
51
67
  clearTimeout(timeoutId);
52
68
  if (!headResponse.ok) {
53
- throw new Error(`URL returned error status ${headResponse.status}: ${headResponse.statusText}. Cannot inscribe content from inaccessible URLs.`);
69
+ throw new Error(
70
+ `URL returned error status ${headResponse.status}: ${headResponse.statusText}. Cannot inscribe content from inaccessible URLs.`
71
+ );
54
72
  }
55
73
  const contentType = headResponse.headers.get("content-type") || "";
56
74
  const contentLength = headResponse.headers.get("content-length");
@@ -59,24 +77,34 @@ class InscribeFromUrlTool extends BaseInscriberQueryTool {
59
77
  "application/xhtml+xml",
60
78
  "text/xml"
61
79
  ];
62
- if (webPageContentTypes.some((type) => contentType.toLowerCase().includes(type))) {
63
- throw new Error(`URL returns HTML/web page content (Content-Type: ${contentType}). This tool only works with direct file URLs (PDFs, images, JSON, etc.). For web page content, first retrieve the content using the appropriate MCP tool or web scraper, then use inscribeFromBuffer to inscribe it.`);
80
+ if (webPageContentTypes.some(
81
+ (type) => contentType.toLowerCase().includes(type)
82
+ )) {
83
+ throw new Error(
84
+ `URL returns HTML/web page content (Content-Type: ${contentType}). This tool only works with direct file URLs (PDFs, images, JSON, etc.). For web page content, first retrieve the content using the appropriate MCP tool or web scraper, then use inscribeFromBuffer to inscribe it.`
85
+ );
64
86
  }
65
87
  if (contentLength && parseInt(contentLength) === 0) {
66
- throw new Error("URL returns empty content (Content-Length: 0). Cannot inscribe empty content.");
88
+ throw new Error(
89
+ "URL returns empty content (Content-Length: 0). Cannot inscribe empty content."
90
+ );
67
91
  }
68
92
  if (contentLength && parseInt(contentLength) < 10) {
69
- throw new Error(`URL content is too small (${contentLength} bytes). Content must be at least 10 bytes.`);
93
+ throw new Error(
94
+ `URL content is too small (${contentLength} bytes). Content must be at least 10 bytes.`
95
+ );
70
96
  }
71
97
  if (!contentType || contentType === "application/octet-stream") {
72
- console.log(`[InscribeFromUrlTool] Content-Type unclear, fetching first 1KB to verify...`);
98
+ console.log(
99
+ `[InscribeFromUrlTool] Content-Type unclear, fetching first 1KB to verify...`
100
+ );
73
101
  const getController = new AbortController();
74
102
  const getTimeoutId = setTimeout(() => getController.abort(), 5e3);
75
103
  try {
76
104
  const getResponse = await fetch(params.url, {
77
105
  signal: getController.signal,
78
106
  headers: {
79
- "Range": "bytes=0-1023"
107
+ Range: "bytes=0-1023"
80
108
  // Get first 1KB
81
109
  }
82
110
  });
@@ -84,9 +112,13 @@ class InscribeFromUrlTool extends BaseInscriberQueryTool {
84
112
  if (getResponse.ok || getResponse.status === 206) {
85
113
  const buffer = await getResponse.arrayBuffer();
86
114
  const bytes = new Uint8Array(buffer);
87
- const text = new TextDecoder("utf-8", { fatal: false }).decode(bytes.slice(0, 512));
115
+ const text = new TextDecoder("utf-8", { fatal: false }).decode(
116
+ bytes.slice(0, 512)
117
+ );
88
118
  if (text.toLowerCase().includes("<!doctype html") || text.toLowerCase().includes("<html") || text.match(/<meta\s+[^>]*>/i) || text.match(/<title>/i)) {
89
- throw new Error(`URL returns HTML content. This tool only works with direct file URLs. For web page content, first retrieve it using the appropriate tool, then use inscribeFromBuffer.`);
119
+ throw new Error(
120
+ `URL returns HTML content. This tool only works with direct file URLs. For web page content, first retrieve it using the appropriate tool, then use inscribeFromBuffer.`
121
+ );
90
122
  }
91
123
  }
92
124
  } catch (getError) {
@@ -94,10 +126,14 @@ class InscribeFromUrlTool extends BaseInscriberQueryTool {
94
126
  if (getError instanceof Error && getError.message.includes("HTML content")) {
95
127
  throw getError;
96
128
  }
97
- console.log(`[InscribeFromUrlTool] Could not perform partial GET validation: ${getError instanceof Error ? getError.message : "Unknown error"}`);
129
+ console.log(
130
+ `[InscribeFromUrlTool] Could not perform partial GET validation: ${getError instanceof Error ? getError.message : "Unknown error"}`
131
+ );
98
132
  }
99
133
  }
100
- console.log(`[InscribeFromUrlTool] URL validation passed. Content-Type: ${contentType}, Content-Length: ${contentLength || "unknown"}`);
134
+ console.log(
135
+ `[InscribeFromUrlTool] URL validation passed. Content-Type: ${contentType}, Content-Length: ${contentLength || "unknown"}`
136
+ );
101
137
  } catch (fetchError) {
102
138
  clearTimeout(timeoutId);
103
139
  throw fetchError;
@@ -105,11 +141,15 @@ class InscribeFromUrlTool extends BaseInscriberQueryTool {
105
141
  } catch (error) {
106
142
  if (error instanceof Error) {
107
143
  if (error.name === "AbortError") {
108
- console.log(`[InscribeFromUrlTool] Warning: URL validation timed out after 10 seconds. Proceeding with inscription attempt.`);
144
+ console.log(
145
+ `[InscribeFromUrlTool] Warning: URL validation timed out after 10 seconds. Proceeding with inscription attempt.`
146
+ );
109
147
  } else if (error.message.includes("URL returned error") || error.message.includes("empty content") || error.message.includes("too small") || error.message.includes("HTML")) {
110
148
  throw error;
111
149
  } else {
112
- console.log(`[InscribeFromUrlTool] Warning: Could not validate URL with HEAD request: ${error.message}. Proceeding with inscription attempt.`);
150
+ console.log(
151
+ `[InscribeFromUrlTool] Warning: Could not validate URL with HEAD request: ${error.message}. Proceeding with inscription attempt.`
152
+ );
113
153
  }
114
154
  }
115
155
  }
@@ -141,7 +181,7 @@ class InscribeFromUrlTool extends BaseInscriberQueryTool {
141
181
  contentInfo: {
142
182
  url: params.url
143
183
  },
144
- message: `Quote generated for URL: ${params.url}
184
+ message: `Estimated Quote for URL: ${params.url}
145
185
  Total cost: ${quote.totalCostHbar} HBAR`
146
186
  };
147
187
  } catch (error) {
@@ -154,7 +194,9 @@ Total cost: ${quote.totalCostHbar} HBAR`
154
194
  if (params.timeoutMs) {
155
195
  const timeoutPromise = new Promise((_, reject) => {
156
196
  setTimeout(
157
- () => reject(new Error(`Inscription timed out after ${params.timeoutMs}ms`)),
197
+ () => reject(
198
+ new Error(`Inscription timed out after ${params.timeoutMs}ms`)
199
+ ),
158
200
  params.timeoutMs
159
201
  );
160
202
  });
@@ -1 +1 @@
1
- {"version":3,"file":"standards-agent-kit.es34.js","sources":["../../src/tools/inscriber/InscribeFromUrlTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { BaseInscriberQueryTool } from './base-inscriber-tools';\nimport { InscriptionOptions } from '@hashgraphonline/standards-sdk';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\n\n/**\n * Schema for inscribing from URL\n */\nconst inscribeFromUrlSchema = z.object({\n url: z.string().url().describe('ONLY direct file download URLs with file extensions (.pdf, .jpg, .png, .json, .zip). NEVER use for web pages, articles, or when you already have content to inscribe.'),\n mode: z\n .enum(['file', 'hashinal'])\n .optional()\n .describe('Inscription mode: file or hashinal NFT'),\n metadata: z\n .record(z.unknown())\n .optional()\n .describe('Metadata to attach to the inscription'),\n tags: z\n .array(z.string())\n .optional()\n .describe('Tags to categorize the inscription'),\n chunkSize: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Chunk size for large files'),\n waitForConfirmation: z\n .boolean()\n .optional()\n .describe('Whether to wait for inscription confirmation'),\n timeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Timeout in milliseconds for inscription (default: no timeout - waits until completion)'),\n apiKey: z\n .string()\n .optional()\n .describe('API key for inscription service'),\n quoteOnly: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, returns a cost quote instead of executing the inscription'),\n});\n\n\n/**\n * Tool for inscribing content from URL\n */\nexport class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeFromUrlSchema> {\n name = 'inscribeFromUrl';\n description = 'ONLY for direct FILE DOWNLOAD URLs ending with file extensions (.pdf, .jpg, .png, .json, .zip). NEVER use for web pages, articles, or ANY HTML content - it WILL FAIL. If you have already retrieved content from any source (including MCP tools), you MUST use inscribeFromBuffer instead. This tool downloads files from URLs - it does NOT inscribe content you already have. When asked to \"inscribe it\" after retrieving content, ALWAYS use inscribeFromBuffer with the actual content. Set quoteOnly=true to get cost estimates without executing the inscription.';\n\n get specificInputSchema() {\n return inscribeFromUrlSchema;\n }\n\n protected async executeQuery(\n params: z.infer<typeof inscribeFromUrlSchema>,\n _runManager?: CallbackManagerForToolRun\n ): Promise<unknown> {\n console.log(`[DEBUG] InscribeFromUrlTool.executeQuery called with URL: ${params.url}`);\n \n if (!params.url || params.url.trim() === '') {\n throw new Error('URL cannot be empty. Please provide a valid URL.');\n }\n\n try {\n const urlObj = new URL(params.url);\n if (!urlObj.protocol || !urlObj.host) {\n throw new Error('Invalid URL format. Please provide a complete URL with protocol (http/https).');\n }\n if (!['http:', 'https:'].includes(urlObj.protocol)) {\n throw new Error('Only HTTP and HTTPS URLs are supported for inscription.');\n }\n \n } catch (error) {\n if (error instanceof Error && error.message.includes('Cannot inscribe content from')) {\n throw error;\n }\n throw new Error(`Invalid URL: ${params.url}. Please provide a valid URL.`);\n }\n\n console.log(`[InscribeFromUrlTool] Validating URL content before inscription...`);\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 10000);\n \n try {\n const headResponse = await fetch(params.url, {\n method: 'HEAD',\n signal: controller.signal,\n });\n \n clearTimeout(timeoutId);\n \n if (!headResponse.ok) {\n throw new Error(`URL returned error status ${headResponse.status}: ${headResponse.statusText}. Cannot inscribe content from inaccessible URLs.`);\n }\n\n const contentType = headResponse.headers.get('content-type') || '';\n const contentLength = headResponse.headers.get('content-length');\n \n const webPageContentTypes = [\n 'text/html',\n 'application/xhtml+xml',\n 'text/xml'\n ];\n \n if (webPageContentTypes.some(type => contentType.toLowerCase().includes(type))) {\n throw new Error(`URL returns HTML/web page content (Content-Type: ${contentType}). This tool only works with direct file URLs (PDFs, images, JSON, etc.). For web page content, first retrieve the content using the appropriate MCP tool or web scraper, then use inscribeFromBuffer to inscribe it.`);\n }\n \n if (contentLength && parseInt(contentLength) === 0) {\n throw new Error('URL returns empty content (Content-Length: 0). Cannot inscribe empty content.');\n }\n\n if (contentLength && parseInt(contentLength) < 10) {\n throw new Error(`URL content is too small (${contentLength} bytes). Content must be at least 10 bytes.`);\n }\n \n if (!contentType || contentType === 'application/octet-stream') {\n console.log(`[InscribeFromUrlTool] Content-Type unclear, fetching first 1KB to verify...`);\n \n const getController = new AbortController();\n const getTimeoutId = setTimeout(() => getController.abort(), 5000);\n \n try {\n const getResponse = await fetch(params.url, {\n signal: getController.signal,\n headers: {\n 'Range': 'bytes=0-1023' // Get first 1KB\n }\n });\n \n clearTimeout(getTimeoutId);\n \n if (getResponse.ok || getResponse.status === 206) { // 206 is partial content\n const buffer = await getResponse.arrayBuffer();\n const bytes = new Uint8Array(buffer);\n const text = new TextDecoder('utf-8', { fatal: false }).decode(bytes.slice(0, 512));\n \n if (text.toLowerCase().includes('<!doctype html') || \n text.toLowerCase().includes('<html') ||\n text.match(/<meta\\s+[^>]*>/i) ||\n text.match(/<title>/i)) {\n throw new Error(`URL returns HTML content. This tool only works with direct file URLs. For web page content, first retrieve it using the appropriate tool, then use inscribeFromBuffer.`);\n }\n }\n } catch (getError) {\n clearTimeout(getTimeoutId);\n if (getError instanceof Error && getError.message.includes('HTML content')) {\n throw getError;\n }\n console.log(`[InscribeFromUrlTool] Could not perform partial GET validation: ${getError instanceof Error ? getError.message : 'Unknown error'}`);\n }\n }\n\n console.log(`[InscribeFromUrlTool] URL validation passed. Content-Type: ${contentType}, Content-Length: ${contentLength || 'unknown'}`);\n } catch (fetchError) {\n clearTimeout(timeoutId);\n throw fetchError;\n }\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n console.log(`[InscribeFromUrlTool] Warning: URL validation timed out after 10 seconds. Proceeding with inscription attempt.`);\n } else if (error.message.includes('URL returned error') || error.message.includes('empty content') || error.message.includes('too small') || error.message.includes('HTML')) {\n throw error;\n } else {\n console.log(`[InscribeFromUrlTool] Warning: Could not validate URL with HEAD request: ${error.message}. Proceeding with inscription attempt.`);\n }\n }\n }\n\n const options: InscriptionOptions = {\n mode: params.mode,\n metadata: params.metadata,\n tags: params.tags,\n chunkSize: params.chunkSize,\n waitForConfirmation: params.quoteOnly ? false : (params.waitForConfirmation ?? true),\n waitMaxAttempts: 10,\n waitIntervalMs: 3000,\n apiKey: params.apiKey,\n network: this.inscriberBuilder['hederaKit'].client.network.toString().includes('mainnet') ? 'mainnet' : 'testnet',\n quoteOnly: params.quoteOnly,\n };\n\n if (params.quoteOnly) {\n try {\n const quote = await this.generateInscriptionQuote(\n { type: 'url', url: params.url },\n options\n );\n \n return {\n success: true,\n quote: {\n totalCostHbar: quote.totalCostHbar,\n validUntil: quote.validUntil,\n breakdown: quote.breakdown,\n },\n contentInfo: {\n url: params.url,\n },\n message: `Quote generated for URL: ${params.url}\\nTotal cost: ${quote.totalCostHbar} HBAR`,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to generate inscription quote';\n throw new Error(`Quote generation failed: ${errorMessage}`);\n }\n }\n\n try {\n let result: Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>;\n \n if (params.timeoutMs) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(\n () => reject(new Error(`Inscription timed out after ${params.timeoutMs}ms`)),\n params.timeoutMs\n );\n });\n\n result = await Promise.race([\n this.inscriberBuilder.inscribe(\n { type: 'url', url: params.url },\n options\n ),\n timeoutPromise\n ]);\n } else {\n result = await this.inscriberBuilder.inscribe(\n { type: 'url', url: params.url },\n options\n );\n }\n\n if (result.confirmed && !result.quote) {\n const topicId = result.inscription?.topic_id || (result.result as any).topicId;\n const network = options.network || 'testnet';\n const cdnUrl = topicId ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}` : null;\n return `Successfully inscribed and confirmed content on the Hedera network!\\n\\nTransaction ID: ${(result.result as any).transactionId}\\nTopic ID: ${topicId || 'N/A'}${cdnUrl ? `\\nView inscription: ${cdnUrl}` : ''}\\n\\nThe inscription is now available.`;\n } else if (!result.quote && !result.confirmed) {\n return `Successfully submitted inscription to the Hedera network!\\n\\nTransaction ID: ${(result.result as any).transactionId}\\n\\nThe inscription is processing and will be confirmed shortly.`;\n } else {\n return 'Inscription operation completed.';\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to inscribe from URL';\n throw new Error(`Inscription failed: ${errorMessage}`);\n }\n }\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"standards-agent-kit.es34.js","sources":["../../src/tools/inscriber/InscribeFromUrlTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { BaseInscriberQueryTool } from './base-inscriber-tools';\nimport { InscriptionOptions } from '@hashgraphonline/standards-sdk';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\n\n/**\n * Schema for inscribing from URL\n */\nconst inscribeFromUrlSchema = z.object({\n url: z\n .string()\n .url()\n .describe(\n 'ONLY direct file download URLs with file extensions (.pdf, .jpg, .png, .json, .zip). NEVER use for web pages, articles, or when you already have content to inscribe.'\n ),\n mode: z\n .enum(['file', 'hashinal'])\n .optional()\n .describe('Inscription mode: file or hashinal NFT'),\n metadata: z\n .record(z.unknown())\n .optional()\n .describe('Metadata to attach to the inscription'),\n tags: z\n .array(z.string())\n .optional()\n .describe('Tags to categorize the inscription'),\n chunkSize: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Chunk size for large files'),\n waitForConfirmation: z\n .boolean()\n .optional()\n .describe('Whether to wait for inscription confirmation'),\n timeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Timeout in milliseconds for inscription (default: no timeout - waits until completion)'\n ),\n apiKey: z.string().optional().describe('API key for inscription service'),\n quoteOnly: z\n .boolean()\n .optional()\n .default(false)\n .describe(\n 'If true, returns a cost quote instead of executing the inscription'\n ),\n});\n\n/**\n * Tool for inscribing content from URL\n */\nexport class InscribeFromUrlTool extends BaseInscriberQueryTool<\n typeof inscribeFromUrlSchema\n> {\n name = 'inscribeFromUrl';\n description =\n 'ONLY for direct FILE DOWNLOAD URLs ending with file extensions (.pdf, .jpg, .png, .json, .zip). NEVER use for web pages, articles, or ANY HTML content - it WILL FAIL. If you have already retrieved content from any source (including MCP tools), you MUST use inscribeFromBuffer instead. This tool downloads files from URLs - it does NOT inscribe content you already have. When asked to \"inscribe it\" after retrieving content, ALWAYS use inscribeFromBuffer with the actual content. Set quoteOnly=true to get cost estimates without executing the inscription.';\n\n get specificInputSchema() {\n return inscribeFromUrlSchema;\n }\n\n protected async executeQuery(\n params: z.infer<typeof inscribeFromUrlSchema>,\n _runManager?: CallbackManagerForToolRun\n ): Promise<unknown> {\n console.log(\n `[DEBUG] InscribeFromUrlTool.executeQuery called with URL: ${params.url}`\n );\n\n if (!params.url || params.url.trim() === '') {\n throw new Error('URL cannot be empty. Please provide a valid URL.');\n }\n\n try {\n const urlObj = new URL(params.url);\n if (!urlObj.protocol || !urlObj.host) {\n throw new Error(\n 'Invalid URL format. Please provide a complete URL with protocol (http/https).'\n );\n }\n if (!['http:', 'https:'].includes(urlObj.protocol)) {\n throw new Error(\n 'Only HTTP and HTTPS URLs are supported for inscription.'\n );\n }\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('Cannot inscribe content from')\n ) {\n throw error;\n }\n throw new Error(\n `Invalid URL: ${params.url}. Please provide a valid URL.`\n );\n }\n\n console.log(\n `[InscribeFromUrlTool] Validating URL content before inscription...`\n );\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 10000);\n\n try {\n const headResponse = await fetch(params.url, {\n method: 'HEAD',\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!headResponse.ok) {\n throw new Error(\n `URL returned error status ${headResponse.status}: ${headResponse.statusText}. Cannot inscribe content from inaccessible URLs.`\n );\n }\n\n const contentType = headResponse.headers.get('content-type') || '';\n const contentLength = headResponse.headers.get('content-length');\n\n const webPageContentTypes = [\n 'text/html',\n 'application/xhtml+xml',\n 'text/xml',\n ];\n\n if (\n webPageContentTypes.some((type) =>\n contentType.toLowerCase().includes(type)\n )\n ) {\n throw new Error(\n `URL returns HTML/web page content (Content-Type: ${contentType}). This tool only works with direct file URLs (PDFs, images, JSON, etc.). For web page content, first retrieve the content using the appropriate MCP tool or web scraper, then use inscribeFromBuffer to inscribe it.`\n );\n }\n\n if (contentLength && parseInt(contentLength) === 0) {\n throw new Error(\n 'URL returns empty content (Content-Length: 0). Cannot inscribe empty content.'\n );\n }\n\n if (contentLength && parseInt(contentLength) < 10) {\n throw new Error(\n `URL content is too small (${contentLength} bytes). Content must be at least 10 bytes.`\n );\n }\n\n if (!contentType || contentType === 'application/octet-stream') {\n console.log(\n `[InscribeFromUrlTool] Content-Type unclear, fetching first 1KB to verify...`\n );\n\n const getController = new AbortController();\n const getTimeoutId = setTimeout(() => getController.abort(), 5000);\n\n try {\n const getResponse = await fetch(params.url, {\n signal: getController.signal,\n headers: {\n Range: 'bytes=0-1023', // Get first 1KB\n },\n });\n\n clearTimeout(getTimeoutId);\n\n if (getResponse.ok || getResponse.status === 206) {\n // 206 is partial content\n const buffer = await getResponse.arrayBuffer();\n const bytes = new Uint8Array(buffer);\n const text = new TextDecoder('utf-8', { fatal: false }).decode(\n bytes.slice(0, 512)\n );\n\n if (\n text.toLowerCase().includes('<!doctype html') ||\n text.toLowerCase().includes('<html') ||\n text.match(/<meta\\s+[^>]*>/i) ||\n text.match(/<title>/i)\n ) {\n throw new Error(\n `URL returns HTML content. This tool only works with direct file URLs. For web page content, first retrieve it using the appropriate tool, then use inscribeFromBuffer.`\n );\n }\n }\n } catch (getError) {\n clearTimeout(getTimeoutId);\n if (\n getError instanceof Error &&\n getError.message.includes('HTML content')\n ) {\n throw getError;\n }\n console.log(\n `[InscribeFromUrlTool] Could not perform partial GET validation: ${\n getError instanceof Error ? getError.message : 'Unknown error'\n }`\n );\n }\n }\n\n console.log(\n `[InscribeFromUrlTool] URL validation passed. Content-Type: ${contentType}, Content-Length: ${\n contentLength || 'unknown'\n }`\n );\n } catch (fetchError) {\n clearTimeout(timeoutId);\n throw fetchError;\n }\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n console.log(\n `[InscribeFromUrlTool] Warning: URL validation timed out after 10 seconds. Proceeding with inscription attempt.`\n );\n } else if (\n error.message.includes('URL returned error') ||\n error.message.includes('empty content') ||\n error.message.includes('too small') ||\n error.message.includes('HTML')\n ) {\n throw error;\n } else {\n console.log(\n `[InscribeFromUrlTool] Warning: Could not validate URL with HEAD request: ${error.message}. Proceeding with inscription attempt.`\n );\n }\n }\n }\n\n const options: InscriptionOptions = {\n mode: params.mode,\n metadata: params.metadata,\n tags: params.tags,\n chunkSize: params.chunkSize,\n waitForConfirmation: params.quoteOnly\n ? false\n : params.waitForConfirmation ?? true,\n waitMaxAttempts: 10,\n waitIntervalMs: 3000,\n apiKey: params.apiKey,\n network: this.inscriberBuilder['hederaKit'].client.network\n .toString()\n .includes('mainnet')\n ? 'mainnet'\n : 'testnet',\n quoteOnly: params.quoteOnly,\n };\n\n if (params.quoteOnly) {\n try {\n const quote = await this.generateInscriptionQuote(\n { type: 'url', url: params.url },\n options\n );\n\n return {\n success: true,\n quote: {\n totalCostHbar: quote.totalCostHbar,\n validUntil: quote.validUntil,\n breakdown: quote.breakdown,\n },\n contentInfo: {\n url: params.url,\n },\n message: `Estimated Quote for URL: ${params.url}\\nTotal cost: ${quote.totalCostHbar} HBAR`,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : 'Failed to generate inscription quote';\n throw new Error(`Quote generation failed: ${errorMessage}`);\n }\n }\n\n try {\n let result: Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>;\n\n if (params.timeoutMs) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(\n () =>\n reject(\n new Error(`Inscription timed out after ${params.timeoutMs}ms`)\n ),\n params.timeoutMs\n );\n });\n\n result = await Promise.race([\n this.inscriberBuilder.inscribe(\n { type: 'url', url: params.url },\n options\n ),\n timeoutPromise,\n ]);\n } else {\n result = await this.inscriberBuilder.inscribe(\n { type: 'url', url: params.url },\n options\n );\n }\n\n if (result.confirmed && !result.quote) {\n const topicId =\n result.inscription?.topic_id || (result.result as any).topicId;\n const network = options.network || 'testnet';\n const cdnUrl = topicId\n ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}`\n : null;\n return `Successfully inscribed and confirmed content on the Hedera network!\\n\\nTransaction ID: ${\n (result.result as any).transactionId\n }\\nTopic ID: ${topicId || 'N/A'}${\n cdnUrl ? `\\nView inscription: ${cdnUrl}` : ''\n }\\n\\nThe inscription is now available.`;\n } else if (!result.quote && !result.confirmed) {\n return `Successfully submitted inscription to the Hedera network!\\n\\nTransaction ID: ${\n (result.result as any).transactionId\n }\\n\\nThe inscription is processing and will be confirmed shortly.`;\n } else {\n return 'Inscription operation completed.';\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to inscribe from URL';\n throw new Error(`Inscription failed: ${errorMessage}`);\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -131,7 +131,7 @@ class InscribeFromFileTool extends BaseInscriberQueryTool {
131
131
  sizeBytes: fileContent.length,
132
132
  filePath: params.filePath
133
133
  },
134
- message: `Quote generated for file: ${fileName} (${(fileContent.length / 1024).toFixed(2)} KB)
134
+ message: `Estimated Quote for file: ${fileName} (${(fileContent.length / 1024).toFixed(2)} KB)
135
135
  Total cost: ${quote.totalCostHbar} HBAR`
136
136
  };
137
137
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"standards-agent-kit.es35.js","sources":["../../src/tools/inscriber/InscribeFromFileTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { BaseInscriberQueryTool } from './base-inscriber-tools';\nimport { InscriptionOptions } from '@hashgraphonline/standards-sdk';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\n/**\n * Schema for inscribing from file\n */\nconst inscribeFromFileSchema = z.object({\n filePath: z\n .string()\n .min(1, 'File path cannot be empty')\n .describe(\n 'The file path of the content to inscribe. Must point to a valid, non-empty file.'\n ),\n mode: z\n .enum(['file', 'hashinal'])\n .optional()\n .describe('Inscription mode: file or hashinal NFT'),\n metadata: z\n .record(z.unknown())\n .optional()\n .describe('Metadata to attach to the inscription'),\n tags: z\n .array(z.string())\n .optional()\n .describe('Tags to categorize the inscription'),\n chunkSize: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Chunk size for large files'),\n waitForConfirmation: z\n .boolean()\n .optional()\n .describe('Whether to wait for inscription confirmation'),\n timeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Timeout in milliseconds for inscription (default: no timeout)'),\n apiKey: z.string().optional().describe('API key for inscription service'),\n quoteOnly: z\n .boolean()\n .optional()\n .default(false)\n .describe(\n 'If true, returns a cost quote instead of executing the inscription'\n ),\n});\n\n/**\n * Tool for inscribing content from file\n */\nexport class InscribeFromFileTool extends BaseInscriberQueryTool<\n typeof inscribeFromFileSchema\n> {\n name = 'inscribeFromFile';\n description =\n 'Inscribe content from a local file to the Hedera network using a file path. IMPORTANT: Only use this tool when you have a valid file path to actual content. The file must exist and contain meaningful data (minimum 10 bytes). For files accessed through MCP filesystem tools, consider reading the file content first and using inscribeFromBuffer instead. Set quoteOnly=true to get cost estimates without executing the inscription.';\n\n get specificInputSchema(): typeof inscribeFromFileSchema {\n return inscribeFromFileSchema;\n }\n\n protected async executeQuery(\n params: z.infer<typeof inscribeFromFileSchema>,\n _runManager?: CallbackManagerForToolRun\n ): Promise<unknown> {\n console.log(\n `[DEBUG] InscribeFromFileTool.executeQuery called with: ${params.filePath}`\n );\n\n let fileContent: Buffer;\n try {\n console.log(`[DEBUG] Checking file: ${params.filePath}`);\n console.log(`[DEBUG] Current working directory: ${process.cwd()}`);\n\n const stats = await fs.stat(params.filePath);\n if (!stats.isFile()) {\n throw new Error(`Path \"${params.filePath}\" is not a file`);\n }\n\n console.log(`[DEBUG] File size: ${stats.size} bytes`);\n\n if (stats.size === 0) {\n throw new Error(\n `File \"${params.filePath}\" is empty (0 bytes). Cannot inscribe empty files.`\n );\n }\n\n if (stats.size < 10) {\n throw new Error(\n `File \"${params.filePath}\" is too small (${stats.size} bytes). Files must contain at least 10 bytes of meaningful content.`\n );\n }\n\n if (stats.size > 100 * 1024 * 1024) {\n console.log(\n `[InscribeFromFileTool] WARNING: Large file detected (${(\n stats.size /\n (1024 * 1024)\n ).toFixed(2)} MB)`\n );\n }\n\n this.logger?.info('Reading file content...');\n fileContent = await fs.readFile(params.filePath);\n this.logger?.info(`Read ${fileContent.length} bytes from file`);\n\n if (!fileContent || fileContent.length === 0) {\n throw new Error(\n `File \"${params.filePath}\" has no content after reading. Cannot inscribe empty files.`\n );\n }\n\n if (fileContent.length < 10) {\n throw new Error(\n `File \"${params.filePath}\" content is too small (${fileContent.length} bytes). Files must contain at least 10 bytes of meaningful content.`\n );\n }\n\n const fileName = path.basename(params.filePath);\n const mimeType = this.getMimeType(fileName);\n if (mimeType.startsWith('text/') || mimeType === 'application/json') {\n const textContent = fileContent.toString(\n 'utf8',\n 0,\n Math.min(fileContent.length, 1000)\n );\n if (textContent.trim() === '') {\n throw new Error(\n `File \"${params.filePath}\" contains only whitespace or empty content. Cannot inscribe meaningless data.`\n );\n }\n }\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n throw new Error(`File not found: \"${params.filePath}\"`);\n }\n throw error;\n }\n throw new Error(`Failed to read file: ${error}`);\n }\n\n const base64Data = fileContent.toString('base64');\n this.logger?.info(`Converted to base64: ${base64Data.length} characters`);\n\n const fileName = path.basename(params.filePath);\n const mimeType = this.getMimeType(fileName);\n this.logger?.info(`File: ${fileName}, MIME type: ${mimeType}`);\n\n const options: InscriptionOptions = {\n mode: params.mode,\n metadata: params.metadata,\n tags: params.tags,\n chunkSize: params.chunkSize,\n waitForConfirmation: params.quoteOnly\n ? false\n : params.waitForConfirmation ?? true,\n waitMaxAttempts: 10,\n waitIntervalMs: 3000,\n apiKey: params.apiKey,\n network: this.inscriberBuilder['hederaKit'].client.network\n .toString()\n .includes('mainnet')\n ? 'mainnet'\n : 'testnet',\n quoteOnly: params.quoteOnly,\n };\n\n if (params.quoteOnly) {\n try {\n const quote = await this.generateInscriptionQuote(\n {\n type: 'buffer',\n buffer: Buffer.from(base64Data, 'base64'),\n fileName,\n mimeType,\n },\n options\n );\n\n return {\n success: true,\n quote: {\n totalCostHbar: quote.totalCostHbar,\n validUntil: quote.validUntil,\n breakdown: quote.breakdown,\n },\n contentInfo: {\n fileName,\n mimeType,\n sizeBytes: fileContent.length,\n filePath: params.filePath,\n },\n message: `Quote generated for file: ${fileName} (${(\n fileContent.length / 1024\n ).toFixed(2)} KB)\\nTotal cost: ${\n quote.totalCostHbar\n } HBAR`,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : 'Failed to generate inscription quote';\n throw new Error(`Quote generation failed: ${errorMessage}`);\n }\n }\n\n try {\n let result: unknown;\n\n if (params.timeoutMs) {\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(\n () =>\n reject(\n new Error(`Inscription timed out after ${params.timeoutMs}ms`)\n ),\n params.timeoutMs\n );\n });\n\n result = await Promise.race([\n this.inscriberBuilder.inscribe(\n {\n type: 'buffer',\n buffer: Buffer.from(base64Data, 'base64'),\n fileName,\n mimeType,\n },\n options\n ),\n timeoutPromise,\n ]);\n } else {\n result = await this.inscriberBuilder.inscribe(\n {\n type: 'buffer',\n buffer: Buffer.from(base64Data, 'base64'),\n fileName,\n mimeType,\n },\n options\n );\n }\n\n const inscriptionResult = result as any;\n if (inscriptionResult.confirmed && !inscriptionResult.quote) {\n const topicId =\n inscriptionResult.inscription?.topic_id ||\n inscriptionResult.result.topicId;\n const network = options.network || 'testnet';\n const cdnUrl = topicId\n ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}`\n : null;\n return `Successfully inscribed and confirmed content on the Hedera network!\\n\\nTransaction ID: ${\n inscriptionResult.result.transactionId\n }\\nTopic ID: ${topicId || 'N/A'}${\n cdnUrl ? `\\nView inscription: ${cdnUrl}` : ''\n }\\n\\nThe inscription is now available.`;\n } else if (!inscriptionResult.quote && !inscriptionResult.confirmed) {\n return `Successfully submitted inscription to the Hedera network!\\n\\nTransaction ID: ${inscriptionResult.result.transactionId}\\n\\nThe inscription is processing and will be confirmed shortly.`;\n } else {\n return 'Inscription operation completed.';\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to inscribe from file';\n throw new Error(`Inscription failed: ${errorMessage}`);\n }\n }\n\n private getMimeType(fileName: string): string {\n const ext = path.extname(fileName).toLowerCase();\n const mimeTypes: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.svg': 'image/svg+xml',\n '.pdf': 'application/pdf',\n '.json': 'application/json',\n '.txt': 'text/plain',\n '.html': 'text/html',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.ts': 'application/typescript',\n '.mp4': 'video/mp4',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.zip': 'application/zip',\n };\n return mimeTypes[ext] || 'application/octet-stream';\n }\n}\n"],"names":["fileName","mimeType"],"mappings":"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"}
1
+ {"version":3,"file":"standards-agent-kit.es35.js","sources":["../../src/tools/inscriber/InscribeFromFileTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { BaseInscriberQueryTool } from './base-inscriber-tools';\nimport { InscriptionOptions } from '@hashgraphonline/standards-sdk';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\n/**\n * Schema for inscribing from file\n */\nconst inscribeFromFileSchema = z.object({\n filePath: z\n .string()\n .min(1, 'File path cannot be empty')\n .describe(\n 'The file path of the content to inscribe. Must point to a valid, non-empty file.'\n ),\n mode: z\n .enum(['file', 'hashinal'])\n .optional()\n .describe('Inscription mode: file or hashinal NFT'),\n metadata: z\n .record(z.unknown())\n .optional()\n .describe('Metadata to attach to the inscription'),\n tags: z\n .array(z.string())\n .optional()\n .describe('Tags to categorize the inscription'),\n chunkSize: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Chunk size for large files'),\n waitForConfirmation: z\n .boolean()\n .optional()\n .describe('Whether to wait for inscription confirmation'),\n timeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Timeout in milliseconds for inscription (default: no timeout)'),\n apiKey: z.string().optional().describe('API key for inscription service'),\n quoteOnly: z\n .boolean()\n .optional()\n .default(false)\n .describe(\n 'If true, returns a cost quote instead of executing the inscription'\n ),\n});\n\n/**\n * Tool for inscribing content from file\n */\nexport class InscribeFromFileTool extends BaseInscriberQueryTool<\n typeof inscribeFromFileSchema\n> {\n name = 'inscribeFromFile';\n description =\n 'Inscribe content from a local file to the Hedera network using a file path. IMPORTANT: Only use this tool when you have a valid file path to actual content. The file must exist and contain meaningful data (minimum 10 bytes). For files accessed through MCP filesystem tools, consider reading the file content first and using inscribeFromBuffer instead. Set quoteOnly=true to get cost estimates without executing the inscription.';\n\n get specificInputSchema(): typeof inscribeFromFileSchema {\n return inscribeFromFileSchema;\n }\n\n protected async executeQuery(\n params: z.infer<typeof inscribeFromFileSchema>,\n _runManager?: CallbackManagerForToolRun\n ): Promise<unknown> {\n console.log(\n `[DEBUG] InscribeFromFileTool.executeQuery called with: ${params.filePath}`\n );\n\n let fileContent: Buffer;\n try {\n console.log(`[DEBUG] Checking file: ${params.filePath}`);\n console.log(`[DEBUG] Current working directory: ${process.cwd()}`);\n\n const stats = await fs.stat(params.filePath);\n if (!stats.isFile()) {\n throw new Error(`Path \"${params.filePath}\" is not a file`);\n }\n\n console.log(`[DEBUG] File size: ${stats.size} bytes`);\n\n if (stats.size === 0) {\n throw new Error(\n `File \"${params.filePath}\" is empty (0 bytes). Cannot inscribe empty files.`\n );\n }\n\n if (stats.size < 10) {\n throw new Error(\n `File \"${params.filePath}\" is too small (${stats.size} bytes). Files must contain at least 10 bytes of meaningful content.`\n );\n }\n\n if (stats.size > 100 * 1024 * 1024) {\n console.log(\n `[InscribeFromFileTool] WARNING: Large file detected (${(\n stats.size /\n (1024 * 1024)\n ).toFixed(2)} MB)`\n );\n }\n\n this.logger?.info('Reading file content...');\n fileContent = await fs.readFile(params.filePath);\n this.logger?.info(`Read ${fileContent.length} bytes from file`);\n\n if (!fileContent || fileContent.length === 0) {\n throw new Error(\n `File \"${params.filePath}\" has no content after reading. Cannot inscribe empty files.`\n );\n }\n\n if (fileContent.length < 10) {\n throw new Error(\n `File \"${params.filePath}\" content is too small (${fileContent.length} bytes). Files must contain at least 10 bytes of meaningful content.`\n );\n }\n\n const fileName = path.basename(params.filePath);\n const mimeType = this.getMimeType(fileName);\n if (mimeType.startsWith('text/') || mimeType === 'application/json') {\n const textContent = fileContent.toString(\n 'utf8',\n 0,\n Math.min(fileContent.length, 1000)\n );\n if (textContent.trim() === '') {\n throw new Error(\n `File \"${params.filePath}\" contains only whitespace or empty content. Cannot inscribe meaningless data.`\n );\n }\n }\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n throw new Error(`File not found: \"${params.filePath}\"`);\n }\n throw error;\n }\n throw new Error(`Failed to read file: ${error}`);\n }\n\n const base64Data = fileContent.toString('base64');\n this.logger?.info(`Converted to base64: ${base64Data.length} characters`);\n\n const fileName = path.basename(params.filePath);\n const mimeType = this.getMimeType(fileName);\n this.logger?.info(`File: ${fileName}, MIME type: ${mimeType}`);\n\n const options: InscriptionOptions = {\n mode: params.mode,\n metadata: params.metadata,\n tags: params.tags,\n chunkSize: params.chunkSize,\n waitForConfirmation: params.quoteOnly\n ? false\n : params.waitForConfirmation ?? true,\n waitMaxAttempts: 10,\n waitIntervalMs: 3000,\n apiKey: params.apiKey,\n network: this.inscriberBuilder['hederaKit'].client.network\n .toString()\n .includes('mainnet')\n ? 'mainnet'\n : 'testnet',\n quoteOnly: params.quoteOnly,\n };\n\n if (params.quoteOnly) {\n try {\n const quote = await this.generateInscriptionQuote(\n {\n type: 'buffer',\n buffer: Buffer.from(base64Data, 'base64'),\n fileName,\n mimeType,\n },\n options\n );\n\n return {\n success: true,\n quote: {\n totalCostHbar: quote.totalCostHbar,\n validUntil: quote.validUntil,\n breakdown: quote.breakdown,\n },\n contentInfo: {\n fileName,\n mimeType,\n sizeBytes: fileContent.length,\n filePath: params.filePath,\n },\n message: `Estimated Quote for file: ${fileName} (${(\n fileContent.length / 1024\n ).toFixed(2)} KB)\\nTotal cost: ${\n quote.totalCostHbar\n } HBAR`,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : 'Failed to generate inscription quote';\n throw new Error(`Quote generation failed: ${errorMessage}`);\n }\n }\n\n try {\n let result: unknown;\n\n if (params.timeoutMs) {\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(\n () =>\n reject(\n new Error(`Inscription timed out after ${params.timeoutMs}ms`)\n ),\n params.timeoutMs\n );\n });\n\n result = await Promise.race([\n this.inscriberBuilder.inscribe(\n {\n type: 'buffer',\n buffer: Buffer.from(base64Data, 'base64'),\n fileName,\n mimeType,\n },\n options\n ),\n timeoutPromise,\n ]);\n } else {\n result = await this.inscriberBuilder.inscribe(\n {\n type: 'buffer',\n buffer: Buffer.from(base64Data, 'base64'),\n fileName,\n mimeType,\n },\n options\n );\n }\n\n const inscriptionResult = result as any;\n if (inscriptionResult.confirmed && !inscriptionResult.quote) {\n const topicId =\n inscriptionResult.inscription?.topic_id ||\n inscriptionResult.result.topicId;\n const network = options.network || 'testnet';\n const cdnUrl = topicId\n ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}`\n : null;\n return `Successfully inscribed and confirmed content on the Hedera network!\\n\\nTransaction ID: ${\n inscriptionResult.result.transactionId\n }\\nTopic ID: ${topicId || 'N/A'}${\n cdnUrl ? `\\nView inscription: ${cdnUrl}` : ''\n }\\n\\nThe inscription is now available.`;\n } else if (!inscriptionResult.quote && !inscriptionResult.confirmed) {\n return `Successfully submitted inscription to the Hedera network!\\n\\nTransaction ID: ${inscriptionResult.result.transactionId}\\n\\nThe inscription is processing and will be confirmed shortly.`;\n } else {\n return 'Inscription operation completed.';\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to inscribe from file';\n throw new Error(`Inscription failed: ${errorMessage}`);\n }\n }\n\n private getMimeType(fileName: string): string {\n const ext = path.extname(fileName).toLowerCase();\n const mimeTypes: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.svg': 'image/svg+xml',\n '.pdf': 'application/pdf',\n '.json': 'application/json',\n '.txt': 'text/plain',\n '.html': 'text/html',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.ts': 'application/typescript',\n '.mp4': 'video/mp4',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.zip': 'application/zip',\n };\n return mimeTypes[ext] || 'application/octet-stream';\n }\n}\n"],"names":["fileName","mimeType"],"mappings":"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"}
@@ -75,7 +75,7 @@ class InscribeFromBufferTool extends BaseInscriberQueryTool {
75
75
  mimeType: resolvedMimeType,
76
76
  sizeBytes: buffer.length
77
77
  },
78
- message: `Quote generated for buffer content: ${resolvedFileName} (${(buffer.length / 1024).toFixed(2)} KB)
78
+ message: `Estimated Quote for buffer content: ${resolvedFileName} (${(buffer.length / 1024).toFixed(2)} KB)
79
79
  Total cost: ${quote.totalCostHbar} HBAR`
80
80
  };
81
81
  } catch (error) {
@@ -83,14 +83,13 @@ Total cost: ${quote.totalCostHbar} HBAR`
83
83
  throw new Error(`Quote generation failed: ${errorMessage}`);
84
84
  }
85
85
  }
86
- const timeoutMs = params.timeoutMs || (options.waitForConfirmation ? 6e4 : void 0);
87
86
  try {
88
87
  const result = await this.executeInscription(
89
88
  buffer,
90
89
  resolvedFileName,
91
90
  resolvedMimeType,
92
91
  options,
93
- timeoutMs
92
+ params.timeoutMs
94
93
  );
95
94
  return this.formatInscriptionResult(result, options);
96
95
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"standards-agent-kit.es36.js","sources":["../../src/tools/inscriber/InscribeFromBufferTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { BaseInscriberQueryTool } from './base-inscriber-tools';\nimport { InscriptionOptions, ContentResolverRegistry } from '@hashgraphonline/standards-sdk';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\nimport { loadConfig } from '../../config/ContentReferenceConfig';\n\nconst inscribeFromBufferSchema = z.object({\n base64Data: z\n .string()\n .min(1, 'Data cannot be empty')\n .describe(\n 'The content to inscribe. Accept BOTH plain text AND base64. Also accepts content reference IDs in format \"content-ref:[id]\". When user says \"inscribe it\" or \"inscribe the content\", use the EXACT content from your previous message or from MCP tool results. DO NOT generate new content. DO NOT create repetitive text. Pass the actual search results or other retrieved content EXACTLY as you received it.'\n ),\n fileName: z\n .string()\n .min(1, 'File name cannot be empty')\n .describe('Name for the inscribed content. Required for all inscriptions.'),\n mimeType: z.string().optional().describe('MIME type of the content'),\n mode: z\n .enum(['file', 'hashinal'])\n .optional()\n .describe('Inscription mode: file or hashinal NFT'),\n metadata: z\n .record(z.unknown())\n .optional()\n .describe('Metadata to attach to the inscription'),\n tags: z\n .array(z.string())\n .optional()\n .describe('Tags to categorize the inscription'),\n chunkSize: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Chunk size for large files'),\n waitForConfirmation: z\n .boolean()\n .optional()\n .describe('Whether to wait for inscription confirmation'),\n timeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Timeout in milliseconds for inscription (default: no timeout - waits until completion)'\n ),\n apiKey: z.string().optional().describe('API key for inscription service'),\n quoteOnly: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, returns a cost quote instead of executing the inscription'),\n});\n\nexport class InscribeFromBufferTool extends BaseInscriberQueryTool<\n typeof inscribeFromBufferSchema\n> {\n name = 'inscribeFromBuffer';\n description =\n 'Inscribe content that you have already retrieved or displayed. When user says \"inscribe it\" after you showed search results or other content, use THIS tool. The base64Data field accepts PLAIN TEXT (not just base64) and content reference IDs in format \"content-ref:[id]\". Pass the EXACT content from your previous response or MCP tool output. DO NOT generate new content or create repetitive text. Content references are automatically resolved to the original content for inscription. Set quoteOnly=true to get cost estimates without executing the inscription.';\n\n private config = loadConfig();\n\n get specificInputSchema() {\n return inscribeFromBufferSchema;\n }\n\n protected async executeQuery(\n params: z.infer<typeof inscribeFromBufferSchema>,\n _runManager?: CallbackManagerForToolRun\n ): Promise<unknown> {\n this.validateInput(params);\n\n const resolvedContent = await this.resolveContent(\n params.base64Data,\n params.mimeType,\n params.fileName\n );\n\n this.validateContent(resolvedContent.buffer);\n\n const buffer = resolvedContent.buffer;\n const resolvedMimeType = resolvedContent.mimeType || params.mimeType;\n const resolvedFileName = resolvedContent.fileName || params.fileName;\n\n const options: InscriptionOptions = {\n mode: params.mode,\n metadata: params.metadata,\n tags: params.tags,\n chunkSize: params.chunkSize,\n waitForConfirmation: params.quoteOnly ? false : (params.waitForConfirmation ?? true),\n waitMaxAttempts: 10,\n waitIntervalMs: 3000,\n apiKey: params.apiKey,\n network: this.inscriberBuilder['hederaKit'].client.network\n .toString()\n .includes('mainnet')\n ? 'mainnet'\n : 'testnet',\n quoteOnly: params.quoteOnly,\n };\n\n if (params.quoteOnly) {\n try {\n const quote = await this.generateInscriptionQuote(\n {\n type: 'buffer',\n buffer,\n fileName: resolvedFileName,\n mimeType: resolvedMimeType,\n },\n options\n );\n \n return {\n success: true,\n quote: {\n totalCostHbar: quote.totalCostHbar,\n validUntil: quote.validUntil,\n breakdown: quote.breakdown,\n },\n contentInfo: {\n fileName: resolvedFileName,\n mimeType: resolvedMimeType,\n sizeBytes: buffer.length,\n },\n message: `Quote generated for buffer content: ${resolvedFileName} (${(buffer.length / 1024).toFixed(2)} KB)\\nTotal cost: ${quote.totalCostHbar} HBAR`,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to generate inscription quote';\n throw new Error(`Quote generation failed: ${errorMessage}`);\n }\n }\n\n const timeoutMs =\n params.timeoutMs || (options.waitForConfirmation ? 60000 : undefined);\n\n try {\n const result = await this.executeInscription(\n buffer,\n resolvedFileName,\n resolvedMimeType,\n options,\n timeoutMs\n );\n return this.formatInscriptionResult(result, options);\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : 'Failed to inscribe from buffer';\n throw new Error(`Inscription failed: ${errorMessage}`);\n }\n }\n\n private validateInput(\n params: z.infer<typeof inscribeFromBufferSchema>\n ): void {\n if (!params.base64Data || params.base64Data.trim() === '') {\n throw new Error(\n 'No data provided. Cannot inscribe empty content. Please provide valid content, plain text, base64 encoded data, or a content reference ID.'\n );\n }\n\n if (!params.fileName || params.fileName.trim() === '') {\n throw new Error(\n 'No fileName provided. A valid fileName is required for inscription.'\n );\n }\n }\n\n private validateContent(buffer: Buffer): void {\n if (buffer.length === 0) {\n throw new Error(\n 'Buffer is empty after conversion. The provided data appears to be invalid or empty.'\n );\n }\n\n if (buffer.length > this.config.maxInscriptionSize) {\n const maxSizeKB = Math.round(this.config.maxInscriptionSize / 1024);\n const bufferSizeKB = Math.round(buffer.length / 1024);\n throw new Error(\n `Content is too large for inscription (${bufferSizeKB}KB, max ${maxSizeKB}KB). Please summarize or extract key information before inscribing.`\n );\n }\n\n if (buffer.length < this.config.minContentSize) {\n throw new Error(\n `Buffer content is too small (${buffer.length} bytes). This may indicate empty or invalid content. Please verify the source data contains actual content.`\n );\n }\n\n if (\n buffer.toString('utf8', 0, Math.min(buffer.length, 100)).trim() === ''\n ) {\n throw new Error(\n 'Buffer contains only whitespace or empty content. Cannot inscribe meaningless data.'\n );\n }\n\n const contentStr = buffer.toString('utf8');\n const emptyHtmlPattern = /<a\\s+href=[\"'][^\"']+[\"']\\s*>\\s*<\\/a>/i;\n const hasOnlyEmptyLinks =\n emptyHtmlPattern.test(contentStr) &&\n contentStr.replace(/<[^>]+>/g, '').trim().length < 50;\n\n if (hasOnlyEmptyLinks) {\n throw new Error(\n 'Buffer contains empty HTML with only links and no actual content. When inscribing content from external sources, use the actual article text you retrieved, not empty HTML with links.'\n );\n }\n }\n\n private async executeInscription(\n buffer: Buffer,\n fileName: string,\n mimeType: string | undefined,\n options: InscriptionOptions,\n timeoutMs?: number\n ): Promise<Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>> {\n const inscriptionData = {\n type: 'buffer' as const,\n buffer,\n fileName,\n mimeType,\n };\n\n if (timeoutMs) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(\n () => reject(new Error(`Inscription timed out after ${timeoutMs}ms`)),\n timeoutMs\n );\n });\n\n return Promise.race([\n this.inscriberBuilder.inscribe(inscriptionData, options),\n timeoutPromise,\n ]);\n }\n\n return this.inscriberBuilder.inscribe(inscriptionData, options);\n }\n\n private formatInscriptionResult(\n result: Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>,\n options: InscriptionOptions\n ): string {\n if (result.confirmed && !result.quote) {\n const topicId = result.inscription?.topic_id || (result.result as any).topicId;\n const network = options.network || 'testnet';\n const cdnUrl = topicId\n ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}`\n : null;\n return `Successfully inscribed and confirmed content on the Hedera network!\\n\\nTransaction ID: ${\n (result.result as any).transactionId\n }\\nTopic ID: ${topicId || 'N/A'}${\n cdnUrl ? `\\nView inscription: ${cdnUrl}` : ''\n }\\n\\nThe inscription is now available.`;\n }\n\n if (!result.quote && !result.confirmed) {\n return `Successfully submitted inscription to the Hedera network!\\n\\nTransaction ID: ${(result.result as any).transactionId}\\n\\nThe inscription is processing and will be confirmed shortly.`;\n }\n\n return 'Inscription operation completed.';\n }\n\n private async resolveContent(\n input: string,\n providedMimeType?: string,\n providedFileName?: string\n ): Promise<{\n buffer: Buffer;\n mimeType?: string;\n fileName?: string;\n wasReference?: boolean;\n }> {\n const trimmedInput = input.trim();\n \n const resolver = this.getContentResolver() || ContentResolverRegistry.getResolver();\n \n if (!resolver) {\n return this.handleDirectContent(trimmedInput, providedMimeType, providedFileName);\n }\n \n const referenceId = resolver.extractReferenceId(trimmedInput);\n\n if (referenceId) {\n try {\n const resolution = await resolver.resolveReference(referenceId);\n\n return {\n buffer: resolution.content,\n mimeType: resolution.metadata?.mimeType || providedMimeType,\n fileName: resolution.metadata?.fileName || providedFileName,\n wasReference: true,\n };\n } catch (error) {\n const errorMsg =\n error instanceof Error\n ? error.message\n : 'Unknown error resolving reference';\n throw new Error(`Reference resolution failed: ${errorMsg}`);\n }\n }\n\n return this.handleDirectContent(trimmedInput, providedMimeType, providedFileName);\n }\n\n private handleDirectContent(\n input: string,\n providedMimeType?: string,\n providedFileName?: string\n ): {\n buffer: Buffer;\n mimeType?: string;\n fileName?: string;\n wasReference?: boolean;\n } {\n const isValidBase64 = /^[A-Za-z0-9+/]*={0,2}$/.test(input);\n\n if (isValidBase64) {\n try {\n const buffer = Buffer.from(input, 'base64');\n return {\n buffer,\n mimeType: providedMimeType,\n fileName: providedFileName,\n wasReference: false,\n };\n } catch (error) {\n throw new Error(\n 'Failed to decode base64 data. Please ensure the data is properly encoded.'\n );\n }\n }\n\n const buffer = Buffer.from(input, 'utf8');\n return {\n buffer,\n mimeType: providedMimeType || 'text/plain',\n fileName: providedFileName,\n wasReference: false,\n };\n }\n}\n"],"names":["buffer"],"mappings":"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"}
1
+ {"version":3,"file":"standards-agent-kit.es36.js","sources":["../../src/tools/inscriber/InscribeFromBufferTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { BaseInscriberQueryTool } from './base-inscriber-tools';\nimport { InscriptionOptions, ContentResolverRegistry } from '@hashgraphonline/standards-sdk';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\nimport { loadConfig } from '../../config/ContentReferenceConfig';\n\nconst inscribeFromBufferSchema = z.object({\n base64Data: z\n .string()\n .min(1, 'Data cannot be empty')\n .describe(\n 'The content to inscribe. Accept BOTH plain text AND base64. Also accepts content reference IDs in format \"content-ref:[id]\". When user says \"inscribe it\" or \"inscribe the content\", use the EXACT content from your previous message or from MCP tool results. DO NOT generate new content. DO NOT create repetitive text. Pass the actual search results or other retrieved content EXACTLY as you received it.'\n ),\n fileName: z\n .string()\n .min(1, 'File name cannot be empty')\n .describe('Name for the inscribed content. Required for all inscriptions.'),\n mimeType: z.string().optional().describe('MIME type of the content'),\n mode: z\n .enum(['file', 'hashinal'])\n .optional()\n .describe('Inscription mode: file or hashinal NFT'),\n metadata: z\n .record(z.unknown())\n .optional()\n .describe('Metadata to attach to the inscription'),\n tags: z\n .array(z.string())\n .optional()\n .describe('Tags to categorize the inscription'),\n chunkSize: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Chunk size for large files'),\n waitForConfirmation: z\n .boolean()\n .optional()\n .describe('Whether to wait for inscription confirmation'),\n timeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Timeout in milliseconds for inscription (default: no timeout - waits until completion)'\n ),\n apiKey: z.string().optional().describe('API key for inscription service'),\n quoteOnly: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, returns a cost quote instead of executing the inscription'),\n});\n\nexport class InscribeFromBufferTool extends BaseInscriberQueryTool<\n typeof inscribeFromBufferSchema\n> {\n name = 'inscribeFromBuffer';\n description =\n 'Inscribe content that you have already retrieved or displayed. When user says \"inscribe it\" after you showed search results or other content, use THIS tool. The base64Data field accepts PLAIN TEXT (not just base64) and content reference IDs in format \"content-ref:[id]\". Pass the EXACT content from your previous response or MCP tool output. DO NOT generate new content or create repetitive text. Content references are automatically resolved to the original content for inscription. Set quoteOnly=true to get cost estimates without executing the inscription.';\n\n private config = loadConfig();\n\n get specificInputSchema() {\n return inscribeFromBufferSchema;\n }\n\n protected async executeQuery(\n params: z.infer<typeof inscribeFromBufferSchema>,\n _runManager?: CallbackManagerForToolRun\n ): Promise<unknown> {\n this.validateInput(params);\n\n const resolvedContent = await this.resolveContent(\n params.base64Data,\n params.mimeType,\n params.fileName\n );\n\n this.validateContent(resolvedContent.buffer);\n\n const buffer = resolvedContent.buffer;\n const resolvedMimeType = resolvedContent.mimeType || params.mimeType;\n const resolvedFileName = resolvedContent.fileName || params.fileName;\n\n const options: InscriptionOptions = {\n mode: params.mode,\n metadata: params.metadata,\n tags: params.tags,\n chunkSize: params.chunkSize,\n waitForConfirmation: params.quoteOnly ? false : (params.waitForConfirmation ?? true),\n waitMaxAttempts: 10,\n waitIntervalMs: 3000,\n apiKey: params.apiKey,\n network: this.inscriberBuilder['hederaKit'].client.network\n .toString()\n .includes('mainnet')\n ? 'mainnet'\n : 'testnet',\n quoteOnly: params.quoteOnly,\n };\n\n if (params.quoteOnly) {\n try {\n const quote = await this.generateInscriptionQuote(\n {\n type: 'buffer',\n buffer,\n fileName: resolvedFileName,\n mimeType: resolvedMimeType,\n },\n options\n );\n \n return {\n success: true,\n quote: {\n totalCostHbar: quote.totalCostHbar,\n validUntil: quote.validUntil,\n breakdown: quote.breakdown,\n },\n contentInfo: {\n fileName: resolvedFileName,\n mimeType: resolvedMimeType,\n sizeBytes: buffer.length,\n },\n message: `Estimated Quote for buffer content: ${resolvedFileName} (${(buffer.length / 1024).toFixed(2)} KB)\\nTotal cost: ${quote.totalCostHbar} HBAR`,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to generate inscription quote';\n throw new Error(`Quote generation failed: ${errorMessage}`);\n }\n }\n\n try {\n const result = await this.executeInscription(\n buffer,\n resolvedFileName,\n resolvedMimeType,\n options,\n params.timeoutMs\n );\n return this.formatInscriptionResult(result, options);\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : 'Failed to inscribe from buffer';\n throw new Error(`Inscription failed: ${errorMessage}`);\n }\n }\n\n private validateInput(\n params: z.infer<typeof inscribeFromBufferSchema>\n ): void {\n if (!params.base64Data || params.base64Data.trim() === '') {\n throw new Error(\n 'No data provided. Cannot inscribe empty content. Please provide valid content, plain text, base64 encoded data, or a content reference ID.'\n );\n }\n\n if (!params.fileName || params.fileName.trim() === '') {\n throw new Error(\n 'No fileName provided. A valid fileName is required for inscription.'\n );\n }\n }\n\n private validateContent(buffer: Buffer): void {\n if (buffer.length === 0) {\n throw new Error(\n 'Buffer is empty after conversion. The provided data appears to be invalid or empty.'\n );\n }\n\n if (buffer.length > this.config.maxInscriptionSize) {\n const maxSizeKB = Math.round(this.config.maxInscriptionSize / 1024);\n const bufferSizeKB = Math.round(buffer.length / 1024);\n throw new Error(\n `Content is too large for inscription (${bufferSizeKB}KB, max ${maxSizeKB}KB). Please summarize or extract key information before inscribing.`\n );\n }\n\n if (buffer.length < this.config.minContentSize) {\n throw new Error(\n `Buffer content is too small (${buffer.length} bytes). This may indicate empty or invalid content. Please verify the source data contains actual content.`\n );\n }\n\n if (\n buffer.toString('utf8', 0, Math.min(buffer.length, 100)).trim() === ''\n ) {\n throw new Error(\n 'Buffer contains only whitespace or empty content. Cannot inscribe meaningless data.'\n );\n }\n\n const contentStr = buffer.toString('utf8');\n const emptyHtmlPattern = /<a\\s+href=[\"'][^\"']+[\"']\\s*>\\s*<\\/a>/i;\n const hasOnlyEmptyLinks =\n emptyHtmlPattern.test(contentStr) &&\n contentStr.replace(/<[^>]+>/g, '').trim().length < 50;\n\n if (hasOnlyEmptyLinks) {\n throw new Error(\n 'Buffer contains empty HTML with only links and no actual content. When inscribing content from external sources, use the actual article text you retrieved, not empty HTML with links.'\n );\n }\n }\n\n private async executeInscription(\n buffer: Buffer,\n fileName: string,\n mimeType: string | undefined,\n options: InscriptionOptions,\n timeoutMs?: number\n ): Promise<Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>> {\n const inscriptionData = {\n type: 'buffer' as const,\n buffer,\n fileName,\n mimeType,\n };\n\n if (timeoutMs) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(\n () => reject(new Error(`Inscription timed out after ${timeoutMs}ms`)),\n timeoutMs\n );\n });\n\n return Promise.race([\n this.inscriberBuilder.inscribe(inscriptionData, options),\n timeoutPromise,\n ]);\n }\n\n return this.inscriberBuilder.inscribe(inscriptionData, options);\n }\n\n private formatInscriptionResult(\n result: Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>,\n options: InscriptionOptions\n ): string {\n if (result.confirmed && !result.quote) {\n const topicId = result.inscription?.topic_id || (result.result as any).topicId;\n const network = options.network || 'testnet';\n const cdnUrl = topicId\n ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}`\n : null;\n return `Successfully inscribed and confirmed content on the Hedera network!\\n\\nTransaction ID: ${\n (result.result as any).transactionId\n }\\nTopic ID: ${topicId || 'N/A'}${\n cdnUrl ? `\\nView inscription: ${cdnUrl}` : ''\n }\\n\\nThe inscription is now available.`;\n }\n\n if (!result.quote && !result.confirmed) {\n return `Successfully submitted inscription to the Hedera network!\\n\\nTransaction ID: ${(result.result as any).transactionId}\\n\\nThe inscription is processing and will be confirmed shortly.`;\n }\n\n return 'Inscription operation completed.';\n }\n\n private async resolveContent(\n input: string,\n providedMimeType?: string,\n providedFileName?: string\n ): Promise<{\n buffer: Buffer;\n mimeType?: string;\n fileName?: string;\n wasReference?: boolean;\n }> {\n const trimmedInput = input.trim();\n \n const resolver = this.getContentResolver() || ContentResolverRegistry.getResolver();\n \n if (!resolver) {\n return this.handleDirectContent(trimmedInput, providedMimeType, providedFileName);\n }\n \n const referenceId = resolver.extractReferenceId(trimmedInput);\n\n if (referenceId) {\n try {\n const resolution = await resolver.resolveReference(referenceId);\n\n return {\n buffer: resolution.content,\n mimeType: resolution.metadata?.mimeType || providedMimeType,\n fileName: resolution.metadata?.fileName || providedFileName,\n wasReference: true,\n };\n } catch (error) {\n const errorMsg =\n error instanceof Error\n ? error.message\n : 'Unknown error resolving reference';\n throw new Error(`Reference resolution failed: ${errorMsg}`);\n }\n }\n\n return this.handleDirectContent(trimmedInput, providedMimeType, providedFileName);\n }\n\n private handleDirectContent(\n input: string,\n providedMimeType?: string,\n providedFileName?: string\n ): {\n buffer: Buffer;\n mimeType?: string;\n fileName?: string;\n wasReference?: boolean;\n } {\n const isValidBase64 = /^[A-Za-z0-9+/]*={0,2}$/.test(input);\n\n if (isValidBase64) {\n try {\n const buffer = Buffer.from(input, 'base64');\n return {\n buffer,\n mimeType: providedMimeType,\n fileName: providedFileName,\n wasReference: false,\n };\n } catch (error) {\n throw new Error(\n 'Failed to decode base64 data. Please ensure the data is properly encoded.'\n );\n }\n }\n\n const buffer = Buffer.from(input, 'utf8');\n return {\n buffer,\n mimeType: providedMimeType || 'text/plain',\n fileName: providedFileName,\n wasReference: false,\n };\n }\n}\n"],"names":["buffer"],"mappings":";;;;AAMA,MAAM,2BAA2B,EAAE,OAAO;AAAA,EACxC,YAAY,EACT,OAAA,EACA,IAAI,GAAG,sBAAsB,EAC7B;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,UAAU,EACP,SACA,IAAI,GAAG,2BAA2B,EAClC,SAAS,gEAAgE;AAAA,EAC5E,UAAU,EAAE,OAAA,EAAS,SAAA,EAAW,SAAS,0BAA0B;AAAA,EACnE,MAAM,EACH,KAAK,CAAC,QAAQ,UAAU,CAAC,EACzB,SAAA,EACA,SAAS,wCAAwC;AAAA,EACpD,UAAU,EACP,OAAO,EAAE,QAAA,CAAS,EAClB,SAAA,EACA,SAAS,uCAAuC;AAAA,EACnD,MAAM,EACH,MAAM,EAAE,OAAA,CAAQ,EAChB,SAAA,EACA,SAAS,oCAAoC;AAAA,EAChD,WAAW,EACR,OAAA,EACA,IAAA,EACA,SAAA,EACA,SAAA,EACA,SAAS,4BAA4B;AAAA,EACxC,qBAAqB,EAClB,QAAA,EACA,SAAA,EACA,SAAS,8CAA8C;AAAA,EAC1D,WAAW,EACR,SACA,MACA,SAAA,EACA,SAAA,EACA;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,QAAQ,EAAE,OAAA,EAAS,SAAA,EAAW,SAAS,iCAAiC;AAAA,EACxE,WAAW,EACR,UACA,SAAA,EACA,QAAQ,KAAK,EACb,SAAS,oEAAoE;AAClF,CAAC;AAEM,MAAM,+BAA+B,uBAE1C;AAAA,EAFK,cAAA;AAAA,UAAA,GAAA,SAAA;AAGL,SAAA,OAAO;AACP,SAAA,cACE;AAEF,SAAQ,SAAS,WAAA;AAAA,EAAW;AAAA,EAE5B,IAAI,sBAAsB;AACxB,WAAO;AAAA,EACT;AAAA,EAEA,MAAgB,aACd,QACA,aACkB;AAClB,SAAK,cAAc,MAAM;AAEzB,UAAM,kBAAkB,MAAM,KAAK;AAAA,MACjC,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,IAAA;AAGT,SAAK,gBAAgB,gBAAgB,MAAM;AAE3C,UAAM,SAAS,gBAAgB;AAC/B,UAAM,mBAAmB,gBAAgB,YAAY,OAAO;AAC5D,UAAM,mBAAmB,gBAAgB,YAAY,OAAO;AAE5D,UAAM,UAA8B;AAAA,MAClC,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,MACjB,MAAM,OAAO;AAAA,MACb,WAAW,OAAO;AAAA,MAClB,qBAAqB,OAAO,YAAY,QAAS,OAAO,uBAAuB;AAAA,MAC/E,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,SAAS,KAAK,iBAAiB,WAAW,EAAE,OAAO,QAChD,SAAA,EACA,SAAS,SAAS,IACjB,YACA;AAAA,MACJ,WAAW,OAAO;AAAA,IAAA;AAGpB,QAAI,OAAO,WAAW;AACpB,UAAI;AACF,cAAM,QAAQ,MAAM,KAAK;AAAA,UACvB;AAAA,YACE,MAAM;AAAA,YACN;AAAA,YACA,UAAU;AAAA,YACV,UAAU;AAAA,UAAA;AAAA,UAEZ;AAAA,QAAA;AAGF,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO;AAAA,YACL,eAAe,MAAM;AAAA,YACrB,YAAY,MAAM;AAAA,YAClB,WAAW,MAAM;AAAA,UAAA;AAAA,UAEnB,aAAa;AAAA,YACX,UAAU;AAAA,YACV,UAAU;AAAA,YACV,WAAW,OAAO;AAAA,UAAA;AAAA,UAEpB,SAAS,uCAAuC,gBAAgB,MAAM,OAAO,SAAS,MAAM,QAAQ,CAAC,CAAC;AAAA,cAAqB,MAAM,aAAa;AAAA,QAAA;AAAA,MAElJ,SAAS,OAAO;AACd,cAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAM,IAAI,MAAM,4BAA4B,YAAY,EAAE;AAAA,MAC5D;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO;AAAA,MAAA;AAET,aAAO,KAAK,wBAAwB,QAAQ,OAAO;AAAA,IACrD,SAAS,OAAO;AACd,YAAM,eACJ,iBAAiB,QACb,MAAM,UACN;AACN,YAAM,IAAI,MAAM,uBAAuB,YAAY,EAAE;AAAA,IACvD;AAAA,EACF;AAAA,EAEQ,cACN,QACM;AACN,QAAI,CAAC,OAAO,cAAc,OAAO,WAAW,KAAA,MAAW,IAAI;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,QAAI,CAAC,OAAO,YAAY,OAAO,SAAS,KAAA,MAAW,IAAI;AACrD,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AAAA,EAEQ,gBAAgB,QAAsB;AAC5C,QAAI,OAAO,WAAW,GAAG;AACvB,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,QAAI,OAAO,SAAS,KAAK,OAAO,oBAAoB;AAClD,YAAM,YAAY,KAAK,MAAM,KAAK,OAAO,qBAAqB,IAAI;AAClE,YAAM,eAAe,KAAK,MAAM,OAAO,SAAS,IAAI;AACpD,YAAM,IAAI;AAAA,QACR,yCAAyC,YAAY,WAAW,SAAS;AAAA,MAAA;AAAA,IAE7E;AAEA,QAAI,OAAO,SAAS,KAAK,OAAO,gBAAgB;AAC9C,YAAM,IAAI;AAAA,QACR,gCAAgC,OAAO,MAAM;AAAA,MAAA;AAAA,IAEjD;AAEA,QACE,OAAO,SAAS,QAAQ,GAAG,KAAK,IAAI,OAAO,QAAQ,GAAG,CAAC,EAAE,KAAA,MAAW,IACpE;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,aAAa,OAAO,SAAS,MAAM;AACzC,UAAM,mBAAmB;AACzB,UAAM,oBACJ,iBAAiB,KAAK,UAAU,KAChC,WAAW,QAAQ,YAAY,EAAE,EAAE,KAAA,EAAO,SAAS;AAErD,QAAI,mBAAmB;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AAAA,EAEA,MAAc,mBACZ,QACA,UACA,UACA,SACA,WACqE;AACrE,UAAM,kBAAkB;AAAA,MACtB,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,WAAW;AACb,YAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD;AAAA,UACE,MAAM,OAAO,IAAI,MAAM,+BAA+B,SAAS,IAAI,CAAC;AAAA,UACpE;AAAA,QAAA;AAAA,MAEJ,CAAC;AAED,aAAO,QAAQ,KAAK;AAAA,QAClB,KAAK,iBAAiB,SAAS,iBAAiB,OAAO;AAAA,QACvD;AAAA,MAAA,CACD;AAAA,IACH;AAEA,WAAO,KAAK,iBAAiB,SAAS,iBAAiB,OAAO;AAAA,EAChE;AAAA,EAEQ,wBACN,QACA,SACQ;AACR,QAAI,OAAO,aAAa,CAAC,OAAO,OAAO;AACrC,YAAM,UAAU,OAAO,aAAa,YAAa,OAAO,OAAe;AACvE,YAAM,UAAU,QAAQ,WAAW;AACnC,YAAM,SAAS,UACX,8CAA8C,OAAO,YAAY,OAAO,KACxE;AACJ,aAAO;AAAA;AAAA,kBACJ,OAAO,OAAe,aACzB;AAAA,YAAe,WAAW,KAAK,GAC7B,SAAS;AAAA,oBAAuB,MAAM,KAAK,EAC7C;AAAA;AAAA;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,SAAS,CAAC,OAAO,WAAW;AACtC,aAAO;AAAA;AAAA,kBAAiF,OAAO,OAAe,aAAa;AAAA;AAAA;AAAA,IAC7H;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,eACZ,OACA,kBACA,kBAMC;AACD,UAAM,eAAe,MAAM,KAAA;AAE3B,UAAM,WAAW,KAAK,mBAAA,KAAwB,wBAAwB,YAAA;AAEtE,QAAI,CAAC,UAAU;AACb,aAAO,KAAK,oBAAoB,cAAc,kBAAkB,gBAAgB;AAAA,IAClF;AAEA,UAAM,cAAc,SAAS,mBAAmB,YAAY;AAE5D,QAAI,aAAa;AACf,UAAI;AACF,cAAM,aAAa,MAAM,SAAS,iBAAiB,WAAW;AAE9D,eAAO;AAAA,UACL,QAAQ,WAAW;AAAA,UACnB,UAAU,WAAW,UAAU,YAAY;AAAA,UAC3C,UAAU,WAAW,UAAU,YAAY;AAAA,UAC3C,cAAc;AAAA,QAAA;AAAA,MAElB,SAAS,OAAO;AACd,cAAM,WACJ,iBAAiB,QACb,MAAM,UACN;AACN,cAAM,IAAI,MAAM,gCAAgC,QAAQ,EAAE;AAAA,MAC5D;AAAA,IACF;AAEA,WAAO,KAAK,oBAAoB,cAAc,kBAAkB,gBAAgB;AAAA,EAClF;AAAA,EAEQ,oBACN,OACA,kBACA,kBAMA;AACA,UAAM,gBAAgB,yBAAyB,KAAK,KAAK;AAEzD,QAAI,eAAe;AACjB,UAAI;AACF,cAAMA,UAAS,OAAO,KAAK,OAAO,QAAQ;AAC1C,eAAO;AAAA,UACL,QAAAA;AAAAA,UACA,UAAU;AAAA,UACV,UAAU;AAAA,UACV,cAAc;AAAA,QAAA;AAAA,MAElB,SAAS,OAAO;AACd,cAAM,IAAI;AAAA,UACR;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF;AAEA,UAAM,SAAS,OAAO,KAAK,OAAO,MAAM;AACxC,WAAO;AAAA,MACL;AAAA,MACA,UAAU,oBAAoB;AAAA,MAC9B,UAAU;AAAA,MACV,cAAc;AAAA,IAAA;AAAA,EAElB;AACF;"}
@@ -71,7 +71,7 @@ class InscribeHashinalTool extends BaseInscriberQueryTool {
71
71
  creator: params.creator,
72
72
  type: params.type
73
73
  },
74
- message: `Quote generated for Hashinal NFT: ${params.name}
74
+ message: `Estimated Quote for Hashinal NFT: ${params.name}
75
75
  Creator: ${params.creator}
76
76
  Total cost: ${quote.totalCostHbar} HBAR`
77
77
  };
@@ -1 +1 @@
1
- {"version":3,"file":"standards-agent-kit.es37.js","sources":["../../src/tools/inscriber/InscribeHashinalTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { BaseInscriberQueryTool } from './base-inscriber-tools';\nimport { InscriptionOptions } from '@hashgraphonline/standards-sdk';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\n\n/**\n * Schema for inscribing Hashinal NFT\n */\nconst inscribeHashinalSchema = z.object({\n url: z.string().url().describe('The URL of the content to inscribe as Hashinal NFT'),\n name: z.string().describe('Name of the Hashinal NFT'),\n creator: z.string().describe('Creator account ID or name'),\n description: z.string().describe('Description of the Hashinal NFT'),\n type: z.string().describe('Type of NFT (e.g., \"image\", \"video\", \"audio\")'),\n attributes: z\n .array(\n z.object({\n trait_type: z.string(),\n value: z.union([z.string(), z.number()]),\n })\n )\n .optional()\n .describe('NFT attributes'),\n properties: z\n .record(z.unknown())\n .optional()\n .describe('Additional properties'),\n jsonFileURL: z\n .string()\n .url()\n .optional()\n .describe('URL to JSON metadata file'),\n tags: z\n .array(z.string())\n .optional()\n .describe('Tags to categorize the NFT'),\n chunkSize: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Chunk size for large files'),\n waitForConfirmation: z\n .boolean()\n .optional()\n .describe('Whether to wait for inscription confirmation'),\n timeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Timeout in milliseconds for inscription (default: no timeout - waits until completion)'),\n apiKey: z\n .string()\n .optional()\n .describe('API key for inscription service'),\n quoteOnly: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, returns a cost quote instead of executing the inscription'),\n});\n\n\n/**\n * Tool for inscribing Hashinal NFTs\n */\nexport class InscribeHashinalTool extends BaseInscriberQueryTool<typeof inscribeHashinalSchema> {\n name = 'inscribeHashinal';\n description = 'Inscribe content as a Hashinal NFT on the Hedera network. Set quoteOnly=true to get cost estimates without executing the inscription.';\n\n get specificInputSchema() {\n return inscribeHashinalSchema;\n }\n\n protected async executeQuery(\n params: z.infer<typeof inscribeHashinalSchema>,\n _runManager?: CallbackManagerForToolRun\n ): Promise<unknown> {\n const metadata = {\n name: params.name,\n creator: params.creator,\n description: params.description,\n type: params.type,\n attributes: params.attributes,\n properties: params.properties,\n };\n\n const options: InscriptionOptions = {\n mode: 'hashinal',\n metadata,\n jsonFileURL: params.jsonFileURL,\n tags: params.tags,\n chunkSize: params.chunkSize,\n waitForConfirmation: params.quoteOnly ? false : (params.waitForConfirmation ?? true),\n waitMaxAttempts: 10,\n waitIntervalMs: 3000,\n apiKey: params.apiKey,\n network: this.inscriberBuilder['hederaKit'].client.network.toString().includes('mainnet') ? 'mainnet' : 'testnet',\n quoteOnly: params.quoteOnly,\n };\n\n if (params.quoteOnly) {\n try {\n const quote = await this.generateInscriptionQuote(\n { type: 'url', url: params.url },\n options\n );\n \n return {\n success: true,\n quote: {\n totalCostHbar: quote.totalCostHbar,\n validUntil: quote.validUntil,\n breakdown: quote.breakdown,\n },\n contentInfo: {\n url: params.url,\n name: params.name,\n creator: params.creator,\n type: params.type,\n },\n message: `Quote generated for Hashinal NFT: ${params.name}\\nCreator: ${params.creator}\\nTotal cost: ${quote.totalCostHbar} HBAR`,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to generate inscription quote';\n throw new Error(`Quote generation failed: ${errorMessage}`);\n }\n }\n\n try {\n let result: Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>;\n \n if (params.timeoutMs) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(\n () => reject(new Error(`Inscription timed out after ${params.timeoutMs}ms`)),\n params.timeoutMs\n );\n });\n\n result = await Promise.race([\n this.inscriberBuilder.inscribe(\n { type: 'url', url: params.url },\n options\n ),\n timeoutPromise\n ]);\n } else {\n result = await this.inscriberBuilder.inscribe(\n { type: 'url', url: params.url },\n options\n );\n }\n\n if (result.confirmed && !result.quote) {\n const topicId = result.inscription?.topic_id || (result.result as any).topicId;\n const network = options.network || 'testnet';\n const cdnUrl = topicId ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}` : null;\n return `Successfully inscribed and confirmed Hashinal NFT on the Hedera network!\\n\\nTransaction ID: ${(result.result as any).transactionId}\\nTopic ID: ${topicId || 'N/A'}${cdnUrl ? `\\nView inscription: ${cdnUrl}` : ''}\\n\\nThe Hashinal NFT is now available.`;\n } else if (!result.quote && !result.confirmed) {\n return `Successfully submitted Hashinal NFT inscription to the Hedera network!\\n\\nTransaction ID: ${(result.result as any).transactionId}\\n\\nThe inscription is processing and will be confirmed shortly.`;\n } else {\n return 'Inscription operation completed.';\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to inscribe Hashinal NFT';\n throw new Error(`Inscription failed: ${errorMessage}`);\n }\n }\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"standards-agent-kit.es37.js","sources":["../../src/tools/inscriber/InscribeHashinalTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { BaseInscriberQueryTool } from './base-inscriber-tools';\nimport { InscriptionOptions } from '@hashgraphonline/standards-sdk';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\n\n/**\n * Schema for inscribing Hashinal NFT\n */\nconst inscribeHashinalSchema = z.object({\n url: z.string().url().describe('The URL of the content to inscribe as Hashinal NFT'),\n name: z.string().describe('Name of the Hashinal NFT'),\n creator: z.string().describe('Creator account ID or name'),\n description: z.string().describe('Description of the Hashinal NFT'),\n type: z.string().describe('Type of NFT (e.g., \"image\", \"video\", \"audio\")'),\n attributes: z\n .array(\n z.object({\n trait_type: z.string(),\n value: z.union([z.string(), z.number()]),\n })\n )\n .optional()\n .describe('NFT attributes'),\n properties: z\n .record(z.unknown())\n .optional()\n .describe('Additional properties'),\n jsonFileURL: z\n .string()\n .url()\n .optional()\n .describe('URL to JSON metadata file'),\n tags: z\n .array(z.string())\n .optional()\n .describe('Tags to categorize the NFT'),\n chunkSize: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Chunk size for large files'),\n waitForConfirmation: z\n .boolean()\n .optional()\n .describe('Whether to wait for inscription confirmation'),\n timeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Timeout in milliseconds for inscription (default: no timeout - waits until completion)'),\n apiKey: z\n .string()\n .optional()\n .describe('API key for inscription service'),\n quoteOnly: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, returns a cost quote instead of executing the inscription'),\n});\n\n\n/**\n * Tool for inscribing Hashinal NFTs\n */\nexport class InscribeHashinalTool extends BaseInscriberQueryTool<typeof inscribeHashinalSchema> {\n name = 'inscribeHashinal';\n description = 'Inscribe content as a Hashinal NFT on the Hedera network. Set quoteOnly=true to get cost estimates without executing the inscription.';\n\n get specificInputSchema() {\n return inscribeHashinalSchema;\n }\n\n protected async executeQuery(\n params: z.infer<typeof inscribeHashinalSchema>,\n _runManager?: CallbackManagerForToolRun\n ): Promise<unknown> {\n const metadata = {\n name: params.name,\n creator: params.creator,\n description: params.description,\n type: params.type,\n attributes: params.attributes,\n properties: params.properties,\n };\n\n const options: InscriptionOptions = {\n mode: 'hashinal',\n metadata,\n jsonFileURL: params.jsonFileURL,\n tags: params.tags,\n chunkSize: params.chunkSize,\n waitForConfirmation: params.quoteOnly ? false : (params.waitForConfirmation ?? true),\n waitMaxAttempts: 10,\n waitIntervalMs: 3000,\n apiKey: params.apiKey,\n network: this.inscriberBuilder['hederaKit'].client.network.toString().includes('mainnet') ? 'mainnet' : 'testnet',\n quoteOnly: params.quoteOnly,\n };\n\n if (params.quoteOnly) {\n try {\n const quote = await this.generateInscriptionQuote(\n { type: 'url', url: params.url },\n options\n );\n \n return {\n success: true,\n quote: {\n totalCostHbar: quote.totalCostHbar,\n validUntil: quote.validUntil,\n breakdown: quote.breakdown,\n },\n contentInfo: {\n url: params.url,\n name: params.name,\n creator: params.creator,\n type: params.type,\n },\n message: `Estimated Quote for Hashinal NFT: ${params.name}\\nCreator: ${params.creator}\\nTotal cost: ${quote.totalCostHbar} HBAR`,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to generate inscription quote';\n throw new Error(`Quote generation failed: ${errorMessage}`);\n }\n }\n\n try {\n let result: Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>;\n \n if (params.timeoutMs) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(\n () => reject(new Error(`Inscription timed out after ${params.timeoutMs}ms`)),\n params.timeoutMs\n );\n });\n\n result = await Promise.race([\n this.inscriberBuilder.inscribe(\n { type: 'url', url: params.url },\n options\n ),\n timeoutPromise\n ]);\n } else {\n result = await this.inscriberBuilder.inscribe(\n { type: 'url', url: params.url },\n options\n );\n }\n\n if (result.confirmed && !result.quote) {\n const topicId = result.inscription?.topic_id || (result.result as any).topicId;\n const network = options.network || 'testnet';\n const cdnUrl = topicId ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}` : null;\n return `Successfully inscribed and confirmed Hashinal NFT on the Hedera network!\\n\\nTransaction ID: ${(result.result as any).transactionId}\\nTopic ID: ${topicId || 'N/A'}${cdnUrl ? `\\nView inscription: ${cdnUrl}` : ''}\\n\\nThe Hashinal NFT is now available.`;\n } else if (!result.quote && !result.confirmed) {\n return `Successfully submitted Hashinal NFT inscription to the Hedera network!\\n\\nTransaction ID: ${(result.result as any).transactionId}\\n\\nThe inscription is processing and will be confirmed shortly.`;\n } else {\n return 'Inscription operation completed.';\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to inscribe Hashinal NFT';\n throw new Error(`Inscription failed: ${errorMessage}`);\n }\n }\n}"],"names":[],"mappings":"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"}