@restatedev/restate-sdk 0.0.0-SNAPSHOT-20231025205407
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 +21 -0
- package/README.md +157 -0
- package/dist/connection/connection.d.ts +19 -0
- package/dist/connection/connection.d.ts.map +1 -0
- package/dist/connection/connection.js +13 -0
- package/dist/connection/connection.js.map +1 -0
- package/dist/connection/embedded_connection.d.ts +22 -0
- package/dist/connection/embedded_connection.d.ts.map +1 -0
- package/dist/connection/embedded_connection.js +78 -0
- package/dist/connection/embedded_connection.js.map +1 -0
- package/dist/connection/http_connection.d.ts +73 -0
- package/dist/connection/http_connection.d.ts.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.d.ts +14 -0
- package/dist/connection/lambda_connection.d.ts.map +1 -0
- package/dist/connection/lambda_connection.js +56 -0
- package/dist/connection/lambda_connection.js.map +1 -0
- package/dist/embedded/api.d.ts +18 -0
- package/dist/embedded/api.d.ts.map +1 -0
- package/dist/embedded/api.js +37 -0
- package/dist/embedded/api.js.map +1 -0
- package/dist/embedded/handler.d.ts +4 -0
- package/dist/embedded/handler.d.ts.map +1 -0
- package/dist/embedded/handler.js +28 -0
- package/dist/embedded/handler.js.map +1 -0
- package/dist/embedded/http2_remote.d.ts +10 -0
- package/dist/embedded/http2_remote.d.ts.map +1 -0
- package/dist/embedded/http2_remote.js +85 -0
- package/dist/embedded/http2_remote.js.map +1 -0
- package/dist/embedded/invocation.d.ts +4 -0
- package/dist/embedded/invocation.d.ts.map +1 -0
- package/dist/embedded/invocation.js +90 -0
- package/dist/embedded/invocation.js.map +1 -0
- package/dist/generated/dev/restate/events.d.ts +96 -0
- package/dist/generated/dev/restate/events.d.ts.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.d.ts +88 -0
- package/dist/generated/dev/restate/ext.d.ts.map +1 -0
- package/dist/generated/dev/restate/ext.js +212 -0
- package/dist/generated/dev/restate/ext.js.map +1 -0
- package/dist/generated/google/protobuf/descriptor.d.ts +1204 -0
- package/dist/generated/google/protobuf/descriptor.d.ts.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.d.ts +86 -0
- package/dist/generated/google/protobuf/empty.d.ts.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.d.ts +175 -0
- package/dist/generated/google/protobuf/struct.d.ts.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.d.ts +105 -0
- package/dist/generated/proto/discovery.d.ts.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.d.ts +150 -0
- package/dist/generated/proto/dynrpc.d.ts.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 +97 -0
- package/dist/generated/proto/javascript.d.ts.map +1 -0
- package/dist/generated/proto/javascript.js +297 -0
- package/dist/generated/proto/javascript.js.map +1 -0
- package/dist/generated/proto/protocol.d.ts +371 -0
- package/dist/generated/proto/protocol.d.ts.map +1 -0
- package/dist/generated/proto/protocol.js +2179 -0
- package/dist/generated/proto/protocol.js.map +1 -0
- package/dist/generated/proto/services.d.ts +307 -0
- package/dist/generated/proto/services.d.ts.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.d.ts +116 -0
- package/dist/generated/proto/test.d.ts.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 +39 -0
- package/dist/invocation.d.ts.map +1 -0
- package/dist/invocation.js +138 -0
- package/dist/invocation.js.map +1 -0
- package/dist/io/decoder.d.ts +8 -0
- package/dist/io/decoder.d.ts.map +1 -0
- package/dist/io/decoder.js +133 -0
- package/dist/io/decoder.js.map +1 -0
- package/dist/io/encoder.d.ts +7 -0
- package/dist/io/encoder.d.ts.map +1 -0
- package/dist/io/encoder.js +57 -0
- package/dist/io/encoder.js.map +1 -0
- package/dist/journal.d.ts +42 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +368 -0
- package/dist/journal.js.map +1 -0
- package/dist/local_state_store.d.ts +13 -0
- package/dist/local_state_store.d.ts.map +1 -0
- package/dist/local_state_store.js +72 -0
- package/dist/local_state_store.js.map +1 -0
- package/dist/public_api.d.ts +10 -0
- package/dist/public_api.d.ts.map +1 -0
- package/dist/public_api.js +59 -0
- package/dist/public_api.js.map +1 -0
- package/dist/restate_context.d.ts +405 -0
- package/dist/restate_context.d.ts.map +1 -0
- package/dist/restate_context.js +46 -0
- package/dist/restate_context.js.map +1 -0
- package/dist/restate_context_impl.d.ts +54 -0
- package/dist/restate_context_impl.d.ts.map +1 -0
- package/dist/restate_context_impl.js +364 -0
- package/dist/restate_context_impl.js.map +1 -0
- package/dist/server/base_restate_server.d.ts +30 -0
- package/dist/server/base_restate_server.d.ts.map +1 -0
- package/dist/server/base_restate_server.js +360 -0
- package/dist/server/base_restate_server.js.map +1 -0
- package/dist/server/restate_lambda_handler.d.ts +104 -0
- package/dist/server/restate_lambda_handler.d.ts.map +1 -0
- package/dist/server/restate_lambda_handler.js +245 -0
- package/dist/server/restate_lambda_handler.js.map +1 -0
- package/dist/server/restate_server.d.ts +91 -0
- package/dist/server/restate_server.d.ts.map +1 -0
- package/dist/server/restate_server.js +230 -0
- package/dist/server/restate_server.js.map +1 -0
- package/dist/state_machine.d.ts +75 -0
- package/dist/state_machine.d.ts.map +1 -0
- package/dist/state_machine.js +380 -0
- package/dist/state_machine.js.map +1 -0
- package/dist/types/errors.d.ts +40 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +121 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/grpc.d.ts +88 -0
- package/dist/types/grpc.d.ts.map +1 -0
- package/dist/types/grpc.js +68 -0
- package/dist/types/grpc.js.map +1 -0
- package/dist/types/protocol.d.ts +24 -0
- package/dist/types/protocol.d.ts.map +1 -0
- package/dist/types/protocol.js +115 -0
- package/dist/types/protocol.js.map +1 -0
- package/dist/types/router.d.ts +33 -0
- package/dist/types/router.d.ts.map +1 -0
- package/dist/types/router.js +36 -0
- package/dist/types/router.js.map +1 -0
- package/dist/types/types.d.ts +30 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +125 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils/assumpsions.d.ts +8 -0
- package/dist/utils/assumpsions.d.ts.map +1 -0
- package/dist/utils/assumpsions.js +101 -0
- package/dist/utils/assumpsions.js.map +1 -0
- package/dist/utils/logger.d.ts +60 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +102 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/public_utils.d.ts +58 -0
- package/dist/utils/public_utils.d.ts.map +1 -0
- package/dist/utils/public_utils.js +49 -0
- package/dist/utils/public_utils.js.map +1 -0
- package/dist/utils/utils.d.ts +14 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +119 -0
- package/dist/utils/utils.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
|
|
4
|
+
*
|
|
5
|
+
* This file is part of the Restate SDK for Node.js/TypeScript,
|
|
6
|
+
* which is released under the MIT license.
|
|
7
|
+
*
|
|
8
|
+
* You can find a copy of the license in file LICENSE in the root
|
|
9
|
+
* directory of this repository or package, or at
|
|
10
|
+
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.LambdaRestateServer = exports.createLambdaApiGatewayHandler = void 0;
|
|
14
|
+
const logger_1 = require("../utils/logger");
|
|
15
|
+
const discovery_1 = require("../generated/proto/discovery");
|
|
16
|
+
const base_restate_server_1 = require("./base_restate_server");
|
|
17
|
+
const lambda_connection_1 = require("../connection/lambda_connection");
|
|
18
|
+
const invocation_1 = require("../invocation");
|
|
19
|
+
const decoder_1 = require("../io/decoder");
|
|
20
|
+
const state_machine_1 = require("../state_machine");
|
|
21
|
+
const errors_1 = require("../types/errors");
|
|
22
|
+
/**
|
|
23
|
+
* Creates an Restate entrypoint for services deployed on AWS Lambda and invoked
|
|
24
|
+
* through API Gateway.
|
|
25
|
+
*
|
|
26
|
+
* Register services on this entrypoint via {@link LambdaRestateServer.bindService } and
|
|
27
|
+
* then create the Lambda invocation handler via {@link LambdaRestateServer.handle }.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* A typical AWS Lambda entry point would look like this
|
|
31
|
+
* ```
|
|
32
|
+
* import * as restate from "@restatedev/restate-sdk";
|
|
33
|
+
*
|
|
34
|
+
* export const handler = restate
|
|
35
|
+
* .createLambdaApiGatewayHandler()
|
|
36
|
+
* .bindService({
|
|
37
|
+
* service: "MyService",
|
|
38
|
+
* instance: new myService.MyServiceImpl(),
|
|
39
|
+
* descriptor: myService.protoMetadata,
|
|
40
|
+
* })
|
|
41
|
+
* .handle();
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
function createLambdaApiGatewayHandler() {
|
|
45
|
+
return new LambdaRestateServer();
|
|
46
|
+
}
|
|
47
|
+
exports.createLambdaApiGatewayHandler = createLambdaApiGatewayHandler;
|
|
48
|
+
/**
|
|
49
|
+
* Restate entrypoint implementation for services deployed on AWS Lambda.
|
|
50
|
+
* This one decodes the requests, create the log event sequence that
|
|
51
|
+
* drives the durable execution of the service invocations.
|
|
52
|
+
*/
|
|
53
|
+
class LambdaRestateServer extends base_restate_server_1.BaseRestateServer {
|
|
54
|
+
constructor() {
|
|
55
|
+
super(discovery_1.ProtocolMode.REQUEST_RESPONSE);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Adds a gRPC service to be served from this endpoint.
|
|
59
|
+
*
|
|
60
|
+
* The {@link ServiceOpts} passed here need to describe the following properties:
|
|
61
|
+
*
|
|
62
|
+
* - The 'service' name: the name of the gRPC service (as in the service definition proto file).
|
|
63
|
+
* - The service 'instance': the implementation of the service logic (must implement the generated
|
|
64
|
+
* gRPC service interface).
|
|
65
|
+
* - The gRPC/protobuf 'descriptor': The protoMetadata descriptor that describes the service, methods,
|
|
66
|
+
* and parameter types. It is usually found as the value 'protoMetadata' in the generated
|
|
67
|
+
* file '(service-name).ts'
|
|
68
|
+
*
|
|
69
|
+
* The descriptor is generated by the protobuf compiler and needed by Restate to reflectively discover
|
|
70
|
+
* the service details, understand payload serialization, perform HTTP/JSON-to-gRPC transcoding, or
|
|
71
|
+
* to proxy the service.
|
|
72
|
+
*
|
|
73
|
+
* If you define multiple services in the same '.proto' file, you may have only one descriptor that
|
|
74
|
+
* describes all services together. You can pass the same descriptor to multiple calls of '.bindService()'.
|
|
75
|
+
*
|
|
76
|
+
* If you don't find the gRPC/protobuf descriptor, make your you generated the gRPC/ProtoBuf code with
|
|
77
|
+
* the option to generate the descriptor. For example, using the 'ts-proto' plugin, make sure you pass
|
|
78
|
+
* the 'outputSchema=true' option. If you are using Restate's project templates, this should all be
|
|
79
|
+
* pre-configured for you.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```
|
|
83
|
+
* endpoint.bindService({
|
|
84
|
+
* service: "MyService",
|
|
85
|
+
* instance: new myService.MyServiceImpl(),
|
|
86
|
+
* descriptor: myService.protoMetadata
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @param serviceOpts The options describing the service to be bound. See above for a detailed description.
|
|
91
|
+
* @returns An instance of this LambdaRestateServer
|
|
92
|
+
*/
|
|
93
|
+
bindService(serviceOpts) {
|
|
94
|
+
// Implementation note: This override if here mainly to change the return type to the more
|
|
95
|
+
// concrete type LambdaRestateServer (from BaseRestateServer).
|
|
96
|
+
super.bindService(serviceOpts);
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
bindRouter(path, router) {
|
|
100
|
+
super.bindRpcService(path, router, false);
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
bindKeyedRouter(path, router) {
|
|
104
|
+
super.bindRpcService(path, router, true);
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Creates the invocation handler function to be called by AWS Lambda.
|
|
109
|
+
*
|
|
110
|
+
* The returned type of this function is `(event: APIGatewayProxyEvent | APIGatewayProxyEventV2) => Promise<APIGatewayProxyResult | APIGatewayProxyResultV2>`.
|
|
111
|
+
* We use `any` types here to avoid a dependency on the `@types/aws-lambda` dependency for consumers of this API.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* A typical AWS Lambda entry point would use this method the follwing way:
|
|
115
|
+
* ```
|
|
116
|
+
* import * as restate from "@restatedev/restate-sdk";
|
|
117
|
+
*
|
|
118
|
+
* export const handler = restate
|
|
119
|
+
* .createLambdaApiGatewayHandler()
|
|
120
|
+
* .bindService({
|
|
121
|
+
* service: "MyService",
|
|
122
|
+
* instance: new myService.MyServiceImpl(),
|
|
123
|
+
* descriptor: myService.protoMetadata,
|
|
124
|
+
* })
|
|
125
|
+
* .handle();
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* @returns The invocation handler function for to be called by AWS Lambda.
|
|
129
|
+
*/
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
131
|
+
handle() {
|
|
132
|
+
// return the handler and bind the current context to it, so that it can find the other methods in this class.
|
|
133
|
+
return this.handleRequest.bind(this);
|
|
134
|
+
}
|
|
135
|
+
// --------------------------------------------------------------------------
|
|
136
|
+
/**
|
|
137
|
+
* This is the main request handling method, effectively a typed variant of `create()`.
|
|
138
|
+
*/
|
|
139
|
+
async handleRequest(event) {
|
|
140
|
+
let path;
|
|
141
|
+
if ("path" in event) {
|
|
142
|
+
// V1
|
|
143
|
+
path = event.path;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// V2
|
|
147
|
+
path = event.rawPath;
|
|
148
|
+
}
|
|
149
|
+
const pathSegments = path.split("/");
|
|
150
|
+
// API Gateway can add a prefix to the path based on the name of the Lambda function and deployment stage
|
|
151
|
+
// (e.g. /default)
|
|
152
|
+
// So we only check the ending of the path on correctness.
|
|
153
|
+
// Logic:
|
|
154
|
+
// 1. Check whether there are at least three segments in the path and whether the third-last one is "invoke".
|
|
155
|
+
// If that is the case, treat it as an invocation.
|
|
156
|
+
// 2. See if the last one is "discover", answer with discovery.
|
|
157
|
+
// 3. Else report "invalid path".
|
|
158
|
+
if (pathSegments.length >= 3 &&
|
|
159
|
+
pathSegments[pathSegments.length - 3] === "invoke") {
|
|
160
|
+
const url = "/" + pathSegments.slice(-3).join("/");
|
|
161
|
+
return await this.handleInvoke(url, event);
|
|
162
|
+
}
|
|
163
|
+
else if (pathSegments[pathSegments.length - 1] === "discover") {
|
|
164
|
+
return this.handleDiscovery();
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const msg = "Invalid path: path doesn't end in /invoke/SvcName/MethodName and also not in /discover: " +
|
|
168
|
+
path;
|
|
169
|
+
logger_1.rlog.error(msg);
|
|
170
|
+
logger_1.rlog.trace();
|
|
171
|
+
return this.toErrorResponse(500, msg);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async handleInvoke(url, event) {
|
|
175
|
+
try {
|
|
176
|
+
const method = this.methodByUrl(url);
|
|
177
|
+
if (event.body == null) {
|
|
178
|
+
throw new Error("The incoming message body was null");
|
|
179
|
+
}
|
|
180
|
+
if (method === undefined) {
|
|
181
|
+
if (url.includes("?")) {
|
|
182
|
+
throw new Error(`Invalid path: path URL seems to include query parameters: ${url}`);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
const msg = `No service found for URL: ${url}`;
|
|
186
|
+
logger_1.rlog.error(msg);
|
|
187
|
+
return this.toErrorResponse(404, msg);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// build the previous journal from the events
|
|
191
|
+
let decodedEntries = (0, decoder_1.decodeLambdaBody)(event.body);
|
|
192
|
+
const journalBuilder = new invocation_1.InvocationBuilder(method);
|
|
193
|
+
decodedEntries.forEach((e) => journalBuilder.handleMessage(e));
|
|
194
|
+
decodedEntries = null;
|
|
195
|
+
// set up and invoke the state machine
|
|
196
|
+
const connection = new lambda_connection_1.LambdaConnection();
|
|
197
|
+
const stateMachine = new state_machine_1.StateMachine(connection, journalBuilder.build(), discovery_1.ProtocolMode.REQUEST_RESPONSE);
|
|
198
|
+
await stateMachine.invoke();
|
|
199
|
+
const result = await connection.getResult();
|
|
200
|
+
return {
|
|
201
|
+
headers: {
|
|
202
|
+
"content-type": "application/restate",
|
|
203
|
+
},
|
|
204
|
+
statusCode: 200,
|
|
205
|
+
isBase64Encoded: true,
|
|
206
|
+
body: encodeResponse(result),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
catch (e) {
|
|
210
|
+
const error = (0, errors_1.ensureError)(e);
|
|
211
|
+
logger_1.rlog.error(error.message);
|
|
212
|
+
logger_1.rlog.error(error.stack);
|
|
213
|
+
return this.toErrorResponse(500, error.message);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
handleDiscovery() {
|
|
217
|
+
// return discovery information
|
|
218
|
+
logger_1.rlog.info("Answering discovery request. Registering these services: " +
|
|
219
|
+
JSON.stringify(this.discovery.services));
|
|
220
|
+
return {
|
|
221
|
+
headers: {
|
|
222
|
+
"content-type": "application/proto",
|
|
223
|
+
},
|
|
224
|
+
statusCode: 200,
|
|
225
|
+
isBase64Encoded: true,
|
|
226
|
+
body: encodeResponse(discovery_1.ServiceDiscoveryResponse.encode(this.discovery).finish()),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
toErrorResponse(code, message) {
|
|
230
|
+
return {
|
|
231
|
+
headers: {
|
|
232
|
+
"content-type": "application/restate",
|
|
233
|
+
},
|
|
234
|
+
statusCode: code,
|
|
235
|
+
isBase64Encoded: true,
|
|
236
|
+
body: encodeResponse(Buffer.from(JSON.stringify({ message }))),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.LambdaRestateServer = LambdaRestateServer;
|
|
241
|
+
function encodeResponse(data) {
|
|
242
|
+
const buffer = data instanceof Buffer ? data : Buffer.from(data);
|
|
243
|
+
return buffer.toString("base64");
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=restate_lambda_handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restate_lambda_handler.js","sourceRoot":"","sources":["../../src/server/restate_lambda_handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { BaseRestateServer, ServiceOpts } from "./base_restate_server";
|
|
2
|
+
import { KeyedRouter, UnKeyedRouter } from "../types/router";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a Restate entrypoint based on a HTTP2 server. The entrypoint will listen
|
|
5
|
+
* for requests to the services at a specified port.
|
|
6
|
+
*
|
|
7
|
+
* This is the entrypoint to be used in most scenarios (standalone, Docker, Kubernetes, ...);
|
|
8
|
+
* any deployments that forwards requests to a network endpoint. The prominent exception is
|
|
9
|
+
* AWS Lambda, which uses the {@link restate_lambda_handler#lambdaApiGatewayHandler}
|
|
10
|
+
* function to create an entry point.
|
|
11
|
+
*
|
|
12
|
+
* After creating this endpoint, register services on this entrypoint via {@link RestateServer.bindService }
|
|
13
|
+
* and start it via {@link RestateServer.listen }.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* A typical entry point would look like this:
|
|
17
|
+
* ```
|
|
18
|
+
* import * as restate from "@restatedev/restate-sdk";
|
|
19
|
+
*
|
|
20
|
+
* export const handler = restate
|
|
21
|
+
* .createServer()
|
|
22
|
+
* .bindService({
|
|
23
|
+
* service: "MyService",
|
|
24
|
+
* instance: new myService.MyServiceImpl(),
|
|
25
|
+
* descriptor: myService.protoMetadata,
|
|
26
|
+
* })
|
|
27
|
+
* .listen(8000);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function createServer(): RestateServer;
|
|
31
|
+
/**
|
|
32
|
+
* Restate entrypoint implementation for services. This server receives and
|
|
33
|
+
* decodes the requests, streams events between the service and the Restate runtime,
|
|
34
|
+
* and drives the durable execution of the service invocations.
|
|
35
|
+
*/
|
|
36
|
+
export declare class RestateServer extends BaseRestateServer {
|
|
37
|
+
constructor();
|
|
38
|
+
bindKeyedRouter<M>(path: string, router: KeyedRouter<M>): RestateServer;
|
|
39
|
+
bindRouter<M>(path: string, router: UnKeyedRouter<M>): RestateServer;
|
|
40
|
+
/**
|
|
41
|
+
* Adds a gRPC service to be served from this endpoint.
|
|
42
|
+
*
|
|
43
|
+
* The {@link ServiceOpts} passed here need to describe the following properties:
|
|
44
|
+
*
|
|
45
|
+
* - The 'service' name: the name of the gRPC service (as in the service definition proto file).
|
|
46
|
+
* - The service 'instance': the implementation of the service logic (must implement the generated
|
|
47
|
+
* gRPC service interface).
|
|
48
|
+
* - The gRPC/protobuf 'descriptor': The protoMetadata descriptor that describes the service, methods,
|
|
49
|
+
* and parameter types. It is usually found as the value 'protoMetadata' in the generated
|
|
50
|
+
* file '(service-name).ts'
|
|
51
|
+
*
|
|
52
|
+
* The descriptor is generated by the protobuf compiler and needed by Restate to reflectively discover
|
|
53
|
+
* the service details, understand payload serialization, perform HTTP/JSON-to-gRPC transcoding, or
|
|
54
|
+
* to proxy the service.
|
|
55
|
+
*
|
|
56
|
+
* If you define multiple services in the same '.proto' file, you may have only one descriptor that
|
|
57
|
+
* describes all services together. You can pass the same descriptor to multiple calls of '.bindService()'.
|
|
58
|
+
*
|
|
59
|
+
* If you don't find the gRPC/protobuf descriptor, make your you generated the gRPC/ProtoBuf code with
|
|
60
|
+
* the option to generate the descriptor. For example, using the 'ts-proto' plugin, make sure you pass
|
|
61
|
+
* the 'outputSchema=true' option. If you are using Restate's project templates, this should all be
|
|
62
|
+
* pre-configured for you.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```
|
|
66
|
+
* endpoint.bindService({
|
|
67
|
+
* service: "MyService",
|
|
68
|
+
* instance: new myService.MyServiceImpl(),
|
|
69
|
+
* descriptor: myService.protoMetadata
|
|
70
|
+
* })
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @param serviceOpts The options describing the service to be bound. See above for a detailed description.
|
|
74
|
+
* @returns An instance of this RestateServer
|
|
75
|
+
*/
|
|
76
|
+
bindService(serviceOpts: ServiceOpts): RestateServer;
|
|
77
|
+
/**
|
|
78
|
+
* Starts the Restate server and listens at the given port.
|
|
79
|
+
*
|
|
80
|
+
* If the port is undefined, this method will use the port set in the `PORT`
|
|
81
|
+
* environment variable. If that variable is undefined as well, the method will
|
|
82
|
+
* default to port 9080.
|
|
83
|
+
*
|
|
84
|
+
* This method's result promise never completes.
|
|
85
|
+
*
|
|
86
|
+
* @param port The port to listen at. May be undefined (see above).
|
|
87
|
+
*/
|
|
88
|
+
listen(port?: number): Promise<void>;
|
|
89
|
+
private handleConnection;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=restate_server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restate_server.d.ts","sourceRoot":"","sources":["../../src/server/restate_server.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAOvE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,IAAI,aAAa,CAE5C;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,iBAAiB;;IAK3C,eAAe,CAAC,CAAC,EACtB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,aAAa;IAOT,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa;IAO3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACI,WAAW,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa;IAO3D;;;;;;;;;;OAUG;IACU,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM;YAiBnB,gBAAgB;CAgC/B"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
|
|
4
|
+
*
|
|
5
|
+
* This file is part of the Restate SDK for Node.js/TypeScript,
|
|
6
|
+
* which is released under the MIT license.
|
|
7
|
+
*
|
|
8
|
+
* You can find a copy of the license in file LICENSE in the root
|
|
9
|
+
* directory of this repository or package, or at
|
|
10
|
+
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
|
|
11
|
+
*/
|
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.RestateServer = exports.createServer = void 0;
|
|
17
|
+
const events_1 = require("events");
|
|
18
|
+
const stream_1 = __importDefault(require("stream"));
|
|
19
|
+
const promises_1 = require("stream/promises");
|
|
20
|
+
const http2_1 = __importDefault(require("http2"));
|
|
21
|
+
const url_1 = require("url");
|
|
22
|
+
const discovery_1 = require("../generated/proto/discovery");
|
|
23
|
+
const base_restate_server_1 = require("./base_restate_server");
|
|
24
|
+
const logger_1 = require("../utils/logger");
|
|
25
|
+
const http_connection_1 = require("../connection/http_connection");
|
|
26
|
+
const errors_1 = require("../types/errors");
|
|
27
|
+
const invocation_1 = require("../invocation");
|
|
28
|
+
const state_machine_1 = require("../state_machine");
|
|
29
|
+
/**
|
|
30
|
+
* Creates a Restate entrypoint based on a HTTP2 server. The entrypoint will listen
|
|
31
|
+
* for requests to the services at a specified port.
|
|
32
|
+
*
|
|
33
|
+
* This is the entrypoint to be used in most scenarios (standalone, Docker, Kubernetes, ...);
|
|
34
|
+
* any deployments that forwards requests to a network endpoint. The prominent exception is
|
|
35
|
+
* AWS Lambda, which uses the {@link restate_lambda_handler#lambdaApiGatewayHandler}
|
|
36
|
+
* function to create an entry point.
|
|
37
|
+
*
|
|
38
|
+
* After creating this endpoint, register services on this entrypoint via {@link RestateServer.bindService }
|
|
39
|
+
* and start it via {@link RestateServer.listen }.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* A typical entry point would look like this:
|
|
43
|
+
* ```
|
|
44
|
+
* import * as restate from "@restatedev/restate-sdk";
|
|
45
|
+
*
|
|
46
|
+
* export const handler = restate
|
|
47
|
+
* .createServer()
|
|
48
|
+
* .bindService({
|
|
49
|
+
* service: "MyService",
|
|
50
|
+
* instance: new myService.MyServiceImpl(),
|
|
51
|
+
* descriptor: myService.protoMetadata,
|
|
52
|
+
* })
|
|
53
|
+
* .listen(8000);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function createServer() {
|
|
57
|
+
return new RestateServer();
|
|
58
|
+
}
|
|
59
|
+
exports.createServer = createServer;
|
|
60
|
+
/**
|
|
61
|
+
* Restate entrypoint implementation for services. This server receives and
|
|
62
|
+
* decodes the requests, streams events between the service and the Restate runtime,
|
|
63
|
+
* and drives the durable execution of the service invocations.
|
|
64
|
+
*/
|
|
65
|
+
class RestateServer extends base_restate_server_1.BaseRestateServer {
|
|
66
|
+
constructor() {
|
|
67
|
+
super(discovery_1.ProtocolMode.BIDI_STREAM);
|
|
68
|
+
}
|
|
69
|
+
bindKeyedRouter(path, router) {
|
|
70
|
+
// Implementation note: This override if here mainly to change the return type to the more
|
|
71
|
+
// concrete type RestateServer (from BaseRestateServer).
|
|
72
|
+
super.bindRpcService(path, router, true);
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
bindRouter(path, router) {
|
|
76
|
+
// Implementation note: This override if here mainly to change the return type to the more
|
|
77
|
+
// concrete type RestateServer (from BaseRestateServer).
|
|
78
|
+
super.bindRpcService(path, router, false);
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Adds a gRPC service to be served from this endpoint.
|
|
83
|
+
*
|
|
84
|
+
* The {@link ServiceOpts} passed here need to describe the following properties:
|
|
85
|
+
*
|
|
86
|
+
* - The 'service' name: the name of the gRPC service (as in the service definition proto file).
|
|
87
|
+
* - The service 'instance': the implementation of the service logic (must implement the generated
|
|
88
|
+
* gRPC service interface).
|
|
89
|
+
* - The gRPC/protobuf 'descriptor': The protoMetadata descriptor that describes the service, methods,
|
|
90
|
+
* and parameter types. It is usually found as the value 'protoMetadata' in the generated
|
|
91
|
+
* file '(service-name).ts'
|
|
92
|
+
*
|
|
93
|
+
* The descriptor is generated by the protobuf compiler and needed by Restate to reflectively discover
|
|
94
|
+
* the service details, understand payload serialization, perform HTTP/JSON-to-gRPC transcoding, or
|
|
95
|
+
* to proxy the service.
|
|
96
|
+
*
|
|
97
|
+
* If you define multiple services in the same '.proto' file, you may have only one descriptor that
|
|
98
|
+
* describes all services together. You can pass the same descriptor to multiple calls of '.bindService()'.
|
|
99
|
+
*
|
|
100
|
+
* If you don't find the gRPC/protobuf descriptor, make your you generated the gRPC/ProtoBuf code with
|
|
101
|
+
* the option to generate the descriptor. For example, using the 'ts-proto' plugin, make sure you pass
|
|
102
|
+
* the 'outputSchema=true' option. If you are using Restate's project templates, this should all be
|
|
103
|
+
* pre-configured for you.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```
|
|
107
|
+
* endpoint.bindService({
|
|
108
|
+
* service: "MyService",
|
|
109
|
+
* instance: new myService.MyServiceImpl(),
|
|
110
|
+
* descriptor: myService.protoMetadata
|
|
111
|
+
* })
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* @param serviceOpts The options describing the service to be bound. See above for a detailed description.
|
|
115
|
+
* @returns An instance of this RestateServer
|
|
116
|
+
*/
|
|
117
|
+
bindService(serviceOpts) {
|
|
118
|
+
// Implementation note: This override if here mainly to change the return type to the more
|
|
119
|
+
// concrete type RestateServer (from BaseRestateServer).
|
|
120
|
+
super.bindService(serviceOpts);
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Starts the Restate server and listens at the given port.
|
|
125
|
+
*
|
|
126
|
+
* If the port is undefined, this method will use the port set in the `PORT`
|
|
127
|
+
* environment variable. If that variable is undefined as well, the method will
|
|
128
|
+
* default to port 9080.
|
|
129
|
+
*
|
|
130
|
+
* This method's result promise never completes.
|
|
131
|
+
*
|
|
132
|
+
* @param port The port to listen at. May be undefined (see above).
|
|
133
|
+
*/
|
|
134
|
+
async listen(port) {
|
|
135
|
+
// Infer the port if not specified, or default it
|
|
136
|
+
const actualPort = port ?? parseInt(process.env.PORT ?? "9080");
|
|
137
|
+
logger_1.rlog.info(`Listening on ${actualPort}...`);
|
|
138
|
+
for await (const connection of incomingConnectionAtPort(actualPort)) {
|
|
139
|
+
this.handleConnection(connection.url, connection.stream).catch((e) => {
|
|
140
|
+
const error = (0, errors_1.ensureError)(e);
|
|
141
|
+
logger_1.rlog.error("Error while handling connection: " + (error.stack ?? error.message));
|
|
142
|
+
connection.stream.end();
|
|
143
|
+
connection.stream.destroy();
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async handleConnection(url, stream) {
|
|
148
|
+
const method = this.methodByUrl(url.path);
|
|
149
|
+
if (method !== undefined) {
|
|
150
|
+
// valid connection, let's dispatch the invocation
|
|
151
|
+
stream.respond({
|
|
152
|
+
"content-type": "application/restate",
|
|
153
|
+
":status": 200,
|
|
154
|
+
});
|
|
155
|
+
const restateStream = http_connection_1.RestateHttp2Connection.from(stream);
|
|
156
|
+
await handleInvocation(method, restateStream);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
// no method under that name. might be a discovery request
|
|
160
|
+
if (url.path == "/discover") {
|
|
161
|
+
logger_1.rlog.info("Answering discovery request. Registering these services: " +
|
|
162
|
+
JSON.stringify(this.discovery.services));
|
|
163
|
+
await respondDiscovery(this.discovery, stream);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// no discovery, so unknown method: 404
|
|
167
|
+
logger_1.rlog.error(`No service and function found for URL ${url.path}`);
|
|
168
|
+
await respondNotFound(stream);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.RestateServer = RestateServer;
|
|
172
|
+
async function* incomingConnectionAtPort(port) {
|
|
173
|
+
const server = http2_1.default.createServer();
|
|
174
|
+
server.on("error", (err) => logger_1.rlog.error("Error in Restate service endpoint http2 server: " + err));
|
|
175
|
+
server.listen(port);
|
|
176
|
+
let connectionId = 1n;
|
|
177
|
+
for await (const [s, h] of (0, events_1.on)(server, "stream")) {
|
|
178
|
+
const stream = s;
|
|
179
|
+
const headers = h;
|
|
180
|
+
const url = (0, url_1.parse)(headers[":path"] ?? "/");
|
|
181
|
+
connectionId++;
|
|
182
|
+
yield { connectionId, url, headers, stream };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function respondDiscovery(response, http2Stream) {
|
|
186
|
+
const responseData = discovery_1.ServiceDiscoveryResponse.encode(response).finish();
|
|
187
|
+
http2Stream.respond({
|
|
188
|
+
":status": 200,
|
|
189
|
+
"content-type": "application/proto",
|
|
190
|
+
});
|
|
191
|
+
await (0, promises_1.pipeline)(stream_1.default.Readable.from(responseData), http2Stream, {
|
|
192
|
+
end: true,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
async function respondNotFound(stream) {
|
|
196
|
+
stream.respond({
|
|
197
|
+
"content-type": "application/restate",
|
|
198
|
+
":status": 404,
|
|
199
|
+
});
|
|
200
|
+
stream.end();
|
|
201
|
+
await (0, promises_1.finished)(stream);
|
|
202
|
+
}
|
|
203
|
+
async function handleInvocation(func, connection) {
|
|
204
|
+
// step 1: collect all journal events
|
|
205
|
+
const journalBuilder = new invocation_1.InvocationBuilder(func);
|
|
206
|
+
connection.pipeToConsumer(journalBuilder);
|
|
207
|
+
try {
|
|
208
|
+
await journalBuilder.completion();
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
// ensure GC friendliness, also in case of errors
|
|
212
|
+
connection.removeCurrentConsumer();
|
|
213
|
+
}
|
|
214
|
+
// step 2: create the state machine
|
|
215
|
+
const stateMachine = new state_machine_1.StateMachine(connection, journalBuilder.build(), discovery_1.ProtocolMode.BIDI_STREAM);
|
|
216
|
+
connection.pipeToConsumer(stateMachine);
|
|
217
|
+
// step 3: invoke the function
|
|
218
|
+
// This call would propagate errors in the state machine logic, but not errors
|
|
219
|
+
// in the application function code. Ending a function with an error as well
|
|
220
|
+
// as failign an invocation and being retried are perfectly valid actions from the
|
|
221
|
+
// SDK's perspective.
|
|
222
|
+
try {
|
|
223
|
+
await stateMachine.invoke();
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
// ensure GC friendliness, also in case of errors
|
|
227
|
+
connection.removeCurrentConsumer();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=restate_server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restate_server.js","sourceRoot":"","sources":["../../src/server/restate_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import * as p from "./types/protocol";
|
|
3
|
+
import { Connection, RestateStreamConsumer } from "./connection/connection";
|
|
4
|
+
import { ProtocolMode } from "./generated/proto/discovery";
|
|
5
|
+
import { Message } from "./types/types";
|
|
6
|
+
import { Invocation } from "./invocation";
|
|
7
|
+
import { TerminalError, RetryableError } from "./types/errors";
|
|
8
|
+
import { LocalStateStore } from "./local_state_store";
|
|
9
|
+
export declare class StateMachine<I, O> implements RestateStreamConsumer {
|
|
10
|
+
private readonly connection;
|
|
11
|
+
private readonly invocation;
|
|
12
|
+
private readonly protocolMode;
|
|
13
|
+
private journal;
|
|
14
|
+
private restateContext;
|
|
15
|
+
private readonly invocationComplete;
|
|
16
|
+
private stateMachineClosed;
|
|
17
|
+
readonly localStateStore: LocalStateStore;
|
|
18
|
+
private inputChannelClosed;
|
|
19
|
+
private suspensionTimeout?;
|
|
20
|
+
private readonly suspensionMillis;
|
|
21
|
+
constructor(connection: Connection, invocation: Invocation<I, O>, protocolMode: ProtocolMode);
|
|
22
|
+
handleMessage(m: Message): boolean;
|
|
23
|
+
handleUserCodeMessage<T>(messageType: bigint, message: p.ProtocolMessage, completedFlag?: boolean, protocolVersion?: number, requiresAckFlag?: boolean): WrappedPromise<T | void>;
|
|
24
|
+
/**
|
|
25
|
+
* Invokes the RPC function and returns a promise that completes when the state machine
|
|
26
|
+
* stops processing the invocation, meaning when:
|
|
27
|
+
* - The function completes with a result or an exception
|
|
28
|
+
* - The execution suspends
|
|
29
|
+
* - An error is raised in the state machine (network, API violation, ...)
|
|
30
|
+
*
|
|
31
|
+
* The returned promise resolves successfully for all the cases above, because the are (from
|
|
32
|
+
* the perspective of the state machine) expected outcomes in which it send out corresponding
|
|
33
|
+
* result messages and cleanly closed the connection.
|
|
34
|
+
*
|
|
35
|
+
* The returned promise is rejected when an unhandled error arises and the caller would be
|
|
36
|
+
* expected to ensure that resources are properly cleaned up.
|
|
37
|
+
*/
|
|
38
|
+
invoke(): Promise<Buffer | void>;
|
|
39
|
+
private finishWithError;
|
|
40
|
+
private sendRetryableError;
|
|
41
|
+
private sendTerminalError;
|
|
42
|
+
private send;
|
|
43
|
+
/**
|
|
44
|
+
* Closes the state machine, flushes all output, and resolves the invocation promise.
|
|
45
|
+
*/
|
|
46
|
+
private finish;
|
|
47
|
+
/**
|
|
48
|
+
* This function propagates errors up to the completion promise, to be handled
|
|
49
|
+
* on the connection layer.
|
|
50
|
+
*/
|
|
51
|
+
private unhandledError;
|
|
52
|
+
private scheduleSuspension;
|
|
53
|
+
private getSuspensionMillis;
|
|
54
|
+
private suspend;
|
|
55
|
+
notifyHandlerExecutionError(e: RetryableError | TerminalError): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* WARNING: make sure you use this at the right point in the code
|
|
58
|
+
* After the index has been incremented...
|
|
59
|
+
* This is error-prone... Would be good to have a better solution for this.
|
|
60
|
+
*/
|
|
61
|
+
getUserCodeJournalIndex(): number;
|
|
62
|
+
getFullServiceName(): string;
|
|
63
|
+
handleInputClosed(): void;
|
|
64
|
+
handleStreamError(e: Error): void;
|
|
65
|
+
nextEntryWillBeReplayed(): boolean;
|
|
66
|
+
private clearSuspensionTimeout;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns a promise that wraps the original promise and calls cb() at the first time
|
|
70
|
+
* this promise or any nested promise that is chained to it is awaited. (then-ed)
|
|
71
|
+
*/
|
|
72
|
+
export type WrappedPromise<T> = Promise<T> & {
|
|
73
|
+
transform: <TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>;
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=state_machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state_machine.d.ts","sourceRoot":"","sources":["../src/state_machine.ts"],"names":[],"mappings":";AAWA,OAAO,KAAK,CAAC,MAAM,kBAAkB,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAaxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAEL,aAAa,EACb,cAAc,EAEf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,qBAAa,YAAY,CAAC,CAAC,EAAE,CAAC,CAAE,YAAW,qBAAqB;IA0B5D,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IA3B/B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,cAAc,CAAyB;IAE/C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2C;IAO9E,OAAO,CAAC,kBAAkB,CAAS;IAEnC,SAAgB,eAAe,EAAE,eAAe,CAAC;IAKjD,OAAO,CAAC,kBAAkB,CAAS;IAGnC,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAE3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;gBAGxB,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5B,YAAY,EAAE,YAAY;IAYtC,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO;IAiClC,qBAAqB,CAAC,CAAC,EAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,CAAC,CAAC,eAAe,EAC1B,aAAa,CAAC,EAAE,OAAO,EACvB,eAAe,CAAC,EAAE,MAAM,EACxB,eAAe,CAAC,EAAE,OAAO,GACxB,cAAc,CAAC,CAAC,GAAG,IAAI,CAAC;IA+C3B;;;;;;;;;;;;;OAaG;IACI,MAAM,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAsHzB,eAAe;IAU7B,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,IAAI;IAMZ;;OAEG;YACW,MAAM;IAcpB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,mBAAmB;YAOb,OAAO;IAoCR,2BAA2B,CAAC,CAAC,EAAE,cAAc,GAAG,aAAa;IAI1E;;;;OAIG;IACI,uBAAuB,IAAI,MAAM;IAIjC,kBAAkB,IAAI,MAAM;IAO5B,iBAAiB,IAAI,IAAI;IAsBzB,iBAAiB,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI;IASjC,uBAAuB;IAI9B,OAAO,CAAC,sBAAsB;CAM/B;AACD;;;GAGG;AAGH,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG;IAC3C,SAAS,EAAE,CAAC,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,KAAK,EACxC,WAAW,CAAC,EACR,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAChD,IAAI,GACJ,SAAS,EACb,UAAU,CAAC,EACP,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GACnD,IAAI,GACJ,SAAS,KACV,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;CACnC,CAAC"}
|