@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.
Files changed (231) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +29 -51
  3. package/dist/clients/workflow_client.d.ts +77 -0
  4. package/dist/clients/workflow_client.d.ts.map +1 -0
  5. package/dist/clients/workflow_client.js +172 -0
  6. package/dist/clients/workflow_client.js.map +1 -0
  7. package/dist/connection/buffered_connection.js +44 -0
  8. package/dist/connection/buffered_connection.js.map +1 -0
  9. package/dist/connection/connection.js +13 -0
  10. package/dist/connection/connection.js.map +1 -0
  11. package/dist/connection/embedded_connection.js +59 -0
  12. package/dist/connection/embedded_connection.js.map +1 -0
  13. package/dist/connection/http_connection.js +203 -0
  14. package/dist/connection/http_connection.js.map +1 -0
  15. package/dist/connection/lambda_connection.js +58 -0
  16. package/dist/connection/lambda_connection.js.map +1 -0
  17. package/dist/{restate_context.d.ts → context.d.ts} +239 -170
  18. package/dist/context.d.ts.map +1 -0
  19. package/dist/context.js +113 -0
  20. package/dist/context.js.map +1 -0
  21. package/dist/{restate_context_impl.d.ts → context_impl.d.ts} +26 -30
  22. package/dist/context_impl.d.ts.map +1 -0
  23. package/dist/context_impl.js +439 -0
  24. package/dist/context_impl.js.map +1 -0
  25. package/dist/embedded/api.d.ts +2 -2
  26. package/dist/embedded/api.d.ts.map +1 -1
  27. package/dist/embedded/api.js +35 -0
  28. package/dist/embedded/api.js.map +1 -0
  29. package/dist/embedded/handler.d.ts +2 -2
  30. package/dist/embedded/handler.d.ts.map +1 -1
  31. package/dist/embedded/handler.js +26 -0
  32. package/dist/embedded/handler.js.map +1 -0
  33. package/dist/embedded/http2_remote.js +91 -0
  34. package/dist/embedded/http2_remote.js.map +1 -0
  35. package/dist/embedded/invocation.d.ts.map +1 -1
  36. package/dist/embedded/invocation.js +94 -0
  37. package/dist/embedded/invocation.js.map +1 -0
  38. package/dist/endpoint/endpoint_impl.d.ts +35 -0
  39. package/dist/endpoint/endpoint_impl.d.ts.map +1 -0
  40. package/dist/endpoint/endpoint_impl.js +405 -0
  41. package/dist/endpoint/endpoint_impl.js.map +1 -0
  42. package/dist/endpoint/http2_handler.d.ts +11 -0
  43. package/dist/endpoint/http2_handler.d.ts.map +1 -0
  44. package/dist/endpoint/http2_handler.js +119 -0
  45. package/dist/endpoint/http2_handler.js.map +1 -0
  46. package/dist/endpoint/lambda_handler.d.ts +15 -0
  47. package/dist/endpoint/lambda_handler.d.ts.map +1 -0
  48. package/dist/endpoint/lambda_handler.js +144 -0
  49. package/dist/endpoint/lambda_handler.js.map +1 -0
  50. package/dist/endpoint.d.ts +161 -0
  51. package/dist/endpoint.d.ts.map +1 -0
  52. package/dist/endpoint.js +22 -0
  53. package/dist/endpoint.js.map +1 -0
  54. package/dist/generated/dev/restate/events.js +371 -0
  55. package/dist/generated/dev/restate/events.js.map +1 -0
  56. package/dist/generated/dev/restate/ext.js +215 -0
  57. package/dist/generated/dev/restate/ext.js.map +1 -0
  58. package/dist/generated/google/protobuf/descriptor.js +6676 -0
  59. package/dist/generated/google/protobuf/descriptor.js.map +1 -0
  60. package/dist/generated/google/protobuf/empty.js +107 -0
  61. package/dist/generated/google/protobuf/empty.js.map +1 -0
  62. package/dist/generated/google/protobuf/struct.js +754 -0
  63. package/dist/generated/google/protobuf/struct.js.map +1 -0
  64. package/dist/generated/proto/discovery.js +364 -0
  65. package/dist/generated/proto/discovery.js.map +1 -0
  66. package/dist/generated/proto/dynrpc.js +668 -0
  67. package/dist/generated/proto/dynrpc.js.map +1 -0
  68. package/dist/generated/proto/javascript.d.ts +13 -0
  69. package/dist/generated/proto/javascript.d.ts.map +1 -1
  70. package/dist/generated/proto/javascript.js +416 -0
  71. package/dist/generated/proto/javascript.js.map +1 -0
  72. package/dist/generated/proto/protocol.d.ts +43 -0
  73. package/dist/generated/proto/protocol.d.ts.map +1 -1
  74. package/dist/generated/proto/protocol.js +2641 -0
  75. package/dist/generated/proto/protocol.js.map +1 -0
  76. package/dist/generated/proto/services.js +1535 -0
  77. package/dist/generated/proto/services.js.map +1 -0
  78. package/dist/generated/proto/test.js +321 -0
  79. package/dist/generated/proto/test.js.map +1 -0
  80. package/dist/invocation.d.ts +4 -1
  81. package/dist/invocation.d.ts.map +1 -1
  82. package/dist/invocation.js +157 -0
  83. package/dist/invocation.js.map +1 -0
  84. package/dist/io/decoder.d.ts +1 -0
  85. package/dist/io/decoder.d.ts.map +1 -1
  86. package/dist/io/decoder.js +140 -0
  87. package/dist/io/decoder.js.map +1 -0
  88. package/dist/io/encoder.d.ts +1 -2
  89. package/dist/io/encoder.d.ts.map +1 -1
  90. package/dist/io/encoder.js +68 -0
  91. package/dist/io/encoder.js.map +1 -0
  92. package/dist/journal.d.ts +13 -4
  93. package/dist/journal.d.ts.map +1 -1
  94. package/dist/journal.js +405 -0
  95. package/dist/journal.js.map +1 -0
  96. package/dist/local_state_store.d.ts +5 -3
  97. package/dist/local_state_store.d.ts.map +1 -1
  98. package/dist/local_state_store.js +82 -0
  99. package/dist/local_state_store.js.map +1 -0
  100. package/dist/logger.d.ts +19 -0
  101. package/dist/logger.d.ts.map +1 -0
  102. package/dist/logger.js +90 -0
  103. package/dist/logger.js.map +1 -0
  104. package/dist/promise_combinator_tracker.d.ts +29 -0
  105. package/dist/promise_combinator_tracker.d.ts.map +1 -0
  106. package/dist/promise_combinator_tracker.js +128 -0
  107. package/dist/promise_combinator_tracker.js.map +1 -0
  108. package/dist/public_api.d.ts +5 -5
  109. package/dist/public_api.d.ts.map +1 -1
  110. package/dist/public_api.js +60 -0
  111. package/dist/public_api.js.map +1 -0
  112. package/dist/state_machine.d.ts +19 -12
  113. package/dist/state_machine.d.ts.map +1 -1
  114. package/dist/state_machine.js +437 -0
  115. package/dist/state_machine.js.map +1 -0
  116. package/dist/types/errors.d.ts +12 -3
  117. package/dist/types/errors.d.ts.map +1 -1
  118. package/dist/types/errors.js +273 -0
  119. package/dist/types/errors.js.map +1 -0
  120. package/dist/types/grpc.d.ts +6 -4
  121. package/dist/types/grpc.d.ts.map +1 -1
  122. package/dist/types/grpc.js +81 -0
  123. package/dist/types/grpc.js.map +1 -0
  124. package/dist/types/protocol.d.ts +9 -5
  125. package/dist/types/protocol.d.ts.map +1 -1
  126. package/dist/types/protocol.js +147 -0
  127. package/dist/types/protocol.js.map +1 -0
  128. package/dist/types/router.d.ts +8 -8
  129. package/dist/types/router.d.ts.map +1 -1
  130. package/dist/types/router.js +36 -0
  131. package/dist/types/router.js.map +1 -0
  132. package/dist/types/types.d.ts +1 -0
  133. package/dist/types/types.d.ts.map +1 -1
  134. package/dist/types/types.js +138 -0
  135. package/dist/types/types.js.map +1 -0
  136. package/dist/utils/{assumpsions.d.ts → assumptions.d.ts} +1 -1
  137. package/dist/utils/{assumpsions.d.ts.map → assumptions.d.ts.map} +1 -1
  138. package/dist/utils/assumptions.js +101 -0
  139. package/dist/utils/assumptions.js.map +1 -0
  140. package/dist/utils/message_logger.d.ts +28 -0
  141. package/dist/utils/message_logger.d.ts.map +1 -0
  142. package/dist/utils/message_logger.js +88 -0
  143. package/dist/utils/message_logger.js.map +1 -0
  144. package/dist/utils/promises.d.ts +15 -0
  145. package/dist/utils/promises.d.ts.map +1 -0
  146. package/dist/utils/promises.js +67 -0
  147. package/dist/utils/promises.js.map +1 -0
  148. package/dist/utils/public_utils.js +49 -0
  149. package/dist/utils/public_utils.js.map +1 -0
  150. package/dist/utils/rand.d.ts +1 -1
  151. package/dist/utils/rand.d.ts.map +1 -1
  152. package/dist/utils/rand.js +114 -0
  153. package/dist/utils/rand.js.map +1 -0
  154. package/dist/utils/utils.d.ts +1 -10
  155. package/dist/utils/utils.d.ts.map +1 -1
  156. package/dist/utils/utils.js +122 -0
  157. package/dist/utils/utils.js.map +1 -0
  158. package/dist/workflows/workflow.d.ts +101 -0
  159. package/dist/workflows/workflow.d.ts.map +1 -0
  160. package/dist/workflows/workflow.js +80 -0
  161. package/dist/workflows/workflow.js.map +1 -0
  162. package/dist/workflows/workflow_state_service.d.ts +35 -0
  163. package/dist/workflows/workflow_state_service.d.ts.map +1 -0
  164. package/dist/workflows/workflow_state_service.js +201 -0
  165. package/dist/workflows/workflow_state_service.js.map +1 -0
  166. package/dist/workflows/workflow_wrapper_service.d.ts +10 -0
  167. package/dist/workflows/workflow_wrapper_service.d.ts.map +1 -0
  168. package/dist/workflows/workflow_wrapper_service.js +264 -0
  169. package/dist/workflows/workflow_wrapper_service.js.map +1 -0
  170. package/package.json +38 -39
  171. package/src/clients/workflow_client.ts +290 -0
  172. package/src/connection/buffered_connection.ts +47 -0
  173. package/src/connection/connection.ts +34 -0
  174. package/src/connection/embedded_connection.ts +62 -0
  175. package/src/connection/http_connection.ts +228 -0
  176. package/src/connection/lambda_connection.ts +69 -0
  177. package/src/context.ts +633 -0
  178. package/src/context_impl.ts +721 -0
  179. package/src/embedded/api.ts +57 -0
  180. package/src/embedded/handler.ts +36 -0
  181. package/src/embedded/http2_remote.ts +103 -0
  182. package/src/embedded/invocation.ts +126 -0
  183. package/src/endpoint/endpoint_impl.ts +623 -0
  184. package/src/endpoint/http2_handler.ts +151 -0
  185. package/src/endpoint/lambda_handler.ts +181 -0
  186. package/src/endpoint.ts +187 -0
  187. package/src/generated/dev/restate/events.ts +430 -0
  188. package/src/generated/dev/restate/ext.ts +238 -0
  189. package/src/generated/google/protobuf/descriptor.ts +7889 -0
  190. package/src/generated/google/protobuf/empty.ts +150 -0
  191. package/src/generated/google/protobuf/struct.ts +878 -0
  192. package/src/generated/proto/discovery.ts +423 -0
  193. package/src/generated/proto/dynrpc.ts +768 -0
  194. package/src/generated/proto/javascript.ts +488 -0
  195. package/src/generated/proto/protocol.ts +3091 -0
  196. package/src/generated/proto/services.ts +1834 -0
  197. package/src/generated/proto/test.ts +387 -0
  198. package/src/invocation.ts +212 -0
  199. package/src/io/decoder.ts +171 -0
  200. package/src/io/encoder.ts +72 -0
  201. package/src/journal.ts +537 -0
  202. package/src/local_state_store.ts +94 -0
  203. package/src/logger.ts +121 -0
  204. package/src/promise_combinator_tracker.ts +191 -0
  205. package/src/public_api.ts +53 -0
  206. package/src/state_machine.ts +635 -0
  207. package/src/types/errors.ts +297 -0
  208. package/src/types/grpc.ts +97 -0
  209. package/src/types/protocol.ts +201 -0
  210. package/src/types/router.ts +118 -0
  211. package/src/types/types.ts +160 -0
  212. package/src/utils/assumptions.ts +131 -0
  213. package/src/utils/message_logger.ts +112 -0
  214. package/src/utils/promises.ts +118 -0
  215. package/src/utils/public_utils.ts +91 -0
  216. package/src/utils/rand.ts +142 -0
  217. package/src/utils/utils.ts +178 -0
  218. package/src/workflows/workflow.ts +178 -0
  219. package/src/workflows/workflow_state_service.ts +299 -0
  220. package/src/workflows/workflow_wrapper_service.ts +314 -0
  221. package/dist/cloudflare_bundle.js +0 -27387
  222. package/dist/restate_context.d.ts.map +0 -1
  223. package/dist/restate_context_impl.d.ts.map +0 -1
  224. package/dist/server/base_restate_server.d.ts +0 -32
  225. package/dist/server/base_restate_server.d.ts.map +0 -1
  226. package/dist/server/restate_lambda_handler.d.ts +0 -104
  227. package/dist/server/restate_lambda_handler.d.ts.map +0 -1
  228. package/dist/server/restate_server.d.ts +0 -97
  229. package/dist/server/restate_server.d.ts.map +0 -1
  230. package/dist/utils/logger.d.ts +0 -60
  231. 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);