w3pk 0.10.0 ā 0.10.2
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/README.md +4 -0
- package/dist/index.d.mts +44 -12
- package/dist/index.d.ts +44 -12
- package/dist/index.js +32 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +33 -31
- package/dist/index.mjs.map +1 -1
- package/dist/inspect/browser.d.mts +5 -0
- package/dist/inspect/browser.d.ts +5 -0
- package/dist/inspect/browser.js +20 -3
- package/dist/inspect/browser.js.map +1 -1
- package/dist/inspect/browser.mjs +20 -3
- package/dist/inspect/browser.mjs.map +1 -1
- package/dist/inspect/index.js +20 -3
- package/dist/inspect/index.js.map +1 -1
- package/dist/inspect/index.mjs +20 -3
- package/dist/inspect/index.mjs.map +1 -1
- package/dist/inspect/node.d.mts +5 -0
- package/dist/inspect/node.d.ts +5 -0
- package/dist/inspect/node.js +13 -2
- package/dist/inspect/node.js.map +1 -1
- package/dist/inspect/node.mjs +13 -2
- package/dist/inspect/node.mjs.map +1 -1
- package/docs/API_REFERENCE.md +10 -91
- package/docs/ARCHITECTURE.md +45 -42
- package/docs/BUILD_VERIFICATION.md +3 -3
- package/docs/INTEGRATION_GUIDELINES.md +6 -9
- package/docs/SECURITY.md +155 -314
- package/package.json +1 -1
- package/dist/chainlist/index.d.mts +0 -96
- package/dist/chainlist/index.d.ts +0 -96
|
@@ -39,6 +39,11 @@ interface BrowserInspectOptions {
|
|
|
39
39
|
* @default 'transactions'
|
|
40
40
|
*/
|
|
41
41
|
focusMode?: "transactions" | "all";
|
|
42
|
+
/**
|
|
43
|
+
* Maximum total size in KB for all collected code (prevents exceeding API token limits)
|
|
44
|
+
* @default 100
|
|
45
|
+
*/
|
|
46
|
+
maxTotalSizeKB?: number;
|
|
42
47
|
}
|
|
43
48
|
/**
|
|
44
49
|
* Result of a browser-based inspection
|
|
@@ -39,6 +39,11 @@ interface BrowserInspectOptions {
|
|
|
39
39
|
* @default 'transactions'
|
|
40
40
|
*/
|
|
41
41
|
focusMode?: "transactions" | "all";
|
|
42
|
+
/**
|
|
43
|
+
* Maximum total size in KB for all collected code (prevents exceeding API token limits)
|
|
44
|
+
* @default 100
|
|
45
|
+
*/
|
|
46
|
+
maxTotalSizeKB?: number;
|
|
42
47
|
}
|
|
43
48
|
/**
|
|
44
49
|
* Result of a browser-based inspection
|
package/dist/inspect/browser.js
CHANGED
|
@@ -68,7 +68,7 @@ function extractTransactionSnippets(content, maxLength = 3e4) {
|
|
|
68
68
|
}
|
|
69
69
|
return snippet || "// No transaction code found";
|
|
70
70
|
}
|
|
71
|
-
async function fetchAppSource(appUrl) {
|
|
71
|
+
async function fetchAppSource(appUrl, maxTotalSizeKB = 100) {
|
|
72
72
|
let markdown = `# Application Code Analysis
|
|
73
73
|
|
|
74
74
|
`;
|
|
@@ -89,13 +89,27 @@ async function fetchAppSource(appUrl) {
|
|
|
89
89
|
|
|
90
90
|
`;
|
|
91
91
|
let totalSnippets = 0;
|
|
92
|
+
let cumulativeSizeKB = 0;
|
|
93
|
+
const maxTotalBytes = maxTotalSizeKB * 1024;
|
|
92
94
|
for (const scriptUrl of scriptUrls.slice(0, 15)) {
|
|
95
|
+
if (cumulativeSizeKB >= maxTotalSizeKB) {
|
|
96
|
+
console.warn(`[W3PK Inspect] Reached total size limit of ${maxTotalSizeKB} KB - stopping collection`);
|
|
97
|
+
markdown += `
|
|
98
|
+
**Note:** Collection stopped - reached ${maxTotalSizeKB} KB limit
|
|
99
|
+
`;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
93
102
|
try {
|
|
94
103
|
const response = await fetch(scriptUrl);
|
|
95
104
|
if (!response.ok) continue;
|
|
96
105
|
const content = await response.text();
|
|
97
106
|
const snippets = extractTransactionSnippets(content);
|
|
98
107
|
if (snippets && !snippets.includes("No transaction code found")) {
|
|
108
|
+
const snippetSize = new Blob([snippets]).size / 1024;
|
|
109
|
+
if (cumulativeSizeKB + snippetSize > maxTotalSizeKB) {
|
|
110
|
+
console.warn(`[W3PK Inspect] Skipping ${new URL(scriptUrl).pathname} - would exceed total size limit`);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
99
113
|
markdown += `### \`${new URL(scriptUrl).pathname}\`
|
|
100
114
|
|
|
101
115
|
`;
|
|
@@ -103,6 +117,7 @@ async function fetchAppSource(appUrl) {
|
|
|
103
117
|
markdown += snippets;
|
|
104
118
|
markdown += "\n```\n\n---\n\n";
|
|
105
119
|
totalSnippets++;
|
|
120
|
+
cumulativeSizeKB += snippetSize;
|
|
106
121
|
}
|
|
107
122
|
} catch (error) {
|
|
108
123
|
}
|
|
@@ -124,11 +139,13 @@ async function inspect(options = {}) {
|
|
|
124
139
|
rukhUrl = "https://rukh.w3hc.org",
|
|
125
140
|
context = "w3pk",
|
|
126
141
|
model = "anthropic",
|
|
127
|
-
focusMode = "transactions"
|
|
142
|
+
focusMode = "transactions",
|
|
143
|
+
maxTotalSizeKB = 100
|
|
128
144
|
} = options;
|
|
129
145
|
console.log("[W3PK Inspect] Starting inspection of", appUrl);
|
|
130
146
|
console.log("[W3PK Inspect] Focus mode:", focusMode);
|
|
131
|
-
|
|
147
|
+
console.log("[W3PK Inspect] Max total size:", maxTotalSizeKB, "KB");
|
|
148
|
+
const sourceMarkdown = await fetchAppSource(appUrl, maxTotalSizeKB);
|
|
132
149
|
console.log("[W3PK Inspect] Collected source code, sending to Rukh API...");
|
|
133
150
|
const message = "Analyze this web application and provide a security report listing all transaction and signing methods.";
|
|
134
151
|
const formData = new FormData();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/inspect/browser.ts"],"sourcesContent":["/**\n * Browser Inspection Module\n *\n * Provides client-side code inspection capabilities for analyzing running web3 applications.\n * Fetches JavaScript sources from the current page and analyzes transaction/signing patterns\n * to generate security reports via the Rukh API.\n *\n * This module is designed to be used directly in the browser console or embedded in\n * web applications to help end-users understand the security posture of the apps they use.\n *\n * @module inspect/browser\n */\n\n/**\n * Configuration options for browser-based application inspection\n */\nexport interface BrowserInspectOptions {\n /**\n * The origin/URL of the app to inspect\n * @default window.location.origin\n */\n appUrl?: string;\n\n /**\n * Rukh API endpoint\n * @default 'https://rukh.w3hc.org'\n */\n rukhUrl?: string;\n\n /**\n * Context to use for analysis\n * @default 'w3pk'\n */\n context?: string;\n\n /**\n * AI model to use\n * @default 'anthropic'\n */\n model?: \"anthropic\" | \"mistral\" | \"openai\";\n\n /**\n * Focus mode for analysis\n * @default 'transactions'\n */\n focusMode?: \"transactions\" | \"all\";\n}\n\n/**\n * Result of a browser-based inspection\n */\nexport interface BrowserInspectResult {\n /**\n * The security report markdown generated by Rukh API\n */\n report: string;\n\n /**\n * List of JavaScript file paths that were analyzed\n */\n analyzedFiles: string[];\n\n /**\n * The application URL that was inspected\n */\n appUrl: string;\n}\n\n/**\n * Extracts transaction-related code snippets from JavaScript content\n *\n * Scans JavaScript code for keywords related to signing, transactions, and web3 operations,\n * then extracts relevant code snippets with surrounding context.\n *\n * @param content - The JavaScript source code to analyze\n * @param maxLength - Maximum length of extracted snippets in characters\n * @returns Extracted code snippets or a message if no relevant code found\n * @internal\n */\nfunction extractTransactionSnippets(\n content: string,\n maxLength: number = 30000,\n): string {\n const keywords = [\n \"signMessage\",\n \"signTypedData\",\n \"sign(\",\n \"signature\",\n \"sendTransaction\",\n \"transaction\",\n \"eth_sign\",\n \"Contract(\",\n \"ethers.Contract\",\n \"new Contract\",\n \"w3pk\",\n \"Web3Passkey\",\n \"useW3PK\",\n \"wallet\",\n \"signer\",\n \"provider\",\n \"authorization\",\n \"delegation\",\n \"EIP7702\",\n ];\n\n const lines = content.split(\"\\n\");\n const relevantLines: string[] = [];\n const maxLines = 500;\n\n for (let i = 0; i < lines.length && relevantLines.length < maxLines; i++) {\n const line = lines[i];\n const lowerLine = line.toLowerCase();\n\n if (keywords.some((kw) => lowerLine.includes(kw.toLowerCase()))) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n\n for (let j = start; j < end; j++) {\n if (!relevantLines.includes(lines[j])) {\n relevantLines.push(lines[j]);\n }\n }\n }\n }\n\n const snippet = relevantLines.join(\"\\n\");\n\n if (snippet.length > maxLength) {\n return snippet.substring(0, maxLength) + \"\\n\\n// ... (truncated)\";\n }\n\n return snippet || \"// No transaction code found\";\n}\n\n/**\n * Fetches JavaScript source code from the currently running application\n *\n * Discovers and fetches all script tags in the current page, extracts transaction-related\n * snippets, and formats them as markdown for analysis.\n *\n * @param appUrl - The base URL of the application being inspected\n * @returns Markdown-formatted source code with transaction-related snippets\n * @internal\n */\nasync function fetchAppSource(appUrl: string): Promise<string> {\n let markdown = `# Application Code Analysis\\n\\n`;\n markdown += `**App URL:** ${appUrl}\\n\\n`;\n markdown += `**Note:** Only transaction-related code snippets shown\\n\\n`;\n markdown += `---\\n\\n`;\n\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const scriptUrls = scripts\n .map((script) => (script as HTMLScriptElement).src)\n .filter(\n (src) =>\n src &&\n !src.includes(\"node_modules\") &&\n !src.includes(\"chrome-extension\"),\n );\n\n markdown += `## JavaScript Files (${scriptUrls.length})\\n\\n`;\n\n let totalSnippets = 0;\n\n for (const scriptUrl of scriptUrls.slice(0, 15)) {\n try {\n const response = await fetch(scriptUrl);\n if (!response.ok) continue;\n\n const content = await response.text();\n const snippets = extractTransactionSnippets(content);\n\n if (snippets && !snippets.includes(\"No transaction code found\")) {\n markdown += `### \\`${new URL(scriptUrl).pathname}\\`\\n\\n`;\n markdown += \"```javascript\\n\";\n markdown += snippets;\n markdown += \"\\n```\\n\\n---\\n\\n\";\n totalSnippets++;\n }\n } catch (error) {\n // Skip files that can't be fetched\n }\n }\n\n if (totalSnippets === 0) {\n markdown += `No transaction-related code found in JavaScript files.\\n`;\n }\n\n return markdown;\n}\n\n/**\n * Inspects the currently running web application and returns a security report\n *\n * This function can be called by end-users in their browser console to analyze\n * the security of the web application they're currently using.\n *\n * @param options - Configuration options\n * @returns A security report analyzing transaction and signing methods\n *\n * @example\n * ```typescript\n * // In browser console or app code:\n * import { inspect } from 'w3pk';\n *\n * const report = await inspect();\n * console.log(report.report);\n * ```\n *\n * @example\n * ```typescript\n * // With custom options:\n * const report = await inspect({\n * appUrl: 'https://w3pk.w3hc.org',\n * model: 'anthropic',\n * focusMode: 'transactions'\n * });\n * ```\n */\nexport async function inspect(\n options: BrowserInspectOptions = {},\n): Promise<BrowserInspectResult> {\n // Check if running in browser\n if (typeof window === \"undefined\") {\n throw new Error(\n \"Browser inspect() can only be called in browser environments. For Node.js, use the CLI or Node.js API.\",\n );\n }\n\n const {\n appUrl = window.location.origin,\n rukhUrl = \"https://rukh.w3hc.org\",\n context = \"w3pk\",\n model = \"anthropic\",\n focusMode = \"transactions\",\n } = options;\n\n console.log(\"[W3PK Inspect] Starting inspection of\", appUrl);\n console.log(\"[W3PK Inspect] Focus mode:\", focusMode);\n\n // Fetch and analyze source code\n const sourceMarkdown = await fetchAppSource(appUrl);\n\n console.log(\"[W3PK Inspect] Collected source code, sending to Rukh API...\");\n\n // Prepare request to Rukh API\n const message =\n \"Analyze this web application and provide a security report listing all transaction and signing methods.\";\n\n const formData = new FormData();\n formData.append(\"message\", message);\n formData.append(\"model\", model);\n formData.append(\"context\", context);\n\n // Create blob from markdown\n const blob = new Blob([sourceMarkdown], { type: \"text/markdown\" });\n formData.append(\"file\", blob, \"app-source.md\");\n\n // Send to Rukh API\n const response = await fetch(`${rukhUrl}/ask`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Rukh API error: ${response.status} - ${error}`);\n }\n\n const data = await response.json();\n const report =\n data.output || data.response || data.message || JSON.stringify(data);\n\n console.log(\"[W3PK Inspect] Analysis complete!\");\n\n // Extract script URLs for analyzedFiles\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const analyzedFiles = scripts\n .map((script) => new URL((script as HTMLScriptElement).src).pathname)\n .filter((src) => src && !src.includes(\"node_modules\"));\n\n return {\n report,\n analyzedFiles,\n appUrl,\n };\n}\n\n/**\n * Quick inspection helper that logs the report to console\n * Perfect for use in browser DevTools console\n *\n * @example\n * ```javascript\n * // In browser console:\n * await w3pk.inspectNow()\n * ```\n */\nexport async function inspectNow(\n options?: BrowserInspectOptions,\n): Promise<void> {\n console.log(\"š W3PK Security Inspection Starting...\\n\");\n\n try {\n const result = await inspect(options);\n\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\"š SECURITY REPORT\");\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\\n\");\n console.log(result.report);\n console.log(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\n `ā
Analyzed ${result.analyzedFiles.length} files from ${result.appUrl}`,\n );\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n } catch (error) {\n console.error(\"ā Inspection failed:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/inspect/browser.ts"],"sourcesContent":["/**\n * Browser Inspection Module\n *\n * Provides client-side code inspection capabilities for analyzing running web3 applications.\n * Fetches JavaScript sources from the current page and analyzes transaction/signing patterns\n * to generate security reports via the Rukh API.\n *\n * This module is designed to be used directly in the browser console or embedded in\n * web applications to help end-users understand the security posture of the apps they use.\n *\n * @module inspect/browser\n */\n\n/**\n * Configuration options for browser-based application inspection\n */\nexport interface BrowserInspectOptions {\n /**\n * The origin/URL of the app to inspect\n * @default window.location.origin\n */\n appUrl?: string;\n\n /**\n * Rukh API endpoint\n * @default 'https://rukh.w3hc.org'\n */\n rukhUrl?: string;\n\n /**\n * Context to use for analysis\n * @default 'w3pk'\n */\n context?: string;\n\n /**\n * AI model to use\n * @default 'anthropic'\n */\n model?: \"anthropic\" | \"mistral\" | \"openai\";\n\n /**\n * Focus mode for analysis\n * @default 'transactions'\n */\n focusMode?: \"transactions\" | \"all\";\n\n /**\n * Maximum total size in KB for all collected code (prevents exceeding API token limits)\n * @default 100\n */\n maxTotalSizeKB?: number;\n}\n\n/**\n * Result of a browser-based inspection\n */\nexport interface BrowserInspectResult {\n /**\n * The security report markdown generated by Rukh API\n */\n report: string;\n\n /**\n * List of JavaScript file paths that were analyzed\n */\n analyzedFiles: string[];\n\n /**\n * The application URL that was inspected\n */\n appUrl: string;\n}\n\n/**\n * Extracts transaction-related code snippets from JavaScript content\n *\n * Scans JavaScript code for keywords related to signing, transactions, and web3 operations,\n * then extracts relevant code snippets with surrounding context.\n *\n * @param content - The JavaScript source code to analyze\n * @param maxLength - Maximum length of extracted snippets in characters\n * @returns Extracted code snippets or a message if no relevant code found\n * @internal\n */\nfunction extractTransactionSnippets(\n content: string,\n maxLength: number = 30000,\n): string {\n const keywords = [\n \"signMessage\",\n \"signTypedData\",\n \"sign(\",\n \"signature\",\n \"sendTransaction\",\n \"transaction\",\n \"eth_sign\",\n \"Contract(\",\n \"ethers.Contract\",\n \"new Contract\",\n \"w3pk\",\n \"Web3Passkey\",\n \"useW3PK\",\n \"wallet\",\n \"signer\",\n \"provider\",\n \"authorization\",\n \"delegation\",\n \"EIP7702\",\n ];\n\n const lines = content.split(\"\\n\");\n const relevantLines: string[] = [];\n const maxLines = 500;\n\n for (let i = 0; i < lines.length && relevantLines.length < maxLines; i++) {\n const line = lines[i];\n const lowerLine = line.toLowerCase();\n\n if (keywords.some((kw) => lowerLine.includes(kw.toLowerCase()))) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n\n for (let j = start; j < end; j++) {\n if (!relevantLines.includes(lines[j])) {\n relevantLines.push(lines[j]);\n }\n }\n }\n }\n\n const snippet = relevantLines.join(\"\\n\");\n\n if (snippet.length > maxLength) {\n return snippet.substring(0, maxLength) + \"\\n\\n// ... (truncated)\";\n }\n\n return snippet || \"// No transaction code found\";\n}\n\n/**\n * Fetches JavaScript source code from the currently running application\n *\n * Discovers and fetches all script tags in the current page, extracts transaction-related\n * snippets, and formats them as markdown for analysis.\n *\n * @param appUrl - The base URL of the application being inspected\n * @param maxTotalSizeKB - Maximum total size in KB for all collected code\n * @returns Markdown-formatted source code with transaction-related snippets\n * @internal\n */\nasync function fetchAppSource(appUrl: string, maxTotalSizeKB: number = 100): Promise<string> {\n let markdown = `# Application Code Analysis\\n\\n`;\n markdown += `**App URL:** ${appUrl}\\n\\n`;\n markdown += `**Note:** Only transaction-related code snippets shown\\n\\n`;\n markdown += `---\\n\\n`;\n\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const scriptUrls = scripts\n .map((script) => (script as HTMLScriptElement).src)\n .filter(\n (src) =>\n src &&\n !src.includes(\"node_modules\") &&\n !src.includes(\"chrome-extension\"),\n );\n\n markdown += `## JavaScript Files (${scriptUrls.length})\\n\\n`;\n\n let totalSnippets = 0;\n let cumulativeSizeKB = 0;\n const maxTotalBytes = maxTotalSizeKB * 1024;\n\n for (const scriptUrl of scriptUrls.slice(0, 15)) {\n // Check if we've reached the size limit\n if (cumulativeSizeKB >= maxTotalSizeKB) {\n console.warn(`[W3PK Inspect] Reached total size limit of ${maxTotalSizeKB} KB - stopping collection`);\n markdown += `\\n**Note:** Collection stopped - reached ${maxTotalSizeKB} KB limit\\n`;\n break;\n }\n\n try {\n const response = await fetch(scriptUrl);\n if (!response.ok) continue;\n\n const content = await response.text();\n const snippets = extractTransactionSnippets(content);\n\n if (snippets && !snippets.includes(\"No transaction code found\")) {\n const snippetSize = new Blob([snippets]).size / 1024;\n\n // Check if adding this snippet would exceed the limit\n if (cumulativeSizeKB + snippetSize > maxTotalSizeKB) {\n console.warn(`[W3PK Inspect] Skipping ${new URL(scriptUrl).pathname} - would exceed total size limit`);\n break;\n }\n\n markdown += `### \\`${new URL(scriptUrl).pathname}\\`\\n\\n`;\n markdown += \"```javascript\\n\";\n markdown += snippets;\n markdown += \"\\n```\\n\\n---\\n\\n\";\n totalSnippets++;\n cumulativeSizeKB += snippetSize;\n }\n } catch (error) {\n // Skip files that can't be fetched\n }\n }\n\n if (totalSnippets === 0) {\n markdown += `No transaction-related code found in JavaScript files.\\n`;\n }\n\n return markdown;\n}\n\n/**\n * Inspects the currently running web application and returns a security report\n *\n * This function can be called by end-users in their browser console to analyze\n * the security of the web application they're currently using.\n *\n * @param options - Configuration options\n * @returns A security report analyzing transaction and signing methods\n *\n * @example\n * ```typescript\n * // In browser console or app code:\n * import { inspect } from 'w3pk';\n *\n * const report = await inspect();\n * console.log(report.report);\n * ```\n *\n * @example\n * ```typescript\n * // With custom options:\n * const report = await inspect({\n * appUrl: 'https://w3pk.w3hc.org',\n * model: 'anthropic',\n * focusMode: 'transactions'\n * });\n * ```\n */\nexport async function inspect(\n options: BrowserInspectOptions = {},\n): Promise<BrowserInspectResult> {\n // Check if running in browser\n if (typeof window === \"undefined\") {\n throw new Error(\n \"Browser inspect() can only be called in browser environments. For Node.js, use the CLI or Node.js API.\",\n );\n }\n\n const {\n appUrl = window.location.origin,\n rukhUrl = \"https://rukh.w3hc.org\",\n context = \"w3pk\",\n model = \"anthropic\",\n focusMode = \"transactions\",\n maxTotalSizeKB = 100,\n } = options;\n\n console.log(\"[W3PK Inspect] Starting inspection of\", appUrl);\n console.log(\"[W3PK Inspect] Focus mode:\", focusMode);\n console.log(\"[W3PK Inspect] Max total size:\", maxTotalSizeKB, \"KB\");\n\n // Fetch and analyze source code\n const sourceMarkdown = await fetchAppSource(appUrl, maxTotalSizeKB);\n\n console.log(\"[W3PK Inspect] Collected source code, sending to Rukh API...\");\n\n // Prepare request to Rukh API\n const message =\n \"Analyze this web application and provide a security report listing all transaction and signing methods.\";\n\n const formData = new FormData();\n formData.append(\"message\", message);\n formData.append(\"model\", model);\n formData.append(\"context\", context);\n\n // Create blob from markdown\n const blob = new Blob([sourceMarkdown], { type: \"text/markdown\" });\n formData.append(\"file\", blob, \"app-source.md\");\n\n // Send to Rukh API\n const response = await fetch(`${rukhUrl}/ask`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Rukh API error: ${response.status} - ${error}`);\n }\n\n const data = await response.json();\n const report =\n data.output || data.response || data.message || JSON.stringify(data);\n\n console.log(\"[W3PK Inspect] Analysis complete!\");\n\n // Extract script URLs for analyzedFiles\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const analyzedFiles = scripts\n .map((script) => new URL((script as HTMLScriptElement).src).pathname)\n .filter((src) => src && !src.includes(\"node_modules\"));\n\n return {\n report,\n analyzedFiles,\n appUrl,\n };\n}\n\n/**\n * Quick inspection helper that logs the report to console\n * Perfect for use in browser DevTools console\n *\n * @example\n * ```javascript\n * // In browser console:\n * await w3pk.inspectNow()\n * ```\n */\nexport async function inspectNow(\n options?: BrowserInspectOptions,\n): Promise<void> {\n console.log(\"š W3PK Security Inspection Starting...\\n\");\n\n try {\n const result = await inspect(options);\n\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\"š SECURITY REPORT\");\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\\n\");\n console.log(result.report);\n console.log(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\n `ā
Analyzed ${result.analyzedFiles.length} files from ${result.appUrl}`,\n );\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n } catch (error) {\n console.error(\"ā Inspection failed:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/inspect/browser.mjs
CHANGED
|
@@ -43,7 +43,7 @@ function extractTransactionSnippets(content, maxLength = 3e4) {
|
|
|
43
43
|
}
|
|
44
44
|
return snippet || "// No transaction code found";
|
|
45
45
|
}
|
|
46
|
-
async function fetchAppSource(appUrl) {
|
|
46
|
+
async function fetchAppSource(appUrl, maxTotalSizeKB = 100) {
|
|
47
47
|
let markdown = `# Application Code Analysis
|
|
48
48
|
|
|
49
49
|
`;
|
|
@@ -64,13 +64,27 @@ async function fetchAppSource(appUrl) {
|
|
|
64
64
|
|
|
65
65
|
`;
|
|
66
66
|
let totalSnippets = 0;
|
|
67
|
+
let cumulativeSizeKB = 0;
|
|
68
|
+
const maxTotalBytes = maxTotalSizeKB * 1024;
|
|
67
69
|
for (const scriptUrl of scriptUrls.slice(0, 15)) {
|
|
70
|
+
if (cumulativeSizeKB >= maxTotalSizeKB) {
|
|
71
|
+
console.warn(`[W3PK Inspect] Reached total size limit of ${maxTotalSizeKB} KB - stopping collection`);
|
|
72
|
+
markdown += `
|
|
73
|
+
**Note:** Collection stopped - reached ${maxTotalSizeKB} KB limit
|
|
74
|
+
`;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
68
77
|
try {
|
|
69
78
|
const response = await fetch(scriptUrl);
|
|
70
79
|
if (!response.ok) continue;
|
|
71
80
|
const content = await response.text();
|
|
72
81
|
const snippets = extractTransactionSnippets(content);
|
|
73
82
|
if (snippets && !snippets.includes("No transaction code found")) {
|
|
83
|
+
const snippetSize = new Blob([snippets]).size / 1024;
|
|
84
|
+
if (cumulativeSizeKB + snippetSize > maxTotalSizeKB) {
|
|
85
|
+
console.warn(`[W3PK Inspect] Skipping ${new URL(scriptUrl).pathname} - would exceed total size limit`);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
74
88
|
markdown += `### \`${new URL(scriptUrl).pathname}\`
|
|
75
89
|
|
|
76
90
|
`;
|
|
@@ -78,6 +92,7 @@ async function fetchAppSource(appUrl) {
|
|
|
78
92
|
markdown += snippets;
|
|
79
93
|
markdown += "\n```\n\n---\n\n";
|
|
80
94
|
totalSnippets++;
|
|
95
|
+
cumulativeSizeKB += snippetSize;
|
|
81
96
|
}
|
|
82
97
|
} catch (error) {
|
|
83
98
|
}
|
|
@@ -99,11 +114,13 @@ async function inspect(options = {}) {
|
|
|
99
114
|
rukhUrl = "https://rukh.w3hc.org",
|
|
100
115
|
context = "w3pk",
|
|
101
116
|
model = "anthropic",
|
|
102
|
-
focusMode = "transactions"
|
|
117
|
+
focusMode = "transactions",
|
|
118
|
+
maxTotalSizeKB = 100
|
|
103
119
|
} = options;
|
|
104
120
|
console.log("[W3PK Inspect] Starting inspection of", appUrl);
|
|
105
121
|
console.log("[W3PK Inspect] Focus mode:", focusMode);
|
|
106
|
-
|
|
122
|
+
console.log("[W3PK Inspect] Max total size:", maxTotalSizeKB, "KB");
|
|
123
|
+
const sourceMarkdown = await fetchAppSource(appUrl, maxTotalSizeKB);
|
|
107
124
|
console.log("[W3PK Inspect] Collected source code, sending to Rukh API...");
|
|
108
125
|
const message = "Analyze this web application and provide a security report listing all transaction and signing methods.";
|
|
109
126
|
const formData = new FormData();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/inspect/browser.ts"],"sourcesContent":["/**\n * Browser Inspection Module\n *\n * Provides client-side code inspection capabilities for analyzing running web3 applications.\n * Fetches JavaScript sources from the current page and analyzes transaction/signing patterns\n * to generate security reports via the Rukh API.\n *\n * This module is designed to be used directly in the browser console or embedded in\n * web applications to help end-users understand the security posture of the apps they use.\n *\n * @module inspect/browser\n */\n\n/**\n * Configuration options for browser-based application inspection\n */\nexport interface BrowserInspectOptions {\n /**\n * The origin/URL of the app to inspect\n * @default window.location.origin\n */\n appUrl?: string;\n\n /**\n * Rukh API endpoint\n * @default 'https://rukh.w3hc.org'\n */\n rukhUrl?: string;\n\n /**\n * Context to use for analysis\n * @default 'w3pk'\n */\n context?: string;\n\n /**\n * AI model to use\n * @default 'anthropic'\n */\n model?: \"anthropic\" | \"mistral\" | \"openai\";\n\n /**\n * Focus mode for analysis\n * @default 'transactions'\n */\n focusMode?: \"transactions\" | \"all\";\n}\n\n/**\n * Result of a browser-based inspection\n */\nexport interface BrowserInspectResult {\n /**\n * The security report markdown generated by Rukh API\n */\n report: string;\n\n /**\n * List of JavaScript file paths that were analyzed\n */\n analyzedFiles: string[];\n\n /**\n * The application URL that was inspected\n */\n appUrl: string;\n}\n\n/**\n * Extracts transaction-related code snippets from JavaScript content\n *\n * Scans JavaScript code for keywords related to signing, transactions, and web3 operations,\n * then extracts relevant code snippets with surrounding context.\n *\n * @param content - The JavaScript source code to analyze\n * @param maxLength - Maximum length of extracted snippets in characters\n * @returns Extracted code snippets or a message if no relevant code found\n * @internal\n */\nfunction extractTransactionSnippets(\n content: string,\n maxLength: number = 30000,\n): string {\n const keywords = [\n \"signMessage\",\n \"signTypedData\",\n \"sign(\",\n \"signature\",\n \"sendTransaction\",\n \"transaction\",\n \"eth_sign\",\n \"Contract(\",\n \"ethers.Contract\",\n \"new Contract\",\n \"w3pk\",\n \"Web3Passkey\",\n \"useW3PK\",\n \"wallet\",\n \"signer\",\n \"provider\",\n \"authorization\",\n \"delegation\",\n \"EIP7702\",\n ];\n\n const lines = content.split(\"\\n\");\n const relevantLines: string[] = [];\n const maxLines = 500;\n\n for (let i = 0; i < lines.length && relevantLines.length < maxLines; i++) {\n const line = lines[i];\n const lowerLine = line.toLowerCase();\n\n if (keywords.some((kw) => lowerLine.includes(kw.toLowerCase()))) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n\n for (let j = start; j < end; j++) {\n if (!relevantLines.includes(lines[j])) {\n relevantLines.push(lines[j]);\n }\n }\n }\n }\n\n const snippet = relevantLines.join(\"\\n\");\n\n if (snippet.length > maxLength) {\n return snippet.substring(0, maxLength) + \"\\n\\n// ... (truncated)\";\n }\n\n return snippet || \"// No transaction code found\";\n}\n\n/**\n * Fetches JavaScript source code from the currently running application\n *\n * Discovers and fetches all script tags in the current page, extracts transaction-related\n * snippets, and formats them as markdown for analysis.\n *\n * @param appUrl - The base URL of the application being inspected\n * @returns Markdown-formatted source code with transaction-related snippets\n * @internal\n */\nasync function fetchAppSource(appUrl: string): Promise<string> {\n let markdown = `# Application Code Analysis\\n\\n`;\n markdown += `**App URL:** ${appUrl}\\n\\n`;\n markdown += `**Note:** Only transaction-related code snippets shown\\n\\n`;\n markdown += `---\\n\\n`;\n\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const scriptUrls = scripts\n .map((script) => (script as HTMLScriptElement).src)\n .filter(\n (src) =>\n src &&\n !src.includes(\"node_modules\") &&\n !src.includes(\"chrome-extension\"),\n );\n\n markdown += `## JavaScript Files (${scriptUrls.length})\\n\\n`;\n\n let totalSnippets = 0;\n\n for (const scriptUrl of scriptUrls.slice(0, 15)) {\n try {\n const response = await fetch(scriptUrl);\n if (!response.ok) continue;\n\n const content = await response.text();\n const snippets = extractTransactionSnippets(content);\n\n if (snippets && !snippets.includes(\"No transaction code found\")) {\n markdown += `### \\`${new URL(scriptUrl).pathname}\\`\\n\\n`;\n markdown += \"```javascript\\n\";\n markdown += snippets;\n markdown += \"\\n```\\n\\n---\\n\\n\";\n totalSnippets++;\n }\n } catch (error) {\n // Skip files that can't be fetched\n }\n }\n\n if (totalSnippets === 0) {\n markdown += `No transaction-related code found in JavaScript files.\\n`;\n }\n\n return markdown;\n}\n\n/**\n * Inspects the currently running web application and returns a security report\n *\n * This function can be called by end-users in their browser console to analyze\n * the security of the web application they're currently using.\n *\n * @param options - Configuration options\n * @returns A security report analyzing transaction and signing methods\n *\n * @example\n * ```typescript\n * // In browser console or app code:\n * import { inspect } from 'w3pk';\n *\n * const report = await inspect();\n * console.log(report.report);\n * ```\n *\n * @example\n * ```typescript\n * // With custom options:\n * const report = await inspect({\n * appUrl: 'https://w3pk.w3hc.org',\n * model: 'anthropic',\n * focusMode: 'transactions'\n * });\n * ```\n */\nexport async function inspect(\n options: BrowserInspectOptions = {},\n): Promise<BrowserInspectResult> {\n // Check if running in browser\n if (typeof window === \"undefined\") {\n throw new Error(\n \"Browser inspect() can only be called in browser environments. For Node.js, use the CLI or Node.js API.\",\n );\n }\n\n const {\n appUrl = window.location.origin,\n rukhUrl = \"https://rukh.w3hc.org\",\n context = \"w3pk\",\n model = \"anthropic\",\n focusMode = \"transactions\",\n } = options;\n\n console.log(\"[W3PK Inspect] Starting inspection of\", appUrl);\n console.log(\"[W3PK Inspect] Focus mode:\", focusMode);\n\n // Fetch and analyze source code\n const sourceMarkdown = await fetchAppSource(appUrl);\n\n console.log(\"[W3PK Inspect] Collected source code, sending to Rukh API...\");\n\n // Prepare request to Rukh API\n const message =\n \"Analyze this web application and provide a security report listing all transaction and signing methods.\";\n\n const formData = new FormData();\n formData.append(\"message\", message);\n formData.append(\"model\", model);\n formData.append(\"context\", context);\n\n // Create blob from markdown\n const blob = new Blob([sourceMarkdown], { type: \"text/markdown\" });\n formData.append(\"file\", blob, \"app-source.md\");\n\n // Send to Rukh API\n const response = await fetch(`${rukhUrl}/ask`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Rukh API error: ${response.status} - ${error}`);\n }\n\n const data = await response.json();\n const report =\n data.output || data.response || data.message || JSON.stringify(data);\n\n console.log(\"[W3PK Inspect] Analysis complete!\");\n\n // Extract script URLs for analyzedFiles\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const analyzedFiles = scripts\n .map((script) => new URL((script as HTMLScriptElement).src).pathname)\n .filter((src) => src && !src.includes(\"node_modules\"));\n\n return {\n report,\n analyzedFiles,\n appUrl,\n };\n}\n\n/**\n * Quick inspection helper that logs the report to console\n * Perfect for use in browser DevTools console\n *\n * @example\n * ```javascript\n * // In browser console:\n * await w3pk.inspectNow()\n * ```\n */\nexport async function inspectNow(\n options?: BrowserInspectOptions,\n): Promise<void> {\n console.log(\"š W3PK Security Inspection Starting...\\n\");\n\n try {\n const result = await inspect(options);\n\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\"š SECURITY REPORT\");\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\\n\");\n console.log(result.report);\n console.log(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\n `ā
Analyzed ${result.analyzedFiles.length} files from ${result.appUrl}`,\n );\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n } catch (error) {\n console.error(\"ā Inspection failed:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/inspect/browser.ts"],"sourcesContent":["/**\n * Browser Inspection Module\n *\n * Provides client-side code inspection capabilities for analyzing running web3 applications.\n * Fetches JavaScript sources from the current page and analyzes transaction/signing patterns\n * to generate security reports via the Rukh API.\n *\n * This module is designed to be used directly in the browser console or embedded in\n * web applications to help end-users understand the security posture of the apps they use.\n *\n * @module inspect/browser\n */\n\n/**\n * Configuration options for browser-based application inspection\n */\nexport interface BrowserInspectOptions {\n /**\n * The origin/URL of the app to inspect\n * @default window.location.origin\n */\n appUrl?: string;\n\n /**\n * Rukh API endpoint\n * @default 'https://rukh.w3hc.org'\n */\n rukhUrl?: string;\n\n /**\n * Context to use for analysis\n * @default 'w3pk'\n */\n context?: string;\n\n /**\n * AI model to use\n * @default 'anthropic'\n */\n model?: \"anthropic\" | \"mistral\" | \"openai\";\n\n /**\n * Focus mode for analysis\n * @default 'transactions'\n */\n focusMode?: \"transactions\" | \"all\";\n\n /**\n * Maximum total size in KB for all collected code (prevents exceeding API token limits)\n * @default 100\n */\n maxTotalSizeKB?: number;\n}\n\n/**\n * Result of a browser-based inspection\n */\nexport interface BrowserInspectResult {\n /**\n * The security report markdown generated by Rukh API\n */\n report: string;\n\n /**\n * List of JavaScript file paths that were analyzed\n */\n analyzedFiles: string[];\n\n /**\n * The application URL that was inspected\n */\n appUrl: string;\n}\n\n/**\n * Extracts transaction-related code snippets from JavaScript content\n *\n * Scans JavaScript code for keywords related to signing, transactions, and web3 operations,\n * then extracts relevant code snippets with surrounding context.\n *\n * @param content - The JavaScript source code to analyze\n * @param maxLength - Maximum length of extracted snippets in characters\n * @returns Extracted code snippets or a message if no relevant code found\n * @internal\n */\nfunction extractTransactionSnippets(\n content: string,\n maxLength: number = 30000,\n): string {\n const keywords = [\n \"signMessage\",\n \"signTypedData\",\n \"sign(\",\n \"signature\",\n \"sendTransaction\",\n \"transaction\",\n \"eth_sign\",\n \"Contract(\",\n \"ethers.Contract\",\n \"new Contract\",\n \"w3pk\",\n \"Web3Passkey\",\n \"useW3PK\",\n \"wallet\",\n \"signer\",\n \"provider\",\n \"authorization\",\n \"delegation\",\n \"EIP7702\",\n ];\n\n const lines = content.split(\"\\n\");\n const relevantLines: string[] = [];\n const maxLines = 500;\n\n for (let i = 0; i < lines.length && relevantLines.length < maxLines; i++) {\n const line = lines[i];\n const lowerLine = line.toLowerCase();\n\n if (keywords.some((kw) => lowerLine.includes(kw.toLowerCase()))) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n\n for (let j = start; j < end; j++) {\n if (!relevantLines.includes(lines[j])) {\n relevantLines.push(lines[j]);\n }\n }\n }\n }\n\n const snippet = relevantLines.join(\"\\n\");\n\n if (snippet.length > maxLength) {\n return snippet.substring(0, maxLength) + \"\\n\\n// ... (truncated)\";\n }\n\n return snippet || \"// No transaction code found\";\n}\n\n/**\n * Fetches JavaScript source code from the currently running application\n *\n * Discovers and fetches all script tags in the current page, extracts transaction-related\n * snippets, and formats them as markdown for analysis.\n *\n * @param appUrl - The base URL of the application being inspected\n * @param maxTotalSizeKB - Maximum total size in KB for all collected code\n * @returns Markdown-formatted source code with transaction-related snippets\n * @internal\n */\nasync function fetchAppSource(appUrl: string, maxTotalSizeKB: number = 100): Promise<string> {\n let markdown = `# Application Code Analysis\\n\\n`;\n markdown += `**App URL:** ${appUrl}\\n\\n`;\n markdown += `**Note:** Only transaction-related code snippets shown\\n\\n`;\n markdown += `---\\n\\n`;\n\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const scriptUrls = scripts\n .map((script) => (script as HTMLScriptElement).src)\n .filter(\n (src) =>\n src &&\n !src.includes(\"node_modules\") &&\n !src.includes(\"chrome-extension\"),\n );\n\n markdown += `## JavaScript Files (${scriptUrls.length})\\n\\n`;\n\n let totalSnippets = 0;\n let cumulativeSizeKB = 0;\n const maxTotalBytes = maxTotalSizeKB * 1024;\n\n for (const scriptUrl of scriptUrls.slice(0, 15)) {\n // Check if we've reached the size limit\n if (cumulativeSizeKB >= maxTotalSizeKB) {\n console.warn(`[W3PK Inspect] Reached total size limit of ${maxTotalSizeKB} KB - stopping collection`);\n markdown += `\\n**Note:** Collection stopped - reached ${maxTotalSizeKB} KB limit\\n`;\n break;\n }\n\n try {\n const response = await fetch(scriptUrl);\n if (!response.ok) continue;\n\n const content = await response.text();\n const snippets = extractTransactionSnippets(content);\n\n if (snippets && !snippets.includes(\"No transaction code found\")) {\n const snippetSize = new Blob([snippets]).size / 1024;\n\n // Check if adding this snippet would exceed the limit\n if (cumulativeSizeKB + snippetSize > maxTotalSizeKB) {\n console.warn(`[W3PK Inspect] Skipping ${new URL(scriptUrl).pathname} - would exceed total size limit`);\n break;\n }\n\n markdown += `### \\`${new URL(scriptUrl).pathname}\\`\\n\\n`;\n markdown += \"```javascript\\n\";\n markdown += snippets;\n markdown += \"\\n```\\n\\n---\\n\\n\";\n totalSnippets++;\n cumulativeSizeKB += snippetSize;\n }\n } catch (error) {\n // Skip files that can't be fetched\n }\n }\n\n if (totalSnippets === 0) {\n markdown += `No transaction-related code found in JavaScript files.\\n`;\n }\n\n return markdown;\n}\n\n/**\n * Inspects the currently running web application and returns a security report\n *\n * This function can be called by end-users in their browser console to analyze\n * the security of the web application they're currently using.\n *\n * @param options - Configuration options\n * @returns A security report analyzing transaction and signing methods\n *\n * @example\n * ```typescript\n * // In browser console or app code:\n * import { inspect } from 'w3pk';\n *\n * const report = await inspect();\n * console.log(report.report);\n * ```\n *\n * @example\n * ```typescript\n * // With custom options:\n * const report = await inspect({\n * appUrl: 'https://w3pk.w3hc.org',\n * model: 'anthropic',\n * focusMode: 'transactions'\n * });\n * ```\n */\nexport async function inspect(\n options: BrowserInspectOptions = {},\n): Promise<BrowserInspectResult> {\n // Check if running in browser\n if (typeof window === \"undefined\") {\n throw new Error(\n \"Browser inspect() can only be called in browser environments. For Node.js, use the CLI or Node.js API.\",\n );\n }\n\n const {\n appUrl = window.location.origin,\n rukhUrl = \"https://rukh.w3hc.org\",\n context = \"w3pk\",\n model = \"anthropic\",\n focusMode = \"transactions\",\n maxTotalSizeKB = 100,\n } = options;\n\n console.log(\"[W3PK Inspect] Starting inspection of\", appUrl);\n console.log(\"[W3PK Inspect] Focus mode:\", focusMode);\n console.log(\"[W3PK Inspect] Max total size:\", maxTotalSizeKB, \"KB\");\n\n // Fetch and analyze source code\n const sourceMarkdown = await fetchAppSource(appUrl, maxTotalSizeKB);\n\n console.log(\"[W3PK Inspect] Collected source code, sending to Rukh API...\");\n\n // Prepare request to Rukh API\n const message =\n \"Analyze this web application and provide a security report listing all transaction and signing methods.\";\n\n const formData = new FormData();\n formData.append(\"message\", message);\n formData.append(\"model\", model);\n formData.append(\"context\", context);\n\n // Create blob from markdown\n const blob = new Blob([sourceMarkdown], { type: \"text/markdown\" });\n formData.append(\"file\", blob, \"app-source.md\");\n\n // Send to Rukh API\n const response = await fetch(`${rukhUrl}/ask`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Rukh API error: ${response.status} - ${error}`);\n }\n\n const data = await response.json();\n const report =\n data.output || data.response || data.message || JSON.stringify(data);\n\n console.log(\"[W3PK Inspect] Analysis complete!\");\n\n // Extract script URLs for analyzedFiles\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const analyzedFiles = scripts\n .map((script) => new URL((script as HTMLScriptElement).src).pathname)\n .filter((src) => src && !src.includes(\"node_modules\"));\n\n return {\n report,\n analyzedFiles,\n appUrl,\n };\n}\n\n/**\n * Quick inspection helper that logs the report to console\n * Perfect for use in browser DevTools console\n *\n * @example\n * ```javascript\n * // In browser console:\n * await w3pk.inspectNow()\n * ```\n */\nexport async function inspectNow(\n options?: BrowserInspectOptions,\n): Promise<void> {\n console.log(\"š W3PK Security Inspection Starting...\\n\");\n\n try {\n const result = await inspect(options);\n\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\"š SECURITY REPORT\");\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\\n\");\n console.log(result.report);\n console.log(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\n `ā
Analyzed ${result.analyzedFiles.length} files from ${result.appUrl}`,\n );\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n } catch (error) {\n console.error(\"ā Inspection failed:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/inspect/index.js
CHANGED
|
@@ -70,7 +70,7 @@ function extractTransactionSnippets(content, maxLength = 3e4) {
|
|
|
70
70
|
}
|
|
71
71
|
return snippet || "// No transaction code found";
|
|
72
72
|
}
|
|
73
|
-
async function fetchAppSource(appUrl) {
|
|
73
|
+
async function fetchAppSource(appUrl, maxTotalSizeKB = 100) {
|
|
74
74
|
let markdown = `# Application Code Analysis
|
|
75
75
|
|
|
76
76
|
`;
|
|
@@ -91,13 +91,27 @@ async function fetchAppSource(appUrl) {
|
|
|
91
91
|
|
|
92
92
|
`;
|
|
93
93
|
let totalSnippets = 0;
|
|
94
|
+
let cumulativeSizeKB = 0;
|
|
95
|
+
const maxTotalBytes = maxTotalSizeKB * 1024;
|
|
94
96
|
for (const scriptUrl of scriptUrls.slice(0, 15)) {
|
|
97
|
+
if (cumulativeSizeKB >= maxTotalSizeKB) {
|
|
98
|
+
console.warn(`[W3PK Inspect] Reached total size limit of ${maxTotalSizeKB} KB - stopping collection`);
|
|
99
|
+
markdown += `
|
|
100
|
+
**Note:** Collection stopped - reached ${maxTotalSizeKB} KB limit
|
|
101
|
+
`;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
95
104
|
try {
|
|
96
105
|
const response = await fetch(scriptUrl);
|
|
97
106
|
if (!response.ok) continue;
|
|
98
107
|
const content = await response.text();
|
|
99
108
|
const snippets = extractTransactionSnippets(content);
|
|
100
109
|
if (snippets && !snippets.includes("No transaction code found")) {
|
|
110
|
+
const snippetSize = new Blob([snippets]).size / 1024;
|
|
111
|
+
if (cumulativeSizeKB + snippetSize > maxTotalSizeKB) {
|
|
112
|
+
console.warn(`[W3PK Inspect] Skipping ${new URL(scriptUrl).pathname} - would exceed total size limit`);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
101
115
|
markdown += `### \`${new URL(scriptUrl).pathname}\`
|
|
102
116
|
|
|
103
117
|
`;
|
|
@@ -105,6 +119,7 @@ async function fetchAppSource(appUrl) {
|
|
|
105
119
|
markdown += snippets;
|
|
106
120
|
markdown += "\n```\n\n---\n\n";
|
|
107
121
|
totalSnippets++;
|
|
122
|
+
cumulativeSizeKB += snippetSize;
|
|
108
123
|
}
|
|
109
124
|
} catch (error) {
|
|
110
125
|
}
|
|
@@ -126,11 +141,13 @@ async function inspect(options = {}) {
|
|
|
126
141
|
rukhUrl = "https://rukh.w3hc.org",
|
|
127
142
|
context = "w3pk",
|
|
128
143
|
model = "anthropic",
|
|
129
|
-
focusMode = "transactions"
|
|
144
|
+
focusMode = "transactions",
|
|
145
|
+
maxTotalSizeKB = 100
|
|
130
146
|
} = options;
|
|
131
147
|
console.log("[W3PK Inspect] Starting inspection of", appUrl);
|
|
132
148
|
console.log("[W3PK Inspect] Focus mode:", focusMode);
|
|
133
|
-
|
|
149
|
+
console.log("[W3PK Inspect] Max total size:", maxTotalSizeKB, "KB");
|
|
150
|
+
const sourceMarkdown = await fetchAppSource(appUrl, maxTotalSizeKB);
|
|
134
151
|
console.log("[W3PK Inspect] Collected source code, sending to Rukh API...");
|
|
135
152
|
const message = "Analyze this web application and provide a security report listing all transaction and signing methods.";
|
|
136
153
|
const formData = new FormData();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/inspect/index.ts","../../src/inspect/browser.ts"],"sourcesContent":["/**\n * Inspection module - browser-compatible by default\n *\n * This is the default export for browsers. It analyzes the currently running application.\n * For Node.js filesystem scanning, use: import { inspectNode } from 'w3pk/inspect/node'\n */\n\n// Browser version (default)\nexport { inspect, inspectNow } from './browser';\nexport type { BrowserInspectOptions, BrowserInspectResult } from './browser';\n","/**\n * Browser Inspection Module\n *\n * Provides client-side code inspection capabilities for analyzing running web3 applications.\n * Fetches JavaScript sources from the current page and analyzes transaction/signing patterns\n * to generate security reports via the Rukh API.\n *\n * This module is designed to be used directly in the browser console or embedded in\n * web applications to help end-users understand the security posture of the apps they use.\n *\n * @module inspect/browser\n */\n\n/**\n * Configuration options for browser-based application inspection\n */\nexport interface BrowserInspectOptions {\n /**\n * The origin/URL of the app to inspect\n * @default window.location.origin\n */\n appUrl?: string;\n\n /**\n * Rukh API endpoint\n * @default 'https://rukh.w3hc.org'\n */\n rukhUrl?: string;\n\n /**\n * Context to use for analysis\n * @default 'w3pk'\n */\n context?: string;\n\n /**\n * AI model to use\n * @default 'anthropic'\n */\n model?: \"anthropic\" | \"mistral\" | \"openai\";\n\n /**\n * Focus mode for analysis\n * @default 'transactions'\n */\n focusMode?: \"transactions\" | \"all\";\n}\n\n/**\n * Result of a browser-based inspection\n */\nexport interface BrowserInspectResult {\n /**\n * The security report markdown generated by Rukh API\n */\n report: string;\n\n /**\n * List of JavaScript file paths that were analyzed\n */\n analyzedFiles: string[];\n\n /**\n * The application URL that was inspected\n */\n appUrl: string;\n}\n\n/**\n * Extracts transaction-related code snippets from JavaScript content\n *\n * Scans JavaScript code for keywords related to signing, transactions, and web3 operations,\n * then extracts relevant code snippets with surrounding context.\n *\n * @param content - The JavaScript source code to analyze\n * @param maxLength - Maximum length of extracted snippets in characters\n * @returns Extracted code snippets or a message if no relevant code found\n * @internal\n */\nfunction extractTransactionSnippets(\n content: string,\n maxLength: number = 30000,\n): string {\n const keywords = [\n \"signMessage\",\n \"signTypedData\",\n \"sign(\",\n \"signature\",\n \"sendTransaction\",\n \"transaction\",\n \"eth_sign\",\n \"Contract(\",\n \"ethers.Contract\",\n \"new Contract\",\n \"w3pk\",\n \"Web3Passkey\",\n \"useW3PK\",\n \"wallet\",\n \"signer\",\n \"provider\",\n \"authorization\",\n \"delegation\",\n \"EIP7702\",\n ];\n\n const lines = content.split(\"\\n\");\n const relevantLines: string[] = [];\n const maxLines = 500;\n\n for (let i = 0; i < lines.length && relevantLines.length < maxLines; i++) {\n const line = lines[i];\n const lowerLine = line.toLowerCase();\n\n if (keywords.some((kw) => lowerLine.includes(kw.toLowerCase()))) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n\n for (let j = start; j < end; j++) {\n if (!relevantLines.includes(lines[j])) {\n relevantLines.push(lines[j]);\n }\n }\n }\n }\n\n const snippet = relevantLines.join(\"\\n\");\n\n if (snippet.length > maxLength) {\n return snippet.substring(0, maxLength) + \"\\n\\n// ... (truncated)\";\n }\n\n return snippet || \"// No transaction code found\";\n}\n\n/**\n * Fetches JavaScript source code from the currently running application\n *\n * Discovers and fetches all script tags in the current page, extracts transaction-related\n * snippets, and formats them as markdown for analysis.\n *\n * @param appUrl - The base URL of the application being inspected\n * @returns Markdown-formatted source code with transaction-related snippets\n * @internal\n */\nasync function fetchAppSource(appUrl: string): Promise<string> {\n let markdown = `# Application Code Analysis\\n\\n`;\n markdown += `**App URL:** ${appUrl}\\n\\n`;\n markdown += `**Note:** Only transaction-related code snippets shown\\n\\n`;\n markdown += `---\\n\\n`;\n\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const scriptUrls = scripts\n .map((script) => (script as HTMLScriptElement).src)\n .filter(\n (src) =>\n src &&\n !src.includes(\"node_modules\") &&\n !src.includes(\"chrome-extension\"),\n );\n\n markdown += `## JavaScript Files (${scriptUrls.length})\\n\\n`;\n\n let totalSnippets = 0;\n\n for (const scriptUrl of scriptUrls.slice(0, 15)) {\n try {\n const response = await fetch(scriptUrl);\n if (!response.ok) continue;\n\n const content = await response.text();\n const snippets = extractTransactionSnippets(content);\n\n if (snippets && !snippets.includes(\"No transaction code found\")) {\n markdown += `### \\`${new URL(scriptUrl).pathname}\\`\\n\\n`;\n markdown += \"```javascript\\n\";\n markdown += snippets;\n markdown += \"\\n```\\n\\n---\\n\\n\";\n totalSnippets++;\n }\n } catch (error) {\n // Skip files that can't be fetched\n }\n }\n\n if (totalSnippets === 0) {\n markdown += `No transaction-related code found in JavaScript files.\\n`;\n }\n\n return markdown;\n}\n\n/**\n * Inspects the currently running web application and returns a security report\n *\n * This function can be called by end-users in their browser console to analyze\n * the security of the web application they're currently using.\n *\n * @param options - Configuration options\n * @returns A security report analyzing transaction and signing methods\n *\n * @example\n * ```typescript\n * // In browser console or app code:\n * import { inspect } from 'w3pk';\n *\n * const report = await inspect();\n * console.log(report.report);\n * ```\n *\n * @example\n * ```typescript\n * // With custom options:\n * const report = await inspect({\n * appUrl: 'https://w3pk.w3hc.org',\n * model: 'anthropic',\n * focusMode: 'transactions'\n * });\n * ```\n */\nexport async function inspect(\n options: BrowserInspectOptions = {},\n): Promise<BrowserInspectResult> {\n // Check if running in browser\n if (typeof window === \"undefined\") {\n throw new Error(\n \"Browser inspect() can only be called in browser environments. For Node.js, use the CLI or Node.js API.\",\n );\n }\n\n const {\n appUrl = window.location.origin,\n rukhUrl = \"https://rukh.w3hc.org\",\n context = \"w3pk\",\n model = \"anthropic\",\n focusMode = \"transactions\",\n } = options;\n\n console.log(\"[W3PK Inspect] Starting inspection of\", appUrl);\n console.log(\"[W3PK Inspect] Focus mode:\", focusMode);\n\n // Fetch and analyze source code\n const sourceMarkdown = await fetchAppSource(appUrl);\n\n console.log(\"[W3PK Inspect] Collected source code, sending to Rukh API...\");\n\n // Prepare request to Rukh API\n const message =\n \"Analyze this web application and provide a security report listing all transaction and signing methods.\";\n\n const formData = new FormData();\n formData.append(\"message\", message);\n formData.append(\"model\", model);\n formData.append(\"context\", context);\n\n // Create blob from markdown\n const blob = new Blob([sourceMarkdown], { type: \"text/markdown\" });\n formData.append(\"file\", blob, \"app-source.md\");\n\n // Send to Rukh API\n const response = await fetch(`${rukhUrl}/ask`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Rukh API error: ${response.status} - ${error}`);\n }\n\n const data = await response.json();\n const report =\n data.output || data.response || data.message || JSON.stringify(data);\n\n console.log(\"[W3PK Inspect] Analysis complete!\");\n\n // Extract script URLs for analyzedFiles\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const analyzedFiles = scripts\n .map((script) => new URL((script as HTMLScriptElement).src).pathname)\n .filter((src) => src && !src.includes(\"node_modules\"));\n\n return {\n report,\n analyzedFiles,\n appUrl,\n };\n}\n\n/**\n * Quick inspection helper that logs the report to console\n * Perfect for use in browser DevTools console\n *\n * @example\n * ```javascript\n * // In browser console:\n * await w3pk.inspectNow()\n * ```\n */\nexport async function inspectNow(\n options?: BrowserInspectOptions,\n): Promise<void> {\n console.log(\"š W3PK Security Inspection Starting...\\n\");\n\n try {\n const result = await inspect(options);\n\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\"š SECURITY REPORT\");\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\\n\");\n console.log(result.report);\n console.log(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\n `ā
Analyzed ${result.analyzedFiles.length} files from ${result.appUrl}`,\n );\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n } catch (error) {\n console.error(\"ā Inspection failed:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/inspect/index.ts","../../src/inspect/browser.ts"],"sourcesContent":["/**\n * Inspection module - browser-compatible by default\n *\n * This is the default export for browsers. It analyzes the currently running application.\n * For Node.js filesystem scanning, use: import { inspectNode } from 'w3pk/inspect/node'\n */\n\n// Browser version (default)\nexport { inspect, inspectNow } from './browser';\nexport type { BrowserInspectOptions, BrowserInspectResult } from './browser';\n","/**\n * Browser Inspection Module\n *\n * Provides client-side code inspection capabilities for analyzing running web3 applications.\n * Fetches JavaScript sources from the current page and analyzes transaction/signing patterns\n * to generate security reports via the Rukh API.\n *\n * This module is designed to be used directly in the browser console or embedded in\n * web applications to help end-users understand the security posture of the apps they use.\n *\n * @module inspect/browser\n */\n\n/**\n * Configuration options for browser-based application inspection\n */\nexport interface BrowserInspectOptions {\n /**\n * The origin/URL of the app to inspect\n * @default window.location.origin\n */\n appUrl?: string;\n\n /**\n * Rukh API endpoint\n * @default 'https://rukh.w3hc.org'\n */\n rukhUrl?: string;\n\n /**\n * Context to use for analysis\n * @default 'w3pk'\n */\n context?: string;\n\n /**\n * AI model to use\n * @default 'anthropic'\n */\n model?: \"anthropic\" | \"mistral\" | \"openai\";\n\n /**\n * Focus mode for analysis\n * @default 'transactions'\n */\n focusMode?: \"transactions\" | \"all\";\n\n /**\n * Maximum total size in KB for all collected code (prevents exceeding API token limits)\n * @default 100\n */\n maxTotalSizeKB?: number;\n}\n\n/**\n * Result of a browser-based inspection\n */\nexport interface BrowserInspectResult {\n /**\n * The security report markdown generated by Rukh API\n */\n report: string;\n\n /**\n * List of JavaScript file paths that were analyzed\n */\n analyzedFiles: string[];\n\n /**\n * The application URL that was inspected\n */\n appUrl: string;\n}\n\n/**\n * Extracts transaction-related code snippets from JavaScript content\n *\n * Scans JavaScript code for keywords related to signing, transactions, and web3 operations,\n * then extracts relevant code snippets with surrounding context.\n *\n * @param content - The JavaScript source code to analyze\n * @param maxLength - Maximum length of extracted snippets in characters\n * @returns Extracted code snippets or a message if no relevant code found\n * @internal\n */\nfunction extractTransactionSnippets(\n content: string,\n maxLength: number = 30000,\n): string {\n const keywords = [\n \"signMessage\",\n \"signTypedData\",\n \"sign(\",\n \"signature\",\n \"sendTransaction\",\n \"transaction\",\n \"eth_sign\",\n \"Contract(\",\n \"ethers.Contract\",\n \"new Contract\",\n \"w3pk\",\n \"Web3Passkey\",\n \"useW3PK\",\n \"wallet\",\n \"signer\",\n \"provider\",\n \"authorization\",\n \"delegation\",\n \"EIP7702\",\n ];\n\n const lines = content.split(\"\\n\");\n const relevantLines: string[] = [];\n const maxLines = 500;\n\n for (let i = 0; i < lines.length && relevantLines.length < maxLines; i++) {\n const line = lines[i];\n const lowerLine = line.toLowerCase();\n\n if (keywords.some((kw) => lowerLine.includes(kw.toLowerCase()))) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n\n for (let j = start; j < end; j++) {\n if (!relevantLines.includes(lines[j])) {\n relevantLines.push(lines[j]);\n }\n }\n }\n }\n\n const snippet = relevantLines.join(\"\\n\");\n\n if (snippet.length > maxLength) {\n return snippet.substring(0, maxLength) + \"\\n\\n// ... (truncated)\";\n }\n\n return snippet || \"// No transaction code found\";\n}\n\n/**\n * Fetches JavaScript source code from the currently running application\n *\n * Discovers and fetches all script tags in the current page, extracts transaction-related\n * snippets, and formats them as markdown for analysis.\n *\n * @param appUrl - The base URL of the application being inspected\n * @param maxTotalSizeKB - Maximum total size in KB for all collected code\n * @returns Markdown-formatted source code with transaction-related snippets\n * @internal\n */\nasync function fetchAppSource(appUrl: string, maxTotalSizeKB: number = 100): Promise<string> {\n let markdown = `# Application Code Analysis\\n\\n`;\n markdown += `**App URL:** ${appUrl}\\n\\n`;\n markdown += `**Note:** Only transaction-related code snippets shown\\n\\n`;\n markdown += `---\\n\\n`;\n\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const scriptUrls = scripts\n .map((script) => (script as HTMLScriptElement).src)\n .filter(\n (src) =>\n src &&\n !src.includes(\"node_modules\") &&\n !src.includes(\"chrome-extension\"),\n );\n\n markdown += `## JavaScript Files (${scriptUrls.length})\\n\\n`;\n\n let totalSnippets = 0;\n let cumulativeSizeKB = 0;\n const maxTotalBytes = maxTotalSizeKB * 1024;\n\n for (const scriptUrl of scriptUrls.slice(0, 15)) {\n // Check if we've reached the size limit\n if (cumulativeSizeKB >= maxTotalSizeKB) {\n console.warn(`[W3PK Inspect] Reached total size limit of ${maxTotalSizeKB} KB - stopping collection`);\n markdown += `\\n**Note:** Collection stopped - reached ${maxTotalSizeKB} KB limit\\n`;\n break;\n }\n\n try {\n const response = await fetch(scriptUrl);\n if (!response.ok) continue;\n\n const content = await response.text();\n const snippets = extractTransactionSnippets(content);\n\n if (snippets && !snippets.includes(\"No transaction code found\")) {\n const snippetSize = new Blob([snippets]).size / 1024;\n\n // Check if adding this snippet would exceed the limit\n if (cumulativeSizeKB + snippetSize > maxTotalSizeKB) {\n console.warn(`[W3PK Inspect] Skipping ${new URL(scriptUrl).pathname} - would exceed total size limit`);\n break;\n }\n\n markdown += `### \\`${new URL(scriptUrl).pathname}\\`\\n\\n`;\n markdown += \"```javascript\\n\";\n markdown += snippets;\n markdown += \"\\n```\\n\\n---\\n\\n\";\n totalSnippets++;\n cumulativeSizeKB += snippetSize;\n }\n } catch (error) {\n // Skip files that can't be fetched\n }\n }\n\n if (totalSnippets === 0) {\n markdown += `No transaction-related code found in JavaScript files.\\n`;\n }\n\n return markdown;\n}\n\n/**\n * Inspects the currently running web application and returns a security report\n *\n * This function can be called by end-users in their browser console to analyze\n * the security of the web application they're currently using.\n *\n * @param options - Configuration options\n * @returns A security report analyzing transaction and signing methods\n *\n * @example\n * ```typescript\n * // In browser console or app code:\n * import { inspect } from 'w3pk';\n *\n * const report = await inspect();\n * console.log(report.report);\n * ```\n *\n * @example\n * ```typescript\n * // With custom options:\n * const report = await inspect({\n * appUrl: 'https://w3pk.w3hc.org',\n * model: 'anthropic',\n * focusMode: 'transactions'\n * });\n * ```\n */\nexport async function inspect(\n options: BrowserInspectOptions = {},\n): Promise<BrowserInspectResult> {\n // Check if running in browser\n if (typeof window === \"undefined\") {\n throw new Error(\n \"Browser inspect() can only be called in browser environments. For Node.js, use the CLI or Node.js API.\",\n );\n }\n\n const {\n appUrl = window.location.origin,\n rukhUrl = \"https://rukh.w3hc.org\",\n context = \"w3pk\",\n model = \"anthropic\",\n focusMode = \"transactions\",\n maxTotalSizeKB = 100,\n } = options;\n\n console.log(\"[W3PK Inspect] Starting inspection of\", appUrl);\n console.log(\"[W3PK Inspect] Focus mode:\", focusMode);\n console.log(\"[W3PK Inspect] Max total size:\", maxTotalSizeKB, \"KB\");\n\n // Fetch and analyze source code\n const sourceMarkdown = await fetchAppSource(appUrl, maxTotalSizeKB);\n\n console.log(\"[W3PK Inspect] Collected source code, sending to Rukh API...\");\n\n // Prepare request to Rukh API\n const message =\n \"Analyze this web application and provide a security report listing all transaction and signing methods.\";\n\n const formData = new FormData();\n formData.append(\"message\", message);\n formData.append(\"model\", model);\n formData.append(\"context\", context);\n\n // Create blob from markdown\n const blob = new Blob([sourceMarkdown], { type: \"text/markdown\" });\n formData.append(\"file\", blob, \"app-source.md\");\n\n // Send to Rukh API\n const response = await fetch(`${rukhUrl}/ask`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Rukh API error: ${response.status} - ${error}`);\n }\n\n const data = await response.json();\n const report =\n data.output || data.response || data.message || JSON.stringify(data);\n\n console.log(\"[W3PK Inspect] Analysis complete!\");\n\n // Extract script URLs for analyzedFiles\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const analyzedFiles = scripts\n .map((script) => new URL((script as HTMLScriptElement).src).pathname)\n .filter((src) => src && !src.includes(\"node_modules\"));\n\n return {\n report,\n analyzedFiles,\n appUrl,\n };\n}\n\n/**\n * Quick inspection helper that logs the report to console\n * Perfect for use in browser DevTools console\n *\n * @example\n * ```javascript\n * // In browser console:\n * await w3pk.inspectNow()\n * ```\n */\nexport async function inspectNow(\n options?: BrowserInspectOptions,\n): Promise<void> {\n console.log(\"š W3PK Security Inspection Starting...\\n\");\n\n try {\n const result = await inspect(options);\n\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\"š SECURITY REPORT\");\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\\n\");\n console.log(result.report);\n console.log(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\n `ā
Analyzed ${result.analyzedFiles.length} files from ${result.appUrl}`,\n );\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n } catch (error) {\n console.error(\"ā Inspection failed:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/inspect/index.mjs
CHANGED
|
@@ -43,7 +43,7 @@ function extractTransactionSnippets(content, maxLength = 3e4) {
|
|
|
43
43
|
}
|
|
44
44
|
return snippet || "// No transaction code found";
|
|
45
45
|
}
|
|
46
|
-
async function fetchAppSource(appUrl) {
|
|
46
|
+
async function fetchAppSource(appUrl, maxTotalSizeKB = 100) {
|
|
47
47
|
let markdown = `# Application Code Analysis
|
|
48
48
|
|
|
49
49
|
`;
|
|
@@ -64,13 +64,27 @@ async function fetchAppSource(appUrl) {
|
|
|
64
64
|
|
|
65
65
|
`;
|
|
66
66
|
let totalSnippets = 0;
|
|
67
|
+
let cumulativeSizeKB = 0;
|
|
68
|
+
const maxTotalBytes = maxTotalSizeKB * 1024;
|
|
67
69
|
for (const scriptUrl of scriptUrls.slice(0, 15)) {
|
|
70
|
+
if (cumulativeSizeKB >= maxTotalSizeKB) {
|
|
71
|
+
console.warn(`[W3PK Inspect] Reached total size limit of ${maxTotalSizeKB} KB - stopping collection`);
|
|
72
|
+
markdown += `
|
|
73
|
+
**Note:** Collection stopped - reached ${maxTotalSizeKB} KB limit
|
|
74
|
+
`;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
68
77
|
try {
|
|
69
78
|
const response = await fetch(scriptUrl);
|
|
70
79
|
if (!response.ok) continue;
|
|
71
80
|
const content = await response.text();
|
|
72
81
|
const snippets = extractTransactionSnippets(content);
|
|
73
82
|
if (snippets && !snippets.includes("No transaction code found")) {
|
|
83
|
+
const snippetSize = new Blob([snippets]).size / 1024;
|
|
84
|
+
if (cumulativeSizeKB + snippetSize > maxTotalSizeKB) {
|
|
85
|
+
console.warn(`[W3PK Inspect] Skipping ${new URL(scriptUrl).pathname} - would exceed total size limit`);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
74
88
|
markdown += `### \`${new URL(scriptUrl).pathname}\`
|
|
75
89
|
|
|
76
90
|
`;
|
|
@@ -78,6 +92,7 @@ async function fetchAppSource(appUrl) {
|
|
|
78
92
|
markdown += snippets;
|
|
79
93
|
markdown += "\n```\n\n---\n\n";
|
|
80
94
|
totalSnippets++;
|
|
95
|
+
cumulativeSizeKB += snippetSize;
|
|
81
96
|
}
|
|
82
97
|
} catch (error) {
|
|
83
98
|
}
|
|
@@ -99,11 +114,13 @@ async function inspect(options = {}) {
|
|
|
99
114
|
rukhUrl = "https://rukh.w3hc.org",
|
|
100
115
|
context = "w3pk",
|
|
101
116
|
model = "anthropic",
|
|
102
|
-
focusMode = "transactions"
|
|
117
|
+
focusMode = "transactions",
|
|
118
|
+
maxTotalSizeKB = 100
|
|
103
119
|
} = options;
|
|
104
120
|
console.log("[W3PK Inspect] Starting inspection of", appUrl);
|
|
105
121
|
console.log("[W3PK Inspect] Focus mode:", focusMode);
|
|
106
|
-
|
|
122
|
+
console.log("[W3PK Inspect] Max total size:", maxTotalSizeKB, "KB");
|
|
123
|
+
const sourceMarkdown = await fetchAppSource(appUrl, maxTotalSizeKB);
|
|
107
124
|
console.log("[W3PK Inspect] Collected source code, sending to Rukh API...");
|
|
108
125
|
const message = "Analyze this web application and provide a security report listing all transaction and signing methods.";
|
|
109
126
|
const formData = new FormData();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/inspect/browser.ts"],"sourcesContent":["/**\n * Browser Inspection Module\n *\n * Provides client-side code inspection capabilities for analyzing running web3 applications.\n * Fetches JavaScript sources from the current page and analyzes transaction/signing patterns\n * to generate security reports via the Rukh API.\n *\n * This module is designed to be used directly in the browser console or embedded in\n * web applications to help end-users understand the security posture of the apps they use.\n *\n * @module inspect/browser\n */\n\n/**\n * Configuration options for browser-based application inspection\n */\nexport interface BrowserInspectOptions {\n /**\n * The origin/URL of the app to inspect\n * @default window.location.origin\n */\n appUrl?: string;\n\n /**\n * Rukh API endpoint\n * @default 'https://rukh.w3hc.org'\n */\n rukhUrl?: string;\n\n /**\n * Context to use for analysis\n * @default 'w3pk'\n */\n context?: string;\n\n /**\n * AI model to use\n * @default 'anthropic'\n */\n model?: \"anthropic\" | \"mistral\" | \"openai\";\n\n /**\n * Focus mode for analysis\n * @default 'transactions'\n */\n focusMode?: \"transactions\" | \"all\";\n}\n\n/**\n * Result of a browser-based inspection\n */\nexport interface BrowserInspectResult {\n /**\n * The security report markdown generated by Rukh API\n */\n report: string;\n\n /**\n * List of JavaScript file paths that were analyzed\n */\n analyzedFiles: string[];\n\n /**\n * The application URL that was inspected\n */\n appUrl: string;\n}\n\n/**\n * Extracts transaction-related code snippets from JavaScript content\n *\n * Scans JavaScript code for keywords related to signing, transactions, and web3 operations,\n * then extracts relevant code snippets with surrounding context.\n *\n * @param content - The JavaScript source code to analyze\n * @param maxLength - Maximum length of extracted snippets in characters\n * @returns Extracted code snippets or a message if no relevant code found\n * @internal\n */\nfunction extractTransactionSnippets(\n content: string,\n maxLength: number = 30000,\n): string {\n const keywords = [\n \"signMessage\",\n \"signTypedData\",\n \"sign(\",\n \"signature\",\n \"sendTransaction\",\n \"transaction\",\n \"eth_sign\",\n \"Contract(\",\n \"ethers.Contract\",\n \"new Contract\",\n \"w3pk\",\n \"Web3Passkey\",\n \"useW3PK\",\n \"wallet\",\n \"signer\",\n \"provider\",\n \"authorization\",\n \"delegation\",\n \"EIP7702\",\n ];\n\n const lines = content.split(\"\\n\");\n const relevantLines: string[] = [];\n const maxLines = 500;\n\n for (let i = 0; i < lines.length && relevantLines.length < maxLines; i++) {\n const line = lines[i];\n const lowerLine = line.toLowerCase();\n\n if (keywords.some((kw) => lowerLine.includes(kw.toLowerCase()))) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n\n for (let j = start; j < end; j++) {\n if (!relevantLines.includes(lines[j])) {\n relevantLines.push(lines[j]);\n }\n }\n }\n }\n\n const snippet = relevantLines.join(\"\\n\");\n\n if (snippet.length > maxLength) {\n return snippet.substring(0, maxLength) + \"\\n\\n// ... (truncated)\";\n }\n\n return snippet || \"// No transaction code found\";\n}\n\n/**\n * Fetches JavaScript source code from the currently running application\n *\n * Discovers and fetches all script tags in the current page, extracts transaction-related\n * snippets, and formats them as markdown for analysis.\n *\n * @param appUrl - The base URL of the application being inspected\n * @returns Markdown-formatted source code with transaction-related snippets\n * @internal\n */\nasync function fetchAppSource(appUrl: string): Promise<string> {\n let markdown = `# Application Code Analysis\\n\\n`;\n markdown += `**App URL:** ${appUrl}\\n\\n`;\n markdown += `**Note:** Only transaction-related code snippets shown\\n\\n`;\n markdown += `---\\n\\n`;\n\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const scriptUrls = scripts\n .map((script) => (script as HTMLScriptElement).src)\n .filter(\n (src) =>\n src &&\n !src.includes(\"node_modules\") &&\n !src.includes(\"chrome-extension\"),\n );\n\n markdown += `## JavaScript Files (${scriptUrls.length})\\n\\n`;\n\n let totalSnippets = 0;\n\n for (const scriptUrl of scriptUrls.slice(0, 15)) {\n try {\n const response = await fetch(scriptUrl);\n if (!response.ok) continue;\n\n const content = await response.text();\n const snippets = extractTransactionSnippets(content);\n\n if (snippets && !snippets.includes(\"No transaction code found\")) {\n markdown += `### \\`${new URL(scriptUrl).pathname}\\`\\n\\n`;\n markdown += \"```javascript\\n\";\n markdown += snippets;\n markdown += \"\\n```\\n\\n---\\n\\n\";\n totalSnippets++;\n }\n } catch (error) {\n // Skip files that can't be fetched\n }\n }\n\n if (totalSnippets === 0) {\n markdown += `No transaction-related code found in JavaScript files.\\n`;\n }\n\n return markdown;\n}\n\n/**\n * Inspects the currently running web application and returns a security report\n *\n * This function can be called by end-users in their browser console to analyze\n * the security of the web application they're currently using.\n *\n * @param options - Configuration options\n * @returns A security report analyzing transaction and signing methods\n *\n * @example\n * ```typescript\n * // In browser console or app code:\n * import { inspect } from 'w3pk';\n *\n * const report = await inspect();\n * console.log(report.report);\n * ```\n *\n * @example\n * ```typescript\n * // With custom options:\n * const report = await inspect({\n * appUrl: 'https://w3pk.w3hc.org',\n * model: 'anthropic',\n * focusMode: 'transactions'\n * });\n * ```\n */\nexport async function inspect(\n options: BrowserInspectOptions = {},\n): Promise<BrowserInspectResult> {\n // Check if running in browser\n if (typeof window === \"undefined\") {\n throw new Error(\n \"Browser inspect() can only be called in browser environments. For Node.js, use the CLI or Node.js API.\",\n );\n }\n\n const {\n appUrl = window.location.origin,\n rukhUrl = \"https://rukh.w3hc.org\",\n context = \"w3pk\",\n model = \"anthropic\",\n focusMode = \"transactions\",\n } = options;\n\n console.log(\"[W3PK Inspect] Starting inspection of\", appUrl);\n console.log(\"[W3PK Inspect] Focus mode:\", focusMode);\n\n // Fetch and analyze source code\n const sourceMarkdown = await fetchAppSource(appUrl);\n\n console.log(\"[W3PK Inspect] Collected source code, sending to Rukh API...\");\n\n // Prepare request to Rukh API\n const message =\n \"Analyze this web application and provide a security report listing all transaction and signing methods.\";\n\n const formData = new FormData();\n formData.append(\"message\", message);\n formData.append(\"model\", model);\n formData.append(\"context\", context);\n\n // Create blob from markdown\n const blob = new Blob([sourceMarkdown], { type: \"text/markdown\" });\n formData.append(\"file\", blob, \"app-source.md\");\n\n // Send to Rukh API\n const response = await fetch(`${rukhUrl}/ask`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Rukh API error: ${response.status} - ${error}`);\n }\n\n const data = await response.json();\n const report =\n data.output || data.response || data.message || JSON.stringify(data);\n\n console.log(\"[W3PK Inspect] Analysis complete!\");\n\n // Extract script URLs for analyzedFiles\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const analyzedFiles = scripts\n .map((script) => new URL((script as HTMLScriptElement).src).pathname)\n .filter((src) => src && !src.includes(\"node_modules\"));\n\n return {\n report,\n analyzedFiles,\n appUrl,\n };\n}\n\n/**\n * Quick inspection helper that logs the report to console\n * Perfect for use in browser DevTools console\n *\n * @example\n * ```javascript\n * // In browser console:\n * await w3pk.inspectNow()\n * ```\n */\nexport async function inspectNow(\n options?: BrowserInspectOptions,\n): Promise<void> {\n console.log(\"š W3PK Security Inspection Starting...\\n\");\n\n try {\n const result = await inspect(options);\n\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\"š SECURITY REPORT\");\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\\n\");\n console.log(result.report);\n console.log(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\n `ā
Analyzed ${result.analyzedFiles.length} files from ${result.appUrl}`,\n );\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n } catch (error) {\n console.error(\"ā Inspection failed:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/inspect/browser.ts"],"sourcesContent":["/**\n * Browser Inspection Module\n *\n * Provides client-side code inspection capabilities for analyzing running web3 applications.\n * Fetches JavaScript sources from the current page and analyzes transaction/signing patterns\n * to generate security reports via the Rukh API.\n *\n * This module is designed to be used directly in the browser console or embedded in\n * web applications to help end-users understand the security posture of the apps they use.\n *\n * @module inspect/browser\n */\n\n/**\n * Configuration options for browser-based application inspection\n */\nexport interface BrowserInspectOptions {\n /**\n * The origin/URL of the app to inspect\n * @default window.location.origin\n */\n appUrl?: string;\n\n /**\n * Rukh API endpoint\n * @default 'https://rukh.w3hc.org'\n */\n rukhUrl?: string;\n\n /**\n * Context to use for analysis\n * @default 'w3pk'\n */\n context?: string;\n\n /**\n * AI model to use\n * @default 'anthropic'\n */\n model?: \"anthropic\" | \"mistral\" | \"openai\";\n\n /**\n * Focus mode for analysis\n * @default 'transactions'\n */\n focusMode?: \"transactions\" | \"all\";\n\n /**\n * Maximum total size in KB for all collected code (prevents exceeding API token limits)\n * @default 100\n */\n maxTotalSizeKB?: number;\n}\n\n/**\n * Result of a browser-based inspection\n */\nexport interface BrowserInspectResult {\n /**\n * The security report markdown generated by Rukh API\n */\n report: string;\n\n /**\n * List of JavaScript file paths that were analyzed\n */\n analyzedFiles: string[];\n\n /**\n * The application URL that was inspected\n */\n appUrl: string;\n}\n\n/**\n * Extracts transaction-related code snippets from JavaScript content\n *\n * Scans JavaScript code for keywords related to signing, transactions, and web3 operations,\n * then extracts relevant code snippets with surrounding context.\n *\n * @param content - The JavaScript source code to analyze\n * @param maxLength - Maximum length of extracted snippets in characters\n * @returns Extracted code snippets or a message if no relevant code found\n * @internal\n */\nfunction extractTransactionSnippets(\n content: string,\n maxLength: number = 30000,\n): string {\n const keywords = [\n \"signMessage\",\n \"signTypedData\",\n \"sign(\",\n \"signature\",\n \"sendTransaction\",\n \"transaction\",\n \"eth_sign\",\n \"Contract(\",\n \"ethers.Contract\",\n \"new Contract\",\n \"w3pk\",\n \"Web3Passkey\",\n \"useW3PK\",\n \"wallet\",\n \"signer\",\n \"provider\",\n \"authorization\",\n \"delegation\",\n \"EIP7702\",\n ];\n\n const lines = content.split(\"\\n\");\n const relevantLines: string[] = [];\n const maxLines = 500;\n\n for (let i = 0; i < lines.length && relevantLines.length < maxLines; i++) {\n const line = lines[i];\n const lowerLine = line.toLowerCase();\n\n if (keywords.some((kw) => lowerLine.includes(kw.toLowerCase()))) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n\n for (let j = start; j < end; j++) {\n if (!relevantLines.includes(lines[j])) {\n relevantLines.push(lines[j]);\n }\n }\n }\n }\n\n const snippet = relevantLines.join(\"\\n\");\n\n if (snippet.length > maxLength) {\n return snippet.substring(0, maxLength) + \"\\n\\n// ... (truncated)\";\n }\n\n return snippet || \"// No transaction code found\";\n}\n\n/**\n * Fetches JavaScript source code from the currently running application\n *\n * Discovers and fetches all script tags in the current page, extracts transaction-related\n * snippets, and formats them as markdown for analysis.\n *\n * @param appUrl - The base URL of the application being inspected\n * @param maxTotalSizeKB - Maximum total size in KB for all collected code\n * @returns Markdown-formatted source code with transaction-related snippets\n * @internal\n */\nasync function fetchAppSource(appUrl: string, maxTotalSizeKB: number = 100): Promise<string> {\n let markdown = `# Application Code Analysis\\n\\n`;\n markdown += `**App URL:** ${appUrl}\\n\\n`;\n markdown += `**Note:** Only transaction-related code snippets shown\\n\\n`;\n markdown += `---\\n\\n`;\n\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const scriptUrls = scripts\n .map((script) => (script as HTMLScriptElement).src)\n .filter(\n (src) =>\n src &&\n !src.includes(\"node_modules\") &&\n !src.includes(\"chrome-extension\"),\n );\n\n markdown += `## JavaScript Files (${scriptUrls.length})\\n\\n`;\n\n let totalSnippets = 0;\n let cumulativeSizeKB = 0;\n const maxTotalBytes = maxTotalSizeKB * 1024;\n\n for (const scriptUrl of scriptUrls.slice(0, 15)) {\n // Check if we've reached the size limit\n if (cumulativeSizeKB >= maxTotalSizeKB) {\n console.warn(`[W3PK Inspect] Reached total size limit of ${maxTotalSizeKB} KB - stopping collection`);\n markdown += `\\n**Note:** Collection stopped - reached ${maxTotalSizeKB} KB limit\\n`;\n break;\n }\n\n try {\n const response = await fetch(scriptUrl);\n if (!response.ok) continue;\n\n const content = await response.text();\n const snippets = extractTransactionSnippets(content);\n\n if (snippets && !snippets.includes(\"No transaction code found\")) {\n const snippetSize = new Blob([snippets]).size / 1024;\n\n // Check if adding this snippet would exceed the limit\n if (cumulativeSizeKB + snippetSize > maxTotalSizeKB) {\n console.warn(`[W3PK Inspect] Skipping ${new URL(scriptUrl).pathname} - would exceed total size limit`);\n break;\n }\n\n markdown += `### \\`${new URL(scriptUrl).pathname}\\`\\n\\n`;\n markdown += \"```javascript\\n\";\n markdown += snippets;\n markdown += \"\\n```\\n\\n---\\n\\n\";\n totalSnippets++;\n cumulativeSizeKB += snippetSize;\n }\n } catch (error) {\n // Skip files that can't be fetched\n }\n }\n\n if (totalSnippets === 0) {\n markdown += `No transaction-related code found in JavaScript files.\\n`;\n }\n\n return markdown;\n}\n\n/**\n * Inspects the currently running web application and returns a security report\n *\n * This function can be called by end-users in their browser console to analyze\n * the security of the web application they're currently using.\n *\n * @param options - Configuration options\n * @returns A security report analyzing transaction and signing methods\n *\n * @example\n * ```typescript\n * // In browser console or app code:\n * import { inspect } from 'w3pk';\n *\n * const report = await inspect();\n * console.log(report.report);\n * ```\n *\n * @example\n * ```typescript\n * // With custom options:\n * const report = await inspect({\n * appUrl: 'https://w3pk.w3hc.org',\n * model: 'anthropic',\n * focusMode: 'transactions'\n * });\n * ```\n */\nexport async function inspect(\n options: BrowserInspectOptions = {},\n): Promise<BrowserInspectResult> {\n // Check if running in browser\n if (typeof window === \"undefined\") {\n throw new Error(\n \"Browser inspect() can only be called in browser environments. For Node.js, use the CLI or Node.js API.\",\n );\n }\n\n const {\n appUrl = window.location.origin,\n rukhUrl = \"https://rukh.w3hc.org\",\n context = \"w3pk\",\n model = \"anthropic\",\n focusMode = \"transactions\",\n maxTotalSizeKB = 100,\n } = options;\n\n console.log(\"[W3PK Inspect] Starting inspection of\", appUrl);\n console.log(\"[W3PK Inspect] Focus mode:\", focusMode);\n console.log(\"[W3PK Inspect] Max total size:\", maxTotalSizeKB, \"KB\");\n\n // Fetch and analyze source code\n const sourceMarkdown = await fetchAppSource(appUrl, maxTotalSizeKB);\n\n console.log(\"[W3PK Inspect] Collected source code, sending to Rukh API...\");\n\n // Prepare request to Rukh API\n const message =\n \"Analyze this web application and provide a security report listing all transaction and signing methods.\";\n\n const formData = new FormData();\n formData.append(\"message\", message);\n formData.append(\"model\", model);\n formData.append(\"context\", context);\n\n // Create blob from markdown\n const blob = new Blob([sourceMarkdown], { type: \"text/markdown\" });\n formData.append(\"file\", blob, \"app-source.md\");\n\n // Send to Rukh API\n const response = await fetch(`${rukhUrl}/ask`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Rukh API error: ${response.status} - ${error}`);\n }\n\n const data = await response.json();\n const report =\n data.output || data.response || data.message || JSON.stringify(data);\n\n console.log(\"[W3PK Inspect] Analysis complete!\");\n\n // Extract script URLs for analyzedFiles\n const scripts = Array.from(document.querySelectorAll(\"script[src]\"));\n const analyzedFiles = scripts\n .map((script) => new URL((script as HTMLScriptElement).src).pathname)\n .filter((src) => src && !src.includes(\"node_modules\"));\n\n return {\n report,\n analyzedFiles,\n appUrl,\n };\n}\n\n/**\n * Quick inspection helper that logs the report to console\n * Perfect for use in browser DevTools console\n *\n * @example\n * ```javascript\n * // In browser console:\n * await w3pk.inspectNow()\n * ```\n */\nexport async function inspectNow(\n options?: BrowserInspectOptions,\n): Promise<void> {\n console.log(\"š W3PK Security Inspection Starting...\\n\");\n\n try {\n const result = await inspect(options);\n\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\"š SECURITY REPORT\");\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\\n\");\n console.log(result.report);\n console.log(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n console.log(\n `ā
Analyzed ${result.analyzedFiles.length} files from ${result.appUrl}`,\n );\n console.log(\"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\");\n } catch (error) {\n console.error(\"ā Inspection failed:\", error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/inspect/node.d.mts
CHANGED
|
@@ -31,6 +31,11 @@ interface InspectOptions {
|
|
|
31
31
|
* @default 500
|
|
32
32
|
*/
|
|
33
33
|
maxFileSizeKB?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Maximum total size in KB for all collected code (prevents exceeding API token limits)
|
|
36
|
+
* @default 100
|
|
37
|
+
*/
|
|
38
|
+
maxTotalSizeKB?: number;
|
|
34
39
|
/**
|
|
35
40
|
* Focus mode: filters files to only include those relevant to specific features
|
|
36
41
|
* - 'transactions': Only files with signing, transactions, or blockchain operations
|
package/dist/inspect/node.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ interface InspectOptions {
|
|
|
31
31
|
* @default 500
|
|
32
32
|
*/
|
|
33
33
|
maxFileSizeKB?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Maximum total size in KB for all collected code (prevents exceeding API token limits)
|
|
36
|
+
* @default 100
|
|
37
|
+
*/
|
|
38
|
+
maxTotalSizeKB?: number;
|
|
34
39
|
/**
|
|
35
40
|
* Focus mode: filters files to only include those relevant to specific features
|
|
36
41
|
* - 'transactions': Only files with signing, transactions, or blockchain operations
|
package/dist/inspect/node.js
CHANGED
|
@@ -92,18 +92,22 @@ function isTransactionRelevant(content, filename) {
|
|
|
92
92
|
(keyword) => lowerContent.includes(keyword.toLowerCase())
|
|
93
93
|
);
|
|
94
94
|
}
|
|
95
|
-
async function walkDirectory(dir, options, rootDir) {
|
|
95
|
+
async function walkDirectory(dir, options, rootDir, cumulativeSizeKB = { value: 0 }) {
|
|
96
96
|
const files = [];
|
|
97
97
|
try {
|
|
98
98
|
const entries = await import_fs.promises.readdir(dir, { withFileTypes: true });
|
|
99
99
|
for (const entry of entries) {
|
|
100
|
+
if (cumulativeSizeKB.value >= options.maxTotalSizeKB) {
|
|
101
|
+
console.warn(`Reached total size limit of ${options.maxTotalSizeKB} KB - stopping collection`);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
100
104
|
const fullPath = import_path.default.join(dir, entry.name);
|
|
101
105
|
const relativePath = import_path.default.relative(rootDir, fullPath);
|
|
102
106
|
if (entry.isDirectory()) {
|
|
103
107
|
if (options.excludeDirs.includes(entry.name)) {
|
|
104
108
|
continue;
|
|
105
109
|
}
|
|
106
|
-
const subFiles = await walkDirectory(fullPath, options, rootDir);
|
|
110
|
+
const subFiles = await walkDirectory(fullPath, options, rootDir, cumulativeSizeKB);
|
|
107
111
|
files.push(...subFiles);
|
|
108
112
|
} else if (entry.isFile()) {
|
|
109
113
|
const ext = import_path.default.extname(entry.name);
|
|
@@ -129,6 +133,12 @@ async function walkDirectory(dir, options, rootDir) {
|
|
|
129
133
|
continue;
|
|
130
134
|
}
|
|
131
135
|
}
|
|
136
|
+
const contentSizeKB = Buffer.byteLength(content, "utf-8") / 1024;
|
|
137
|
+
if (cumulativeSizeKB.value + contentSizeKB > options.maxTotalSizeKB) {
|
|
138
|
+
console.warn(`Skipping ${relativePath} - would exceed total size limit (${(cumulativeSizeKB.value + contentSizeKB).toFixed(2)} KB > ${options.maxTotalSizeKB} KB)`);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
cumulativeSizeKB.value += contentSizeKB;
|
|
132
142
|
files.push({ path: fullPath, content, relativePath });
|
|
133
143
|
}
|
|
134
144
|
}
|
|
@@ -160,6 +170,7 @@ async function gatherCode(options = {}) {
|
|
|
160
170
|
".turbo"
|
|
161
171
|
],
|
|
162
172
|
maxFileSizeKB: options.maxFileSizeKB || 500,
|
|
173
|
+
maxTotalSizeKB: options.maxTotalSizeKB || 100,
|
|
163
174
|
focusMode: options.focusMode || "all"
|
|
164
175
|
};
|
|
165
176
|
const appPath = import_path.default.resolve(opts.appPath);
|