Skip to content

Commit c0f57ad

Browse files
New API to define handlers/shared handlers without wrapped functions. This supports proper contextual typing, and allows to evolve the Typed State API as well.
1 parent 8f15000 commit c0f57ad

File tree

11 files changed

+422
-200
lines changed

11 files changed

+422
-200
lines changed

packages/restate-sdk-clients/src/api.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
WorkflowDefinitionFrom,
88
Serde,
99
Duration,
10+
FlattenHandlersDefinition,
1011
JournalValueCodec,
1112
} from "@restatedev/restate-sdk-core";
1213
import { millisOrDurationToMillis } from "@restatedev/restate-sdk-core";
@@ -26,7 +27,9 @@ export interface Ingress {
2627
/**
2728
* Create a client from a {@link ServiceDefinition}.
2829
*/
29-
serviceClient<D>(opts: ServiceDefinitionFrom<D>): IngressClient<Service<D>>;
30+
serviceClient<D>(
31+
opts: ServiceDefinitionFrom<D>
32+
): IngressClient<FlattenHandlersDefinition<Service<D>>>;
3033

3134
/**
3235
* Create a client from a {@link WorkflowDefinition}.
@@ -36,7 +39,7 @@ export interface Ingress {
3639
workflowClient<D>(
3740
opts: WorkflowDefinitionFrom<D>,
3841
key: string
39-
): IngressWorkflowClient<Workflow<D>>;
42+
): IngressWorkflowClient<FlattenHandlersDefinition<Workflow<D>>>;
4043

4144
/**
4245
* Create a client from a {@link VirtualObjectDefinition}.
@@ -45,22 +48,22 @@ export interface Ingress {
4548
objectClient<D>(
4649
opts: VirtualObjectDefinitionFrom<D>,
4750
key: string
48-
): IngressClient<VirtualObject<D>>;
51+
): IngressClient<FlattenHandlersDefinition<VirtualObject<D>>>;
4952

5053
/**
5154
* Create a client from a {@link ServiceDefinition}.
5255
*/
5356
serviceSendClient<D>(
5457
opts: ServiceDefinitionFrom<D>
55-
): IngressSendClient<Service<D>>;
58+
): IngressSendClient<FlattenHandlersDefinition<Service<D>>>;
5659

5760
/**
5861
* Create a client from a {@link VirtualObjectDefinition}.
5962
*/
6063
objectSendClient<D>(
6164
opts: VirtualObjectDefinitionFrom<D>,
6265
key: string
63-
): IngressSendClient<VirtualObject<D>>;
66+
): IngressSendClient<FlattenHandlersDefinition<VirtualObject<D>>>;
6467

6568
/**
6669
* Resolve an awakeable from the ingress client.

packages/restate-sdk-clients/src/ingress.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
type Serde,
2020
serde,
2121
type JournalValueCodec,
22+
type FlattenHandlersDefinition,
2223
} from "@restatedev/restate-sdk-core";
2324
import type {
2425
ConnectionOpts,
@@ -296,21 +297,27 @@ class HttpIngress implements Ingress {
296297
);
297298
}
298299

299-
serviceClient<D>(opts: ServiceDefinitionFrom<D>): IngressClient<Service<D>> {
300-
return this.proxy(opts.name) as IngressClient<Service<D>>;
300+
serviceClient<D>(
301+
opts: ServiceDefinitionFrom<D>
302+
): IngressClient<FlattenHandlersDefinition<Service<D>>> {
303+
return this.proxy(opts.name) as IngressClient<
304+
FlattenHandlersDefinition<Service<D>>
305+
>;
301306
}
302307

303308
objectClient<D>(
304309
opts: VirtualObjectDefinitionFrom<D>,
305310
key: string
306-
): IngressClient<VirtualObject<D>> {
307-
return this.proxy(opts.name, key) as IngressClient<VirtualObject<D>>;
311+
): IngressClient<FlattenHandlersDefinition<VirtualObject<D>>> {
312+
return this.proxy(opts.name, key) as IngressClient<
313+
FlattenHandlersDefinition<VirtualObject<D>>
314+
>;
308315
}
309316

310317
workflowClient<D>(
311318
opts: WorkflowDefinitionFrom<D>,
312319
key: string
313-
): IngressWorkflowClient<Workflow<D>> {
320+
): IngressWorkflowClient<FlattenHandlersDefinition<Workflow<D>>> {
314321
const component = opts.name;
315322
const conn = this.opts;
316323

@@ -392,23 +399,23 @@ class HttpIngress implements Ingress {
392399
};
393400
},
394401
}
395-
) as IngressWorkflowClient<Workflow<D>>;
402+
) as IngressWorkflowClient<FlattenHandlersDefinition<Workflow<D>>>;
396403
}
397404

398405
objectSendClient<D>(
399406
opts: VirtualObjectDefinitionFrom<D>,
400407
key: string
401-
): IngressSendClient<VirtualObject<D>> {
408+
): IngressSendClient<FlattenHandlersDefinition<VirtualObject<D>>> {
402409
return this.proxy(opts.name, key, true) as IngressSendClient<
403-
VirtualObject<D>
410+
FlattenHandlersDefinition<VirtualObject<D>>
404411
>;
405412
}
406413

407414
serviceSendClient<D>(
408415
opts: ServiceDefinitionFrom<D>
409-
): IngressSendClient<Service<D>> {
416+
): IngressSendClient<FlattenHandlersDefinition<Service<D>>> {
410417
return this.proxy(opts.name, undefined, true) as IngressSendClient<
411-
Service<D>
418+
FlattenHandlersDefinition<Service<D>>
412419
>;
413420
}
414421

packages/restate-sdk-clients/src/public_api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type {
2222
VirtualObject,
2323
Duration,
2424
JournalValueCodec,
25+
FlattenHandlersDefinition,
2526
} from "@restatedev/restate-sdk-core";
2627

2728
export { serde } from "@restatedev/restate-sdk-core";

packages/restate-sdk-core/src/core.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,28 @@ export interface RestateWorkflowContext
2929

3030
// ----------- service -------------------------------------------------------
3131

32+
/**
33+
* @deprecated
34+
*/
3235
export type ArgType<T> = T extends (ctx: any) => any
3336
? void
3437
: T extends (ctx: any, input: infer I) => any
3538
? I
3639
: never;
3740

41+
/**
42+
* @deprecated
43+
*/
3844
export type HandlerReturnType<T> = T extends (
3945
ctx: any,
4046
input: any
4147
) => Promise<infer R>
4248
? R
4349
: never;
4450

51+
/**
52+
* @deprecated
53+
*/
4554
export type ServiceHandler<F, C = RestateContext> = F extends (
4655
ctx: C
4756
) => Promise<any>
@@ -65,6 +74,9 @@ export type ServiceDefinitionFrom<M> = M extends ServiceDefinition<
6574

6675
// ----------- object -------------------------------------------------------
6776

77+
/**
78+
* @deprecated
79+
*/
6880
export type ObjectSharedHandler<
6981
F,
7082
SC = RestateObjectSharedContext
@@ -74,6 +86,9 @@ export type ObjectSharedHandler<
7486
? F
7587
: (ctx: SC, param?: any) => Promise<any>;
7688

89+
/**
90+
* @deprecated
91+
*/
7792
export type ObjectHandler<F, C = RestateObjectContext> = F extends (
7893
ctx: C,
7994
param: any
@@ -104,6 +119,9 @@ export type VirtualObjectDefinitionFrom<M> = M extends VirtualObjectDefinition<
104119

105120
// ----------- workflow -------------------------------------------------------
106121

122+
/**
123+
* @deprecated
124+
*/
107125
export type WorkflowSharedHandler<
108126
F,
109127
SC = RestateWorkflowSharedContext
@@ -113,6 +131,9 @@ export type WorkflowSharedHandler<
113131
? F
114132
: (ctx: SC, param?: any) => Promise<any>;
115133

134+
/**
135+
* @deprecated
136+
*/
116137
export type WorkflowHandler<F, C = RestateWorkflowContext> = F extends (
117138
ctx: C,
118139
param: any
@@ -135,3 +156,28 @@ export type WorkflowDefinitionFrom<M> = M extends WorkflowDefinition<
135156
>
136157
? M
137158
: WorkflowDefinition<string, M>;
159+
160+
// -------- Type manipulation for clients
161+
162+
export type FlattenHandlersDefinition<M> = {
163+
[K in keyof M]: M[K] extends {
164+
handler:
165+
| ((ctx: any, param: any) => Promise<any>)
166+
| ((ctx: any) => Promise<any>)
167+
| ((ctx: any, param?: any) => Promise<any>);
168+
}
169+
? M[K]["handler"]
170+
: M[K] extends {
171+
sharedHandler:
172+
| ((ctx: any, param: any) => Promise<any>)
173+
| ((ctx: any) => Promise<any>)
174+
| ((ctx: any, param?: any) => Promise<any>);
175+
}
176+
? M[K]["sharedHandler"]
177+
: M[K] extends
178+
| ((ctx: any, param: any) => Promise<any>)
179+
| ((ctx: any) => Promise<any>)
180+
| ((ctx: any, param?: any) => Promise<any>)
181+
? M[K]
182+
: never;
183+
};

packages/restate-sdk-core/src/public_api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type {
3131
WorkflowDefinitionFrom,
3232
ArgType,
3333
HandlerReturnType,
34+
FlattenHandlersDefinition,
3435
} from "./core.js";
3536

3637
export type { Serde } from "./serde_api.js";

packages/restate-sdk-examples/src/object.ts

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,46 +22,25 @@ import {
2222
export const counter = object({
2323
name: "counter",
2424
handlers: {
25-
/**
26-
* Add amount to the currently stored count
27-
*/
28-
add: async (ctx: ObjectContext, amount: number) => {
25+
add: async (ctx, amount: number) => {
2926
const current = await ctx.get<number>("count");
3027
const updated = (current ?? 0) + amount;
3128
ctx.set("count", updated);
3229
return updated;
3330
},
34-
35-
/**
36-
* Get the current amount.
37-
*
38-
* Notice that VirtualObjects can have "shared" handlers.
39-
* These handlers can be executed concurrently to the exclusive handlers (i.e. add)
40-
* But they can not modify the state (set is missing from the ctx).
41-
*/
42-
current: createObjectSharedHandler(
43-
async (ctx: ObjectSharedContext): Promise<number> => {
31+
current: {
32+
sharedHandler: async (ctx) => {
4433
return (await ctx.get("count")) ?? 0;
45-
}
46-
),
47-
48-
/**
49-
* Handlers (shared or exclusive) can be configured to bypass JSON serialization,
50-
* by specifying the input (accept) and output (contentType) content types.
51-
*
52-
* to call that handler with binary data, you can use the following curl command:
53-
* curl -X POST -H "Content-Type: application/octet-stream" --data-binary 'hello' ${RESTATE_INGRESS_URL}/counter/mykey/binary
54-
*/
55-
binary: createObjectHandler(
56-
{
57-
input: serde.binary,
58-
output: serde.binary,
5934
},
60-
async (ctx: ObjectContext, data: Uint8Array) => {
61-
// console.log("Received binary data", data);
62-
return data;
63-
}
64-
),
35+
},
36+
clear: {
37+
handler: async (ctx) => {
38+
ctx.clearAll();
39+
},
40+
options: {
41+
enableLazyState: true,
42+
},
43+
},
6544
},
6645
});
6746

packages/restate-sdk/src/common_api.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ export type {
8383
ServiceOptions,
8484
ObjectOptions,
8585
WorkflowOptions,
86+
ServiceHandlers,
87+
ObjectHandlers,
88+
WorkflowHandlers,
89+
ServiceHandlerDefinition,
90+
ObjectHandlerDefinition,
91+
WorkflowHandlerDefinition,
92+
WorkflowSharedHandlerDefinition,
93+
Handler,
8694
} from "./types/rpc.js";
8795
export {
8896
service,
@@ -99,6 +107,7 @@ export type {
99107
ServiceDefinition,
100108
VirtualObjectDefinition,
101109
WorkflowDefinition,
110+
FlattenHandlersDefinition,
102111
} from "@restatedev/restate-sdk-core";
103112

104113
export type {
@@ -131,8 +140,23 @@ export type { EndpointOptions } from "./endpoint/types.js";
131140

132141
import { handlers } from "./types/rpc.js";
133142

143+
/**
144+
* @deprecated
145+
*/
134146
export const createServiceHandler = handlers.handler;
147+
/**
148+
* @deprecated
149+
*/
135150
export const createObjectHandler = handlers.object.exclusive;
151+
/**
152+
* @deprecated
153+
*/
136154
export const createObjectSharedHandler = handlers.object.shared;
155+
/**
156+
* @deprecated
157+
*/
137158
export const createWorkflowHandler = handlers.workflow.workflow;
159+
/**
160+
* @deprecated
161+
*/
138162
export const createWorkflowSharedHandler = handlers.workflow.shared;

0 commit comments

Comments
 (0)