diff --git a/.stats.yml b/.stats.yml
index 6e991c2..ff3783d 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
-configured_endpoints: 6
+configured_endpoints: 9
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/nen-labs%2Fsteel-73f12c3021fc56466b869b17a82fec982131d51e383151c897908d874bc188da.yml
diff --git a/api.md b/api.md
index ab2d301..328188a 100644
--- a/api.md
+++ b/api.md
@@ -1,3 +1,17 @@
+# Steel
+
+Types:
+
+- PdfResponse
+- ScrapeResponse
+- ScreenshotResponse
+
+Methods:
+
+- client.pdf({ ...params }) -> PdfResponse
+- client.scrape({ ...params }) -> ScrapeResponse
+- client.screenshot({ ...params }) -> ScreenshotResponse
+
# Sessions
Types:
diff --git a/src/index.ts b/src/index.ts
index 9e7645c..b02f68a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -7,6 +7,15 @@ import * as Pagination from './pagination';
import { type SessionsCursorParams, SessionsCursorResponse } from './pagination';
import * as Uploads from './uploads';
import * as API from './resources/index';
+import * as TopLevelAPI from './resources/top-level';
+import {
+ PdfParams,
+ PdfResponse,
+ ScrapeParams,
+ ScrapeResponse,
+ ScreenshotParams,
+ ScreenshotResponse,
+} from './resources/top-level';
import {
Session,
SessionContext,
@@ -137,6 +146,33 @@ export class Steel extends Core.APIClient {
sessions: API.Sessions = new API.Sessions(this);
+ /**
+ * Generates a PDF from a specified webpage.
+ */
+ pdf(body: TopLevelAPI.PdfParams, options?: Core.RequestOptions): Core.APIPromise {
+ return this.post('/v1/pdf', { body, ...options });
+ }
+
+ /**
+ * Extracts content from a specified URL.
+ */
+ scrape(
+ body: TopLevelAPI.ScrapeParams,
+ options?: Core.RequestOptions,
+ ): Core.APIPromise {
+ return this.post('/v1/scrape', { body, ...options });
+ }
+
+ /**
+ * Captures a screenshot of a specified webpage.
+ */
+ screenshot(
+ body: TopLevelAPI.ScreenshotParams,
+ options?: Core.RequestOptions,
+ ): Core.APIPromise {
+ return this.post('/v1/screenshot', { body, ...options });
+ }
+
protected override defaultQuery(): Core.DefaultQuery | undefined {
return this._options.defaultQuery;
}
@@ -184,6 +220,15 @@ export declare namespace Steel {
type SessionsCursorResponse as SessionsCursorResponse,
};
+ export {
+ type PdfResponse as PdfResponse,
+ type ScrapeResponse as ScrapeResponse,
+ type ScreenshotResponse as ScreenshotResponse,
+ type PdfParams as PdfParams,
+ type ScrapeParams as ScrapeParams,
+ type ScreenshotParams as ScreenshotParams,
+ };
+
export {
Sessions as Sessions,
type Session as Session,
diff --git a/src/resources/index.ts b/src/resources/index.ts
index 5c4c83f..0586b0d 100644
--- a/src/resources/index.ts
+++ b/src/resources/index.ts
@@ -14,3 +14,11 @@ export {
type SessionReleaseParams,
type SessionReleaseAllParams,
} from './sessions';
+export {
+ type PdfResponse,
+ type ScrapeResponse,
+ type ScreenshotResponse,
+ type PdfParams,
+ type ScrapeParams,
+ type ScreenshotParams,
+} from './top-level';
diff --git a/src/resources/top-level.ts b/src/resources/top-level.ts
new file mode 100644
index 0000000..469536c
--- /dev/null
+++ b/src/resources/top-level.ts
@@ -0,0 +1,214 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export interface PdfResponse {
+ /**
+ * URL where the PDF is hosted
+ */
+ url: string;
+}
+
+/**
+ * Response from a successful scrape request
+ */
+export interface ScrapeResponse {
+ content: ScrapeResponse.Content;
+
+ links: Array;
+
+ metadata: ScrapeResponse.Metadata;
+
+ pdf?: ScrapeResponse.Pdf;
+
+ screenshot?: ScrapeResponse.Screenshot;
+}
+
+export namespace ScrapeResponse {
+ export interface Content {
+ /**
+ * Cleaned HTML content of the webpage
+ */
+ cleaned_html?: string;
+
+ /**
+ * Raw HTML content of the webpage
+ */
+ html?: string;
+
+ /**
+ * Webpage content converted to Markdown
+ */
+ markdown?: string;
+
+ /**
+ * Webpage content in Readability format
+ */
+ readability?: Record;
+ }
+
+ export interface Link {
+ /**
+ * Text content of the link
+ */
+ text: string;
+
+ /**
+ * URL of the link
+ */
+ url: string;
+ }
+
+ export interface Metadata {
+ /**
+ * HTTP status code of the response
+ */
+ statusCode: number;
+
+ /**
+ * Description of the webpage
+ */
+ description?: string;
+
+ /**
+ * Detected language of the webpage
+ */
+ language?: string;
+
+ /**
+ * Open Graph description
+ */
+ ogDescription?: string;
+
+ /**
+ * Open Graph image URL
+ */
+ ogImage?: string;
+
+ /**
+ * Open Graph title
+ */
+ ogTitle?: string;
+
+ /**
+ * Publication timestamp of the content (if available)
+ */
+ published_timestamp?: string;
+
+ /**
+ * Timestamp when the scrape was performed
+ */
+ timestamp?: string;
+
+ /**
+ * Title of the webpage
+ */
+ title?: string;
+
+ /**
+ * Source URL of the scraped page
+ */
+ urlSource?: string;
+ }
+
+ export interface Pdf {
+ /**
+ * URL of the generated PDF
+ */
+ url: string;
+ }
+
+ export interface Screenshot {
+ /**
+ * URL of the screenshot image
+ */
+ url: string;
+ }
+}
+
+export interface ScreenshotResponse {
+ /**
+ * URL where the screenshot is hosted
+ */
+ url: string;
+}
+
+export interface PdfParams {
+ /**
+ * URL of the webpage to convert to PDF
+ */
+ url: string;
+
+ /**
+ * Delay before generating the PDF (in milliseconds)
+ */
+ delay?: number;
+
+ /**
+ * Use a Steel-provided residential proxy for generating the PDF
+ */
+ useProxy?: boolean;
+}
+
+export interface ScrapeParams {
+ /**
+ * URL of the webpage to scrape
+ */
+ url: string;
+
+ /**
+ * Delay before scraping (in milliseconds)
+ */
+ delay?: number;
+
+ /**
+ * Desired format(s) for the scraped content. Default is `html`.
+ */
+ format?: Array<'html' | 'readability' | 'cleaned_html' | 'markdown'>;
+
+ /**
+ * Include a PDF in the response
+ */
+ pdf?: boolean;
+
+ /**
+ * Include a screenshot in the response
+ */
+ screenshot?: boolean;
+
+ /**
+ * Use a Steel-provided residential proxy for the scrape
+ */
+ useProxy?: boolean;
+}
+
+export interface ScreenshotParams {
+ /**
+ * URL of the webpage to capture
+ */
+ url: string;
+
+ /**
+ * Delay before capturing the screenshot (in milliseconds)
+ */
+ delay?: number;
+
+ /**
+ * Capture the full page screenshot. Default is `false`.
+ */
+ fullPage?: boolean;
+
+ /**
+ * Use a Steel-provided residential proxy for capturing the screenshot
+ */
+ useProxy?: boolean;
+}
+
+export declare namespace TopLevel {
+ export {
+ type PdfResponse as PdfResponse,
+ type ScrapeResponse as ScrapeResponse,
+ type ScreenshotResponse as ScreenshotResponse,
+ type PdfParams as PdfParams,
+ type ScrapeParams as ScrapeParams,
+ type ScreenshotParams as ScreenshotParams,
+ };
+}
diff --git a/tests/api-resources/top-level.test.ts b/tests/api-resources/top-level.test.ts
new file mode 100644
index 0000000..fa65ff7
--- /dev/null
+++ b/tests/api-resources/top-level.test.ts
@@ -0,0 +1,68 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import Steel from 'steel-sdk';
+import { Response } from 'node-fetch';
+
+const client = new Steel({
+ steelAPIKey: 'My Steel API Key',
+ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
+});
+
+describe('top level methods', () => {
+ test('pdf: only required params', async () => {
+ const responsePromise = client.pdf({ url: 'https://example.com' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ test('pdf: required and optional params', async () => {
+ const response = await client.pdf({ url: 'https://example.com', delay: 0, useProxy: true });
+ });
+
+ test('scrape: only required params', async () => {
+ const responsePromise = client.scrape({ url: 'https://example.com' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ test('scrape: required and optional params', async () => {
+ const response = await client.scrape({
+ url: 'https://example.com',
+ delay: 0,
+ format: ['html'],
+ pdf: true,
+ screenshot: true,
+ useProxy: true,
+ });
+ });
+
+ test('screenshot: only required params', async () => {
+ const responsePromise = client.screenshot({ url: 'https://example.com' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ test('screenshot: required and optional params', async () => {
+ const response = await client.screenshot({
+ url: 'https://example.com',
+ delay: 0,
+ fullPage: true,
+ useProxy: true,
+ });
+ });
+});