Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions packages/restate-sdk-clients/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
WorkflowDefinitionFrom,
Serde,
Duration,
FlattenHandlersDefinition,
JournalValueCodec,
} from "@restatedev/restate-sdk-core";
import { millisOrDurationToMillis } from "@restatedev/restate-sdk-core";
Expand All @@ -26,7 +27,9 @@ export interface Ingress {
/**
* Create a client from a {@link ServiceDefinition}.
*/
serviceClient<D>(opts: ServiceDefinitionFrom<D>): IngressClient<Service<D>>;
serviceClient<D>(
opts: ServiceDefinitionFrom<D>
): IngressClient<FlattenHandlersDefinition<Service<D>>>;

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

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

/**
* Create a client from a {@link ServiceDefinition}.
*/
serviceSendClient<D>(
opts: ServiceDefinitionFrom<D>
): IngressSendClient<Service<D>>;
): IngressSendClient<FlattenHandlersDefinition<Service<D>>>;

/**
* Create a client from a {@link VirtualObjectDefinition}.
*/
objectSendClient<D>(
opts: VirtualObjectDefinitionFrom<D>,
key: string
): IngressSendClient<VirtualObject<D>>;
): IngressSendClient<FlattenHandlersDefinition<VirtualObject<D>>>;

/**
* Resolve an awakeable from the ingress client.
Expand Down
27 changes: 17 additions & 10 deletions packages/restate-sdk-clients/src/ingress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
type Serde,
serde,
type JournalValueCodec,
type FlattenHandlersDefinition,
} from "@restatedev/restate-sdk-core";
import type {
ConnectionOpts,
Expand Down Expand Up @@ -296,21 +297,27 @@ class HttpIngress implements Ingress {
);
}

serviceClient<D>(opts: ServiceDefinitionFrom<D>): IngressClient<Service<D>> {
return this.proxy(opts.name) as IngressClient<Service<D>>;
serviceClient<D>(
opts: ServiceDefinitionFrom<D>
): IngressClient<FlattenHandlersDefinition<Service<D>>> {
return this.proxy(opts.name) as IngressClient<
FlattenHandlersDefinition<Service<D>>
>;
}

objectClient<D>(
opts: VirtualObjectDefinitionFrom<D>,
key: string
): IngressClient<VirtualObject<D>> {
return this.proxy(opts.name, key) as IngressClient<VirtualObject<D>>;
): IngressClient<FlattenHandlersDefinition<VirtualObject<D>>> {
return this.proxy(opts.name, key) as IngressClient<
FlattenHandlersDefinition<VirtualObject<D>>
>;
}

workflowClient<D>(
opts: WorkflowDefinitionFrom<D>,
key: string
): IngressWorkflowClient<Workflow<D>> {
): IngressWorkflowClient<FlattenHandlersDefinition<Workflow<D>>> {
const component = opts.name;
const conn = this.opts;

Expand Down Expand Up @@ -392,23 +399,23 @@ class HttpIngress implements Ingress {
};
},
}
) as IngressWorkflowClient<Workflow<D>>;
) as IngressWorkflowClient<FlattenHandlersDefinition<Workflow<D>>>;
}

objectSendClient<D>(
opts: VirtualObjectDefinitionFrom<D>,
key: string
): IngressSendClient<VirtualObject<D>> {
): IngressSendClient<FlattenHandlersDefinition<VirtualObject<D>>> {
return this.proxy(opts.name, key, true) as IngressSendClient<
VirtualObject<D>
FlattenHandlersDefinition<VirtualObject<D>>
>;
}

serviceSendClient<D>(
opts: ServiceDefinitionFrom<D>
): IngressSendClient<Service<D>> {
): IngressSendClient<FlattenHandlersDefinition<Service<D>>> {
return this.proxy(opts.name, undefined, true) as IngressSendClient<
Service<D>
FlattenHandlersDefinition<Service<D>>
>;
}

Expand Down
1 change: 1 addition & 0 deletions packages/restate-sdk-clients/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type {
VirtualObject,
Duration,
JournalValueCodec,
FlattenHandlersDefinition,
} from "@restatedev/restate-sdk-core";

export { serde } from "@restatedev/restate-sdk-core";
Expand Down
46 changes: 46 additions & 0 deletions packages/restate-sdk-core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,28 @@ export interface RestateWorkflowContext

// ----------- service -------------------------------------------------------

/**
* @deprecated
*/
export type ArgType<T> = T extends (ctx: any) => any
? void
: T extends (ctx: any, input: infer I) => any
? I
: never;

/**
* @deprecated
*/
export type HandlerReturnType<T> = T extends (
ctx: any,
input: any
) => Promise<infer R>
? R
: never;

/**
* @deprecated
*/
export type ServiceHandler<F, C = RestateContext> = F extends (
ctx: C
) => Promise<any>
Expand All @@ -65,6 +74,9 @@ export type ServiceDefinitionFrom<M> = M extends ServiceDefinition<

// ----------- object -------------------------------------------------------

/**
* @deprecated
*/
export type ObjectSharedHandler<
F,
SC = RestateObjectSharedContext
Expand All @@ -74,6 +86,9 @@ export type ObjectSharedHandler<
? F
: (ctx: SC, param?: any) => Promise<any>;

/**
* @deprecated
*/
export type ObjectHandler<F, C = RestateObjectContext> = F extends (
ctx: C,
param: any
Expand Down Expand Up @@ -104,6 +119,9 @@ export type VirtualObjectDefinitionFrom<M> = M extends VirtualObjectDefinition<

// ----------- workflow -------------------------------------------------------

/**
* @deprecated
*/
export type WorkflowSharedHandler<
F,
SC = RestateWorkflowSharedContext
Expand All @@ -113,6 +131,9 @@ export type WorkflowSharedHandler<
? F
: (ctx: SC, param?: any) => Promise<any>;

/**
* @deprecated
*/
export type WorkflowHandler<F, C = RestateWorkflowContext> = F extends (
ctx: C,
param: any
Expand All @@ -135,3 +156,28 @@ export type WorkflowDefinitionFrom<M> = M extends WorkflowDefinition<
>
? M
: WorkflowDefinition<string, M>;

// -------- Type manipulation for clients

export type FlattenHandlersDefinition<M> = {
[K in keyof M]: M[K] extends {
handler:
| ((ctx: any, param: any) => Promise<any>)
| ((ctx: any) => Promise<any>)
| ((ctx: any, param?: any) => Promise<any>);
}
? M[K]["handler"]
: M[K] extends {
sharedHandler:
| ((ctx: any, param: any) => Promise<any>)
| ((ctx: any) => Promise<any>)
| ((ctx: any, param?: any) => Promise<any>);
}
? M[K]["sharedHandler"]
: M[K] extends
| ((ctx: any, param: any) => Promise<any>)
| ((ctx: any) => Promise<any>)
| ((ctx: any, param?: any) => Promise<any>)
? M[K]
: never;
};
1 change: 1 addition & 0 deletions packages/restate-sdk-core/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type {
WorkflowDefinitionFrom,
ArgType,
HandlerReturnType,
FlattenHandlersDefinition,
} from "./core.js";

export type { Serde } from "./serde_api.js";
Expand Down
12 changes: 7 additions & 5 deletions packages/restate-sdk-examples/src/ingress_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import * as restate from "@restatedev/restate-sdk-clients";
import type { Greeter } from "./greeter.js";
import type { PaymentWorkflow } from "./workflow.js";
import type { Counter } from "./object.js";
import type { RawService } from "./raw.js";

const Greeter: Greeter = { name: "greeter" };
const Counter: Counter = { name: "counter" };
const RawService: RawService = { name: "raw" };
const Workflow: PaymentWorkflow = { name: "payment" };

const ingress = restate.connect({ url: "http://localhost:8080" });
Expand Down Expand Up @@ -157,12 +159,12 @@ const workflow = async (name: string) => {
console.log(await client.workflowAttach());
};

const binaryRawCall = async (name: string) => {
const counter = ingress.objectClient(Counter, name);
const binaryRawCall = async () => {
const rawService = ingress.serviceClient(RawService);

const buffer = new TextEncoder().encode("hello!");

const outBuffer = await counter.binary(
const outBuffer = await rawService.binary(
buffer,
restate.rpc.opts({
input: restate.serde.binary,
Expand All @@ -173,7 +175,7 @@ const binaryRawCall = async (name: string) => {

const str = new TextDecoder().decode(outBuffer);

console.log(`We got a buffer for ${name} : ${str}`);
console.log(`We got a buffer : ${str}`);
};

// Before running this example, make sure
Expand All @@ -198,5 +200,5 @@ Promise.resolve()
.then(() => globalCustomHeaders("bob"))
.then(() => customInterface("bob"))
.then(() => delayedCall("bob"))
.then(() => binaryRawCall("bob"))
.then(() => binaryRawCall())
.catch((e) => console.error(e));
48 changes: 12 additions & 36 deletions packages/restate-sdk-examples/src/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,35 @@
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
*/

import {
createObjectHandler,
createObjectSharedHandler,
object,
type ObjectContext,
type ObjectSharedContext,
serde,
serve,
} from "@restatedev/restate-sdk";
import { object, serve } from "@restatedev/restate-sdk";

export const counter = object({
name: "counter",
handlers: {
/**
* Add amount to the currently stored count
*/
add: async (ctx: ObjectContext, amount: number) => {
add: async (ctx, amount: number) => {
const current = await ctx.get<number>("count");
const updated = (current ?? 0) + amount;
ctx.set("count", updated);
return updated;
},

/**
* Get the current amount.
*
* Notice that VirtualObjects can have "shared" handlers.
* These handlers can be executed concurrently to the exclusive handlers (i.e. add)
* But they can not modify the state (set is missing from the ctx).
*/
current: createObjectSharedHandler(
async (ctx: ObjectSharedContext): Promise<number> => {
return (await ctx.get("count")) ?? 0;
}
),

/**
* Handlers (shared or exclusive) can be configured to bypass JSON serialization,
* by specifying the input (accept) and output (contentType) content types.
*
* to call that handler with binary data, you can use the following curl command:
* curl -X POST -H "Content-Type: application/octet-stream" --data-binary 'hello' ${RESTATE_INGRESS_URL}/counter/mykey/binary
*/
binary: createObjectHandler(
{
input: serde.binary,
output: serde.binary,
current: {
sharedHandler: async (ctx) => {
return (await ctx.get<number>("count")) ?? 0;
},
async (ctx: ObjectContext, data: Uint8Array) => {
// console.log("Received binary data", data);
return data;
}
),
},
clear: {
handler: async (ctx) => {
ctx.clearAll();
},
enableLazyState: true,
},
},
});

Expand Down
38 changes: 38 additions & 0 deletions packages/restate-sdk-examples/src/raw.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
*
* This file is part of the Restate SDK for Node.js/TypeScript,
* which is released under the MIT license.
*
* You can find a copy of the license in file LICENSE in the root
* directory of this repository or package, or at
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
*/

import { service, serve } from "@restatedev/restate-sdk";
import { serde } from "@restatedev/restate-sdk-core";

const rawService = service({
name: "raw",
handlers: {
binary: {
/**
* Handlers can be configured to bypass JSON serialization,
* by specifying the input (accept) and output (contentType) content types.
*
* To call this handler with binary data, you can use the following curl command:
* curl -X POST -H "Content-Type: application/octet-stream" --data-binary 'hello' ${RESTATE_INGRESS_URL}/raw/binary
*/
input: serde.binary,
output: serde.binary,
handler: async (ctx, data: Uint8Array) => {
// console.log("Received binary data", data);
return data;
},
},
},
});

export type RawService = typeof rawService;

serve({ services: [rawService] });
Loading
Loading