notte-sdk 0.0.22 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { a as NotteProxyConfig } from '../types-DmqqdEMP.mjs';
1
+ import { a as NotteProxyConfig } from '../types-C5V9BOux.mjs';
2
2
 
3
3
  /**
4
4
  * Framework-agnostic proxy handler that forwards requests to the Notte API.
@@ -1,4 +1,4 @@
1
- import { a as NotteProxyConfig } from '../types-DmqqdEMP.js';
1
+ import { a as NotteProxyConfig } from '../types-C5V9BOux.js';
2
2
 
3
3
  /**
4
4
  * Framework-agnostic proxy handler that forwards requests to the Notte API.
@@ -83,6 +83,21 @@ var DEFAULT_ALLOWED_PATTERNS = [
83
83
  // /managed-auth/connect-links/status
84
84
  /^managed-auth\/connect-links\/submit$/,
85
85
  // /managed-auth/connect-links/submit
86
+ /^managed-auth\/connections\/[^\/]+\/check$/,
87
+ // /managed-auth/connections/{connection_id}/check
88
+ /^managed-auth\/connections\/[^\/]+\/reauthenticate$/,
89
+ // /managed-auth/connections/{connection_id}/reauthenticate
90
+ /^managed-auth\/connections\/[^\/]+\/refresh$/,
91
+ // /managed-auth/connections/{connection_id}/refresh
92
+ /^managed-auth\/operations\/[^\/]+$/,
93
+ // /managed-auth/operations/{operation_id}
94
+ // Payments endpoints
95
+ /^payments\/[^\/]+$/,
96
+ // /payments/{payment_id}
97
+ /^payments\/connect$/,
98
+ // /payments/connect
99
+ /^payments\/disconnect$/,
100
+ // /payments/disconnect
86
101
  // Personas endpoints
87
102
  /^personas$/,
88
103
  // /personas
@@ -110,9 +125,6 @@ var DEFAULT_ALLOWED_PATTERNS = [
110
125
  // /prompts/improve
111
126
  /^prompts\/nudge$/,
112
127
  // /prompts/nudge
113
- // Proxies endpoints
114
- /^proxies\/gateway\/credentials$/,
115
- // /proxies/gateway/credentials
116
128
  // Ready endpoints
117
129
  /^ready$/,
118
130
  // /ready
@@ -138,6 +150,8 @@ var DEFAULT_ALLOWED_PATTERNS = [
138
150
  // /sessions
139
151
  /^sessions\/[^\/]+$/,
140
152
  // /sessions/{session_id}
153
+ /^sessions\/[^\/]+\/auth$/,
154
+ // /sessions/{session_id}/auth
141
155
  /^sessions\/[^\/]+\/cookies$/,
142
156
  // /sessions/{session_id}/cookies
143
157
  /^sessions\/[^\/]+\/debug$/,
@@ -158,6 +172,10 @@ var DEFAULT_ALLOWED_PATTERNS = [
158
172
  // /sessions/{session_id}/page/scrape
159
173
  /^sessions\/[^\/]+\/page\/screenshot$/,
160
174
  // /sessions/{session_id}/page/screenshot
175
+ /^sessions\/[^\/]+\/payments$/,
176
+ // /sessions/{session_id}/payments
177
+ /^sessions\/[^\/]+\/profile-preview$/,
178
+ // /sessions/{session_id}/profile-preview
161
179
  /^sessions\/[^\/]+\/replay$/,
162
180
  // /sessions/{session_id}/replay
163
181
  /^sessions\/[^\/]+\/stop$/,
@@ -231,6 +249,9 @@ async function handleProxyRequest(request, pathSegments, config) {
231
249
  );
232
250
  }
233
251
  }
252
+ if (typeof config.authenticate !== "function") {
253
+ throw new NotteProxyAuthError("Proxy caller authentication is required");
254
+ }
234
255
  let apiKey = config.apiKey || process.env.NOTTE_API_KEY;
235
256
  if (config.authenticate) {
236
257
  const result = await config.authenticate(request);
@@ -254,6 +275,7 @@ async function handleProxyRequest(request, pathSegments, config) {
254
275
  const targetUrl = `${apiUrl}/${path}${searchParams ? `?${searchParams}` : ""}`;
255
276
  const forwardHeaders = new Headers();
256
277
  forwardHeaders.set("Authorization", `Bearer ${apiKey}`);
278
+ forwardHeaders.set("x-notte-api-key", apiKey);
257
279
  forwardHeaders.set(
258
280
  "x-notte-request-origin",
259
281
  config.requestOrigin || "sdk-proxy"
@@ -276,7 +298,8 @@ async function handleProxyRequest(request, pathSegments, config) {
276
298
  }
277
299
  const requestOptions = {
278
300
  method: request.method,
279
- headers: forwardHeaders
301
+ headers: forwardHeaders,
302
+ signal: request.signal
280
303
  };
281
304
  if (METHODS_WITH_BODY.includes(request.method) && request.body) {
282
305
  requestOptions.body = request.body;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/proxy/core.ts","../../src/proxy/patterns.ts","../../src/proxy/types.ts"],"sourcesContent":["import { validatePath, DEFAULT_ALLOWED_PATTERNS } from './patterns';\nimport type { NotteProxyConfig } from './types';\nimport { NotteProxyAuthError } from './types';\n\nconst DEFAULT_API_URL = 'https://api.notte.cc';\nconst DEFAULT_FORWARD_HEADERS = ['content-type', 'accept'];\nconst METHODS_WITH_BODY = ['POST', 'PUT', 'PATCH'];\n\n/**\n * Framework-agnostic proxy handler that forwards requests to the Notte API.\n *\n * Takes a standard Web API `Request`, injects authentication, and returns\n * a standard Web API `Response`. Works with any runtime that supports\n * the Web API standards (Node 18+, Deno, Bun, Cloudflare Workers).\n *\n * @param request - The incoming HTTP request (standard Web API Request)\n * @param pathSegments - The path segments after the proxy base path (e.g., ['sessions', 'start'])\n * @param config - Proxy configuration including API key, auth hooks, etc.\n * @returns A standard Web API Response\n */\nexport async function handleProxyRequest(\n request: Request,\n pathSegments: string[],\n config: NotteProxyConfig,\n): Promise<Response> {\n try {\n // Step 1: Path validation\n if (config.allowedPatterns !== false) {\n const patterns = config.allowedPatterns || DEFAULT_ALLOWED_PATTERNS;\n const pathValidation = validatePath(pathSegments, patterns);\n\n if (!pathValidation.isValid) {\n return new Response(\n JSON.stringify({\n error: 'Invalid API endpoint',\n details: pathValidation.error,\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n }\n\n // Step 2: Authentication\n let apiKey = config.apiKey || process.env.NOTTE_API_KEY;\n\n if (config.authenticate) {\n const result = await config.authenticate(request);\n if (typeof result === 'string') {\n apiKey = result;\n }\n }\n\n if (!apiKey) {\n return new Response(\n JSON.stringify({ error: 'No API key configured' }),\n {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Step 3: Build target URL\n const apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\\/$/, '');\n const path = pathSegments.join('/');\n const incomingUrl = new URL(request.url);\n const searchParams = incomingUrl.searchParams.toString();\n const targetUrl = `${apiUrl}/${path}${searchParams ? `?${searchParams}` : ''}`;\n\n // Step 4: Build headers\n const forwardHeaders = new Headers();\n forwardHeaders.set('Authorization', `Bearer ${apiKey}`);\n forwardHeaders.set(\n 'x-notte-request-origin',\n config.requestOrigin || 'sdk-proxy',\n );\n\n const headersToForward =\n config.forwardHeaders || DEFAULT_FORWARD_HEADERS;\n for (const header of headersToForward) {\n const value = request.headers.get(header);\n if (value) {\n forwardHeaders.set(header, value);\n }\n }\n\n // Step 5: onBeforeRequest hook\n if (config.onBeforeRequest) {\n await config.onBeforeRequest({\n path,\n method: request.method,\n headers: forwardHeaders,\n url: targetUrl,\n incomingRequest: request,\n });\n }\n\n // Step 6: Forward the request\n const requestOptions: RequestInit = {\n method: request.method,\n headers: forwardHeaders,\n };\n\n if (METHODS_WITH_BODY.includes(request.method) && request.body) {\n requestOptions.body = request.body;\n (requestOptions as any).duplex = 'half';\n }\n\n let response: globalThis.Response;\n try {\n response = await fetch(targetUrl, requestOptions);\n } catch (fetchError) {\n const errorMessage =\n fetchError instanceof Error\n ? fetchError.message\n : 'Unknown fetch error';\n return new Response(\n JSON.stringify({\n error: 'Failed to forward request to Notte API',\n details: errorMessage,\n }),\n {\n status: 502,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Step 7: Handle response\n const contentType = response.headers.get('content-type') || '';\n\n const isBinaryResponse =\n contentType.startsWith('image/') ||\n contentType.startsWith('video/') ||\n contentType.startsWith('audio/') ||\n contentType.includes('octet-stream');\n\n const isStreamingResponse = contentType.includes('text/event-stream');\n\n // For streaming responses, pass through the body with appropriate headers\n if (isStreamingResponse && response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n }\n\n // For all other responses with a body stream, pass it through directly\n if (response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: {\n 'Content-Type': contentType,\n },\n });\n }\n\n // Fallback for responses without a body stream: buffer appropriately\n if (isBinaryResponse) {\n const data = await response.arrayBuffer();\n return new Response(data, {\n status: response.status,\n statusText: response.statusText,\n headers: { 'Content-Type': contentType },\n });\n }\n\n // Fallback: buffer as text\n const data = await response.text();\n return new Response(data, {\n status: response.status,\n statusText: response.statusText,\n headers: { 'Content-Type': contentType },\n });\n } catch (error) {\n // NotteProxyAuthError from authenticate() → 401\n if (error instanceof NotteProxyAuthError) {\n return new Response(\n JSON.stringify({ error: error.message }),\n {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Re-throw unexpected errors so the adapter layer can handle them\n throw error;\n }\n}\n","/**\n * Auto-generated from sdk.gen.ts by scripts/generate-proxy-patterns.js\n * DO NOT EDIT MANUALLY — re-run `npm run generate` to update.\n *\n * Allowed API endpoint patterns to prevent SSRF attacks.\n * Every pattern corresponds to an endpoint in the Notte API OpenAPI spec.\n */\nexport const DEFAULT_ALLOWED_PATTERNS: RegExp[] = [\n // Agents endpoints\n /^agents$/, // /agents\n /^agents\\/[^\\/]+$/, // /agents/{agent_id}\n /^agents\\/[^\\/]+\\/stop$/, // /agents/{agent_id}/stop\n /^agents\\/[^\\/]+\\/workflow\\/code$/, // /agents/{agent_id}/workflow/code\n /^agents\\/start$/, // /agents/start\n\n // Anything endpoints\n /^anything\\/start$/, // /anything/start\n\n // Functions endpoints\n /^functions$/, // /functions\n /^functions\\/[^\\/]+$/, // /functions/{function_id}\n /^functions\\/[^\\/]+\\/fork$/, // /functions/{function_id}/fork\n /^functions\\/[^\\/]+\\/rollback$/, // /functions/{function_id}/rollback\n /^functions\\/[^\\/]+\\/runs$/, // /functions/{function_id}/runs\n /^functions\\/[^\\/]+\\/runs\\/[^\\/]+$/, // /functions/{function_id}/runs/{run_id}\n /^functions\\/[^\\/]+\\/runs\\/start$/, // /functions/{function_id}/runs/start\n /^functions\\/[^\\/]+\\/schedule$/, // /functions/{function_id}/schedule\n /^functions\\/health$/, // /functions/health\n\n // Mailboxes endpoints\n /^mailboxes$/, // /mailboxes\n /^mailboxes\\/[^\\/]+$/, // /mailboxes/{mailbox_id}\n /^mailboxes\\/connect-token$/, // /mailboxes/connect-token\n /^mailboxes\\/sync$/, // /mailboxes/sync\n\n // Managed-auth endpoints\n /^managed-auth\\/connect-links$/, // /managed-auth/connect-links\n /^managed-auth\\/connect-links\\/context$/, // /managed-auth/connect-links/context\n /^managed-auth\\/connect-links\\/mailboxes$/, // /managed-auth/connect-links/mailboxes\n /^managed-auth\\/connect-links\\/mailboxes\\/connect$/, // /managed-auth/connect-links/mailboxes/connect\n /^managed-auth\\/connect-links\\/mailboxes\\/sync$/, // /managed-auth/connect-links/mailboxes/sync\n /^managed-auth\\/connect-links\\/status$/, // /managed-auth/connect-links/status\n /^managed-auth\\/connect-links\\/submit$/, // /managed-auth/connect-links/submit\n\n // Personas endpoints\n /^personas$/, // /personas\n /^personas\\/[^\\/]+$/, // /personas/{persona_id}\n /^personas\\/[^\\/]+\\/emails$/, // /personas/{persona_id}/emails\n /^personas\\/[^\\/]+\\/sms$/, // /personas/{persona_id}/sms\n /^personas\\/create$/, // /personas/create\n\n // Profiles endpoints\n /^profiles$/, // /profiles\n /^profiles\\/[^\\/]+$/, // /profiles/{profile_id}\n /^profiles\\/[^\\/]+\\/cookies$/, // /profiles/{profile_id}/cookies\n /^profiles\\/[^\\/]+\\/duplicate$/, // /profiles/{profile_id}/duplicate\n /^profiles\\/create$/, // /profiles/create\n\n // Prompts endpoints\n /^prompts\\/improve$/, // /prompts/improve\n /^prompts\\/nudge$/, // /prompts/nudge\n\n // Proxies endpoints\n /^proxies\\/gateway\\/credentials$/, // /proxies/gateway/credentials\n\n // Ready endpoints\n /^ready$/, // /ready\n\n // Root endpoints\n /^health$/, // /health\n /^scrape$/, // /scrape\n /^scrape_from_html$/, // /scrape_from_html\n\n // Search endpoints\n /^search$/, // /search\n\n // Secrets endpoints\n /^secrets$/, // /secrets\n /^secrets\\/[^\\/]+$/, // /secrets/{name}\n /^secrets\\/[^\\/]+$/, // /secrets/{secret_id}\n\n // Sessions endpoints\n /^sessions$/, // /sessions\n /^sessions\\/[^\\/]+$/, // /sessions/{session_id}\n /^sessions\\/[^\\/]+\\/cookies$/, // /sessions/{session_id}/cookies\n /^sessions\\/[^\\/]+\\/debug$/, // /sessions/{session_id}/debug\n /^sessions\\/[^\\/]+\\/files$/, // /sessions/{session_id}/files\n /^sessions\\/[^\\/]+\\/files\\/[^\\/]+$/, // /sessions/{session_id}/files/{file_id}\n /^sessions\\/[^\\/]+\\/network\\/logs$/, // /sessions/{session_id}/network/logs\n /^sessions\\/[^\\/]+\\/offset$/, // /sessions/{session_id}/offset\n /^sessions\\/[^\\/]+\\/page\\/execute$/, // /sessions/{session_id}/page/execute\n /^sessions\\/[^\\/]+\\/page\\/observe$/, // /sessions/{session_id}/page/observe\n /^sessions\\/[^\\/]+\\/page\\/scrape$/, // /sessions/{session_id}/page/scrape\n /^sessions\\/[^\\/]+\\/page\\/screenshot$/, // /sessions/{session_id}/page/screenshot\n /^sessions\\/[^\\/]+\\/replay$/, // /sessions/{session_id}/replay\n /^sessions\\/[^\\/]+\\/stop$/, // /sessions/{session_id}/stop\n /^sessions\\/[^\\/]+\\/workflow\\/code$/, // /sessions/{session_id}/workflow/code\n /^sessions\\/start$/, // /sessions/start\n\n // Usage endpoints\n /^usage$/, // /usage\n /^usage\\/logs$/, // /usage/logs\n\n // Vaults endpoints\n /^vaults$/, // /vaults\n /^vaults\\/[^\\/]+$/, // /vaults/{vault_id}\n /^vaults\\/[^\\/]+\\/card$/, // /vaults/{vault_id}/card\n /^vaults\\/[^\\/]+\\/credentials$/, // /vaults/{vault_id}/credentials\n /^vaults\\/create$/, // /vaults/create\n];\n\nexport interface PathValidationResult {\n isValid: boolean;\n error?: string;\n}\n\n/**\n * Validates a request path against a list of allowed patterns.\n * Prevents directory traversal and SSRF attacks.\n */\nexport function validatePath(\n pathSegments: string[],\n allowedPatterns: RegExp[],\n): PathValidationResult {\n const path = pathSegments.join('/');\n\n // Check for directory traversal attempts\n if (path.includes('..') || path.includes('//') || path.startsWith('/')) {\n return {\n isValid: false,\n error: 'Invalid path: directory traversal detected',\n };\n }\n\n // Check against allowed patterns\n const isValidPattern = allowedPatterns.some((pattern) => pattern.test(path));\n if (!isValidPattern) {\n return {\n isValid: false,\n error: `Invalid path: ${path} does not match any allowed endpoint pattern`,\n };\n }\n\n return { isValid: true };\n}\n","/**\n * Error class for authentication/authorization failures in the proxy.\n * Throw this from `authenticate()` to return a 401 response.\n *\n * @example\n * ```typescript\n * authenticate: async (request) => {\n * const session = await getSession(request);\n * if (!session) throw new NotteProxyAuthError('Not logged in');\n * }\n * ```\n */\nexport class NotteProxyAuthError extends Error {\n constructor(message = 'Unauthorized') {\n super(message);\n this.name = 'NotteProxyAuthError';\n }\n}\n\n/**\n * Configuration for the Notte API proxy.\n *\n * The proxy forwards incoming HTTP requests to the Notte API,\n * injecting authentication headers server-side so the API key\n * is never exposed to the client.\n */\nexport interface NotteProxyConfig {\n /**\n * The Notte API key to use for all forwarded requests.\n * Falls back to the NOTTE_API_KEY environment variable when omitted.\n * Can be overridden per-request by returning a string from `authenticate`.\n */\n apiKey?: string;\n\n /**\n * Base URL of the Notte API.\n * @default 'https://api.notte.cc'\n */\n apiUrl?: string;\n\n /**\n * Optional async function to authenticate/authorize incoming requests.\n *\n * - Throw a `NotteProxyAuthError` to reject the request (returns 401).\n * - Return `void` to allow the request through using the default `apiKey`.\n * - Return a `string` to override the API key for this specific request\n * (useful for per-user API keys).\n */\n authenticate?: (request: Request) => Promise<void | string>;\n\n /**\n * Allowed API endpoint patterns for path validation (SSRF prevention).\n *\n * - `undefined` (default): uses the built-in allowlist derived from the OpenAPI spec.\n * - `RegExp[]`: custom list of allowed patterns.\n * - `false`: disables path validation entirely (not recommended for public-facing proxies).\n */\n allowedPatterns?: RegExp[] | false;\n\n /**\n * Value for the `x-notte-request-origin` header sent to the Notte API.\n * @default 'sdk-proxy'\n */\n requestOrigin?: string;\n\n /**\n * List of header names to forward from the incoming request to the Notte API.\n * @default ['content-type', 'accept']\n */\n forwardHeaders?: string[];\n\n /**\n * Optional hook called just before the request is forwarded to the Notte API.\n * Use this to modify outgoing headers, log requests, etc.\n */\n onBeforeRequest?: (ctx: {\n path: string;\n method: string;\n headers: Headers;\n url: string;\n incomingRequest: Request;\n }) => Promise<void> | void;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOO,IAAM,2BAAqC;AAAA;AAAA,EAEhD;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;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","names":["data"]}
1
+ {"version":3,"sources":["../../src/proxy/core.ts","../../src/proxy/patterns.ts","../../src/proxy/types.ts"],"sourcesContent":["import { validatePath, DEFAULT_ALLOWED_PATTERNS } from './patterns';\nimport type { NotteProxyConfig } from './types';\nimport { NotteProxyAuthError } from './types';\n\nconst DEFAULT_API_URL = 'https://api.notte.cc';\nconst DEFAULT_FORWARD_HEADERS = ['content-type', 'accept'];\nconst METHODS_WITH_BODY = ['POST', 'PUT', 'PATCH'];\n\n/**\n * Framework-agnostic proxy handler that forwards requests to the Notte API.\n *\n * Takes a standard Web API `Request`, injects authentication, and returns\n * a standard Web API `Response`. Works with any runtime that supports\n * the Web API standards (Node 18+, Deno, Bun, Cloudflare Workers).\n *\n * @param request - The incoming HTTP request (standard Web API Request)\n * @param pathSegments - The path segments after the proxy base path (e.g., ['sessions', 'start'])\n * @param config - Proxy configuration including API key, auth hooks, etc.\n * @returns A standard Web API Response\n */\nexport async function handleProxyRequest(\n request: Request,\n pathSegments: string[],\n config: NotteProxyConfig,\n): Promise<Response> {\n try {\n // Step 1: Path validation\n if (config.allowedPatterns !== false) {\n const patterns = config.allowedPatterns || DEFAULT_ALLOWED_PATTERNS;\n const pathValidation = validatePath(pathSegments, patterns);\n\n if (!pathValidation.isValid) {\n return new Response(\n JSON.stringify({\n error: 'Invalid API endpoint',\n details: pathValidation.error,\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n }\n\n // Step 2: Authentication\n if (typeof config.authenticate !== 'function') {\n throw new NotteProxyAuthError('Proxy caller authentication is required');\n }\n let apiKey = config.apiKey || process.env.NOTTE_API_KEY;\n\n if (config.authenticate) {\n const result = await config.authenticate(request);\n if (typeof result === 'string') {\n apiKey = result;\n }\n }\n\n if (!apiKey) {\n return new Response(\n JSON.stringify({ error: 'No API key configured' }),\n {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Step 3: Build target URL\n const apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\\/$/, '');\n const path = pathSegments.join('/');\n const incomingUrl = new URL(request.url);\n const searchParams = incomingUrl.searchParams.toString();\n const targetUrl = `${apiUrl}/${path}${searchParams ? `?${searchParams}` : ''}`;\n\n // Step 4: Build headers\n const forwardHeaders = new Headers();\n forwardHeaders.set('Authorization', `Bearer ${apiKey}`);\n // Function run endpoints authenticate with their own header (the API does\n // not forward `Authorization` to the runtime), so inject it as well.\n forwardHeaders.set('x-notte-api-key', apiKey);\n forwardHeaders.set(\n 'x-notte-request-origin',\n config.requestOrigin || 'sdk-proxy',\n );\n\n const headersToForward =\n config.forwardHeaders || DEFAULT_FORWARD_HEADERS;\n for (const header of headersToForward) {\n const value = request.headers.get(header);\n if (value) {\n forwardHeaders.set(header, value);\n }\n }\n\n // Step 5: onBeforeRequest hook\n if (config.onBeforeRequest) {\n await config.onBeforeRequest({\n path,\n method: request.method,\n headers: forwardHeaders,\n url: targetUrl,\n incomingRequest: request,\n });\n }\n\n // Step 6: Forward the request\n const requestOptions: RequestInit = {\n method: request.method,\n headers: forwardHeaders,\n signal: request.signal,\n };\n\n if (METHODS_WITH_BODY.includes(request.method) && request.body) {\n requestOptions.body = request.body;\n (requestOptions as any).duplex = 'half';\n }\n\n let response: globalThis.Response;\n try {\n response = await fetch(targetUrl, requestOptions);\n } catch (fetchError) {\n const errorMessage =\n fetchError instanceof Error\n ? fetchError.message\n : 'Unknown fetch error';\n return new Response(\n JSON.stringify({\n error: 'Failed to forward request to Notte API',\n details: errorMessage,\n }),\n {\n status: 502,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Step 7: Handle response\n const contentType = response.headers.get('content-type') || '';\n\n const isBinaryResponse =\n contentType.startsWith('image/') ||\n contentType.startsWith('video/') ||\n contentType.startsWith('audio/') ||\n contentType.includes('octet-stream');\n\n const isStreamingResponse = contentType.includes('text/event-stream');\n\n // For streaming responses, pass through the body with appropriate headers\n if (isStreamingResponse && response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n }\n\n // For all other responses with a body stream, pass it through directly\n if (response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: {\n 'Content-Type': contentType,\n },\n });\n }\n\n // Fallback for responses without a body stream: buffer appropriately\n if (isBinaryResponse) {\n const data = await response.arrayBuffer();\n return new Response(data, {\n status: response.status,\n statusText: response.statusText,\n headers: { 'Content-Type': contentType },\n });\n }\n\n // Fallback: buffer as text\n const data = await response.text();\n return new Response(data, {\n status: response.status,\n statusText: response.statusText,\n headers: { 'Content-Type': contentType },\n });\n } catch (error) {\n // NotteProxyAuthError from authenticate() → 401\n if (error instanceof NotteProxyAuthError) {\n return new Response(\n JSON.stringify({ error: error.message }),\n {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Re-throw unexpected errors so the adapter layer can handle them\n throw error;\n }\n}\n","/**\n * Auto-generated from sdk.gen.ts by scripts/generate-proxy-patterns.js\n * DO NOT EDIT MANUALLY — re-run `npm run generate` to update.\n *\n * Allowed API endpoint patterns to prevent SSRF attacks.\n * Every pattern corresponds to an endpoint in the Notte API OpenAPI spec.\n */\nexport const DEFAULT_ALLOWED_PATTERNS: RegExp[] = [\n // Agents endpoints\n /^agents$/, // /agents\n /^agents\\/[^\\/]+$/, // /agents/{agent_id}\n /^agents\\/[^\\/]+\\/stop$/, // /agents/{agent_id}/stop\n /^agents\\/[^\\/]+\\/workflow\\/code$/, // /agents/{agent_id}/workflow/code\n /^agents\\/start$/, // /agents/start\n\n // Anything endpoints\n /^anything\\/start$/, // /anything/start\n\n // Functions endpoints\n /^functions$/, // /functions\n /^functions\\/[^\\/]+$/, // /functions/{function_id}\n /^functions\\/[^\\/]+\\/fork$/, // /functions/{function_id}/fork\n /^functions\\/[^\\/]+\\/rollback$/, // /functions/{function_id}/rollback\n /^functions\\/[^\\/]+\\/runs$/, // /functions/{function_id}/runs\n /^functions\\/[^\\/]+\\/runs\\/[^\\/]+$/, // /functions/{function_id}/runs/{run_id}\n /^functions\\/[^\\/]+\\/runs\\/start$/, // /functions/{function_id}/runs/start\n /^functions\\/[^\\/]+\\/schedule$/, // /functions/{function_id}/schedule\n /^functions\\/health$/, // /functions/health\n\n // Mailboxes endpoints\n /^mailboxes$/, // /mailboxes\n /^mailboxes\\/[^\\/]+$/, // /mailboxes/{mailbox_id}\n /^mailboxes\\/connect-token$/, // /mailboxes/connect-token\n /^mailboxes\\/sync$/, // /mailboxes/sync\n\n // Managed-auth endpoints\n /^managed-auth\\/connect-links$/, // /managed-auth/connect-links\n /^managed-auth\\/connect-links\\/context$/, // /managed-auth/connect-links/context\n /^managed-auth\\/connect-links\\/mailboxes$/, // /managed-auth/connect-links/mailboxes\n /^managed-auth\\/connect-links\\/mailboxes\\/connect$/, // /managed-auth/connect-links/mailboxes/connect\n /^managed-auth\\/connect-links\\/mailboxes\\/sync$/, // /managed-auth/connect-links/mailboxes/sync\n /^managed-auth\\/connect-links\\/status$/, // /managed-auth/connect-links/status\n /^managed-auth\\/connect-links\\/submit$/, // /managed-auth/connect-links/submit\n /^managed-auth\\/connections\\/[^\\/]+\\/check$/, // /managed-auth/connections/{connection_id}/check\n /^managed-auth\\/connections\\/[^\\/]+\\/reauthenticate$/, // /managed-auth/connections/{connection_id}/reauthenticate\n /^managed-auth\\/connections\\/[^\\/]+\\/refresh$/, // /managed-auth/connections/{connection_id}/refresh\n /^managed-auth\\/operations\\/[^\\/]+$/, // /managed-auth/operations/{operation_id}\n\n // Payments endpoints\n /^payments\\/[^\\/]+$/, // /payments/{payment_id}\n /^payments\\/connect$/, // /payments/connect\n /^payments\\/disconnect$/, // /payments/disconnect\n\n // Personas endpoints\n /^personas$/, // /personas\n /^personas\\/[^\\/]+$/, // /personas/{persona_id}\n /^personas\\/[^\\/]+\\/emails$/, // /personas/{persona_id}/emails\n /^personas\\/[^\\/]+\\/sms$/, // /personas/{persona_id}/sms\n /^personas\\/create$/, // /personas/create\n\n // Profiles endpoints\n /^profiles$/, // /profiles\n /^profiles\\/[^\\/]+$/, // /profiles/{profile_id}\n /^profiles\\/[^\\/]+\\/cookies$/, // /profiles/{profile_id}/cookies\n /^profiles\\/[^\\/]+\\/duplicate$/, // /profiles/{profile_id}/duplicate\n /^profiles\\/create$/, // /profiles/create\n\n // Prompts endpoints\n /^prompts\\/improve$/, // /prompts/improve\n /^prompts\\/nudge$/, // /prompts/nudge\n\n // Ready endpoints\n /^ready$/, // /ready\n\n // Root endpoints\n /^health$/, // /health\n /^scrape$/, // /scrape\n /^scrape_from_html$/, // /scrape_from_html\n\n // Search endpoints\n /^search$/, // /search\n\n // Secrets endpoints\n /^secrets$/, // /secrets\n /^secrets\\/[^\\/]+$/, // /secrets/{name}\n /^secrets\\/[^\\/]+$/, // /secrets/{secret_id}\n\n // Sessions endpoints\n /^sessions$/, // /sessions\n /^sessions\\/[^\\/]+$/, // /sessions/{session_id}\n /^sessions\\/[^\\/]+\\/auth$/, // /sessions/{session_id}/auth\n /^sessions\\/[^\\/]+\\/cookies$/, // /sessions/{session_id}/cookies\n /^sessions\\/[^\\/]+\\/debug$/, // /sessions/{session_id}/debug\n /^sessions\\/[^\\/]+\\/files$/, // /sessions/{session_id}/files\n /^sessions\\/[^\\/]+\\/files\\/[^\\/]+$/, // /sessions/{session_id}/files/{file_id}\n /^sessions\\/[^\\/]+\\/network\\/logs$/, // /sessions/{session_id}/network/logs\n /^sessions\\/[^\\/]+\\/offset$/, // /sessions/{session_id}/offset\n /^sessions\\/[^\\/]+\\/page\\/execute$/, // /sessions/{session_id}/page/execute\n /^sessions\\/[^\\/]+\\/page\\/observe$/, // /sessions/{session_id}/page/observe\n /^sessions\\/[^\\/]+\\/page\\/scrape$/, // /sessions/{session_id}/page/scrape\n /^sessions\\/[^\\/]+\\/page\\/screenshot$/, // /sessions/{session_id}/page/screenshot\n /^sessions\\/[^\\/]+\\/payments$/, // /sessions/{session_id}/payments\n /^sessions\\/[^\\/]+\\/profile-preview$/, // /sessions/{session_id}/profile-preview\n /^sessions\\/[^\\/]+\\/replay$/, // /sessions/{session_id}/replay\n /^sessions\\/[^\\/]+\\/stop$/, // /sessions/{session_id}/stop\n /^sessions\\/[^\\/]+\\/workflow\\/code$/, // /sessions/{session_id}/workflow/code\n /^sessions\\/start$/, // /sessions/start\n\n // Usage endpoints\n /^usage$/, // /usage\n /^usage\\/logs$/, // /usage/logs\n\n // Vaults endpoints\n /^vaults$/, // /vaults\n /^vaults\\/[^\\/]+$/, // /vaults/{vault_id}\n /^vaults\\/[^\\/]+\\/card$/, // /vaults/{vault_id}/card\n /^vaults\\/[^\\/]+\\/credentials$/, // /vaults/{vault_id}/credentials\n /^vaults\\/create$/, // /vaults/create\n];\n\nexport interface PathValidationResult {\n isValid: boolean;\n error?: string;\n}\n\n/**\n * Validates a request path against a list of allowed patterns.\n * Prevents directory traversal and SSRF attacks.\n */\nexport function validatePath(\n pathSegments: string[],\n allowedPatterns: RegExp[],\n): PathValidationResult {\n const path = pathSegments.join('/');\n\n // Check for directory traversal attempts\n if (path.includes('..') || path.includes('//') || path.startsWith('/')) {\n return {\n isValid: false,\n error: 'Invalid path: directory traversal detected',\n };\n }\n\n // Check against allowed patterns\n const isValidPattern = allowedPatterns.some((pattern) => pattern.test(path));\n if (!isValidPattern) {\n return {\n isValid: false,\n error: `Invalid path: ${path} does not match any allowed endpoint pattern`,\n };\n }\n\n return { isValid: true };\n}\n","/**\n * Error class for authentication/authorization failures in the proxy.\n * Throw this from `authenticate()` to return a 401 response.\n *\n * @example\n * ```typescript\n * authenticate: async (request) => {\n * const session = await getSession(request);\n * if (!session) throw new NotteProxyAuthError('Not logged in');\n * }\n * ```\n */\nexport class NotteProxyAuthError extends Error {\n constructor(message = 'Unauthorized') {\n super(message);\n this.name = 'NotteProxyAuthError';\n }\n}\n\n/**\n * Configuration for the Notte API proxy.\n *\n * The proxy forwards incoming HTTP requests to the Notte API,\n * injecting authentication headers server-side so the API key\n * is never exposed to the client.\n */\nexport interface NotteProxyConfig {\n /**\n * The Notte API key to use for all forwarded requests.\n * Falls back to the NOTTE_API_KEY environment variable when omitted.\n * Can be overridden per-request by returning a string from `authenticate`.\n */\n apiKey?: string;\n\n /**\n * Base URL of the Notte API.\n * @default 'https://api.notte.cc'\n */\n apiUrl?: string;\n\n /**\n * Authenticate and authorize incoming requests. Missing callbacks fail closed (401).\n * Check resource ownership as well as caller identity. With a shared key, every\n * authorized caller otherwise has access to the same account resources.\n *\n * - Throw a `NotteProxyAuthError` to reject the request (returns 401).\n * - Return `void` to allow the request through using the default `apiKey`.\n * - Return a `string` to override the API key for this specific request\n * (useful for per-user API keys).\n */\n authenticate?: (request: Request) => Promise<void | string>;\n\n /**\n * Allowed API endpoint patterns for path validation (SSRF prevention).\n *\n * - `undefined` (default): uses the built-in allowlist derived from the OpenAPI spec.\n * - `RegExp[]`: custom list of allowed patterns.\n * - `false`: disables path validation entirely (not recommended for public-facing proxies).\n */\n allowedPatterns?: RegExp[] | false;\n\n /**\n * Value for the `x-notte-request-origin` header sent to the Notte API.\n * @default 'sdk-proxy'\n */\n requestOrigin?: string;\n\n /**\n * List of header names to forward from the incoming request to the Notte API.\n * @default ['content-type', 'accept']\n */\n forwardHeaders?: string[];\n\n /**\n * Optional hook called just before the request is forwarded to the Notte API.\n * Use this to modify outgoing headers, log requests, etc.\n */\n onBeforeRequest?: (ctx: {\n path: string;\n method: string;\n headers: Headers;\n url: string;\n incomingRequest: Request;\n }) => Promise<void> | void;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOO,IAAM,2BAAqC;AAAA;AAAA,EAEhD;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;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","names":["data"]}
@@ -57,6 +57,21 @@ var DEFAULT_ALLOWED_PATTERNS = [
57
57
  // /managed-auth/connect-links/status
58
58
  /^managed-auth\/connect-links\/submit$/,
59
59
  // /managed-auth/connect-links/submit
60
+ /^managed-auth\/connections\/[^\/]+\/check$/,
61
+ // /managed-auth/connections/{connection_id}/check
62
+ /^managed-auth\/connections\/[^\/]+\/reauthenticate$/,
63
+ // /managed-auth/connections/{connection_id}/reauthenticate
64
+ /^managed-auth\/connections\/[^\/]+\/refresh$/,
65
+ // /managed-auth/connections/{connection_id}/refresh
66
+ /^managed-auth\/operations\/[^\/]+$/,
67
+ // /managed-auth/operations/{operation_id}
68
+ // Payments endpoints
69
+ /^payments\/[^\/]+$/,
70
+ // /payments/{payment_id}
71
+ /^payments\/connect$/,
72
+ // /payments/connect
73
+ /^payments\/disconnect$/,
74
+ // /payments/disconnect
60
75
  // Personas endpoints
61
76
  /^personas$/,
62
77
  // /personas
@@ -84,9 +99,6 @@ var DEFAULT_ALLOWED_PATTERNS = [
84
99
  // /prompts/improve
85
100
  /^prompts\/nudge$/,
86
101
  // /prompts/nudge
87
- // Proxies endpoints
88
- /^proxies\/gateway\/credentials$/,
89
- // /proxies/gateway/credentials
90
102
  // Ready endpoints
91
103
  /^ready$/,
92
104
  // /ready
@@ -112,6 +124,8 @@ var DEFAULT_ALLOWED_PATTERNS = [
112
124
  // /sessions
113
125
  /^sessions\/[^\/]+$/,
114
126
  // /sessions/{session_id}
127
+ /^sessions\/[^\/]+\/auth$/,
128
+ // /sessions/{session_id}/auth
115
129
  /^sessions\/[^\/]+\/cookies$/,
116
130
  // /sessions/{session_id}/cookies
117
131
  /^sessions\/[^\/]+\/debug$/,
@@ -132,6 +146,10 @@ var DEFAULT_ALLOWED_PATTERNS = [
132
146
  // /sessions/{session_id}/page/scrape
133
147
  /^sessions\/[^\/]+\/page\/screenshot$/,
134
148
  // /sessions/{session_id}/page/screenshot
149
+ /^sessions\/[^\/]+\/payments$/,
150
+ // /sessions/{session_id}/payments
151
+ /^sessions\/[^\/]+\/profile-preview$/,
152
+ // /sessions/{session_id}/profile-preview
135
153
  /^sessions\/[^\/]+\/replay$/,
136
154
  // /sessions/{session_id}/replay
137
155
  /^sessions\/[^\/]+\/stop$/,
@@ -205,6 +223,9 @@ async function handleProxyRequest(request, pathSegments, config) {
205
223
  );
206
224
  }
207
225
  }
226
+ if (typeof config.authenticate !== "function") {
227
+ throw new NotteProxyAuthError("Proxy caller authentication is required");
228
+ }
208
229
  let apiKey = config.apiKey || process.env.NOTTE_API_KEY;
209
230
  if (config.authenticate) {
210
231
  const result = await config.authenticate(request);
@@ -228,6 +249,7 @@ async function handleProxyRequest(request, pathSegments, config) {
228
249
  const targetUrl = `${apiUrl}/${path}${searchParams ? `?${searchParams}` : ""}`;
229
250
  const forwardHeaders = new Headers();
230
251
  forwardHeaders.set("Authorization", `Bearer ${apiKey}`);
252
+ forwardHeaders.set("x-notte-api-key", apiKey);
231
253
  forwardHeaders.set(
232
254
  "x-notte-request-origin",
233
255
  config.requestOrigin || "sdk-proxy"
@@ -250,7 +272,8 @@ async function handleProxyRequest(request, pathSegments, config) {
250
272
  }
251
273
  const requestOptions = {
252
274
  method: request.method,
253
- headers: forwardHeaders
275
+ headers: forwardHeaders,
276
+ signal: request.signal
254
277
  };
255
278
  if (METHODS_WITH_BODY.includes(request.method) && request.body) {
256
279
  requestOptions.body = request.body;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/proxy/patterns.ts","../../src/proxy/types.ts","../../src/proxy/core.ts"],"sourcesContent":["/**\n * Auto-generated from sdk.gen.ts by scripts/generate-proxy-patterns.js\n * DO NOT EDIT MANUALLY — re-run `npm run generate` to update.\n *\n * Allowed API endpoint patterns to prevent SSRF attacks.\n * Every pattern corresponds to an endpoint in the Notte API OpenAPI spec.\n */\nexport const DEFAULT_ALLOWED_PATTERNS: RegExp[] = [\n // Agents endpoints\n /^agents$/, // /agents\n /^agents\\/[^\\/]+$/, // /agents/{agent_id}\n /^agents\\/[^\\/]+\\/stop$/, // /agents/{agent_id}/stop\n /^agents\\/[^\\/]+\\/workflow\\/code$/, // /agents/{agent_id}/workflow/code\n /^agents\\/start$/, // /agents/start\n\n // Anything endpoints\n /^anything\\/start$/, // /anything/start\n\n // Functions endpoints\n /^functions$/, // /functions\n /^functions\\/[^\\/]+$/, // /functions/{function_id}\n /^functions\\/[^\\/]+\\/fork$/, // /functions/{function_id}/fork\n /^functions\\/[^\\/]+\\/rollback$/, // /functions/{function_id}/rollback\n /^functions\\/[^\\/]+\\/runs$/, // /functions/{function_id}/runs\n /^functions\\/[^\\/]+\\/runs\\/[^\\/]+$/, // /functions/{function_id}/runs/{run_id}\n /^functions\\/[^\\/]+\\/runs\\/start$/, // /functions/{function_id}/runs/start\n /^functions\\/[^\\/]+\\/schedule$/, // /functions/{function_id}/schedule\n /^functions\\/health$/, // /functions/health\n\n // Mailboxes endpoints\n /^mailboxes$/, // /mailboxes\n /^mailboxes\\/[^\\/]+$/, // /mailboxes/{mailbox_id}\n /^mailboxes\\/connect-token$/, // /mailboxes/connect-token\n /^mailboxes\\/sync$/, // /mailboxes/sync\n\n // Managed-auth endpoints\n /^managed-auth\\/connect-links$/, // /managed-auth/connect-links\n /^managed-auth\\/connect-links\\/context$/, // /managed-auth/connect-links/context\n /^managed-auth\\/connect-links\\/mailboxes$/, // /managed-auth/connect-links/mailboxes\n /^managed-auth\\/connect-links\\/mailboxes\\/connect$/, // /managed-auth/connect-links/mailboxes/connect\n /^managed-auth\\/connect-links\\/mailboxes\\/sync$/, // /managed-auth/connect-links/mailboxes/sync\n /^managed-auth\\/connect-links\\/status$/, // /managed-auth/connect-links/status\n /^managed-auth\\/connect-links\\/submit$/, // /managed-auth/connect-links/submit\n\n // Personas endpoints\n /^personas$/, // /personas\n /^personas\\/[^\\/]+$/, // /personas/{persona_id}\n /^personas\\/[^\\/]+\\/emails$/, // /personas/{persona_id}/emails\n /^personas\\/[^\\/]+\\/sms$/, // /personas/{persona_id}/sms\n /^personas\\/create$/, // /personas/create\n\n // Profiles endpoints\n /^profiles$/, // /profiles\n /^profiles\\/[^\\/]+$/, // /profiles/{profile_id}\n /^profiles\\/[^\\/]+\\/cookies$/, // /profiles/{profile_id}/cookies\n /^profiles\\/[^\\/]+\\/duplicate$/, // /profiles/{profile_id}/duplicate\n /^profiles\\/create$/, // /profiles/create\n\n // Prompts endpoints\n /^prompts\\/improve$/, // /prompts/improve\n /^prompts\\/nudge$/, // /prompts/nudge\n\n // Proxies endpoints\n /^proxies\\/gateway\\/credentials$/, // /proxies/gateway/credentials\n\n // Ready endpoints\n /^ready$/, // /ready\n\n // Root endpoints\n /^health$/, // /health\n /^scrape$/, // /scrape\n /^scrape_from_html$/, // /scrape_from_html\n\n // Search endpoints\n /^search$/, // /search\n\n // Secrets endpoints\n /^secrets$/, // /secrets\n /^secrets\\/[^\\/]+$/, // /secrets/{name}\n /^secrets\\/[^\\/]+$/, // /secrets/{secret_id}\n\n // Sessions endpoints\n /^sessions$/, // /sessions\n /^sessions\\/[^\\/]+$/, // /sessions/{session_id}\n /^sessions\\/[^\\/]+\\/cookies$/, // /sessions/{session_id}/cookies\n /^sessions\\/[^\\/]+\\/debug$/, // /sessions/{session_id}/debug\n /^sessions\\/[^\\/]+\\/files$/, // /sessions/{session_id}/files\n /^sessions\\/[^\\/]+\\/files\\/[^\\/]+$/, // /sessions/{session_id}/files/{file_id}\n /^sessions\\/[^\\/]+\\/network\\/logs$/, // /sessions/{session_id}/network/logs\n /^sessions\\/[^\\/]+\\/offset$/, // /sessions/{session_id}/offset\n /^sessions\\/[^\\/]+\\/page\\/execute$/, // /sessions/{session_id}/page/execute\n /^sessions\\/[^\\/]+\\/page\\/observe$/, // /sessions/{session_id}/page/observe\n /^sessions\\/[^\\/]+\\/page\\/scrape$/, // /sessions/{session_id}/page/scrape\n /^sessions\\/[^\\/]+\\/page\\/screenshot$/, // /sessions/{session_id}/page/screenshot\n /^sessions\\/[^\\/]+\\/replay$/, // /sessions/{session_id}/replay\n /^sessions\\/[^\\/]+\\/stop$/, // /sessions/{session_id}/stop\n /^sessions\\/[^\\/]+\\/workflow\\/code$/, // /sessions/{session_id}/workflow/code\n /^sessions\\/start$/, // /sessions/start\n\n // Usage endpoints\n /^usage$/, // /usage\n /^usage\\/logs$/, // /usage/logs\n\n // Vaults endpoints\n /^vaults$/, // /vaults\n /^vaults\\/[^\\/]+$/, // /vaults/{vault_id}\n /^vaults\\/[^\\/]+\\/card$/, // /vaults/{vault_id}/card\n /^vaults\\/[^\\/]+\\/credentials$/, // /vaults/{vault_id}/credentials\n /^vaults\\/create$/, // /vaults/create\n];\n\nexport interface PathValidationResult {\n isValid: boolean;\n error?: string;\n}\n\n/**\n * Validates a request path against a list of allowed patterns.\n * Prevents directory traversal and SSRF attacks.\n */\nexport function validatePath(\n pathSegments: string[],\n allowedPatterns: RegExp[],\n): PathValidationResult {\n const path = pathSegments.join('/');\n\n // Check for directory traversal attempts\n if (path.includes('..') || path.includes('//') || path.startsWith('/')) {\n return {\n isValid: false,\n error: 'Invalid path: directory traversal detected',\n };\n }\n\n // Check against allowed patterns\n const isValidPattern = allowedPatterns.some((pattern) => pattern.test(path));\n if (!isValidPattern) {\n return {\n isValid: false,\n error: `Invalid path: ${path} does not match any allowed endpoint pattern`,\n };\n }\n\n return { isValid: true };\n}\n","/**\n * Error class for authentication/authorization failures in the proxy.\n * Throw this from `authenticate()` to return a 401 response.\n *\n * @example\n * ```typescript\n * authenticate: async (request) => {\n * const session = await getSession(request);\n * if (!session) throw new NotteProxyAuthError('Not logged in');\n * }\n * ```\n */\nexport class NotteProxyAuthError extends Error {\n constructor(message = 'Unauthorized') {\n super(message);\n this.name = 'NotteProxyAuthError';\n }\n}\n\n/**\n * Configuration for the Notte API proxy.\n *\n * The proxy forwards incoming HTTP requests to the Notte API,\n * injecting authentication headers server-side so the API key\n * is never exposed to the client.\n */\nexport interface NotteProxyConfig {\n /**\n * The Notte API key to use for all forwarded requests.\n * Falls back to the NOTTE_API_KEY environment variable when omitted.\n * Can be overridden per-request by returning a string from `authenticate`.\n */\n apiKey?: string;\n\n /**\n * Base URL of the Notte API.\n * @default 'https://api.notte.cc'\n */\n apiUrl?: string;\n\n /**\n * Optional async function to authenticate/authorize incoming requests.\n *\n * - Throw a `NotteProxyAuthError` to reject the request (returns 401).\n * - Return `void` to allow the request through using the default `apiKey`.\n * - Return a `string` to override the API key for this specific request\n * (useful for per-user API keys).\n */\n authenticate?: (request: Request) => Promise<void | string>;\n\n /**\n * Allowed API endpoint patterns for path validation (SSRF prevention).\n *\n * - `undefined` (default): uses the built-in allowlist derived from the OpenAPI spec.\n * - `RegExp[]`: custom list of allowed patterns.\n * - `false`: disables path validation entirely (not recommended for public-facing proxies).\n */\n allowedPatterns?: RegExp[] | false;\n\n /**\n * Value for the `x-notte-request-origin` header sent to the Notte API.\n * @default 'sdk-proxy'\n */\n requestOrigin?: string;\n\n /**\n * List of header names to forward from the incoming request to the Notte API.\n * @default ['content-type', 'accept']\n */\n forwardHeaders?: string[];\n\n /**\n * Optional hook called just before the request is forwarded to the Notte API.\n * Use this to modify outgoing headers, log requests, etc.\n */\n onBeforeRequest?: (ctx: {\n path: string;\n method: string;\n headers: Headers;\n url: string;\n incomingRequest: Request;\n }) => Promise<void> | void;\n}\n","import { validatePath, DEFAULT_ALLOWED_PATTERNS } from './patterns';\nimport type { NotteProxyConfig } from './types';\nimport { NotteProxyAuthError } from './types';\n\nconst DEFAULT_API_URL = 'https://api.notte.cc';\nconst DEFAULT_FORWARD_HEADERS = ['content-type', 'accept'];\nconst METHODS_WITH_BODY = ['POST', 'PUT', 'PATCH'];\n\n/**\n * Framework-agnostic proxy handler that forwards requests to the Notte API.\n *\n * Takes a standard Web API `Request`, injects authentication, and returns\n * a standard Web API `Response`. Works with any runtime that supports\n * the Web API standards (Node 18+, Deno, Bun, Cloudflare Workers).\n *\n * @param request - The incoming HTTP request (standard Web API Request)\n * @param pathSegments - The path segments after the proxy base path (e.g., ['sessions', 'start'])\n * @param config - Proxy configuration including API key, auth hooks, etc.\n * @returns A standard Web API Response\n */\nexport async function handleProxyRequest(\n request: Request,\n pathSegments: string[],\n config: NotteProxyConfig,\n): Promise<Response> {\n try {\n // Step 1: Path validation\n if (config.allowedPatterns !== false) {\n const patterns = config.allowedPatterns || DEFAULT_ALLOWED_PATTERNS;\n const pathValidation = validatePath(pathSegments, patterns);\n\n if (!pathValidation.isValid) {\n return new Response(\n JSON.stringify({\n error: 'Invalid API endpoint',\n details: pathValidation.error,\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n }\n\n // Step 2: Authentication\n let apiKey = config.apiKey || process.env.NOTTE_API_KEY;\n\n if (config.authenticate) {\n const result = await config.authenticate(request);\n if (typeof result === 'string') {\n apiKey = result;\n }\n }\n\n if (!apiKey) {\n return new Response(\n JSON.stringify({ error: 'No API key configured' }),\n {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Step 3: Build target URL\n const apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\\/$/, '');\n const path = pathSegments.join('/');\n const incomingUrl = new URL(request.url);\n const searchParams = incomingUrl.searchParams.toString();\n const targetUrl = `${apiUrl}/${path}${searchParams ? `?${searchParams}` : ''}`;\n\n // Step 4: Build headers\n const forwardHeaders = new Headers();\n forwardHeaders.set('Authorization', `Bearer ${apiKey}`);\n forwardHeaders.set(\n 'x-notte-request-origin',\n config.requestOrigin || 'sdk-proxy',\n );\n\n const headersToForward =\n config.forwardHeaders || DEFAULT_FORWARD_HEADERS;\n for (const header of headersToForward) {\n const value = request.headers.get(header);\n if (value) {\n forwardHeaders.set(header, value);\n }\n }\n\n // Step 5: onBeforeRequest hook\n if (config.onBeforeRequest) {\n await config.onBeforeRequest({\n path,\n method: request.method,\n headers: forwardHeaders,\n url: targetUrl,\n incomingRequest: request,\n });\n }\n\n // Step 6: Forward the request\n const requestOptions: RequestInit = {\n method: request.method,\n headers: forwardHeaders,\n };\n\n if (METHODS_WITH_BODY.includes(request.method) && request.body) {\n requestOptions.body = request.body;\n (requestOptions as any).duplex = 'half';\n }\n\n let response: globalThis.Response;\n try {\n response = await fetch(targetUrl, requestOptions);\n } catch (fetchError) {\n const errorMessage =\n fetchError instanceof Error\n ? fetchError.message\n : 'Unknown fetch error';\n return new Response(\n JSON.stringify({\n error: 'Failed to forward request to Notte API',\n details: errorMessage,\n }),\n {\n status: 502,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Step 7: Handle response\n const contentType = response.headers.get('content-type') || '';\n\n const isBinaryResponse =\n contentType.startsWith('image/') ||\n contentType.startsWith('video/') ||\n contentType.startsWith('audio/') ||\n contentType.includes('octet-stream');\n\n const isStreamingResponse = contentType.includes('text/event-stream');\n\n // For streaming responses, pass through the body with appropriate headers\n if (isStreamingResponse && response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n }\n\n // For all other responses with a body stream, pass it through directly\n if (response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: {\n 'Content-Type': contentType,\n },\n });\n }\n\n // Fallback for responses without a body stream: buffer appropriately\n if (isBinaryResponse) {\n const data = await response.arrayBuffer();\n return new Response(data, {\n status: response.status,\n statusText: response.statusText,\n headers: { 'Content-Type': contentType },\n });\n }\n\n // Fallback: buffer as text\n const data = await response.text();\n return new Response(data, {\n status: response.status,\n statusText: response.statusText,\n headers: { 'Content-Type': contentType },\n });\n } catch (error) {\n // NotteProxyAuthError from authenticate() → 401\n if (error instanceof NotteProxyAuthError) {\n return new Response(\n JSON.stringify({ error: error.message }),\n {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Re-throw unexpected errors so the adapter layer can handle them\n throw error;\n }\n}\n"],"mappings":"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","names":["data"]}
1
+ {"version":3,"sources":["../../src/proxy/patterns.ts","../../src/proxy/types.ts","../../src/proxy/core.ts"],"sourcesContent":["/**\n * Auto-generated from sdk.gen.ts by scripts/generate-proxy-patterns.js\n * DO NOT EDIT MANUALLY — re-run `npm run generate` to update.\n *\n * Allowed API endpoint patterns to prevent SSRF attacks.\n * Every pattern corresponds to an endpoint in the Notte API OpenAPI spec.\n */\nexport const DEFAULT_ALLOWED_PATTERNS: RegExp[] = [\n // Agents endpoints\n /^agents$/, // /agents\n /^agents\\/[^\\/]+$/, // /agents/{agent_id}\n /^agents\\/[^\\/]+\\/stop$/, // /agents/{agent_id}/stop\n /^agents\\/[^\\/]+\\/workflow\\/code$/, // /agents/{agent_id}/workflow/code\n /^agents\\/start$/, // /agents/start\n\n // Anything endpoints\n /^anything\\/start$/, // /anything/start\n\n // Functions endpoints\n /^functions$/, // /functions\n /^functions\\/[^\\/]+$/, // /functions/{function_id}\n /^functions\\/[^\\/]+\\/fork$/, // /functions/{function_id}/fork\n /^functions\\/[^\\/]+\\/rollback$/, // /functions/{function_id}/rollback\n /^functions\\/[^\\/]+\\/runs$/, // /functions/{function_id}/runs\n /^functions\\/[^\\/]+\\/runs\\/[^\\/]+$/, // /functions/{function_id}/runs/{run_id}\n /^functions\\/[^\\/]+\\/runs\\/start$/, // /functions/{function_id}/runs/start\n /^functions\\/[^\\/]+\\/schedule$/, // /functions/{function_id}/schedule\n /^functions\\/health$/, // /functions/health\n\n // Mailboxes endpoints\n /^mailboxes$/, // /mailboxes\n /^mailboxes\\/[^\\/]+$/, // /mailboxes/{mailbox_id}\n /^mailboxes\\/connect-token$/, // /mailboxes/connect-token\n /^mailboxes\\/sync$/, // /mailboxes/sync\n\n // Managed-auth endpoints\n /^managed-auth\\/connect-links$/, // /managed-auth/connect-links\n /^managed-auth\\/connect-links\\/context$/, // /managed-auth/connect-links/context\n /^managed-auth\\/connect-links\\/mailboxes$/, // /managed-auth/connect-links/mailboxes\n /^managed-auth\\/connect-links\\/mailboxes\\/connect$/, // /managed-auth/connect-links/mailboxes/connect\n /^managed-auth\\/connect-links\\/mailboxes\\/sync$/, // /managed-auth/connect-links/mailboxes/sync\n /^managed-auth\\/connect-links\\/status$/, // /managed-auth/connect-links/status\n /^managed-auth\\/connect-links\\/submit$/, // /managed-auth/connect-links/submit\n /^managed-auth\\/connections\\/[^\\/]+\\/check$/, // /managed-auth/connections/{connection_id}/check\n /^managed-auth\\/connections\\/[^\\/]+\\/reauthenticate$/, // /managed-auth/connections/{connection_id}/reauthenticate\n /^managed-auth\\/connections\\/[^\\/]+\\/refresh$/, // /managed-auth/connections/{connection_id}/refresh\n /^managed-auth\\/operations\\/[^\\/]+$/, // /managed-auth/operations/{operation_id}\n\n // Payments endpoints\n /^payments\\/[^\\/]+$/, // /payments/{payment_id}\n /^payments\\/connect$/, // /payments/connect\n /^payments\\/disconnect$/, // /payments/disconnect\n\n // Personas endpoints\n /^personas$/, // /personas\n /^personas\\/[^\\/]+$/, // /personas/{persona_id}\n /^personas\\/[^\\/]+\\/emails$/, // /personas/{persona_id}/emails\n /^personas\\/[^\\/]+\\/sms$/, // /personas/{persona_id}/sms\n /^personas\\/create$/, // /personas/create\n\n // Profiles endpoints\n /^profiles$/, // /profiles\n /^profiles\\/[^\\/]+$/, // /profiles/{profile_id}\n /^profiles\\/[^\\/]+\\/cookies$/, // /profiles/{profile_id}/cookies\n /^profiles\\/[^\\/]+\\/duplicate$/, // /profiles/{profile_id}/duplicate\n /^profiles\\/create$/, // /profiles/create\n\n // Prompts endpoints\n /^prompts\\/improve$/, // /prompts/improve\n /^prompts\\/nudge$/, // /prompts/nudge\n\n // Ready endpoints\n /^ready$/, // /ready\n\n // Root endpoints\n /^health$/, // /health\n /^scrape$/, // /scrape\n /^scrape_from_html$/, // /scrape_from_html\n\n // Search endpoints\n /^search$/, // /search\n\n // Secrets endpoints\n /^secrets$/, // /secrets\n /^secrets\\/[^\\/]+$/, // /secrets/{name}\n /^secrets\\/[^\\/]+$/, // /secrets/{secret_id}\n\n // Sessions endpoints\n /^sessions$/, // /sessions\n /^sessions\\/[^\\/]+$/, // /sessions/{session_id}\n /^sessions\\/[^\\/]+\\/auth$/, // /sessions/{session_id}/auth\n /^sessions\\/[^\\/]+\\/cookies$/, // /sessions/{session_id}/cookies\n /^sessions\\/[^\\/]+\\/debug$/, // /sessions/{session_id}/debug\n /^sessions\\/[^\\/]+\\/files$/, // /sessions/{session_id}/files\n /^sessions\\/[^\\/]+\\/files\\/[^\\/]+$/, // /sessions/{session_id}/files/{file_id}\n /^sessions\\/[^\\/]+\\/network\\/logs$/, // /sessions/{session_id}/network/logs\n /^sessions\\/[^\\/]+\\/offset$/, // /sessions/{session_id}/offset\n /^sessions\\/[^\\/]+\\/page\\/execute$/, // /sessions/{session_id}/page/execute\n /^sessions\\/[^\\/]+\\/page\\/observe$/, // /sessions/{session_id}/page/observe\n /^sessions\\/[^\\/]+\\/page\\/scrape$/, // /sessions/{session_id}/page/scrape\n /^sessions\\/[^\\/]+\\/page\\/screenshot$/, // /sessions/{session_id}/page/screenshot\n /^sessions\\/[^\\/]+\\/payments$/, // /sessions/{session_id}/payments\n /^sessions\\/[^\\/]+\\/profile-preview$/, // /sessions/{session_id}/profile-preview\n /^sessions\\/[^\\/]+\\/replay$/, // /sessions/{session_id}/replay\n /^sessions\\/[^\\/]+\\/stop$/, // /sessions/{session_id}/stop\n /^sessions\\/[^\\/]+\\/workflow\\/code$/, // /sessions/{session_id}/workflow/code\n /^sessions\\/start$/, // /sessions/start\n\n // Usage endpoints\n /^usage$/, // /usage\n /^usage\\/logs$/, // /usage/logs\n\n // Vaults endpoints\n /^vaults$/, // /vaults\n /^vaults\\/[^\\/]+$/, // /vaults/{vault_id}\n /^vaults\\/[^\\/]+\\/card$/, // /vaults/{vault_id}/card\n /^vaults\\/[^\\/]+\\/credentials$/, // /vaults/{vault_id}/credentials\n /^vaults\\/create$/, // /vaults/create\n];\n\nexport interface PathValidationResult {\n isValid: boolean;\n error?: string;\n}\n\n/**\n * Validates a request path against a list of allowed patterns.\n * Prevents directory traversal and SSRF attacks.\n */\nexport function validatePath(\n pathSegments: string[],\n allowedPatterns: RegExp[],\n): PathValidationResult {\n const path = pathSegments.join('/');\n\n // Check for directory traversal attempts\n if (path.includes('..') || path.includes('//') || path.startsWith('/')) {\n return {\n isValid: false,\n error: 'Invalid path: directory traversal detected',\n };\n }\n\n // Check against allowed patterns\n const isValidPattern = allowedPatterns.some((pattern) => pattern.test(path));\n if (!isValidPattern) {\n return {\n isValid: false,\n error: `Invalid path: ${path} does not match any allowed endpoint pattern`,\n };\n }\n\n return { isValid: true };\n}\n","/**\n * Error class for authentication/authorization failures in the proxy.\n * Throw this from `authenticate()` to return a 401 response.\n *\n * @example\n * ```typescript\n * authenticate: async (request) => {\n * const session = await getSession(request);\n * if (!session) throw new NotteProxyAuthError('Not logged in');\n * }\n * ```\n */\nexport class NotteProxyAuthError extends Error {\n constructor(message = 'Unauthorized') {\n super(message);\n this.name = 'NotteProxyAuthError';\n }\n}\n\n/**\n * Configuration for the Notte API proxy.\n *\n * The proxy forwards incoming HTTP requests to the Notte API,\n * injecting authentication headers server-side so the API key\n * is never exposed to the client.\n */\nexport interface NotteProxyConfig {\n /**\n * The Notte API key to use for all forwarded requests.\n * Falls back to the NOTTE_API_KEY environment variable when omitted.\n * Can be overridden per-request by returning a string from `authenticate`.\n */\n apiKey?: string;\n\n /**\n * Base URL of the Notte API.\n * @default 'https://api.notte.cc'\n */\n apiUrl?: string;\n\n /**\n * Authenticate and authorize incoming requests. Missing callbacks fail closed (401).\n * Check resource ownership as well as caller identity. With a shared key, every\n * authorized caller otherwise has access to the same account resources.\n *\n * - Throw a `NotteProxyAuthError` to reject the request (returns 401).\n * - Return `void` to allow the request through using the default `apiKey`.\n * - Return a `string` to override the API key for this specific request\n * (useful for per-user API keys).\n */\n authenticate?: (request: Request) => Promise<void | string>;\n\n /**\n * Allowed API endpoint patterns for path validation (SSRF prevention).\n *\n * - `undefined` (default): uses the built-in allowlist derived from the OpenAPI spec.\n * - `RegExp[]`: custom list of allowed patterns.\n * - `false`: disables path validation entirely (not recommended for public-facing proxies).\n */\n allowedPatterns?: RegExp[] | false;\n\n /**\n * Value for the `x-notte-request-origin` header sent to the Notte API.\n * @default 'sdk-proxy'\n */\n requestOrigin?: string;\n\n /**\n * List of header names to forward from the incoming request to the Notte API.\n * @default ['content-type', 'accept']\n */\n forwardHeaders?: string[];\n\n /**\n * Optional hook called just before the request is forwarded to the Notte API.\n * Use this to modify outgoing headers, log requests, etc.\n */\n onBeforeRequest?: (ctx: {\n path: string;\n method: string;\n headers: Headers;\n url: string;\n incomingRequest: Request;\n }) => Promise<void> | void;\n}\n","import { validatePath, DEFAULT_ALLOWED_PATTERNS } from './patterns';\nimport type { NotteProxyConfig } from './types';\nimport { NotteProxyAuthError } from './types';\n\nconst DEFAULT_API_URL = 'https://api.notte.cc';\nconst DEFAULT_FORWARD_HEADERS = ['content-type', 'accept'];\nconst METHODS_WITH_BODY = ['POST', 'PUT', 'PATCH'];\n\n/**\n * Framework-agnostic proxy handler that forwards requests to the Notte API.\n *\n * Takes a standard Web API `Request`, injects authentication, and returns\n * a standard Web API `Response`. Works with any runtime that supports\n * the Web API standards (Node 18+, Deno, Bun, Cloudflare Workers).\n *\n * @param request - The incoming HTTP request (standard Web API Request)\n * @param pathSegments - The path segments after the proxy base path (e.g., ['sessions', 'start'])\n * @param config - Proxy configuration including API key, auth hooks, etc.\n * @returns A standard Web API Response\n */\nexport async function handleProxyRequest(\n request: Request,\n pathSegments: string[],\n config: NotteProxyConfig,\n): Promise<Response> {\n try {\n // Step 1: Path validation\n if (config.allowedPatterns !== false) {\n const patterns = config.allowedPatterns || DEFAULT_ALLOWED_PATTERNS;\n const pathValidation = validatePath(pathSegments, patterns);\n\n if (!pathValidation.isValid) {\n return new Response(\n JSON.stringify({\n error: 'Invalid API endpoint',\n details: pathValidation.error,\n }),\n {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n }\n\n // Step 2: Authentication\n if (typeof config.authenticate !== 'function') {\n throw new NotteProxyAuthError('Proxy caller authentication is required');\n }\n let apiKey = config.apiKey || process.env.NOTTE_API_KEY;\n\n if (config.authenticate) {\n const result = await config.authenticate(request);\n if (typeof result === 'string') {\n apiKey = result;\n }\n }\n\n if (!apiKey) {\n return new Response(\n JSON.stringify({ error: 'No API key configured' }),\n {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Step 3: Build target URL\n const apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\\/$/, '');\n const path = pathSegments.join('/');\n const incomingUrl = new URL(request.url);\n const searchParams = incomingUrl.searchParams.toString();\n const targetUrl = `${apiUrl}/${path}${searchParams ? `?${searchParams}` : ''}`;\n\n // Step 4: Build headers\n const forwardHeaders = new Headers();\n forwardHeaders.set('Authorization', `Bearer ${apiKey}`);\n // Function run endpoints authenticate with their own header (the API does\n // not forward `Authorization` to the runtime), so inject it as well.\n forwardHeaders.set('x-notte-api-key', apiKey);\n forwardHeaders.set(\n 'x-notte-request-origin',\n config.requestOrigin || 'sdk-proxy',\n );\n\n const headersToForward =\n config.forwardHeaders || DEFAULT_FORWARD_HEADERS;\n for (const header of headersToForward) {\n const value = request.headers.get(header);\n if (value) {\n forwardHeaders.set(header, value);\n }\n }\n\n // Step 5: onBeforeRequest hook\n if (config.onBeforeRequest) {\n await config.onBeforeRequest({\n path,\n method: request.method,\n headers: forwardHeaders,\n url: targetUrl,\n incomingRequest: request,\n });\n }\n\n // Step 6: Forward the request\n const requestOptions: RequestInit = {\n method: request.method,\n headers: forwardHeaders,\n signal: request.signal,\n };\n\n if (METHODS_WITH_BODY.includes(request.method) && request.body) {\n requestOptions.body = request.body;\n (requestOptions as any).duplex = 'half';\n }\n\n let response: globalThis.Response;\n try {\n response = await fetch(targetUrl, requestOptions);\n } catch (fetchError) {\n const errorMessage =\n fetchError instanceof Error\n ? fetchError.message\n : 'Unknown fetch error';\n return new Response(\n JSON.stringify({\n error: 'Failed to forward request to Notte API',\n details: errorMessage,\n }),\n {\n status: 502,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Step 7: Handle response\n const contentType = response.headers.get('content-type') || '';\n\n const isBinaryResponse =\n contentType.startsWith('image/') ||\n contentType.startsWith('video/') ||\n contentType.startsWith('audio/') ||\n contentType.includes('octet-stream');\n\n const isStreamingResponse = contentType.includes('text/event-stream');\n\n // For streaming responses, pass through the body with appropriate headers\n if (isStreamingResponse && response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n }\n\n // For all other responses with a body stream, pass it through directly\n if (response.body) {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: {\n 'Content-Type': contentType,\n },\n });\n }\n\n // Fallback for responses without a body stream: buffer appropriately\n if (isBinaryResponse) {\n const data = await response.arrayBuffer();\n return new Response(data, {\n status: response.status,\n statusText: response.statusText,\n headers: { 'Content-Type': contentType },\n });\n }\n\n // Fallback: buffer as text\n const data = await response.text();\n return new Response(data, {\n status: response.status,\n statusText: response.statusText,\n headers: { 'Content-Type': contentType },\n });\n } catch (error) {\n // NotteProxyAuthError from authenticate() → 401\n if (error instanceof NotteProxyAuthError) {\n return new Response(\n JSON.stringify({ error: error.message }),\n {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n\n // Re-throw unexpected errors so the adapter layer can handle them\n throw error;\n }\n}\n"],"mappings":";AAOO,IAAM,2BAAqC;AAAA;AAAA,EAEhD;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;A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","names":["data"]}
@@ -1,5 +1,5 @@
1
- import { a as NotteProxyConfig } from '../types-DmqqdEMP.mjs';
2
- export { N as NotteProxyAuthError } from '../types-DmqqdEMP.mjs';
1
+ import { a as NotteProxyConfig } from '../types-C5V9BOux.mjs';
2
+ export { N as NotteProxyAuthError } from '../types-C5V9BOux.mjs';
3
3
  export { handleProxyRequest } from './core.mjs';
4
4
 
5
5
  /**
@@ -39,22 +39,28 @@ type NextRouteHandler = (request: Request, context: {
39
39
  * @example
40
40
  * ```typescript
41
41
  * // app/api/notte/[...path]/route.ts
42
- * import { createNotteProxy } from '@notte/sdk/next';
42
+ * import { createNotteProxy, NotteProxyAuthError } from 'notte-sdk/next';
43
+ * import { getUser } from '@/lib/auth'; // Your server-side authentication implementation
43
44
  *
44
45
  * export const { GET, POST, PUT, DELETE, PATCH } = createNotteProxy({
45
- * apiKey: process.env.NOTTE_API_KEY!,
46
+ * authenticate: async (request) => {
47
+ * const user = await getUser(request);
48
+ * if (!user?.notteApiKey) throw new NotteProxyAuthError();
49
+ * return user.notteApiKey;
50
+ * },
46
51
  * });
47
52
  * ```
48
53
  *
49
54
  * @example With authentication
50
55
  * ```typescript
51
- * import { createNotteProxy, NotteProxyAuthError } from '@notte/sdk/next';
56
+ * import { createNotteProxy, NotteProxyAuthError } from 'notte-sdk/next';
52
57
  *
53
58
  * export const { GET, POST, PUT, DELETE, PATCH } = createNotteProxy({
54
59
  * apiKey: process.env.NOTTE_API_KEY!,
55
60
  * authenticate: async (request) => {
56
61
  * const session = await getSession(request);
57
62
  * if (!session) throw new NotteProxyAuthError('Not logged in');
63
+ * await authorizeNotteRequest(session, request); // Enforce resource ownership
58
64
  * },
59
65
  * });
60
66
  * ```
@@ -62,10 +68,9 @@ type NextRouteHandler = (request: Request, context: {
62
68
  * @example With per-user API keys
63
69
  * ```typescript
64
70
  * export const { GET, POST, PUT, DELETE, PATCH } = createNotteProxy({
65
- * apiKey: 'fallback-key', // pragma: allowlist secret
66
71
  * authenticate: async (request) => {
67
72
  * const user = await getUser(request);
68
- * if (!user) throw new NotteProxyAuthError();
73
+ * if (!user?.notteApiKey) throw new NotteProxyAuthError();
69
74
  * return user.notteApiKey; // returned string overrides apiKey
70
75
  * },
71
76
  * });
@@ -1,5 +1,5 @@
1
- import { a as NotteProxyConfig } from '../types-DmqqdEMP.js';
2
- export { N as NotteProxyAuthError } from '../types-DmqqdEMP.js';
1
+ import { a as NotteProxyConfig } from '../types-C5V9BOux.js';
2
+ export { N as NotteProxyAuthError } from '../types-C5V9BOux.js';
3
3
  export { handleProxyRequest } from './core.js';
4
4
 
5
5
  /**
@@ -39,22 +39,28 @@ type NextRouteHandler = (request: Request, context: {
39
39
  * @example
40
40
  * ```typescript
41
41
  * // app/api/notte/[...path]/route.ts
42
- * import { createNotteProxy } from '@notte/sdk/next';
42
+ * import { createNotteProxy, NotteProxyAuthError } from 'notte-sdk/next';
43
+ * import { getUser } from '@/lib/auth'; // Your server-side authentication implementation
43
44
  *
44
45
  * export const { GET, POST, PUT, DELETE, PATCH } = createNotteProxy({
45
- * apiKey: process.env.NOTTE_API_KEY!,
46
+ * authenticate: async (request) => {
47
+ * const user = await getUser(request);
48
+ * if (!user?.notteApiKey) throw new NotteProxyAuthError();
49
+ * return user.notteApiKey;
50
+ * },
46
51
  * });
47
52
  * ```
48
53
  *
49
54
  * @example With authentication
50
55
  * ```typescript
51
- * import { createNotteProxy, NotteProxyAuthError } from '@notte/sdk/next';
56
+ * import { createNotteProxy, NotteProxyAuthError } from 'notte-sdk/next';
52
57
  *
53
58
  * export const { GET, POST, PUT, DELETE, PATCH } = createNotteProxy({
54
59
  * apiKey: process.env.NOTTE_API_KEY!,
55
60
  * authenticate: async (request) => {
56
61
  * const session = await getSession(request);
57
62
  * if (!session) throw new NotteProxyAuthError('Not logged in');
63
+ * await authorizeNotteRequest(session, request); // Enforce resource ownership
58
64
  * },
59
65
  * });
60
66
  * ```
@@ -62,10 +68,9 @@ type NextRouteHandler = (request: Request, context: {
62
68
  * @example With per-user API keys
63
69
  * ```typescript
64
70
  * export const { GET, POST, PUT, DELETE, PATCH } = createNotteProxy({
65
- * apiKey: 'fallback-key', // pragma: allowlist secret
66
71
  * authenticate: async (request) => {
67
72
  * const user = await getUser(request);
68
- * if (!user) throw new NotteProxyAuthError();
73
+ * if (!user?.notteApiKey) throw new NotteProxyAuthError();
69
74
  * return user.notteApiKey; // returned string overrides apiKey
70
75
  * },
71
76
  * });
@@ -87,6 +87,21 @@ var DEFAULT_ALLOWED_PATTERNS = [
87
87
  // /managed-auth/connect-links/status
88
88
  /^managed-auth\/connect-links\/submit$/,
89
89
  // /managed-auth/connect-links/submit
90
+ /^managed-auth\/connections\/[^\/]+\/check$/,
91
+ // /managed-auth/connections/{connection_id}/check
92
+ /^managed-auth\/connections\/[^\/]+\/reauthenticate$/,
93
+ // /managed-auth/connections/{connection_id}/reauthenticate
94
+ /^managed-auth\/connections\/[^\/]+\/refresh$/,
95
+ // /managed-auth/connections/{connection_id}/refresh
96
+ /^managed-auth\/operations\/[^\/]+$/,
97
+ // /managed-auth/operations/{operation_id}
98
+ // Payments endpoints
99
+ /^payments\/[^\/]+$/,
100
+ // /payments/{payment_id}
101
+ /^payments\/connect$/,
102
+ // /payments/connect
103
+ /^payments\/disconnect$/,
104
+ // /payments/disconnect
90
105
  // Personas endpoints
91
106
  /^personas$/,
92
107
  // /personas
@@ -114,9 +129,6 @@ var DEFAULT_ALLOWED_PATTERNS = [
114
129
  // /prompts/improve
115
130
  /^prompts\/nudge$/,
116
131
  // /prompts/nudge
117
- // Proxies endpoints
118
- /^proxies\/gateway\/credentials$/,
119
- // /proxies/gateway/credentials
120
132
  // Ready endpoints
121
133
  /^ready$/,
122
134
  // /ready
@@ -142,6 +154,8 @@ var DEFAULT_ALLOWED_PATTERNS = [
142
154
  // /sessions
143
155
  /^sessions\/[^\/]+$/,
144
156
  // /sessions/{session_id}
157
+ /^sessions\/[^\/]+\/auth$/,
158
+ // /sessions/{session_id}/auth
145
159
  /^sessions\/[^\/]+\/cookies$/,
146
160
  // /sessions/{session_id}/cookies
147
161
  /^sessions\/[^\/]+\/debug$/,
@@ -162,6 +176,10 @@ var DEFAULT_ALLOWED_PATTERNS = [
162
176
  // /sessions/{session_id}/page/scrape
163
177
  /^sessions\/[^\/]+\/page\/screenshot$/,
164
178
  // /sessions/{session_id}/page/screenshot
179
+ /^sessions\/[^\/]+\/payments$/,
180
+ // /sessions/{session_id}/payments
181
+ /^sessions\/[^\/]+\/profile-preview$/,
182
+ // /sessions/{session_id}/profile-preview
165
183
  /^sessions\/[^\/]+\/replay$/,
166
184
  // /sessions/{session_id}/replay
167
185
  /^sessions\/[^\/]+\/stop$/,
@@ -235,6 +253,9 @@ async function handleProxyRequest(request, pathSegments, config) {
235
253
  );
236
254
  }
237
255
  }
256
+ if (typeof config.authenticate !== "function") {
257
+ throw new NotteProxyAuthError("Proxy caller authentication is required");
258
+ }
238
259
  let apiKey = config.apiKey || process.env.NOTTE_API_KEY;
239
260
  if (config.authenticate) {
240
261
  const result = await config.authenticate(request);
@@ -258,6 +279,7 @@ async function handleProxyRequest(request, pathSegments, config) {
258
279
  const targetUrl = `${apiUrl}/${path}${searchParams ? `?${searchParams}` : ""}`;
259
280
  const forwardHeaders = new Headers();
260
281
  forwardHeaders.set("Authorization", `Bearer ${apiKey}`);
282
+ forwardHeaders.set("x-notte-api-key", apiKey);
261
283
  forwardHeaders.set(
262
284
  "x-notte-request-origin",
263
285
  config.requestOrigin || "sdk-proxy"
@@ -280,7 +302,8 @@ async function handleProxyRequest(request, pathSegments, config) {
280
302
  }
281
303
  const requestOptions = {
282
304
  method: request.method,
283
- headers: forwardHeaders
305
+ headers: forwardHeaders,
306
+ signal: request.signal
284
307
  };
285
308
  if (METHODS_WITH_BODY.includes(request.method) && request.body) {
286
309
  requestOptions.body = request.body;