@felan-ai/ext-web-access 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +18 -0
  3. package/README.md +58 -0
  4. package/dist/boundary.d.ts +6 -0
  5. package/dist/boundary.d.ts.map +1 -0
  6. package/dist/boundary.js +33 -0
  7. package/dist/boundary.js.map +1 -0
  8. package/dist/config.d.ts +37 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +64 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/content-find.d.ts +12 -0
  13. package/dist/content-find.d.ts.map +1 -0
  14. package/dist/content-find.js +80 -0
  15. package/dist/content-find.js.map +1 -0
  16. package/dist/credentials.d.ts +12 -0
  17. package/dist/credentials.d.ts.map +1 -0
  18. package/dist/credentials.js +87 -0
  19. package/dist/credentials.js.map +1 -0
  20. package/dist/extract.d.ts +11 -0
  21. package/dist/extract.d.ts.map +1 -0
  22. package/dist/extract.js +168 -0
  23. package/dist/extract.js.map +1 -0
  24. package/dist/github.d.ts +13 -0
  25. package/dist/github.d.ts.map +1 -0
  26. package/dist/github.js +166 -0
  27. package/dist/github.js.map +1 -0
  28. package/dist/http.d.ts +5 -0
  29. package/dist/http.d.ts.map +1 -0
  30. package/dist/http.js +47 -0
  31. package/dist/http.js.map +1 -0
  32. package/dist/index.d.ts +4 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +502 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/providers.d.ts +17 -0
  37. package/dist/providers.d.ts.map +1 -0
  38. package/dist/providers.js +653 -0
  39. package/dist/providers.js.map +1 -0
  40. package/dist/source-check.d.ts +21 -0
  41. package/dist/source-check.d.ts.map +1 -0
  42. package/dist/source-check.js +136 -0
  43. package/dist/source-check.js.map +1 -0
  44. package/dist/ssrf.d.ts +36 -0
  45. package/dist/ssrf.d.ts.map +1 -0
  46. package/dist/ssrf.js +306 -0
  47. package/dist/ssrf.js.map +1 -0
  48. package/dist/storage.d.ts +15 -0
  49. package/dist/storage.d.ts.map +1 -0
  50. package/dist/storage.js +88 -0
  51. package/dist/storage.js.map +1 -0
  52. package/dist/types.d.ts +100 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +2 -0
  55. package/dist/types.js.map +1 -0
  56. package/package.json +52 -0
@@ -0,0 +1,168 @@
1
+ import { Readability } from '@mozilla/readability';
2
+ import { parseHTML } from 'linkedom';
3
+ import TurndownService from 'turndown';
4
+ import { positiveInteger, positiveNumber } from './config.js';
5
+ import { extractGitHubRepository, parseGitHubUrl } from './github.js';
6
+ import { combinedSignal, readResponseBytes } from './http.js';
7
+ import { fetchRemoteUrl, ssrfSettings, validateRemoteUrl } from './ssrf.js';
8
+ const MAX_HTTP_RESPONSE_BYTES = 5 * 1024 * 1024;
9
+ const MAX_IMAGE_BYTES = 3 * 1024 * 1024;
10
+ const MAX_EXTRACTED_CHARACTERS = 750_000;
11
+ const DEFAULT_PDF_MAX_SIZE_MB = 20;
12
+ const MAX_PDF_MAX_SIZE_MB = 50;
13
+ const DEFAULT_PDF_MAX_PAGES = 100;
14
+ const HTTP_TIMEOUT_MS = 30_000;
15
+ export async function extractContent(rawUrl, runtime, config, signal, options = {}) {
16
+ const settings = ssrfSettings(config);
17
+ const url = await validateRemoteUrl(rawUrl, settings);
18
+ const github = options.allowGitHub === false ? undefined : parseGitHubUrl(url.toString());
19
+ if (github && options.mode !== 'raw') {
20
+ return extractGitHubRepository(url.toString(), github, runtime, config, signal, options.forceClone);
21
+ }
22
+ const response = await fetchRemoteUrl(url, {
23
+ headers: {
24
+ Accept: 'text/html,application/xhtml+xml,application/json,text/plain,application/pdf,image/*;q=0.8,*/*;q=0.5',
25
+ 'User-Agent': 'Felan-Web-Access/0.1',
26
+ },
27
+ signal: combinedSignal(signal, HTTP_TIMEOUT_MS),
28
+ }, settings);
29
+ if (!response.ok) {
30
+ return { url: url.toString(), title: url.hostname, content: '', error: `HTTP ${response.status}` };
31
+ }
32
+ const contentType = response.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase() ?? '';
33
+ const contentLength = Number(response.headers.get('content-length'));
34
+ if (contentType.startsWith('image/') && Number.isFinite(contentLength) && contentLength > MAX_IMAGE_BYTES) {
35
+ throw new Error(`Image exceeds the ${MAX_IMAGE_BYTES}-byte limit`);
36
+ }
37
+ const pdfMaximumBytes = positiveNumber(config.pdf?.maxSizeMB, DEFAULT_PDF_MAX_SIZE_MB, MAX_PDF_MAX_SIZE_MB) * 1024 * 1024;
38
+ if (isPdf(url, contentType) && Number.isFinite(contentLength) && contentLength > pdfMaximumBytes) {
39
+ throw new Error(`PDF exceeds the configured ${pdfMaximumBytes}-byte limit`);
40
+ }
41
+ const maximumBytes = contentType.startsWith('image/')
42
+ ? MAX_IMAGE_BYTES
43
+ : isPdf(url, contentType) ? pdfMaximumBytes : MAX_HTTP_RESPONSE_BYTES;
44
+ const bytes = await readResponseBytes(response, maximumBytes);
45
+ if (contentType.startsWith('image/')) {
46
+ return {
47
+ url: url.toString(),
48
+ title: fileTitle(url, 'image'),
49
+ content: `[Remote image: ${contentType}, ${bytes.byteLength} bytes]`,
50
+ error: null,
51
+ contentType,
52
+ image: { data: Buffer.from(bytes).toString('base64'), mimeType: contentType },
53
+ };
54
+ }
55
+ if (isPdf(url, contentType))
56
+ return extractPdf(bytes, url, config, contentType);
57
+ const text = new TextDecoder().decode(bytes);
58
+ if (options.mode === 'raw') {
59
+ return { url: url.toString(), title: fileTitle(url, url.hostname), content: text, error: null, contentType };
60
+ }
61
+ if (contentType.includes('html') || looksLikeHtml(text))
62
+ return extractHtml(text, url, contentType);
63
+ if (contentType.includes('json') || looksLikeJson(text))
64
+ return extractJson(text, url, contentType);
65
+ return boundedExtracted({
66
+ url: url.toString(),
67
+ title: fileTitle(url, url.hostname),
68
+ content: text,
69
+ error: null,
70
+ contentType: contentType || 'text/plain',
71
+ });
72
+ }
73
+ export async function fetchWithConcurrency(urls, concurrency, fetchOne, captureErrors = true) {
74
+ const results = new Array(urls.length);
75
+ let next = 0;
76
+ const workers = Array.from({ length: Math.min(concurrency, urls.length) }, async () => {
77
+ while (next < urls.length) {
78
+ const index = next;
79
+ next += 1;
80
+ const url = urls[index];
81
+ try {
82
+ results[index] = await fetchOne(url);
83
+ }
84
+ catch (error) {
85
+ if (!captureErrors)
86
+ throw error;
87
+ results[index] = { url, title: '', content: '', error: errorMessage(error) };
88
+ }
89
+ }
90
+ });
91
+ await Promise.all(workers);
92
+ return results;
93
+ }
94
+ function extractHtml(html, url, contentType) {
95
+ const { document } = parseHTML(html);
96
+ const article = new Readability(document, { charThreshold: 20 }).parse();
97
+ const turndown = new TurndownService({ codeBlockStyle: 'fenced', headingStyle: 'atx' });
98
+ const title = article?.title?.trim() || document.title?.trim() || fileTitle(url, url.hostname);
99
+ const content = article?.content ? turndown.turndown(article.content) : turndown.turndown(document.body?.innerHTML ?? html);
100
+ return boundedExtracted({ url: url.toString(), title, content: content.trim(), error: null, contentType });
101
+ }
102
+ function extractJson(text, url, contentType) {
103
+ let content = text;
104
+ try {
105
+ content = JSON.stringify(JSON.parse(text), null, 2);
106
+ }
107
+ catch {
108
+ // Invalid JSON is still useful as exact text.
109
+ }
110
+ return boundedExtracted({ url: url.toString(), title: fileTitle(url, url.hostname), content, error: null, contentType });
111
+ }
112
+ async function extractPdf(bytes, url, config, contentType) {
113
+ if (typeof Promise.try !== 'function') {
114
+ const { default: promiseTry } = await import('promise.try');
115
+ promiseTry.shim();
116
+ }
117
+ const [{ getDocumentProxy }, pdfjs] = await Promise.all([import('unpdf'), import('unpdf/pdfjs')]);
118
+ const verbosity = pdfjs.VerbosityLevel.ERRORS;
119
+ const pdf = await getDocumentProxy(bytes, { verbosity });
120
+ const metadata = await pdf.getMetadata();
121
+ const info = metadata.info && typeof metadata.info === 'object' ? metadata.info : {};
122
+ const title = typeof info.Title === 'string' && info.Title.trim() ? info.Title.trim() : fileTitle(url, 'document');
123
+ const maximumPages = positiveInteger(config.pdf?.maxPages, DEFAULT_PDF_MAX_PAGES, 500);
124
+ const pageCount = Math.min(pdf.numPages, maximumPages);
125
+ const sections = [`# ${title}`, '', `Source: ${url.toString()}`, `Pages: ${pdf.numPages}`, ''];
126
+ for (let pageNumber = 1; pageNumber <= pageCount; pageNumber += 1) {
127
+ const page = await pdf.getPage(pageNumber);
128
+ const textContent = await page.getTextContent();
129
+ const pageText = textContent.items.map((item) => typeof item.str === 'string' ? item.str : '').join(' ').replace(/\s+/gu, ' ').trim();
130
+ if (pageText)
131
+ sections.push(`<!-- Page ${pageNumber} -->`, '', pageText, '');
132
+ }
133
+ return boundedExtracted({
134
+ url: url.toString(),
135
+ title,
136
+ content: sections.join('\n').trim(),
137
+ error: null,
138
+ contentType,
139
+ ...(pdf.numPages > maximumPages ? { truncated: true } : {}),
140
+ });
141
+ }
142
+ function boundedExtracted(value) {
143
+ if (value.content.length <= MAX_EXTRACTED_CHARACTERS)
144
+ return value;
145
+ return {
146
+ ...value,
147
+ content: value.content.slice(0, MAX_EXTRACTED_CHARACTERS),
148
+ truncated: true,
149
+ };
150
+ }
151
+ function isPdf(url, contentType) {
152
+ return contentType === 'application/pdf' || url.pathname.toLowerCase().endsWith('.pdf');
153
+ }
154
+ function looksLikeHtml(text) {
155
+ return /<!doctype html|<html[\s>]|<body[\s>]/iu.test(text.slice(0, 2_000));
156
+ }
157
+ function looksLikeJson(text) {
158
+ const trimmed = text.trimStart();
159
+ return trimmed.startsWith('{') || trimmed.startsWith('[');
160
+ }
161
+ function fileTitle(url, fallback) {
162
+ const segment = url.pathname.split('/').filter(Boolean).at(-1);
163
+ return segment ? decodeURIComponent(segment) : fallback;
164
+ }
165
+ function errorMessage(error) {
166
+ return error instanceof Error ? error.message : String(error);
167
+ }
168
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { AgentRuntime } from '@felan-ai/agent-core';
2
+ import { type WebAccessConfig } from './config.js';
3
+ import type { ExtractedContent } from './types.js';
4
+ export interface GitHubUrlInfo {
5
+ owner: string;
6
+ repo: string;
7
+ ref?: string;
8
+ path?: string;
9
+ type: 'root' | 'tree' | 'blob';
10
+ }
11
+ export declare function parseGitHubUrl(rawUrl: string): GitHubUrlInfo | undefined;
12
+ export declare function extractGitHubRepository(url: string, info: GitHubUrlInfo, runtime: AgentRuntime, config: WebAccessConfig, signal?: AbortSignal, forceClone?: boolean): Promise<ExtractedContent>;
13
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAenD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CAChC;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAqBxE;AAED,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,UAAU,UAAQ,GACjB,OAAO,CAAC,gBAAgB,CAAC,CAoE3B"}
package/dist/github.js ADDED
@@ -0,0 +1,166 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { join, posix } from 'node:path';
3
+ import { positiveNumber } from './config.js';
4
+ import { combinedSignal, readJsonResponse } from './http.js';
5
+ import { endpointSsrfSettings, fetchRemoteUrl } from './ssrf.js';
6
+ const MAX_FILES = 200;
7
+ const MAX_FILE_CHARACTERS = 100_000;
8
+ const MAX_TOTAL_CHARACTERS = 750_000;
9
+ const clonePromises = new Map();
10
+ const textDecoder = new TextDecoder('utf8', { fatal: true });
11
+ const BINARY_EXTENSIONS = new Set([
12
+ '.7z', '.avi', '.bin', '.bmp', '.class', '.dll', '.doc', '.docx', '.dylib', '.exe', '.gif', '.gz',
13
+ '.ico', '.jar', '.jpeg', '.jpg', '.lockb', '.mov', '.mp3', '.mp4', '.o', '.otf', '.pdf', '.png',
14
+ '.pyc', '.so', '.tar', '.ttf', '.wav', '.webm', '.webp', '.woff', '.woff2', '.xls', '.xlsx', '.zip',
15
+ ]);
16
+ const NOISE_DIRECTORIES = new Set(['.git', '.next', '.turbo', 'build', 'coverage', 'dist', 'node_modules', 'target', 'vendor']);
17
+ export function parseGitHubUrl(rawUrl) {
18
+ let url;
19
+ try {
20
+ url = new URL(rawUrl);
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ if (url.hostname.toLowerCase() !== 'github.com')
26
+ return undefined;
27
+ const segments = url.pathname.split('/').filter(Boolean).map((segment) => decodeURIComponent(segment));
28
+ const [owner, rawRepo, kind, ref, ...path] = segments;
29
+ const repo = rawRepo?.replace(/\.git$/u, '');
30
+ if (!owner || !repo || !validSegment(owner) || !validSegment(repo))
31
+ return undefined;
32
+ if (kind !== undefined && kind !== 'tree' && kind !== 'blob')
33
+ return undefined;
34
+ if (kind && (!ref || !validSegment(ref) || path.some((segment) => !validPathSegment(segment))))
35
+ return undefined;
36
+ return {
37
+ owner,
38
+ repo,
39
+ type: kind ?? 'root',
40
+ ...(ref ? { ref } : {}),
41
+ ...(path.length > 0 ? { path: path.join('/') } : {}),
42
+ };
43
+ }
44
+ export async function extractGitHubRepository(url, info, runtime, config, signal, forceClone = false) {
45
+ if (config.githubClone?.enabled === false)
46
+ throw new Error('GitHub repository extraction is disabled');
47
+ const maximumRepoSizeMb = positiveNumber(config.githubClone?.maxRepoSizeMB, 350, 2_000);
48
+ const timeoutMs = positiveNumber(config.githubClone?.cloneTimeoutSeconds, 30, 300) * 1_000;
49
+ if (!forceClone) {
50
+ const sizeMb = await githubRepositorySizeMb(info, config, signal);
51
+ if (sizeMb > maximumRepoSizeMb) {
52
+ throw new Error(`GitHub repository is ${Math.ceil(sizeMb)} MB; pass forceClone: true to exceed the configured ${maximumRepoSizeMb} MB threshold`);
53
+ }
54
+ }
55
+ const storage = runtime.storage('session');
56
+ const key = createHash('sha256').update(`${info.owner}/${info.repo}@${info.ref ?? 'HEAD'}`).digest('hex').slice(0, 20);
57
+ const repositoryPath = join(storage.root, 'web-access', 'repos', key);
58
+ await storage.mkdir(join(storage.root, 'web-access', 'repos'), { recursive: true });
59
+ if (forceClone) {
60
+ try {
61
+ await storage.remove(repositoryPath, { recursive: true });
62
+ }
63
+ catch {
64
+ // A missing clone is already in the requested state.
65
+ }
66
+ }
67
+ if (!await hasClone(storage, repositoryPath)) {
68
+ let clone = clonePromises.get(repositoryPath);
69
+ if (!clone) {
70
+ clone = cloneRepository(runtime, repositoryPath, info, timeoutMs, signal);
71
+ clonePromises.set(repositoryPath, clone);
72
+ }
73
+ try {
74
+ await clone;
75
+ }
76
+ finally {
77
+ clonePromises.delete(repositoryPath);
78
+ }
79
+ }
80
+ const files = (await storage.listFiles(repositoryPath, { recursive: true }))
81
+ .filter(isUsefulFile)
82
+ .filter((path) => info.type === 'root' || !info.path || path === info.path || path.startsWith(`${info.path}/`))
83
+ .slice(0, MAX_FILES);
84
+ if (info.type === 'blob' && info.path && !files.includes(info.path))
85
+ throw new Error(`GitHub repository path not found: ${info.path}`);
86
+ const sections = [`# ${info.owner}/${info.repo}`, '', `Source: ${url}`, ''];
87
+ let totalCharacters = sections.join('\n').length;
88
+ let includedFiles = 0;
89
+ for (const file of files) {
90
+ let text;
91
+ try {
92
+ text = textDecoder.decode(await storage.readFile(join(repositoryPath, file)));
93
+ }
94
+ catch {
95
+ continue;
96
+ }
97
+ if (text.includes('\0'))
98
+ continue;
99
+ const body = text.length > MAX_FILE_CHARACTERS ? `${text.slice(0, MAX_FILE_CHARACTERS)}\n[File truncated]` : text;
100
+ const fence = '```';
101
+ const rendered = `## ${file}\n\n${fence}${languageFor(file)}\n${body}\n${fence}`;
102
+ if (totalCharacters + rendered.length > MAX_TOTAL_CHARACTERS)
103
+ break;
104
+ sections.push(rendered);
105
+ totalCharacters += rendered.length;
106
+ includedFiles += 1;
107
+ }
108
+ return {
109
+ url,
110
+ title: info.path ? `${info.owner}/${info.repo} - ${info.path}` : `${info.owner}/${info.repo}`,
111
+ content: sections.join('\n'),
112
+ error: null,
113
+ contentType: 'text/markdown',
114
+ ...(includedFiles < files.length ? { truncated: true } : {}),
115
+ };
116
+ }
117
+ async function cloneRepository(runtime, destination, info, timeoutMs, signal) {
118
+ const args = ['clone', '--depth', '1', '--filter=blob:none'];
119
+ if (info.ref)
120
+ args.push('--branch', info.ref);
121
+ args.push(`https://github.com/${info.owner}/${info.repo}.git`, destination);
122
+ const result = await runtime.exec('git', args, { ...(signal ? { signal } : {}), timeout: timeoutMs });
123
+ if (signal?.aborted || result.killed)
124
+ throw new Error('GitHub clone was aborted');
125
+ if (result.code !== 0)
126
+ throw new Error('GitHub repository clone failed');
127
+ }
128
+ async function githubRepositorySizeMb(info, config, signal) {
129
+ const response = await fetchRemoteUrl(`https://api.github.com/repos/${info.owner}/${info.repo}`, {
130
+ headers: { Accept: 'application/vnd.github+json', 'User-Agent': 'felan-web-access' },
131
+ signal: combinedSignal(signal, 15_000),
132
+ }, endpointSsrfSettings(config), { allowCrossOriginRedirects: false });
133
+ if (!response.ok)
134
+ throw new Error(`GitHub API request failed with HTTP ${response.status}`);
135
+ const data = await readJsonResponse(response, 512 * 1024, 'GitHub API');
136
+ if (typeof data.size !== 'number' || !Number.isFinite(data.size) || data.size < 0) {
137
+ throw new Error('GitHub API response did not include a valid repository size');
138
+ }
139
+ return data.size / 1_024;
140
+ }
141
+ async function hasClone(storage, path) {
142
+ try {
143
+ return (await storage.listFiles(path, { recursive: false })).length > 0
144
+ || (await storage.listFiles(join(path, '.git'), { recursive: false })).length > 0;
145
+ }
146
+ catch {
147
+ return false;
148
+ }
149
+ }
150
+ function isUsefulFile(path) {
151
+ const normalized = path.replace(/\\/gu, '/');
152
+ if (normalized.split('/').some((segment) => NOISE_DIRECTORIES.has(segment)))
153
+ return false;
154
+ const extension = posix.extname(normalized).toLowerCase();
155
+ return !BINARY_EXTENSIONS.has(extension);
156
+ }
157
+ function languageFor(path) {
158
+ return posix.extname(path).slice(1).replace(/[^a-z0-9_+-]/giu, '');
159
+ }
160
+ function validSegment(value) {
161
+ return /^[A-Za-z0-9_.-]+$/u.test(value) && value !== '.' && value !== '..';
162
+ }
163
+ function validPathSegment(value) {
164
+ return value !== '' && value !== '.' && value !== '..' && !value.includes('\0');
165
+ }
166
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export declare function readResponseBytes(response: Response, maximumBytes: number): Promise<Uint8Array>;
2
+ export declare function readResponseText(response: Response, maximumBytes: number): Promise<string>;
3
+ export declare function readJsonResponse<T>(response: Response, maximumBytes: number, label: string): Promise<T>;
4
+ export declare function combinedSignal(signal: AbortSignal | undefined, timeoutMs: number): AbortSignal;
5
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BrG;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEhG;AAED,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAO7G;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,CAG9F"}
package/dist/http.js ADDED
@@ -0,0 +1,47 @@
1
+ export async function readResponseBytes(response, maximumBytes) {
2
+ const reader = response.body?.getReader();
3
+ if (!reader)
4
+ return new Uint8Array();
5
+ const chunks = [];
6
+ let total = 0;
7
+ try {
8
+ while (true) {
9
+ const { done, value } = await reader.read();
10
+ if (done)
11
+ break;
12
+ total += value.byteLength;
13
+ if (total > maximumBytes) {
14
+ await reader.cancel();
15
+ throw new Error(`Response exceeds the ${maximumBytes}-byte limit`);
16
+ }
17
+ chunks.push(value);
18
+ }
19
+ }
20
+ finally {
21
+ reader.releaseLock();
22
+ }
23
+ const bytes = new Uint8Array(total);
24
+ let offset = 0;
25
+ for (const chunk of chunks) {
26
+ bytes.set(chunk, offset);
27
+ offset += chunk.byteLength;
28
+ }
29
+ return bytes;
30
+ }
31
+ export async function readResponseText(response, maximumBytes) {
32
+ return new TextDecoder().decode(await readResponseBytes(response, maximumBytes));
33
+ }
34
+ export async function readJsonResponse(response, maximumBytes, label) {
35
+ const text = await readResponseText(response, maximumBytes);
36
+ try {
37
+ return JSON.parse(text);
38
+ }
39
+ catch {
40
+ throw new Error(`${label} returned invalid JSON`);
41
+ }
42
+ }
43
+ export function combinedSignal(signal, timeoutMs) {
44
+ const timeout = AbortSignal.timeout(timeoutMs);
45
+ return signal ? AbortSignal.any([signal, timeout]) : timeout;
46
+ }
47
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAAkB,EAAE,YAAoB;IAC9E,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;IAC1C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,UAAU,EAAE,CAAC;IACrC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;YAC1B,IAAI,KAAK,GAAG,YAAY,EAAE,CAAC;gBACzB,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,wBAAwB,YAAY,aAAa,CAAC,CAAC;YACrE,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAkB,EAAE,YAAoB;IAC7E,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,iBAAiB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAI,QAAkB,EAAE,YAAoB,EAAE,KAAa;IAC/F,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,wBAAwB,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAA+B,EAAE,SAAiB;IAC/E,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { FelanExtension } from '@felan-ai/agent-core';
2
+ declare const webAccessExtension: FelanExtension;
3
+ export default webAccessExtension;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,cAAc,EAGf,MAAM,sBAAsB,CAAC;AA4F9B,QAAA,MAAM,kBAAkB,EAAE,cA2LzB,CAAC;AAyQF,eAAe,kBAAkB,CAAC"}