@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,91 @@
|
|
|
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
|
+
/**
|
|
13
|
+
* Retry policy that decides how to delay between retries.
|
|
14
|
+
*/
|
|
15
|
+
export interface RetryPolicy {
|
|
16
|
+
computeNextDelay(previousDelayMs: number): number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A {@link RetryPolicy} that keeps a fixed delay between retries.
|
|
21
|
+
*/
|
|
22
|
+
export const FIXED_DELAY: RetryPolicy = {
|
|
23
|
+
computeNextDelay(previousDelayMs: number): number {
|
|
24
|
+
return previousDelayMs;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A {@link RetryPolicy} that does an exponential backoff delay between retries.
|
|
30
|
+
* Each delay is twice as long as the previous delay.
|
|
31
|
+
*/
|
|
32
|
+
export const EXPONENTIAL_BACKOFF: RetryPolicy = {
|
|
33
|
+
computeNextDelay(previousDelayMs: number): number {
|
|
34
|
+
return 2 * previousDelayMs;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* All properties related to retrying, like the policy (exponential, fixed, ...), the
|
|
40
|
+
* initial delay, the maximum number of retries.
|
|
41
|
+
*/
|
|
42
|
+
export interface RetrySettings {
|
|
43
|
+
/**
|
|
44
|
+
* The initial delay between retries. As more retries happen, the delay may change per the policy.
|
|
45
|
+
*/
|
|
46
|
+
initialDelayMs?: number;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Optionally, the maximum delay between retries. No matter what the policy says, this is the maximum time
|
|
50
|
+
* that Restate sleeps between retries.
|
|
51
|
+
* If not set, there is effectively no limit (internally the limit is Number.MAX_SAFE_INTEGER).
|
|
52
|
+
*/
|
|
53
|
+
maxDelayMs?: number;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Optionally, the maximum number of retries before this function fails with an exception.
|
|
57
|
+
* If not set, there is effectively no limit (internally the limit is Number.MAX_SAFE_INTEGER).
|
|
58
|
+
*/
|
|
59
|
+
maxRetries?: number;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Optionally, the {@link RetryPolicy} to use. Defaults to {@link EXPONENTIAL_BACKOFF}.
|
|
63
|
+
*/
|
|
64
|
+
policy?: RetryPolicy;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Optionally, the name of side effect action that is used in error- and log messages around retries.
|
|
68
|
+
*/
|
|
69
|
+
name?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The default initial delay between retries: 10 milliseconds.
|
|
74
|
+
*/
|
|
75
|
+
export const DEFAULT_INITIAL_DELAY_MS = 10;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Default retry policy that retries an infinite number of times, with exponential backoff
|
|
79
|
+
* and a starting delay of 10 milliseconds.
|
|
80
|
+
*/
|
|
81
|
+
export const DEFAULT_INFINITE_EXPONENTIAL_BACKOFF: RetrySettings = {
|
|
82
|
+
initialDelayMs: DEFAULT_INITIAL_DELAY_MS,
|
|
83
|
+
maxDelayMs: Number.MAX_SAFE_INTEGER,
|
|
84
|
+
maxRetries: Number.MAX_SAFE_INTEGER,
|
|
85
|
+
policy: EXPONENTIAL_BACKOFF,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Retry policy that does no retries.
|
|
90
|
+
*/
|
|
91
|
+
export const NO_RETRIES: RetrySettings = { maxRetries: 0 };
|
|
@@ -0,0 +1,142 @@
|
|
|
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
|
+
//! Some parts copied from https://github.com/uuidjs/uuid/blob/main/src/stringify.js
|
|
13
|
+
//! License MIT
|
|
14
|
+
|
|
15
|
+
import { Rand } from "../context";
|
|
16
|
+
import { ErrorCodes, TerminalError } from "../types/errors";
|
|
17
|
+
import { CallContexType, ContextImpl } from "../context_impl";
|
|
18
|
+
import { createHash } from "crypto";
|
|
19
|
+
|
|
20
|
+
export class RandImpl implements Rand {
|
|
21
|
+
private randstate256: [bigint, bigint, bigint, bigint];
|
|
22
|
+
|
|
23
|
+
constructor(id: Buffer | [bigint, bigint, bigint, bigint]) {
|
|
24
|
+
if (id instanceof Buffer) {
|
|
25
|
+
// hash the invocation ID, which is known to contain 74 bits of entropy
|
|
26
|
+
const hash = createHash("sha256").update(id).digest();
|
|
27
|
+
|
|
28
|
+
this.randstate256 = [
|
|
29
|
+
hash.readBigUInt64LE(0),
|
|
30
|
+
hash.readBigUInt64LE(8),
|
|
31
|
+
hash.readBigUInt64LE(16),
|
|
32
|
+
hash.readBigUInt64LE(24),
|
|
33
|
+
];
|
|
34
|
+
} else {
|
|
35
|
+
this.randstate256 = id;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static U64_MASK = (1n << 64n) - 1n;
|
|
40
|
+
|
|
41
|
+
// xoshiro256++
|
|
42
|
+
// https://prng.di.unimi.it/xoshiro256plusplus.c - public domain
|
|
43
|
+
u64(): bigint {
|
|
44
|
+
const result: bigint =
|
|
45
|
+
(RandImpl.rotl(
|
|
46
|
+
(this.randstate256[0] + this.randstate256[3]) & RandImpl.U64_MASK,
|
|
47
|
+
23n
|
|
48
|
+
) +
|
|
49
|
+
this.randstate256[0]) &
|
|
50
|
+
RandImpl.U64_MASK;
|
|
51
|
+
|
|
52
|
+
const t: bigint = (this.randstate256[1] << 17n) & RandImpl.U64_MASK;
|
|
53
|
+
|
|
54
|
+
this.randstate256[2] ^= this.randstate256[0];
|
|
55
|
+
this.randstate256[3] ^= this.randstate256[1];
|
|
56
|
+
this.randstate256[1] ^= this.randstate256[2];
|
|
57
|
+
this.randstate256[0] ^= this.randstate256[3];
|
|
58
|
+
|
|
59
|
+
this.randstate256[2] ^= t;
|
|
60
|
+
|
|
61
|
+
this.randstate256[3] = RandImpl.rotl(this.randstate256[3], 45n);
|
|
62
|
+
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static rotl(x: bigint, k: bigint): bigint {
|
|
67
|
+
return ((x << k) & RandImpl.U64_MASK) | (x >> (64n - k));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
checkContext() {
|
|
71
|
+
const context = ContextImpl.callContext.getStore();
|
|
72
|
+
if (context && context.type === CallContexType.SideEffect) {
|
|
73
|
+
throw new TerminalError(
|
|
74
|
+
`You may not call methods on Rand from within a side effect.`,
|
|
75
|
+
{ errorCode: ErrorCodes.INTERNAL }
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static U53_MASK = (1n << 53n) - 1n;
|
|
81
|
+
|
|
82
|
+
public random(): number {
|
|
83
|
+
this.checkContext();
|
|
84
|
+
|
|
85
|
+
// first generate a uint in range [0,2^53), which can be mapped 1:1 to a float64 in [0,1)
|
|
86
|
+
const u53 = this.u64() & RandImpl.U53_MASK;
|
|
87
|
+
// then divide by 2^53, which will simply update the exponent
|
|
88
|
+
return Number(u53) / 2 ** 53;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public uuidv4(): string {
|
|
92
|
+
this.checkContext();
|
|
93
|
+
|
|
94
|
+
const buf = Buffer.alloc(16);
|
|
95
|
+
buf.writeBigUInt64LE(this.u64(), 0);
|
|
96
|
+
buf.writeBigUInt64LE(this.u64(), 8);
|
|
97
|
+
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
|
98
|
+
buf[6] = (buf[6] & 0x0f) | 0x40;
|
|
99
|
+
buf[8] = (buf[8] & 0x3f) | 0x80;
|
|
100
|
+
return uuidStringify(buf);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const byteToHex: string[] = [];
|
|
105
|
+
|
|
106
|
+
for (let i = 0; i < 256; ++i) {
|
|
107
|
+
byteToHex.push((i + 0x100).toString(16).slice(1));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Convert array of 16 byte values to UUID string format of the form:
|
|
112
|
+
* XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
|
113
|
+
*/
|
|
114
|
+
function uuidStringify(arr: Buffer, offset = 0) {
|
|
115
|
+
// Note: Be careful editing this code! It's been tuned for performance
|
|
116
|
+
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
|
|
117
|
+
//
|
|
118
|
+
// Note to future-self: No, you can't remove the `toLowerCase()` call.
|
|
119
|
+
// REF: https://github.com/uuidjs/uuid/pull/677#issuecomment-1757351351
|
|
120
|
+
return (
|
|
121
|
+
byteToHex[arr[offset + 0]] +
|
|
122
|
+
byteToHex[arr[offset + 1]] +
|
|
123
|
+
byteToHex[arr[offset + 2]] +
|
|
124
|
+
byteToHex[arr[offset + 3]] +
|
|
125
|
+
"-" +
|
|
126
|
+
byteToHex[arr[offset + 4]] +
|
|
127
|
+
byteToHex[arr[offset + 5]] +
|
|
128
|
+
"-" +
|
|
129
|
+
byteToHex[arr[offset + 6]] +
|
|
130
|
+
byteToHex[arr[offset + 7]] +
|
|
131
|
+
"-" +
|
|
132
|
+
byteToHex[arr[offset + 8]] +
|
|
133
|
+
byteToHex[arr[offset + 9]] +
|
|
134
|
+
"-" +
|
|
135
|
+
byteToHex[arr[offset + 10]] +
|
|
136
|
+
byteToHex[arr[offset + 11]] +
|
|
137
|
+
byteToHex[arr[offset + 12]] +
|
|
138
|
+
byteToHex[arr[offset + 13]] +
|
|
139
|
+
byteToHex[arr[offset + 14]] +
|
|
140
|
+
byteToHex[arr[offset + 15]]
|
|
141
|
+
).toLowerCase();
|
|
142
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
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 {
|
|
15
|
+
BackgroundInvokeEntryMessage,
|
|
16
|
+
ClearStateEntryMessage,
|
|
17
|
+
CompleteAwakeableEntryMessage,
|
|
18
|
+
GetStateEntryMessage,
|
|
19
|
+
InvokeEntryMessage,
|
|
20
|
+
OutputStreamEntryMessage,
|
|
21
|
+
SetStateEntryMessage,
|
|
22
|
+
} from "../generated/proto/protocol";
|
|
23
|
+
import {
|
|
24
|
+
AWAKEABLE_ENTRY_MESSAGE_TYPE,
|
|
25
|
+
BACKGROUND_INVOKE_ENTRY_MESSAGE_TYPE,
|
|
26
|
+
CLEAR_STATE_ENTRY_MESSAGE_TYPE,
|
|
27
|
+
COMPLETE_AWAKEABLE_ENTRY_MESSAGE_TYPE,
|
|
28
|
+
GET_STATE_ENTRY_MESSAGE_TYPE,
|
|
29
|
+
INVOKE_ENTRY_MESSAGE_TYPE,
|
|
30
|
+
OUTPUT_STREAM_ENTRY_MESSAGE_TYPE,
|
|
31
|
+
SET_STATE_ENTRY_MESSAGE_TYPE,
|
|
32
|
+
SIDE_EFFECT_ENTRY_MESSAGE_TYPE,
|
|
33
|
+
SLEEP_ENTRY_MESSAGE_TYPE,
|
|
34
|
+
} from "../types/protocol";
|
|
35
|
+
|
|
36
|
+
export function jsonSerialize(obj: any): string {
|
|
37
|
+
return JSON.stringify(obj, (_, v) =>
|
|
38
|
+
typeof v === "bigint" ? "BIGINT::" + v.toString() : v
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function jsonDeserialize<T>(json: string): T {
|
|
43
|
+
return JSON.parse(json, (_, v) =>
|
|
44
|
+
typeof v === "string" && v.startsWith("BIGINT::")
|
|
45
|
+
? BigInt(v.substring(8))
|
|
46
|
+
: v
|
|
47
|
+
) as T;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// When using google.protobuf.Value in RPC handler responses, we want to roughly match the behaviour of JSON.stringify
|
|
51
|
+
// for example in converting Date objects to a UTC string
|
|
52
|
+
export function jsonSafeAny(key: string, value: any): any {
|
|
53
|
+
if (
|
|
54
|
+
value !== undefined &&
|
|
55
|
+
value !== null &&
|
|
56
|
+
typeof value.toJSON == "function"
|
|
57
|
+
) {
|
|
58
|
+
return value.toJSON(key) as any;
|
|
59
|
+
} else if (globalThis.Array.isArray(value)) {
|
|
60
|
+
// in place replace
|
|
61
|
+
value.forEach((_, i) => (value[i] = jsonSafeAny(i.toString(), value[i])));
|
|
62
|
+
return value;
|
|
63
|
+
} else if (typeof value === "object") {
|
|
64
|
+
Object.keys(value).forEach((key) => {
|
|
65
|
+
value[key] = jsonSafeAny(key, value[key]);
|
|
66
|
+
});
|
|
67
|
+
return value;
|
|
68
|
+
} else {
|
|
69
|
+
// primitive that doesn't have a toJSON method, with no children
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function formatMessageAsJson(obj: any): string {
|
|
75
|
+
const newObj = { ...(obj as Record<string, unknown>) };
|
|
76
|
+
for (const [key, value] of Object.entries(newObj)) {
|
|
77
|
+
if (Buffer.isBuffer(value)) {
|
|
78
|
+
newObj[key] = value.toString().trim();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Stringify object. Replace bigintToString serializer to prevent "BigInt not serializable" errors
|
|
82
|
+
return JSON.stringify(obj, (_, v) =>
|
|
83
|
+
typeof v === "bigint" ? v.toString() + "n" : v
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Equality functions
|
|
89
|
+
* @param msg1 the current message from user code
|
|
90
|
+
* @param msg2 the replayed message
|
|
91
|
+
*/
|
|
92
|
+
// These functions are used to check whether a replayed message matches the current user code.
|
|
93
|
+
// We check the fields which we can check
|
|
94
|
+
// (the fields which do not contain results, because these might be filled in the result)
|
|
95
|
+
|
|
96
|
+
const getStateMsgEquality = (
|
|
97
|
+
msg1: GetStateEntryMessage,
|
|
98
|
+
msg2: GetStateEntryMessage
|
|
99
|
+
) => {
|
|
100
|
+
return msg1.key.equals(msg2.key);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const invokeMsgEquality = (
|
|
104
|
+
msg1: InvokeEntryMessage | BackgroundInvokeEntryMessage,
|
|
105
|
+
msg2: InvokeEntryMessage | BackgroundInvokeEntryMessage
|
|
106
|
+
) => {
|
|
107
|
+
return (
|
|
108
|
+
msg1.serviceName === msg2.serviceName &&
|
|
109
|
+
msg1.methodName === msg2.methodName &&
|
|
110
|
+
msg1.parameter.equals(msg2.parameter)
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const setStateMsgEquality = (
|
|
115
|
+
msg1: SetStateEntryMessage,
|
|
116
|
+
msg2: SetStateEntryMessage
|
|
117
|
+
) => {
|
|
118
|
+
return msg1.key.equals(msg2.key) && msg1.value.equals(msg2.value);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const clearStateMsgEquality = (
|
|
122
|
+
msg1: ClearStateEntryMessage,
|
|
123
|
+
msg2: ClearStateEntryMessage
|
|
124
|
+
) => {
|
|
125
|
+
return msg1.key.equals(msg2.key);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const completeAwakeableMsgEquality = (
|
|
129
|
+
msg1: CompleteAwakeableEntryMessage,
|
|
130
|
+
msg2: CompleteAwakeableEntryMessage
|
|
131
|
+
) => {
|
|
132
|
+
if (!(msg1.id === msg2.id)) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (msg1.value && msg2.value) {
|
|
137
|
+
return msg1.value.equals(msg2.value);
|
|
138
|
+
} else if (msg1.failure && msg2.failure) {
|
|
139
|
+
return (
|
|
140
|
+
msg1.failure?.code === msg2.failure?.code &&
|
|
141
|
+
msg1.failure?.message === msg2.failure?.message
|
|
142
|
+
);
|
|
143
|
+
} else {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const outputMsgEquality = (
|
|
149
|
+
msg1: OutputStreamEntryMessage,
|
|
150
|
+
msg2: OutputStreamEntryMessage
|
|
151
|
+
) => {
|
|
152
|
+
if (msg1.value && msg2.value) {
|
|
153
|
+
return msg1.value.equals(msg2.value);
|
|
154
|
+
} else if (msg1.failure && msg2.failure) {
|
|
155
|
+
return (
|
|
156
|
+
msg1.failure?.code === msg2.failure?.code &&
|
|
157
|
+
msg1.failure?.message === msg2.failure?.message
|
|
158
|
+
);
|
|
159
|
+
} else {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const equalityCheckers = new Map<
|
|
165
|
+
bigint,
|
|
166
|
+
(msg1: any, msg2: any) => boolean
|
|
167
|
+
>([
|
|
168
|
+
[GET_STATE_ENTRY_MESSAGE_TYPE, getStateMsgEquality],
|
|
169
|
+
[SET_STATE_ENTRY_MESSAGE_TYPE, setStateMsgEquality],
|
|
170
|
+
[CLEAR_STATE_ENTRY_MESSAGE_TYPE, clearStateMsgEquality],
|
|
171
|
+
[INVOKE_ENTRY_MESSAGE_TYPE, invokeMsgEquality],
|
|
172
|
+
[BACKGROUND_INVOKE_ENTRY_MESSAGE_TYPE, invokeMsgEquality],
|
|
173
|
+
[COMPLETE_AWAKEABLE_ENTRY_MESSAGE_TYPE, completeAwakeableMsgEquality],
|
|
174
|
+
[OUTPUT_STREAM_ENTRY_MESSAGE_TYPE, outputMsgEquality],
|
|
175
|
+
[AWAKEABLE_ENTRY_MESSAGE_TYPE, () => true],
|
|
176
|
+
[SIDE_EFFECT_ENTRY_MESSAGE_TYPE, () => true],
|
|
177
|
+
[SLEEP_ENTRY_MESSAGE_TYPE, () => true],
|
|
178
|
+
]);
|
|
@@ -0,0 +1,178 @@
|
|
|
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 * as restate from "../public_api";
|
|
13
|
+
import * as wws from "./workflow_wrapper_service";
|
|
14
|
+
import * as wss from "./workflow_state_service";
|
|
15
|
+
|
|
16
|
+
const STATE_SERVICE_PATH_SUFFIX = "_state";
|
|
17
|
+
|
|
18
|
+
// ----------------------------------------------------------------------------
|
|
19
|
+
// workflow definition / registration
|
|
20
|
+
// ----------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new workflow service that will be served under the given path.
|
|
24
|
+
*
|
|
25
|
+
* A workflow must consist of
|
|
26
|
+
* - one run method: `run(ctx: WfContext, params: T) => Promise<R>`
|
|
27
|
+
* - an arbitrary number of interaction methods: `foo(ctx: SharedWfContext, params: X) => Promise<Y>`
|
|
28
|
+
*/
|
|
29
|
+
export function workflow<R, T, U>(
|
|
30
|
+
path: string,
|
|
31
|
+
workflow: Workflow<R, T, U>
|
|
32
|
+
): WorkflowServices<R, T, U> {
|
|
33
|
+
// the state service manages all state and promises for us
|
|
34
|
+
const stateServiceRouter = wss.workflowStateService;
|
|
35
|
+
const stateServiceApi: restate.ServiceApi<wss.api> = {
|
|
36
|
+
path: path + STATE_SERVICE_PATH_SUFFIX,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// the wrapper service manages life cycle, contexts, delegation to the state service
|
|
40
|
+
const wrapperServiceRouter = wws.createWrapperService(
|
|
41
|
+
workflow,
|
|
42
|
+
path,
|
|
43
|
+
stateServiceApi
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
api: { path } as restate.ServiceApi<WorkflowRestateRpcApi<R, T, U>>,
|
|
48
|
+
registerServices: (endpoint: restate.RestateEndpoint) => {
|
|
49
|
+
endpoint.bindKeyedRouter(stateServiceApi.path, stateServiceRouter);
|
|
50
|
+
endpoint.bindRouter(path, wrapperServiceRouter);
|
|
51
|
+
},
|
|
52
|
+
} satisfies WorkflowServices<R, T, U>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The type signature of a workflow.
|
|
57
|
+
* A workflow must consist of
|
|
58
|
+
* - one run method: `run(ctx: WfContext, params: T) => Promise<R>`
|
|
59
|
+
* - an arbitrary number of interaction methods: `foo(ctx: SharedWfContext, params: T) => Promise<R>`
|
|
60
|
+
*/
|
|
61
|
+
export type Workflow<R, T, U> = {
|
|
62
|
+
run: RunMethod<R, T>;
|
|
63
|
+
} & WorkflowMethods<R, T, U>;
|
|
64
|
+
|
|
65
|
+
type RunMethod<R, T> = (ctx: WfContext, params: T) => Promise<R>;
|
|
66
|
+
type InteractionMethod<R, T> = (ctx: SharedWfContext, params: T) => Promise<R>;
|
|
67
|
+
|
|
68
|
+
type WorkflowMethods<R, T, U> = {
|
|
69
|
+
[K in keyof U]: K extends "run"
|
|
70
|
+
? U[K] extends RunMethod<R, T>
|
|
71
|
+
? U[K]
|
|
72
|
+
: "The 'run' methods needs to follow the signature: (ctx: WfContext, params: any) => Promise<any> "
|
|
73
|
+
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
|
+
U[K] extends InteractionMethod<any, any>
|
|
75
|
+
? U[K]
|
|
76
|
+
: "Methods other than 'run' are interaction methods and need to follow the signature: (ctx: SharedWfContext, params: any) => Promise<any>";
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The workflow service(s) and API.
|
|
81
|
+
*
|
|
82
|
+
* Register at a Restate endpoint (HTTP/2, Lambda, etc.) as follows:
|
|
83
|
+
* ```
|
|
84
|
+
* const myWorkflow = restate.workflows.workflow("org.acme.myworkflow", {
|
|
85
|
+
* // workflow implementation
|
|
86
|
+
* })
|
|
87
|
+
* restate.createServer().bind(myWorkflow)
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* The {@link WorkflowServices.api} can be used to create typed clients, both
|
|
91
|
+
* from other Restate-backed serviced (e.g., `ctx.rpc(api).triggerMySignal()`)
|
|
92
|
+
* or from external clients (`clients.connectWorkflows(restateUri).connectToWorkflow(api, id);`).
|
|
93
|
+
*/
|
|
94
|
+
export interface WorkflowServices<R, T, U> extends restate.ServiceBundle {
|
|
95
|
+
readonly api: restate.ServiceApi<WorkflowRestateRpcApi<R, T, U>>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ----------------------------------------------------------------------------
|
|
99
|
+
// workflow-specific types (promises, contexts)
|
|
100
|
+
// ----------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
export type DurablePromise<T> = restate.CombineablePromise<T> & {
|
|
103
|
+
peek(): Promise<T | null>;
|
|
104
|
+
|
|
105
|
+
resolve(value?: T): void;
|
|
106
|
+
reject(errorMsg: string): void;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The context for the workflow's interaction methods, which are all methods
|
|
111
|
+
* other than the 'run()' method.
|
|
112
|
+
*
|
|
113
|
+
* This gives primarily access to state reads and promises.
|
|
114
|
+
*/
|
|
115
|
+
export interface SharedWfContext {
|
|
116
|
+
workflowId(): string;
|
|
117
|
+
|
|
118
|
+
get<T>(stateName: string): Promise<T | null>;
|
|
119
|
+
|
|
120
|
+
promise<T = void>(name: string): DurablePromise<T>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The context for the workflow's 'run()' function.
|
|
125
|
+
*
|
|
126
|
+
* This is a full context as for stateful durable keyed services, plus the
|
|
127
|
+
* workflow-specific bits, like workflowID and durable promises.
|
|
128
|
+
*/
|
|
129
|
+
export interface WfContext extends SharedWfContext, restate.KeyedContext {}
|
|
130
|
+
|
|
131
|
+
export enum LifecycleStatus {
|
|
132
|
+
NOT_STARTED = "NOT_STARTED",
|
|
133
|
+
RUNNING = "RUNNING",
|
|
134
|
+
FINISHED = "FINISHED",
|
|
135
|
+
FAILED = "FAILED",
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export enum WorkflowStartResult {
|
|
139
|
+
STARTED = "STARTED",
|
|
140
|
+
ALREADY_STARTED = "ALREADY_STARTED",
|
|
141
|
+
ALREADY_FINISHED = "ALREADY_FINISHED",
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ----------------------------------------------------------------------------
|
|
145
|
+
// types and signatures for typed clients
|
|
146
|
+
// ----------------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The type of requests accepted by the workflow service.
|
|
150
|
+
* Must contain the 'workflowId' property.
|
|
151
|
+
*/
|
|
152
|
+
export type WorkflowRequest<T> = T & { workflowId: string };
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The API signature of the workflow for use with RPC operations from Restate services.
|
|
156
|
+
*/
|
|
157
|
+
export type WorkflowRestateRpcApi<R, T, U> = {
|
|
158
|
+
start: (param: WorkflowRequest<T>) => Promise<WorkflowStartResult>;
|
|
159
|
+
waitForResult: (request: WorkflowRequest<unknown>) => Promise<R>;
|
|
160
|
+
status: (request: WorkflowRequest<unknown>) => Promise<LifecycleStatus>;
|
|
161
|
+
} & {
|
|
162
|
+
[K in keyof Omit<U, "run">]: U[K] extends InteractionMethod<infer R, infer T>
|
|
163
|
+
? (request: WorkflowRequest<T>) => Promise<R>
|
|
164
|
+
: never;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The API signature of the workflow for external clients.
|
|
169
|
+
*/
|
|
170
|
+
export type WorkflowClientApi<U> = {
|
|
171
|
+
[K in keyof Omit<U, "run">]: U[K] extends (
|
|
172
|
+
ctx: SharedWfContext
|
|
173
|
+
) => Promise<infer R>
|
|
174
|
+
? () => Promise<R>
|
|
175
|
+
: U[K] extends (ctx: SharedWfContext, params: infer T) => Promise<infer R>
|
|
176
|
+
? (request: T) => Promise<R>
|
|
177
|
+
: never;
|
|
178
|
+
};
|