From dc895a6f73ace40d48d008ba447d80d1283061aa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 07:12:54 +0000 Subject: [PATCH 1/6] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 22 ++-- src/resources/monitors.ts | 119 ++++++++++--------- tests/api-resources/monitors.test.ts | 18 +-- 4 files changed, 82 insertions(+), 81 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0ac1eb3..6da4682 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 32 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-242450ea46eb8c3e843fd6c4bf87e73192b5f62f6da697cd091d13c6aa7a991b.yml -openapi_spec_hash: c1c561976de1abcacede71fd5ab9b3d9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-2bf2b44f6593c44b2948683469bbb2b09cd8e90c97b12057fac6220cf0d2eee7.yml +openapi_spec_hash: ae8b5109ec997cac8d3e6ec96040f6c8 config_hash: 70e7e80b5e87f94981bee396c6cd41e8 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index a392002..0675fc2 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -1180,52 +1180,52 @@ const EMBEDDED_METHODS: MethodEntry[] = [ stainlessPath: '(resource) monitors > (method) create', qualified: 'client.monitors.create', params: [ - "change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; };", 'name: string;', - "schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; };", "target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; };", + "change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; };", "mode?: 'web';", + "schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; };", 'tags?: string[];', "webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; };", ], response: - "{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }", + "{ id: string; change_detection: object | object; created_at: string; initial_run_id: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }", markdown: - "## create\n\n`client.monitors.create(change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }, name: string, schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }, target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }, mode?: 'web', tags?: string[], webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }): { id: string; change_detection: object | object; created_at: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }`\n\n**post** `/monitors`\n\nCreates a monitor. The request body is a union of the supported target/change detection combinations. The monitor runs immediately after creation to create its initial baseline.\n\n### Parameters\n\n- `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n Discriminated union describing how changes are detected.\n\n- `name: string`\n\n- `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n Run the monitor on a fixed interval defined by a frequency and a unit, e.g. every 6 hours or every 2 days. The total interval (frequency × unit) must be between 10 minutes and 1 year.\n - `frequency: number`\n Number of units between runs. The resulting interval (frequency × unit) must be at least 10 minutes and at most 1 year (e.g. minimum 10 when unit is minutes; maximum 365 when unit is days).\n - `type: 'interval'`\n - `unit: 'minutes' | 'hours' | 'days'`\n\n- `target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n Discriminated union describing what the monitor watches.\n\n- `mode?: 'web'`\n Top-level monitor category. Always `web` today; the concrete behavior is described by `target` and `change_detection`.\n\n- `tags?: string[]`\n User-defined tags for grouping and filtering monitors and their changes. Duplicates are removed.\n\n- `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `url: string`\n Webhook URL events are delivered to.\n - `events?: 'change.detected' | 'run.completed'[]`\n Events delivered to this endpoint. `change.detected` fires only when a run detects a change; `run.completed` fires on every completed run — including runs that detected no change — and embeds the change when one was detected. Defaults to `[\"change.detected\"]` when omitted.\n - `secret?: string`\n Signing secret used to verify webhook authenticity. Each delivery includes an `X-Context-Signature: t=,v1=` header, where the HMAC is SHA-256 over `\"{t}.{rawRequestBody}\"` keyed by this secret. Recompute it with a constant-time compare and reject stale timestamps to prevent replay. Generated by the API; cannot be set by clients.\n\n### Returns\n\n- `{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }`\n A web monitor. `mode` is the constant `web`; behavior is described by `target` (page/sitemap/extract) and `change_detection` (exact/semantic).\n\n - `id: string`\n - `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n - `created_at: string`\n - `mode: 'web'`\n - `name: string`\n - `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n - `status: 'active' | 'paused' | 'failed'`\n - `target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n - `updated_at: string`\n - `baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }`\n - `last_change_at?: string`\n - `last_error?: { code: string; message: string; }`\n - `last_run_at?: string`\n - `next_run_at?: string`\n - `tags?: string[]`\n - `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitor = await client.monitors.create({\n change_detection: { type: 'exact' },\n name: 'Acme pricing page',\n schedule: {\n frequency: 6,\n type: 'interval',\n unit: 'hours',\n},\n target: { type: 'page', url: 'https://acme.com/pricing' },\n});\n\nconsole.log(monitor);\n```", + "## create\n\n`client.monitors.create(name: string, target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }, change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }, mode?: 'web', schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }, tags?: string[], webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }): { id: string; change_detection: object | object; created_at: string; initial_run_id: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }`\n\n**post** `/monitors`\n\nCreates a monitor. The request body is a union of the supported target/change detection combinations. The monitor runs immediately after creation to create its initial baseline.\n\n### Parameters\n\n- `name: string`\n\n- `target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n Discriminated union describing what the monitor watches.\n\n- `change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n Discriminated union describing how changes are detected.\n\n- `mode?: 'web'`\n Top-level monitor category. Always `web` today; the concrete behavior is described by `target` and `change_detection`.\n\n- `schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n Run the monitor on a fixed interval defined by a frequency and a unit, e.g. every 6 hours or every 2 days. The total interval (frequency × unit) must be between 10 minutes and 1 year.\n - `frequency: number`\n Number of units between runs. The resulting interval (frequency × unit) must be at least 10 minutes and at most 1 year (e.g. minimum 10 when unit is minutes; maximum 365 when unit is days).\n - `type: 'interval'`\n - `unit: 'minutes' | 'hours' | 'days'`\n\n- `tags?: string[]`\n User-defined tags for grouping and filtering monitors and their changes. Duplicates are removed.\n\n- `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `url: string`\n Webhook URL events are delivered to.\n - `events?: 'change.detected' | 'run.completed'[]`\n Events delivered to this endpoint. `change.detected` fires only when a run detects a change; `run.completed` fires on every completed run — including runs that detected no change — and embeds the change when one was detected. Defaults to `[\"change.detected\"]` when omitted.\n - `secret?: string`\n Signing secret used to verify webhook authenticity. Each delivery includes an `X-Context-Signature: t=,v1=` header, where the HMAC is SHA-256 over `\"{t}.{rawRequestBody}\"` keyed by this secret. Recompute it with a constant-time compare and reject stale timestamps to prevent replay. Generated by the API; cannot be set by clients.\n\n### Returns\n\n- `{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; initial_run_id: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }`\n A newly created monitor plus `initial_run_id`, the id of the baseline run queued at creation.\n\n - `id: string`\n - `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n - `created_at: string`\n - `initial_run_id: string`\n - `mode: 'web'`\n - `name: string`\n - `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n - `status: 'active' | 'paused' | 'failed'`\n - `target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n - `updated_at: string`\n - `baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }`\n - `last_change_at?: string`\n - `last_error?: { code: string; message: string; }`\n - `last_run_at?: string`\n - `next_run_at?: string`\n - `tags?: string[]`\n - `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitor = await client.monitors.create({\n name: 'Acme pricing page',\n target: { type: 'page', url: 'https://acme.com/pricing' },\n});\n\nconsole.log(monitor);\n```", perLanguage: { typescript: { method: 'client.monitors.create', example: - "import ContextDev from 'context.dev';\n\nconst client = new ContextDev({\n apiKey: process.env['CONTEXT_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst monitor = await client.monitors.create({\n change_detection: { type: 'exact' },\n name: 'Acme pricing page',\n schedule: {\n type: 'interval',\n frequency: 6,\n unit: 'hours',\n },\n target: { type: 'page', url: 'https://acme.com/pricing' },\n mode: 'web',\n webhook: { url: 'https://example.com/webhook' },\n});\n\nconsole.log(monitor.id);", + "import ContextDev from 'context.dev';\n\nconst client = new ContextDev({\n apiKey: process.env['CONTEXT_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst monitor = await client.monitors.create({\n name: 'Acme pricing page',\n target: { type: 'page', url: 'https://acme.com/pricing' },\n change_detection: { type: 'exact' },\n mode: 'web',\n schedule: {\n type: 'interval',\n frequency: 6,\n unit: 'hours',\n },\n webhook: { url: 'https://example.com/webhook' },\n});\n\nconsole.log(monitor.id);", }, python: { method: 'monitors.create', example: - 'import os\nfrom context.dev import ContextDev\n\nclient = ContextDev(\n api_key=os.environ.get("CONTEXT_DEV_API_KEY"), # This is the default and can be omitted\n)\nmonitor = client.monitors.create(\n change_detection={\n "type": "exact"\n },\n name="Acme pricing page",\n schedule={\n "type": "interval",\n "frequency": 6,\n "unit": "hours",\n },\n target={\n "type": "page",\n "url": "https://acme.com/pricing",\n },\n mode="web",\n webhook={\n "url": "https://example.com/webhook"\n },\n)\nprint(monitor.id)', + 'import os\nfrom context.dev import ContextDev\n\nclient = ContextDev(\n api_key=os.environ.get("CONTEXT_DEV_API_KEY"), # This is the default and can be omitted\n)\nmonitor = client.monitors.create(\n name="Acme pricing page",\n target={\n "type": "page",\n "url": "https://acme.com/pricing",\n },\n change_detection={\n "type": "exact"\n },\n mode="web",\n schedule={\n "type": "interval",\n "frequency": 6,\n "unit": "hours",\n },\n webhook={\n "url": "https://example.com/webhook"\n },\n)\nprint(monitor.id)', }, go: { method: 'client.Monitors.New', example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/context-dot-dev/context-go-sdk"\n\t"github.com/context-dot-dev/context-go-sdk/option"\n)\n\nfunc main() {\n\tclient := contextdev.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmonitor, err := client.Monitors.New(context.TODO(), contextdev.MonitorNewParams{\n\t\tChangeDetection: contextdev.MonitorNewParamsChangeDetectionUnion{\n\t\t\tOfExact: &contextdev.MonitorNewParamsChangeDetectionExact{},\n\t\t},\n\t\tName: "Acme pricing page",\n\t\tSchedule: contextdev.MonitorNewParamsSchedule{\n\t\t\tType: "interval",\n\t\t\tFrequency: 6,\n\t\t\tUnit: "hours",\n\t\t},\n\t\tTarget: contextdev.MonitorNewParamsTargetUnion{\n\t\t\tOfPage: &contextdev.MonitorNewParamsTargetPage{\n\t\t\t\tURL: "https://acme.com/pricing",\n\t\t\t},\n\t\t},\n\t\tMode: contextdev.MonitorNewParamsModeWeb,\n\t\tWebhook: contextdev.MonitorNewParamsWebhook{\n\t\t\tURL: "https://example.com/webhook",\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", monitor.ID)\n}\n', + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/context-dot-dev/context-go-sdk"\n\t"github.com/context-dot-dev/context-go-sdk/option"\n)\n\nfunc main() {\n\tclient := contextdev.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmonitor, err := client.Monitors.New(context.TODO(), contextdev.MonitorNewParams{\n\t\tName: "Acme pricing page",\n\t\tTarget: contextdev.MonitorNewParamsTargetUnion{\n\t\t\tOfPage: &contextdev.MonitorNewParamsTargetPage{\n\t\t\t\tURL: "https://acme.com/pricing",\n\t\t\t},\n\t\t},\n\t\tChangeDetection: contextdev.MonitorNewParamsChangeDetectionUnion{\n\t\t\tOfExact: &contextdev.MonitorNewParamsChangeDetectionExact{},\n\t\t},\n\t\tMode: contextdev.MonitorNewParamsModeWeb,\n\t\tSchedule: contextdev.MonitorNewParamsSchedule{\n\t\t\tType: "interval",\n\t\t\tFrequency: 6,\n\t\t\tUnit: "hours",\n\t\t},\n\t\tWebhook: contextdev.MonitorNewParamsWebhook{\n\t\t\tURL: "https://example.com/webhook",\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", monitor.ID)\n}\n', }, ruby: { method: 'monitors.create', example: - 'require "context_dev"\n\ncontext_dev = ContextDev::Client.new(api_key: "My API Key")\n\nmonitor = context_dev.monitors.create(\n change_detection: {type: :exact},\n name: "Acme pricing page",\n schedule: {frequency: 6, type: :interval, unit: :hours},\n target: {type: :page, url: "https://acme.com/pricing"}\n)\n\nputs(monitor)', + 'require "context_dev"\n\ncontext_dev = ContextDev::Client.new(api_key: "My API Key")\n\nmonitor = context_dev.monitors.create(\n name: "Acme pricing page",\n target: {type: :page, url: "https://acme.com/pricing"}\n)\n\nputs(monitor)', }, cli: { method: 'monitors create', example: - "context-dev monitors create \\\n --api-key 'My API Key' \\\n --change-detection '{type: exact}' \\\n --name 'Acme pricing page' \\\n --schedule '{frequency: 6, type: interval, unit: hours}' \\\n --target '{type: page, url: https://acme.com/pricing}'", + "context-dev monitors create \\\n --api-key 'My API Key' \\\n --name 'Acme pricing page' \\\n --target '{type: page, url: https://acme.com/pricing}'", }, php: { method: 'monitors->create', example: - "monitors->create(\n changeDetection: ['type' => 'exact'],\n name: 'Acme pricing page',\n schedule: ['frequency' => 6, 'type' => 'interval', 'unit' => 'hours'],\n target: [\n 'type' => 'page',\n 'url' => 'https://acme.com/pricing',\n 'normalizeWhitespace' => true,\n ],\n mode: 'web',\n tags: ['pricing', 'competitor'],\n webhook: [\n 'url' => 'https://example.com/webhook',\n 'events' => ['change.detected', 'run.completed'],\n ],\n);\n\nvar_dump($monitor);", + "monitors->create(\n name: 'Acme pricing page',\n target: [\n 'type' => 'page',\n 'url' => 'https://acme.com/pricing',\n 'normalizeWhitespace' => true,\n ],\n changeDetection: ['type' => 'exact'],\n mode: 'web',\n schedule: ['frequency' => 6, 'type' => 'interval', 'unit' => 'hours'],\n tags: ['pricing', 'competitor'],\n webhook: [\n 'url' => 'https://example.com/webhook',\n 'events' => ['change.detected', 'run.completed'],\n ],\n);\n\nvar_dump($monitor);", }, http: { example: - 'curl https://api.context.dev/v1/monitors \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $CONTEXT_DEV_API_KEY" \\\n -d \'{\n "change_detection": {\n "type": "exact"\n },\n "name": "Acme pricing page",\n "schedule": {\n "frequency": 6,\n "type": "interval",\n "unit": "hours"\n },\n "target": {\n "type": "page",\n "url": "https://acme.com/pricing"\n },\n "mode": "web",\n "tags": [\n "pricing",\n "competitor"\n ],\n "webhook": {\n "url": "https://example.com/webhook"\n }\n }\'', + 'curl https://api.context.dev/v1/monitors \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $CONTEXT_DEV_API_KEY" \\\n -d \'{\n "name": "Acme pricing page",\n "target": {\n "type": "page",\n "url": "https://acme.com/pricing"\n },\n "change_detection": {\n "type": "exact"\n },\n "mode": "web",\n "schedule": {\n "frequency": 6,\n "type": "interval",\n "unit": "hours"\n },\n "tags": [\n "pricing",\n "competitor"\n ],\n "webhook": {\n "url": "https://example.com/webhook"\n }\n }\'', }, }, }, diff --git a/src/resources/monitors.ts b/src/resources/monitors.ts index 9d8d990..ab0b610 100644 --- a/src/resources/monitors.ts +++ b/src/resources/monitors.ts @@ -18,15 +18,15 @@ export class Monitors extends APIResource { * @example * ```ts * const monitor = await client.monitors.create({ - * change_detection: { type: 'exact' }, * name: 'Acme pricing page', + * target: { type: 'page', url: 'https://acme.com/pricing' }, + * change_detection: { type: 'exact' }, + * mode: 'web', * schedule: { * type: 'interval', * frequency: 6, * unit: 'hours', * }, - * target: { type: 'page', url: 'https://acme.com/pricing' }, - * mode: 'web', * webhook: { url: 'https://example.com/webhook' }, * }); * ``` @@ -262,8 +262,8 @@ export namespace WebhookDelivery { } /** - * A web monitor. `mode` is the constant `web`; behavior is described by `target` - * (page/sitemap/extract) and `change_detection` (exact/semantic). + * A newly created monitor plus `initial_run_id`, the id of the baseline run queued + * at creation. */ export interface MonitorCreateResponse { id: string; @@ -277,6 +277,13 @@ export interface MonitorCreateResponse { created_at: string; + /** + * The baseline run queued by this create call, or null if it could not be queued + * immediately (in which case the baseline runs on the next scheduled tick). Poll + * GET /monitors/{monitor_id}/runs/{run_id}. + */ + initial_run_id: string | null; + /** * Top-level monitor category. Always `web` today; the concrete behavior is * described by `target` and `change_detection`. @@ -2062,22 +2069,8 @@ export interface MonitorRunResponse { } export interface MonitorCreateParams { - /** - * Discriminated union describing how changes are detected. - */ - change_detection: - | MonitorCreateParams.MonitorsExactChangeDetection - | MonitorCreateParams.MonitorsSemanticChangeDetection; - name: string; - /** - * Run the monitor on a fixed interval defined by a frequency and a unit, e.g. - * every 6 hours or every 2 days. The total interval (frequency × unit) must be - * between 10 minutes and 1 year. - */ - schedule: MonitorCreateParams.Schedule; - /** * Discriminated union describing what the monitor watches. */ @@ -2086,12 +2079,26 @@ export interface MonitorCreateParams { | MonitorCreateParams.MonitorsSitemapTarget | MonitorCreateParams.MonitorsExtractTarget; + /** + * Discriminated union describing how changes are detected. + */ + change_detection?: + | MonitorCreateParams.MonitorsExactChangeDetection + | MonitorCreateParams.MonitorsSemanticChangeDetection; + /** * Top-level monitor category. Always `web` today; the concrete behavior is * described by `target` and `change_detection`. */ mode?: 'web'; + /** + * Run the monitor on a fixed interval defined by a frequency and a unit, e.g. + * every 6 hours or every 2 days. The total interval (frequency × unit) must be + * between 10 minutes and 1 year. + */ + schedule?: MonitorCreateParams.Schedule; + /** * User-defined tags for grouping and filtering monitors and their changes. * Duplicates are removed. @@ -2102,43 +2109,6 @@ export interface MonitorCreateParams { } export namespace MonitorCreateParams { - /** - * Detect exact changes. For page targets, this means visible text diffs. For - * sitemap targets, this means URL additions and removals. - */ - export interface MonitorsExactChangeDetection { - type: 'exact'; - } - - /** - * Detect meaning-level changes to tracked page content, ignoring cosmetic or - * paraphrase-only differences. Which changes are meaningful is judged against the - * extract target's `instructions` (and `schema`, when provided). - */ - export interface MonitorsSemanticChangeDetection { - type: 'semantic'; - - confidence_threshold?: number; - } - - /** - * Run the monitor on a fixed interval defined by a frequency and a unit, e.g. - * every 6 hours or every 2 days. The total interval (frequency × unit) must be - * between 10 minutes and 1 year. - */ - export interface Schedule { - /** - * Number of units between runs. The resulting interval (frequency × unit) must be - * at least 10 minutes and at most 1 year (e.g. minimum 10 when unit is minutes; - * maximum 365 when unit is days). - */ - frequency: number; - - type: 'interval'; - - unit: 'minutes' | 'hours' | 'days'; - } - /** * Watch a single web page. */ @@ -2230,6 +2200,43 @@ export namespace MonitorCreateParams { schema?: { [key: string]: unknown }; } + /** + * Detect exact changes. For page targets, this means visible text diffs. For + * sitemap targets, this means URL additions and removals. + */ + export interface MonitorsExactChangeDetection { + type: 'exact'; + } + + /** + * Detect meaning-level changes to tracked page content, ignoring cosmetic or + * paraphrase-only differences. Which changes are meaningful is judged against the + * extract target's `instructions` (and `schema`, when provided). + */ + export interface MonitorsSemanticChangeDetection { + type: 'semantic'; + + confidence_threshold?: number; + } + + /** + * Run the monitor on a fixed interval defined by a frequency and a unit, e.g. + * every 6 hours or every 2 days. The total interval (frequency × unit) must be + * between 10 minutes and 1 year. + */ + export interface Schedule { + /** + * Number of units between runs. The resulting interval (frequency × unit) must be + * at least 10 minutes and at most 1 year (e.g. minimum 10 when unit is minutes; + * maximum 365 when unit is days). + */ + frequency: number; + + type: 'interval'; + + unit: 'minutes' | 'hours' | 'days'; + } + export interface Webhook { /** * Webhook URL events are delivered to. diff --git a/tests/api-resources/monitors.test.ts b/tests/api-resources/monitors.test.ts index 26a89f3..fa69e07 100644 --- a/tests/api-resources/monitors.test.ts +++ b/tests/api-resources/monitors.test.ts @@ -11,13 +11,7 @@ describe('resource monitors', () => { // Mock server tests are disabled test.skip('create: only required params', async () => { const responsePromise = client.monitors.create({ - change_detection: { type: 'exact' }, name: 'Acme pricing page', - schedule: { - frequency: 6, - type: 'interval', - unit: 'hours', - }, target: { type: 'page', url: 'https://acme.com/pricing' }, }); const rawResponse = await responsePromise.asResponse(); @@ -32,19 +26,19 @@ describe('resource monitors', () => { // Mock server tests are disabled test.skip('create: required and optional params', async () => { const response = await client.monitors.create({ - change_detection: { type: 'exact' }, name: 'Acme pricing page', - schedule: { - frequency: 6, - type: 'interval', - unit: 'hours', - }, target: { type: 'page', url: 'https://acme.com/pricing', normalize_whitespace: true, }, + change_detection: { type: 'exact' }, mode: 'web', + schedule: { + frequency: 6, + type: 'interval', + unit: 'hours', + }, tags: ['pricing', 'competitor'], webhook: { url: 'https://example.com/webhook', events: ['change.detected', 'run.completed'] }, }); From 09c34c9d22462550b52a3468818b28848a291cf9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 06:43:25 +0000 Subject: [PATCH 2/6] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 20 ++-- src/resources/monitors.ts | 96 +++++++++++++++----- tests/api-resources/monitors.test.ts | 2 + 4 files changed, 86 insertions(+), 36 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6da4682..3f4cd2e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 32 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-2bf2b44f6593c44b2948683469bbb2b09cd8e90c97b12057fac6220cf0d2eee7.yml -openapi_spec_hash: ae8b5109ec997cac8d3e6ec96040f6c8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-91f4286859fc23813c5255b877395c87dd81520c3913fdfdae3cfa343e1a4873.yml +openapi_spec_hash: 71746b5b65f20617ee021e071d5f7f92 config_hash: 70e7e80b5e87f94981bee396c6cd41e8 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 0675fc2..6b45eca 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -1181,7 +1181,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.monitors.create', params: [ 'name: string;', - "target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; };", + "target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; };", "change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; };", "mode?: 'web';", "schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; };", @@ -1191,7 +1191,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ id: string; change_detection: object | object; created_at: string; initial_run_id: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }", markdown: - "## create\n\n`client.monitors.create(name: string, target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }, change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }, mode?: 'web', schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }, tags?: string[], webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }): { id: string; change_detection: object | object; created_at: string; initial_run_id: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }`\n\n**post** `/monitors`\n\nCreates a monitor. The request body is a union of the supported target/change detection combinations. The monitor runs immediately after creation to create its initial baseline.\n\n### Parameters\n\n- `name: string`\n\n- `target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n Discriminated union describing what the monitor watches.\n\n- `change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n Discriminated union describing how changes are detected.\n\n- `mode?: 'web'`\n Top-level monitor category. Always `web` today; the concrete behavior is described by `target` and `change_detection`.\n\n- `schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n Run the monitor on a fixed interval defined by a frequency and a unit, e.g. every 6 hours or every 2 days. The total interval (frequency × unit) must be between 10 minutes and 1 year.\n - `frequency: number`\n Number of units between runs. The resulting interval (frequency × unit) must be at least 10 minutes and at most 1 year (e.g. minimum 10 when unit is minutes; maximum 365 when unit is days).\n - `type: 'interval'`\n - `unit: 'minutes' | 'hours' | 'days'`\n\n- `tags?: string[]`\n User-defined tags for grouping and filtering monitors and their changes. Duplicates are removed.\n\n- `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `url: string`\n Webhook URL events are delivered to.\n - `events?: 'change.detected' | 'run.completed'[]`\n Events delivered to this endpoint. `change.detected` fires only when a run detects a change; `run.completed` fires on every completed run — including runs that detected no change — and embeds the change when one was detected. Defaults to `[\"change.detected\"]` when omitted.\n - `secret?: string`\n Signing secret used to verify webhook authenticity. Each delivery includes an `X-Context-Signature: t=,v1=` header, where the HMAC is SHA-256 over `\"{t}.{rawRequestBody}\"` keyed by this secret. Recompute it with a constant-time compare and reject stale timestamps to prevent replay. Generated by the API; cannot be set by clients.\n\n### Returns\n\n- `{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; initial_run_id: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }`\n A newly created monitor plus `initial_run_id`, the id of the baseline run queued at creation.\n\n - `id: string`\n - `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n - `created_at: string`\n - `initial_run_id: string`\n - `mode: 'web'`\n - `name: string`\n - `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n - `status: 'active' | 'paused' | 'failed'`\n - `target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n - `updated_at: string`\n - `baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }`\n - `last_change_at?: string`\n - `last_error?: { code: string; message: string; }`\n - `last_run_at?: string`\n - `next_run_at?: string`\n - `tags?: string[]`\n - `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitor = await client.monitors.create({\n name: 'Acme pricing page',\n target: { type: 'page', url: 'https://acme.com/pricing' },\n});\n\nconsole.log(monitor);\n```", + "## create\n\n`client.monitors.create(name: string, target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }, change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }, mode?: 'web', schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }, tags?: string[], webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }): { id: string; change_detection: object | object; created_at: string; initial_run_id: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }`\n\n**post** `/monitors`\n\nCreates a monitor. The request body is a union of the supported target/change detection combinations. The monitor runs immediately after creation to create its initial baseline.\n\n### Parameters\n\n- `name: string`\n\n- `target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n Discriminated union describing what the monitor watches.\n\n- `change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n Discriminated union describing how changes are detected.\n\n- `mode?: 'web'`\n Top-level monitor category. Always `web` today; the concrete behavior is described by `target` and `change_detection`.\n\n- `schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n Run the monitor on a fixed interval defined by a frequency and a unit, e.g. every 6 hours or every 2 days. The total interval (frequency × unit) must be between 10 minutes and 1 year.\n - `frequency: number`\n Number of units between runs. The resulting interval (frequency × unit) must be at least 10 minutes and at most 1 year (e.g. minimum 10 when unit is minutes; maximum 365 when unit is days).\n - `type: 'interval'`\n - `unit: 'minutes' | 'hours' | 'days'`\n\n- `tags?: string[]`\n User-defined tags for grouping and filtering monitors and their changes. Duplicates are removed.\n\n- `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `url: string`\n Webhook URL events are delivered to.\n - `events?: 'change.detected' | 'run.completed'[]`\n Events delivered to this endpoint. `change.detected` fires only when a run detects a change; `run.completed` fires on every completed run — including runs that detected no change — and embeds the change when one was detected. Defaults to `[\"change.detected\"]` when omitted.\n - `secret?: string`\n Signing secret used to verify webhook authenticity. Each delivery includes an `X-Context-Signature: t=,v1=` header, where the HMAC is SHA-256 over `\"{t}.{rawRequestBody}\"` keyed by this secret. Recompute it with a constant-time compare and reject stale timestamps to prevent replay. Generated by the API; cannot be set by clients.\n\n### Returns\n\n- `{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; initial_run_id: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }`\n A newly created monitor plus `initial_run_id`, the id of the baseline run queued at creation.\n\n - `id: string`\n - `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n - `created_at: string`\n - `initial_run_id: string`\n - `mode: 'web'`\n - `name: string`\n - `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n - `status: 'active' | 'paused' | 'failed'`\n - `target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n - `updated_at: string`\n - `baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }`\n - `last_change_at?: string`\n - `last_error?: { code: string; message: string; }`\n - `last_run_at?: string`\n - `next_run_at?: string`\n - `tags?: string[]`\n - `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitor = await client.monitors.create({\n name: 'Acme pricing page',\n target: { type: 'page', url: 'https://acme.com/pricing' },\n});\n\nconsole.log(monitor);\n```", perLanguage: { typescript: { method: 'client.monitors.create', @@ -1221,7 +1221,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ php: { method: 'monitors->create', example: - "monitors->create(\n name: 'Acme pricing page',\n target: [\n 'type' => 'page',\n 'url' => 'https://acme.com/pricing',\n 'normalizeWhitespace' => true,\n ],\n changeDetection: ['type' => 'exact'],\n mode: 'web',\n schedule: ['frequency' => 6, 'type' => 'interval', 'unit' => 'hours'],\n tags: ['pricing', 'competitor'],\n webhook: [\n 'url' => 'https://example.com/webhook',\n 'events' => ['change.detected', 'run.completed'],\n ],\n);\n\nvar_dump($monitor);", + "monitors->create(\n name: 'Acme pricing page',\n target: [\n 'type' => 'page',\n 'url' => 'https://acme.com/pricing',\n 'instructions' => 'Report pricing or plan availability changes. Ignore counters, timestamps, testimonials, and navigation.',\n 'normalizeWhitespace' => true,\n ],\n changeDetection: ['type' => 'exact'],\n mode: 'web',\n schedule: ['frequency' => 6, 'type' => 'interval', 'unit' => 'hours'],\n tags: ['pricing', 'competitor'],\n webhook: [\n 'url' => 'https://example.com/webhook',\n 'events' => ['change.detected', 'run.completed'],\n ],\n);\n\nvar_dump($monitor);", }, http: { example: @@ -1253,7 +1253,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ data: { id: string; change_detection: object | object; created_at: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }[]; has_more: boolean; next_cursor: string; }", markdown: - "## list\n\n`client.monitors.list(change_detection_type?: 'exact' | 'semantic', cursor?: string, limit?: number, q?: string, search_by?: 'name' | 'url' | 'instructions' | 'tags'[], search_type?: 'exact' | 'prefix', status?: 'active' | 'paused' | 'failed', tag?: string, tags?: string[], target_type?: 'page' | 'sitemap' | 'extract'): { data: object[]; has_more: boolean; next_cursor: string; }`\n\n**get** `/monitors`\n\nLists monitors for the authenticated organization. Supports free-text search (`q` over `search_by` fields, `prefix` or `exact` via `search_type`) plus status/type/tag filters. Results are paginated via the opaque `cursor`.\n\n### Parameters\n\n- `change_detection_type?: 'exact' | 'semantic'`\n Filter by change detection type.\n\n- `cursor?: string`\n Opaque pagination cursor from a previous response.\n\n- `limit?: number`\n Maximum number of items to return per page (1-100). Defaults to 25.\n\n- `q?: string`\n Free-text search term, matched against the fields named in `search_by`.\n\n- `search_by?: 'name' | 'url' | 'instructions' | 'tags'[]`\n Comma-separated fields to search with `q`. Defaults to all of them. Note `instructions` only exists on extract monitors.\n\n- `search_type?: 'exact' | 'prefix'`\n `prefix` for as-you-type prefix matching (default), `exact` for full-token matching.\n\n- `status?: 'active' | 'paused' | 'failed'`\n Filter monitors by lifecycle status.\n\n- `tag?: string`\n Filter to items that have this tag.\n\n- `tags?: string[]`\n Comma-separated list of tags to filter by (matches monitors having any of them).\n\n- `target_type?: 'page' | 'sitemap' | 'extract'`\n Filter by target type.\n\n### Returns\n\n- `{ data: { id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }[]; has_more: boolean; next_cursor: string; }`\n\n - `data: { id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }[]`\n - `has_more: boolean`\n - `next_cursor: string`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitors = await client.monitors.list();\n\nconsole.log(monitors);\n```", + "## list\n\n`client.monitors.list(change_detection_type?: 'exact' | 'semantic', cursor?: string, limit?: number, q?: string, search_by?: 'name' | 'url' | 'instructions' | 'tags'[], search_type?: 'exact' | 'prefix', status?: 'active' | 'paused' | 'failed', tag?: string, tags?: string[], target_type?: 'page' | 'sitemap' | 'extract'): { data: object[]; has_more: boolean; next_cursor: string; }`\n\n**get** `/monitors`\n\nLists monitors for the authenticated organization. Supports free-text search (`q` over `search_by` fields, `prefix` or `exact` via `search_type`) plus status/type/tag filters. Results are paginated via the opaque `cursor`.\n\n### Parameters\n\n- `change_detection_type?: 'exact' | 'semantic'`\n Filter by change detection type.\n\n- `cursor?: string`\n Opaque pagination cursor from a previous response.\n\n- `limit?: number`\n Maximum number of items to return per page (1-100). Defaults to 25.\n\n- `q?: string`\n Free-text search term, matched against the fields named in `search_by`.\n\n- `search_by?: 'name' | 'url' | 'instructions' | 'tags'[]`\n Comma-separated fields to search with `q`. Defaults to all of them. Note `instructions` only exists on extract monitors.\n\n- `search_type?: 'exact' | 'prefix'`\n `prefix` for as-you-type prefix matching (default), `exact` for full-token matching.\n\n- `status?: 'active' | 'paused' | 'failed'`\n Filter monitors by lifecycle status.\n\n- `tag?: string`\n Filter to items that have this tag.\n\n- `tags?: string[]`\n Comma-separated list of tags to filter by (matches monitors having any of them).\n\n- `target_type?: 'page' | 'sitemap' | 'extract'`\n Filter by target type.\n\n### Returns\n\n- `{ data: { id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }[]; has_more: boolean; next_cursor: string; }`\n\n - `data: { id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }[]`\n - `has_more: boolean`\n - `next_cursor: string`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitors = await client.monitors.list();\n\nconsole.log(monitors);\n```", perLanguage: { typescript: { method: 'client.monitors.list', @@ -1300,9 +1300,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.monitors.retrieve', params: ['monitor_id: string;'], response: - "{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }", + "{ id: string; change_detection: object | object; created_at: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }", markdown: - "## retrieve\n\n`client.monitors.retrieve(monitor_id: string): { id: string; change_detection: object | object; created_at: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }`\n\n**get** `/monitors/{monitor_id}`\n\nGet a monitor\n\n### Parameters\n\n- `monitor_id: string`\n\n### Returns\n\n- `{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }`\n A web monitor. `mode` is the constant `web`; behavior is described by `target` (page/sitemap/extract) and `change_detection` (exact/semantic).\n\n - `id: string`\n - `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n - `created_at: string`\n - `mode: 'web'`\n - `name: string`\n - `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n - `status: 'active' | 'paused' | 'failed'`\n - `target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n - `updated_at: string`\n - `baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }`\n - `last_change_at?: string`\n - `last_error?: { code: string; message: string; }`\n - `last_run_at?: string`\n - `next_run_at?: string`\n - `tags?: string[]`\n - `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitor = await client.monitors.retrieve('mon_123');\n\nconsole.log(monitor);\n```", + "## retrieve\n\n`client.monitors.retrieve(monitor_id: string): { id: string; change_detection: object | object; created_at: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }`\n\n**get** `/monitors/{monitor_id}`\n\nGet a monitor\n\n### Parameters\n\n- `monitor_id: string`\n\n### Returns\n\n- `{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }`\n A web monitor. `mode` is the constant `web`; behavior is described by `target` (page/sitemap/extract) and `change_detection` (exact/semantic).\n\n - `id: string`\n - `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n - `created_at: string`\n - `mode: 'web'`\n - `name: string`\n - `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n - `status: 'active' | 'paused' | 'failed'`\n - `target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n - `updated_at: string`\n - `baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }`\n - `last_change_at?: string`\n - `last_error?: { code: string; message: string; }`\n - `last_run_at?: string`\n - `next_run_at?: string`\n - `tags?: string[]`\n - `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitor = await client.monitors.retrieve('mon_123');\n\nconsole.log(monitor);\n```", perLanguage: { typescript: { method: 'client.monitors.retrieve', @@ -1355,13 +1355,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ "schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; };", "status?: 'active' | 'paused';", 'tags?: string[];', - "target?: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; };", + "target?: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; };", "webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; };", ], response: - "{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }", + "{ id: string; change_detection: object | object; created_at: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }", markdown: - "## update\n\n`client.monitors.update(monitor_id: string, change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }, name?: string, schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }, status?: 'active' | 'paused', tags?: string[], target?: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }, webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }): { id: string; change_detection: object | object; created_at: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }`\n\n**patch** `/monitors/{monitor_id}`\n\nUpdates a monitor. If `target` or `change_detection` changes, the monitor creates a new baseline. Unsupported target/change detection combinations are rejected.\n\n### Parameters\n\n- `monitor_id: string`\n\n- `change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n Discriminated union describing how changes are detected.\n\n- `name?: string`\n\n- `schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n Run the monitor on a fixed interval defined by a frequency and a unit, e.g. every 6 hours or every 2 days. The total interval (frequency × unit) must be between 10 minutes and 1 year.\n - `frequency: number`\n Number of units between runs. The resulting interval (frequency × unit) must be at least 10 minutes and at most 1 year (e.g. minimum 10 when unit is minutes; maximum 365 when unit is days).\n - `type: 'interval'`\n - `unit: 'minutes' | 'hours' | 'days'`\n\n- `status?: 'active' | 'paused'`\n\n- `tags?: string[]`\n User-defined tags for grouping and filtering monitors and their changes. Duplicates are removed.\n\n- `target?: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n Discriminated union describing what the monitor watches.\n\n- `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n Set to null to remove the webhook.\n - `url: string`\n Webhook URL events are delivered to.\n - `events?: 'change.detected' | 'run.completed'[]`\n Events delivered to this endpoint. `change.detected` fires only when a run detects a change; `run.completed` fires on every completed run — including runs that detected no change — and embeds the change when one was detected. Defaults to `[\"change.detected\"]` when omitted.\n - `secret?: string`\n Signing secret used to verify webhook authenticity. Each delivery includes an `X-Context-Signature: t=,v1=` header, where the HMAC is SHA-256 over `\"{t}.{rawRequestBody}\"` keyed by this secret. Recompute it with a constant-time compare and reject stale timestamps to prevent replay. Generated by the API; cannot be set by clients.\n\n### Returns\n\n- `{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }`\n A web monitor. `mode` is the constant `web`; behavior is described by `target` (page/sitemap/extract) and `change_detection` (exact/semantic).\n\n - `id: string`\n - `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n - `created_at: string`\n - `mode: 'web'`\n - `name: string`\n - `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n - `status: 'active' | 'paused' | 'failed'`\n - `target: { type: 'page'; url: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n - `updated_at: string`\n - `baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }`\n - `last_change_at?: string`\n - `last_error?: { code: string; message: string; }`\n - `last_run_at?: string`\n - `next_run_at?: string`\n - `tags?: string[]`\n - `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitor = await client.monitors.update('mon_123');\n\nconsole.log(monitor);\n```", + "## update\n\n`client.monitors.update(monitor_id: string, change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }, name?: string, schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }, status?: 'active' | 'paused', tags?: string[], target?: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }, webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }): { id: string; change_detection: object | object; created_at: string; mode: 'web'; name: string; schedule: object; status: 'active' | 'paused' | 'failed'; target: object | object | object; updated_at: string; baseline?: object | object | object; last_change_at?: string; last_error?: object; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: object; webhook_failure?: object; }`\n\n**patch** `/monitors/{monitor_id}`\n\nUpdates a monitor. If `target` or `change_detection` changes, the monitor creates a new baseline. Unsupported target/change detection combinations are rejected.\n\n### Parameters\n\n- `monitor_id: string`\n\n- `change_detection?: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n Discriminated union describing how changes are detected.\n\n- `name?: string`\n\n- `schedule?: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n Run the monitor on a fixed interval defined by a frequency and a unit, e.g. every 6 hours or every 2 days. The total interval (frequency × unit) must be between 10 minutes and 1 year.\n - `frequency: number`\n Number of units between runs. The resulting interval (frequency × unit) must be at least 10 minutes and at most 1 year (e.g. minimum 10 when unit is minutes; maximum 365 when unit is days).\n - `type: 'interval'`\n - `unit: 'minutes' | 'hours' | 'days'`\n\n- `status?: 'active' | 'paused'`\n\n- `tags?: string[]`\n User-defined tags for grouping and filtering monitors and their changes. Duplicates are removed.\n\n- `target?: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n Discriminated union describing what the monitor watches.\n\n- `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n Set to null to remove the webhook.\n - `url: string`\n Webhook URL events are delivered to.\n - `events?: 'change.detected' | 'run.completed'[]`\n Events delivered to this endpoint. `change.detected` fires only when a run detects a change; `run.completed` fires on every completed run — including runs that detected no change — and embeds the change when one was detected. Defaults to `[\"change.detected\"]` when omitted.\n - `secret?: string`\n Signing secret used to verify webhook authenticity. Each delivery includes an `X-Context-Signature: t=,v1=` header, where the HMAC is SHA-256 over `\"{t}.{rawRequestBody}\"` keyed by this secret. Recompute it with a constant-time compare and reject stale timestamps to prevent replay. Generated by the API; cannot be set by clients.\n\n### Returns\n\n- `{ id: string; change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }; created_at: string; mode: 'web'; name: string; schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }; status: 'active' | 'paused' | 'failed'; target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }; updated_at: string; baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }; last_change_at?: string; last_error?: { code: string; message: string; }; last_run_at?: string; next_run_at?: string; tags?: string[]; webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }; webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }; }`\n A web monitor. `mode` is the constant `web`; behavior is described by `target` (page/sitemap/extract) and `change_detection` (exact/semantic).\n\n - `id: string`\n - `change_detection: { type: 'exact'; } | { type: 'semantic'; confidence_threshold?: number; }`\n - `created_at: string`\n - `mode: 'web'`\n - `name: string`\n - `schedule: { frequency: number; type: 'interval'; unit: 'minutes' | 'hours' | 'days'; }`\n - `status: 'active' | 'paused' | 'failed'`\n - `target: { type: 'page'; url: string; instructions?: string; normalize_whitespace?: boolean; } | { type: 'sitemap'; url: string; exclude?: string[]; include?: string[]; max_urls?: number; } | { instructions: string; type: 'extract'; url: string; follow_subdomains?: boolean; max_depth?: number; max_pages?: number; schema?: object; }`\n - `updated_at: string`\n - `baseline?: { captured_at: string; text: string; } | { captured_at: string; url_count: number; urls: string[]; } | { captured_at: string; data: object; urls_analyzed: string[]; }`\n - `last_change_at?: string`\n - `last_error?: { code: string; message: string; }`\n - `last_run_at?: string`\n - `next_run_at?: string`\n - `tags?: string[]`\n - `webhook?: { url: string; events?: 'change.detected' | 'run.completed'[]; secret?: string; }`\n - `webhook_failure?: { consecutive_failures: number; last_failed_at: string; last_message: string; last_status: 'rejected' | 'failed' | 'skipped_unsafe_url'; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst monitor = await client.monitors.update('mon_123');\n\nconsole.log(monitor);\n```", perLanguage: { typescript: { method: 'client.monitors.update', @@ -1390,7 +1390,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ php: { method: 'monitors->update', example: - "monitors->update(\n 'mon_123',\n changeDetection: ['type' => 'exact'],\n name: 'Acme pricing monitor',\n schedule: ['frequency' => 1, 'type' => 'interval', 'unit' => 'hours'],\n status: 'active',\n tags: ['pricing', 'competitor'],\n target: [\n 'type' => 'page',\n 'url' => 'https://acme.com/pricing',\n 'normalizeWhitespace' => true,\n ],\n webhook: [\n 'url' => 'https://example.com/webhook',\n 'events' => ['change.detected', 'run.completed'],\n ],\n);\n\nvar_dump($monitor);", + "monitors->update(\n 'mon_123',\n changeDetection: ['type' => 'exact'],\n name: 'Acme pricing monitor',\n schedule: ['frequency' => 1, 'type' => 'interval', 'unit' => 'hours'],\n status: 'active',\n tags: ['pricing', 'competitor'],\n target: [\n 'type' => 'page',\n 'url' => 'https://acme.com/pricing',\n 'instructions' => 'Report pricing or plan availability changes. Ignore counters, timestamps, testimonials, and navigation.',\n 'normalizeWhitespace' => true,\n ],\n webhook: [\n 'url' => 'https://example.com/webhook',\n 'events' => ['change.detected', 'run.completed'],\n ],\n);\n\nvar_dump($monitor);", }, http: { example: diff --git a/src/resources/monitors.ts b/src/resources/monitors.ts index ab0b610..e2f6302 100644 --- a/src/resources/monitors.ts +++ b/src/resources/monitors.ts @@ -370,9 +370,10 @@ export namespace MonitorCreateResponse { } /** - * Detect meaning-level changes to tracked page content, ignoring cosmetic or - * paraphrase-only differences. Which changes are meaningful is judged against the - * extract target's `instructions` (and `schema`, when provided). + * Detect meaning-level changes to page content, ignoring cosmetic or + * instruction-irrelevant differences. Which changes are meaningful is judged + * against the page or extract target's `instructions` (and an extract target's + * `schema`, when provided). */ export interface MonitorsSemanticChangeDetection { type: 'semantic'; @@ -399,13 +400,20 @@ export namespace MonitorCreateResponse { } /** - * Watch a single web page. + * Watch a single web page. Exact detection reports visible-text diffs; semantic + * detection judges confirmed stable diffs against `instructions`. */ export interface MonitorsPageTarget { type: 'page'; url: string; + /** + * Plain-language goal describing which page changes matter. When provided without + * change_detection, semantic detection is inferred. + */ + instructions?: string; + /** * Normalize whitespace before comparing or analyzing text. */ @@ -711,9 +719,10 @@ export namespace MonitorRetrieveResponse { } /** - * Detect meaning-level changes to tracked page content, ignoring cosmetic or - * paraphrase-only differences. Which changes are meaningful is judged against the - * extract target's `instructions` (and `schema`, when provided). + * Detect meaning-level changes to page content, ignoring cosmetic or + * instruction-irrelevant differences. Which changes are meaningful is judged + * against the page or extract target's `instructions` (and an extract target's + * `schema`, when provided). */ export interface MonitorsSemanticChangeDetection { type: 'semantic'; @@ -740,13 +749,20 @@ export namespace MonitorRetrieveResponse { } /** - * Watch a single web page. + * Watch a single web page. Exact detection reports visible-text diffs; semantic + * detection judges confirmed stable diffs against `instructions`. */ export interface MonitorsPageTarget { type: 'page'; url: string; + /** + * Plain-language goal describing which page changes matter. When provided without + * change_detection, semantic detection is inferred. + */ + instructions?: string; + /** * Normalize whitespace before comparing or analyzing text. */ @@ -1052,9 +1068,10 @@ export namespace MonitorUpdateResponse { } /** - * Detect meaning-level changes to tracked page content, ignoring cosmetic or - * paraphrase-only differences. Which changes are meaningful is judged against the - * extract target's `instructions` (and `schema`, when provided). + * Detect meaning-level changes to page content, ignoring cosmetic or + * instruction-irrelevant differences. Which changes are meaningful is judged + * against the page or extract target's `instructions` (and an extract target's + * `schema`, when provided). */ export interface MonitorsSemanticChangeDetection { type: 'semantic'; @@ -1081,13 +1098,20 @@ export namespace MonitorUpdateResponse { } /** - * Watch a single web page. + * Watch a single web page. Exact detection reports visible-text diffs; semantic + * detection judges confirmed stable diffs against `instructions`. */ export interface MonitorsPageTarget { type: 'page'; url: string; + /** + * Plain-language goal describing which page changes matter. When provided without + * change_detection, semantic detection is inferred. + */ + instructions?: string; + /** * Normalize whitespace before comparing or analyzing text. */ @@ -1393,9 +1417,10 @@ export namespace MonitorListResponse { } /** - * Detect meaning-level changes to tracked page content, ignoring cosmetic or - * paraphrase-only differences. Which changes are meaningful is judged against the - * extract target's `instructions` (and `schema`, when provided). + * Detect meaning-level changes to page content, ignoring cosmetic or + * instruction-irrelevant differences. Which changes are meaningful is judged + * against the page or extract target's `instructions` (and an extract target's + * `schema`, when provided). */ export interface MonitorsSemanticChangeDetection { type: 'semantic'; @@ -1422,13 +1447,20 @@ export namespace MonitorListResponse { } /** - * Watch a single web page. + * Watch a single web page. Exact detection reports visible-text diffs; semantic + * detection judges confirmed stable diffs against `instructions`. */ export interface MonitorsPageTarget { type: 'page'; url: string; + /** + * Plain-language goal describing which page changes matter. When provided without + * change_detection, semantic detection is inferred. + */ + instructions?: string; + /** * Normalize whitespace before comparing or analyzing text. */ @@ -2110,13 +2142,20 @@ export interface MonitorCreateParams { export namespace MonitorCreateParams { /** - * Watch a single web page. + * Watch a single web page. Exact detection reports visible-text diffs; semantic + * detection judges confirmed stable diffs against `instructions`. */ export interface MonitorsPageTarget { type: 'page'; url: string; + /** + * Plain-language goal describing which page changes matter. When provided without + * change_detection, semantic detection is inferred. + */ + instructions?: string; + /** * Normalize whitespace before comparing or analyzing text. */ @@ -2209,9 +2248,10 @@ export namespace MonitorCreateParams { } /** - * Detect meaning-level changes to tracked page content, ignoring cosmetic or - * paraphrase-only differences. Which changes are meaningful is judged against the - * extract target's `instructions` (and `schema`, when provided). + * Detect meaning-level changes to page content, ignoring cosmetic or + * instruction-irrelevant differences. Which changes are meaningful is judged + * against the page or extract target's `instructions` (and an extract target's + * `schema`, when provided). */ export interface MonitorsSemanticChangeDetection { type: 'semantic'; @@ -2302,9 +2342,10 @@ export namespace MonitorUpdateParams { } /** - * Detect meaning-level changes to tracked page content, ignoring cosmetic or - * paraphrase-only differences. Which changes are meaningful is judged against the - * extract target's `instructions` (and `schema`, when provided). + * Detect meaning-level changes to page content, ignoring cosmetic or + * instruction-irrelevant differences. Which changes are meaningful is judged + * against the page or extract target's `instructions` (and an extract target's + * `schema`, when provided). */ export interface MonitorsSemanticChangeDetection { type: 'semantic'; @@ -2331,13 +2372,20 @@ export namespace MonitorUpdateParams { } /** - * Watch a single web page. + * Watch a single web page. Exact detection reports visible-text diffs; semantic + * detection judges confirmed stable diffs against `instructions`. */ export interface MonitorsPageTarget { type: 'page'; url: string; + /** + * Plain-language goal describing which page changes matter. When provided without + * change_detection, semantic detection is inferred. + */ + instructions?: string; + /** * Normalize whitespace before comparing or analyzing text. */ diff --git a/tests/api-resources/monitors.test.ts b/tests/api-resources/monitors.test.ts index fa69e07..cd7c960 100644 --- a/tests/api-resources/monitors.test.ts +++ b/tests/api-resources/monitors.test.ts @@ -30,6 +30,8 @@ describe('resource monitors', () => { target: { type: 'page', url: 'https://acme.com/pricing', + instructions: + 'Report pricing or plan availability changes. Ignore counters, timestamps, testimonials, and navigation.', normalize_whitespace: true, }, change_detection: { type: 'exact' }, From 54940ea4237cf68a517cff23b36b3a4dd0c56283 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 00:36:12 +0000 Subject: [PATCH 3/6] feat(api): api update --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 443cc05..957aa46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1228,9 +1228,9 @@ baseline-browser-mapping@^2.9.0: integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg== brace-expansion@^2.0.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.2.tgz#0bba2271feb7d458b0d31ad13625aaa4754431e2" - integrity sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA== + version "2.1.3" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.3.tgz#1bf69aacdf6a4380ca17c284d9f928d4aa6401bc" + integrity sha512-DRdx5neNsG/QXbniLFWi2YmC/68oeOOmKz6zOjVk6ZS1ZLXgLIKqVEc6hWsmkjBbgii0SwaBTcJ5XKj5gzY/4A== dependencies: balanced-match "^1.0.0" From e4e2090fc99a577fbe41050482c9520eeb512e93 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 07:18:58 +0000 Subject: [PATCH 4/6] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3f4cd2e..6183d03 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 32 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-91f4286859fc23813c5255b877395c87dd81520c3913fdfdae3cfa343e1a4873.yml -openapi_spec_hash: 71746b5b65f20617ee021e071d5f7f92 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-9ee1d9a454772b4cd978d5e0ad8ead21d732fa559686130daf0540084b5f6be5.yml +openapi_spec_hash: fb66e1f80fb2aad8adc4ae37d69bdc02 config_hash: 70e7e80b5e87f94981bee396c6cd41e8 From 7ececf23429c46cebf13d4c1edfb93312426fd4c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 07:57:40 +0000 Subject: [PATCH 5/6] feat(api): manual updates --- .stats.yml | 6 +- api.md | 18 + packages/mcp-server/src/code-tool-worker.ts | 5 + packages/mcp-server/src/local-docs-search.ts | 253 +++ packages/mcp-server/src/methods.ts | 30 + src/client.ts | 29 + src/resources/batch.ts | 1524 ++++++++++++++++++ src/resources/index.ts | 13 + tests/api-resources/batch.test.ts | 135 ++ 9 files changed, 2010 insertions(+), 3 deletions(-) create mode 100644 src/resources/batch.ts create mode 100644 tests/api-resources/batch.test.ts diff --git a/.stats.yml b/.stats.yml index 6183d03..a173ebe 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 32 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-9ee1d9a454772b4cd978d5e0ad8ead21d732fa559686130daf0540084b5f6be5.yml +configured_endpoints: 37 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-6dfc33639ef5ad1fd0fa05f9f00fcdd59940188ef625252c6ee9db85c6f8fc59.yml openapi_spec_hash: fb66e1f80fb2aad8adc4ae37d69bdc02 -config_hash: 70e7e80b5e87f94981bee396c6cd41e8 +config_hash: 2bea1743c84d63bd61f8501a6ea63065 diff --git a/api.md b/api.md index fdc70b0..54fe4df 100644 --- a/api.md +++ b/api.md @@ -118,3 +118,21 @@ Methods: - client.monitors.listRuns(monitorID, { ...params }) -> MonitorListRunsResponse - client.monitors.retrieveChange(changeID) -> MonitorRetrieveChangeResponse - client.monitors.run(monitorID) -> MonitorRunResponse + +# Batch + +Types: + +- BatchRetrieveResponse +- BatchListResponse +- BatchCancelResponse +- BatchGetResultsResponse +- BatchSubmitResponse + +Methods: + +- client.batch.retrieve(batchID, { ...params }) -> BatchRetrieveResponse +- client.batch.list({ ...params }) -> BatchListResponse +- client.batch.cancel(batchID, { ...params }) -> BatchCancelResponse +- client.batch.getResults(batchID, { ...params }) -> BatchGetResultsResponse +- client.batch.submit({ ...params }) -> BatchSubmitResponse diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index 2abec5e..6c28678 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -140,6 +140,11 @@ const fuse = new Fuse( 'client.monitors.retrieveChange', 'client.monitors.run', 'client.monitors.update', + 'client.batch.cancel', + 'client.batch.getResults', + 'client.batch.list', + 'client.batch.retrieve', + 'client.batch.submit', ], { threshold: 1, shouldSort: true }, ); diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 6b45eca..c44ba8a 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -1864,6 +1864,259 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, }, }, + { + name: 'submit', + endpoint: '/people/retrieve', + httpMethod: 'post', + summary: 'Retrieve Person', + description: 'Retrieve and normalize a person profile from identifiers.', + stainlessPath: '(resource) batch > (method) submit', + qualified: 'client.batch.submit', + params: ['identifiers: { linkedinUrl?: string; };', 'tags?: string[];', 'timeoutMS?: number;'], + response: + "{ code: 200; metadata: { identifiers: { linkedinUrl?: string; }; sourcesAttempted: 'linkedin' | 'cv' | 'manual' | 'github' | 'other'[]; sourcesSucceeded: 'linkedin' | 'cv' | 'manual' | 'github' | 'other'[]; urlsAnalyzed: string[]; personalWebsiteUrl?: string; }; person: { education: { institution: object; dates?: object; description?: string; fieldOfStudy?: string; qualification?: string; }[]; experience: { company: object; title: string; dates?: object; description?: string; }[]; profile: { fullName?: string; headline?: string; location?: string; profilePictureUrl?: string; summary?: string; }; skills: { name: string; normalized?: string; proficiency?: string; }[]; }; status: 'ok'; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", + markdown: + "## submit\n\n`client.batch.submit(identifiers: { linkedinUrl?: string; }, tags?: string[], timeoutMS?: number): { code: 200; metadata: object; person: object; status: 'ok'; key_metadata?: object; }`\n\n**post** `/people/retrieve`\n\nRetrieve and normalize a person profile from identifiers.\n\n### Parameters\n\n- `identifiers: { linkedinUrl?: string; }`\n Known identifiers for the person. At least one identifier is required.\n - `linkedinUrl?: string`\n LinkedIn profile URL, e.g. https://www.linkedin.com/in/yahia-bakour/.\n\n- `tags?: string[]`\n Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ code: 200; metadata: { identifiers: { linkedinUrl?: string; }; sourcesAttempted: 'linkedin' | 'cv' | 'manual' | 'github' | 'other'[]; sourcesSucceeded: 'linkedin' | 'cv' | 'manual' | 'github' | 'other'[]; urlsAnalyzed: string[]; personalWebsiteUrl?: string; }; person: { education: { institution: object; dates?: object; description?: string; fieldOfStudy?: string; qualification?: string; }[]; experience: { company: object; title: string; dates?: object; description?: string; }[]; profile: { fullName?: string; headline?: string; location?: string; profilePictureUrl?: string; summary?: string; }; skills: { name: string; normalized?: string; proficiency?: string; }[]; }; status: 'ok'; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `code: 200`\n - `metadata: { identifiers: { linkedinUrl?: string; }; sourcesAttempted: 'linkedin' | 'cv' | 'manual' | 'github' | 'other'[]; sourcesSucceeded: 'linkedin' | 'cv' | 'manual' | 'github' | 'other'[]; urlsAnalyzed: string[]; personalWebsiteUrl?: string; }`\n - `person: { education: { institution: { display: string; normalized?: string; }; dates?: { endDate?: { year: number; day?: number; month?: number; }; isCurrent?: boolean; startDate?: { year: number; day?: number; month?: number; }; }; description?: string; fieldOfStudy?: string; qualification?: string; }[]; experience: { company: { display: string; normalized?: string; }; title: string; dates?: { endDate?: { year: number; day?: number; month?: number; }; isCurrent?: boolean; startDate?: { year: number; day?: number; month?: number; }; }; description?: string; }[]; profile: { fullName?: string; headline?: string; location?: string; profilePictureUrl?: string; summary?: string; }; skills: { name: string; normalized?: string; proficiency?: string; }[]; }`\n - `status: 'ok'`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst response = await client.batch.submit({ identifiers: {} });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.batch.submit', + example: + "import ContextDev from 'context.dev';\n\nconst client = new ContextDev({\n apiKey: process.env['CONTEXT_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.batch.submit({\n identifiers: { linkedinUrl: 'https://www.linkedin.com/in/yahia-bakour/' },\n});\n\nconsole.log(response.code);", + }, + python: { + method: 'batch.submit', + example: + 'import os\nfrom context.dev import ContextDev\n\nclient = ContextDev(\n api_key=os.environ.get("CONTEXT_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.batch.submit(\n identifiers={\n "linkedin_url": "https://www.linkedin.com/in/yahia-bakour/"\n },\n)\nprint(response.code)', + }, + go: { + method: 'client.Batch.Submit', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/context-dot-dev/context-go-sdk"\n\t"github.com/context-dot-dev/context-go-sdk/option"\n)\n\nfunc main() {\n\tclient := contextdev.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Batch.Submit(context.TODO(), contextdev.BatchSubmitParams{\n\t\tIdentifiers: contextdev.BatchSubmitParamsIdentifiers{\n\t\t\tLinkedinURL: contextdev.String("https://www.linkedin.com/in/yahia-bakour/"),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Code)\n}\n', + }, + ruby: { + method: 'batch.submit', + example: + 'require "context_dev"\n\ncontext_dev = ContextDev::Client.new(api_key: "My API Key")\n\nresponse = context_dev.batch.submit(identifiers: {})\n\nputs(response)', + }, + cli: { + method: 'batch submit', + example: "context-dev batch submit \\\n --api-key 'My API Key' \\\n --identifiers '{}'", + }, + php: { + method: 'batch->submit', + example: + "batch->submit(\n identifiers: ['linkedinURL' => 'https://www.linkedin.com/in/yahia-bakour/'],\n tags: ['production', 'team-alpha'],\n timeoutMs: 1000,\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl https://api.context.dev/v1/people/retrieve \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $CONTEXT_DEV_API_KEY" \\\n -d \'{\n "identifiers": {\n "linkedinUrl": "https://www.linkedin.com/in/yahia-bakour/"\n },\n "tags": [\n "production",\n "team-alpha"\n ]\n }\'', + }, + }, + }, + { + name: 'list', + endpoint: '/batch/list', + httpMethod: 'get', + summary: 'List batches', + description: 'List your batches from newest to oldest. Filter by status or continue with a cursor.', + stainlessPath: '(resource) batch > (method) list', + qualified: 'client.batch.list', + params: [ + 'cursor?: string;', + 'limit?: number;', + "status?: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed';", + 'tags?: string[];', + ], + response: + "{ data?: { id: string; credits: { charged: number; estimated: number; }; error: { code: string; message: string; }; errors: { code: string; count: number; }[]; input: { accepted: number; duplicates: number; invalid: number; submitted: number; }; mode: 'scrape' | 'crawl'; progress: { failed: number; pending: number; succeeded: number; }; results: { expires_at: string; files: object[]; }; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: { completed_at: string; created_at: string; started_at: string; }; type: 'markdown' | 'html'; }[]; has_more?: boolean; key_metadata?: { credits_consumed: number; credits_remaining: number; }; next_cursor?: string; }", + markdown: + "## list\n\n`client.batch.list(cursor?: string, limit?: number, status?: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed', tags?: string[]): { data?: object[]; has_more?: boolean; key_metadata?: object; next_cursor?: string; }`\n\n**get** `/batch/list`\n\nList your batches from newest to oldest. Filter by status or continue with a cursor.\n\n### Parameters\n\n- `cursor?: string`\n Cursor from the previous page.\n\n- `limit?: number`\n Batches per page. Defaults to 25.\n\n- `status?: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'`\n Filter by status.\n\n- `tags?: string[]`\n Optional comma-separated caller-defined tags for tracking this request. Tags are recorded on the request's usage log and can be used to filter usage on the dashboard usage page. Up to 20 tags, each 1-50 characters.\n\n### Returns\n\n- `{ data?: { id: string; credits: { charged: number; estimated: number; }; error: { code: string; message: string; }; errors: { code: string; count: number; }[]; input: { accepted: number; duplicates: number; invalid: number; submitted: number; }; mode: 'scrape' | 'crawl'; progress: { failed: number; pending: number; succeeded: number; }; results: { expires_at: string; files: object[]; }; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: { completed_at: string; created_at: string; started_at: string; }; type: 'markdown' | 'html'; }[]; has_more?: boolean; key_metadata?: { credits_consumed: number; credits_remaining: number; }; next_cursor?: string; }`\n\n - `data?: { id: string; credits: { charged: number; estimated: number; }; error: { code: string; message: string; }; errors: { code: string; count: number; }[]; input: { accepted: number; duplicates: number; invalid: number; submitted: number; }; mode: 'scrape' | 'crawl'; progress: { failed: number; pending: number; succeeded: number; }; results: { expires_at: string; files: { bytes: number; items: number; url: string; }[]; }; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: { completed_at: string; created_at: string; started_at: string; }; type: 'markdown' | 'html'; }[]`\n - `has_more?: boolean`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `next_cursor?: string`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst batches = await client.batch.list();\n\nconsole.log(batches);\n```", + perLanguage: { + typescript: { + method: 'client.batch.list', + example: + "import ContextDev from 'context.dev';\n\nconst client = new ContextDev({\n apiKey: process.env['CONTEXT_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst batches = await client.batch.list();\n\nconsole.log(batches.data);", + }, + python: { + method: 'batch.list', + example: + 'import os\nfrom context.dev import ContextDev\n\nclient = ContextDev(\n api_key=os.environ.get("CONTEXT_DEV_API_KEY"), # This is the default and can be omitted\n)\nbatches = client.batch.list()\nprint(batches.data)', + }, + go: { + method: 'client.Batch.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/context-dot-dev/context-go-sdk"\n\t"github.com/context-dot-dev/context-go-sdk/option"\n)\n\nfunc main() {\n\tclient := contextdev.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tbatches, err := client.Batch.List(context.TODO(), contextdev.BatchListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", batches.Data)\n}\n', + }, + ruby: { + method: 'batch.list', + example: + 'require "context_dev"\n\ncontext_dev = ContextDev::Client.new(api_key: "My API Key")\n\nbatches = context_dev.batch.list\n\nputs(batches)', + }, + cli: { + method: 'batch list', + example: "context-dev batch list \\\n --api-key 'My API Key'", + }, + php: { + method: 'batch->list', + example: + "batch->list(\n cursor: 'cursor',\n limit: 1,\n status: 'queued',\n tags: ['production', 'team-alpha'],\n);\n\nvar_dump($batches);", + }, + http: { + example: + 'curl https://api.context.dev/v1/batch/list \\\n -H "Authorization: Bearer $CONTEXT_DEV_API_KEY"', + }, + }, + }, + { + name: 'retrieve', + endpoint: '/batch/{batch_id}', + httpMethod: 'get', + summary: 'Get a batch', + description: + 'Check progress and get download links when the batch finishes. Also returns the rejected-URL list and webhook signing secret from submission, so nothing is lost if the submit response was dropped.', + stainlessPath: '(resource) batch > (method) retrieve', + qualified: 'client.batch.retrieve', + params: ['batch_id: string;', 'tags?: string[];'], + response: + "{ id: string; credits: { charged: number; estimated: number; }; error: { code: string; message: string; }; errors: { code: string; count: number; }[]; input: { accepted: number; duplicates: number; invalid: number; submitted: number; }; invalid_urls: { reason: string; url: string; }[]; mode: 'scrape' | 'crawl'; progress: { failed: number; pending: number; succeeded: number; }; results: { expires_at: string; files: { bytes: number; items: number; url: string; }[]; }; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: { completed_at: string; created_at: string; started_at: string; }; type: 'markdown' | 'html'; key_metadata?: { credits_consumed: number; credits_remaining: number; }; webhook_secret?: string; }", + markdown: + "## retrieve\n\n`client.batch.retrieve(batch_id: string, tags?: string[]): { id: string; credits: object; error: object; errors: object[]; input: object; invalid_urls: object[]; mode: 'scrape' | 'crawl'; progress: object; results: object; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: object; type: 'markdown' | 'html'; key_metadata?: object; webhook_secret?: string; }`\n\n**get** `/batch/{batch_id}`\n\nCheck progress and get download links when the batch finishes. Also returns the rejected-URL list and webhook signing secret from submission, so nothing is lost if the submit response was dropped.\n\n### Parameters\n\n- `batch_id: string`\n ID of the batch to retrieve or cancel.\n\n- `tags?: string[]`\n Optional comma-separated caller-defined tags for tracking this request. Tags are recorded on the request's usage log and can be used to filter usage on the dashboard usage page. Up to 20 tags, each 1-50 characters.\n\n### Returns\n\n- `{ id: string; credits: { charged: number; estimated: number; }; error: { code: string; message: string; }; errors: { code: string; count: number; }[]; input: { accepted: number; duplicates: number; invalid: number; submitted: number; }; invalid_urls: { reason: string; url: string; }[]; mode: 'scrape' | 'crawl'; progress: { failed: number; pending: number; succeeded: number; }; results: { expires_at: string; files: { bytes: number; items: number; url: string; }[]; }; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: { completed_at: string; created_at: string; started_at: string; }; type: 'markdown' | 'html'; key_metadata?: { credits_consumed: number; credits_remaining: number; }; webhook_secret?: string; }`\n\n - `id: string`\n - `credits: { charged: number; estimated: number; }`\n - `error: { code: string; message: string; }`\n - `errors: { code: string; count: number; }[]`\n - `input: { accepted: number; duplicates: number; invalid: number; submitted: number; }`\n - `invalid_urls: { reason: string; url: string; }[]`\n - `mode: 'scrape' | 'crawl'`\n - `progress: { failed: number; pending: number; succeeded: number; }`\n - `results: { expires_at: string; files: { bytes: number; items: number; url: string; }[]; }`\n - `status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'`\n - `timing: { completed_at: string; created_at: string; started_at: string; }`\n - `type: 'markdown' | 'html'`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `webhook_secret?: string`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst batch = await client.batch.retrieve('batch_9f2c8a');\n\nconsole.log(batch);\n```", + perLanguage: { + typescript: { + method: 'client.batch.retrieve', + example: + "import ContextDev from 'context.dev';\n\nconst client = new ContextDev({\n apiKey: process.env['CONTEXT_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst batch = await client.batch.retrieve('batch_9f2c8a');\n\nconsole.log(batch.id);", + }, + python: { + method: 'batch.retrieve', + example: + 'import os\nfrom context.dev import ContextDev\n\nclient = ContextDev(\n api_key=os.environ.get("CONTEXT_DEV_API_KEY"), # This is the default and can be omitted\n)\nbatch = client.batch.retrieve(\n batch_id="batch_9f2c8a",\n)\nprint(batch.id)', + }, + go: { + method: 'client.Batch.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/context-dot-dev/context-go-sdk"\n\t"github.com/context-dot-dev/context-go-sdk/option"\n)\n\nfunc main() {\n\tclient := contextdev.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tbatch, err := client.Batch.Get(\n\t\tcontext.TODO(),\n\t\t"batch_9f2c8a",\n\t\tcontextdev.BatchGetParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", batch.ID)\n}\n', + }, + ruby: { + method: 'batch.retrieve', + example: + 'require "context_dev"\n\ncontext_dev = ContextDev::Client.new(api_key: "My API Key")\n\nbatch = context_dev.batch.retrieve("batch_9f2c8a")\n\nputs(batch)', + }, + cli: { + method: 'batch retrieve', + example: "context-dev batch retrieve \\\n --api-key 'My API Key' \\\n --batch-id batch_9f2c8a", + }, + php: { + method: 'batch->retrieve', + example: + "batch->retrieve(\n 'batch_9f2c8a', tags: ['production', 'team-alpha']\n);\n\nvar_dump($batch);", + }, + http: { + example: + 'curl https://api.context.dev/v1/batch/$BATCH_ID \\\n -H "Authorization: Bearer $CONTEXT_DEV_API_KEY"', + }, + }, + }, + { + name: 'get_results', + endpoint: '/batch/{batch_id}/results', + httpMethod: 'get', + summary: 'Get batch results', + description: + 'Page through the result records of a finished batch as JSON, in the same order as the downloadable result files. Use this instead of downloading and parsing the NDJSON files yourself.', + stainlessPath: '(resource) batch > (method) get_results', + qualified: 'client.batch.getResults', + params: ['batch_id: string;', 'cursor?: string;', 'limit?: number;', 'tags?: string[];'], + response: + "{ data?: { final_url: string; http_status: number; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: object[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; status: 'ok'; url: string; html?: string; itemId?: string; markdown?: string; meta?: object; } | { error_code: string; message: string; status: 'error'; url: string; itemId?: string; meta?: object; }[]; has_more?: boolean; key_metadata?: { credits_consumed: number; credits_remaining: number; }; next_cursor?: string; }", + markdown: + "## get_results\n\n`client.batch.getResults(batch_id: string, cursor?: string, limit?: number, tags?: string[]): { data?: object | object[]; has_more?: boolean; key_metadata?: object; next_cursor?: string; }`\n\n**get** `/batch/{batch_id}/results`\n\nPage through the result records of a finished batch as JSON, in the same order as the downloadable result files. Use this instead of downloading and parsing the NDJSON files yourself.\n\n### Parameters\n\n- `batch_id: string`\n ID of the batch to retrieve or cancel.\n\n- `cursor?: string`\n next_cursor from the previous page.\n\n- `limit?: number`\n Records per page. Defaults to 25. A page can close early so its payload stays under ~8 MB; rely on next_cursor rather than counting records.\n\n- `tags?: string[]`\n Optional comma-separated caller-defined tags for tracking this request. Tags are recorded on the request's usage log and can be used to filter usage on the dashboard usage page. Up to 20 tags, each 1-50 characters.\n\n### Returns\n\n- `{ data?: { final_url: string; http_status: number; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: object[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; status: 'ok'; url: string; html?: string; itemId?: string; markdown?: string; meta?: object; } | { error_code: string; message: string; status: 'error'; url: string; itemId?: string; meta?: object; }[]; has_more?: boolean; key_metadata?: { credits_consumed: number; credits_remaining: number; }; next_cursor?: string; }`\n\n - `data?: { final_url: string; http_status: number; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; status: 'ok'; url: string; html?: string; itemId?: string; markdown?: string; meta?: object; } | { error_code: string; message: string; status: 'error'; url: string; itemId?: string; meta?: object; }[]`\n - `has_more?: boolean`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `next_cursor?: string`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst response = await client.batch.getResults('batch_9f2c8a');\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.batch.getResults', + example: + "import ContextDev from 'context.dev';\n\nconst client = new ContextDev({\n apiKey: process.env['CONTEXT_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.batch.getResults('batch_9f2c8a');\n\nconsole.log(response.data);", + }, + python: { + method: 'batch.get_results', + example: + 'import os\nfrom context.dev import ContextDev\n\nclient = ContextDev(\n api_key=os.environ.get("CONTEXT_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.batch.get_results(\n batch_id="batch_9f2c8a",\n)\nprint(response.data)', + }, + go: { + method: 'client.Batch.GetResults', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/context-dot-dev/context-go-sdk"\n\t"github.com/context-dot-dev/context-go-sdk/option"\n)\n\nfunc main() {\n\tclient := contextdev.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Batch.GetResults(\n\t\tcontext.TODO(),\n\t\t"batch_9f2c8a",\n\t\tcontextdev.BatchGetResultsParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Data)\n}\n', + }, + ruby: { + method: 'batch.get_results', + example: + 'require "context_dev"\n\ncontext_dev = ContextDev::Client.new(api_key: "My API Key")\n\nresponse = context_dev.batch.get_results("batch_9f2c8a")\n\nputs(response)', + }, + cli: { + method: 'batch get_results', + example: "context-dev batch get-results \\\n --api-key 'My API Key' \\\n --batch-id batch_9f2c8a", + }, + php: { + method: 'batch->getResults', + example: + "batch->getResults(\n 'batch_9f2c8a', cursor: 'cursor', limit: 1, tags: ['production', 'team-alpha']\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl https://api.context.dev/v1/batch/$BATCH_ID/results \\\n -H "Authorization: Bearer $CONTEXT_DEV_API_KEY"', + }, + }, + }, + { + name: 'cancel', + endpoint: '/batch/{batch_id}/cancel', + httpMethod: 'post', + summary: 'Cancel a batch', + description: + 'Stop a batch from starting new pages. In-progress pages finish, and unused credits are refunded.', + stainlessPath: '(resource) batch > (method) cancel', + qualified: 'client.batch.cancel', + params: ['batch_id: string;', 'tags?: string[];'], + response: + "{ id: string; credits: { charged: number; estimated: number; }; error: { code: string; message: string; }; errors: { code: string; count: number; }[]; input: { accepted: number; duplicates: number; invalid: number; submitted: number; }; mode: 'scrape' | 'crawl'; progress: { failed: number; pending: number; succeeded: number; }; results: { expires_at: string; files: { bytes: number; items: number; url: string; }[]; }; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: { completed_at: string; created_at: string; started_at: string; }; type: 'markdown' | 'html'; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", + markdown: + "## cancel\n\n`client.batch.cancel(batch_id: string, tags?: string[]): { id: string; credits: object; error: object; errors: object[]; input: object; mode: 'scrape' | 'crawl'; progress: object; results: object; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: object; type: 'markdown' | 'html'; key_metadata?: object; }`\n\n**post** `/batch/{batch_id}/cancel`\n\nStop a batch from starting new pages. In-progress pages finish, and unused credits are refunded.\n\n### Parameters\n\n- `batch_id: string`\n ID of the batch to retrieve or cancel.\n\n- `tags?: string[]`\n Optional comma-separated caller-defined tags for tracking this request. Tags are recorded on the request's usage log and can be used to filter usage on the dashboard usage page. Up to 20 tags, each 1-50 characters.\n\n### Returns\n\n- `{ id: string; credits: { charged: number; estimated: number; }; error: { code: string; message: string; }; errors: { code: string; count: number; }[]; input: { accepted: number; duplicates: number; invalid: number; submitted: number; }; mode: 'scrape' | 'crawl'; progress: { failed: number; pending: number; succeeded: number; }; results: { expires_at: string; files: { bytes: number; items: number; url: string; }[]; }; status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; timing: { completed_at: string; created_at: string; started_at: string; }; type: 'markdown' | 'html'; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `id: string`\n - `credits: { charged: number; estimated: number; }`\n - `error: { code: string; message: string; }`\n - `errors: { code: string; count: number; }[]`\n - `input: { accepted: number; duplicates: number; invalid: number; submitted: number; }`\n - `mode: 'scrape' | 'crawl'`\n - `progress: { failed: number; pending: number; succeeded: number; }`\n - `results: { expires_at: string; files: { bytes: number; items: number; url: string; }[]; }`\n - `status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'`\n - `timing: { completed_at: string; created_at: string; started_at: string; }`\n - `type: 'markdown' | 'html'`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst response = await client.batch.cancel('batch_9f2c8a');\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.batch.cancel', + example: + "import ContextDev from 'context.dev';\n\nconst client = new ContextDev({\n apiKey: process.env['CONTEXT_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.batch.cancel('batch_9f2c8a');\n\nconsole.log(response.id);", + }, + python: { + method: 'batch.cancel', + example: + 'import os\nfrom context.dev import ContextDev\n\nclient = ContextDev(\n api_key=os.environ.get("CONTEXT_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.batch.cancel(\n batch_id="batch_9f2c8a",\n)\nprint(response.id)', + }, + go: { + method: 'client.Batch.Cancel', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/context-dot-dev/context-go-sdk"\n\t"github.com/context-dot-dev/context-go-sdk/option"\n)\n\nfunc main() {\n\tclient := contextdev.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Batch.Cancel(\n\t\tcontext.TODO(),\n\t\t"batch_9f2c8a",\n\t\tcontextdev.BatchCancelParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', + }, + ruby: { + method: 'batch.cancel', + example: + 'require "context_dev"\n\ncontext_dev = ContextDev::Client.new(api_key: "My API Key")\n\nresponse = context_dev.batch.cancel("batch_9f2c8a")\n\nputs(response)', + }, + cli: { + method: 'batch cancel', + example: "context-dev batch cancel \\\n --api-key 'My API Key' \\\n --batch-id batch_9f2c8a", + }, + php: { + method: 'batch->cancel', + example: + "batch->cancel(\n 'batch_9f2c8a', tags: ['production', 'team-alpha']\n);\n\nvar_dump($response);", + }, + http: { + example: + 'curl https://api.context.dev/v1/batch/$BATCH_ID/cancel \\\n -X POST \\\n -H "Authorization: Bearer $CONTEXT_DEV_API_KEY"', + }, + }, + }, ]; const EMBEDDED_READMES: { language: string; content: string }[] = [ diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts index 2099187..e3ee5c2 100644 --- a/packages/mcp-server/src/methods.ts +++ b/packages/mcp-server/src/methods.ts @@ -202,6 +202,36 @@ export const sdkMethods: SdkMethod[] = [ httpMethod: 'post', httpPath: '/monitors/{monitor_id}/run', }, + { + clientCallName: 'client.batch.retrieve', + fullyQualifiedName: 'batch.retrieve', + httpMethod: 'get', + httpPath: '/batch/{batch_id}', + }, + { + clientCallName: 'client.batch.list', + fullyQualifiedName: 'batch.list', + httpMethod: 'get', + httpPath: '/batch/list', + }, + { + clientCallName: 'client.batch.cancel', + fullyQualifiedName: 'batch.cancel', + httpMethod: 'post', + httpPath: '/batch/{batch_id}/cancel', + }, + { + clientCallName: 'client.batch.getResults', + fullyQualifiedName: 'batch.getResults', + httpMethod: 'get', + httpPath: '/batch/{batch_id}/results', + }, + { + clientCallName: 'client.batch.submit', + fullyQualifiedName: 'batch.submit', + httpMethod: 'post', + httpPath: '/people/retrieve', + }, ]; function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] | undefined { diff --git a/src/client.ts b/src/client.ts index 14f5c7e..a96dcb1 100644 --- a/src/client.ts +++ b/src/client.ts @@ -24,6 +24,19 @@ import { AIExtractProductsParams, AIExtractProductsResponse, } from './resources/ai'; +import { + Batch, + BatchCancelParams, + BatchCancelResponse, + BatchGetResultsParams, + BatchGetResultsResponse, + BatchListParams, + BatchListResponse, + BatchRetrieveParams, + BatchRetrieveResponse, + BatchSubmitParams, + BatchSubmitResponse, +} from './resources/batch'; import { Brand, BrandRetrieveParams, @@ -817,6 +830,7 @@ export class ContextDev { * Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. */ monitors: API.Monitors = new API.Monitors(this); + batch: API.Batch = new API.Batch(this); } ContextDev.Parse = Parse; @@ -826,6 +840,7 @@ ContextDev.Brand = Brand; ContextDev.Industry = Industry; ContextDev.Utility = Utility; ContextDev.Monitors = Monitors; +ContextDev.Batch = Batch; export declare namespace ContextDev { export type RequestOptions = Opts.RequestOptions; @@ -917,4 +932,18 @@ export declare namespace ContextDev { type MonitorListChangesParams as MonitorListChangesParams, type MonitorListRunsParams as MonitorListRunsParams, }; + + export { + Batch as Batch, + type BatchRetrieveResponse as BatchRetrieveResponse, + type BatchListResponse as BatchListResponse, + type BatchCancelResponse as BatchCancelResponse, + type BatchGetResultsResponse as BatchGetResultsResponse, + type BatchSubmitResponse as BatchSubmitResponse, + type BatchRetrieveParams as BatchRetrieveParams, + type BatchListParams as BatchListParams, + type BatchCancelParams as BatchCancelParams, + type BatchGetResultsParams as BatchGetResultsParams, + type BatchSubmitParams as BatchSubmitParams, + }; } diff --git a/src/resources/batch.ts b/src/resources/batch.ts new file mode 100644 index 0000000..c16dd2e --- /dev/null +++ b/src/resources/batch.ts @@ -0,0 +1,1524 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +import { RequestOptions } from '../internal/request-options'; +import { path } from '../internal/utils/path'; + +export class Batch extends APIResource { + /** + * Check progress and get download links when the batch finishes. Also returns the + * rejected-URL list and webhook signing secret from submission, so nothing is lost + * if the submit response was dropped. + * + * @example + * ```ts + * const batch = await client.batch.retrieve('batch_9f2c8a'); + * ``` + */ + retrieve( + batchID: string, + query: BatchRetrieveParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get(path`/batch/${batchID}`, { query, ...options }); + } + + /** + * List your batches from newest to oldest. Filter by status or continue with a + * cursor. + * + * @example + * ```ts + * const batches = await client.batch.list(); + * ``` + */ + list( + query: BatchListParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get('/batch/list', { query, ...options }); + } + + /** + * Stop a batch from starting new pages. In-progress pages finish, and unused + * credits are refunded. + * + * @example + * ```ts + * const response = await client.batch.cancel('batch_9f2c8a'); + * ``` + */ + cancel( + batchID: string, + params: BatchCancelParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + const { tags } = params ?? {}; + return this._client.post(path`/batch/${batchID}/cancel`, { query: { tags }, ...options }); + } + + /** + * Page through the result records of a finished batch as JSON, in the same order + * as the downloadable result files. Use this instead of downloading and parsing + * the NDJSON files yourself. + * + * @example + * ```ts + * const response = await client.batch.getResults( + * 'batch_9f2c8a', + * ); + * ``` + */ + getResults( + batchID: string, + query: BatchGetResultsParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get(path`/batch/${batchID}/results`, { query, ...options }); + } + + /** + * Retrieve and normalize a person profile from identifiers. + * + * @example + * ```ts + * const response = await client.batch.submit({ + * identifiers: { + * linkedinUrl: + * 'https://www.linkedin.com/in/yahia-bakour/', + * }, + * }); + * ``` + */ + submit(body: BatchSubmitParams, options?: RequestOptions): APIPromise { + return this._client.post('/people/retrieve', { body, ...options }); + } +} + +export interface BatchRetrieveResponse { + /** + * Batch ID used to retrieve or cancel the job. + */ + id: string; + + /** + * Reserved and used credits. + */ + credits: BatchRetrieveResponse.Credits; + + /** + * Batch-level error. Null unless `status` is `failed`. + */ + error: BatchRetrieveResponse.Error | null; + + /** + * Page failures grouped by error code. + */ + errors: Array; + + /** + * Submission counts. + */ + input: BatchRetrieveResponse.Input; + + /** + * Rejected URLs, up to 100. These are not charged. + */ + invalid_urls: Array; + + /** + * How pages are selected. + */ + mode: 'scrape' | 'crawl'; + + /** + * Current processing counts. Use `status` to check completion. + */ + progress: BatchRetrieveResponse.Progress; + + /** + * Download links available when the batch finishes. GET /batch/{batch_id}/results + * serves the same records as paginated JSON. + */ + results: BatchRetrieveResponse.Results | null; + + /** + * Current state. `completed`, `cancelled`, and `failed` are final. + */ + status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; + + timing: BatchRetrieveResponse.Timing; + + /** + * Output format. + */ + type: 'markdown' | 'html'; + + /** + * API key usage for this request. + */ + key_metadata?: BatchRetrieveResponse.KeyMetadata; + + /** + * Webhook signing secret. Also returned by GET /batch/{batch_id}. + */ + webhook_secret?: string; +} + +export namespace BatchRetrieveResponse { + /** + * Reserved and used credits. + */ + export interface Credits { + /** + * Credits used by successful pages. + */ + charged: number; + + /** + * Credits reserved when the batch was accepted. + */ + estimated: number; + } + + /** + * Batch-level error. Null unless `status` is `failed`. + */ + export interface Error { + /** + * Batch error code. + */ + code: string; + + /** + * Batch error message. + */ + message: string; + } + + export interface Error { + /** + * Error code for these failures. + */ + code: string; + + /** + * Pages that failed with this code. + */ + count: number; + } + + /** + * Submission counts. + */ + export interface Input { + /** + * Pages accepted, or the crawl page limit. Credits are reserved for this count. + */ + accepted: number; + + /** + * Duplicate URL and `itemId` pairs skipped. Always 0 for crawls. + */ + duplicates: number; + + /** + * Pages rejected during validation. + */ + invalid: number; + + /** + * Pages submitted before validation. For a crawl, the page limit. + */ + submitted: number; + } + + export interface InvalidURL { + /** + * Why it was rejected. + */ + reason: string; + + /** + * Rejected URL. + */ + url: string; + } + + /** + * Current processing counts. Use `status` to check completion. + */ + export interface Progress { + /** + * Pages that could not be scraped. + */ + failed: number; + + /** + * Accepted pages not yet attempted. Always 0 once the batch completes; a crawl can + * finish under its page limit when the site has no more reachable pages. + */ + pending: number; + + /** + * Pages scraped successfully. + */ + succeeded: number; + } + + /** + * Download links available when the batch finishes. GET /batch/{batch_id}/results + * serves the same records as paginated JSON. + */ + export interface Results { + /** + * When the download URLs expire. + */ + expires_at: string; + + /** + * Result files. Order is not guaranteed. + */ + files: Array; + } + + export namespace Results { + export interface File { + /** + * Compressed file size in bytes. + */ + bytes: number; + + /** + * Results in this file. + */ + items: number; + + /** + * Temporary URL for a gzipped NDJSON file. + */ + url: string; + } + } + + export interface Timing { + /** + * When processing finished. Null while active. + */ + completed_at: string | null; + + /** + * When the batch was created. + */ + created_at: string; + + /** + * When processing started. Null while queued. + */ + started_at: string | null; + } + + /** + * API key usage for this request. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } +} + +export interface BatchListResponse { + /** + * Batches on this page. + */ + data?: Array; + + /** + * Whether another page is available. + */ + has_more?: boolean; + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BatchListResponse.KeyMetadata; + + /** + * Cursor for the next page. + */ + next_cursor?: string | null; +} + +export namespace BatchListResponse { + /** + * An asynchronous web scraping job. + */ + export interface Data { + /** + * Batch ID used to retrieve or cancel the job. + */ + id: string; + + /** + * Reserved and used credits. + */ + credits: Data.Credits; + + /** + * Batch-level error. Null unless `status` is `failed`. + */ + error: Data.Error | null; + + /** + * Page failures grouped by error code. + */ + errors: Array; + + /** + * Submission counts. + */ + input: Data.Input; + + /** + * How pages are selected. + */ + mode: 'scrape' | 'crawl'; + + /** + * Current processing counts. Use `status` to check completion. + */ + progress: Data.Progress; + + /** + * Download links available when the batch finishes. GET /batch/{batch_id}/results + * serves the same records as paginated JSON. + */ + results: Data.Results | null; + + /** + * Current state. `completed`, `cancelled`, and `failed` are final. + */ + status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; + + timing: Data.Timing; + + /** + * Output format. + */ + type: 'markdown' | 'html'; + } + + export namespace Data { + /** + * Reserved and used credits. + */ + export interface Credits { + /** + * Credits used by successful pages. + */ + charged: number; + + /** + * Credits reserved when the batch was accepted. + */ + estimated: number; + } + + /** + * Batch-level error. Null unless `status` is `failed`. + */ + export interface Error { + /** + * Batch error code. + */ + code: string; + + /** + * Batch error message. + */ + message: string; + } + + export interface Error { + /** + * Error code for these failures. + */ + code: string; + + /** + * Pages that failed with this code. + */ + count: number; + } + + /** + * Submission counts. + */ + export interface Input { + /** + * Pages accepted, or the crawl page limit. Credits are reserved for this count. + */ + accepted: number; + + /** + * Duplicate URL and `itemId` pairs skipped. Always 0 for crawls. + */ + duplicates: number; + + /** + * Pages rejected during validation. + */ + invalid: number; + + /** + * Pages submitted before validation. For a crawl, the page limit. + */ + submitted: number; + } + + /** + * Current processing counts. Use `status` to check completion. + */ + export interface Progress { + /** + * Pages that could not be scraped. + */ + failed: number; + + /** + * Accepted pages not yet attempted. Always 0 once the batch completes; a crawl can + * finish under its page limit when the site has no more reachable pages. + */ + pending: number; + + /** + * Pages scraped successfully. + */ + succeeded: number; + } + + /** + * Download links available when the batch finishes. GET /batch/{batch_id}/results + * serves the same records as paginated JSON. + */ + export interface Results { + /** + * When the download URLs expire. + */ + expires_at: string; + + /** + * Result files. Order is not guaranteed. + */ + files: Array; + } + + export namespace Results { + export interface File { + /** + * Compressed file size in bytes. + */ + bytes: number; + + /** + * Results in this file. + */ + items: number; + + /** + * Temporary URL for a gzipped NDJSON file. + */ + url: string; + } + } + + export interface Timing { + /** + * When processing finished. Null while active. + */ + completed_at: string | null; + + /** + * When the batch was created. + */ + created_at: string; + + /** + * When processing started. Null while queued. + */ + started_at: string | null; + } + } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } +} + +export interface BatchCancelResponse { + /** + * Batch ID used to retrieve or cancel the job. + */ + id: string; + + /** + * Reserved and used credits. + */ + credits: BatchCancelResponse.Credits; + + /** + * Batch-level error. Null unless `status` is `failed`. + */ + error: BatchCancelResponse.Error | null; + + /** + * Page failures grouped by error code. + */ + errors: Array; + + /** + * Submission counts. + */ + input: BatchCancelResponse.Input; + + /** + * How pages are selected. + */ + mode: 'scrape' | 'crawl'; + + /** + * Current processing counts. Use `status` to check completion. + */ + progress: BatchCancelResponse.Progress; + + /** + * Download links available when the batch finishes. GET /batch/{batch_id}/results + * serves the same records as paginated JSON. + */ + results: BatchCancelResponse.Results | null; + + /** + * Current state. `completed`, `cancelled`, and `failed` are final. + */ + status: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; + + timing: BatchCancelResponse.Timing; + + /** + * Output format. + */ + type: 'markdown' | 'html'; + + /** + * API key usage for this request. + */ + key_metadata?: BatchCancelResponse.KeyMetadata; +} + +export namespace BatchCancelResponse { + /** + * Reserved and used credits. + */ + export interface Credits { + /** + * Credits used by successful pages. + */ + charged: number; + + /** + * Credits reserved when the batch was accepted. + */ + estimated: number; + } + + /** + * Batch-level error. Null unless `status` is `failed`. + */ + export interface Error { + /** + * Batch error code. + */ + code: string; + + /** + * Batch error message. + */ + message: string; + } + + export interface Error { + /** + * Error code for these failures. + */ + code: string; + + /** + * Pages that failed with this code. + */ + count: number; + } + + /** + * Submission counts. + */ + export interface Input { + /** + * Pages accepted, or the crawl page limit. Credits are reserved for this count. + */ + accepted: number; + + /** + * Duplicate URL and `itemId` pairs skipped. Always 0 for crawls. + */ + duplicates: number; + + /** + * Pages rejected during validation. + */ + invalid: number; + + /** + * Pages submitted before validation. For a crawl, the page limit. + */ + submitted: number; + } + + /** + * Current processing counts. Use `status` to check completion. + */ + export interface Progress { + /** + * Pages that could not be scraped. + */ + failed: number; + + /** + * Accepted pages not yet attempted. Always 0 once the batch completes; a crawl can + * finish under its page limit when the site has no more reachable pages. + */ + pending: number; + + /** + * Pages scraped successfully. + */ + succeeded: number; + } + + /** + * Download links available when the batch finishes. GET /batch/{batch_id}/results + * serves the same records as paginated JSON. + */ + export interface Results { + /** + * When the download URLs expire. + */ + expires_at: string; + + /** + * Result files. Order is not guaranteed. + */ + files: Array; + } + + export namespace Results { + export interface File { + /** + * Compressed file size in bytes. + */ + bytes: number; + + /** + * Results in this file. + */ + items: number; + + /** + * Temporary URL for a gzipped NDJSON file. + */ + url: string; + } + } + + export interface Timing { + /** + * When processing finished. Null while active. + */ + completed_at: string | null; + + /** + * When the batch was created. + */ + created_at: string; + + /** + * When processing started. Null while queued. + */ + started_at: string | null; + } + + /** + * API key usage for this request. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } +} + +export interface BatchGetResultsResponse { + /** + * Result records on this page. + */ + data?: Array; + + /** + * Whether another page is available. + */ + has_more?: boolean; + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BatchGetResultsResponse.KeyMetadata; + + /** + * Cursor for the next page. + */ + next_cursor?: string | null; +} + +export namespace BatchGetResultsResponse { + /** + * A page the batch fetched successfully. + */ + export interface Ok { + /** + * URL the content was read from, after redirects. + */ + final_url: string; + + /** + * HTTP status of the final response, when known. + */ + http_status: number | null; + + /** + * Metadata extracted from the scraped page HTML. + */ + metadata: Ok.Metadata; + + /** + * The page was scraped. + */ + status: 'ok'; + + /** + * URL as submitted, or as discovered by the crawl. + */ + url: string; + + /** + * Raw page HTML. Present on html batches. + */ + html?: string; + + /** + * Caller-supplied identifier echoed from submission. + */ + itemId?: string; + + /** + * Page content as Markdown. Present on markdown batches. + */ + markdown?: string; + + /** + * Caller-supplied metadata echoed from submission. + */ + meta?: { [key: string]: unknown }; + } + + export namespace Ok { + /** + * Metadata extracted from the scraped page HTML. + */ + export interface Metadata { + /** + * Final URL scraped after redirects or scraper fallback, when known. Falls back to + * sourceUrl when unavailable. + */ + finalUrl: string; + + /** + * Original URL requested by the caller. + */ + sourceUrl: string; + + /** + * Additional non-social meta tags not promoted to top-level metadata fields. + */ + additionalMeta?: { [key: string]: string | Array }; + + /** + * Resolved alternate links from link rel=alternate tags. + */ + alternates?: Array; + + /** + * Author metadata, when present. + */ + author?: string; + + /** + * Resolved canonical URL, when present. + */ + canonicalUrl?: string; + + /** + * Best description extracted from standard, Open Graph, or Twitter metadata. + */ + description?: string; + + /** + * Resolved favicon URL, when present. + */ + favicon?: string; + + /** + * Primary resolved preview image from Open Graph, Twitter, or image metadata. + */ + image?: string; + + /** + * JSON-LD structured data blocks parsed from the page. + */ + jsonLd?: Array<{ [key: string]: unknown }>; + + /** + * Keywords extracted from the page's keywords meta tag. + */ + keywords?: Array; + + /** + * Language extracted from html lang or language meta tags. + */ + language?: string; + + /** + * Modified timestamp/date from page metadata, when present. + */ + modifiedTime?: string; + + /** + * Open Graph metadata with the og: prefix removed and keys camel-cased. + */ + openGraph?: { [key: string]: string | Array }; + + /** + * Published timestamp/date from page metadata, when present. + */ + publishedTime?: string; + + /** + * Robots meta directive, when present. + */ + robots?: string; + + /** + * Site or application name from page metadata. + */ + siteName?: string; + + /** + * Best title extracted from the page. + */ + title?: string; + + /** + * Twitter card metadata with the twitter: prefix removed and keys camel-cased. + */ + twitter?: { [key: string]: string | Array }; + } + + export namespace Metadata { + export interface Alternate { + /** + * Resolved alternate URL. + */ + href: string; + + /** + * Language or locale for the alternate URL, when present. + */ + hreflang?: string; + + /** + * Alternate resource title, when present. + */ + title?: string; + + /** + * Alternate resource MIME type, when present. + */ + type?: string; + } + } + } + + /** + * A page the batch could not fetch. + */ + export interface Error { + /** + * Why the page failed. + */ + error_code: string; + + /** + * Human-readable failure detail. + */ + message: string; + + /** + * The page could not be scraped. + */ + status: 'error'; + + /** + * URL as submitted, or as discovered by the crawl. + */ + url: string; + + /** + * Caller-supplied identifier echoed from submission. + */ + itemId?: string; + + /** + * Caller-supplied metadata echoed from submission. + */ + meta?: { [key: string]: unknown }; + } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } +} + +export interface BatchSubmitResponse { + /** + * HTTP status code. + */ + code: 200; + + /** + * Additional response details. + */ + metadata: BatchSubmitResponse.Metadata; + + /** + * Retrieved person profile. + */ + person: BatchSubmitResponse.Person; + + /** + * Response status. + */ + status: 'ok'; + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BatchSubmitResponse.KeyMetadata; +} + +export namespace BatchSubmitResponse { + /** + * Additional response details. + */ + export interface Metadata { + /** + * Identifiers returned for the person. + */ + identifiers: Metadata.Identifiers; + + /** + * Source categories checked. + */ + sourcesAttempted: Array<'linkedin' | 'cv' | 'manual' | 'github' | 'other'>; + + /** + * Source categories with data. + */ + sourcesSucceeded: Array<'linkedin' | 'cv' | 'manual' | 'github' | 'other'>; + + /** + * URLs reviewed for this profile. + */ + urlsAnalyzed: Array; + + /** + * Personal website URL, when found. + */ + personalWebsiteUrl?: string; + } + + export namespace Metadata { + /** + * Identifiers returned for the person. + */ + export interface Identifiers { + /** + * LinkedIn profile URL. + */ + linkedinUrl?: string; + } + } + + /** + * Retrieved person profile. + */ + export interface Person { + /** + * Education history. + */ + education: Array; + + /** + * Work history. + */ + experience: Array; + + /** + * Core profile details. + */ + profile: Person.Profile; + + /** + * Listed skills. + */ + skills: Array; + } + + export namespace Person { + export interface Education { + /** + * School or institution name. + */ + institution: Education.Institution; + + /** + * Education dates. + */ + dates?: Education.Dates; + + /** + * Additional education details. + */ + description?: string; + + /** + * Area of study. + */ + fieldOfStudy?: string; + + /** + * Degree, certificate, or credential. + */ + qualification?: string; + } + + export namespace Education { + /** + * School or institution name. + */ + export interface Institution { + /** + * Display name. + */ + display: string; + + /** + * Standardized name, when available. + */ + normalized?: string; + } + + /** + * Education dates. + */ + export interface Dates { + /** + * End date, when known. + */ + endDate?: Dates.EndDate; + + /** + * Whether the entry is current. + */ + isCurrent?: boolean; + + /** + * Start date, when known. + */ + startDate?: Dates.StartDate; + } + + export namespace Dates { + /** + * End date, when known. + */ + export interface EndDate { + /** + * Year value. + */ + year: number; + + /** + * Day value, when known. + */ + day?: number; + + /** + * Month value, when known. + */ + month?: number; + } + + /** + * Start date, when known. + */ + export interface StartDate { + /** + * Year value. + */ + year: number; + + /** + * Day value, when known. + */ + day?: number; + + /** + * Month value, when known. + */ + month?: number; + } + } + } + + export interface Experience { + /** + * Company or organization name. + */ + company: Experience.Company; + + /** + * Role or job title. + */ + title: string; + + /** + * Role dates. + */ + dates?: Experience.Dates; + + /** + * Role description. + */ + description?: string; + } + + export namespace Experience { + /** + * Company or organization name. + */ + export interface Company { + /** + * Display name. + */ + display: string; + + /** + * Standardized name, when available. + */ + normalized?: string; + } + + /** + * Role dates. + */ + export interface Dates { + /** + * End date, when known. + */ + endDate?: Dates.EndDate; + + /** + * Whether the entry is current. + */ + isCurrent?: boolean; + + /** + * Start date, when known. + */ + startDate?: Dates.StartDate; + } + + export namespace Dates { + /** + * End date, when known. + */ + export interface EndDate { + /** + * Year value. + */ + year: number; + + /** + * Day value, when known. + */ + day?: number; + + /** + * Month value, when known. + */ + month?: number; + } + + /** + * Start date, when known. + */ + export interface StartDate { + /** + * Year value. + */ + year: number; + + /** + * Day value, when known. + */ + day?: number; + + /** + * Month value, when known. + */ + month?: number; + } + } + } + + /** + * Core profile details. + */ + export interface Profile { + /** + * Person's full name. + */ + fullName?: string; + + /** + * Short professional headline. + */ + headline?: string; + + /** + * Person's listed location. + */ + location?: string; + + /** + * Profile image URL. + */ + profilePictureUrl?: string; + + /** + * Brief profile summary. + */ + summary?: string; + } + + export interface Skill { + /** + * Skill name. + */ + name: string; + + /** + * Standardized skill name, when available. + */ + normalized?: string; + + /** + * Skill proficiency, when available. + */ + proficiency?: string; + } + } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } +} + +export interface BatchRetrieveParams { + /** + * Optional comma-separated caller-defined tags for tracking this request. Tags are + * recorded on the request's usage log and can be used to filter usage on the + * dashboard usage page. Up to 20 tags, each 1-50 characters. + */ + tags?: Array; +} + +export interface BatchListParams { + /** + * Cursor from the previous page. + */ + cursor?: string; + + /** + * Batches per page. Defaults to 25. + */ + limit?: number; + + /** + * Filter by status. + */ + status?: 'queued' | 'running' | 'cancelling' | 'completed' | 'cancelled' | 'failed'; + + /** + * Optional comma-separated caller-defined tags for tracking this request. Tags are + * recorded on the request's usage log and can be used to filter usage on the + * dashboard usage page. Up to 20 tags, each 1-50 characters. + */ + tags?: Array; +} + +export interface BatchCancelParams { + /** + * Optional comma-separated caller-defined tags for tracking this request. Tags are + * recorded on the request's usage log and can be used to filter usage on the + * dashboard usage page. Up to 20 tags, each 1-50 characters. + */ + tags?: Array; +} + +export interface BatchGetResultsParams { + /** + * next_cursor from the previous page. + */ + cursor?: string; + + /** + * Records per page. Defaults to 25. A page can close early so its payload stays + * under ~8 MB; rely on next_cursor rather than counting records. + */ + limit?: number; + + /** + * Optional comma-separated caller-defined tags for tracking this request. Tags are + * recorded on the request's usage log and can be used to filter usage on the + * dashboard usage page. Up to 20 tags, each 1-50 characters. + */ + tags?: Array; +} + +export interface BatchSubmitParams { + /** + * Known identifiers for the person. At least one identifier is required. + */ + identifiers: BatchSubmitParams.Identifiers; + + /** + * Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters. + */ + tags?: Array; + + /** + * Optional timeout in milliseconds for the request. If the request takes longer + * than this value, it will be aborted with a 408 status code. Maximum allowed + * value is 300000ms (5 minutes). + */ + timeoutMS?: number; +} + +export namespace BatchSubmitParams { + /** + * Known identifiers for the person. At least one identifier is required. + */ + export interface Identifiers { + /** + * LinkedIn profile URL, e.g. https://www.linkedin.com/in/yahia-bakour/. + */ + linkedinUrl?: string; + } +} + +export declare namespace Batch { + export { + type BatchRetrieveResponse as BatchRetrieveResponse, + type BatchListResponse as BatchListResponse, + type BatchCancelResponse as BatchCancelResponse, + type BatchGetResultsResponse as BatchGetResultsResponse, + type BatchSubmitResponse as BatchSubmitResponse, + type BatchRetrieveParams as BatchRetrieveParams, + type BatchListParams as BatchListParams, + type BatchCancelParams as BatchCancelParams, + type BatchGetResultsParams as BatchGetResultsParams, + type BatchSubmitParams as BatchSubmitParams, + }; +} diff --git a/src/resources/index.ts b/src/resources/index.ts index fe1b275..b492009 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -7,6 +7,19 @@ export { type AIExtractProductParams, type AIExtractProductsParams, } from './ai'; +export { + Batch, + type BatchRetrieveResponse, + type BatchListResponse, + type BatchCancelResponse, + type BatchGetResultsResponse, + type BatchSubmitResponse, + type BatchRetrieveParams, + type BatchListParams, + type BatchCancelParams, + type BatchGetResultsParams, + type BatchSubmitParams, +} from './batch'; export { Brand, type BrandRetrieveResponse, diff --git a/tests/api-resources/batch.test.ts b/tests/api-resources/batch.test.ts new file mode 100644 index 0000000..0b4c57e --- /dev/null +++ b/tests/api-resources/batch.test.ts @@ -0,0 +1,135 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ContextDev from 'context.dev'; + +const client = new ContextDev({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource batch', () => { + // Mock server tests are disabled + test.skip('retrieve', async () => { + const responsePromise = client.batch.retrieve('batch_9f2c8a'); + 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); + }); + + // Mock server tests are disabled + test.skip('retrieve: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.batch.retrieve( + 'batch_9f2c8a', + { tags: ['production', 'team-alpha'] }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(ContextDev.NotFoundError); + }); + + // Mock server tests are disabled + test.skip('list', async () => { + const responsePromise = client.batch.list(); + 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); + }); + + // Mock server tests are disabled + test.skip('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.batch.list( + { + cursor: 'cursor', + limit: 1, + status: 'queued', + tags: ['production', 'team-alpha'], + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(ContextDev.NotFoundError); + }); + + // Mock server tests are disabled + test.skip('cancel', async () => { + const responsePromise = client.batch.cancel('batch_9f2c8a'); + 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); + }); + + // Mock server tests are disabled + test.skip('cancel: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.batch.cancel( + 'batch_9f2c8a', + { tags: ['production', 'team-alpha'] }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(ContextDev.NotFoundError); + }); + + // Mock server tests are disabled + test.skip('getResults', async () => { + const responsePromise = client.batch.getResults('batch_9f2c8a'); + 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); + }); + + // Mock server tests are disabled + test.skip('getResults: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.batch.getResults( + 'batch_9f2c8a', + { + cursor: 'cursor', + limit: 1, + tags: ['production', 'team-alpha'], + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(ContextDev.NotFoundError); + }); + + // Mock server tests are disabled + test.skip('submit: only required params', async () => { + const responsePromise = client.batch.submit({ identifiers: {} }); + 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); + }); + + // Mock server tests are disabled + test.skip('submit: required and optional params', async () => { + const response = await client.batch.submit({ + identifiers: { linkedinUrl: 'https://www.linkedin.com/in/yahia-bakour/' }, + tags: ['production', 'team-alpha'], + timeoutMS: 1000, + }); + }); +}); From 1979a9b5db6a0dc79c0cae3edbfa614e2cb31c3f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 07:58:04 +0000 Subject: [PATCH 6/6] release: 2.7.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- packages/mcp-server/manifest.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/server.ts | 2 +- src/version.ts | 2 +- 7 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 69e82f1..6ed9c80 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.6.0" + ".": "2.7.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 54d170a..1917317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 2.7.0 (2026-07-30) + +Full Changelog: [v2.6.0...v2.7.0](https://github.com/context-dot-dev/context-typescript-sdk/compare/v2.6.0...v2.7.0) + +### Features + +* **api:** api update ([54940ea](https://github.com/context-dot-dev/context-typescript-sdk/commit/54940ea4237cf68a517cff23b36b3a4dd0c56283)) +* **api:** api update ([09c34c9](https://github.com/context-dot-dev/context-typescript-sdk/commit/09c34c9d22462550b52a3468818b28848a291cf9)) +* **api:** api update ([dc895a6](https://github.com/context-dot-dev/context-typescript-sdk/commit/dc895a6f73ace40d48d008ba447d80d1283061aa)) +* **api:** manual updates ([7ececf2](https://github.com/context-dot-dev/context-typescript-sdk/commit/7ececf23429c46cebf13d4c1edfb93312426fd4c)) + ## 2.6.0 (2026-07-22) Full Changelog: [v2.5.0...v2.6.0](https://github.com/context-dot-dev/context-typescript-sdk/compare/v2.5.0...v2.6.0) diff --git a/package.json b/package.json index 008caa7..2c4dd1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "context.dev", - "version": "2.6.0", + "version": "2.7.0", "description": "The official TypeScript library for the Context Dev API", "author": "Context Dev ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json index a024e4d..82f5835 100644 --- a/packages/mcp-server/manifest.json +++ b/packages/mcp-server/manifest.json @@ -1,7 +1,7 @@ { "dxt_version": "0.2", "name": "context.dev-mcp", - "version": "2.6.0", + "version": "2.7.0", "description": "The official MCP Server for the Context Dev API", "author": { "name": "Context Dev", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index d964768..f80a63e 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "context.dev-mcp", - "version": "2.6.0", + "version": "2.7.0", "description": "The official MCP Server for the Context Dev API", "author": "Context Dev ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index a954c9b..b8ff8c7 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -28,7 +28,7 @@ export const newMcpServer = async ({ new McpServer( { name: 'context_dev_api', - version: '2.6.0', + version: '2.7.0', }, { instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }), diff --git a/src/version.ts b/src/version.ts index cc6e4a8..9556c21 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '2.6.0'; // x-release-please-version +export const VERSION = '2.7.0'; // x-release-please-version