@restatedev/restate-sdk 0.7.3-worker → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +29 -51
- package/dist/clients/workflow_client.d.ts +77 -0
- package/dist/clients/workflow_client.d.ts.map +1 -0
- package/dist/clients/workflow_client.js +172 -0
- package/dist/clients/workflow_client.js.map +1 -0
- package/dist/connection/buffered_connection.js +44 -0
- package/dist/connection/buffered_connection.js.map +1 -0
- package/dist/connection/connection.js +13 -0
- package/dist/connection/connection.js.map +1 -0
- package/dist/connection/embedded_connection.js +59 -0
- package/dist/connection/embedded_connection.js.map +1 -0
- package/dist/connection/http_connection.js +203 -0
- package/dist/connection/http_connection.js.map +1 -0
- package/dist/connection/lambda_connection.js +58 -0
- package/dist/connection/lambda_connection.js.map +1 -0
- package/dist/{restate_context.d.ts → context.d.ts} +239 -170
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +113 -0
- package/dist/context.js.map +1 -0
- package/dist/{restate_context_impl.d.ts → context_impl.d.ts} +26 -30
- package/dist/context_impl.d.ts.map +1 -0
- package/dist/context_impl.js +439 -0
- package/dist/context_impl.js.map +1 -0
- package/dist/embedded/api.d.ts +2 -2
- package/dist/embedded/api.d.ts.map +1 -1
- package/dist/embedded/api.js +35 -0
- package/dist/embedded/api.js.map +1 -0
- package/dist/embedded/handler.d.ts +2 -2
- package/dist/embedded/handler.d.ts.map +1 -1
- package/dist/embedded/handler.js +26 -0
- package/dist/embedded/handler.js.map +1 -0
- package/dist/embedded/http2_remote.js +91 -0
- package/dist/embedded/http2_remote.js.map +1 -0
- package/dist/embedded/invocation.d.ts.map +1 -1
- package/dist/embedded/invocation.js +94 -0
- package/dist/embedded/invocation.js.map +1 -0
- package/dist/endpoint/endpoint_impl.d.ts +35 -0
- package/dist/endpoint/endpoint_impl.d.ts.map +1 -0
- package/dist/endpoint/endpoint_impl.js +405 -0
- package/dist/endpoint/endpoint_impl.js.map +1 -0
- package/dist/endpoint/http2_handler.d.ts +11 -0
- package/dist/endpoint/http2_handler.d.ts.map +1 -0
- package/dist/endpoint/http2_handler.js +119 -0
- package/dist/endpoint/http2_handler.js.map +1 -0
- package/dist/endpoint/lambda_handler.d.ts +15 -0
- package/dist/endpoint/lambda_handler.d.ts.map +1 -0
- package/dist/endpoint/lambda_handler.js +144 -0
- package/dist/endpoint/lambda_handler.js.map +1 -0
- package/dist/endpoint.d.ts +161 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/endpoint.js +22 -0
- package/dist/endpoint.js.map +1 -0
- package/dist/generated/dev/restate/events.js +371 -0
- package/dist/generated/dev/restate/events.js.map +1 -0
- package/dist/generated/dev/restate/ext.js +215 -0
- package/dist/generated/dev/restate/ext.js.map +1 -0
- package/dist/generated/google/protobuf/descriptor.js +6676 -0
- package/dist/generated/google/protobuf/descriptor.js.map +1 -0
- package/dist/generated/google/protobuf/empty.js +107 -0
- package/dist/generated/google/protobuf/empty.js.map +1 -0
- package/dist/generated/google/protobuf/struct.js +754 -0
- package/dist/generated/google/protobuf/struct.js.map +1 -0
- package/dist/generated/proto/discovery.js +364 -0
- package/dist/generated/proto/discovery.js.map +1 -0
- package/dist/generated/proto/dynrpc.js +668 -0
- package/dist/generated/proto/dynrpc.js.map +1 -0
- package/dist/generated/proto/javascript.d.ts +13 -0
- package/dist/generated/proto/javascript.d.ts.map +1 -1
- package/dist/generated/proto/javascript.js +416 -0
- package/dist/generated/proto/javascript.js.map +1 -0
- package/dist/generated/proto/protocol.d.ts +43 -0
- package/dist/generated/proto/protocol.d.ts.map +1 -1
- package/dist/generated/proto/protocol.js +2641 -0
- package/dist/generated/proto/protocol.js.map +1 -0
- package/dist/generated/proto/services.js +1535 -0
- package/dist/generated/proto/services.js.map +1 -0
- package/dist/generated/proto/test.js +321 -0
- package/dist/generated/proto/test.js.map +1 -0
- package/dist/invocation.d.ts +4 -1
- package/dist/invocation.d.ts.map +1 -1
- package/dist/invocation.js +157 -0
- package/dist/invocation.js.map +1 -0
- package/dist/io/decoder.d.ts +1 -0
- package/dist/io/decoder.d.ts.map +1 -1
- package/dist/io/decoder.js +140 -0
- package/dist/io/decoder.js.map +1 -0
- package/dist/io/encoder.d.ts +1 -2
- package/dist/io/encoder.d.ts.map +1 -1
- package/dist/io/encoder.js +68 -0
- package/dist/io/encoder.js.map +1 -0
- package/dist/journal.d.ts +13 -4
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +405 -0
- package/dist/journal.js.map +1 -0
- package/dist/local_state_store.d.ts +5 -3
- package/dist/local_state_store.d.ts.map +1 -1
- package/dist/local_state_store.js +82 -0
- package/dist/local_state_store.js.map +1 -0
- package/dist/logger.d.ts +19 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +90 -0
- package/dist/logger.js.map +1 -0
- package/dist/promise_combinator_tracker.d.ts +29 -0
- package/dist/promise_combinator_tracker.d.ts.map +1 -0
- package/dist/promise_combinator_tracker.js +128 -0
- package/dist/promise_combinator_tracker.js.map +1 -0
- package/dist/public_api.d.ts +5 -5
- package/dist/public_api.d.ts.map +1 -1
- package/dist/public_api.js +60 -0
- package/dist/public_api.js.map +1 -0
- package/dist/state_machine.d.ts +19 -12
- package/dist/state_machine.d.ts.map +1 -1
- package/dist/state_machine.js +437 -0
- package/dist/state_machine.js.map +1 -0
- package/dist/types/errors.d.ts +12 -3
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/errors.js +273 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/grpc.d.ts +6 -4
- package/dist/types/grpc.d.ts.map +1 -1
- package/dist/types/grpc.js +81 -0
- package/dist/types/grpc.js.map +1 -0
- package/dist/types/protocol.d.ts +9 -5
- package/dist/types/protocol.d.ts.map +1 -1
- package/dist/types/protocol.js +147 -0
- package/dist/types/protocol.js.map +1 -0
- package/dist/types/router.d.ts +8 -8
- package/dist/types/router.d.ts.map +1 -1
- package/dist/types/router.js +36 -0
- package/dist/types/router.js.map +1 -0
- package/dist/types/types.d.ts +1 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +138 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils/{assumpsions.d.ts → assumptions.d.ts} +1 -1
- package/dist/utils/{assumpsions.d.ts.map → assumptions.d.ts.map} +1 -1
- package/dist/utils/assumptions.js +101 -0
- package/dist/utils/assumptions.js.map +1 -0
- package/dist/utils/message_logger.d.ts +28 -0
- package/dist/utils/message_logger.d.ts.map +1 -0
- package/dist/utils/message_logger.js +88 -0
- package/dist/utils/message_logger.js.map +1 -0
- package/dist/utils/promises.d.ts +15 -0
- package/dist/utils/promises.d.ts.map +1 -0
- package/dist/utils/promises.js +67 -0
- package/dist/utils/promises.js.map +1 -0
- package/dist/utils/public_utils.js +49 -0
- package/dist/utils/public_utils.js.map +1 -0
- package/dist/utils/rand.d.ts +1 -1
- package/dist/utils/rand.d.ts.map +1 -1
- package/dist/utils/rand.js +114 -0
- package/dist/utils/rand.js.map +1 -0
- package/dist/utils/utils.d.ts +1 -10
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +122 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/workflows/workflow.d.ts +101 -0
- package/dist/workflows/workflow.d.ts.map +1 -0
- package/dist/workflows/workflow.js +80 -0
- package/dist/workflows/workflow.js.map +1 -0
- package/dist/workflows/workflow_state_service.d.ts +35 -0
- package/dist/workflows/workflow_state_service.d.ts.map +1 -0
- package/dist/workflows/workflow_state_service.js +201 -0
- package/dist/workflows/workflow_state_service.js.map +1 -0
- package/dist/workflows/workflow_wrapper_service.d.ts +10 -0
- package/dist/workflows/workflow_wrapper_service.d.ts.map +1 -0
- package/dist/workflows/workflow_wrapper_service.js +264 -0
- package/dist/workflows/workflow_wrapper_service.js.map +1 -0
- package/package.json +38 -39
- package/src/clients/workflow_client.ts +290 -0
- package/src/connection/buffered_connection.ts +47 -0
- package/src/connection/connection.ts +34 -0
- package/src/connection/embedded_connection.ts +62 -0
- package/src/connection/http_connection.ts +228 -0
- package/src/connection/lambda_connection.ts +69 -0
- package/src/context.ts +633 -0
- package/src/context_impl.ts +721 -0
- package/src/embedded/api.ts +57 -0
- package/src/embedded/handler.ts +36 -0
- package/src/embedded/http2_remote.ts +103 -0
- package/src/embedded/invocation.ts +126 -0
- package/src/endpoint/endpoint_impl.ts +623 -0
- package/src/endpoint/http2_handler.ts +151 -0
- package/src/endpoint/lambda_handler.ts +181 -0
- package/src/endpoint.ts +187 -0
- package/src/generated/dev/restate/events.ts +430 -0
- package/src/generated/dev/restate/ext.ts +238 -0
- package/src/generated/google/protobuf/descriptor.ts +7889 -0
- package/src/generated/google/protobuf/empty.ts +150 -0
- package/src/generated/google/protobuf/struct.ts +878 -0
- package/src/generated/proto/discovery.ts +423 -0
- package/src/generated/proto/dynrpc.ts +768 -0
- package/src/generated/proto/javascript.ts +488 -0
- package/src/generated/proto/protocol.ts +3091 -0
- package/src/generated/proto/services.ts +1834 -0
- package/src/generated/proto/test.ts +387 -0
- package/src/invocation.ts +212 -0
- package/src/io/decoder.ts +171 -0
- package/src/io/encoder.ts +72 -0
- package/src/journal.ts +537 -0
- package/src/local_state_store.ts +94 -0
- package/src/logger.ts +121 -0
- package/src/promise_combinator_tracker.ts +191 -0
- package/src/public_api.ts +53 -0
- package/src/state_machine.ts +635 -0
- package/src/types/errors.ts +297 -0
- package/src/types/grpc.ts +97 -0
- package/src/types/protocol.ts +201 -0
- package/src/types/router.ts +118 -0
- package/src/types/types.ts +160 -0
- package/src/utils/assumptions.ts +131 -0
- package/src/utils/message_logger.ts +112 -0
- package/src/utils/promises.ts +118 -0
- package/src/utils/public_utils.ts +91 -0
- package/src/utils/rand.ts +142 -0
- package/src/utils/utils.ts +178 -0
- package/src/workflows/workflow.ts +178 -0
- package/src/workflows/workflow_state_service.ts +299 -0
- package/src/workflows/workflow_wrapper_service.ts +314 -0
- package/dist/cloudflare_bundle.js +0 -27387
- package/dist/restate_context.d.ts.map +0 -1
- package/dist/restate_context_impl.d.ts.map +0 -1
- package/dist/server/base_restate_server.d.ts +0 -32
- package/dist/server/base_restate_server.d.ts.map +0 -1
- package/dist/server/restate_lambda_handler.d.ts +0 -104
- package/dist/server/restate_lambda_handler.d.ts.map +0 -1
- package/dist/server/restate_server.d.ts +0 -97
- package/dist/server/restate_server.d.ts.map +0 -1
- package/dist/utils/logger.d.ts +0 -60
- package/dist/utils/logger.d.ts.map +0 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
|
|
3
|
+
*
|
|
4
|
+
* This file is part of the Restate SDK for Node.js/TypeScript,
|
|
5
|
+
* which is released under the MIT license.
|
|
6
|
+
*
|
|
7
|
+
* You can find a copy of the license in file LICENSE in the root
|
|
8
|
+
* directory of this repository or package, or at
|
|
9
|
+
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
13
|
+
|
|
14
|
+
import { CombineablePromise, Context, KeyedContext } from "../context";
|
|
15
|
+
import { Event } from "./types";
|
|
16
|
+
|
|
17
|
+
// ----------- generics -------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
type WithKeyArgument<F> = F extends () => infer R ? (key: string) => R : F;
|
|
20
|
+
|
|
21
|
+
type WithoutRpcContext<F> = F extends (
|
|
22
|
+
ctx: infer C extends Context,
|
|
23
|
+
...args: infer P
|
|
24
|
+
) => infer R
|
|
25
|
+
? (...args: P) => R
|
|
26
|
+
: never;
|
|
27
|
+
|
|
28
|
+
export type Client<M> = {
|
|
29
|
+
[K in keyof M as M[K] extends never ? never : K]: M[K] extends (
|
|
30
|
+
...args: infer P
|
|
31
|
+
) => PromiseLike<infer O>
|
|
32
|
+
? (...args: P) => CombineablePromise<O>
|
|
33
|
+
: never;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type SendClient<M> = {
|
|
37
|
+
[K in keyof M as M[K] extends never ? never : K]: M[K] extends (
|
|
38
|
+
...args: infer P
|
|
39
|
+
) => any
|
|
40
|
+
? (...args: P) => void
|
|
41
|
+
: never;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// ----------- unkeyed handlers ----------------------------------------------
|
|
45
|
+
|
|
46
|
+
export type UnKeyedHandler<F> = F extends (ctx: Context) => Promise<any>
|
|
47
|
+
? F
|
|
48
|
+
: F extends (ctx: Context, input: any) => Promise<any>
|
|
49
|
+
? F
|
|
50
|
+
: never;
|
|
51
|
+
|
|
52
|
+
export type UnKeyedRouterOpts<U> = {
|
|
53
|
+
[K in keyof U]: U[K] extends UnKeyedHandler<any> ? U[K] : never;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type UnKeyedRouter<U> = {
|
|
57
|
+
[K in keyof U]: U[K] extends UnKeyedHandler<infer F>
|
|
58
|
+
? WithoutRpcContext<F>
|
|
59
|
+
: never;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const router = <M>(opts: UnKeyedRouterOpts<M>): UnKeyedRouter<M> => {
|
|
63
|
+
if (opts === undefined || opts === null) {
|
|
64
|
+
throw new Error("router must be defined");
|
|
65
|
+
}
|
|
66
|
+
return opts as UnKeyedRouter<M>;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// ----------- keyed handlers ----------------------------------------------
|
|
70
|
+
|
|
71
|
+
export type KeyedHandler<F> = F extends (ctx: KeyedContext) => Promise<any>
|
|
72
|
+
? F
|
|
73
|
+
: F extends (ctx: KeyedContext, key: string, value: any) => Promise<any>
|
|
74
|
+
? F
|
|
75
|
+
: never;
|
|
76
|
+
|
|
77
|
+
export type KeyedRouterOpts<U> = {
|
|
78
|
+
[K in keyof U]: U[K] extends KeyedHandler<U[K]> | KeyedEventHandler<U[K]>
|
|
79
|
+
? U[K]
|
|
80
|
+
: never;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type KeyedRouter<U> = {
|
|
84
|
+
[K in keyof U]: U[K] extends KeyedEventHandler<U[K]>
|
|
85
|
+
? never
|
|
86
|
+
: U[K] extends KeyedHandler<infer F>
|
|
87
|
+
? WithKeyArgument<WithoutRpcContext<F>>
|
|
88
|
+
: never;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const keyedRouter = <M>(opts: KeyedRouterOpts<M>): KeyedRouter<M> => {
|
|
92
|
+
if (opts === undefined || opts === null) {
|
|
93
|
+
throw new Error("router must be defined");
|
|
94
|
+
}
|
|
95
|
+
return opts as KeyedRouter<M>;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// ----------- event handlers ----------------------------------------------
|
|
99
|
+
|
|
100
|
+
export type KeyedEventHandler<U> = U extends () => Promise<void>
|
|
101
|
+
? never
|
|
102
|
+
: U extends (ctx: KeyedContext) => Promise<void>
|
|
103
|
+
? never
|
|
104
|
+
: U extends (ctx: KeyedContext, event: Event) => Promise<void>
|
|
105
|
+
? U
|
|
106
|
+
: never;
|
|
107
|
+
|
|
108
|
+
export const keyedEventHandler = <H>(handler: KeyedEventHandler<H>): H => {
|
|
109
|
+
return { eventHandler: true, handler: handler } as H;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const isEventHandler = (
|
|
113
|
+
handler: any
|
|
114
|
+
): handler is {
|
|
115
|
+
handler: (ctx: KeyedContext, event: Event) => Promise<void>;
|
|
116
|
+
} => {
|
|
117
|
+
return typeof handler === "object" && handler["eventHandler"];
|
|
118
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
|
|
3
|
+
*
|
|
4
|
+
* This file is part of the Restate SDK for Node.js/TypeScript,
|
|
5
|
+
* which is released under the MIT license.
|
|
6
|
+
*
|
|
7
|
+
* You can find a copy of the license in file LICENSE in the root
|
|
8
|
+
* directory of this repository or package, or at
|
|
9
|
+
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
AWAKEABLE_ENTRY_MESSAGE_TYPE,
|
|
14
|
+
COMPLETION_MESSAGE_TYPE,
|
|
15
|
+
ENTRY_ACK_MESSAGE_TYPE,
|
|
16
|
+
ERROR_MESSAGE_TYPE,
|
|
17
|
+
formatMessageType,
|
|
18
|
+
GET_STATE_ENTRY_MESSAGE_TYPE,
|
|
19
|
+
GET_STATE_KEYS_ENTRY_MESSAGE_TYPE,
|
|
20
|
+
KNOWN_MESSAGE_TYPES,
|
|
21
|
+
POLL_INPUT_STREAM_ENTRY_MESSAGE_TYPE,
|
|
22
|
+
PROTOBUF_MESSAGE_BY_TYPE,
|
|
23
|
+
ProtocolMessage,
|
|
24
|
+
SLEEP_ENTRY_MESSAGE_TYPE,
|
|
25
|
+
START_MESSAGE_TYPE,
|
|
26
|
+
SUSPENSION_MESSAGE_TYPE,
|
|
27
|
+
} from "./protocol";
|
|
28
|
+
|
|
29
|
+
export class Message {
|
|
30
|
+
constructor(
|
|
31
|
+
readonly messageType: bigint,
|
|
32
|
+
readonly message: ProtocolMessage,
|
|
33
|
+
readonly completed?: boolean,
|
|
34
|
+
readonly protocolVersion?: number,
|
|
35
|
+
readonly requiresAck?: boolean
|
|
36
|
+
) {}
|
|
37
|
+
|
|
38
|
+
// For debugging purposes
|
|
39
|
+
toJSON(): unknown {
|
|
40
|
+
const pbType = PROTOBUF_MESSAGE_BY_TYPE.get(this.messageType);
|
|
41
|
+
if (pbType === undefined) {
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
messageType: formatMessageType(this.messageType),
|
|
46
|
+
message: pbType.toJSON(this.message),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
class MessageType {
|
|
52
|
+
static assertValid(messageTypeId: bigint) {
|
|
53
|
+
if (KNOWN_MESSAGE_TYPES.has(messageTypeId)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if ((messageTypeId & CUSTOM_MESSAGE_MASK) !== 0n) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`Unknown message type ${messageTypeId}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static hasCompletedFlag(messageType: bigint): boolean {
|
|
63
|
+
return (
|
|
64
|
+
messageType === POLL_INPUT_STREAM_ENTRY_MESSAGE_TYPE ||
|
|
65
|
+
messageType === GET_STATE_ENTRY_MESSAGE_TYPE ||
|
|
66
|
+
messageType === GET_STATE_KEYS_ENTRY_MESSAGE_TYPE ||
|
|
67
|
+
messageType === SLEEP_ENTRY_MESSAGE_TYPE ||
|
|
68
|
+
messageType === AWAKEABLE_ENTRY_MESSAGE_TYPE
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static hasProtocolVersion(messageType: bigint): boolean {
|
|
73
|
+
return messageType == START_MESSAGE_TYPE;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static hasRequiresAckFlag(messageType: bigint): boolean {
|
|
77
|
+
return (
|
|
78
|
+
messageType !== START_MESSAGE_TYPE &&
|
|
79
|
+
messageType !== ERROR_MESSAGE_TYPE &&
|
|
80
|
+
messageType !== SUSPENSION_MESSAGE_TYPE &&
|
|
81
|
+
messageType !== ENTRY_ACK_MESSAGE_TYPE &&
|
|
82
|
+
messageType !== COMPLETION_MESSAGE_TYPE
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const CUSTOM_MESSAGE_MASK = BigInt(0xfc00);
|
|
88
|
+
const COMPLETED_MASK = BigInt(0x0001_0000_0000);
|
|
89
|
+
const VERSION_MASK = BigInt(0x03ff_0000_0000);
|
|
90
|
+
const REQUIRES_ACK_MASK = BigInt(0x8000_0000_0000);
|
|
91
|
+
|
|
92
|
+
// The header is exported but only for tests.
|
|
93
|
+
export class Header {
|
|
94
|
+
constructor(
|
|
95
|
+
readonly messageType: bigint,
|
|
96
|
+
readonly frameLength: number,
|
|
97
|
+
readonly completedFlag?: boolean,
|
|
98
|
+
readonly protocolVersion?: number,
|
|
99
|
+
readonly requiresAckFlag?: boolean,
|
|
100
|
+
readonly partialStateFlag?: boolean
|
|
101
|
+
) {}
|
|
102
|
+
|
|
103
|
+
public static fromU64be(value: bigint): Header {
|
|
104
|
+
const messageType: bigint = (value >> 48n) & 0xffffn;
|
|
105
|
+
MessageType.assertValid(messageType);
|
|
106
|
+
|
|
107
|
+
const completedFlag =
|
|
108
|
+
MessageType.hasCompletedFlag(messageType) &&
|
|
109
|
+
(value & COMPLETED_MASK) !== 0n
|
|
110
|
+
? true
|
|
111
|
+
: undefined;
|
|
112
|
+
const protocolVersion = MessageType.hasProtocolVersion(messageType)
|
|
113
|
+
? Number(((value & VERSION_MASK) >> 32n) & 0xffffn)
|
|
114
|
+
: undefined;
|
|
115
|
+
const requiresAckFlag =
|
|
116
|
+
MessageType.hasRequiresAckFlag(messageType) &&
|
|
117
|
+
(value & REQUIRES_ACK_MASK) !== 0n
|
|
118
|
+
? true
|
|
119
|
+
: undefined;
|
|
120
|
+
const frameLength = Number(value & 0xffffffffn);
|
|
121
|
+
|
|
122
|
+
return new Header(
|
|
123
|
+
messageType,
|
|
124
|
+
frameLength,
|
|
125
|
+
completedFlag,
|
|
126
|
+
protocolVersion,
|
|
127
|
+
requiresAckFlag
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public toU64be(): bigint {
|
|
132
|
+
let res = (this.messageType << 48n) | BigInt(this.frameLength);
|
|
133
|
+
if (this.completedFlag) {
|
|
134
|
+
res = res | COMPLETED_MASK;
|
|
135
|
+
}
|
|
136
|
+
if (this.protocolVersion !== undefined) {
|
|
137
|
+
res = res | (BigInt(this.protocolVersion) << 32n);
|
|
138
|
+
}
|
|
139
|
+
if (this.requiresAckFlag) {
|
|
140
|
+
res = res | REQUIRES_ACK_MASK;
|
|
141
|
+
}
|
|
142
|
+
return res;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export class Event {
|
|
147
|
+
constructor(
|
|
148
|
+
readonly key: string,
|
|
149
|
+
readonly payload: Buffer,
|
|
150
|
+
readonly attributes: Record<string, string>
|
|
151
|
+
) {}
|
|
152
|
+
|
|
153
|
+
public json<T>(): T {
|
|
154
|
+
return JSON.parse(this.payload.toString("utf-8")) as T;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public body(): Uint8Array {
|
|
158
|
+
return this.payload;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
|
|
3
|
+
*
|
|
4
|
+
* This file is part of the Restate SDK for Node.js/TypeScript,
|
|
5
|
+
* which is released under the MIT license.
|
|
6
|
+
*
|
|
7
|
+
* You can find a copy of the license in file LICENSE in the root
|
|
8
|
+
* directory of this repository or package, or at
|
|
9
|
+
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { RpcRequest } from "../generated/proto/dynrpc";
|
|
13
|
+
import { TerminalError } from "../types/errors";
|
|
14
|
+
|
|
15
|
+
const ASSUME_UNKEYED_SINCE_FIRST_PARAM_NOT_STRING = 1;
|
|
16
|
+
const ASSUME_UNKEYED_SINCE_ZERO_ARGS = 2;
|
|
17
|
+
const ASSUME_KEYED_SINCE_TWO_ARGS_STR_AND_ANY = 3;
|
|
18
|
+
const ASSUME_EITHER_KEYED_OR_UNKEYED_ONE_STR_ARG = 4;
|
|
19
|
+
|
|
20
|
+
export const requestFromArgs = (args: unknown[]): RpcRequest => {
|
|
21
|
+
switch (args.length) {
|
|
22
|
+
case 0: {
|
|
23
|
+
return RpcRequest.create({
|
|
24
|
+
senderAssumes: ASSUME_UNKEYED_SINCE_ZERO_ARGS,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
case 1: {
|
|
28
|
+
if (typeof args[0] === "string") {
|
|
29
|
+
return RpcRequest.create({
|
|
30
|
+
key: args[0],
|
|
31
|
+
senderAssumes: ASSUME_EITHER_KEYED_OR_UNKEYED_ONE_STR_ARG,
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
return RpcRequest.create({
|
|
35
|
+
request: args[0],
|
|
36
|
+
senderAssumes: ASSUME_UNKEYED_SINCE_FIRST_PARAM_NOT_STRING,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
case 2: {
|
|
41
|
+
if (typeof args[0] !== "string") {
|
|
42
|
+
throw new TerminalError(
|
|
43
|
+
`Two argument handlers are only possible for keyed handlers. Where the first argument must be of type 'string'.`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return RpcRequest.create({
|
|
47
|
+
key: args[0],
|
|
48
|
+
request: args[1],
|
|
49
|
+
senderAssumes: ASSUME_KEYED_SINCE_TWO_ARGS_STR_AND_ANY,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
default: {
|
|
53
|
+
throw new TerminalError("wrong number of arguments " + args.length);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/* eslint-disable @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any */
|
|
59
|
+
export type JsType =
|
|
60
|
+
| string
|
|
61
|
+
| number
|
|
62
|
+
| boolean
|
|
63
|
+
| Object
|
|
64
|
+
| null
|
|
65
|
+
| Array<any>
|
|
66
|
+
| undefined;
|
|
67
|
+
/* eslint-enable @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any */
|
|
68
|
+
|
|
69
|
+
const requireThat = (condition: boolean, errorMessage: string) => {
|
|
70
|
+
if (!condition) {
|
|
71
|
+
throw new TerminalError(errorMessage);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const verifyAssumptions = (
|
|
76
|
+
isKeyed: boolean,
|
|
77
|
+
request: RpcRequest
|
|
78
|
+
): { key?: string; request?: JsType } => {
|
|
79
|
+
const assumption = request.senderAssumes ?? 0;
|
|
80
|
+
switch (assumption) {
|
|
81
|
+
case 0: {
|
|
82
|
+
// no assumption: this comes from an ingress.
|
|
83
|
+
const hasKeyProperty =
|
|
84
|
+
typeof request.key === "string" && request.key.length > 0;
|
|
85
|
+
if (isKeyed) {
|
|
86
|
+
requireThat(
|
|
87
|
+
hasKeyProperty,
|
|
88
|
+
"Trying to call a keyed handler with a missing or empty 'key' property."
|
|
89
|
+
);
|
|
90
|
+
} else {
|
|
91
|
+
requireThat(
|
|
92
|
+
!hasKeyProperty,
|
|
93
|
+
"Trying to call a an unkeyed handler with a 'key' property. Did you mean using the 'request' property instead?"
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return { key: request.key, request: request.request };
|
|
97
|
+
}
|
|
98
|
+
case ASSUME_UNKEYED_SINCE_FIRST_PARAM_NOT_STRING: {
|
|
99
|
+
requireThat(
|
|
100
|
+
!isKeyed,
|
|
101
|
+
"Trying to call a keyed handler with a missing key. This could happen if the first argument passed is not a 'string'."
|
|
102
|
+
);
|
|
103
|
+
return { request: request.request };
|
|
104
|
+
}
|
|
105
|
+
case ASSUME_UNKEYED_SINCE_ZERO_ARGS: {
|
|
106
|
+
requireThat(
|
|
107
|
+
!isKeyed,
|
|
108
|
+
"A keyed handler must at least be invoked with a single non empty string argument, that represents the key. 0 arguments given."
|
|
109
|
+
);
|
|
110
|
+
return { request: request.request };
|
|
111
|
+
}
|
|
112
|
+
case ASSUME_KEYED_SINCE_TWO_ARGS_STR_AND_ANY: {
|
|
113
|
+
requireThat(
|
|
114
|
+
isKeyed,
|
|
115
|
+
"An unkeyed handler must have at most 1 argument. two given."
|
|
116
|
+
);
|
|
117
|
+
return { key: request.key, request: request.request };
|
|
118
|
+
}
|
|
119
|
+
case ASSUME_EITHER_KEYED_OR_UNKEYED_ONE_STR_ARG: {
|
|
120
|
+
if (isKeyed) {
|
|
121
|
+
return { key: request.key };
|
|
122
|
+
}
|
|
123
|
+
return { request: request.key };
|
|
124
|
+
}
|
|
125
|
+
default: {
|
|
126
|
+
throw new TerminalError(
|
|
127
|
+
`Unknown assumption id ${assumption}. This indicates an incorrect (or involuntary) setting of the assumption property at the ingress request, or an SDK bug.`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
|
|
3
|
+
*
|
|
4
|
+
* This file is part of the Restate SDK for Node.js/TypeScript,
|
|
5
|
+
* which is released under the MIT license.
|
|
6
|
+
*
|
|
7
|
+
* You can find a copy of the license in file LICENSE in the root
|
|
8
|
+
* directory of this repository or package, or at
|
|
9
|
+
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
13
|
+
/* eslint-disable no-console */
|
|
14
|
+
|
|
15
|
+
import { formatMessageType } from "../types/protocol";
|
|
16
|
+
import { formatMessageAsJson } from "./utils";
|
|
17
|
+
import { createRestateConsole, LoggerContext } from "../logger";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The environment variable which is read to determine the debug log settings.
|
|
21
|
+
*/
|
|
22
|
+
export const DEBUG_LOGGING_ENV = "RESTATE_DEBUG_LOGGING";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The values for the {@link DEBUG_LOGGING_ENV} variable.
|
|
26
|
+
*/
|
|
27
|
+
export enum RestateDebugLogLevel {
|
|
28
|
+
/** No debug logging at all. Good for performance and avoid per-invocation log volume */
|
|
29
|
+
OFF,
|
|
30
|
+
|
|
31
|
+
/** Logs debug information for every Restate function invocation. */
|
|
32
|
+
INVOKE,
|
|
33
|
+
|
|
34
|
+
/** Logs debug information for every Restate effect (=journal event) inside an invocation,
|
|
35
|
+
* like RPC, state access, sideEffect, ... */
|
|
36
|
+
JOURNAL,
|
|
37
|
+
|
|
38
|
+
/** Logs debug information for every Restate effect (=journal event) inside an invocation,
|
|
39
|
+
* like RPC, state access, sideEffect, ... Additionally, this adds a JSON representation
|
|
40
|
+
* of the journal message to the log. */
|
|
41
|
+
JOURNAL_VERBOSE,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const DEFAULT_DEBUG_LOG_LEVEL =
|
|
45
|
+
process.env["NODE_ENV"]?.toUpperCase() === "PRODUCTION"
|
|
46
|
+
? RestateDebugLogLevel.OFF
|
|
47
|
+
: RestateDebugLogLevel.INVOKE;
|
|
48
|
+
|
|
49
|
+
function readLogLevel(): RestateDebugLogLevel {
|
|
50
|
+
const env = process.env[DEBUG_LOGGING_ENV]?.toUpperCase();
|
|
51
|
+
if (env == undefined) {
|
|
52
|
+
return DEFAULT_DEBUG_LOG_LEVEL;
|
|
53
|
+
}
|
|
54
|
+
const idx = Object.keys(RestateDebugLogLevel)
|
|
55
|
+
.filter((t) =>
|
|
56
|
+
// Object.keys contains the numbers as well
|
|
57
|
+
// https://stackoverflow.com/questions/48768774/how-to-get-all-the-values-of-an-enum-with-typescript
|
|
58
|
+
isNaN(Number(t))
|
|
59
|
+
)
|
|
60
|
+
.findIndex((level) => level == env);
|
|
61
|
+
if (idx < 0) {
|
|
62
|
+
return DEFAULT_DEBUG_LOG_LEVEL;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return idx;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const log_level = readLogLevel();
|
|
69
|
+
|
|
70
|
+
export type StateMachineConsole = Console & {
|
|
71
|
+
debugInvokeMessage: (msg: string) => void;
|
|
72
|
+
|
|
73
|
+
debugJournalMessage: (
|
|
74
|
+
logMessage: string,
|
|
75
|
+
messageType?: bigint,
|
|
76
|
+
message?: any
|
|
77
|
+
) => void;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export function createStateMachineConsole(
|
|
81
|
+
context: LoggerContext
|
|
82
|
+
): StateMachineConsole {
|
|
83
|
+
const console = createRestateConsole(context);
|
|
84
|
+
|
|
85
|
+
Object.defineProperties(console, {
|
|
86
|
+
debugInvokeMessage: {
|
|
87
|
+
value: (msg: string) => {
|
|
88
|
+
if (log_level >= RestateDebugLogLevel.INVOKE) {
|
|
89
|
+
console.debug(msg);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
debugJournalMessage: {
|
|
94
|
+
value: (logMessage: string, messageType?: bigint, message?: any) => {
|
|
95
|
+
if (log_level >= RestateDebugLogLevel.JOURNAL) {
|
|
96
|
+
const type =
|
|
97
|
+
messageType !== undefined
|
|
98
|
+
? " ; " + formatMessageType(messageType)
|
|
99
|
+
: "";
|
|
100
|
+
const journalEvent =
|
|
101
|
+
log_level >= RestateDebugLogLevel.JOURNAL_VERBOSE &&
|
|
102
|
+
message !== undefined
|
|
103
|
+
? " : " + formatMessageAsJson(message)
|
|
104
|
+
: "";
|
|
105
|
+
console.debug(`${logMessage}${type}${journalEvent}`);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return console as StateMachineConsole;
|
|
112
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
|
|
3
|
+
*
|
|
4
|
+
* This file is part of the Restate SDK for Node.js/TypeScript,
|
|
5
|
+
* which is released under the MIT license.
|
|
6
|
+
*
|
|
7
|
+
* You can find a copy of the license in file LICENSE in the root
|
|
8
|
+
* directory of this repository or package, or at
|
|
9
|
+
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// -- Wrapped promise
|
|
13
|
+
|
|
14
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
15
|
+
export type WrappedPromise<T> = Promise<T> & {
|
|
16
|
+
// The reason for this transform is that we want to retain the wrapping.
|
|
17
|
+
// When working with WrappedPromise you MUST use this method instead of then for mapping the promise results.
|
|
18
|
+
transform: <TResult1 = T, TResult2 = never>(
|
|
19
|
+
onfulfilled?:
|
|
20
|
+
| ((value: T) => TResult1 | PromiseLike<TResult1>)
|
|
21
|
+
| null
|
|
22
|
+
| undefined,
|
|
23
|
+
onrejected?:
|
|
24
|
+
| ((reason: any) => TResult2 | PromiseLike<TResult2>)
|
|
25
|
+
| null
|
|
26
|
+
| undefined
|
|
27
|
+
) => WrappedPromise<TResult1 | TResult2>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function wrapDeeply<T>(
|
|
31
|
+
promise: Promise<T>,
|
|
32
|
+
onThen?: () => void
|
|
33
|
+
): WrappedPromise<T> {
|
|
34
|
+
// We need this to support nesting of WrappedPromise
|
|
35
|
+
let transform: <TResult1 = T, TResult2 = never>(
|
|
36
|
+
onfulfilled?:
|
|
37
|
+
| ((value: T) => TResult1 | PromiseLike<TResult1>)
|
|
38
|
+
| null
|
|
39
|
+
| undefined,
|
|
40
|
+
onrejected?:
|
|
41
|
+
| ((reason: any) => TResult2 | PromiseLike<TResult2>)
|
|
42
|
+
| null
|
|
43
|
+
| undefined
|
|
44
|
+
) => WrappedPromise<TResult1 | TResult2>;
|
|
45
|
+
if (Object.hasOwn(promise, "transform")) {
|
|
46
|
+
const wrappedPromise = promise as WrappedPromise<T>;
|
|
47
|
+
transform = (onfulfilled, onrejected) =>
|
|
48
|
+
wrapDeeply(wrappedPromise.transform(onfulfilled, onrejected), onThen);
|
|
49
|
+
} else {
|
|
50
|
+
transform = (onfulfilled, onrejected) =>
|
|
51
|
+
wrapDeeply(promise.then(onfulfilled, onrejected), onThen);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
55
|
+
return {
|
|
56
|
+
transform,
|
|
57
|
+
|
|
58
|
+
then: function <TResult1 = T, TResult2 = never>(
|
|
59
|
+
onfulfilled?:
|
|
60
|
+
| ((value: T) => TResult1 | PromiseLike<TResult1>)
|
|
61
|
+
| null
|
|
62
|
+
| undefined,
|
|
63
|
+
onrejected?:
|
|
64
|
+
| ((reason: any) => TResult2 | PromiseLike<TResult2>)
|
|
65
|
+
| null
|
|
66
|
+
| undefined
|
|
67
|
+
): Promise<TResult1 | TResult2> {
|
|
68
|
+
if (onThen !== undefined) {
|
|
69
|
+
onThen();
|
|
70
|
+
}
|
|
71
|
+
return promise.then(onfulfilled, onrejected);
|
|
72
|
+
},
|
|
73
|
+
catch: function <TResult = never>(
|
|
74
|
+
onrejected?:
|
|
75
|
+
| ((reason: any) => TResult | PromiseLike<TResult>)
|
|
76
|
+
| null
|
|
77
|
+
| undefined
|
|
78
|
+
): Promise<T | TResult> {
|
|
79
|
+
return wrapDeeply(promise.catch(onrejected), onThen);
|
|
80
|
+
},
|
|
81
|
+
finally: function (
|
|
82
|
+
onfinally?: (() => void) | null | undefined
|
|
83
|
+
): Promise<T> {
|
|
84
|
+
return wrapDeeply(promise.finally(onfinally), onThen);
|
|
85
|
+
},
|
|
86
|
+
[Symbol.toStringTag]: "",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Like https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
|
91
|
+
// (not yet available in node)
|
|
92
|
+
export class CompletablePromise<T> {
|
|
93
|
+
private success!: (value: T | PromiseLike<T>) => void;
|
|
94
|
+
private failure!: (reason?: any) => void;
|
|
95
|
+
|
|
96
|
+
public readonly promise: Promise<T>;
|
|
97
|
+
|
|
98
|
+
constructor() {
|
|
99
|
+
this.promise = new Promise((resolve, reject) => {
|
|
100
|
+
this.success = resolve;
|
|
101
|
+
this.failure = reject;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public resolve(value: T) {
|
|
106
|
+
this.success(value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public reject(reason?: any) {
|
|
110
|
+
this.failure(reason);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// A promise that is never completed
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
116
|
+
export const PROMISE_PENDING: Promise<any> = new Promise<any>(() => {});
|
|
117
|
+
export const WRAPPED_PROMISE_PENDING: Promise<any> =
|
|
118
|
+
wrapDeeply(PROMISE_PENDING);
|