← back to 0xMassi__webclaw-js

Function bodies 44 total

All specs Real LLM only Function bodies
Webclaw class · typescript · L46-L347 (302 LOC)
src/client.ts
export class Webclaw {
  private readonly apiKey: string;
  private readonly baseUrl: string;
  private readonly timeout: number;

  constructor(config: WebclawConfig) {
    if (!config.apiKey) throw new Error("apiKey is required");
    this.apiKey = config.apiKey;
    this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
    this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
  }

  // -- Public API methods --

  /**
   * Scrape a single URL and extract its content.
   * @param params - URL and extraction options (formats, selectors, caching).
   * @returns Extracted content in the requested formats.
   * @throws {WebclawError} On network or API errors.
   */
  async scrape(params: ScrapeRequest): Promise<ScrapeResponse> {
    if (!params.url) throw new Error("url is required");
    return this.post<ScrapeResponse>("/v1/scrape", params);
  }

  /**
   * Start an async crawl job that discovers and scrapes pages from a root URL.
   * @param params - Root URL and crawl l
constructor method · typescript · L51-L56 (6 LOC)
src/client.ts
  constructor(config: WebclawConfig) {
    if (!config.apiKey) throw new Error("apiKey is required");
    this.apiKey = config.apiKey;
    this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
    this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
  }
scrape method · typescript · L66-L69 (4 LOC)
src/client.ts
  async scrape(params: ScrapeRequest): Promise<ScrapeResponse> {
    if (!params.url) throw new Error("url is required");
    return this.post<ScrapeResponse>("/v1/scrape", params);
  }
crawl method · typescript · L77-L80 (4 LOC)
src/client.ts
  async crawl(params: CrawlRequest): Promise<CrawlJob> {
    const res = await this.post<CrawlStartResponse>("/v1/crawl", params);
    return new CrawlJob(res.id, this);
  }
getCrawlStatus method · typescript · L88-L90 (3 LOC)
src/client.ts
  async getCrawlStatus(id: string): Promise<CrawlStatusResponse> {
    return this.get<CrawlStatusResponse>(`/v1/crawl/${encodeURIComponent(id)}`);
  }
map method · typescript · L97-L99 (3 LOC)
src/client.ts
  async map(params: MapRequest): Promise<MapResponse> {
    return this.post<MapResponse>("/v1/map", params);
  }
batch method · typescript · L106-L109 (4 LOC)
src/client.ts
  async batch(params: BatchRequest): Promise<BatchResponse> {
    if (!params.urls?.length) throw new Error("urls must be a non-empty array");
    return this.post<BatchResponse>("/v1/batch", params);
  }
Repobility — same analyzer, your code, free for public repos · /scan/
extract method · typescript · L116-L119 (4 LOC)
src/client.ts
  async extract(params: ExtractRequest): Promise<ExtractResponse> {
    if (!params.url) throw new Error("url is required");
    return this.post<ExtractResponse>("/v1/extract", params);
  }
summarize method · typescript · L126-L128 (3 LOC)
src/client.ts
  async summarize(params: SummarizeRequest): Promise<SummarizeResponse> {
    return this.post<SummarizeResponse>("/v1/summarize", params);
  }
brand method · typescript · L135-L137 (3 LOC)
src/client.ts
  async brand(params: BrandRequest): Promise<BrandResponse> {
    return this.post<BrandResponse>("/v1/brand", params);
  }
search method · typescript · L144-L147 (4 LOC)
src/client.ts
  async search(params: SearchRequest): Promise<SearchResponse> {
    if (!params.query) throw new Error("query is required");
    return this.post<SearchResponse>("/v1/search", params);
  }
diff method · typescript · L154-L156 (3 LOC)
src/client.ts
  async diff(params: DiffRequest): Promise<DiffResponse> {
    return this.post<DiffResponse>("/v1/diff", params);
  }
research method · typescript · L166-L185 (20 LOC)
src/client.ts
  async research(
    params: ResearchRequest,
    opts: ResearchPollOptions = {},
  ): Promise<ResearchResponse> {
    if (!params.query) throw new Error("query is required");
    const start = await this.post<ResearchStartResponse>(
      "/v1/research",
      params,
    );

    const interval = opts.interval ?? 2_000;
    const defaultMax = params.deep ? 1_200_000 : 600_000;
    const maxWait = opts.maxWait ?? defaultMax;

    return pollUntilDone(
      () => this.getResearchStatus(start.id),
      (r) => r.status === "completed" || r.status === "failed",
      { interval, timeout: maxWait },
    );
  }
waitForResearch method · typescript · L196-L209 (14 LOC)
src/client.ts
  async waitForResearch(
    id: string,
    opts: ResearchPollOptions = {},
  ): Promise<ResearchResponse> {
    const interval = opts.interval ?? 2_000;
    // No `deep` hint here since we don't have the original request;
    // pick the longer window so shallow jobs finish comfortably.
    const maxWait = opts.maxWait ?? 1_200_000;
    return pollUntilDone(
      () => this.getResearchStatus(id),
      (r) => r.status === "completed" || r.status === "failed",
      { interval, timeout: maxWait },
    );
  }
waitForCrawl method · typescript · L217-L228 (12 LOC)
src/client.ts
  async waitForCrawl(
    id: string,
    opts: CrawlPollOptions = {},
  ): Promise<CrawlStatusResponse> {
    const interval = opts.interval ?? 2_000;
    const maxWait = opts.maxWait ?? 300_000;
    return pollUntilDone(
      () => this.getCrawlStatus(id),
      (s) => s.status === "completed" || s.status === "failed",
      { interval, timeout: maxWait },
    );
  }
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
getResearchStatus method · typescript · L236-L238 (3 LOC)
src/client.ts
  async getResearchStatus(id: string): Promise<ResearchResponse> {
    return this.get<ResearchResponse>(`/v1/research/${encodeURIComponent(id)}`);
  }
watchCreate method · typescript · L242-L245 (4 LOC)
src/client.ts
  async watchCreate(params: WatchCreateRequest): Promise<WatchResponse> {
    if (!params.url) throw new Error("url is required");
    return this.post<WatchResponse>("/v1/watch", params);
  }
watchList method · typescript · L247-L253 (7 LOC)
src/client.ts
  async watchList(limit?: number, offset?: number): Promise<WatchResponse[]> {
    const query = new URLSearchParams();
    if (limit !== undefined) query.set("limit", String(limit));
    if (offset !== undefined) query.set("offset", String(offset));
    const qs = query.toString();
    return this.get<WatchResponse[]>(`/v1/watch${qs ? `?${qs}` : ""}`);
  }
watchGet method · typescript · L255-L257 (3 LOC)
src/client.ts
  async watchGet(id: string): Promise<WatchResponse> {
    return this.get<WatchResponse>(`/v1/watch/${encodeURIComponent(id)}`);
  }
watchDelete method · typescript · L259-L261 (3 LOC)
src/client.ts
  async watchDelete(id: string): Promise<void> {
    await this.del(`/v1/watch/${encodeURIComponent(id)}`);
  }
watchCheck method · typescript · L263-L268 (6 LOC)
src/client.ts
  async watchCheck(id: string): Promise<WatchResponse> {
    return this.post<WatchResponse>(
      `/v1/watch/${encodeURIComponent(id)}/check`,
      {},
    );
  }
request method · typescript · L272-L321 (50 LOC)
src/client.ts
  private async request<T>(path: string, init: RequestInit): Promise<T> {
    const url = `${this.baseUrl}${path}`;
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), this.timeout);

    let res: Response;
    try {
      res = await fetch(url, { ...init, signal: controller.signal });
    } catch (err: unknown) {
      if (isAbortError(err)) {
        throw new TimeoutError(this.timeout);
      }
      throw new WebclawError(
        err instanceof Error ? err.message : "Network request failed",
      );
    } finally {
      clearTimeout(timer);
    }

    // DELETE with 204 has no body
    if (res.ok && res.status === 204) {
      return undefined as T;
    }

    if (res.ok) {
      try {
        return (await res.json()) as T;
      } catch {
        throw new WebclawError("Invalid JSON in response body", res.status);
      }
    }

    const body = await res.text().catch(() => null);
    const parsed = tryParseJson(body);
    const
post method · typescript · L323-L332 (10 LOC)
src/client.ts
  private post<T>(path: string, body: unknown): Promise<T> {
    return this.request<T>(path, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${this.apiKey}`,
      },
      body: JSON.stringify(body),
    });
  }
Repobility · open methodology · https://repobility.com/research/
get method · typescript · L334-L339 (6 LOC)
src/client.ts
  private get<T>(path: string): Promise<T> {
    return this.request<T>(path, {
      method: "GET",
      headers: { Authorization: `Bearer ${this.apiKey}` },
    });
  }
del method · typescript · L341-L346 (6 LOC)
src/client.ts
  private del(path: string): Promise<void> {
    return this.request<void>(path, {
      method: "DELETE",
      headers: { Authorization: `Bearer ${this.apiKey}` },
    });
  }
CrawlJob class · typescript · L353-L375 (23 LOC)
src/client.ts
export class CrawlJob {
  constructor(
    public readonly id: string,
    private readonly client: Webclaw,
  ) {}

  async getStatus(): Promise<CrawlStatusResponse> {
    return this.client.getCrawlStatus(this.id);
  }

  async waitForCompletion(
    opts: CrawlPollOptions = {},
  ): Promise<CrawlStatusResponse> {
    const interval = opts.interval ?? 2_000;
    const maxWait = opts.maxWait ?? 300_000;

    return pollUntilDone(
      () => this.getStatus(),
      (s) => s.status === "completed" || s.status === "failed",
      { interval, timeout: maxWait },
    );
  }
}
constructor method · typescript · L354-L357 (4 LOC)
src/client.ts
  constructor(
    public readonly id: string,
    private readonly client: Webclaw,
  ) {}
getStatus method · typescript · L359-L361 (3 LOC)
src/client.ts
  async getStatus(): Promise<CrawlStatusResponse> {
    return this.client.getCrawlStatus(this.id);
  }
waitForCompletion method · typescript · L363-L374 (12 LOC)
src/client.ts
  async waitForCompletion(
    opts: CrawlPollOptions = {},
  ): Promise<CrawlStatusResponse> {
    const interval = opts.interval ?? 2_000;
    const maxWait = opts.maxWait ?? 300_000;

    return pollUntilDone(
      () => this.getStatus(),
      (s) => s.status === "completed" || s.status === "failed",
      { interval, timeout: maxWait },
    );
  }
pollUntilDone function · typescript · L380-L383 (4 LOC)
src/client.ts
async function pollUntilDone<T>(
  checkFn: () => Promise<T>,
  isDone: (result: T) => boolean,
  options: { interval: number; timeout: number },
isAbortError function · typescript · L396-L400 (5 LOC)
src/client.ts
function isAbortError(err: unknown): boolean {
  if (err instanceof DOMException && err.name === "AbortError") return true;
  if (err instanceof Error && err.name === "AbortError") return true;
  return false;
}
Repobility (the analyzer behind this table) · https://repobility.com
sleep function · typescript · L402-L404 (3 LOC)
src/client.ts
function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
tryParseJson function · typescript · L406-L413 (8 LOC)
src/client.ts
function tryParseJson(text: string | null): unknown {
  if (!text) return null;
  try {
    return JSON.parse(text);
  } catch {
    return null;
  }
}
parseRetryAfter function · typescript · L415-L419 (5 LOC)
src/client.ts
function parseRetryAfter(header: string | null): number | null {
  if (!header) return null;
  const seconds = Number(header);
  return Number.isFinite(seconds) ? seconds : null;
}
WebclawError class · typescript · L6-L15 (10 LOC)
src/errors.ts
export class WebclawError extends Error {
  constructor(
    message: string,
    public readonly status?: number,
    public readonly body?: unknown,
  ) {
    super(message);
    this.name = "WebclawError";
  }
}
constructor method · typescript · L7-L14 (8 LOC)
src/errors.ts
  constructor(
    message: string,
    public readonly status?: number,
    public readonly body?: unknown,
  ) {
    super(message);
    this.name = "WebclawError";
  }
AuthenticationError class · typescript · L17-L22 (6 LOC)
src/errors.ts
export class AuthenticationError extends WebclawError {
  constructor(message = "Invalid or missing API key") {
    super(message, 401);
    this.name = "AuthenticationError";
  }
}
constructor method · typescript · L18-L21 (4 LOC)
src/errors.ts
  constructor(message = "Invalid or missing API key") {
    super(message, 401);
    this.name = "AuthenticationError";
  }
RateLimitError class · typescript · L24-L32 (9 LOC)
src/errors.ts
export class RateLimitError extends WebclawError {
  public readonly retryAfter: number | null;

  constructor(retryAfterSeconds: number | null = null) {
    super("Rate limit exceeded", 429);
    this.name = "RateLimitError";
    this.retryAfter = retryAfterSeconds;
  }
}
Repobility — same analyzer, your code, free for public repos · /scan/
constructor method · typescript · L27-L31 (5 LOC)
src/errors.ts
  constructor(retryAfterSeconds: number | null = null) {
    super("Rate limit exceeded", 429);
    this.name = "RateLimitError";
    this.retryAfter = retryAfterSeconds;
  }
NotFoundError class · typescript · L34-L39 (6 LOC)
src/errors.ts
export class NotFoundError extends WebclawError {
  constructor(message = "Resource not found") {
    super(message, 404);
    this.name = "NotFoundError";
  }
}
constructor method · typescript · L35-L38 (4 LOC)
src/errors.ts
  constructor(message = "Resource not found") {
    super(message, 404);
    this.name = "NotFoundError";
  }
TimeoutError class · typescript · L41-L46 (6 LOC)
src/errors.ts
export class TimeoutError extends WebclawError {
  constructor(timeoutMs: number) {
    super(`Request timed out after ${timeoutMs}ms`);
    this.name = "TimeoutError";
  }
}
constructor method · typescript · L42-L45 (4 LOC)
src/errors.ts
  constructor(timeoutMs: number) {
    super(`Request timed out after ${timeoutMs}ms`);
    this.name = "TimeoutError";
  }