Skip to content
File

Blob: types/defines/rpc.d.ts

typescript401 lines
1// Namespace for RPC utility types. Unfortunately, we can't use a `module` here as these types need
2// to referenced by `Fetcher`. This is included in the "importable" version of the types which
3// strips all `module` blocks.
4declare namespace Rpc {
5 // Branded types for identifying `WorkerEntrypoint`/`DurableObject`/`Target`s.
6 // TypeScript uses *structural* typing meaning anything with the same shape as type `T` is a `T`.
7 // For the classes exported by `cloudflare:workers` we want *nominal* typing (i.e. we only want to
8 // accept `WorkerEntrypoint` from `cloudflare:workers`, not any other class with the same shape)
9 export const __RPC_STUB_BRAND: '__RPC_STUB_BRAND';
10 export const __RPC_TARGET_BRAND: '__RPC_TARGET_BRAND';
11 export const __WORKER_ENTRYPOINT_BRAND: '__WORKER_ENTRYPOINT_BRAND';
12 export const __DURABLE_OBJECT_BRAND: '__DURABLE_OBJECT_BRAND';
13 export const __WORKFLOW_ENTRYPOINT_BRAND: '__WORKFLOW_ENTRYPOINT_BRAND';
14 export interface RpcTargetBranded {
15 [__RPC_TARGET_BRAND]: never;
16 }
17 export interface WorkerEntrypointBranded {
18 [__WORKER_ENTRYPOINT_BRAND]: never;
19 }
20 export interface DurableObjectBranded {
21 [__DURABLE_OBJECT_BRAND]: never;
22 }
23 export interface WorkflowEntrypointBranded {
24 [__WORKFLOW_ENTRYPOINT_BRAND]: never;
25 }
26 export type EntrypointBranded =
27 | WorkerEntrypointBranded
28 | DurableObjectBranded
29 | WorkflowEntrypointBranded;
30 
31 // Types that can be used through `Stub`s
32 export type Stubable = RpcTargetBranded | ((...args: any[]) => any);
33 
34 // Types that can be passed over RPC
35 // The reason for using a generic type here is to build a serializable subset of structured
36 // cloneable composite types. This allows types defined with the "interface" keyword to pass the
37 // serializable check as well. Otherwise, only types defined with the "type" keyword would pass.
38 type Serializable<T> =
39 // Structured cloneables
40 | BaseType
41 // Structured cloneable composites
42 | Map<
43 T extends Map<infer U, unknown> ? Serializable<U> : never,
44 T extends Map<unknown, infer U> ? Serializable<U> : never
45 >
46 | Set<T extends Set<infer U> ? Serializable<U> : never>
47 | ReadonlyArray<T extends ReadonlyArray<infer U> ? Serializable<U> : never>
48 | {
49 [K in keyof T]: K extends number | string ? Serializable<T[K]> : never;
50 }
51 // Special types
52 | Stub<Stubable>
53 // Serialized as stubs, see `Stubify`
54 | Stubable;
55 
56 // Base type for all RPC stubs, including common memory management methods.
57 // `T` is used as a marker type for unwrapping `Stub`s later.
58 interface StubBase<T extends Stubable> extends Disposable {
59 [__RPC_STUB_BRAND]: T;
60 dup(): this;
61 }
62 export type Stub<T extends Stubable> = Provider<T> & StubBase<T>;
63 
64 // This represents all the types that can be sent as-is over an RPC boundary
65 type BaseType =
66 | void
67 | undefined
68 | null
69 | boolean
70 | number
71 | bigint
72 | string
73 | TypedArray
74 | ArrayBuffer
75 | DataView
76 | Date
77 | Error
78 | RegExp
79 | ReadableStream<Uint8Array>
80 | WritableStream<Uint8Array>
81 | Request
82 | Response
83 | Headers;
84 // Recursively rewrite all `Stubable` types with `Stub`s
85 // prettier-ignore
86 type Stubify<T> =
87 T extends Stubable ? Stub<T>
88 : T extends Map<infer K, infer V> ? Map<Stubify<K>, Stubify<V>>
89 : T extends Set<infer V> ? Set<Stubify<V>>
90 : T extends Array<infer V> ? Array<Stubify<V>>
91 : T extends ReadonlyArray<infer V> ? ReadonlyArray<Stubify<V>>
92 : T extends BaseType ? T
93 // When using "unknown" instead of "any", interfaces are not stubified.
94 : T extends { [key: string | number]: any } ? { [K in keyof T]: Stubify<T[K]> }
95 : T;
96 
97 // Recursively rewrite all `Stub<T>`s with the corresponding `T`s.
98 // Note we use `StubBase` instead of `Stub` here to avoid circular dependencies:
99 // `Stub` depends on `Provider`, which depends on `Unstubify`, which would depend on `Stub`.
100 // prettier-ignore
101 type Unstubify<T> =
102 T extends StubBase<infer V> ? V
103 : T extends Map<infer K, infer V> ? Map<Unstubify<K>, Unstubify<V>>
104 : T extends Set<infer V> ? Set<Unstubify<V>>
105 : T extends Array<infer V> ? Array<Unstubify<V>>
106 : T extends ReadonlyArray<infer V> ? ReadonlyArray<Unstubify<V>>
107 : T extends BaseType ? T
108 : T extends { [key: string | number]: unknown } ? { [K in keyof T]: Unstubify<T[K]> }
109 : T;
110 type UnstubifyAll<A extends any[]> = { [I in keyof A]: Unstubify<A[I]> };
111 
112 // Utility type for adding `Provider`/`Disposable`s to `object` types only.
113 // Note `unknown & T` is equivalent to `T`.
114 type MaybeProvider<T> = T extends object ? Provider<T> : unknown;
115 type MaybeDisposable<T> = T extends object ? Disposable : unknown;
116 
117 // Type for method return or property on an RPC interface.
118 // - Stubable types are replaced by stubs.
119 // - Serializable types are passed by value, with stubable types replaced by stubs
120 // and a top-level `Disposer`.
121 // Everything else can't be passed over PRC.
122 // Technically, we use custom thenables here, but they quack like `Promise`s.
123 // Intersecting with `(Maybe)Provider` allows pipelining.
124 // prettier-ignore
125 type Result<R> =
126 R extends Stubable ? Promise<Stub<R>> & Provider<R>
127 : R extends Serializable<R> ? Promise<Stubify<R> & MaybeDisposable<R>> & MaybeProvider<R>
128 : never;
129 
130 // Type for method or property on an RPC interface.
131 // For methods, unwrap `Stub`s in parameters, and rewrite returns to be `Result`s.
132 // Unwrapping `Stub`s allows calling with `Stubable` arguments.
133 // For properties, rewrite types to be `Result`s.
134 // In each case, unwrap `Promise`s.
135 type MethodOrProperty<V> = V extends (...args: infer P) => infer R
136 ? (...args: UnstubifyAll<P>) => Result<Awaited<R>>
137 : Result<Awaited<V>>;
138 
139 // Type for the callable part of an `Provider` if `T` is callable.
140 // This is intersected with methods/properties.
141 type MaybeCallableProvider<T> = T extends (...args: any[]) => any
142 ? MethodOrProperty<T>
143 : unknown;
144 
145 // Base type for all other types providing RPC-like interfaces.
146 // Rewrites all methods/properties to be `MethodOrProperty`s, while preserving callable types.
147 // `Reserved` names (e.g. stub method names like `dup()`) and symbols can't be accessed over RPC.
148 export type Provider<
149 T extends object,
150 Reserved extends string = never,
151 > = MaybeCallableProvider<T> & Pick<
152 {
153 [K in keyof T]: MethodOrProperty<T[K]>;
154 },
155 Exclude<
156 keyof T,
157 Reserved | symbol | keyof StubBase<never>
158 >
159 >
160}
161 
162declare namespace Cloudflare {
163 // Type of `env`.
164 //
165 // The specific project can extend `Env` by redeclaring it in project-specific files. Typescript
166 // will merge all declarations.
167 //
168 // You can use `wrangler types` to generate the `Env` type automatically.
169 interface Env {}
170 
171 // Project-specific parameters used to inform types.
172 //
173 // This interface is, again, intended to be declared in project-specific files, and then that
174 // declaration will be merged with this one.
175 //
176 // A project should have a declaration like this:
177 //
178 // interface GlobalProps {
179 // // Declares the main module's exports. Used to populate Cloudflare.Exports aka the type
180 // // of `ctx.exports`.
181 // mainModule: typeof import("my-main-module");
182 //
183 // // Declares which of the main module's exports are configured with durable storage, and
184 // // thus should behave as Durable Object namsepace bindings.
185 // durableNamespaces: "MyDurableObject" | "AnotherDurableObject";
186 // }
187 //
188 // You can use `wrangler types` to generate `GlobalProps` automatically.
189 interface GlobalProps {}
190 
191 // Evaluates to the type of a property in GlobalProps, defaulting to `Default` if it is not
192 // present.
193 type GlobalProp<K extends string, Default> =
194 K extends keyof GlobalProps ? GlobalProps[K] : Default;
195 
196 // The type of the program's main module exports, if known. Requires `GlobalProps` to declare the
197 // `mainModule` property.
198 type MainModule = GlobalProp<"mainModule", {}>;
199 
200 // The type of ctx.exports, which contains loopback bindings for all top-level exports.
201 type Exports = {
202 [K in keyof MainModule]:
203 & LoopbackForExport<MainModule[K]>
204 
205 // If the export is listed in `durableNamespaces`, then it is also a
206 // DurableObjectNamespace.
207 & (K extends GlobalProp<"durableNamespaces", never>
208 ? MainModule[K] extends new (...args: any[]) => infer DoInstance
209 ? DoInstance extends Rpc.DurableObjectBranded
210 ? DurableObjectNamespace<DoInstance>
211 : DurableObjectNamespace<undefined>
212 : DurableObjectNamespace<undefined>
213 : {});
214 };
215}
216 
217declare namespace CloudflareWorkersModule {
218 export type RpcStub<T extends Rpc.Stubable> = Rpc.Stub<T>;
219 export const RpcStub: {
220 new <T extends Rpc.Stubable>(value: T): Rpc.Stub<T>;
221 };
222 
223 export abstract class RpcTarget implements Rpc.RpcTargetBranded {
224 [Rpc.__RPC_TARGET_BRAND]: never;
225 }
226 
227 // `protected` fields don't appear in `keyof`s, so can't be accessed over RPC
228 
229 export abstract class WorkerEntrypoint<
230 Env = Cloudflare.Env,
231 Props = {},
232 > implements Rpc.WorkerEntrypointBranded
233 {
234 [Rpc.__WORKER_ENTRYPOINT_BRAND]: never;
235 
236 protected ctx: ExecutionContext<Props>;
237 protected env: Env;
238 constructor(ctx: ExecutionContext, env: Env);
239 
240 email?(message: ForwardableEmailMessage): void | Promise<void>;
241 fetch?(request: Request): Response | Promise<Response>;
242 connect?(socket: Socket): void | Promise<void>;
243 queue?(batch: MessageBatch): void | Promise<void>;
244 scheduled?(controller: ScheduledController): void | Promise<void>;
245 tail?(events: TraceItem[]): void | Promise<void>;
246 tailStream?(event: TailStream.TailEvent<TailStream.Onset>): TailStream.TailEventHandlerType | Promise<TailStream.TailEventHandlerType>;
247 test?(controller: TestController): void | Promise<void>;
248 trace?(traces: TraceItem[]): void | Promise<void>;
249 }
250 
251 export abstract class DurableObject<
252 Env = Cloudflare.Env,
253 Props = {},
254 > implements Rpc.DurableObjectBranded
255 {
256 [Rpc.__DURABLE_OBJECT_BRAND]: never;
257 
258 protected ctx: DurableObjectState<Props>;
259 protected env: Env;
260 constructor(ctx: DurableObjectState, env: Env);
261 
262 alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
263 fetch?(request: Request): Response | Promise<Response>;
264 connect?(socket: Socket): void | Promise<void>;
265 webSocketMessage?(
266 ws: WebSocket,
267 message: string | ArrayBuffer
268 ): void | Promise<void>;
269 webSocketClose?(
270 ws: WebSocket,
271 code: number,
272 reason: string,
273 wasClean: boolean
274 ): void | Promise<void>;
275 webSocketError?(ws: WebSocket, error: unknown): void | Promise<void>;
276 }
277 
278 export type WorkflowDurationLabel =
279 | 'second'
280 | 'minute'
281 | 'hour'
282 | 'day'
283 | 'week'
284 | 'month'
285 | 'year';
286 
287 export type WorkflowSleepDuration =
288 | `${number} ${WorkflowDurationLabel}${'s' | ''}`
289 | number;
290 
291 export type WorkflowDelayDuration = WorkflowSleepDuration;
292 
293 export type WorkflowTimeoutDuration = WorkflowSleepDuration;
294 
295 export type WorkflowRetentionDuration = WorkflowSleepDuration;
296 
297 export type WorkflowBackoff = 'constant' | 'linear' | 'exponential';
298 
299 export type WorkflowStepConfig = {
300 retries?: {
301 limit: number;
302 delay: WorkflowDelayDuration | number;
303 backoff?: WorkflowBackoff;
304 };
305 timeout?: WorkflowTimeoutDuration | number;
306 };
307 
308 export type WorkflowEvent<T> = {
309 payload: Readonly<T>;
310 timestamp: Date;
311 instanceId: string;
312 };
313 
314 export type WorkflowStepEvent<T> = {
315 payload: Readonly<T>;
316 timestamp: Date;
317 type: string;
318 };
319 
320 export type WorkflowStepContext = {
321 step: {
322 name: string;
323 count: number;
324 };
325 attempt: number;
326 config: WorkflowStepConfig;
327 };
328 
329 export abstract class WorkflowStep {
330 do<T extends Rpc.Serializable<T>>(
331 name: string,
332 callback: (ctx: WorkflowStepContext) => Promise<T>
333 ): Promise<T>;
334 do<T extends Rpc.Serializable<T>>(
335 name: string,
336 config: WorkflowStepConfig,
337 callback: (ctx: WorkflowStepContext) => Promise<T>
338 ): Promise<T>;
339 sleep: (name: string, duration: WorkflowSleepDuration) => Promise<void>;
340 sleepUntil: (name: string, timestamp: Date | number) => Promise<void>;
341 waitForEvent<T extends Rpc.Serializable<T>>(
342 name: string,
343 options: {
344 type: string;
345 timeout?: WorkflowTimeoutDuration | number;
346 }
347 ): Promise<WorkflowStepEvent<T>>;
348 }
349 
350 export type WorkflowInstanceStatus =
351 | 'queued'
352 | 'running'
353 | 'paused'
354 | 'errored'
355 | 'terminated'
356 | 'complete'
357 | 'waiting'
358 | 'waitingForPause'
359 | 'unknown';
360 
361 export abstract class WorkflowEntrypoint<
362 Env = unknown,
363 T extends Rpc.Serializable<T> | unknown = unknown,
364 > implements Rpc.WorkflowEntrypointBranded
365 {
366 [Rpc.__WORKFLOW_ENTRYPOINT_BRAND]: never;
367 
368 protected ctx: ExecutionContext;
369 protected env: Env;
370 
371 constructor(ctx: ExecutionContext, env: Env);
372 
373 run(
374 event: Readonly<WorkflowEvent<T>>,
375 step: WorkflowStep
376 ): Promise<unknown>;
377 }
378 
379 export function waitUntil(promise: Promise<unknown>): void;
380 
381 export function withEnv(newEnv: unknown, fn: () => unknown): unknown;
382 export function withExports(
383 newExports: unknown,
384 fn: () => unknown
385 ): unknown;
386 export function withEnvAndExports(
387 newEnv: unknown,
388 newExports: unknown,
389 fn: () => unknown
390 ): unknown;
391 
392 export const env: Cloudflare.Env;
393 export const exports: Cloudflare.Exports;
394 export const cache: CacheContext;
395 export const tracing: Tracing;
396}
397 
398declare module 'cloudflare:workers' {
399 export = CloudflareWorkersModule;
400}