mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
102 lines
3.8 KiB
TypeScript
102 lines
3.8 KiB
TypeScript
/**
|
|
* `@deepseek-ai/dsh-web-fetch-local`: registers an anonymous public HTTP(S)
|
|
* `WebFetchProvider` with `ctx.web`. A function/namespace plugin (NOT a
|
|
* default-export service): it registers INTO the seam's fetch registry, like the
|
|
* search providers register into the search registry.
|
|
*
|
|
* @module @deepseek-ai/dsh-web-fetch-local
|
|
*/
|
|
|
|
import type { Context } from 'cordis'
|
|
import z from 'schemastery'
|
|
import type {} from '@deepseek-ai/dsh-web'
|
|
import { LocalFetchProvider } from './provider.ts'
|
|
import type { LocalFetchLimits } from './provider.ts'
|
|
|
|
const MAX_NODE_TIMER_DELAY_MS = 2_147_483_647
|
|
|
|
export {
|
|
LOCAL_FETCH_PROVIDER_ID,
|
|
LocalFetchProvider,
|
|
} from './provider.ts'
|
|
export type { LocalFetchLimits } from './provider.ts'
|
|
|
|
/** Default `User-Agent`: an explicit product agent, never a browser disguise. */
|
|
export const DEFAULT_USER_AGENT = 'deepseek-harness/0.0.1 (+https://github.com/deepseek-ai)'
|
|
|
|
/** Cordis plugin name used by loader diagnostics. */
|
|
export const name = 'web-fetch-local'
|
|
|
|
/** The web seam this provider registers into. */
|
|
export const inject = ['web']
|
|
|
|
/** Plugin config: the provider's transport and size limits plus its `User-Agent` (all defaulted). */
|
|
export interface Config {
|
|
/** Maximum accepted request URL length. */
|
|
maxUrlLength?: number
|
|
/** Maximum response body size in bytes. */
|
|
maxResponseBytes?: number
|
|
/** Maximum decoded body length in characters. */
|
|
maxBodyChars?: number
|
|
/** Default fetch timeout in milliseconds, within Node's timer range. */
|
|
timeoutMs?: number
|
|
/** Maximum number of same-origin redirect hops to follow. */
|
|
maxRedirects?: number
|
|
/** `User-Agent` header sent on every request. */
|
|
userAgent?: string
|
|
}
|
|
|
|
export const Config: z<Config> = z.object({
|
|
maxUrlLength: z.number().default(2048),
|
|
maxResponseBytes: z.number().default(5_000_000),
|
|
maxBodyChars: z.number().default(100_000),
|
|
timeoutMs: z.number().default(30_000),
|
|
maxRedirects: z.number().default(5),
|
|
userAgent: z.string().default(DEFAULT_USER_AGENT),
|
|
})
|
|
|
|
/** The shape after schemastery applies its defaults to every field. */
|
|
type ResolvedConfig = Required<Config>
|
|
|
|
/** A resource limit (byte/char/length/timeout cap) must be a positive finite number. */
|
|
function assertPositiveFinite(name: string, value: number): void {
|
|
if (!Number.isFinite(value) || value <= 0) {
|
|
throw new Error(`web-fetch-local: ${name} must be a positive finite number`)
|
|
}
|
|
}
|
|
|
|
/** Node coerces larger timer delays to 1 ms, so reject them at configuration time. */
|
|
function assertTimeoutMs(value: number): void {
|
|
assertPositiveFinite('timeoutMs', value)
|
|
if (value > MAX_NODE_TIMER_DELAY_MS) {
|
|
throw new Error(`web-fetch-local: timeoutMs must be no greater than ${MAX_NODE_TIMER_DELAY_MS}`)
|
|
}
|
|
}
|
|
|
|
/** The redirect hop cap must be a non-negative integer (0 follows no redirects). */
|
|
function assertNonNegativeInteger(name: string, value: number): void {
|
|
if (!Number.isInteger(value) || value < 0) {
|
|
throw new Error(`web-fetch-local: ${name} must be a non-negative integer`)
|
|
}
|
|
}
|
|
|
|
/** Register the local HTTP(S) fetch provider with `ctx.web`. */
|
|
export function apply(ctx: Context, config: Config): void {
|
|
// schemastery (Config) has already filled every defaulted field.
|
|
const resolved = config as ResolvedConfig
|
|
assertPositiveFinite('maxUrlLength', resolved.maxUrlLength)
|
|
assertPositiveFinite('maxResponseBytes', resolved.maxResponseBytes)
|
|
assertPositiveFinite('maxBodyChars', resolved.maxBodyChars)
|
|
assertTimeoutMs(resolved.timeoutMs)
|
|
assertNonNegativeInteger('maxRedirects', resolved.maxRedirects)
|
|
const limits: LocalFetchLimits = {
|
|
maxUrlLength: resolved.maxUrlLength,
|
|
maxResponseBytes: resolved.maxResponseBytes,
|
|
maxBodyChars: resolved.maxBodyChars,
|
|
timeoutMs: resolved.timeoutMs,
|
|
maxRedirects: resolved.maxRedirects,
|
|
userAgent: resolved.userAgent,
|
|
}
|
|
ctx.web.registerFetchProvider(new LocalFetchProvider(limits))
|
|
}
|