avatar endpoints

This commit is contained in:
Devin Zuczek
2026-06-30 18:52:37 -04:00
parent 1c89350906
commit 3a3f96bba6
11 changed files with 3213 additions and 533 deletions
+2 -1
View File
@@ -10,10 +10,11 @@
* and keep these helpers in sync.
*/
/** Schema DDL (mirror of migrations/0001_accounts.sql, sans the seed INSERTs). */
/** Schema DDL (mirror of migrations 0001_accounts + 0002_avatar, sans seed INSERTs). */
export const SCHEMA_DDL: string[] = [
`CREATE TABLE IF NOT EXISTS accounts (
data TEXT NOT NULL,
avatar TEXT,
account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.AccountId')) VIRTUAL,
username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.Username'))) VIRTUAL
)`,
+4 -41
View File
@@ -4,12 +4,10 @@ import { useWorkersLogger } from 'workers-tagged-logger'
import { withNotFound, withOnError } from '@repo/hono-helpers'
import apiConfigV2 from '../static/api-config-v2.json'
import defaultAvatar from '../static/default-avatar.json'
import gameConfigsV1All from '../static/gameconfigs-v1-all.json'
import storefrontGiftDrop2 from '../static/storefronts-v3-giftdropstore-2.json'
import storefrontGiftDrop3 from '../static/storefronts-v3-giftdropstore-3.json'
import storefrontGiftDrop300 from '../static/storefronts-v3-giftdropstore-300.json'
import { DEFAULT_AVATAR_ITEMS } from './default-avatar-items'
import { defaultSettings } from './default-settings'
import { validateAndGetAccountId } from './jwt'
import { getRoomById, getRoomByName, getRoomsByCreator, getRoomsByIds } from './rooms-db'
@@ -229,45 +227,10 @@ const app = new Hono<App>({ strict: false })
return c.json([])
})
// ---- Avatar ---------------------------------------------------------------
.get('/api/avatar/v4/items', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
// Owned items would be concatenated here; none without a DB binding.
return c.json(DEFAULT_AVATAR_ITEMS)
})
.get('/api/avatar/v2', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
// TODO: load/create PlayerAvatar for `id`. Must return a populated outfit —
// the client NREs on an empty OutfitSelections — so serve a valid default.
return c.json(defaultAvatar)
})
.post('/api/avatar/v2/set', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
const update = await c.req.json<Record<string, unknown>>().catch(() => null)
if (update === null) return c.body(null, 400)
// TODO: persist; echo the accepted avatar back. Fall back to the valid
// default avatar fields when the client omits them.
return c.json({
OwnerAccountId: id,
OutfitSelections: update.OutfitSelections ?? defaultAvatar.OutfitSelections,
FaceFeatures: update.FaceFeatures ?? defaultAvatar.FaceFeatures,
SkinColor: update.SkinColor ?? defaultAvatar.SkinColor,
HairColor: update.HairColor ?? defaultAvatar.HairColor,
})
})
.get('/api/avatar/v3/saved', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
return c.json([]) // TODO: query SavedOutfits
})
.get('/api/avatar/v2/gifts', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
return c.json([]) // TODO: query pending ReceivedGifts
})
// ---- Avatar gifts ---------------------------------------------------------
// The avatar read endpoints (`v4/items`, `v2`, `v2/set`, `v3/saved`, `v2/gifts`)
// live in the `econ` worker, which the client calls on the econ host — not here.
// Only the gift generate/consume actions remain on this worker.
.post('/api/avatar/v2/gifts/generate', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
+2 -18
View File
@@ -4,7 +4,6 @@ import { beforeAll, describe, expect, test } from 'vitest'
import '../../api.app'
import { DEFAULT_AVATAR_ITEMS } from '../../default-avatar-items'
import type { Env } from '../../context'
@@ -246,26 +245,17 @@ describe('public endpoints', () => {
describe('auth-gated endpoints', () => {
test('401 without a bearer token', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v4/items`)
const res = await exports.default.fetch(`${ORIGIN}/api/settings/v2`)
expect(res.status).toBe(401)
})
test('401 with a garbage token', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v4/items`, {
const res = await exports.default.fetch(`${ORIGIN}/api/settings/v2`, {
headers: { Authorization: 'Bearer not-a-real-token' },
})
expect(res.status).toBe(401)
})
test('GET /api/avatar/v4/items returns default items with a valid token', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v4/items`, {
headers: await bearer(),
})
expect(res.status).toBe(200)
const items = (await res.json()) as unknown[]
expect(items).toHaveLength(DEFAULT_AVATAR_ITEMS.length)
})
test('GET /api/settings/v2 returns the default settings for the account', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/settings/v2`, {
headers: await bearer(),
@@ -276,12 +266,6 @@ describe('auth-gated endpoints', () => {
for (const s of settings) expect(s.PlayerId).toBe(42)
})
test('GET /api/avatar/v2 returns a default avatar', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v2`, { headers: await bearer() })
const body = (await res.json()) as { OutfitSelections: string }
expect(body.OutfitSelections.length).toBeGreaterThan(0)
})
test('GET /api/checklist/v1/current 401s without a token, returns [] with one', async () => {
const anon = await exports.default.fetch(`${ORIGIN}/api/checklist/v1/current`)
expect(anon.status).toBe(401)
+5
View File
@@ -0,0 +1,5 @@
-- Store the player's avatar (set via the econ worker's /api/avatar/v2/set). It's
-- an opaque JSON payload that isn't queried, so a single nullable TEXT column on
-- the account row suffices. Kept in sync with SCHEMA_DDL in src/accounts-db.ts.
ALTER TABLE accounts ADD COLUMN avatar TEXT;
+2 -1
View File
@@ -10,10 +10,11 @@
* and keep these helpers in sync.
*/
/** Schema DDL (mirror of migrations/0001_accounts.sql, sans the seed INSERTs). */
/** Schema DDL (mirror of migrations 0001_accounts + 0002_avatar, sans seed INSERTs). */
export const SCHEMA_DDL: string[] = [
`CREATE TABLE IF NOT EXISTS accounts (
data TEXT NOT NULL,
avatar TEXT,
account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.AccountId')) VIRTUAL,
username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.Username'))) VIRTUAL
)`,
+53
View File
@@ -0,0 +1,53 @@
/**
* Avatar storage on the shared `recflare` accounts table. The avatar is a single
* JSON payload the client sends/consumes and never queries on, so it lives in a
* dedicated nullable `avatar` TEXT column on the player's account row (added by
* the auth worker's migration 0002_avatar).
*
* The `auth` worker owns the accounts schema/migrations; econ only reads/writes
* the avatar column. SCHEMA_DDL mirrors the table so tests can build it without
* depending on the auth worker — keep it in sync with auth's accounts-db.ts.
*/
/** Schema DDL for tests — the accounts table including the avatar column. */
export const SCHEMA_DDL: string[] = [
`CREATE TABLE IF NOT EXISTS accounts (
data TEXT NOT NULL,
avatar TEXT,
account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.AccountId')) VIRTUAL,
username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.Username'))) VIRTUAL
)`,
`CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_account_id ON accounts (account_id)`,
]
/** The stored avatar payload — opaque JSON the client sets and reads back. */
export type Avatar = Record<string, unknown>
interface AvatarRow {
avatar: string | null
}
/** Read the player's stored avatar, or null when they have none yet. */
export async function getAvatar(db: D1Database, accountId: number): Promise<Avatar | null> {
const row = await db
.prepare('SELECT avatar FROM accounts WHERE account_id = ?1')
.bind(accountId)
.first<AvatarRow>()
return row?.avatar ? (JSON.parse(row.avatar) as Avatar) : null
}
/**
* Persist the player's avatar onto their account row. Returns false when no
* account row exists for the id (nothing was updated).
*/
export async function setAvatar(
db: D1Database,
accountId: number,
avatar: Avatar
): Promise<boolean> {
const { meta } = await db
.prepare('UPDATE accounts SET avatar = ?2 WHERE account_id = ?1')
.bind(accountId, JSON.stringify(avatar))
.run()
return meta.changes > 0
}
+2 -1
View File
@@ -2,7 +2,8 @@ import type { HonoApp } from '@repo/hono-helpers'
import type { SharedHonoEnv, SharedHonoVariables } from '@repo/hono-helpers/src/types'
export type Env = SharedHonoEnv & {
// add additional Bindings here
/** Shared `recflare` D1 (accounts table) — stores the player's avatar. */
DB: D1Database
}
/** Variables can be extended */
+28 -12
View File
@@ -8,6 +8,7 @@ import defaultAvatarItems from '../static/default-avatar-items.json'
import myProgress from '../static/my-progress.json'
import storefrontGiftDrop3 from '../static/storefronts-v3-giftdropstore-3.json'
import weeklyChallenge from '../static/weekly-challenge.json'
import { getAvatar, setAvatar } from './avatar-db'
import { validateAndGetAccountId } from './jwt'
import type { Context } from 'hono'
@@ -72,9 +73,8 @@ const app = new Hono<App>()
// Default-unlocked avatar items, served from the bundled static JSON.
.get('/api/avatar/v1/defaultunlocked', (c) => c.json(defaultAvatarItems))
// Default base avatar items. Reads the same source file as defaultunlocked,
// so it returns the identical catalog.
.get('/api/avatar/v1/defaultbaseavataritems', (c) => c.json(defaultAvatarItems))
// Default base avatar items — empty stub for now. No auth.
.get('/api/avatar/v1/defaultbaseavataritems', (c) => c.json([]))
// The player's avatar items — owned items concatenated with the default
// catalog. No DB binding yet, so owned is empty and this is just the catalog.
@@ -85,25 +85,41 @@ const app = new Hono<App>()
return c.json(defaultAvatarItems)
})
// The player's owned custom avatar items. No auth; returns `{ items: [] }`.
// The client downloads these when custom-item creation is
// The player's owned custom avatar items. [Authorize]; paginated. Empty stub for
// now (no DB binding). The client downloads these when custom-item creation is
// allowed; a 404 here surfaces as "Failed to download unlocked avatar items".
.get('/econ/customAvatarItems/v1/owned', (c) => c.json({ items: [] }))
.get('/econ/customAvatarItems/v1/owned', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
return c.json({ Results: [], TotalResults: 0 })
})
// The player's objectives progress. Serves a static JSON file verbatim with
// no auth — same default for everyone until there's a DB binding to track
// per-player progress.
.get('/api/objectives/v1/myprogress', (c) => c.json(myProgress))
// The player's avatar. No DB binding yet, so it always returns the default
// for a player with no PlayerAvatar row.
// The player's avatar, stored as a JSON blob on their account row. Falls back
// to the default outfit when they haven't saved one — the client's parser NREs
// on an empty OutfitSelections (real RecNet never returns one).
.get('/api/avatar/v2', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
// TODO: load/create the PlayerAvatar for `id` once a DB binding exists.
// Must return a populated outfit — the client's parser NREs on an empty
// OutfitSelections (real RecNet never returns one), so serve a valid default.
return c.json(defaultAvatar)
return c.json((await getAvatar(c.env.DB, id)) ?? defaultAvatar)
})
// Save the player's avatar. [Authorize]. Stores the posted JSON payload verbatim
// on the account row and echoes it back. 400 on a non-object body; 404 when the
// caller has no account row to attach it to.
.post('/api/avatar/v2/set', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
const avatar = (await c.req.json().catch(() => null)) as Record<string, unknown> | null
if (avatar === null || typeof avatar !== 'object' || Array.isArray(avatar)) {
return c.body(null, 400)
}
if (!(await setAvatar(c.env.DB, id, avatar))) return c.body(null, 404)
return c.json(avatar)
})
// NUX checklist — the client fetches this on the econ host during load. []
+76 -11
View File
@@ -1,10 +1,28 @@
import { env } from 'cloudflare:test'
import { exports } from 'cloudflare:workers'
import { describe, expect, test } from 'vitest'
import { beforeAll, describe, expect, test } from 'vitest'
import '../../econ.app'
import { SCHEMA_DDL } from '../../avatar-db'
import type { Env } from '../../context'
declare module 'cloudflare:test' {
interface ProvidedEnv extends Env {}
}
const ORIGIN = 'https://example.com'
// Build the accounts table and seed the test player (the default token's sub, 42)
// so avatar reads/writes have a row to attach to.
beforeAll(async () => {
for (const stmt of SCHEMA_DDL) await env.DB.prepare(stmt).run()
await env.DB.prepare('INSERT OR IGNORE INTO accounts (data) VALUES (?1)')
.bind(JSON.stringify({ AccountId: 42, Username: 'Tester', DisplayName: 'Tester' }))
.run()
})
// Mint a token the way the `auth` worker does, using the same dev secret.
const DEV_SECRET = 'dev-insecure-signing-key-change-me'
@@ -41,13 +59,10 @@ describe('econ endpoints', () => {
expect(body[0]).toHaveProperty('AvatarItemDesc')
})
test('GET /api/avatar/v1/defaultbaseavataritems returns the same catalog', async () => {
test('GET /api/avatar/v1/defaultbaseavataritems is an empty stub (no auth)', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v1/defaultbaseavataritems`)
expect(res.status).toBe(200)
const body = (await res.json()) as unknown[]
expect(Array.isArray(body)).toBe(true)
expect(body.length).toBeGreaterThan(0)
expect(body[0]).toHaveProperty('AvatarItemDesc')
expect(await res.json()).toEqual([])
})
test('GET /api/avatar/v4/items 401s without a token', async () => {
@@ -72,8 +87,11 @@ describe('econ endpoints', () => {
expect(res.status).toBe(401)
})
test('GET /api/avatar/v2 returns a populated default avatar with a valid token', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v2`, { headers: await bearer() })
test('GET /api/avatar/v2 returns a populated default avatar when none is saved', async () => {
// Account 7 has no saved avatar → falls back to the default outfit.
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v2`, {
headers: await bearer('7'),
})
expect(res.status).toBe(200)
const body = (await res.json()) as { OutfitSelections: string; FaceFeatures: string }
// Must be non-empty — the client's outfit parser NREs on an empty string.
@@ -82,10 +100,57 @@ describe('econ endpoints', () => {
expect(body.FaceFeatures).toContain('eyeId')
})
test('GET /econ/customAvatarItems/v1/owned returns { items: [] } (no auth)', async () => {
const res = await exports.default.fetch(`${ORIGIN}/econ/customAvatarItems/v1/owned`)
test('POST /api/avatar/v2/set 401s without a token', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v2/set`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ OutfitSelections: 'a,,0' }),
})
expect(res.status).toBe(401)
})
test('POST /api/avatar/v2/set saves the avatar, and GET reads it back', async () => {
const headers = { ...(await bearer()), 'Content-Type': 'application/json' }
const avatar = {
OutfitSelections: '1fd69ef8-0b74-4962-af5a-67f0bf0358f2,,0;d0a9262f-5504-46a7-bb10-7507503db58e,,1',
OutfitSelectionsV2: '{"selections":[]}',
FaceFeatures: '{"eyeId":"AjGMoJhEcEehacRZjUMuDg"}',
SkinColor: '3529b670-a66d-448e-9573-1905eae5b9bf',
HairColor: '0e_jaaObREWTf1AorAZ95g',
CustomAvatarItems: [],
}
// Save echoes the payload back.
const setRes = await exports.default.fetch(`${ORIGIN}/api/avatar/v2/set`, {
method: 'POST',
headers,
body: JSON.stringify(avatar),
})
expect(setRes.status).toBe(200)
expect(await setRes.json()).toEqual(avatar)
// And it persists — GET now returns the saved avatar, not the default.
const getRes = await exports.default.fetch(`${ORIGIN}/api/avatar/v2`, { headers: await bearer() })
expect(await getRes.json()).toEqual(avatar)
})
test('POST /api/avatar/v2/set 404s when the caller has no account row', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v2/set`, {
method: 'POST',
headers: { ...(await bearer('99999')), 'Content-Type': 'application/json' },
body: JSON.stringify({ OutfitSelections: 'a,,0' }),
})
expect(res.status).toBe(404)
})
test('GET /econ/customAvatarItems/v1/owned 401s without a token, returns an empty paginated stub', async () => {
const anon = await exports.default.fetch(`${ORIGIN}/econ/customAvatarItems/v1/owned`)
expect(anon.status).toBe(401)
const res = await exports.default.fetch(`${ORIGIN}/econ/customAvatarItems/v1/owned`, {
headers: await bearer(),
})
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ items: [] })
expect(await res.json()).toEqual({ Results: [], TotalResults: 0 })
})
test('GET /api/objectives/v1/myprogress returns the default progress (no auth)', async () => {
+3029 -448
View File
@@ -1,5 +1,5 @@
/* eslint-disable */
// Runtime types generated with workerd@1.20260317.1 2025-09-20 nodejs_compat
// Runtime types generated with workerd@1.20260625.1 2025-09-20 nodejs_compat
// Begin runtime types
/*! *****************************************************************************
Copyright (c) Cloudflare. All rights reserved.
@@ -421,8 +421,12 @@ interface ExecutionContext<Props = unknown> {
waitUntil(promise: Promise<any>): void;
passThroughOnException(): void;
readonly props: Props;
cache?: CacheContext;
readonly access?: CloudflareAccessContext;
tracing: Tracing;
}
type ExportedHandlerFetchHandler<Env = unknown, CfHostMetadata = unknown, Props = unknown> = (request: Request<CfHostMetadata, IncomingRequestCfProperties<CfHostMetadata>>, env: Env, ctx: ExecutionContext<Props>) => Response | Promise<Response>;
type ExportedHandlerConnectHandler<Env = unknown, Props = unknown> = (socket: Socket, env: Env, ctx: ExecutionContext<Props>) => void | Promise<void>;
type ExportedHandlerTailHandler<Env = unknown, Props = unknown> = (events: TraceItem[], env: Env, ctx: ExecutionContext<Props>) => void | Promise<void>;
type ExportedHandlerTraceHandler<Env = unknown, Props = unknown> = (traces: TraceItem[], env: Env, ctx: ExecutionContext<Props>) => void | Promise<void>;
type ExportedHandlerTailStreamHandler<Env = unknown, Props = unknown> = (event: TailStream.TailEvent<TailStream.Onset>, env: Env, ctx: ExecutionContext<Props>) => TailStream.TailEventHandlerType | Promise<TailStream.TailEventHandlerType>;
@@ -431,6 +435,7 @@ type ExportedHandlerQueueHandler<Env = unknown, Message = unknown, Props = unkno
type ExportedHandlerTestHandler<Env = unknown, Props = unknown> = (controller: TestController, env: Env, ctx: ExecutionContext<Props>) => void | Promise<void>;
interface ExportedHandler<Env = unknown, QueueHandlerMessage = unknown, CfHostMetadata = unknown, Props = unknown> {
fetch?: ExportedHandlerFetchHandler<Env, CfHostMetadata, Props>;
connect?: ExportedHandlerConnectHandler<Env, Props>;
tail?: ExportedHandlerTailHandler<Env, Props>;
trace?: ExportedHandlerTraceHandler<Env, Props>;
tailStream?: ExportedHandlerTailStreamHandler<Env, Props>;
@@ -446,24 +451,50 @@ declare abstract class Navigator {
sendBeacon(url: string, body?: BodyInit): boolean;
readonly userAgent: string;
readonly hardwareConcurrency: number;
readonly platform: string;
readonly language: string;
readonly languages: string[];
}
interface AlarmInvocationInfo {
readonly isRetry: boolean;
readonly retryCount: number;
readonly scheduledTime: number;
}
interface Cloudflare {
readonly compatibilityFlags: Record<string, boolean>;
}
interface CachePurgeError {
code: number;
message: string;
}
interface CachePurgeResult {
success: boolean;
errors: CachePurgeError[];
}
interface CachePurgeOptions {
tags?: string[];
pathPrefixes?: string[];
purgeEverything?: boolean;
}
interface CacheContext {
purge(options: CachePurgeOptions): Promise<CachePurgeResult>;
}
interface CloudflareAccessContext {
readonly aud: string;
getIdentity(): Promise<CloudflareAccessIdentity | undefined>;
}
declare abstract class ColoLocalActorNamespace {
get(actorId: string): Fetcher;
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
connect?(socket: Socket): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise<void>;
webSocketClose?(ws: WebSocket, code: number, reason: string, wasClean: boolean): void | Promise<void>;
webSocketError?(ws: WebSocket, error: unknown): void | Promise<void>;
}
type DurableObjectStub<T extends Rpc.DurableObjectBranded | undefined = undefined> = Fetcher<T, "alarm" | "webSocketMessage" | "webSocketClose" | "webSocketError"> & {
type DurableObjectStub<T extends Rpc.DurableObjectBranded | undefined = undefined> = Fetcher<T, "alarm" | "connect" | "webSocketMessage" | "webSocketClose" | "webSocketError"> & {
readonly id: DurableObjectId;
readonly name?: string;
};
@@ -471,6 +502,7 @@ interface DurableObjectId {
toString(): string;
equals(other: DurableObjectId): boolean;
readonly name?: string;
readonly jurisdiction?: string;
}
declare abstract class DurableObjectNamespace<T extends Rpc.DurableObjectBranded | undefined = undefined> {
newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions): DurableObjectId;
@@ -484,7 +516,7 @@ type DurableObjectJurisdiction = "eu" | "fedramp" | "fedramp-high";
interface DurableObjectNamespaceNewUniqueIdOptions {
jurisdiction?: DurableObjectJurisdiction;
}
type DurableObjectLocationHint = "wnam" | "enam" | "sam" | "weur" | "eeur" | "apac" | "oc" | "afr" | "me";
type DurableObjectLocationHint = "wnam" | "enam" | "sam" | "weur" | "eeur" | "apac" | "apac-ne" | "apac-se" | "oc" | "afr" | "me";
type DurableObjectRoutingMode = "primary-only";
interface DurableObjectNamespaceGetDurableObjectOptions {
locationHint?: DurableObjectLocationHint;
@@ -498,6 +530,7 @@ interface DurableObjectState<Props = unknown> {
readonly id: DurableObjectId;
readonly storage: DurableObjectStorage;
container?: Container;
facets: DurableObjectFacets;
blockConcurrencyWhile<T>(callback: () => Promise<T>): Promise<T>;
acceptWebSocket(ws: WebSocket, tags?: string[]): void;
getWebSockets(tag?: string): WebSocket[];
@@ -574,6 +607,16 @@ declare class WebSocketRequestResponsePair {
get request(): string;
get response(): string;
}
interface DurableObjectFacets {
get<T extends Rpc.DurableObjectBranded | undefined = undefined>(name: string, getStartupOptions: () => FacetStartupOptions<T> | Promise<FacetStartupOptions<T>>): Fetcher<T>;
abort(name: string, reason: any): void;
delete(name: string): void;
clone(src: string, dst: string): void;
}
interface FacetStartupOptions<T extends Rpc.DurableObjectBranded | undefined = undefined> {
id?: DurableObjectId | string;
class: DurableObjectClass<T>;
}
interface AnalyticsEngineDataset {
writeDataPoint(event?: AnalyticsEngineDataPoint): void;
}
@@ -866,7 +909,7 @@ interface CustomEventCustomEventInit {
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob)
*/
declare class Blob {
constructor(type?: ((ArrayBuffer | ArrayBufferView) | string | Blob)[], options?: BlobOptions);
constructor(bits?: ((ArrayBuffer | ArrayBufferView) | string | Blob)[], options?: BlobOptions);
/**
* The **`size`** read-only property of the Blob interface returns the size of the Blob or File in bytes.
*
@@ -1862,8 +1905,31 @@ interface KVNamespaceGetWithMetadataResult<Value, Metadata> {
}
type QueueContentType = "text" | "bytes" | "json" | "v8";
interface Queue<Body = unknown> {
send(message: Body, options?: QueueSendOptions): Promise<void>;
sendBatch(messages: Iterable<MessageSendRequest<Body>>, options?: QueueSendBatchOptions): Promise<void>;
metrics(): Promise<QueueMetrics>;
send(message: Body, options?: QueueSendOptions): Promise<QueueSendResponse>;
sendBatch(messages: Iterable<MessageSendRequest<Body>>, options?: QueueSendBatchOptions): Promise<QueueSendBatchResponse>;
}
interface QueueSendMetrics {
backlogCount: number;
backlogBytes: number;
oldestMessageTimestamp?: Date;
}
interface QueueSendMetadata {
metrics: QueueSendMetrics;
}
interface QueueSendResponse {
metadata: QueueSendMetadata;
}
interface QueueSendBatchMetrics {
backlogCount: number;
backlogBytes: number;
oldestMessageTimestamp?: Date;
}
interface QueueSendBatchMetadata {
metrics: QueueSendBatchMetrics;
}
interface QueueSendBatchResponse {
metadata: QueueSendBatchMetadata;
}
interface QueueSendOptions {
contentType?: QueueContentType;
@@ -1877,6 +1943,19 @@ interface MessageSendRequest<Body = unknown> {
contentType?: QueueContentType;
delaySeconds?: number;
}
interface QueueMetrics {
backlogCount: number;
backlogBytes: number;
oldestMessageTimestamp?: Date;
}
interface MessageBatchMetrics {
backlogCount: number;
backlogBytes: number;
oldestMessageTimestamp?: Date;
}
interface MessageBatchMetadata {
metrics: MessageBatchMetrics;
}
interface QueueRetryOptions {
delaySeconds?: number;
}
@@ -1891,12 +1970,14 @@ interface Message<Body = unknown> {
interface QueueEvent<Body = unknown> extends ExtendableEvent {
readonly messages: readonly Message<Body>[];
readonly queue: string;
readonly metadata: MessageBatchMetadata;
retryAll(options?: QueueRetryOptions): void;
ackAll(): void;
}
interface MessageBatch<Body = unknown> {
readonly messages: readonly Message<Body>[];
readonly queue: string;
readonly metadata: MessageBatchMetadata;
retryAll(options?: QueueRetryOptions): void;
ackAll(): void;
}
@@ -1915,7 +1996,7 @@ interface R2ListOptions {
startAfter?: string;
include?: ("httpMetadata" | "customMetadata")[];
}
declare abstract class R2Bucket {
interface R2Bucket {
head(key: string): Promise<R2Object | null>;
get(key: string, options: R2GetOptions & {
onlyIf: R2Conditional | Headers;
@@ -2580,6 +2661,11 @@ interface QueuingStrategyInit {
*/
highWaterMark: number;
}
interface TracePreviewInfo {
id: string;
slug: string;
name: string;
}
interface ScriptVersion {
id?: string;
tag?: string;
@@ -2590,7 +2676,7 @@ declare abstract class TailEvent extends ExtendableEvent {
readonly traces: TraceItem[];
}
interface TraceItem {
readonly event: (TraceItemFetchEventInfo | TraceItemJsRpcEventInfo | TraceItemScheduledEventInfo | TraceItemAlarmEventInfo | TraceItemQueueEventInfo | TraceItemEmailEventInfo | TraceItemTailEventInfo | TraceItemCustomEventInfo | TraceItemHibernatableWebSocketEventInfo) | null;
readonly event: (TraceItemFetchEventInfo | TraceItemJsRpcEventInfo | TraceItemConnectEventInfo | TraceItemScheduledEventInfo | TraceItemAlarmEventInfo | TraceItemQueueEventInfo | TraceItemEmailEventInfo | TraceItemTailEventInfo | TraceItemCustomEventInfo | TraceItemHibernatableWebSocketEventInfo) | null;
readonly eventTimestamp: number | null;
readonly logs: TraceLog[];
readonly exceptions: TraceException[];
@@ -2600,6 +2686,8 @@ interface TraceItem {
readonly scriptVersion?: ScriptVersion;
readonly dispatchNamespace?: string;
readonly scriptTags?: string[];
readonly tailAttributes?: Record<string, boolean | number | string>;
readonly preview?: TracePreviewInfo;
readonly durableObjectId?: string;
readonly outcome: string;
readonly executionModel: string;
@@ -2610,6 +2698,8 @@ interface TraceItem {
interface TraceItemAlarmEventInfo {
readonly scheduledTime: Date;
}
interface TraceItemConnectEventInfo {
}
interface TraceItemCustomEventInfo {
}
interface TraceItemScheduledEventInfo {
@@ -3197,6 +3287,28 @@ interface EventSourceEventSourceInit {
withCredentials?: boolean;
fetcher?: Fetcher;
}
interface ExecOutput {
readonly stdout: ArrayBuffer;
readonly stderr: ArrayBuffer;
readonly exitCode: number;
}
interface ContainerExecOptions {
cwd?: string;
env?: Record<string, string>;
user?: string;
stdin?: ReadableStream | "pipe";
stdout?: "pipe" | "ignore";
stderr?: "pipe" | "ignore" | "combined";
}
interface ExecProcess {
readonly stdin: WritableStream | null;
readonly stdout: ReadableStream | null;
readonly stderr: ReadableStream | null;
readonly pid: number;
readonly exitCode: Promise<number>;
output(): Promise<ExecOutput>;
kill(signal?: number): void;
}
interface Container {
get running(): boolean;
start(options?: ContainerStartupOptions): void;
@@ -3207,12 +3319,40 @@ interface Container {
setInactivityTimeout(durationMs: number | bigint): Promise<void>;
interceptOutboundHttp(addr: string, binding: Fetcher): Promise<void>;
interceptAllOutboundHttp(binding: Fetcher): Promise<void>;
snapshotDirectory(options: ContainerDirectorySnapshotOptions): Promise<ContainerDirectorySnapshot>;
snapshotContainer(options: ContainerSnapshotOptions): Promise<ContainerSnapshot>;
interceptOutboundHttps(addr: string, binding: Fetcher): Promise<void>;
exec(cmd: string[], options?: ContainerExecOptions): Promise<ExecProcess>;
}
interface ContainerDirectorySnapshot {
id: string;
size: number;
dir: string;
name?: string;
}
interface ContainerDirectorySnapshotOptions {
dir: string;
name?: string;
}
interface ContainerDirectorySnapshotRestoreParams {
snapshot: ContainerDirectorySnapshot;
mountPoint?: string;
}
interface ContainerSnapshot {
id: string;
size: number;
name?: string;
}
interface ContainerSnapshotOptions {
name?: string;
}
interface ContainerStartupOptions {
entrypoint?: string[];
enableInternet: boolean;
env?: Record<string, string>;
hardTimeout?: (number | bigint);
labels?: Record<string, string>;
directorySnapshots?: ContainerDirectorySnapshotRestoreParams[];
containerSnapshot?: ContainerSnapshot;
}
/**
* The **`MessagePort`** interface of the Channel Messaging API represents one of the two ports of a MessageChannel, allowing messages to be sent from one port and listening out for them arriving at the other.
@@ -3275,6 +3415,10 @@ type LoopbackDurableObjectClass<T extends Rpc.DurableObjectBranded | undefined =
}) => DurableObjectClass<T> : (opts: {
props?: any;
}) => DurableObjectClass<T>);
interface LoopbackDurableObjectNamespace extends DurableObjectNamespace {
}
interface LoopbackColoLocalActorNamespace extends ColoLocalActorNamespace {
}
interface SyncKvStorage {
get<T = unknown>(key: string): T | undefined;
list<T = unknown>(options?: SyncKvListOptions): Iterable<[
@@ -3294,9 +3438,11 @@ interface SyncKvListOptions {
}
interface WorkerStub {
getEntrypoint<T extends Rpc.WorkerEntrypointBranded | undefined>(name?: string, options?: WorkerStubEntrypointOptions): Fetcher<T>;
getDurableObjectClass<T extends Rpc.DurableObjectBranded | undefined>(name?: string, options?: WorkerStubEntrypointOptions): DurableObjectClass<T>;
}
interface WorkerStubEntrypointOptions {
props?: any;
limits?: workerdResourceLimits;
}
interface WorkerLoader {
get(name: string | null, getCode: () => WorkerLoaderWorkerCode | Promise<WorkerLoaderWorkerCode>): WorkerStub;
@@ -3315,6 +3461,7 @@ interface WorkerLoaderWorkerCode {
compatibilityDate: string;
compatibilityFlags?: string[];
allowExperimental?: boolean;
limits?: workerdResourceLimits;
mainModule: string;
modules: Record<string, WorkerLoaderModule | string>;
env?: any;
@@ -3322,6 +3469,10 @@ interface WorkerLoaderWorkerCode {
tails?: Fetcher[];
streamingTails?: Fetcher[];
}
interface workerdResourceLimits {
cpuMs?: number;
subRequests?: number;
}
/**
* The Workers runtime supports a subset of the Performance API, used to measure timing and performance,
* as well as timing of subrequests and other operations.
@@ -3340,81 +3491,415 @@ declare abstract class Performance {
*/
toJSON(): object;
}
// AI Search V2 API Error Interfaces
interface Tracing {
enterSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T;
startActiveSpan<T, A extends unknown[]>(name: string, callback: (span: Span, ...args: A) => T, ...args: A): T;
Span: typeof Span;
}
declare abstract class Span {
get isTraced(): boolean;
setAttribute(key: string, value?: (boolean | number | string)): void;
end(): void;
}
/**
* Represents the identity of a user authenticated via Cloudflare Access.
* This matches the result of calling /cdn-cgi/access/get-identity.
*
* The exact structure of the returned object depends on the identity provider
* configuration for the Access application. The fields below represent commonly
* available properties, but additional provider-specific fields may be present.
*/
interface CloudflareAccessIdentity extends Record<string, unknown> {
/** The user's email address, if available from the identity provider. */
email?: string;
/** The user's display name. */
name?: string;
/** The user's unique identifier. */
user_uuid?: string;
/** The Cloudflare account ID. */
account_id?: string;
/** Login timestamp (Unix epoch seconds). */
iat?: number;
/** The user's IP address at authentication time. */
ip?: string;
/** Authentication methods used (e.g., "pwd"). */
amr?: string[];
/** Identity provider information. */
idp?: {
id: string;
type: string;
};
/** Geographic information about where the user authenticated. */
geo?: {
country: string;
};
/** Group memberships from the identity provider. */
groups?: Array<{
id: string;
name: string;
email?: string;
}>;
/** Device posture check results, keyed by check ID. */
devicePosture?: Record<string, unknown>;
/** True if the user connected via Cloudflare WARP. */
is_warp?: boolean;
/** True if the user is authenticated via Cloudflare Gateway. */
is_gateway?: boolean;
}
// ============================================================================
// Agent Memory
//
// Public type surface for user Workers binding to an Agent Memory namespace.
// ============================================================================
/** Memory type — every memory is classified into exactly one. */
type AgentMemoryMemoryType = "fact" | "event" | "instruction" | "task";
/** Search intensity for recall. */
type AgentMemoryThinkingLevel = "low" | "medium" | "high";
/** Response verbosity for recall. */
type AgentMemoryResponseLength = "short" | "medium" | "long";
/** A conversation message passed to ingest(). */
interface AgentMemoryMessage {
role: "system" | "user" | "assistant";
content: string;
/** Optional message timestamp. */
timestamp?: Date;
}
/** Raw memory content passed to remember(). */
interface AgentMemoryIncomingMemory {
/** Raw memory content. The service classifies and summarizes automatically. */
content: string;
/** Optional session identifier to associate with this memory. */
sessionId?: string | null | undefined;
}
/** A stored memory returned from remember(), get(), and delete(). */
interface AgentMemoryMemory {
/** Memory ID. */
id: string;
/** Memory type. */
type: AgentMemoryMemoryType;
/** Text summary. */
summary: string;
/** Memory text. */
content: string;
/** Session that created this memory. */
sessionId: string | null;
/** Memory creation time. */
createdAt: Date;
/** Memory last-update time. */
updatedAt: Date;
}
/** Single entry in a list() response. Same shape as Memory minus full content. */
type AgentMemoryMemoryListEntry = Omit<AgentMemoryMemory, "content">;
/** A scored memory candidate in a recall result. */
interface AgentMemoryScoredCandidate {
/** Candidate ID. */
id: string;
/** Text summary. */
summary: string;
/** Session that created this candidate, when known. */
sessionId: string | null;
/** Relevance score (higher is better). Comparable only within a single query. */
score: number;
}
/** Options for the ingest() method. */
interface AgentMemoryIngestOptions {
/** Session identifier to associate with memories created during ingestion. */
sessionId?: string | null | undefined;
}
/** Options for the getSummary() method. */
interface AgentMemoryGetSummaryOptions {
/** Session identifier to retrieve session summary for. */
sessionId?: string | null | undefined;
}
/** Response from the getSummary() method. */
interface AgentMemoryGetSummaryResponse {
/** Markdown summary. */
summary: string;
}
/**
* Options for the recall() method.
*
* `referenceDate` accepts a Date object, an ISO-8601 date string
* (YYYY-MM-DD), or a full ISO-8601 datetime string. When provided, this
* date is used as "today" for resolving relative time references
* ("how many days ago", "last week") instead of the server's wall-clock time.
*/
interface AgentMemoryRecallOptions {
/** Recall intensity: "low" (default), "medium", or "high". */
thinkingLevel?: AgentMemoryThinkingLevel;
/** Response verbosity: "short", "medium" (default), or "long". */
responseLength?: AgentMemoryResponseLength;
/** Temporal anchor for date arithmetic. */
referenceDate?: Date | string;
}
/** Response from the recall() method. */
interface AgentMemoryRecallResult {
/** Number of memories retrieved. */
count: number;
/** LLM-generated answer synthesizing the matching memories. */
answer: string;
/** Matching memories ranked by relevance. */
candidates: AgentMemoryScoredCandidate[];
}
/**
* Options for the list() method.
*
* `cursor` is the opaque continuation token returned by the previous page;
* pass it back unchanged to fetch the next page. `sessionId` and `type`
* are exact-match filters; combining them is allowed.
*/
interface AgentMemoryListMemoriesOptions {
/** Maximum number of memories to return. Default 20, max 500. */
limit?: number;
/** Opaque cursor from a previous page. */
cursor?: string;
/** Exact-match session filter. */
sessionId?: string;
/** Exact-match memory-type filter. */
type?: AgentMemoryMemoryType;
}
/** Response from the list() method. */
interface AgentMemoryListMemoriesResult {
memories: AgentMemoryMemoryListEntry[];
/** Continuation cursor; absent when this page exhausted the result set. */
cursor?: string;
}
/**
* A single Agent Memory profile, scoped to a profile name.
*
* Returned by {@link AgentMemoryNamespace.getProfile}.
*/
declare abstract class AgentMemoryProfile {
/**
* Retrieve a memory by ID.
*
* @param memoryId - ULID of the memory to retrieve.
* @throws if the memory does not exist.
*/
get(memoryId: string): Promise<AgentMemoryMemory>;
/**
* Delete a memory by ID.
*
* Removes the memory and any source messages linked by the memory's
* source message IDs.
*
* @param memoryId - ULID of the memory to delete.
* @throws if the memory does not exist.
*/
delete(memoryId: string): Promise<AgentMemoryMemory>;
/**
* Store a memory in this profile. The content is automatically classified,
* summarized, and indexed.
*
* @param memory - Raw memory content to persist.
*/
remember(memory: AgentMemoryIncomingMemory): Promise<AgentMemoryMemory>;
/**
* Extract memories from a conversation.
*
* @param messages - Conversation messages to extract memories from.
* @param options - Optional ingest options.
*/
ingest(messages: Iterable<AgentMemoryMessage>, options?: AgentMemoryIngestOptions): Promise<void>;
/**
* Get a profile summary.
*
* @param options - Optional getSummary options.
*/
getSummary(options?: AgentMemoryGetSummaryOptions): Promise<AgentMemoryGetSummaryResponse>;
/**
* Recall memories in this profile.
*
* @param query - Recall query matched against memory content and keywords.
* @param options - Optional recall parameters.
* @returns Matching memories with relevance scores and a synthesized answer.
*/
recall(query: string, options?: AgentMemoryRecallOptions): Promise<AgentMemoryRecallResult>;
/**
* List active memories in this profile.
*
* Returns a paginated, filterable view of stored memories. Superseded
* versions are excluded. Use the returned `cursor` (when present) to
* fetch the next page.
*
* @param options - Optional pagination and filter options.
*/
list(options?: AgentMemoryListMemoriesOptions): Promise<AgentMemoryListMemoriesResult>;
/**
* Soft-delete every memory and message in this profile that is tagged
* with `sessionId`.
*
* Idempotent: deleting a sessionId that has no rows is a no-op.
*
* @param sessionId - Session to delete.
*/
deleteSession(sessionId: string): Promise<void>;
}
/**
* Namespace-level Agent Memory binding.
*
* Used as the type of an `env.MEMORY`-style binding backed by the Agent
* Memory product.
*
* @example
* ```ts
* export default {
* async fetch(_request: Request, env: Env): Promise<Response> {
* const profile = await env.MEMORY.getProfile("wrangler-e2e");
* const summary = await profile.getSummary();
* return Response.json(summary);
* },
* };
* ```
*/
declare abstract class AgentMemoryNamespace {
/**
* Get a memory profile by name. Profiles are isolated by namespace and
* addressed by a compound key (namespaceId:profileName).
*
* @param profileName - Profile name (validated against naming rules).
* @returns RPC target for interacting with the profile.
*/
getProfile(profileName: string): Promise<AgentMemoryProfile>;
/**
* Soft-delete a profile and schedule deferred purge. Marks all
* memories and messages as deleted.
*
* @param profileName - Name of the profile to delete.
*/
deleteProfile(profileName: string): Promise<void>;
}
// ============ AI Search Error Interfaces ============
interface AiSearchInternalError extends Error {
}
interface AiSearchNotFoundError extends Error {
}
interface AiSearchNameNotSetError extends Error {
}
// AI Search V2 Request Types
type AiSearchSearchRequest = {
messages: Array<{
role: 'system' | 'developer' | 'user' | 'assistant' | 'tool';
content: string | null;
}>;
ai_search_options?: {
retrieval?: {
retrieval_type?: 'vector' | 'keyword' | 'hybrid';
/** Match threshold (0-1, default 0.4) */
match_threshold?: number;
/** Maximum number of results (1-50, default 10) */
max_num_results?: number;
filters?: VectorizeVectorMetadataFilter;
/** Context expansion (0-3, default 0) */
context_expansion?: number;
[key: string]: unknown;
};
query_rewrite?: {
enabled?: boolean;
model?: string;
rewrite_prompt?: string;
[key: string]: unknown;
};
reranking?: {
/** Enable reranking (default false) */
enabled?: boolean;
model?: '@cf/baai/bge-reranker-base' | '';
/** Match threshold (0-1, default 0.4) */
match_threshold?: number;
[key: string]: unknown;
};
// ============ AI Search Common Types ============
/** A single message in a conversation-style search or chat request. */
type AiSearchMessage = {
role: 'system' | 'developer' | 'user' | 'assistant' | 'tool';
content: string | null;
};
/**
* Common shape for `ai_search_options` used by both single-instance and multi-instance requests.
* Contains retrieval, query rewrite, reranking, and cache sub-options.
*/
type AiSearchOptions = {
retrieval?: {
/** Which retrieval backend to use. Defaults to the instance's configured index_method. */
retrieval_type?: 'vector' | 'keyword' | 'hybrid';
/** Fusion method for combining vector + keyword results. */
fusion_method?: 'max' | 'rrf';
/** How keyword terms are combined: "and" = all terms must match, "or" = any term matches. */
keyword_match_mode?: 'and' | 'or';
/** Minimum similarity score (0-1) for a result to be included. Default 0.4. */
match_threshold?: number;
/** Maximum number of results to return (1-50). Default 10. */
max_num_results?: number;
/** Vectorize metadata filters applied to the search. */
filters?: VectorizeVectorMetadataFilter;
/** Number of surrounding chunks to include for context (0-3). Default 0. */
context_expansion?: number;
/** If true, return only item metadata without chunk text. */
metadata_only?: boolean;
/** If true (default), return empty results on retrieval failure instead of throwing. */
return_on_failure?: boolean;
/** Boost results by metadata field values. Max 3 entries. */
boost_by?: Array<{
field: string;
direction?: 'asc' | 'desc' | 'exists' | 'not_exists';
}>;
[key: string]: unknown;
};
};
type AiSearchChatCompletionsRequest = {
messages: Array<{
role: 'system' | 'developer' | 'user' | 'assistant' | 'tool';
content: string | null;
}>;
model?: string;
stream?: boolean;
ai_search_options?: {
retrieval?: {
retrieval_type?: 'vector' | 'keyword' | 'hybrid';
match_threshold?: number;
max_num_results?: number;
filters?: VectorizeVectorMetadataFilter;
context_expansion?: number;
[key: string]: unknown;
};
query_rewrite?: {
enabled?: boolean;
model?: string;
rewrite_prompt?: string;
[key: string]: unknown;
};
reranking?: {
enabled?: boolean;
model?: '@cf/baai/bge-reranker-base' | '';
match_threshold?: number;
[key: string]: unknown;
};
query_rewrite?: {
enabled?: boolean;
model?: string;
rewrite_prompt?: string;
[key: string]: unknown;
};
reranking?: {
enabled?: boolean;
model?: string;
/** Match threshold (0-1, default 0.4) */
match_threshold?: number;
[key: string]: unknown;
};
cache?: {
enabled?: boolean;
cache_threshold?: 'super_strict_match' | 'close_enough' | 'flexible_friend' | 'anything_goes';
};
[key: string]: unknown;
};
// AI Search V2 Response Types
// ============ AI Search Request Types ============
/**
* Request body for single-instance search.
* Exactly one of `query` or `messages` must be provided.
*/
type AiSearchSearchRequest = {
/** Simple query string. */
query: string;
messages?: never;
ai_search_options?: AiSearchOptions;
} | {
query?: never;
/** Conversation-style input. At least one user message with non-empty content is required. */
messages: AiSearchMessage[];
ai_search_options?: AiSearchOptions;
};
type AiSearchChatCompletionsRequest = {
messages: AiSearchMessage[];
model?: string;
stream?: boolean;
ai_search_options?: AiSearchOptions;
[key: string]: unknown;
};
// ============ AI Search Multi-Instance Types (Namespace-Scoped) ============
/** `ai_search_options` shape for multi-instance requests — requires `instance_ids`. */
type AiSearchMultiSearchOptions = AiSearchOptions & {
/** Instance IDs to search across (1-10). */
instance_ids: string[];
};
/**
* Request for searching across multiple instances within a namespace.
* `ai_search_options` is required and must include `instance_ids`.
* Exactly one of `query` or `messages` must be provided.
*/
type AiSearchMultiSearchRequest = {
/** Simple query string. */
query: string;
messages?: never;
ai_search_options: AiSearchMultiSearchOptions;
} | {
query?: never;
/** Conversation-style input. */
messages: AiSearchMessage[];
ai_search_options: AiSearchMultiSearchOptions;
};
/** A search result chunk tagged with the instance it originated from. */
type AiSearchMultiSearchChunk = AiSearchSearchResponse['chunks'][number] & {
instance_id: string;
};
/** Describes a per-instance error during a multi-instance operation. */
type AiSearchMultiSearchError = {
instance_id: string;
message: string;
};
/** Response from a multi-instance search, with chunks tagged by instance and optional partial-failure errors. */
type AiSearchMultiSearchResponse = {
search_query: string;
chunks: AiSearchMultiSearchChunk[];
errors?: AiSearchMultiSearchError[];
};
/** Request for chat completions across multiple instances within a namespace. `ai_search_options` is required and must include `instance_ids`. */
type AiSearchMultiChatCompletionsRequest = Omit<AiSearchChatCompletionsRequest, 'ai_search_options'> & {
ai_search_options: AiSearchMultiSearchOptions;
};
/** Response from multi-instance chat completions, with chunks tagged by instance and optional partial-failure errors. */
type AiSearchMultiChatCompletionsResponse = Omit<AiSearchChatCompletionsResponse, 'chunks'> & {
chunks: AiSearchMultiSearchChunk[];
errors?: AiSearchMultiSearchError[];
};
// ============ AI Search Response Types ============
type AiSearchSearchResponse = {
search_query: string;
chunks: Array<{
@@ -3433,26 +3918,138 @@ type AiSearchSearchResponse = {
keyword_score?: number;
/** Vector similarity score (0-1) */
vector_score?: number;
/** Keyword rank position */
keyword_rank?: number;
/** Vector rank position */
vector_rank?: number;
/** Reranking model score */
reranking_score?: number;
/** Fusion method used to combine results */
fusion_method?: 'rrf' | 'max';
[key: string]: unknown;
};
}>;
};
type AiSearchListResponse = Array<{
id: string;
internal_id?: string;
account_id?: string;
account_tag?: string;
/** Whether the instance is enabled (default true) */
enable?: boolean;
type?: 'r2' | 'web-crawler';
source?: string;
type AiSearchChatCompletionsResponse = {
id?: string;
object?: string;
model?: string;
choices: Array<{
index?: number;
message: {
role: 'system' | 'developer' | 'user' | 'assistant' | 'tool';
content: string | null;
[key: string]: unknown;
};
[key: string]: unknown;
}>;
chunks: AiSearchSearchResponse['chunks'];
[key: string]: unknown;
}>;
};
type AiSearchStatsResponse = {
queued?: number;
running?: number;
completed?: number;
error?: number;
skipped?: number;
outdated?: number;
last_activity?: string;
/** Storage engine statistics. */
engine?: {
vectorize?: {
vectorsCount: number;
dimensions: number;
};
r2?: {
payloadSizeBytes: number;
metadataSizeBytes: number;
objectCount: number;
};
};
};
// ============ AI Search Instance Info Types ============
type AiSearchInstanceInfo = {
id: string;
type?: 'r2' | 'web-crawler' | string;
source?: string;
source_params?: unknown;
paused?: boolean;
status?: string;
namespace?: string;
created_at?: string;
modified_at?: string;
token_id?: string;
ai_gateway_id?: string;
rewrite_query?: boolean;
reranking?: boolean;
embedding_model?: string;
ai_search_model?: string;
rewrite_model?: string;
reranking_model?: string;
/** @deprecated Use index_method instead. */
hybrid_search_enabled?: boolean;
/** Controls which storage backends are active. */
index_method?: {
vector?: boolean;
keyword?: boolean;
};
/** Fusion method for combining vector and keyword results. */
fusion_method?: 'max' | 'rrf';
indexing_options?: {
keyword_tokenizer?: 'porter' | 'trigram';
} | null;
retrieval_options?: {
keyword_match_mode?: 'and' | 'or';
boost_by?: Array<{
field: string;
direction?: 'asc' | 'desc' | 'exists' | 'not_exists';
}>;
} | null;
chunk?: boolean;
chunk_size?: number;
chunk_overlap?: number;
score_threshold?: number;
max_num_results?: number;
cache?: boolean;
cache_threshold?: 'super_strict_match' | 'close_enough' | 'flexible_friend' | 'anything_goes';
custom_metadata?: Array<{
field_name: string;
data_type: 'text' | 'number' | 'boolean' | 'datetime';
}>;
/** Sync interval in seconds. */
sync_interval?: 3600 | 7200 | 14400 | 21600 | 43200 | 86400;
metadata?: Record<string, unknown>;
[key: string]: unknown;
};
/** Pagination, search, and ordering parameters for listing instances within a namespace. */
type AiSearchListInstancesParams = {
page?: number;
per_page?: number;
/** Search instances by ID. */
search?: string;
/** Field to sort by. */
order_by?: 'created_at';
/** Sort direction. */
order_by_direction?: 'asc' | 'desc';
};
type AiSearchListResponse = {
result: AiSearchInstanceInfo[];
result_info?: {
count: number;
page: number;
per_page: number;
total_count: number;
};
};
// ============ AI Search Config Types ============
type AiSearchConfig = {
/** Instance ID (1-32 chars, pattern: ^[a-z0-9_]+(?:-[a-z0-9_]+)*$) */
id: string;
type: 'r2' | 'web-crawler';
source: string;
source_params?: object;
/** Instance type. Omit to create with built-in storage. */
type?: 'r2' | 'web-crawler' | string;
/** Source URL (required for web-crawler type). */
source?: string;
source_params?: unknown;
/** Token ID (UUID format) */
token_id?: string;
ai_gateway_id?: string;
@@ -3462,52 +4059,460 @@ type AiSearchConfig = {
reranking?: boolean;
embedding_model?: string;
ai_search_model?: string;
};
type AiSearchInstance = {
id: string;
enable?: boolean;
type?: 'r2' | 'web-crawler';
source?: string;
rewrite_model?: string;
reranking_model?: string;
/** @deprecated Use index_method instead. */
hybrid_search_enabled?: boolean;
/** Controls which storage backends are used during indexing. Defaults to vector-only. */
index_method?: {
vector?: boolean;
keyword?: boolean;
};
/** Fusion method for combining vector and keyword results. "rrf" = reciprocal rank fusion (default), "max" = maximum score. */
fusion_method?: 'max' | 'rrf';
indexing_options?: {
keyword_tokenizer?: 'porter' | 'trigram';
} | null;
retrieval_options?: {
keyword_match_mode?: 'and' | 'or';
boost_by?: Array<{
field: string;
direction?: 'asc' | 'desc' | 'exists' | 'not_exists';
}>;
} | null;
chunk?: boolean;
chunk_size?: number;
chunk_overlap?: number;
/** Minimum similarity score (0-1) for a result to be included. */
score_threshold?: number;
max_num_results?: number;
cache?: boolean;
/** Similarity threshold for cache hits. Stricter = fewer cache hits but higher relevance. */
cache_threshold?: 'super_strict_match' | 'close_enough' | 'flexible_friend' | 'anything_goes';
custom_metadata?: Array<{
field_name: string;
data_type: 'text' | 'number' | 'boolean' | 'datetime';
}>;
namespace?: string;
/** Sync interval in seconds. 3600=1h, 7200=2h, 14400=4h, 21600=6h, 43200=12h, 86400=24h. */
sync_interval?: 3600 | 7200 | 14400 | 21600 | 43200 | 86400;
metadata?: Record<string, unknown>;
[key: string]: unknown;
};
// AI Search Instance Service - Instance-level operations
declare abstract class AiSearchInstanceService {
// ============ AI Search Item Types ============
type AiSearchItemInfo = {
id: string;
key: string;
status: 'completed' | 'error' | 'skipped' | 'queued' | 'running' | 'outdated';
next_action?: 'INDEX' | 'DELETE' | null;
error?: string;
checksum?: string;
namespace?: string;
chunks_count?: number | null;
file_size?: number | null;
source_id?: string | null;
last_seen_at?: string;
created_at?: string;
metadata?: Record<string, unknown>;
[key: string]: unknown;
};
type AiSearchItemContentResult = {
body: ReadableStream;
contentType: string;
filename: string;
size: number;
};
type AiSearchUploadItemOptions = {
metadata?: Record<string, unknown>;
};
type AiSearchListItemsParams = {
page?: number;
per_page?: number;
/** Search items by key name. */
search?: string;
/** Sort order for results. */
sort_by?: 'status' | 'modified_at';
/** Filter items by processing status. */
status?: 'queued' | 'running' | 'completed' | 'error' | 'skipped' | 'outdated';
/** Filter items by source (e.g. "builtin" or "web-crawler:https://example.com"). */
source?: string;
/** JSON-encoded Vectorize filter for metadata filtering. */
metadata_filter?: string;
};
type AiSearchListItemsResponse = {
result: AiSearchItemInfo[];
result_info?: {
count: number;
page: number;
per_page: number;
total_count: number;
};
};
// ============ AI Search Item Logs Types ============
type AiSearchItemLogsParams = {
/** Maximum number of log entries to return (1-100, default 50). */
limit?: number;
/** Opaque cursor for pagination. Pass the `cursor` value from a previous response. */
cursor?: string;
};
type AiSearchItemLog = {
timestamp: string;
action: string;
message: string;
fileKey?: string;
chunkCount?: number;
processingTimeMs?: number;
errorType?: string;
};
/** Paginated response for item processing logs (cursor-based). */
type AiSearchItemLogsResponse = {
result: AiSearchItemLog[];
result_info: {
count: number;
per_page: number;
cursor: string | null;
truncated: boolean;
};
};
// ============ AI Search Item Chunks Types ============
type AiSearchItemChunksParams = {
/** Maximum number of chunks to return (1-100, default 20). */
limit?: number;
/** Offset into the chunks list (default 0). */
offset?: number;
};
/** A single indexed chunk belonging to an item, including its text content and byte range. */
type AiSearchItemChunk = {
id: string;
text: string;
start_byte: number;
end_byte: number;
item?: {
timestamp?: number;
key: string;
metadata?: Record<string, unknown>;
};
};
/** Paginated response for item chunks (offset-based). */
type AiSearchItemChunksResponse = {
result: AiSearchItemChunk[];
result_info: {
count: number;
total: number;
limit: number;
offset: number;
};
};
// ============ AI Search Job Types ============
type AiSearchJobInfo = {
id: string;
source: 'user' | 'schedule';
description?: string;
last_seen_at?: string;
started_at?: string;
ended_at?: string;
end_reason?: string;
};
type AiSearchJobLog = {
id: number;
message: string;
message_type: number;
created_at: number;
};
type AiSearchCreateJobParams = {
description?: string;
};
type AiSearchListJobsParams = {
page?: number;
per_page?: number;
};
type AiSearchListJobsResponse = {
result: AiSearchJobInfo[];
result_info?: {
count: number;
page: number;
per_page: number;
total_count: number;
};
};
type AiSearchJobLogsParams = {
page?: number;
per_page?: number;
};
type AiSearchJobLogsResponse = {
result: AiSearchJobLog[];
result_info?: {
count: number;
page: number;
per_page: number;
total_count: number;
};
};
// ============ AI Search Sub-Service Classes ============
/**
* Single item service for an AI Search instance.
* Provides info, download, sync, logs, and chunks operations on a specific item.
*/
declare abstract class AiSearchItem {
/** Get metadata about this item. */
info(): Promise<AiSearchItemInfo>;
/**
* Download the item's content.
* @returns Object with body stream, content type, filename, and size.
*/
download(): Promise<AiSearchItemContentResult>;
/**
* Trigger re-indexing of this item.
* @returns The updated item info.
*/
sync(): Promise<AiSearchItemInfo>;
/**
* Retrieve processing logs for this item (cursor-based pagination).
* @param params Optional pagination parameters (limit, cursor).
* @returns Paginated log entries for this item.
*/
logs(params?: AiSearchItemLogsParams): Promise<AiSearchItemLogsResponse>;
/**
* List indexed chunks for this item (offset-based pagination).
* @param params Optional pagination parameters (limit, offset).
* @returns Paginated chunk entries for this item.
*/
chunks(params?: AiSearchItemChunksParams): Promise<AiSearchItemChunksResponse>;
}
/**
* Items collection service for an AI Search instance.
* Provides list, upload, and access to individual items.
*/
declare abstract class AiSearchItems {
/** List items in this instance. */
list(params?: AiSearchListItemsParams): Promise<AiSearchListItemsResponse>;
/**
* Upload a file as an item. Behaves as an upsert: if an item with the same
* filename already exists, it is overwritten and re-indexed.
* @param name Filename for the uploaded item.
* @param content File content as a ReadableStream, Blob, or string.
* @param options Optional metadata to attach to the item.
* @returns The created item info.
*/
upload(name: string, content: ReadableStream | Blob | string, options?: AiSearchUploadItemOptions): Promise<AiSearchItemInfo>;
/**
* Upload a file and poll until processing completes.
* Behaves as an upsert: if an item with the same filename already exists,
* it is overwritten and re-indexed.
* @param name Filename for the uploaded item.
* @param content File content as a ReadableStream, Blob, or string.
* @param options Optional metadata and polling configuration.
* @returns The item info after processing completes (or timeout).
*/
uploadAndPoll(name: string, content: ReadableStream | Blob | string, options?: AiSearchUploadItemOptions & {
/** Polling interval in milliseconds (default 1000). */
pollIntervalMs?: number;
/** Maximum time to wait in milliseconds (default 30000). */
timeoutMs?: number;
}): Promise<AiSearchItemInfo>;
/**
* Get an item by ID.
* @param itemId The item identifier.
* @returns Item service for info, download, sync, logs, and chunks operations.
*/
get(itemId: string): AiSearchItem;
/**
* Delete an item from the instance.
* @param itemId The item identifier.
*/
delete(itemId: string): Promise<void>;
}
/**
* Single job service for an AI Search instance.
* Provides info, logs, and cancel operations for a specific job.
*/
declare abstract class AiSearchJob {
/** Get metadata about this job. */
info(): Promise<AiSearchJobInfo>;
/** Get logs for this job. */
logs(params?: AiSearchJobLogsParams): Promise<AiSearchJobLogsResponse>;
/**
* Cancel a running job.
* @returns The updated job info.
* @throws AiSearchNotFoundError if the job does not exist.
*/
cancel(): Promise<AiSearchJobInfo>;
}
/**
* Jobs collection service for an AI Search instance.
* Provides list, create, and access to individual jobs.
*/
declare abstract class AiSearchJobs {
/** List jobs for this instance. */
list(params?: AiSearchListJobsParams): Promise<AiSearchListJobsResponse>;
/**
* Create a new indexing job.
* @param params Optional job parameters.
* @returns The created job info.
*/
create(params?: AiSearchCreateJobParams): Promise<AiSearchJobInfo>;
/**
* Get a job by ID.
* @param jobId The job identifier.
* @returns Job service for info, logs, and cancel operations.
*/
get(jobId: string): AiSearchJob;
}
// ============ AI Search Binding Classes ============
/**
* Instance-level AI Search service.
*
* Used as:
* - The return type of `AiSearchNamespace.get(name)` (namespace binding)
* - The type of `env.BLOG_SEARCH` (single instance binding via `ai_search`)
*
* Provides search, chat, update, stats, items, and jobs operations.
*
* @example
* ```ts
* // Via namespace binding
* const instance = env.AI_SEARCH.get("blog");
* const results = await instance.search({
* query: "How does caching work?",
* });
*
* // Via single instance binding
* const results = await env.BLOG_SEARCH.search({
* messages: [{ role: "user", content: "How does caching work?" }],
* });
* ```
*/
declare abstract class AiSearchInstance {
/**
* Search the AI Search instance for relevant chunks.
* @param params Search request with messages and AI search options
* @returns Search response with matching chunks
* @param params Search request with query or messages and optional AI search options.
* @returns Search response with matching chunks and search query.
*/
search(params: AiSearchSearchRequest): Promise<AiSearchSearchResponse>;
/**
* Generate chat completions with AI Search context (streaming).
* @param params Chat completions request with stream: true.
* @returns ReadableStream of server-sent events.
*/
chatCompletions(params: AiSearchChatCompletionsRequest & {
stream: true;
}): Promise<ReadableStream>;
/**
* Generate chat completions with AI Search context.
* @param params Chat completions request with optional streaming
* @returns Response object (if streaming) or chat completion result
* @param params Chat completions request.
* @returns Chat completion response with choices and RAG chunks.
*/
chatCompletions(params: AiSearchChatCompletionsRequest): Promise<Response | object>;
chatCompletions(params: AiSearchChatCompletionsRequest): Promise<AiSearchChatCompletionsResponse>;
/**
* Delete this AI Search instance.
* Update the instance configuration.
* @param config Partial configuration to update.
* @returns Updated instance info.
*/
delete(): Promise<void>;
update(config: Partial<AiSearchConfig>): Promise<AiSearchInstanceInfo>;
/** Get metadata about this instance. */
info(): Promise<AiSearchInstanceInfo>;
/**
* Get instance statistics (item count, indexing status, etc.).
* @returns Statistics with counts per status, last activity time, and engine details.
*/
stats(): Promise<AiSearchStatsResponse>;
/** Items collection — list, upload, and manage items in this instance. */
get items(): AiSearchItems;
/** Jobs collection — list, create, and inspect indexing jobs. */
get jobs(): AiSearchJobs;
}
// AI Search Account Service - Account-level operations
declare abstract class AiSearchAccountService {
/**
* Namespace-level AI Search service.
*
* Used as the type of `env.AI_SEARCH` (namespace binding via `ai_search_namespaces`).
* Scoped to a single namespace. Provides dynamic instance access, creation, deletion,
* and multi-instance search/chat operations.
*
* @example
* ```ts
* // Access an instance within the namespace
* const blog = env.AI_SEARCH.get("blog");
* const results = await blog.search({ query: "How does caching work?" });
*
* // List all instances in the namespace
* const instances = await env.AI_SEARCH.list();
*
* // Create a new instance with built-in storage
* const tenant = await env.AI_SEARCH.create({ id: "tenant-123" });
*
* // Upload items into the instance
* await tenant.items.upload("doc.pdf", fileContent);
*
* // Search across multiple instances
* const multi = await env.AI_SEARCH.search({
* query: "caching",
* ai_search_options: { instance_ids: ["blog", "docs"] },
* });
*
* // Delete an instance
* await env.AI_SEARCH.delete("tenant-123");
* ```
*/
declare abstract class AiSearchNamespace {
/**
* List all AI Search instances in the account.
* @returns Array of AI Search instances
* Get an instance by name within the bound namespace.
* @param name Instance name.
* @returns Instance service for search, chat, update, stats, items, and jobs.
*/
list(): Promise<AiSearchListResponse>;
get(name: string): AiSearchInstance;
/**
* Get an AI Search instance by ID.
* @param name Instance ID
* @returns Instance service for performing operations
* List instances in the bound namespace.
* @param params Optional pagination, search, and ordering parameters.
* @returns Array of instance metadata with pagination info.
*/
get(name: string): AiSearchInstanceService;
list(params?: AiSearchListInstancesParams): Promise<AiSearchListResponse>;
/**
* Create a new AI Search instance.
* @param config Instance configuration
* @returns Instance service for performing operations
* Create a new instance within the bound namespace.
* @param config Instance configuration. Only `id` is required omit `type` and `source` to create with built-in storage.
* @returns Instance service for the newly created instance.
*
* @example
* ```ts
* // Create with built-in storage (upload items manually)
* const instance = await env.AI_SEARCH.create({ id: "my-search" });
*
* // Create with web crawler source
* const instance = await env.AI_SEARCH.create({
* id: "docs-search",
* type: "web-crawler",
* source: "https://developers.cloudflare.com",
* });
* ```
*/
create(config: AiSearchConfig): Promise<AiSearchInstanceService>;
create(config: AiSearchConfig): Promise<AiSearchInstance>;
/**
* Delete an instance from the bound namespace.
* @param name Instance name to delete.
*/
delete(name: string): Promise<void>;
/**
* Search across multiple instances within the bound namespace.
* Fans out to the specified instance_ids and merges results.
* @param params Search request with required `ai_search_options.instance_ids`.
* @returns Search response with chunks tagged by instance_id and optional partial-failure errors.
*/
search(params: AiSearchMultiSearchRequest): Promise<AiSearchMultiSearchResponse>;
/**
* Generate chat completions across multiple instances within the bound namespace (streaming).
* Fans out to the specified instance_ids, merges context, and generates a response.
* @param params Chat completions request with stream: true and required `ai_search_options.instance_ids`.
* @returns ReadableStream of server-sent events.
*/
chatCompletions(params: AiSearchMultiChatCompletionsRequest & {
stream: true;
}): Promise<ReadableStream>;
/**
* Generate chat completions across multiple instances within the bound namespace.
* Fans out to the specified instance_ids, merges context, and generates a response.
* @param params Chat completions request with required `ai_search_options.instance_ids`.
* @returns Chat completion response with choices, chunks tagged by instance_id, and optional partial-failure errors.
*/
chatCompletions(params: AiSearchMultiChatCompletionsRequest): Promise<AiSearchMultiChatCompletionsResponse>;
}
type AiImageClassificationInput = {
image: number[];
@@ -3772,6 +4777,356 @@ declare abstract class BaseAiTranslation {
inputs: AiTranslationInput;
postProcessedOutputs: AiTranslationOutput;
}
/**
* Workers AI support for OpenAI's Chat Completions API
*/
type ChatCompletionContentPartText = {
type: "text";
text: string;
};
type ChatCompletionContentPartImage = {
type: "image_url";
image_url: {
url: string;
detail?: "auto" | "low" | "high";
};
};
type ChatCompletionContentPartInputAudio = {
type: "input_audio";
input_audio: {
/** Base64 encoded audio data. */
data: string;
format: "wav" | "mp3";
};
};
type ChatCompletionContentPartFile = {
type: "file";
file: {
/** Base64 encoded file data. */
file_data?: string;
/** The ID of an uploaded file. */
file_id?: string;
filename?: string;
};
};
type ChatCompletionContentPartRefusal = {
type: "refusal";
refusal: string;
};
type ChatCompletionContentPart = ChatCompletionContentPartText | ChatCompletionContentPartImage | ChatCompletionContentPartInputAudio | ChatCompletionContentPartFile;
type FunctionDefinition = {
name: string;
description?: string;
parameters?: Record<string, unknown>;
strict?: boolean | null;
};
type ChatCompletionFunctionTool = {
type: "function";
function: FunctionDefinition;
};
type ChatCompletionCustomToolGrammarFormat = {
type: "grammar";
grammar: {
definition: string;
syntax: "lark" | "regex";
};
};
type ChatCompletionCustomToolTextFormat = {
type: "text";
};
type ChatCompletionCustomToolFormat = ChatCompletionCustomToolTextFormat | ChatCompletionCustomToolGrammarFormat;
type ChatCompletionCustomTool = {
type: "custom";
custom: {
name: string;
description?: string;
format?: ChatCompletionCustomToolFormat;
};
};
type ChatCompletionTool = ChatCompletionFunctionTool | ChatCompletionCustomTool;
type ChatCompletionMessageFunctionToolCall = {
id: string;
type: "function";
function: {
name: string;
/** JSON-encoded arguments string. */
arguments: string;
};
};
type ChatCompletionMessageCustomToolCall = {
id: string;
type: "custom";
custom: {
name: string;
input: string;
};
};
type ChatCompletionMessageToolCall = ChatCompletionMessageFunctionToolCall | ChatCompletionMessageCustomToolCall;
type ChatCompletionToolChoiceFunction = {
type: "function";
function: {
name: string;
};
};
type ChatCompletionToolChoiceCustom = {
type: "custom";
custom: {
name: string;
};
};
type ChatCompletionToolChoiceAllowedTools = {
type: "allowed_tools";
allowed_tools: {
mode: "auto" | "required";
tools: Array<Record<string, unknown>>;
};
};
type ChatCompletionToolChoiceOption = "none" | "auto" | "required" | ChatCompletionToolChoiceFunction | ChatCompletionToolChoiceCustom | ChatCompletionToolChoiceAllowedTools;
type DeveloperMessage = {
role: "developer";
content: string | Array<{
type: "text";
text: string;
}>;
name?: string;
};
type SystemMessage = {
role: "system";
content: string | Array<{
type: "text";
text: string;
}>;
name?: string;
};
/**
* Permissive merged content part used inside UserMessage arrays.
*
* Cabidela has a limitation where anyOf/oneOf with enum-based discrimination
* inside nested array items does not correctly match different branches for
* different array elements, so the schema uses a single merged object.
*/
type UserMessageContentPart = {
type: "text" | "image_url" | "input_audio" | "file";
text?: string;
image_url?: {
url?: string;
detail?: "auto" | "low" | "high";
};
input_audio?: {
data?: string;
format?: "wav" | "mp3";
};
file?: {
file_data?: string;
file_id?: string;
filename?: string;
};
};
type UserMessage = {
role: "user";
content: string | Array<UserMessageContentPart>;
name?: string;
};
type AssistantMessageContentPart = {
type: "text" | "refusal";
text?: string;
refusal?: string;
};
type AssistantMessage = {
role: "assistant";
content?: string | null | Array<AssistantMessageContentPart>;
refusal?: string | null;
name?: string;
audio?: {
id: string;
};
tool_calls?: Array<ChatCompletionMessageToolCall>;
function_call?: {
name: string;
arguments: string;
};
};
type ToolMessage = {
role: "tool";
content: string | Array<{
type: "text";
text: string;
}>;
tool_call_id: string;
};
type FunctionMessage = {
role: "function";
content: string;
name: string;
};
type ChatCompletionMessageParam = DeveloperMessage | SystemMessage | UserMessage | AssistantMessage | ToolMessage | FunctionMessage;
type ChatCompletionsResponseFormatText = {
type: "text";
};
type ChatCompletionsResponseFormatJSONObject = {
type: "json_object";
};
type ResponseFormatJSONSchema = {
type: "json_schema";
json_schema: {
name: string;
description?: string;
schema?: Record<string, unknown>;
strict?: boolean | null;
};
};
type ResponseFormat = ChatCompletionsResponseFormatText | ChatCompletionsResponseFormatJSONObject | ResponseFormatJSONSchema;
type ChatCompletionsStreamOptions = {
include_usage?: boolean;
include_obfuscation?: boolean;
};
type PredictionContent = {
type: "content";
content: string | Array<{
type: "text";
text: string;
}>;
};
type AudioParams = {
voice: string | {
id: string;
};
format: "wav" | "aac" | "mp3" | "flac" | "opus" | "pcm16";
};
type WebSearchUserLocation = {
type: "approximate";
approximate: {
city?: string;
country?: string;
region?: string;
timezone?: string;
};
};
type WebSearchOptions = {
search_context_size?: "low" | "medium" | "high";
user_location?: WebSearchUserLocation;
};
type ChatTemplateKwargs = {
/** Whether to enable reasoning, enabled by default. */
enable_thinking?: boolean;
/** If false, preserves reasoning context between turns. */
clear_thinking?: boolean;
};
/** Shared optional properties used by both Prompt and Messages input branches. */
type ChatCompletionsCommonOptions = {
model?: string;
audio?: AudioParams;
frequency_penalty?: number | null;
logit_bias?: Record<string, unknown> | null;
logprobs?: boolean | null;
top_logprobs?: number | null;
max_tokens?: number | null;
max_completion_tokens?: number | null;
metadata?: Record<string, unknown> | null;
modalities?: Array<"text" | "audio"> | null;
n?: number | null;
parallel_tool_calls?: boolean;
prediction?: PredictionContent;
presence_penalty?: number | null;
reasoning_effort?: "low" | "medium" | "high" | null;
chat_template_kwargs?: ChatTemplateKwargs;
response_format?: ResponseFormat;
seed?: number | null;
service_tier?: "auto" | "default" | "flex" | "scale" | "priority" | null;
stop?: string | Array<string> | null;
store?: boolean | null;
stream?: boolean | null;
stream_options?: ChatCompletionsStreamOptions;
temperature?: number | null;
tool_choice?: ChatCompletionToolChoiceOption;
tools?: Array<ChatCompletionTool>;
top_p?: number | null;
user?: string;
web_search_options?: WebSearchOptions;
function_call?: "none" | "auto" | {
name: string;
};
functions?: Array<FunctionDefinition>;
};
type PromptTokensDetails = {
cached_tokens?: number;
audio_tokens?: number;
};
type CompletionTokensDetails = {
reasoning_tokens?: number;
audio_tokens?: number;
accepted_prediction_tokens?: number;
rejected_prediction_tokens?: number;
};
type CompletionUsage = {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
prompt_tokens_details?: PromptTokensDetails;
completion_tokens_details?: CompletionTokensDetails;
};
type ChatCompletionTopLogprob = {
token: string;
logprob: number;
bytes: Array<number> | null;
};
type ChatCompletionTokenLogprob = {
token: string;
logprob: number;
bytes: Array<number> | null;
top_logprobs: Array<ChatCompletionTopLogprob>;
};
type ChatCompletionAudio = {
id: string;
/** Base64 encoded audio bytes. */
data: string;
expires_at: number;
transcript: string;
};
type ChatCompletionUrlCitation = {
type: "url_citation";
url_citation: {
url: string;
title: string;
start_index: number;
end_index: number;
};
};
type ChatCompletionResponseMessage = {
role: "assistant";
content: string | null;
refusal: string | null;
annotations?: Array<ChatCompletionUrlCitation>;
audio?: ChatCompletionAudio;
tool_calls?: Array<ChatCompletionMessageToolCall>;
function_call?: {
name: string;
arguments: string;
} | null;
};
type ChatCompletionLogprobs = {
content: Array<ChatCompletionTokenLogprob> | null;
refusal?: Array<ChatCompletionTokenLogprob> | null;
};
type ChatCompletionChoice = {
index: number;
message: ChatCompletionResponseMessage;
finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | "function_call";
logprobs: ChatCompletionLogprobs | null;
};
type ChatCompletionsMessagesInput = {
messages: Array<ChatCompletionMessageParam>;
} & ChatCompletionsCommonOptions;
type ChatCompletionsOutput = {
id: string;
object: string;
created: number;
model: string;
choices: Array<ChatCompletionChoice>;
usage?: CompletionUsage;
system_fingerprint?: string | null;
service_tier?: "auto" | "default" | "flex" | "scale" | "priority" | null;
};
/**
* Workers AI support for OpenAI's Responses API
* Reference: https://github.com/openai/openai-node/blob/master/src/resources/responses/responses.ts
@@ -4129,6 +5484,12 @@ type ReasoningEffort = "minimal" | "low" | "medium" | "high" | null;
type StreamOptions = {
include_obfuscation?: boolean;
};
/** Marks keys from T that aren't in U as optional never */
type Without<T, U> = {
[P in Exclude<keyof T, keyof U>]?: never;
};
/** Either T or U, but not both (mutually exclusive) */
type XOR<T, U> = (T & Without<U, T>) | (U & Without<T, U>);
type Ai_Cf_Baai_Bge_Base_En_V1_5_Input = {
text: string | string[];
/**
@@ -4399,10 +5760,10 @@ declare abstract class Base_Ai_Cf_Openai_Whisper_Tiny_En {
postProcessedOutputs: Ai_Cf_Openai_Whisper_Tiny_En_Output;
}
interface Ai_Cf_Openai_Whisper_Large_V3_Turbo_Input {
/**
* Base64 encoded value of the audio data.
*/
audio: string;
audio: string | {
body?: object;
contentType?: string;
};
/**
* Supported tasks are 'translate' or 'transcribe'.
*/
@@ -4420,9 +5781,33 @@ interface Ai_Cf_Openai_Whisper_Large_V3_Turbo_Input {
*/
initial_prompt?: string;
/**
* The prefix it appended the the beginning of the output of the transcription and can guide the transcription result.
* The prefix appended to the beginning of the output of the transcription and can guide the transcription result.
*/
prefix?: string;
/**
* The number of beams to use in beam search decoding. Higher values may improve accuracy at the cost of speed.
*/
beam_size?: number;
/**
* Whether to condition on previous text during transcription. Setting to false may help prevent hallucination loops.
*/
condition_on_previous_text?: boolean;
/**
* Threshold for detecting no-speech segments. Segments with no-speech probability above this value are skipped.
*/
no_speech_threshold?: number;
/**
* Threshold for filtering out segments with high compression ratio, which often indicate repetitive or hallucinated text.
*/
compression_ratio_threshold?: number;
/**
* Threshold for filtering out segments with low average log probability, indicating low confidence.
*/
log_prob_threshold?: number;
/**
* Optional threshold (in seconds) to skip silent periods that may cause hallucinations.
*/
hallucination_silence_threshold?: number;
}
interface Ai_Cf_Openai_Whisper_Large_V3_Turbo_Output {
transcription_info?: {
@@ -4562,8 +5947,8 @@ interface Ai_Cf_Baai_Bge_M3_Input_Embedding_1 {
*/
truncate_inputs?: boolean;
}
type Ai_Cf_Baai_Bge_M3_Output = Ai_Cf_Baai_Bge_M3_Ouput_Query | Ai_Cf_Baai_Bge_M3_Output_EmbeddingFor_Contexts | Ai_Cf_Baai_Bge_M3_Ouput_Embedding | Ai_Cf_Baai_Bge_M3_AsyncResponse;
interface Ai_Cf_Baai_Bge_M3_Ouput_Query {
type Ai_Cf_Baai_Bge_M3_Output = Ai_Cf_Baai_Bge_M3_Output_Query | Ai_Cf_Baai_Bge_M3_Output_EmbeddingFor_Contexts | Ai_Cf_Baai_Bge_M3_Output_Embedding | Ai_Cf_Baai_Bge_M3_AsyncResponse;
interface Ai_Cf_Baai_Bge_M3_Output_Query {
response?: {
/**
* Index of the context in the request
@@ -4583,7 +5968,7 @@ interface Ai_Cf_Baai_Bge_M3_Output_EmbeddingFor_Contexts {
*/
pooling?: "mean" | "cls";
}
interface Ai_Cf_Baai_Bge_M3_Ouput_Embedding {
interface Ai_Cf_Baai_Bge_M3_Output_Embedding {
shape?: number[];
/**
* Embeddings of the requested text values
@@ -4686,7 +6071,7 @@ interface Ai_Cf_Meta_Llama_3_2_11B_Vision_Instruct_Messages {
*/
role?: string;
/**
* The tool call id. Must be supplied for tool calls for Mistral-3. If you don't know what to put here you can fall back to 000000001
* The tool call id. If you don't know what to put here you can fall back to 000000001
*/
tool_call_id?: string;
content?: string | {
@@ -4932,10 +6317,16 @@ interface Ai_Cf_Meta_Llama_3_3_70B_Instruct_Fp8_Fast_Messages {
* The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool').
*/
role: string;
/**
* The content of the message as a string.
*/
content: string;
content: string | {
/**
* Type of the content (text)
*/
type?: string;
/**
* Text content
*/
text?: string;
}[];
}[];
functions?: {
name: string;
@@ -5576,7 +6967,7 @@ interface Ai_Cf_Qwen_Qwq_32B_Messages {
*/
role?: string;
/**
* The tool call id. Must be supplied for tool calls for Mistral-3. If you don't know what to put here you can fall back to 000000001
* The tool call id. If you don't know what to put here you can fall back to 000000001
*/
tool_call_id?: string;
content?: string | {
@@ -5697,7 +7088,7 @@ interface Ai_Cf_Qwen_Qwq_32B_Messages {
};
})[];
/**
* JSON schema that should be fulfilled for the response.
* JSON schema that should be fufilled for the response.
*/
guided_json?: object;
/**
@@ -5963,7 +7354,7 @@ interface Ai_Cf_Mistralai_Mistral_Small_3_1_24B_Instruct_Messages {
};
})[];
/**
* JSON schema that should be fulfilled for the response.
* JSON schema that should be fufilled for the response.
*/
guided_json?: object;
/**
@@ -6054,7 +7445,7 @@ interface Ai_Cf_Google_Gemma_3_12B_It_Prompt {
*/
prompt: string;
/**
* JSON schema that should be fulfilled for the response.
* JSON schema that should be fufilled for the response.
*/
guided_json?: object;
/**
@@ -6213,7 +7604,7 @@ interface Ai_Cf_Google_Gemma_3_12B_It_Messages {
};
})[];
/**
* JSON schema that should be fulfilled for the response.
* JSON schema that should be fufilled for the response.
*/
guided_json?: object;
/**
@@ -6485,7 +7876,7 @@ interface Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Messages {
})[];
response_format?: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_JSON_Mode;
/**
* JSON schema that should be fulfilled for the response.
* JSON schema that should be fufilled for the response.
*/
guided_json?: object;
/**
@@ -6715,7 +8106,7 @@ interface Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_Messages_Inner {
})[];
response_format?: Ai_Cf_Meta_Llama_4_Scout_17B_16E_Instruct_JSON_Mode;
/**
* JSON schema that should be fulfilled for the response.
* JSON schema that should be fufilled for the response.
*/
guided_json?: object;
/**
@@ -6877,10 +8268,16 @@ interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Messages {
* The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool').
*/
role: string;
/**
* The content of the message as a string.
*/
content: string;
content: string | {
/**
* Type of the content (text)
*/
type?: string;
/**
* Text content
*/
text?: string;
}[];
}[];
functions?: {
name: string;
@@ -7086,10 +8483,16 @@ interface Ai_Cf_Qwen_Qwen3_30B_A3B_Fp8_Messages_1 {
* The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool').
*/
role: string;
/**
* The content of the message as a string.
*/
content: string;
content: string | {
/**
* Type of the content (text)
*/
type?: string;
/**
* Text content
*/
text?: string;
}[];
}[];
functions?: {
name: string;
@@ -7640,12 +9043,12 @@ declare abstract class Base_Ai_Cf_Pipecat_Ai_Smart_Turn_V2 {
postProcessedOutputs: Ai_Cf_Pipecat_Ai_Smart_Turn_V2_Output;
}
declare abstract class Base_Ai_Cf_Openai_Gpt_Oss_120B {
inputs: ResponsesInput;
postProcessedOutputs: ResponsesOutput;
inputs: XOR<ResponsesInput, ChatCompletionsMessagesInput>;
postProcessedOutputs: XOR<ResponsesOutput, ChatCompletionsOutput>;
}
declare abstract class Base_Ai_Cf_Openai_Gpt_Oss_20B {
inputs: ResponsesInput;
postProcessedOutputs: ResponsesOutput;
inputs: XOR<ResponsesInput, ChatCompletionsMessagesInput>;
postProcessedOutputs: XOR<ResponsesOutput, ChatCompletionsOutput>;
}
interface Ai_Cf_Leonardo_Phoenix_1_0_Input {
/**
@@ -7765,7 +9168,7 @@ interface Ai_Cf_Ai4Bharat_Indictrans2_En_Indic_1B_Input {
*/
text: string | string[];
/**
* Target language to translate to
* Target langauge to translate to
*/
target_language: "asm_Beng" | "awa_Deva" | "ben_Beng" | "bho_Deva" | "brx_Deva" | "doi_Deva" | "eng_Latn" | "gom_Deva" | "gon_Deva" | "guj_Gujr" | "hin_Deva" | "hne_Deva" | "kan_Knda" | "kas_Arab" | "kas_Deva" | "kha_Latn" | "lus_Latn" | "mag_Deva" | "mai_Deva" | "mal_Mlym" | "mar_Deva" | "mni_Beng" | "mni_Mtei" | "npi_Deva" | "ory_Orya" | "pan_Guru" | "san_Deva" | "sat_Olck" | "snd_Arab" | "snd_Deva" | "tam_Taml" | "tel_Telu" | "urd_Arab" | "unr_Deva";
}
@@ -7844,10 +9247,16 @@ interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Messages {
* The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool').
*/
role: string;
/**
* The content of the message as a string.
*/
content: string;
content: string | {
/**
* Type of the content (text)
*/
type?: string;
/**
* Text content
*/
text?: string;
}[];
}[];
functions?: {
name: string;
@@ -8053,10 +9462,16 @@ interface Ai_Cf_Aisingapore_Gemma_Sea_Lion_V4_27B_It_Messages_1 {
* The role of the message sender (e.g., 'user', 'assistant', 'system', 'tool').
*/
role: string;
/**
* The content of the message as a string.
*/
content: string;
content: string | {
/**
* Type of the content (text)
*/
type?: string;
/**
* Text content
*/
text?: string;
}[];
}[];
functions?: {
name: string;
@@ -8552,6 +9967,74 @@ declare abstract class Base_Ai_Cf_Deepgram_Aura_2_Es {
inputs: Ai_Cf_Deepgram_Aura_2_Es_Input;
postProcessedOutputs: Ai_Cf_Deepgram_Aura_2_Es_Output;
}
interface Ai_Cf_Black_Forest_Labs_Flux_2_Dev_Input {
multipart: {
body?: object;
contentType?: string;
};
}
interface Ai_Cf_Black_Forest_Labs_Flux_2_Dev_Output {
/**
* Generated image as Base64 string.
*/
image?: string;
}
declare abstract class Base_Ai_Cf_Black_Forest_Labs_Flux_2_Dev {
inputs: Ai_Cf_Black_Forest_Labs_Flux_2_Dev_Input;
postProcessedOutputs: Ai_Cf_Black_Forest_Labs_Flux_2_Dev_Output;
}
interface Ai_Cf_Black_Forest_Labs_Flux_2_Klein_4B_Input {
multipart: {
body?: object;
contentType?: string;
};
}
interface Ai_Cf_Black_Forest_Labs_Flux_2_Klein_4B_Output {
/**
* Generated image as Base64 string.
*/
image?: string;
}
declare abstract class Base_Ai_Cf_Black_Forest_Labs_Flux_2_Klein_4B {
inputs: Ai_Cf_Black_Forest_Labs_Flux_2_Klein_4B_Input;
postProcessedOutputs: Ai_Cf_Black_Forest_Labs_Flux_2_Klein_4B_Output;
}
interface Ai_Cf_Black_Forest_Labs_Flux_2_Klein_9B_Input {
multipart: {
body?: object;
contentType?: string;
};
}
interface Ai_Cf_Black_Forest_Labs_Flux_2_Klein_9B_Output {
/**
* Generated image as Base64 string.
*/
image?: string;
}
declare abstract class Base_Ai_Cf_Black_Forest_Labs_Flux_2_Klein_9B {
inputs: Ai_Cf_Black_Forest_Labs_Flux_2_Klein_9B_Input;
postProcessedOutputs: Ai_Cf_Black_Forest_Labs_Flux_2_Klein_9B_Output;
}
declare abstract class Base_Ai_Cf_Zai_Org_Glm_4_7_Flash {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Moonshotai_Kimi_K2_5 {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Moonshotai_Kimi_K2_6 {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Nvidia_Nemotron_3_120B_A12B {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
declare abstract class Base_Ai_Cf_Google_Gemma_4_26B_A4B_IT {
inputs: ChatCompletionsInput;
postProcessedOutputs: ChatCompletionsOutput;
}
interface AiModels {
"@cf/huggingface/distilbert-sst-2-int8": BaseAiTextClassification;
"@cf/stabilityai/stable-diffusion-xl-base-1.0": BaseAiTextToImage;
@@ -8570,7 +10053,6 @@ interface AiModels {
"@hf/thebloke/zephyr-7b-beta-awq": BaseAiTextGeneration;
"@hf/thebloke/openhermes-2.5-mistral-7b-awq": BaseAiTextGeneration;
"@hf/thebloke/neural-chat-7b-v3-1-awq": BaseAiTextGeneration;
"@hf/thebloke/llamaguard-7b-awq": BaseAiTextGeneration;
"@hf/thebloke/deepseek-coder-6.7b-base-awq": BaseAiTextGeneration;
"@hf/thebloke/deepseek-coder-6.7b-instruct-awq": BaseAiTextGeneration;
"@cf/deepseek-ai/deepseek-math-7b-instruct": BaseAiTextGeneration;
@@ -8637,6 +10119,14 @@ interface AiModels {
"@cf/deepgram/flux": Base_Ai_Cf_Deepgram_Flux;
"@cf/deepgram/aura-2-en": Base_Ai_Cf_Deepgram_Aura_2_En;
"@cf/deepgram/aura-2-es": Base_Ai_Cf_Deepgram_Aura_2_Es;
"@cf/black-forest-labs/flux-2-dev": Base_Ai_Cf_Black_Forest_Labs_Flux_2_Dev;
"@cf/black-forest-labs/flux-2-klein-4b": Base_Ai_Cf_Black_Forest_Labs_Flux_2_Klein_4B;
"@cf/black-forest-labs/flux-2-klein-9b": Base_Ai_Cf_Black_Forest_Labs_Flux_2_Klein_9B;
"@cf/zai-org/glm-4.7-flash": Base_Ai_Cf_Zai_Org_Glm_4_7_Flash;
"@cf/moonshotai/kimi-k2.5": Base_Ai_Cf_Moonshotai_Kimi_K2_5;
"@cf/moonshotai/kimi-k2.6": Base_Ai_Cf_Moonshotai_Kimi_K2_6;
"@cf/nvidia/nemotron-3-120b-a12b": Base_Ai_Cf_Nvidia_Nemotron_3_120B_A12B;
"@cf/google/gemma-4-26b-a4b-it": Base_Ai_Cf_Google_Gemma_4_26B_A4B_IT;
}
type AiOptions = {
/**
@@ -8662,6 +10152,7 @@ type AiOptions = {
returnRawResponse?: boolean;
prefix?: string;
extraHeaders?: object;
signal?: AbortSignal;
};
type AiModelsSearchParams = {
author?: string;
@@ -8688,64 +10179,61 @@ type AiModelsSearchObject = {
value: string;
}[];
};
type ChatCompletionsBase = ChatCompletionsMessagesInput;
type ChatCompletionsInput = ChatCompletionsMessagesInput;
interface InferenceUpstreamError extends Error {
}
interface AiInternalError extends Error {
}
type AiModelListType = Record<string, any>;
type AiAsyncBatchResponse = {
request_id: string;
};
declare abstract class Ai<AiModelList extends AiModelListType = AiModels> {
aiGatewayLogId: string | null;
gateway(gatewayId: string): AiGateway;
/**
* Access the AI Search API for managing AI-powered search instances.
*
* This is the new API that replaces AutoRAG with better namespace separation:
* - Account-level operations: `list()`, `create()`
* - Instance-level operations: `get(id).search()`, `get(id).chatCompletions()`, `get(id).delete()`
*
* @example
* ```typescript
* // List all AI Search instances
* const instances = await env.AI.aiSearch.list();
*
* // Search an instance
* const results = await env.AI.aiSearch.get('my-search').search({
* messages: [{ role: 'user', content: 'What is the policy?' }],
* ai_search_options: {
* retrieval: { max_num_results: 10 }
* }
* });
*
* // Generate chat completions with AI Search context
* const response = await env.AI.aiSearch.get('my-search').chatCompletions({
* messages: [{ role: 'user', content: 'What is the policy?' }],
* model: '@cf/meta/llama-3.3-70b-instruct-fp8-fast'
* });
* ```
* @deprecated Use the standalone `ai_search_namespaces` or `ai_search` Workers bindings instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
aiSearch(): AiSearchAccountService;
aiSearch(): AiSearchNamespace;
/**
* @deprecated AutoRAG has been replaced by AI Search.
* Use `env.AI.aiSearch` instead for better API design and new features.
* Use the standalone `ai_search_namespaces` or `ai_search` Workers bindings instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*
* Migration guide:
* - `env.AI.autorag().list()` `env.AI.aiSearch.list()`
* - `env.AI.autorag('id').search({ query: '...' })` `env.AI.aiSearch.get('id').search({ messages: [{ role: 'user', content: '...' }] })`
* - `env.AI.autorag('id').aiSearch(...)` `env.AI.aiSearch.get('id').chatCompletions(...)`
*
* Note: The old API continues to work for backwards compatibility, but new projects should use AI Search.
*
* @see AiSearchAccountService
* @param autoragId Optional instance ID (omit for account-level operations)
* @param autoragId Instance ID
*/
autorag(autoragId: string): AutoRAG;
run<Name extends keyof AiModelList, Options extends AiOptions, InputOptions extends AiModelList[Name]["inputs"]>(model: Name, inputs: InputOptions, options?: Options): Promise<Options extends {
// Batch request
run<Name extends keyof AiModelList>(model: Name, inputs: {
requests: AiModelList[Name]['inputs'][];
}, options: AiOptions & {
queueRequest: true;
}): Promise<AiAsyncBatchResponse>;
// Raw response
run<Name extends keyof AiModelList>(model: Name, inputs: AiModelList[Name]['inputs'], options: AiOptions & {
returnRawResponse: true;
} | {
}): Promise<Response>;
// WebSocket
run<Name extends keyof AiModelList>(model: Name, inputs: AiModelList[Name]['inputs'], options: AiOptions & {
websocket: true;
} ? Response : InputOptions extends {
}): Promise<Response>;
// Streaming
run<Name extends keyof AiModelList>(model: Name, inputs: AiModelList[Name]['inputs'] & {
stream: true;
} ? ReadableStream : AiModelList[Name]["postProcessedOutputs"]>;
}, options?: AiOptions): Promise<ReadableStream>;
// Normal (default) - known model
run<Name extends keyof AiModelList>(model: Name, inputs: AiModelList[Name]['inputs'], options?: AiOptions): Promise<AiModelList[Name]['postProcessedOutputs']>;
// Unknown model (fallback).
//
// The `Exclude<..., keyof AiModelList>` constraint forces TypeScript to
// route any model name that is a literal key of `AiModelList` to one of
// the known-model overloads above (so input/output mismatches surface as
// type errors rather than silently falling back to `Record<string, unknown>`).
// Names that aren't in `AiModelList` — e.g. third-party gateway models
// like `"google/nano-banana"` — still hit this overload.
run<Model extends string>(model: Model extends keyof AiModelList ? never : Model, inputs: Record<string, unknown>, options?: AiOptions): Promise<Record<string, unknown>>;
models(params?: AiModelsSearchParams): Promise<AiModelsSearchObject[]>;
toMarkdown(): ToMarkdownService;
toMarkdown(files: MarkdownDocument[], options?: ConversionRequestOptions): Promise<ConversionResponse[]>;
@@ -8843,29 +10331,250 @@ declare abstract class AiGateway {
run(data: AIGatewayUniversalRequest | AIGatewayUniversalRequest[], options?: {
gateway?: UniversalGatewayOptions;
extraHeaders?: object;
signal?: AbortSignal;
}): Promise<Response>;
getUrl(provider?: AIGatewayProviders | string): Promise<string>; // eslint-disable-line
}
// Copyright (c) 2022-2025 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0
/**
* @deprecated AutoRAG has been replaced by AI Search. Use AiSearchInternalError instead.
* @see AiSearchInternalError
* Artifacts Git-compatible file storage on Cloudflare Workers.
*
* Provides programmatic access to create, manage, and fork repositories,
* and to issue and revoke scoped access tokens.
*/
/** Information about a repository. */
interface ArtifactsRepoInfo {
/** Unique repository ID. */
id: string;
/** Repository name. */
name: string;
/** Repository description, or null if not set. */
description: string | null;
/** Default branch name (e.g. "main"). */
defaultBranch: string;
/** ISO 8601 creation timestamp. */
createdAt: string;
/** ISO 8601 last-updated timestamp. */
updatedAt: string;
/** ISO 8601 timestamp of the last push, or null if never pushed. */
lastPushAt: string | null;
/** Fork source (e.g. "github:owner/repo", "artifacts:namespace/repo"), or null if not a fork. */
source: string | null;
/** Whether the repository is read-only. */
readOnly: boolean;
/** HTTPS git remote URL. */
remote: string;
}
/** Result of creating a repository — includes the initial access token. */
interface ArtifactsCreateRepoResult {
/** Unique repository ID. */
id: string;
/** Repository name. */
name: string;
/** Repository description, or null if not set. */
description: string | null;
/** Default branch name. */
defaultBranch: string;
/** HTTPS git remote URL. */
remote: string;
/** Plaintext access token (only returned at creation time). */
token: string;
/** ISO 8601 token expiry timestamp. */
tokenExpiresAt: string;
}
/** Paginated list of repositories. */
interface ArtifactsRepoListResult {
/** Repositories in this page (without the `remote` field). */
repos: Omit<ArtifactsRepoInfo, 'remote'>[];
/** Total number of repositories in the namespace. */
total: number;
/** Cursor for the next page, if there are more results. */
cursor?: string;
}
/** Result of creating an access token. */
interface ArtifactsCreateTokenResult {
/** Unique token ID. */
id: string;
/** Plaintext token (only returned at creation time). */
plaintext: string;
/** Token scope: "read" or "write". */
scope: 'read' | 'write';
/** ISO 8601 token expiry timestamp. */
expiresAt: string;
}
/** Token metadata (no plaintext). */
interface ArtifactsTokenInfo {
/** Unique token ID. */
id: string;
/** Token scope: "read" or "write". */
scope: 'read' | 'write';
/** Token state: "active", "expired", or "revoked". */
state: 'active' | 'expired' | 'revoked';
/** ISO 8601 creation timestamp. */
createdAt: string;
/** ISO 8601 expiry timestamp. */
expiresAt: string;
}
/** Paginated list of tokens for a repository. */
interface ArtifactsTokenListResult {
/** Tokens in this page. */
tokens: ArtifactsTokenInfo[];
/** Total number of tokens for the repository. */
total: number;
}
/**
* Handle for a single repository. Returned by Artifacts.get().
*
* Methods may throw `ArtifactsError` with code `INTERNAL_ERROR` if an unexpected service error occurs.
*/
interface ArtifactsRepo extends ArtifactsRepoInfo {
/**
* Create an access token for this repo.
* @param scope Token scope: "write" (default) or "read".
* @param ttl Time-to-live in seconds (default 86400, min 60, max 31536000).
* @throws {ArtifactsError} with code `INVALID_TTL` if ttl is out of range.
*/
createToken(scope?: 'write' | 'read', ttl?: number): Promise<ArtifactsCreateTokenResult>;
/** List tokens for this repo (metadata only, no plaintext). */
listTokens(): Promise<ArtifactsTokenListResult>;
/**
* Revoke a token by plaintext or ID.
* @param tokenOrId Plaintext token or token ID.
* @returns true if revoked, false if not found.
* @throws {ArtifactsError} with code `INVALID_INPUT` if tokenOrId is empty.
*/
revokeToken(tokenOrId: string): Promise<boolean>;
// ── Fork ──
/**
* Fork this repo to a new repo.
* @param name Target repository name.
* @param opts Optional: description, readOnly flag, defaultBranchOnly (default true).
* @throws {ArtifactsError} with code `INVALID_REPO_NAME` if name is invalid.
* @throws {ArtifactsError} with code `ALREADY_EXISTS` if the target repo already exists.
* @throws {ArtifactsError} with code `FORK_IN_PROGRESS` if a fork is already running.
*/
fork(name: string, opts?: {
description?: string;
readOnly?: boolean;
defaultBranchOnly?: boolean;
}): Promise<ArtifactsCreateRepoResult>;
}
// ── Error types ──────────────────────────────────────────────────────────────
/**
* Error codes returned by Artifacts binding operations.
*
* Each code maps to a numeric code available on `ArtifactsError.numericCode`.
*/
type ArtifactsErrorCode = 'ALREADY_EXISTS' | 'NOT_FOUND' | 'IMPORT_IN_PROGRESS' | 'FORK_IN_PROGRESS' | 'INVALID_INPUT' | 'INVALID_REPO_NAME' | 'INVALID_TTL' | 'INVALID_URL' | 'REMOTE_AUTH_REQUIRED' | 'UPSTREAM_UNAVAILABLE' | 'MEMORY_LIMIT' | 'INTERNAL_ERROR';
/**
* Error thrown by Artifacts binding operations.
*
* Uses a string `.code` discriminator following the Cloudflare platform
* convention (StreamError, ImagesError, etc.). The `.numericCode` matches
* the REST API `errors[].code` values.
*/
interface ArtifactsError extends Error {
readonly name: 'ArtifactsError';
/** String error code for programmatic matching. */
readonly code: ArtifactsErrorCode;
/** Numeric error code matching the REST API. */
readonly numericCode: number;
}
// ── Binding ──────────────────────────────────────────────────────────────────
/**
* Artifacts binding namespace-level operations.
*
* Methods may throw `ArtifactsError` with code `INTERNAL_ERROR` if an unexpected service error occurs.
*/
interface Artifacts {
/**
* Create a new repository with an initial access token.
* @param name Repository name (alphanumeric, dots, hyphens, underscores).
* @param opts Optional: readOnly flag, description, default branch name.
* @returns Repo metadata with initial token.
* @throws {ArtifactsError} with code `INVALID_REPO_NAME` if name is invalid.
* @throws {ArtifactsError} with code `ALREADY_EXISTS` if the repo already exists.
*/
create(name: string, opts?: {
readOnly?: boolean;
description?: string;
setDefaultBranch?: string;
}): Promise<ArtifactsCreateRepoResult>;
/**
* Get a handle to an existing repository.
* @param name Repository name.
* @returns Repo handle.
* @throws {ArtifactsError} with code `NOT_FOUND` if the repo does not exist.
* @throws {ArtifactsError} with code `IMPORT_IN_PROGRESS` if the repo is still importing.
* @throws {ArtifactsError} with code `FORK_IN_PROGRESS` if the repo is still forking.
*/
get(name: string): Promise<ArtifactsRepo>;
/**
* Import a repository from an external git remote.
* @param params Source URL and optional branch/depth, plus target name and options.
* @returns Repo metadata with initial token.
* @throws {ArtifactsError} with code `INVALID_REPO_NAME` if the target name is invalid.
* @throws {ArtifactsError} with code `INVALID_INPUT` if the source URL is not valid HTTPS.
* @throws {ArtifactsError} with code `INVALID_URL` if the source URL does not point to a git repository.
* @throws {ArtifactsError} with code `REMOTE_AUTH_REQUIRED` if the remote requires authentication.
* @throws {ArtifactsError} with code `NOT_FOUND` if the remote repository does not exist.
* @throws {ArtifactsError} with code `UPSTREAM_UNAVAILABLE` if the remote cannot be reached.
* @throws {ArtifactsError} with code `MEMORY_LIMIT` if the import exceeds service memory limits.
* @throws {ArtifactsError} with code `ALREADY_EXISTS` if the target repo already exists.
*/
import(params: {
source: {
url: string;
branch?: string;
depth?: number;
};
target: {
name: string;
opts?: {
description?: string;
readOnly?: boolean;
};
};
}): Promise<ArtifactsCreateRepoResult>;
/**
* List repositories with cursor-based pagination.
* @param opts Optional: limit (1200, default 50), cursor for next page.
*/
list(opts?: {
limit?: number;
cursor?: string;
}): Promise<ArtifactsRepoListResult>;
/**
* Delete a repository and all associated tokens.
* @param name Repository name.
* @returns true if deleted, false if not found.
* @throws {ArtifactsError} with code `INVALID_REPO_NAME` if name is invalid.
*/
delete(name: string): Promise<boolean>;
}
/**
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
interface AutoRAGInternalError extends Error {
}
/**
* @deprecated AutoRAG has been replaced by AI Search. Use AiSearchNotFoundError instead.
* @see AiSearchNotFoundError
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
interface AutoRAGNotFoundError extends Error {
}
/**
* @deprecated This error type is no longer used in the AI Search API.
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
interface AutoRAGUnauthorizedError extends Error {
}
/**
* @deprecated AutoRAG has been replaced by AI Search. Use AiSearchNameNotSetError instead.
* @see AiSearchNameNotSetError
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
interface AutoRAGNameNotSetError extends Error {
}
@@ -8879,9 +10588,8 @@ type CompoundFilter = {
filters: ComparisonFilter[];
};
/**
* @deprecated AutoRAG has been replaced by AI Search.
* Use AiSearchSearchRequest with the new API instead.
* @see AiSearchSearchRequest
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
type AutoRagSearchRequest = {
query: string;
@@ -8898,26 +10606,23 @@ type AutoRagSearchRequest = {
rewrite_query?: boolean;
};
/**
* @deprecated AutoRAG has been replaced by AI Search.
* Use AiSearchChatCompletionsRequest with the new API instead.
* @see AiSearchChatCompletionsRequest
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
type AutoRagAiSearchRequest = AutoRagSearchRequest & {
stream?: boolean;
system_prompt?: string;
};
/**
* @deprecated AutoRAG has been replaced by AI Search.
* Use AiSearchChatCompletionsRequest with stream: true instead.
* @see AiSearchChatCompletionsRequest
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
type AutoRagAiSearchRequestStreaming = Omit<AutoRagAiSearchRequest, 'stream'> & {
stream: true;
};
/**
* @deprecated AutoRAG has been replaced by AI Search.
* Use AiSearchSearchResponse with the new API instead.
* @see AiSearchSearchResponse
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
type AutoRagSearchResponse = {
object: 'vector_store.search_results.page';
@@ -8936,9 +10641,8 @@ type AutoRagSearchResponse = {
next_page: string | null;
};
/**
* @deprecated AutoRAG has been replaced by AI Search.
* Use AiSearchListResponse with the new API instead.
* @see AiSearchListResponse
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
type AutoRagListResponse = {
id: string;
@@ -8950,123 +10654,488 @@ type AutoRagListResponse = {
status: string;
}[];
/**
* @deprecated AutoRAG has been replaced by AI Search.
* The new API returns different response formats for chat completions.
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
type AutoRagAiSearchResponse = AutoRagSearchResponse & {
response: string;
};
/**
* @deprecated AutoRAG has been replaced by AI Search.
* Use the new AI Search API instead: `env.AI.aiSearch`
*
* Migration guide:
* - `env.AI.autorag().list()` `env.AI.aiSearch.list()`
* - `env.AI.autorag('id').search(...)` `env.AI.aiSearch.get('id').search(...)`
* - `env.AI.autorag('id').aiSearch(...)` `env.AI.aiSearch.get('id').chatCompletions(...)`
*
* @see AiSearchAccountService
* @see AiSearchInstanceService
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
declare abstract class AutoRAG {
/**
* @deprecated Use `env.AI.aiSearch.list()` instead.
* @see AiSearchAccountService.list
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
list(): Promise<AutoRagListResponse>;
/**
* @deprecated Use `env.AI.aiSearch.get(id).search(...)` instead.
* Note: The new API uses a messages array instead of a query string.
* @see AiSearchInstanceService.search
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
search(params: AutoRagSearchRequest): Promise<AutoRagSearchResponse>;
/**
* @deprecated Use `env.AI.aiSearch.get(id).chatCompletions(...)` instead.
* @see AiSearchInstanceService.chatCompletions
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
aiSearch(params: AutoRagAiSearchRequestStreaming): Promise<Response>;
/**
* @deprecated Use `env.AI.aiSearch.get(id).chatCompletions(...)` instead.
* @see AiSearchInstanceService.chatCompletions
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
aiSearch(params: AutoRagAiSearchRequest): Promise<AutoRagAiSearchResponse>;
/**
* @deprecated Use `env.AI.aiSearch.get(id).chatCompletions(...)` instead.
* @see AiSearchInstanceService.chatCompletions
* @deprecated Use the standalone AI Search Workers binding instead.
* See https://developers.cloudflare.com/ai-search/usage/workers-binding/
*/
aiSearch(params: AutoRagAiSearchRequest): Promise<AutoRagAiSearchResponse | Response>;
}
interface BasicImageTransformations {
/**
* Maximum width in image pixels. The value must be an integer.
type BrowserRunLifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';
type BrowserRunResourceType = 'document' | 'stylesheet' | 'image' | 'media' | 'font' | 'script' | 'texttrack' | 'xhr' | 'fetch' | 'prefetch' | 'eventsource' | 'websocket' | 'manifest' | 'signedexchange' | 'ping' | 'cspviolationreport' | 'preflight' | 'other';
/** Options fields shared by all quick actions. */
interface BrowserRunBaseOptions {
/** Adds `<script>` tags into the page with the desired URL or content.
* @see https://pptr.dev/api/puppeteer.frameaddscripttagoptions
*/
width?: number;
/**
* Maximum height in image pixels. The value must be an integer.
addScriptTag?: Array<{
content?: string;
url?: string;
type?: string;
id?: string;
}>;
/** Adds `<link rel="stylesheet">` or `<style>` tags into the page.
* @see https://pptr.dev/api/puppeteer.frameaddstyletagoptions
*/
height?: number;
/**
* Resizing mode as a string. It affects interpretation of width and height
* options:
* - scale-down: Similar to contain, but the image is never enlarged. If
* the image is larger than given width or height, it will be resized.
* Otherwise its original size will be kept.
* - contain: Resizes to maximum size that fits within the given width and
* height. If only a single dimension is given (e.g. only width), the
* image will be shrunk or enlarged to exactly match that dimension.
* Aspect ratio is always preserved.
* - cover: Resizes (shrinks or enlarges) to fill the entire area of width
* and height. If the image has an aspect ratio different from the ratio
* of width and height, it will be cropped to fit.
* - crop: The image will be shrunk and cropped to fit within the area
* specified by width and height. The image will not be enlarged. For images
* smaller than the given dimensions it's the same as scale-down. For
* images larger than the given dimensions, it's the same as cover.
* See also trim.
* - pad: Resizes to the maximum size that fits within the given width and
* height, and then fills the remaining area with a background color
* (white by default). Use of this mode is not recommended, as the same
* effect can be more efficiently achieved with the contain mode and the
* CSS object-fit: contain property.
* - squeeze: Stretches and deforms to the width and height given, even if it
* breaks aspect ratio
addStyleTag?: Array<{
content?: string;
url?: string;
}>;
/** Provide credentials for HTTP authentication. @see https://pptr.dev/api/puppeteer.credentials */
authenticate?: {
username: string;
password: string;
};
/** Set cookies before navigating. @see https://pptr.dev/api/puppeteer.cookieparam */
cookies?: Array<{
name: string;
value: string;
url?: string;
domain?: string;
path?: string;
secure?: boolean;
httpOnly?: boolean;
sameSite?: 'Strict' | 'Lax' | 'None';
expires?: number;
priority?: 'Low' | 'Medium' | 'High';
sameParty?: boolean;
sourceScheme?: 'Unset' | 'NonSecure' | 'Secure';
sourcePort?: number;
partitionKey?: string;
}>;
/** Emulate a specific CSS media type (e.g. `"screen"`, `"print"`). */
emulateMediaType?: string;
/** Navigation options. @see https://pptr.dev/api/puppeteer.gotooptions */
gotoOptions?: {
/** Navigation timeout in milliseconds (max 60 000). @default 30000 */
timeout?: number;
/** When to consider navigation complete. @default "domcontentloaded" */
waitUntil?: BrowserRunLifecycleEvent | BrowserRunLifecycleEvent[];
referer?: string;
referrerPolicy?: string;
};
/** Block requests matching these regex patterns. Mutually exclusive with `allowRequestPattern`. */
rejectRequestPattern?: string[];
/** Only allow requests matching these regex patterns. Mutually exclusive with `rejectRequestPattern`. */
allowRequestPattern?: string[];
/** Block requests of these resource types. Mutually exclusive with `allowResourceTypes`. */
rejectResourceTypes?: BrowserRunResourceType[];
/** Only allow requests of these resource types. Mutually exclusive with `rejectResourceTypes`. */
allowResourceTypes?: BrowserRunResourceType[];
/** Additional HTTP headers sent with every request. */
setExtraHTTPHeaders?: Record<string, string>;
/** Whether JavaScript is enabled on the page. */
setJavaScriptEnabled?: boolean;
/** Override the default user agent string.
* @default "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
* */
userAgent?: string;
/** Set the browser viewport size.
* @see https://pptr.dev/api/puppeteer.viewport
* @default {width:1920,height:1080}
* */
viewport?: {
width: number;
height: number;
deviceScaleFactor?: number;
isMobile?: boolean;
isLandscape?: boolean;
hasTouch?: boolean;
};
/** Wait for a CSS selector to appear in the page before proceeding.
* @see https://pptr.dev/api/puppeteer.waitforselectoroptions
*/
fit?: "scale-down" | "contain" | "cover" | "crop" | "pad" | "squeeze";
/**
* Image segmentation using artificial intelligence models. Sets pixels not
* within selected segment area to transparent e.g "foreground" sets every
* background pixel as transparent.
waitForSelector?: {
selector: string;
hidden?: true;
visible?: true;
/** Timeout in milliseconds. Max 120000 */
timeout?: number;
};
/** Wait for a fixed delay in milliseconds before proceeding. Max 120000 */
waitForTimeout?: number;
/** When true, continue on best-effort when awaited events fail or timeout. */
bestAttempt?: boolean;
/** Maximum duration in milliseconds for the browser action after page load. Max 120000 */
actionTimeout?: number;
/** Cache time to live in seconds (0-86400). Set to 0 to disable.
* @default 5
*/
segment?: "foreground";
/**
* When cropping with fit: "cover", this defines the side or point that should
* be left uncropped. The value is either a string
* "left", "right", "top", "bottom", "auto", or "center" (the default),
* or an object {x, y} containing focal point coordinates in the original
* image expressed as fractions ranging from 0.0 (top or left) to 1.0
* (bottom or right), 0.5 being the center. {fit: "cover", gravity: "top"} will
* crop bottom or left and right sides as necessary, but wont crop anything
* from the top. {fit: "cover", gravity: {x:0.5, y:0.2}} will crop each side to
* preserve as much as possible around a point at 20% of the height of the
* source image.
*/
gravity?: 'face' | 'left' | 'right' | 'top' | 'bottom' | 'center' | 'auto' | 'entropy' | BasicImageTransformationsGravityCoordinates;
/**
* Background color to add underneath the image. Applies only to images with
* transparency (such as PNG). Accepts any CSS color (#RRGGBB, rgba(),
* hsl(), etc.)
*/
background?: string;
/**
* Number of degrees (90, 180, 270) to rotate the image by. width and height
* options refer to axes after rotation.
*/
rotate?: 0 | 90 | 180 | 270 | 360;
cacheTTL?: number;
}
interface BasicImageTransformationsGravityCoordinates {
x?: number;
y?: number;
mode?: 'remainder' | 'box-center';
/** Common options shared by all quick actions. Exactly one of `url` or `html` must be provided.*/
type BrowserRunCommonOptions = (BrowserRunBaseOptions & {
/** URL to navigate to, e.g. `"https://example.com"`. */
url: string;
}) | (BrowserRunBaseOptions & {
/** Set the HTML content of the page directly. */
html: string;
});
type BrowserRunPuppeteerScreenshotOptions = {
/** @default "png" */
type?: 'png' | 'jpeg' | 'webp';
/** @default "binary" */
encoding?: 'binary' | 'base64';
quality?: number;
fullPage?: boolean;
clip?: {
x: number;
y: number;
width: number;
height: number;
scale?: number;
};
omitBackground?: boolean;
optimizeForSpeed?: boolean;
captureBeyondViewport?: boolean;
fromSurface?: boolean;
};
type BrowserRunScreenshotOptions = BrowserRunCommonOptions & {
/** CSS selector of the element to screenshot. */
selector?: string;
/** When true, scroll the entire page before taking the screenshot. */
scrollPage?: boolean;
/** @see https://pptr.dev/api/puppeteer.screenshotoptions */
screenshotOptions?: BrowserRunPuppeteerScreenshotOptions;
};
type BrowserRunPDFOptions = BrowserRunCommonOptions & {
/** @see https://pptr.dev/api/puppeteer.pdfoptions */
pdfOptions?: {
/** @default 1 */
scale?: number;
/** @default false */
displayHeaderFooter?: boolean;
headerTemplate?: string;
footerTemplate?: string;
/** @default false */
printBackground?: boolean;
/** @default false */
landscape?: boolean;
pageRanges?: string;
/** @default "letter" */
format?: 'letter' | 'legal' | 'tabloid' | 'ledger' | 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5' | 'a6';
width?: string | number;
height?: string | number;
/** @default false */
preferCSSPageSize?: boolean;
margin?: {
top?: string | number;
right?: string | number;
bottom?: string | number;
left?: string | number;
};
/** @default false */
omitBackground?: boolean;
/** @default true */
tagged?: boolean;
/** @default false */
outline?: boolean;
/** @default 30000 */
timeout?: number;
};
};
type BrowserRunScrapeOptions = BrowserRunCommonOptions & {
/** CSS selectors to scrape. At least one element is required. */
elements: Array<{
selector: string;
}>;
};
type BrowserRunLinksOptions = BrowserRunCommonOptions & {
/** When true, only return links that are visible on the page. @default false */
visibleLinksOnly?: boolean;
/** When true, exclude links pointing to external domains. @default false */
excludeExternalLinks?: boolean;
};
type BrowserRunSnapshotOptions = BrowserRunCommonOptions & {
/** @see https://pptr.dev/api/puppeteer.screenshotoptions */
screenshotOptions?: Omit<BrowserRunPuppeteerScreenshotOptions, 'encoding'>;
};
interface BrowserRunJsonBaseOptions {
/** Custom AI models to try in order. Max 3. Falls back to next on error. */
custom_ai?: Array<{
/** Model ID in `<provider>/<model_name>` format, e.g. `"workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast"`. */
model: string;
/** Bearer token. Not needed for workers-ai models. */
authorization?: string;
}>;
}
/**
* Options for the `json` quick action.
* At least one of `prompt` or `response_format` must be provided.
*/
type BrowserRunJsonOptions = BrowserRunCommonOptions & BrowserRunJsonBaseOptions & ({
/** Natural-language prompt describing what data to extract. */
prompt: string;
/** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */
response_format?: AiTextGenerationResponseFormat;
} | {
/** Natural-language prompt describing what data to extract. */
prompt?: string;
/** Structured output schema for the AI model. @see https://developers.cloudflare.com/workers-ai/json-mode/ */
response_format: AiTextGenerationResponseFormat;
});
type BrowserRunContentOptions = BrowserRunCommonOptions;
type BrowserRunMarkdownOptions = BrowserRunCommonOptions;
type BrowserRunResponseMeta = {
/** HTTP status code of the rendered page */
status: number;
/** Page title */
title: string;
};
/** Success response for `content` action. */
type BrowserRunContentSuccessResponse = {
success: true;
/** Extracted HTML content */
result: string;
meta: BrowserRunResponseMeta;
};
/** Success response for `links` action. */
type BrowserRunLinksSuccessResponse = {
success: true;
/** Extracted links */
result: string[];
};
/** Success response for `scrape` action. */
type BrowserRunScrapeSuccessResponse = {
success: true;
result: Array<{
/** The CSS selector used to find elements. */
selector: string;
/** Array of elements matching the selector. */
results: Array<{
/** Outer HTML of the element. */
html: string;
/** Text content of the element. */
text: string;
/** Width of the element in pixels. */
width: number;
/** Height of the element in pixels. */
height: number;
/** Top position of the element relative to the viewport in pixels. */
top: number;
/** Left position of the element relative to the viewport in pixels. */
left: number;
/** Array of HTML attributes on the element. */
attributes: Array<{
/** Attribute name. */
name: string;
/** Attribute value. */
value: string;
}>;
}>;
}>;
};
/** Success response for `snapshot` action. */
type BrowserRunSnapshotSuccessResponse = {
success: true;
result: {
/** HTML content of the page. */
content: string;
/** Base64-encoded screenshot image. */
screenshot: string;
};
meta: BrowserRunResponseMeta;
};
/** Success response for `json` action. */
type BrowserRunJsonSuccessResponse = {
success: true;
/** JSON data extracted from the page using an AI model */
result: Record<string, unknown>;
};
/** Success response for `markdown` action. */
type BrowserRunMarkdownSuccessResponse = {
success: true;
/** Extracted markdown content */
result: string;
};
/** Error response for BrowserRun actions. */
type BrowserRunErrorResponse = {
success: false;
errors: {
message: string;
code?: number;
detail?: string;
path?: string;
}[];
};
/** Error response for BrowserRun `json` action. */
type BrowserRunJsonErrorResponse = BrowserRunErrorResponse & {
/** Raw AI response text for debugging */
rawAiResponse?: string;
};
/**
* Browser Run API binding for automating headless browsers.
* @see https://developers.cloudflare.com/browser-run/
*/
declare abstract class BrowserRun {
/**
* Send a raw HTTP request to the Browser Run API.
* Used by libraries like `@cloudflare/puppeteer` to acquire and connect to a browser instance.
* @see https://developers.cloudflare.com/browser-run/
*/
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
/**
* Take a screenshot of a web page.
* @param action - Must be `'screenshot'`.
* @param options - Screenshot options including viewport, selectors, and image format.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - Binary image data with `Content-Type: image/png`, `image/jpeg`, or `image/webp` (when `encoding: 'binary'`, the default)
* - Data URI string with `Content-Type: text/plain` (when `encoding: 'base64'`)
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'screenshot', options: BrowserRunScreenshotOptions): Promise<Response>;
/**
* Generate a PDF of a web page.
* @param action - Must be `'pdf'`.
* @param options - PDF generation options including page size, margins, and headers/footers.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - Binary PDF data with `Content-Type: application/pdf`
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'pdf', options: BrowserRunPDFOptions): Promise<Response>;
/**
* Get the HTML content of a web page.
* @param action - Must be `'content'`.
* @param options - Navigation and page interaction options.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - `BrowserRunContentSuccessResponse` JSON with `Content-Type: application/json`
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'content', options: BrowserRunContentOptions): Promise<Response>;
/**
* Scrape elements from a web page by CSS selector.
* @param action - Must be `'scrape'`.
* @param options - Scrape options with CSS selectors for elements to extract.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - `BrowserRunScrapeSuccessResponse` JSON with `Content-Type: application/json`
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'scrape', options: BrowserRunScrapeOptions): Promise<Response>;
/**
* Extract all links from a web page.
* @param action - Must be `'links'`.
* @param options - Options to filter visible or internal links only.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - `BrowserRunLinksSuccessResponse` JSON with `Content-Type: application/json`
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'links', options: BrowserRunLinksOptions): Promise<Response>;
/**
* Get both the HTML content and a base64-encoded screenshot of a web page.
* @param action - Must be `'snapshot'`.
* @param options - Snapshot options including screenshot settings (encoding is always base64).
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - `BrowserRunSnapshotSuccessResponse` JSON with `Content-Type: application/json`
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'snapshot', options: BrowserRunSnapshotOptions): Promise<Response>;
/**
* Extract structured JSON data from a web page using AI.
* @param action - Must be `'json'`.
* @param options - JSON extraction options with prompt or response_format schema.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - `BrowserRunJsonSuccessResponse` JSON with `Content-Type: application/json`
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
* - HTTP 422 with code `2012` for HTML-to-markdown conversion failures
* - HTTP 422/500 for AI extraction failures (may include `rawAiResponse` field)
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'json', options: BrowserRunJsonOptions): Promise<Response>;
/**
* Convert a web page to Markdown.
* @param action - Must be `'markdown'`.
* @param options - Navigation and page interaction options.
* @returns A `Response` containing one of:
*
* **Success (HTTP 200):**
* - `BrowserRunMarkdownSuccessResponse` JSON with `Content-Type: application/json`
*
* **Error:**
* - `BrowserRunErrorResponse` JSON with appropriate HTTP status code (400, 422, 429, 500, 503)
* - HTTP 422 with code `2012` for HTML-to-markdown conversion failures
*
* **Headers:**
* - `X-Browser-Ms-Used`: Browser time consumed in milliseconds (set when status < 500)
*/
quickAction(action: 'markdown', options: BrowserRunMarkdownOptions): Promise<Response>;
}
/**
* In addition to the properties you can set in the RequestInit dict
@@ -9106,8 +11175,56 @@ interface RequestInitCfProperties extends Record<string, unknown> {
* (e.g. { '200-299': 86400, '404': 1, '500-599': 0 })
*/
cacheTtlByStatus?: Record<string, number>;
/** Controls how responses with a `Vary` header are cached for this request. */
vary?: RequestInitCfPropertiesVary;
/**
* Explicit Cache-Control header value to set on the response stored in cache.
* This gives full control over cache directives (e.g. 'public, max-age=3600, s-maxage=86400').
*
* Cannot be used together with `cacheTtl` or the `cache` request option (`no-store`/`no-cache`),
* as these are mutually exclusive cache control mechanisms. Setting both will throw a TypeError.
*
* Can be used together with `cacheTtlByStatus`.
*/
cacheControl?: string;
/**
* Whether the response should be eligible for Cache Reserve storage.
*/
cacheReserveEligible?: boolean;
/**
* Whether to respect strong ETags (as opposed to weak ETags) from the origin.
*/
respectStrongEtag?: boolean;
/**
* Whether to strip ETag headers from the origin response before caching.
*/
stripEtags?: boolean;
/**
* Whether to strip Last-Modified headers from the origin response before caching.
*/
stripLastModified?: boolean;
/**
* Whether to enable Cache Deception Armor, which protects against web cache
* deception attacks by verifying the Content-Type matches the URL extension.
*/
cacheDeceptionArmor?: boolean;
/**
* Minimum file size in bytes for a response to be eligible for Cache Reserve storage.
*/
cacheReserveMinimumFileSize?: number;
scrapeShield?: boolean;
apps?: boolean;
/**
* Controls whether an outbound gRPC-web subrequest from this Worker is
* converted to gRPC at the Cloudflare edge.
*
* - `"passthrough"`: forward the subrequest unchanged as gRPC-web (default).
* - `"convert"`: convert the gRPC-web subrequest to gRPC at the edge.
*
* Provides per-request control over the same edge conversion behavior
* gated by the `auto_grpc_convert` compatibility flag.
*/
grpcWeb?: "passthrough" | "convert";
image?: RequestInitCfPropertiesImage;
minify?: RequestInitCfPropertiesImageMinify;
mirage?: boolean;
@@ -9128,49 +11245,122 @@ interface RequestInitCfProperties extends Record<string, unknown> {
*/
resolveOverride?: string;
}
interface RequestInitCfPropertiesImageDraw extends BasicImageTransformations {
/**
* Controls how Workers Standard Vary handles a request header listed by an
* origin `Vary` response header:
*
* - `"normalize"`: normalize the request header value before it is used in the
* cache variance key.
* - `"passthrough"`: use the raw request header value in the cache variance
* key.
* - `"bypass"`: bypass cache when the header appears in the origin `Vary`
* response header.
*/
type RequestInitCfPropertiesVaryAction = "normalize" | "passthrough" | "bypass";
/** Configuration for Workers Standard Vary support. */
interface RequestInitCfPropertiesVary {
/** The fallback action for varied request headers not listed in `headers`. */
default: RequestInitCfPropertiesVaryHeader;
/**
* Absolute URL of the image file to use for the drawing. It can be any of
* the supported file formats. For drawing of watermarks or non-rectangular
* overlays we recommend using PNG or WebP images.
*/
url: string;
/**
* Floating-point number between 0 (transparent) and 1 (opaque).
* For example, opacity: 0.5 makes overlay semitransparent.
*/
opacity?: number;
/**
* - If set to true, the overlay image will be tiled to cover the entire
* area. This is useful for stock-photo-like watermarks.
* - If set to "x", the overlay image will be tiled horizontally only
* (form a line).
* - If set to "y", the overlay image will be tiled vertically only
* (form a line).
*/
repeat?: true | "x" | "y";
/**
* Position of the overlay image relative to a given edge. Each property is
* an offset in pixels. 0 aligns exactly to the edge. For example, left: 10
* positions left side of the overlay 10 pixels from the left edge of the
* image it's drawn over. bottom: 0 aligns bottom of the overlay with bottom
* of the background image.
* Lowercase request header names and their Vary configuration.
*
* Setting both left & right, or both top & bottom is an error.
*
* If no position is specified, the image will be centered.
* The `accept` header can include `media_types`, the `accept-language`
* header can include `languages`, and other headers support only `action`.
*/
top?: number;
left?: number;
bottom?: number;
right?: number;
headers?: RequestInitCfPropertiesVaryHeaders;
}
interface RequestInitCfPropertiesImage extends BasicImageTransformations {
/** Common Vary behavior for a single request header. */
interface RequestInitCfPropertiesVaryHeader {
/** How this request header contributes to cache variance. */
action: RequestInitCfPropertiesVaryAction;
}
/** Vary behavior for the `accept` request header. */
interface RequestInitCfPropertiesVaryAcceptHeader extends RequestInitCfPropertiesVaryHeader {
/**
* Device Pixel Ratio. Default 1. Multiplier for width/height that makes it
* easier to specify higher-DPI sizes in <img srcset>.
* Media types to keep when normalizing the `Accept` request header.
*
* Named `media_types` to match the serialized `cf.vary` configuration.
*/
dpr?: number;
media_types?: string[];
}
/** Vary behavior for the `accept-language` request header. */
interface RequestInitCfPropertiesVaryAcceptLanguageHeader extends RequestInitCfPropertiesVaryHeader {
/**
* Language tags to keep when normalizing the `Accept-Language` request
* header.
*/
languages?: string[];
}
/**
* Lowercase request header names and their Vary behavior.
*
* The index signature allows arbitrary custom request headers beyond the
* well-known `accept` and `accept-language` specializations.
*/
interface RequestInitCfPropertiesVaryHeaders {
accept?: RequestInitCfPropertiesVaryAcceptHeader;
"accept-language"?: RequestInitCfPropertiesVaryAcceptLanguageHeader;
[header: string]: RequestInitCfPropertiesVaryHeader | RequestInitCfPropertiesVaryAcceptHeader | RequestInitCfPropertiesVaryAcceptLanguageHeader | undefined;
}
interface BasicImageTransformations {
/**
* Maximum width in image pixels. The value must be an integer.
*/
width?: number;
/**
* Maximum height in image pixels. The value must be an integer.
*/
height?: number;
/**
* When cropping with fit: "cover", this defines the side or point that should
* be left uncropped. The value is either a string
* "left", "right", "top", "bottom", "auto", or "center" (the default),
* or an object {x, y} containing focal point coordinates in the original
* image expressed as fractions ranging from 0.0 (top or left) to 1.0
* (bottom or right), 0.5 being the center. {fit: "cover", gravity: "top"} will
* crop bottom or left and right sides as necessary, but wont crop anything
* from the top. {fit: "cover", gravity: {x:0.5, y:0.2}} will crop each side to
* preserve as much as possible around a point at 20% of the height of the
* source image.
*/
gravity?: 'face' | 'left' | 'right' | 'top' | 'bottom' | 'center' | 'auto' | 'entropy' | BasicImageTransformationsGravityCoordinates;
/**
* Specifies how closely the image is cropped toward detected faces when combined
* with the gravity=face option. Accepts a valid range between 0.0 (includes as much
* of the background as possible) and 1.0 (crops the image as closely to the face as
* possible). The default is 0.
*/
zoom?: number;
/**
* Resizing mode as a string. It affects interpretation of width and height
* options:
* - scale-down: Similar to contain, but the image is never enlarged. If
* the image is larger than given width or height, it will be resized.
* Otherwise its original size will be kept.
* - scale-up: Similar to contain, but the image is never shrunk. If the
* image is smaller than the given width or height, it will be resized.
* Otherwise its original size will be kept.
* - contain: Resizes to maximum size that fits within the given width and
* height. If only a single dimension is given (e.g. only width), the
* image will be shrunk or enlarged to exactly match that dimension.
* Aspect ratio is always preserved.
* - cover: Resizes (shrinks or enlarges) to fill the entire area of width
* and height. If the image has an aspect ratio different from the ratio
* of width and height, it will be cropped to fit.
* - crop: The image will be shrunk and cropped to fit within the area
* specified by width and height. The image will not be enlarged. For images
* smaller than the given dimensions it's the same as scale-down. For
* images larger than the given dimensions, it's the same as cover.
* See also trim.
* - pad: Resizes to the maximum size that fits within the given width and
* height, and then fills the remaining area with a background color
* (white by default). Use of this mode is not recommended, as the same
* effect can be more efficiently achieved with the contain mode and the
* CSS object-fit: contain property.
* - squeeze: Stretches and deforms to the width and height given, even if it
* breaks aspect ratio
*/
fit?: "scale-down" | "scale-up" | "contain" | "cover" | "crop" | "pad" | "squeeze";
/**
* Allows you to trim your image. Takes dpr into account and is performed before
* resizing or rotation.
@@ -9199,6 +11389,154 @@ interface RequestInitCfPropertiesImage extends BasicImageTransformations {
keep?: number;
};
};
/**
* Background color to add underneath the image. Applies only to images with
* transparency (such as PNG). Accepts any CSS color (#RRGGBB, rgba(),
* hsl(), etc.)
*/
background?: string;
/**
* Flips the images horizontally, vertically, or both. Flipping is applied before
* rotation, so if you apply flip=h,rotate=90 then the image will be flipped
* horizontally, then rotated by 90 degrees.
*/
flip?: 'h' | 'v' | 'hv';
/**
* Number of degrees (90, 180, 270) to rotate the image by. width and height
* options refer to axes after rotation.
*/
rotate?: 0 | 90 | 180 | 270 | 360;
/**
* Strength of sharpening filter to apply to the image. Floating-point
* number between 0 (no sharpening, default) and 10 (maximum). 1.0 is a
* recommended value for downscaled images.
*/
sharpen?: number;
/**
* Radius of a blur filter (approximate gaussian). Maximum supported radius
* is 250.
*/
blur?: number;
/**
* Increase contrast by a factor. A value of 1.0 equals no change, a value of
* 0.5 equals low contrast, and a value of 2.0 equals high contrast. 0 is
* ignored.
*/
contrast?: number;
/**
* Increase brightness by a factor. A value of 1.0 equals no change, a value
* of 0.5 equals half brightness, and a value of 2.0 equals twice as bright.
* 0 is ignored.
*/
brightness?: number;
/**
* Increase exposure by a factor. A value of 1.0 equals no change, a value of
* 0.5 darkens the image, and a value of 2.0 lightens the image. 0 is ignored.
*/
gamma?: number;
/**
* Increase contrast by a factor. A value of 1.0 equals no change, a value of
* 0.5 equals low contrast, and a value of 2.0 equals high contrast. 0 is
* ignored.
*/
saturation?: number;
/**
* Device Pixel Ratio. Default 1. Multiplier for width/height that makes it
* easier to specify higher-DPI sizes in <img srcset>.
*/
dpr?: number;
/**
* Adds a border around the image. The border is added after resizing. Border
* width takes dpr into account, and can be specified either using a single
* width property, or individually for each side.
*/
border?: {
color: string;
width: number;
} | {
color: string;
top: number;
right: number;
bottom: number;
left: number;
};
/**
* Image segmentation using artificial intelligence models. Sets pixels not
* within selected segment area to transparent e.g "foreground" sets every
* background pixel as transparent.
*/
segment?: "foreground";
/**
* Controls the algorithm used when an image needs to be enlarged. This
* parameter works with any fit mode that upscales, such as `contain`,
* `cover`, and `scale-up`. It has no effect when `fit=scale-down` or when
* the target dimensions are smaller than the source.
* - interpolate: Uses bicubic interpolation, which may reduce image quality.
* This is the default behavior when `upscale` is not specified.
* - generate: Uses AI upscaling to produce sharper, more detailed results
* when enlarging images.
*/
upscale?: "interpolate" | "generate";
}
interface BasicImageTransformationsGravityCoordinates {
x?: number;
y?: number;
mode?: 'remainder' | 'box-center';
}
interface RequestInitCfPropertiesImageDraw extends BasicImageTransformations {
/**
* Absolute URL of the image file to use for the drawing. It can be any of
* the supported file formats. For drawing of watermarks or non-rectangular
* overlays we recommend using PNG or WebP images.
*/
url: string;
/**
* Floating-point number between 0 (transparent) and 1 (opaque).
* For example, opacity: 0.5 makes overlay semitransparent.
*/
opacity?: number;
/**
* - If set to true, the overlay image will be tiled to cover the entire
* area. This is useful for stock-photo-like watermarks.
* - If set to "x", the overlay image will be tiled horizontally only
* (form a line).
* - If set to "y", the overlay image will be tiled vertically only
* (form a line).
*/
repeat?: true | "x" | "y";
/**
* How to combine the foreground and backdrop pixels to create the result
*/
composite?:
/** Foreground drawn on top of backdrop (default) */
'over'
/** Foreground shown only where backdrop is opaque */
| 'in'
/** Foreground drawn on top, but clipped to the backdrop's shape */
| 'atop'
/** Foreground shown only where backdrop is transparent */
| 'out'
/** Foreground and backdrop visible only where the other is not */
| 'xor'
/** Foreground and backdrop channels added (brightening) */
| 'lighter';
/**
* Position of the overlay image relative to a given edge. Each property is
* an offset in pixels. 0 aligns exactly to the edge. For example, left: 10
* positions left side of the overlay 10 pixels from the left edge of the
* image it's drawn over. bottom: 0 aligns bottom of the overlay with bottom
* of the background image.
*
* Setting both left & right, or both top & bottom is an error.
*
* If no position is specified, the image will be centered.
*/
top?: number;
left?: number;
bottom?: number;
right?: number;
}
interface RequestInitCfPropertiesImage extends BasicImageTransformations {
/**
* Quality setting from 1-100 (useful values are in 60-90 range). Lower values
* make images look worse, but load faster. The default is 85. It applies only
@@ -9240,17 +11578,6 @@ interface RequestInitCfPropertiesImage extends BasicImageTransformations {
* output formats always discard metadata.
*/
metadata?: "keep" | "copyright" | "none";
/**
* Strength of sharpening filter to apply to the image. Floating-point
* number between 0 (no sharpening, default) and 10 (maximum). 1.0 is a
* recommended value for downscaled images.
*/
sharpen?: number;
/**
* Radius of a blur filter (approximate gaussian). Maximum supported radius
* is 250.
*/
blur?: number;
/**
* Overlays are drawn in the order they appear in the array (last array
* entry is the topmost layer).
@@ -9262,50 +11589,6 @@ interface RequestInitCfPropertiesImage extends BasicImageTransformations {
* the origin.
*/
"origin-auth"?: "share-publicly";
/**
* Adds a border around the image. The border is added after resizing. Border
* width takes dpr into account, and can be specified either using a single
* width property, or individually for each side.
*/
border?: {
color: string;
width: number;
} | {
color: string;
top: number;
right: number;
bottom: number;
left: number;
};
/**
* Increase brightness by a factor. A value of 1.0 equals no change, a value
* of 0.5 equals half brightness, and a value of 2.0 equals twice as bright.
* 0 is ignored.
*/
brightness?: number;
/**
* Increase contrast by a factor. A value of 1.0 equals no change, a value of
* 0.5 equals low contrast, and a value of 2.0 equals high contrast. 0 is
* ignored.
*/
contrast?: number;
/**
* Increase exposure by a factor. A value of 1.0 equals no change, a value of
* 0.5 darkens the image, and a value of 2.0 lightens the image. 0 is ignored.
*/
gamma?: number;
/**
* Increase contrast by a factor. A value of 1.0 equals no change, a value of
* 0.5 equals low contrast, and a value of 2.0 equals high contrast. 0 is
* ignored.
*/
saturation?: number;
/**
* Flips the images horizontally, vertically, or both. Flipping is applied before
* rotation, so if you apply flip=h,rotate=90 then the image will be flipped
* horizontally, then rotated by 90 degrees.
*/
flip?: 'h' | 'v' | 'hv';
/**
* Slightly reduces latency on a cache miss by selecting a
* quickest-to-compress file format, at a cost of increased file size and
@@ -9686,6 +11969,32 @@ interface IncomingRequestCfPropertiesTLSClientAuth {
* @example "Dec 22 19:39:00 2018 GMT"
*/
certNotAfter: string;
/**
* The client leaf certificate in [RFC 9440](https://www.rfc-editor.org/rfc/rfc9440)
* format (`:base64-DER:`). Empty if no client certificate was presented or if
* the leaf certificate exceeded 10 KB (see {@link certRFC9440TooLarge}).
*
* Suitable for forwarding to an origin via the `Client-Cert` HTTP header.
*/
certRFC9440: string;
/**
* `true` if the leaf certificate exceeded 10 KB and was omitted from
* {@link certRFC9440}.
*/
certRFC9440TooLarge: boolean;
/**
* The intermediate certificate chain in [RFC 9440](https://www.rfc-editor.org/rfc/rfc9440)
* format as a comma-separated list. Empty if no intermediates were sent or
* if the chain exceeded 16 KB (see {@link certChainRFC9440TooLarge}).
*
* Suitable for forwarding to an origin via the `Client-Cert-Chain` HTTP header.
*/
certChainRFC9440: string;
/**
* `true` if the intermediate chain exceeded 16 KB and was omitted from
* {@link certChainRFC9440}.
*/
certChainRFC9440TooLarge: boolean;
}
/** Placeholder values for TLS Client Authorization */
interface IncomingRequestCfPropertiesTLSClientAuthPlaceholder {
@@ -9706,6 +12015,10 @@ interface IncomingRequestCfPropertiesTLSClientAuthPlaceholder {
certFingerprintSHA256: "";
certNotBefore: "";
certNotAfter: "";
certRFC9440: "";
certRFC9440TooLarge: false;
certChainRFC9440: "";
certChainRFC9440TooLarge: false;
}
/** Possible outcomes of TLS verification */
declare type CertVerificationStatus =
@@ -9920,11 +12233,11 @@ interface SendEmail {
send(message: EmailMessage): Promise<EmailSendResult>;
send(builder: {
from: string | EmailAddress;
to: string | string[];
to: string | EmailAddress | (string | EmailAddress)[];
subject: string;
replyTo?: string | EmailAddress;
cc?: string | string[];
bcc?: string | string[];
cc?: string | EmailAddress | (string | EmailAddress)[];
bcc?: string | EmailAddress | (string | EmailAddress)[];
headers?: Record<string, string>;
text?: string;
html?: string;
@@ -9942,6 +12255,105 @@ declare module "cloudflare:email" {
};
export { _EmailMessage as EmailMessage };
}
/**
* Evaluation context for targeting rules.
* Keys are attribute names (e.g. "userId", "country"), values are the attribute values.
*/
type FlagshipEvaluationContext = Record<string, string | number | boolean>;
interface FlagshipEvaluationDetails<T> {
flagKey: string;
value: T;
variant?: string | undefined;
reason?: string | undefined;
errorCode?: string | undefined;
errorMessage?: string | undefined;
}
interface FlagshipEvaluationError extends Error {
}
/**
* Feature flags binding for evaluating feature flags from a Cloudflare Workers script.
*
* @example
* ```typescript
* // Get a boolean flag value with a default
* const enabled = await env.FLAGS.getBooleanValue('my-feature', false);
*
* // Get a flag value with evaluation context for targeting
* const variant = await env.FLAGS.getStringValue('experiment', 'control', {
* userId: 'user-123',
* country: 'US',
* });
*
* // Get full evaluation details including variant and reason
* const details = await env.FLAGS.getBooleanDetails('my-feature', false);
* console.log(details.variant, details.reason);
* ```
*/
declare abstract class Flagship {
/**
* Get a flag value without type checking.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Optional default value returned when evaluation fails.
* @param context Optional evaluation context for targeting rules.
*/
get(flagKey: string, defaultValue?: unknown, context?: FlagshipEvaluationContext): Promise<unknown>;
/**
* Get a boolean flag value.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Default value returned when evaluation fails or the flag type does not match.
* @param context Optional evaluation context for targeting rules.
*/
getBooleanValue(flagKey: string, defaultValue: boolean, context?: FlagshipEvaluationContext): Promise<boolean>;
/**
* Get a string flag value.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Default value returned when evaluation fails or the flag type does not match.
* @param context Optional evaluation context for targeting rules.
*/
getStringValue(flagKey: string, defaultValue: string, context?: FlagshipEvaluationContext): Promise<string>;
/**
* Get a number flag value.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Default value returned when evaluation fails or the flag type does not match.
* @param context Optional evaluation context for targeting rules.
*/
getNumberValue(flagKey: string, defaultValue: number, context?: FlagshipEvaluationContext): Promise<number>;
/**
* Get an object flag value.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Default value returned when evaluation fails or the flag type does not match.
* @param context Optional evaluation context for targeting rules.
*/
getObjectValue<T extends object>(flagKey: string, defaultValue: T, context?: FlagshipEvaluationContext): Promise<T>;
/**
* Get a boolean flag value with full evaluation details.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Default value returned when evaluation fails or the flag type does not match.
* @param context Optional evaluation context for targeting rules.
*/
getBooleanDetails(flagKey: string, defaultValue: boolean, context?: FlagshipEvaluationContext): Promise<FlagshipEvaluationDetails<boolean>>;
/**
* Get a string flag value with full evaluation details.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Default value returned when evaluation fails or the flag type does not match.
* @param context Optional evaluation context for targeting rules.
*/
getStringDetails(flagKey: string, defaultValue: string, context?: FlagshipEvaluationContext): Promise<FlagshipEvaluationDetails<string>>;
/**
* Get a number flag value with full evaluation details.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Default value returned when evaluation fails or the flag type does not match.
* @param context Optional evaluation context for targeting rules.
*/
getNumberDetails(flagKey: string, defaultValue: number, context?: FlagshipEvaluationContext): Promise<FlagshipEvaluationDetails<number>>;
/**
* Get an object flag value with full evaluation details.
* @param flagKey The key of the flag to evaluate.
* @param defaultValue Default value returned when evaluation fails or the flag type does not match.
* @param context Optional evaluation context for targeting rules.
*/
getObjectDetails<T extends object>(flagKey: string, defaultValue: T, context?: FlagshipEvaluationContext): Promise<FlagshipEvaluationDetails<T>>;
}
/**
* Hello World binding to serve as an explanatory example. DO NOT USE
*/
@@ -10061,11 +12473,25 @@ type ImageTransform = {
type ImageDrawOptions = {
opacity?: number;
repeat?: boolean | string;
composite?: ImageCompositeMode;
top?: number;
left?: number;
bottom?: number;
right?: number;
};
type ImageCompositeMode =
/** Foreground drawn on top of backdrop (default) */
'over'
/** Foreground shown only where backdrop is opaque */
| 'in'
/** Foreground drawn on top, but clipped to the backdrop's shape */
| 'atop'
/** Foreground shown only where backdrop is transparent */
| 'out'
/** Foreground and backdrop visible only where the other is not */
| 'xor'
/** Foreground and backdrop channels added (brightening) */
| 'lighter';
type ImageInputOptions = {
encoding?: 'base64';
};
@@ -10109,19 +12535,37 @@ interface ImageList {
cursor?: string;
listComplete: boolean;
}
interface HostedImagesBinding {
interface ImageHandle {
/**
* Get detailed metadata for a hosted image
* @param imageId The ID of the image (UUID or custom ID)
* Get metadata for a hosted image
* @returns Image metadata, or null if not found
*/
details(imageId: string): Promise<ImageMetadata | null>;
details(): Promise<ImageMetadata | null>;
/**
* Get the raw image data for a hosted image
* @param imageId The ID of the image (UUID or custom ID)
* @returns ReadableStream of image bytes, or null if not found
*/
image(imageId: string): Promise<ReadableStream<Uint8Array> | null>;
bytes(): Promise<ReadableStream<Uint8Array> | null>;
/**
* Update hosted image metadata
* @param options Properties to update
* @returns Updated image metadata
* @throws {@link ImagesError} if update fails
*/
update(options: ImageUpdateOptions): Promise<ImageMetadata>;
/**
* Delete a hosted image
* @returns True if deleted, false if not found
*/
delete(): Promise<boolean>;
}
interface HostedImagesBinding {
/**
* Get a handle for a hosted image
* @param imageId The ID of the image (UUID or custom ID)
* @returns A handle for per-image operations
*/
image(imageId: string): ImageHandle;
/**
* Upload a new hosted image
* @param image The image file to upload
@@ -10130,20 +12574,6 @@ interface HostedImagesBinding {
* @throws {@link ImagesError} if upload fails
*/
upload(image: ReadableStream<Uint8Array> | ArrayBuffer, options?: ImageUploadOptions): Promise<ImageMetadata>;
/**
* Update hosted image metadata
* @param imageId The ID of the image
* @param options Properties to update
* @returns Updated image metadata
* @throws {@link ImagesError} if update fails
*/
update(imageId: string, options: ImageUpdateOptions): Promise<ImageMetadata>;
/**
* Delete a hosted image
* @param imageId The ID of the image
* @returns True if deleted, false if not found
*/
delete(imageId: string): Promise<boolean>;
/**
* List hosted images with pagination
* @param options List configuration
@@ -10611,7 +13041,8 @@ declare namespace CloudflareWorkersModule {
constructor(ctx: ExecutionContext, env: Env);
email?(message: ForwardableEmailMessage): void | Promise<void>;
fetch?(request: Request): Response | Promise<Response>;
queue?(batch: MessageBatch<unknown>): void | Promise<void>;
connect?(socket: Socket): void | Promise<void>;
queue?(batch: MessageBatch): void | Promise<void>;
scheduled?(controller: ScheduledController): void | Promise<void>;
tail?(events: TraceItem[]): void | Promise<void>;
tailStream?(event: TailStream.TailEvent<TailStream.Onset>): TailStream.TailEventHandlerType | Promise<TailStream.TailEventHandlerType>;
@@ -10625,6 +13056,7 @@ declare namespace CloudflareWorkersModule {
constructor(ctx: DurableObjectState, env: Env);
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
fetch?(request: Request): Response | Promise<Response>;
connect?(socket: Socket): void | Promise<void>;
webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise<void>;
webSocketClose?(ws: WebSocket, code: number, reason: string, wasClean: boolean): void | Promise<void>;
webSocketError?(ws: WebSocket, error: unknown): void | Promise<void>;
@@ -10635,6 +13067,7 @@ declare namespace CloudflareWorkersModule {
export type WorkflowTimeoutDuration = WorkflowSleepDuration;
export type WorkflowRetentionDuration = WorkflowSleepDuration;
export type WorkflowBackoff = 'constant' | 'linear' | 'exponential';
export type WorkflowStepSensitivity = 'output';
export type WorkflowStepConfig = {
retries?: {
limit: number;
@@ -10642,23 +13075,51 @@ declare namespace CloudflareWorkersModule {
backoff?: WorkflowBackoff;
};
timeout?: WorkflowTimeoutDuration | number;
sensitive?: WorkflowStepSensitivity;
};
export type WorkflowStepRollbackConfig = Pick<WorkflowStepConfig, 'retries' | 'timeout'>;
export type WorkflowCronSchedule = {
/** Cron expression that triggered this event. */
cron: string;
/** Timestamp of the scheduled trigger, in milliseconds since the Unix epoch. */
scheduledTime: number;
};
export type WorkflowEvent<T> = {
payload: Readonly<T>;
timestamp: Date;
instanceId: string;
workflowName: string;
schedule?: WorkflowCronSchedule;
};
export type WorkflowStepEvent<T> = {
payload: Readonly<T>;
timestamp: Date;
type: string;
sensitive?: WorkflowStepSensitivity;
};
export type WorkflowStepContext = {
step: {
name: string;
count: number;
};
attempt: number;
config: WorkflowStepConfig;
};
export type WorkflowRollbackContext<T = unknown> = {
ctx: WorkflowStepContext;
error: Error;
output: T | undefined;
/** @deprecated Use `ctx.step.name` and `ctx.step.count` instead. */
stepName: string;
};
export type WorkflowRollbackHandler<T = unknown> = (ctx: WorkflowRollbackContext<T>) => Promise<void>;
export type WorkflowStepRollbackOptions<T = unknown> = {
rollback: WorkflowRollbackHandler<T>;
rollbackConfig?: WorkflowStepRollbackConfig;
};
export abstract class WorkflowStep {
do<T extends Rpc.Serializable<T>>(name: string, callback: (ctx: WorkflowStepContext) => Promise<T>): Promise<T>;
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfig, callback: (ctx: WorkflowStepContext) => Promise<T>): Promise<T>;
do<T extends Rpc.Serializable<T>>(name: string, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>;
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfig, callback: (ctx: WorkflowStepContext) => Promise<T>, rollbackOptions?: WorkflowStepRollbackOptions<T>): Promise<T>;
sleep: (name: string, duration: WorkflowSleepDuration) => Promise<void>;
sleepUntil: (name: string, timestamp: Date | number) => Promise<void>;
waitForEvent<T extends Rpc.Serializable<T>>(name: string, options: {
@@ -10680,6 +13141,8 @@ declare namespace CloudflareWorkersModule {
export function withEnvAndExports(newEnv: unknown, newExports: unknown, fn: () => unknown): unknown;
export const env: Cloudflare.Env;
export const exports: Cloudflare.Exports;
export const cache: CacheContext;
export const tracing: Tracing;
}
declare module 'cloudflare:workers' {
export = CloudflareWorkersModule;
@@ -10724,17 +13187,6 @@ interface StreamBinding {
* @returns A handle for per-video operations.
*/
video(id: string): StreamVideoHandle;
/**
* Uploads a new video from a File.
* @param file The video file to upload.
* @returns The uploaded video details.
* @throws {BadRequestError} if the upload parameter is invalid
* @throws {QuotaReachedError} if the account storage capacity is exceeded
* @throws {MaxFileSizeError} if the file size is too large
* @throws {RateLimitedError} if the server received too many requests
* @throws {InternalError} if an unexpected error occurs
*/
upload(file: File): Promise<StreamVideo>;
/**
* Uploads a new video from a provided URL.
* @param url The URL to upload from.
@@ -11069,14 +13521,13 @@ interface StreamScopedCaptions {
* Uploads the caption or subtitle file to the endpoint for a specific BCP47 language.
* One caption or subtitle file per language is allowed.
* @param language The BCP 47 language tag for the caption or subtitle.
* @param file The caption or subtitle file to upload.
* @param input The caption or subtitle stream to upload.
* @returns The created caption entry.
* @throws {NotFoundError} if the video is not found
* @throws {BadRequestError} if the language or file is invalid
* @throws {MaxFileSizeError} if the file size is too large
* @throws {InternalError} if an unexpected error occurs
*/
upload(language: string, file: File): Promise<StreamCaption>;
upload(language: string, input: ReadableStream): Promise<StreamCaption>;
/**
* Generate captions or subtitles for the provided language via AI.
* @param language The BCP 47 language tag to generate.
@@ -11150,16 +13601,15 @@ interface StreamVideos {
interface StreamWatermarks {
/**
* Generate a new watermark profile
* @param file The image file to upload
* @param input The image stream to upload
* @param params The watermark creation parameters.
* @returns The created watermark profile.
* @throws {BadRequestError} if the parameters are invalid
* @throws {InvalidURLError} if the URL is invalid
* @throws {MaxFileSizeError} if the file size is too large
* @throws {TooManyWatermarksError} if the number of allowed watermarks is reached
* @throws {InternalError} if an unexpected error occurs
*/
generate(file: File, params: StreamWatermarkCreateParams): Promise<StreamWatermark>;
generate(input: ReadableStream, params: StreamWatermarkCreateParams): Promise<StreamWatermark>;
/**
* Generate a new watermark profile
* @param url The image url to upload
@@ -11167,7 +13617,6 @@ interface StreamWatermarks {
* @returns The created watermark profile.
* @throws {BadRequestError} if the parameters are invalid
* @throws {InvalidURLError} if the URL is invalid
* @throws {MaxFileSizeError} if the file size is too large
* @throws {TooManyWatermarksError} if the number of allowed watermarks is reached
* @throws {InternalError} if an unexpected error occurs
*/
@@ -11558,12 +14007,20 @@ declare namespace TailStream {
readonly type: "fetch";
readonly statusCode: number;
}
type EventOutcome = "ok" | "canceled" | "exception" | "unknown" | "killSwitch" | "daemonDown" | "exceededCpu" | "exceededMemory" | "loadShed" | "responseStreamDisconnected" | "scriptNotFound";
interface ConnectEventInfo {
readonly type: "connect";
}
type EventOutcome = "ok" | "canceled" | "exception" | "unknown" | "killSwitch" | "daemonDown" | "exceededCpu" | "exceededMemory" | "loadShed" | "responseStreamDisconnected" | "scriptNotFound" | "internalError" | "exceededWallTime";
interface ScriptVersion {
readonly id: string;
readonly tag?: string;
readonly message?: string;
}
interface TracePreviewInfo {
readonly id: string;
readonly slug: string;
readonly name: string;
}
interface Onset {
readonly type: "onset";
readonly attributes: Attribute[];
@@ -11575,7 +14032,8 @@ declare namespace TailStream {
readonly scriptName?: string;
readonly scriptTags?: string[];
readonly scriptVersion?: ScriptVersion;
readonly info: FetchEventInfo | JsRpcEventInfo | ScheduledEventInfo | AlarmEventInfo | QueueEventInfo | EmailEventInfo | TraceEventInfo | HibernatableWebSocketEventInfo | CustomEventInfo;
readonly preview?: TracePreviewInfo;
readonly info: FetchEventInfo | ConnectEventInfo | JsRpcEventInfo | ScheduledEventInfo | AlarmEventInfo | QueueEventInfo | EmailEventInfo | TraceEventInfo | HibernatableWebSocketEventInfo | CustomEventInfo;
}
interface Outcome {
readonly type: "outcome";
@@ -11651,6 +14109,9 @@ declare namespace TailStream {
// 1. This is an Onset event
// 2. We are not inheriting any SpanContext. (e.g. this is a cross-account service binding or a new top-level invocation)
readonly spanId?: string;
// W3C trace flags from an upstream traceparent. Absent when no upstream
// sampling decision was made.
readonly traceFlags?: number;
}
interface TailEvent<Event extends EventType> {
// invocation id of the currently invoked worker stage.
@@ -11924,6 +14385,103 @@ type WorkerVersionMetadata = {
/** The timestamp of when the Worker Version was uploaded */
timestamp: string;
};
// ============ Web Search Request Types ============
/**
* Options for a Web Search query.
*/
type WebSearchSearchOptions = {
/** The search query. */
query: string;
/**
* Maximum number of results to return. Defaults to 10, capped at 20.
* The actual count may be lower if fewer matches exist.
*/
limit?: number;
};
// ============ Web Search Response Types ============
/**
* A single Web Search result.
*
* Web Search is discovery-only -- results carry catalog metadata about a page
* but never the page body. To read a result's content the caller invokes the
* global `fetch()` API against the result's `url`, at which point the
* destination's own access controls apply (including Cloudflare Pay-per-Crawl).
*/
type WebSearchResult = {
/** Canonical URL. */
url: string;
/** Page title. */
title: string;
/** Page-level description. May be absent. */
description?: string;
/**
* Last-modified date for the page, when known. Naive (no timezone)
* ISO-8601 datetime, e.g. `"2025-11-30T04:39:48"`.
*/
lastModifiedDate?: string;
/**
* Page meta image URL (typically the `og:image`). May be absent.
*/
imageUrl?: string;
/** Optional favicon URL for UI hints. */
faviconUrl?: string;
};
/**
* Per-response metadata for a Web Search query. Carries operational
* fields useful for support and debugging.
*/
type WebSearchResponseMetadata = {
/** The query that was executed. */
query: string;
/** Opaque request identifier used for support and debugging. */
requestId: string;
/** End-to-end latency for this search request, in milliseconds. */
latencyMs: number;
};
/**
* Response from a Web Search query.
*/
type WebSearchSearchResponse = {
items: WebSearchResult[];
metadata: WebSearchResponseMetadata;
};
// ============ Web Search Binding Class ============
/**
* Cloudflare Web Search binding.
*
* Discovery-only primitive for agents and Workers. Returns URLs and catalog
* metadata for a query; never returns page content or excerpts. To read a
* result's body, fetch the URL with the global `fetch()` API.
*
* Declared in wrangler with a single object (there is exactly one corpus, the
* public web, so there is no name, namespace, or instance to specify):
*
* ```jsonc
* { "web_search": { "binding": "WEBSEARCH" } }
* ```
*
* @example
* ```ts
* const { items, metadata } = await env.WEBSEARCH.search({
* query: "Cloudflare Workers",
* });
*
* const top = items[0];
* console.log(top.url, top.title, metadata.latencyMs);
*
* // Read content yourself; pay-per-crawl and other publisher
* // controls apply at the fetch site, not at search time.
* const page = await fetch(top.url);
* ```
*/
declare abstract class WebSearch {
/**
* Run a Web Search query.
* @param options Search options. Only `query` is required.
* @returns The matching results plus per-response metadata.
*/
search(options: WebSearchSearchOptions): Promise<WebSearchSearchResponse>;
}
interface DynamicDispatchLimits {
/**
* Limit CPU time in milliseconds.
@@ -12025,6 +14583,27 @@ interface WorkflowError {
code?: number;
message: string;
}
interface WorkflowInstanceRestartOptions {
/**
* Restart from a specific step. If omitted, the instance restarts from the beginning.
* The step must exist in the instance's execution history.
*/
from?: {
/**
* The step name as defined in your workflow code.
*/
name: string;
/**
* 1-indexed occurrence of this step name. Use when the same step name appears multiple times (e.g. in a loop).
* @default 1
*/
count?: number;
/**
* Step type filter. Use when different step types share the same name.
*/
type?: 'do' | 'sleep' | 'waitForEvent';
};
}
declare abstract class WorkflowInstance {
public id: string;
/**
@@ -12040,9 +14619,11 @@ declare abstract class WorkflowInstance {
*/
public terminate(): Promise<void>;
/**
* Restart the instance.
* Restart the instance. Optionally restart from a specific step, preserving
* cached results for all steps before it.
* @param options Options for the restart, including an optional step to restart from.
*/
public restart(): Promise<void>;
public restart(options?: WorkflowInstanceRestartOptions): Promise<void>;
/**
* Returns the current status of the instance.
*/
+10
View File
@@ -4,6 +4,16 @@
"main": "src/econ.app.ts",
"compatibility_date": "2025-09-20",
"compatibility_flags": ["nodejs_compat"],
// Shared `recflare` D1 (accounts table) — read/write the player's avatar column.
// The accounts schema/migrations are owned by the `auth` worker. The "local"
// placeholder is replaced with the real id from RECFLARE_D1 at deploy time.
"d1_databases": [
{
"binding": "DB",
"database_name": "recflare",
"database_id": "local"
}
],
"logpush": false,
"upload_source_maps": true,
"observability": {