@restatedev/restate-sdk-testcontainers 1.13.0 → 1.14.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/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/restate-sdk-core/src/serde_api.d.cts +98 -0
- package/dist/restate-sdk-core/src/serde_api.d.cts.map +1 -1
- package/dist/restate-sdk-core/src/serde_api.d.ts +98 -0
- package/dist/restate-sdk-core/src/serde_api.d.ts.map +1 -1
- package/dist/restate_test_environment.cjs +27 -18
- package/dist/restate_test_environment.d.cts +38 -11
- package/dist/restate_test_environment.d.cts.map +1 -1
- package/dist/restate_test_environment.d.ts +38 -11
- package/dist/restate_test_environment.d.ts.map +1 -1
- package/dist/restate_test_environment.js +28 -19
- package/dist/restate_test_environment.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -10,5 +10,5 @@ import { LogMetadata, LogSource, LoggerContext, LoggerTransport, RestateLogLevel
|
|
|
10
10
|
import { DefaultServiceOptions, RestateEndpoint, RestateEndpointBase } from "./restate-sdk/src/endpoint.cjs";
|
|
11
11
|
import { EndpointOptions } from "./restate-sdk/src/endpoint/types.cjs";
|
|
12
12
|
import "./restate-sdk/src/index.cjs";
|
|
13
|
-
import { RestateContainer, RestateTestEnvironment, StateProxy, TestEnvironmentOptions } from "./restate_test_environment.cjs";
|
|
14
|
-
export { type DefaultServiceOptions, type Duration, type EndpointOptions, type Hooks, type HooksProvider, type Interceptor, type InvocationId, type JournalValueCodec, type LogMetadata, type LogSource, type LoggerContext, type LoggerTransport, type ObjectOptions, type Request, RestateContainer, type RestateEndpoint, type RestateEndpointBase, type RestateError, type RestateLogLevel, RestateTestEnvironment, type RetryPolicy, type Serde, type ServiceDefinition, type ServiceOptions, StateProxy, type Target, type TerminalError, type TestEnvironmentOptions, type TypedState, type UntypedState, type VirtualObjectDefinition, type WorkflowDefinition, type WorkflowOptions };
|
|
13
|
+
import { RestateContainer, RestateTestEnvironment, ServiceEndpointAccess, StateProxy, TestEnvironmentOptions, TestEnvironmentStorage } from "./restate_test_environment.cjs";
|
|
14
|
+
export { type DefaultServiceOptions, type Duration, type EndpointOptions, type Hooks, type HooksProvider, type Interceptor, type InvocationId, type JournalValueCodec, type LogMetadata, type LogSource, type LoggerContext, type LoggerTransport, type ObjectOptions, type Request, RestateContainer, type RestateEndpoint, type RestateEndpointBase, type RestateError, type RestateLogLevel, RestateTestEnvironment, type RetryPolicy, type Serde, type ServiceDefinition, type ServiceEndpointAccess, type ServiceOptions, StateProxy, type Target, type TerminalError, type TestEnvironmentOptions, type TestEnvironmentStorage, type TypedState, type UntypedState, type VirtualObjectDefinition, type WorkflowDefinition, type WorkflowOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ import { LogMetadata, LogSource, LoggerContext, LoggerTransport, RestateLogLevel
|
|
|
10
10
|
import { DefaultServiceOptions, RestateEndpoint, RestateEndpointBase } from "./restate-sdk/src/endpoint.js";
|
|
11
11
|
import { EndpointOptions } from "./restate-sdk/src/endpoint/types.js";
|
|
12
12
|
import "./restate-sdk/src/index.js";
|
|
13
|
-
import { RestateContainer, RestateTestEnvironment, StateProxy, TestEnvironmentOptions } from "./restate_test_environment.js";
|
|
14
|
-
export { type DefaultServiceOptions, type Duration, type EndpointOptions, type Hooks, type HooksProvider, type Interceptor, type InvocationId, type JournalValueCodec, type LogMetadata, type LogSource, type LoggerContext, type LoggerTransport, type ObjectOptions, type Request, RestateContainer, type RestateEndpoint, type RestateEndpointBase, type RestateError, type RestateLogLevel, RestateTestEnvironment, type RetryPolicy, type Serde, type ServiceDefinition, type ServiceOptions, StateProxy, type Target, type TerminalError, type TestEnvironmentOptions, type TypedState, type UntypedState, type VirtualObjectDefinition, type WorkflowDefinition, type WorkflowOptions };
|
|
13
|
+
import { RestateContainer, RestateTestEnvironment, ServiceEndpointAccess, StateProxy, TestEnvironmentOptions, TestEnvironmentStorage } from "./restate_test_environment.js";
|
|
14
|
+
export { type DefaultServiceOptions, type Duration, type EndpointOptions, type Hooks, type HooksProvider, type Interceptor, type InvocationId, type JournalValueCodec, type LogMetadata, type LogSource, type LoggerContext, type LoggerTransport, type ObjectOptions, type Request, RestateContainer, type RestateEndpoint, type RestateEndpointBase, type RestateError, type RestateLogLevel, RestateTestEnvironment, type RetryPolicy, type Serde, type ServiceDefinition, type ServiceEndpointAccess, type ServiceOptions, StateProxy, type Target, type TerminalError, type TestEnvironmentOptions, type TestEnvironmentStorage, type TypedState, type UntypedState, type VirtualObjectDefinition, type WorkflowDefinition, type WorkflowOptions };
|
|
@@ -1,8 +1,106 @@
|
|
|
1
1
|
//#region ../restate-sdk-core/src/serde_api.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Serializer/deserializer pair for any Restate-managed value of type `T` —
|
|
4
|
+
* handler inputs and outputs, service state, side-effect results,
|
|
5
|
+
* awakeables, durable promises, and so on.
|
|
6
|
+
*
|
|
7
|
+
* A `Serde<T>` is responsible for two conversions:
|
|
8
|
+
*
|
|
9
|
+
* - **Wire format**: `serialize` / `deserialize` convert a value `T` to and
|
|
10
|
+
* from the raw bytes that flow over the network and get stored in the
|
|
11
|
+
* journal.
|
|
12
|
+
* - **JSON preview (optional)**: `preview.toJsonString` /
|
|
13
|
+
* `preview.fromJsonString` convert a value `T` to and from a JSON string,
|
|
14
|
+
* used by tooling to render and edit values that humans can read.
|
|
15
|
+
*
|
|
16
|
+
* It also advertises metadata (`contentType`, `jsonSchema`) that surfaces in
|
|
17
|
+
* service discovery.
|
|
18
|
+
*/
|
|
2
19
|
interface Serde<T> {
|
|
20
|
+
/**
|
|
21
|
+
* MIME type of the bytes produced by `serialize` (and accepted by
|
|
22
|
+
* `deserialize`).
|
|
23
|
+
*/
|
|
3
24
|
contentType?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Optional JSON Schema describing the logical shape of `T`. Surfaced in
|
|
27
|
+
* discovery so that tooling can generate forms, auto-complete payloads,
|
|
28
|
+
* etc. Has no effect on serialization at runtime.
|
|
29
|
+
*/
|
|
4
30
|
jsonSchema?: object;
|
|
31
|
+
/**
|
|
32
|
+
* Optional bridge between the serde's wire format and a JSON
|
|
33
|
+
* representation that humans (and tooling like the Restate UI) can read
|
|
34
|
+
* and edit.
|
|
35
|
+
*
|
|
36
|
+
* Only useful for serdes whose wire format isn't already plain JSON —
|
|
37
|
+
* protobuf, MessagePack, length-prefixed binary, JSON variants that need
|
|
38
|
+
* post-processing for bigints/dates, etc. Both methods may be async if the
|
|
39
|
+
* conversion needs I/O.
|
|
40
|
+
*
|
|
41
|
+
* ### Preview flow
|
|
42
|
+
*
|
|
43
|
+
* Together with `serialize` / `deserialize`, the four functions chain in
|
|
44
|
+
* both directions between a JSON string and on-the-wire bytes:
|
|
45
|
+
*
|
|
46
|
+
* ```text
|
|
47
|
+
* JSON string ──fromJsonString──► T ──serialize──► wire bytes
|
|
48
|
+
* wire bytes ──deserialize────► T ──toJsonString──► JSON string
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* The split keeps `serialize` / `deserialize` responsible for the full
|
|
52
|
+
* on-the-wire format; `preview` only handles the JSON ↔ `T` bridge.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* // Wire format is protobuf; the protobuf-es runtime already ships
|
|
57
|
+
* // `toJsonString` / `fromJsonString`, so preview is a direct pass-through.
|
|
58
|
+
* import {
|
|
59
|
+
* fromBinary,
|
|
60
|
+
* fromJsonString,
|
|
61
|
+
* toBinary,
|
|
62
|
+
* toJsonString,
|
|
63
|
+
* } from "@bufbuild/protobuf";
|
|
64
|
+
* import { PersonSchema, type Person } from "./person_pb.js";
|
|
65
|
+
*
|
|
66
|
+
* const personSerde: Serde<Person> = {
|
|
67
|
+
* contentType: "application/protobuf",
|
|
68
|
+
* serialize(message) { return toBinary(PersonSchema, message); },
|
|
69
|
+
* deserialize(bytes) { return fromBinary(PersonSchema, bytes); },
|
|
70
|
+
* preview: {
|
|
71
|
+
* toJsonString: (v) => toJsonString(PersonSchema, v),
|
|
72
|
+
* fromJsonString: (j) => fromJsonString(PersonSchema, j),
|
|
73
|
+
* },
|
|
74
|
+
* };
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
preview?: {
|
|
78
|
+
/**
|
|
79
|
+
* Convert a value into a JSON string for display or editing by humans.
|
|
80
|
+
* The returned string must round-trip through `fromJsonString` back to
|
|
81
|
+
* the same logical value.
|
|
82
|
+
*/
|
|
83
|
+
toJsonString(value: T): Promise<string> | string;
|
|
84
|
+
/**
|
|
85
|
+
* Parse a human-supplied JSON string back into a value of type `T`.
|
|
86
|
+
* Should throw (or reject) if `json` is invalid for this serde.
|
|
87
|
+
*/
|
|
88
|
+
fromJsonString(json: string): Promise<T> | T;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Convert a value of type `T` into its on-the-wire bytes. This is the
|
|
92
|
+
* format Restate sends between services and persists in the journal.
|
|
93
|
+
*
|
|
94
|
+
* Must be the inverse of `deserialize` — `deserialize(serialize(v))`
|
|
95
|
+
* should produce a value equivalent to `v`.
|
|
96
|
+
*/
|
|
5
97
|
serialize(value: T): Uint8Array;
|
|
98
|
+
/**
|
|
99
|
+
* Convert on-the-wire bytes back into a value of type `T`. Must be the
|
|
100
|
+
* inverse of `serialize`.
|
|
101
|
+
*
|
|
102
|
+
* May throw if `data` doesn't conform to the expected wire format.
|
|
103
|
+
*/
|
|
6
104
|
deserialize(data: Uint8Array): T;
|
|
7
105
|
}
|
|
8
106
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serde_api.d.cts","names":[],"sources":["../../../../restate-sdk-core/src/serde_api.ts"],"sourcesContent":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"serde_api.d.cts","names":[],"sources":["../../../../restate-sdk-core/src/serde_api.ts"],"sourcesContent":[],"mappings":";AAoCA;;;;;;;;;;;;;;;;;UAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAkEO,IAAI;;;;;kCAMM,QAAQ,KAAK;;;;;;;;;mBAU5B,IAAI;;;;;;;oBAQH,aAAa"}
|
|
@@ -1,8 +1,106 @@
|
|
|
1
1
|
//#region ../restate-sdk-core/src/serde_api.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Serializer/deserializer pair for any Restate-managed value of type `T` —
|
|
4
|
+
* handler inputs and outputs, service state, side-effect results,
|
|
5
|
+
* awakeables, durable promises, and so on.
|
|
6
|
+
*
|
|
7
|
+
* A `Serde<T>` is responsible for two conversions:
|
|
8
|
+
*
|
|
9
|
+
* - **Wire format**: `serialize` / `deserialize` convert a value `T` to and
|
|
10
|
+
* from the raw bytes that flow over the network and get stored in the
|
|
11
|
+
* journal.
|
|
12
|
+
* - **JSON preview (optional)**: `preview.toJsonString` /
|
|
13
|
+
* `preview.fromJsonString` convert a value `T` to and from a JSON string,
|
|
14
|
+
* used by tooling to render and edit values that humans can read.
|
|
15
|
+
*
|
|
16
|
+
* It also advertises metadata (`contentType`, `jsonSchema`) that surfaces in
|
|
17
|
+
* service discovery.
|
|
18
|
+
*/
|
|
2
19
|
interface Serde<T> {
|
|
20
|
+
/**
|
|
21
|
+
* MIME type of the bytes produced by `serialize` (and accepted by
|
|
22
|
+
* `deserialize`).
|
|
23
|
+
*/
|
|
3
24
|
contentType?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Optional JSON Schema describing the logical shape of `T`. Surfaced in
|
|
27
|
+
* discovery so that tooling can generate forms, auto-complete payloads,
|
|
28
|
+
* etc. Has no effect on serialization at runtime.
|
|
29
|
+
*/
|
|
4
30
|
jsonSchema?: object;
|
|
31
|
+
/**
|
|
32
|
+
* Optional bridge between the serde's wire format and a JSON
|
|
33
|
+
* representation that humans (and tooling like the Restate UI) can read
|
|
34
|
+
* and edit.
|
|
35
|
+
*
|
|
36
|
+
* Only useful for serdes whose wire format isn't already plain JSON —
|
|
37
|
+
* protobuf, MessagePack, length-prefixed binary, JSON variants that need
|
|
38
|
+
* post-processing for bigints/dates, etc. Both methods may be async if the
|
|
39
|
+
* conversion needs I/O.
|
|
40
|
+
*
|
|
41
|
+
* ### Preview flow
|
|
42
|
+
*
|
|
43
|
+
* Together with `serialize` / `deserialize`, the four functions chain in
|
|
44
|
+
* both directions between a JSON string and on-the-wire bytes:
|
|
45
|
+
*
|
|
46
|
+
* ```text
|
|
47
|
+
* JSON string ──fromJsonString──► T ──serialize──► wire bytes
|
|
48
|
+
* wire bytes ──deserialize────► T ──toJsonString──► JSON string
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* The split keeps `serialize` / `deserialize` responsible for the full
|
|
52
|
+
* on-the-wire format; `preview` only handles the JSON ↔ `T` bridge.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* // Wire format is protobuf; the protobuf-es runtime already ships
|
|
57
|
+
* // `toJsonString` / `fromJsonString`, so preview is a direct pass-through.
|
|
58
|
+
* import {
|
|
59
|
+
* fromBinary,
|
|
60
|
+
* fromJsonString,
|
|
61
|
+
* toBinary,
|
|
62
|
+
* toJsonString,
|
|
63
|
+
* } from "@bufbuild/protobuf";
|
|
64
|
+
* import { PersonSchema, type Person } from "./person_pb.js";
|
|
65
|
+
*
|
|
66
|
+
* const personSerde: Serde<Person> = {
|
|
67
|
+
* contentType: "application/protobuf",
|
|
68
|
+
* serialize(message) { return toBinary(PersonSchema, message); },
|
|
69
|
+
* deserialize(bytes) { return fromBinary(PersonSchema, bytes); },
|
|
70
|
+
* preview: {
|
|
71
|
+
* toJsonString: (v) => toJsonString(PersonSchema, v),
|
|
72
|
+
* fromJsonString: (j) => fromJsonString(PersonSchema, j),
|
|
73
|
+
* },
|
|
74
|
+
* };
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
preview?: {
|
|
78
|
+
/**
|
|
79
|
+
* Convert a value into a JSON string for display or editing by humans.
|
|
80
|
+
* The returned string must round-trip through `fromJsonString` back to
|
|
81
|
+
* the same logical value.
|
|
82
|
+
*/
|
|
83
|
+
toJsonString(value: T): Promise<string> | string;
|
|
84
|
+
/**
|
|
85
|
+
* Parse a human-supplied JSON string back into a value of type `T`.
|
|
86
|
+
* Should throw (or reject) if `json` is invalid for this serde.
|
|
87
|
+
*/
|
|
88
|
+
fromJsonString(json: string): Promise<T> | T;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Convert a value of type `T` into its on-the-wire bytes. This is the
|
|
92
|
+
* format Restate sends between services and persists in the journal.
|
|
93
|
+
*
|
|
94
|
+
* Must be the inverse of `deserialize` — `deserialize(serialize(v))`
|
|
95
|
+
* should produce a value equivalent to `v`.
|
|
96
|
+
*/
|
|
5
97
|
serialize(value: T): Uint8Array;
|
|
98
|
+
/**
|
|
99
|
+
* Convert on-the-wire bytes back into a value of type `T`. Must be the
|
|
100
|
+
* inverse of `serialize`.
|
|
101
|
+
*
|
|
102
|
+
* May throw if `data` doesn't conform to the expected wire format.
|
|
103
|
+
*/
|
|
6
104
|
deserialize(data: Uint8Array): T;
|
|
7
105
|
}
|
|
8
106
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serde_api.d.ts","names":[],"sources":["../../../../restate-sdk-core/src/serde_api.ts"],"sourcesContent":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"serde_api.d.ts","names":[],"sources":["../../../../restate-sdk-core/src/serde_api.ts"],"sourcesContent":[],"mappings":";AAoCA;;;;;;;;;;;;;;;;;UAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAkEO,IAAI;;;;;kCAMM,QAAQ,KAAK;;;;;;;;;mBAU5B,IAAI;;;;;;;oBAQH,aAAa"}
|
|
@@ -9,6 +9,10 @@ let http2 = require("http2");
|
|
|
9
9
|
http2 = require_rolldown_runtime.__toESM(http2);
|
|
10
10
|
|
|
11
11
|
//#region src/restate_test_environment.ts
|
|
12
|
+
const DEFAULT_START_OPTIONS = {
|
|
13
|
+
serviceEndpointAccess: "docker-host",
|
|
14
|
+
storage: "memory"
|
|
15
|
+
};
|
|
12
16
|
/**
|
|
13
17
|
* Custom wait strategy that waits for Restate partitions to be ready by
|
|
14
18
|
* executing a SQL query against the admin API. This ensures all partitions
|
|
@@ -51,12 +55,7 @@ var PartitionsReadyWaitStrategy = class {
|
|
|
51
55
|
}
|
|
52
56
|
};
|
|
53
57
|
async function prepareRestateEndpoint(param) {
|
|
54
|
-
|
|
55
|
-
if (typeof param === "function") {
|
|
56
|
-
const restateEndpoint = (0, __restatedev_restate_sdk.endpoint)();
|
|
57
|
-
param(restateEndpoint);
|
|
58
|
-
handler = restateEndpoint.http2Handler();
|
|
59
|
-
} else handler = (0, __restatedev_restate_sdk.createEndpointHandler)(param);
|
|
58
|
+
const handler = (0, __restatedev_restate_sdk.createEndpointHandler)(param);
|
|
60
59
|
const restateHttpServer = http2.createServer(handler);
|
|
61
60
|
await new Promise((resolve, reject) => {
|
|
62
61
|
restateHttpServer.listen(0).once("listening", resolve).once("error", reject);
|
|
@@ -65,20 +64,26 @@ async function prepareRestateEndpoint(param) {
|
|
|
65
64
|
console.info(`Restate container listening on port ${restateServerPort}`);
|
|
66
65
|
return restateHttpServer;
|
|
67
66
|
}
|
|
68
|
-
async function prepareRestateTestContainer(restateServerPort, restateContainerFactory) {
|
|
69
|
-
|
|
67
|
+
async function prepareRestateTestContainer(restateServerPort, restateContainerFactory, options) {
|
|
68
|
+
let restateContainer = restateContainerFactory().withExposedPorts(8080, 9070).withWaitStrategy(testcontainers.Wait.forAll([
|
|
70
69
|
testcontainers.Wait.forHttp("/restate/health", 8080),
|
|
71
70
|
testcontainers.Wait.forHttp("/health", 9070),
|
|
72
71
|
new PartitionsReadyWaitStrategy()
|
|
73
72
|
]));
|
|
74
|
-
|
|
73
|
+
if (options.storage === "memory") restateContainer = restateContainer.withTmpFs({ "/restate-data": "rw" });
|
|
74
|
+
const serviceEndpointHost = options.serviceEndpointAccess === "docker-host" ? "host.docker.internal" : "host.testcontainers.internal";
|
|
75
|
+
if (options.serviceEndpointAccess === "docker-host") restateContainer = restateContainer.withExtraHosts([{
|
|
76
|
+
host: "host.docker.internal",
|
|
77
|
+
ipAddress: "host-gateway"
|
|
78
|
+
}]);
|
|
79
|
+
else await testcontainers.TestContainers.exposeHostPorts(restateServerPort);
|
|
75
80
|
const startedRestateContainer = await restateContainer.start();
|
|
76
81
|
try {
|
|
77
|
-
console.info(`Registering services at http
|
|
82
|
+
console.info(`Registering services at http://${serviceEndpointHost}:${restateServerPort}...`);
|
|
78
83
|
const res = await fetch(`http://${startedRestateContainer.getHost()}:${startedRestateContainer.getMappedPort(9070)}/deployments`, {
|
|
79
84
|
method: "POST",
|
|
80
85
|
headers: { "Content-Type": "application/json" },
|
|
81
|
-
body: JSON.stringify({ uri: `http
|
|
86
|
+
body: JSON.stringify({ uri: `http://${serviceEndpointHost}:${restateServerPort}` })
|
|
82
87
|
});
|
|
83
88
|
if (!res.ok) {
|
|
84
89
|
const badResponse = await res.text();
|
|
@@ -110,18 +115,22 @@ var RestateTestEnvironment = class RestateTestEnvironment {
|
|
|
110
115
|
await this.startedRestateContainer.stop();
|
|
111
116
|
this.startedRestateHttpServer.close();
|
|
112
117
|
}
|
|
113
|
-
static async start(
|
|
118
|
+
static async start(options, restateContainerFactory) {
|
|
114
119
|
let containerFactory;
|
|
115
120
|
if (restateContainerFactory) containerFactory = restateContainerFactory;
|
|
116
|
-
else if (
|
|
121
|
+
else if (options.container) containerFactory = options.container;
|
|
122
|
+
else containerFactory = () => {
|
|
117
123
|
const container = new RestateContainer();
|
|
118
|
-
if (
|
|
119
|
-
if (
|
|
124
|
+
if (options.alwaysReplay) container.alwaysReplay();
|
|
125
|
+
if (options.disableRetries) container.disableRetries();
|
|
120
126
|
return container;
|
|
121
127
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
128
|
+
const resolvedStartOptions = {
|
|
129
|
+
serviceEndpointAccess: options.serviceEndpointAccess ?? DEFAULT_START_OPTIONS.serviceEndpointAccess,
|
|
130
|
+
storage: options.storage ?? DEFAULT_START_OPTIONS.storage
|
|
131
|
+
};
|
|
132
|
+
const startedRestateHttpServer = await prepareRestateEndpoint(options);
|
|
133
|
+
return new RestateTestEnvironment(startedRestateHttpServer, await prepareRestateTestContainer(startedRestateHttpServer.address().port, containerFactory, resolvedStartOptions));
|
|
125
134
|
}
|
|
126
135
|
};
|
|
127
136
|
var RestateContainer = class extends testcontainers.GenericContainer {
|
|
@@ -1,14 +1,50 @@
|
|
|
1
1
|
import { VirtualObjectDefinition, WorkflowDefinition } from "./restate-sdk-core/src/core.cjs";
|
|
2
2
|
import { Serde } from "./restate-sdk-core/src/serde_api.cjs";
|
|
3
3
|
import { TypedState, UntypedState } from "./restate-sdk/src/context.cjs";
|
|
4
|
-
import { RestateEndpoint } from "./restate-sdk/src/endpoint.cjs";
|
|
5
4
|
import { EndpointOptions } from "./restate-sdk/src/endpoint/types.cjs";
|
|
6
5
|
import "./restate-sdk/src/index.cjs";
|
|
7
6
|
import * as http2 from "http2";
|
|
8
7
|
import { GenericContainer, StartedTestContainer } from "testcontainers";
|
|
9
8
|
|
|
10
9
|
//#region src/restate_test_environment.d.ts
|
|
10
|
+
type ServiceEndpointAccess = "testcontainers" | "docker-host";
|
|
11
|
+
type TestEnvironmentStorage = "disk" | "memory";
|
|
11
12
|
interface TestEnvironmentOptions extends EndpointOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Factory for the Restate container used by the test environment.
|
|
15
|
+
*
|
|
16
|
+
* Use this to customize the Restate image or container settings before the
|
|
17
|
+
* helper applies its own ports, wait strategy, networking, and storage
|
|
18
|
+
* configuration.
|
|
19
|
+
*
|
|
20
|
+
* For backwards compatibility, the second `start(options, factory)` argument
|
|
21
|
+
* is still supported and takes precedence over this option.
|
|
22
|
+
*
|
|
23
|
+
* @defaultValue `() => new RestateContainer()`
|
|
24
|
+
*/
|
|
25
|
+
container?: () => GenericContainer;
|
|
26
|
+
/**
|
|
27
|
+
* Controls how the Restate container reaches the SDK service endpoint running
|
|
28
|
+
* on the test host.
|
|
29
|
+
*
|
|
30
|
+
* - `"testcontainers"` exposes the host port through Testcontainers and
|
|
31
|
+
* registers `http://host.testcontainers.internal:<port>`.
|
|
32
|
+
* - `"docker-host"` skips Testcontainers port exposure, adds
|
|
33
|
+
* `host.docker.internal:host-gateway` to the Restate container, and
|
|
34
|
+
* registers `http://host.docker.internal:<port>`.
|
|
35
|
+
*
|
|
36
|
+
* @defaultValue `"docker-host"`
|
|
37
|
+
*/
|
|
38
|
+
serviceEndpointAccess?: ServiceEndpointAccess;
|
|
39
|
+
/**
|
|
40
|
+
* Controls where Restate stores container data.
|
|
41
|
+
*
|
|
42
|
+
* - `"disk"` keeps the current Testcontainers/Docker storage behavior.
|
|
43
|
+
* - `"memory"` mounts `/restate-data` as tmpfs for faster disposable tests.
|
|
44
|
+
*
|
|
45
|
+
* @defaultValue `"memory"`
|
|
46
|
+
*/
|
|
47
|
+
storage?: TestEnvironmentStorage;
|
|
12
48
|
/**
|
|
13
49
|
* Forces restate-server to always replay on a suspension point.
|
|
14
50
|
* This is useful to hunt non-deterministic bugs that might prevent
|
|
@@ -30,15 +66,6 @@ declare class RestateTestEnvironment {
|
|
|
30
66
|
adminAPIBaseUrl(): string;
|
|
31
67
|
stateOf<TState extends TypedState = UntypedState>(service: VirtualObjectDefinition<string, unknown> | WorkflowDefinition<string, unknown>, key: string): StateProxy<TState>;
|
|
32
68
|
stop(): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
*
|
|
35
|
-
* @deprecated Please use {@link TestEnvironmentOptions} instead of this.
|
|
36
|
-
* @example
|
|
37
|
-
* ```
|
|
38
|
-
* RestateTestEnvironment.start({ services: [mysService] })
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
static start(mountServicesFn: (server: RestateEndpoint) => void, restateContainerFactory?: () => GenericContainer): Promise<RestateTestEnvironment>;
|
|
42
69
|
static start(options: TestEnvironmentOptions, restateContainerFactory?: () => GenericContainer): Promise<RestateTestEnvironment>;
|
|
43
70
|
}
|
|
44
71
|
declare class RestateContainer extends GenericContainer {
|
|
@@ -69,5 +96,5 @@ declare class StateProxy<TState extends TypedState> {
|
|
|
69
96
|
private setAllRaw;
|
|
70
97
|
}
|
|
71
98
|
//#endregion
|
|
72
|
-
export { RestateContainer, RestateTestEnvironment, StateProxy, TestEnvironmentOptions };
|
|
99
|
+
export { RestateContainer, RestateTestEnvironment, ServiceEndpointAccess, StateProxy, TestEnvironmentOptions, TestEnvironmentStorage };
|
|
73
100
|
//# sourceMappingURL=restate_test_environment.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restate_test_environment.d.cts","names":[],"sources":["../src/restate_test_environment.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"restate_test_environment.d.cts","names":[],"sources":["../src/restate_test_environment.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1,14 +1,50 @@
|
|
|
1
1
|
import { VirtualObjectDefinition, WorkflowDefinition } from "./restate-sdk-core/src/core.js";
|
|
2
2
|
import { Serde } from "./restate-sdk-core/src/serde_api.js";
|
|
3
3
|
import { TypedState, UntypedState } from "./restate-sdk/src/context.js";
|
|
4
|
-
import { RestateEndpoint } from "./restate-sdk/src/endpoint.js";
|
|
5
4
|
import { EndpointOptions } from "./restate-sdk/src/endpoint/types.js";
|
|
6
5
|
import "./restate-sdk/src/index.js";
|
|
7
6
|
import { GenericContainer, StartedTestContainer } from "testcontainers";
|
|
8
7
|
import * as http2 from "http2";
|
|
9
8
|
|
|
10
9
|
//#region src/restate_test_environment.d.ts
|
|
10
|
+
type ServiceEndpointAccess = "testcontainers" | "docker-host";
|
|
11
|
+
type TestEnvironmentStorage = "disk" | "memory";
|
|
11
12
|
interface TestEnvironmentOptions extends EndpointOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Factory for the Restate container used by the test environment.
|
|
15
|
+
*
|
|
16
|
+
* Use this to customize the Restate image or container settings before the
|
|
17
|
+
* helper applies its own ports, wait strategy, networking, and storage
|
|
18
|
+
* configuration.
|
|
19
|
+
*
|
|
20
|
+
* For backwards compatibility, the second `start(options, factory)` argument
|
|
21
|
+
* is still supported and takes precedence over this option.
|
|
22
|
+
*
|
|
23
|
+
* @defaultValue `() => new RestateContainer()`
|
|
24
|
+
*/
|
|
25
|
+
container?: () => GenericContainer;
|
|
26
|
+
/**
|
|
27
|
+
* Controls how the Restate container reaches the SDK service endpoint running
|
|
28
|
+
* on the test host.
|
|
29
|
+
*
|
|
30
|
+
* - `"testcontainers"` exposes the host port through Testcontainers and
|
|
31
|
+
* registers `http://host.testcontainers.internal:<port>`.
|
|
32
|
+
* - `"docker-host"` skips Testcontainers port exposure, adds
|
|
33
|
+
* `host.docker.internal:host-gateway` to the Restate container, and
|
|
34
|
+
* registers `http://host.docker.internal:<port>`.
|
|
35
|
+
*
|
|
36
|
+
* @defaultValue `"docker-host"`
|
|
37
|
+
*/
|
|
38
|
+
serviceEndpointAccess?: ServiceEndpointAccess;
|
|
39
|
+
/**
|
|
40
|
+
* Controls where Restate stores container data.
|
|
41
|
+
*
|
|
42
|
+
* - `"disk"` keeps the current Testcontainers/Docker storage behavior.
|
|
43
|
+
* - `"memory"` mounts `/restate-data` as tmpfs for faster disposable tests.
|
|
44
|
+
*
|
|
45
|
+
* @defaultValue `"memory"`
|
|
46
|
+
*/
|
|
47
|
+
storage?: TestEnvironmentStorage;
|
|
12
48
|
/**
|
|
13
49
|
* Forces restate-server to always replay on a suspension point.
|
|
14
50
|
* This is useful to hunt non-deterministic bugs that might prevent
|
|
@@ -30,15 +66,6 @@ declare class RestateTestEnvironment {
|
|
|
30
66
|
adminAPIBaseUrl(): string;
|
|
31
67
|
stateOf<TState extends TypedState = UntypedState>(service: VirtualObjectDefinition<string, unknown> | WorkflowDefinition<string, unknown>, key: string): StateProxy<TState>;
|
|
32
68
|
stop(): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
*
|
|
35
|
-
* @deprecated Please use {@link TestEnvironmentOptions} instead of this.
|
|
36
|
-
* @example
|
|
37
|
-
* ```
|
|
38
|
-
* RestateTestEnvironment.start({ services: [mysService] })
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
static start(mountServicesFn: (server: RestateEndpoint) => void, restateContainerFactory?: () => GenericContainer): Promise<RestateTestEnvironment>;
|
|
42
69
|
static start(options: TestEnvironmentOptions, restateContainerFactory?: () => GenericContainer): Promise<RestateTestEnvironment>;
|
|
43
70
|
}
|
|
44
71
|
declare class RestateContainer extends GenericContainer {
|
|
@@ -69,5 +96,5 @@ declare class StateProxy<TState extends TypedState> {
|
|
|
69
96
|
private setAllRaw;
|
|
70
97
|
}
|
|
71
98
|
//#endregion
|
|
72
|
-
export { RestateContainer, RestateTestEnvironment, StateProxy, TestEnvironmentOptions };
|
|
99
|
+
export { RestateContainer, RestateTestEnvironment, ServiceEndpointAccess, StateProxy, TestEnvironmentOptions, TestEnvironmentStorage };
|
|
73
100
|
//# sourceMappingURL=restate_test_environment.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restate_test_environment.d.ts","names":[],"sources":["../src/restate_test_environment.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"restate_test_environment.d.ts","names":[],"sources":["../src/restate_test_environment.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { createEndpointHandler,
|
|
1
|
+
import { createEndpointHandler, serde } from "@restatedev/restate-sdk";
|
|
2
2
|
import { GenericContainer, TestContainers, Wait, getContainerRuntimeClient } from "testcontainers";
|
|
3
3
|
import { tableFromIPC } from "apache-arrow";
|
|
4
4
|
import * as http2 from "http2";
|
|
5
5
|
|
|
6
6
|
//#region src/restate_test_environment.ts
|
|
7
|
+
const DEFAULT_START_OPTIONS = {
|
|
8
|
+
serviceEndpointAccess: "docker-host",
|
|
9
|
+
storage: "memory"
|
|
10
|
+
};
|
|
7
11
|
/**
|
|
8
12
|
* Custom wait strategy that waits for Restate partitions to be ready by
|
|
9
13
|
* executing a SQL query against the admin API. This ensures all partitions
|
|
@@ -46,12 +50,7 @@ var PartitionsReadyWaitStrategy = class {
|
|
|
46
50
|
}
|
|
47
51
|
};
|
|
48
52
|
async function prepareRestateEndpoint(param) {
|
|
49
|
-
|
|
50
|
-
if (typeof param === "function") {
|
|
51
|
-
const restateEndpoint = endpoint();
|
|
52
|
-
param(restateEndpoint);
|
|
53
|
-
handler = restateEndpoint.http2Handler();
|
|
54
|
-
} else handler = createEndpointHandler(param);
|
|
53
|
+
const handler = createEndpointHandler(param);
|
|
55
54
|
const restateHttpServer = http2.createServer(handler);
|
|
56
55
|
await new Promise((resolve, reject) => {
|
|
57
56
|
restateHttpServer.listen(0).once("listening", resolve).once("error", reject);
|
|
@@ -60,20 +59,26 @@ async function prepareRestateEndpoint(param) {
|
|
|
60
59
|
console.info(`Restate container listening on port ${restateServerPort}`);
|
|
61
60
|
return restateHttpServer;
|
|
62
61
|
}
|
|
63
|
-
async function prepareRestateTestContainer(restateServerPort, restateContainerFactory) {
|
|
64
|
-
|
|
62
|
+
async function prepareRestateTestContainer(restateServerPort, restateContainerFactory, options) {
|
|
63
|
+
let restateContainer = restateContainerFactory().withExposedPorts(8080, 9070).withWaitStrategy(Wait.forAll([
|
|
65
64
|
Wait.forHttp("/restate/health", 8080),
|
|
66
65
|
Wait.forHttp("/health", 9070),
|
|
67
66
|
new PartitionsReadyWaitStrategy()
|
|
68
67
|
]));
|
|
69
|
-
|
|
68
|
+
if (options.storage === "memory") restateContainer = restateContainer.withTmpFs({ "/restate-data": "rw" });
|
|
69
|
+
const serviceEndpointHost = options.serviceEndpointAccess === "docker-host" ? "host.docker.internal" : "host.testcontainers.internal";
|
|
70
|
+
if (options.serviceEndpointAccess === "docker-host") restateContainer = restateContainer.withExtraHosts([{
|
|
71
|
+
host: "host.docker.internal",
|
|
72
|
+
ipAddress: "host-gateway"
|
|
73
|
+
}]);
|
|
74
|
+
else await TestContainers.exposeHostPorts(restateServerPort);
|
|
70
75
|
const startedRestateContainer = await restateContainer.start();
|
|
71
76
|
try {
|
|
72
|
-
console.info(`Registering services at http
|
|
77
|
+
console.info(`Registering services at http://${serviceEndpointHost}:${restateServerPort}...`);
|
|
73
78
|
const res = await fetch(`http://${startedRestateContainer.getHost()}:${startedRestateContainer.getMappedPort(9070)}/deployments`, {
|
|
74
79
|
method: "POST",
|
|
75
80
|
headers: { "Content-Type": "application/json" },
|
|
76
|
-
body: JSON.stringify({ uri: `http
|
|
81
|
+
body: JSON.stringify({ uri: `http://${serviceEndpointHost}:${restateServerPort}` })
|
|
77
82
|
});
|
|
78
83
|
if (!res.ok) {
|
|
79
84
|
const badResponse = await res.text();
|
|
@@ -105,18 +110,22 @@ var RestateTestEnvironment = class RestateTestEnvironment {
|
|
|
105
110
|
await this.startedRestateContainer.stop();
|
|
106
111
|
this.startedRestateHttpServer.close();
|
|
107
112
|
}
|
|
108
|
-
static async start(
|
|
113
|
+
static async start(options, restateContainerFactory) {
|
|
109
114
|
let containerFactory;
|
|
110
115
|
if (restateContainerFactory) containerFactory = restateContainerFactory;
|
|
111
|
-
else if (
|
|
116
|
+
else if (options.container) containerFactory = options.container;
|
|
117
|
+
else containerFactory = () => {
|
|
112
118
|
const container = new RestateContainer();
|
|
113
|
-
if (
|
|
114
|
-
if (
|
|
119
|
+
if (options.alwaysReplay) container.alwaysReplay();
|
|
120
|
+
if (options.disableRetries) container.disableRetries();
|
|
115
121
|
return container;
|
|
116
122
|
};
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
const resolvedStartOptions = {
|
|
124
|
+
serviceEndpointAccess: options.serviceEndpointAccess ?? DEFAULT_START_OPTIONS.serviceEndpointAccess,
|
|
125
|
+
storage: options.storage ?? DEFAULT_START_OPTIONS.storage
|
|
126
|
+
};
|
|
127
|
+
const startedRestateHttpServer = await prepareRestateEndpoint(options);
|
|
128
|
+
return new RestateTestEnvironment(startedRestateHttpServer, await prepareRestateTestContainer(startedRestateHttpServer.address().port, containerFactory, resolvedStartOptions));
|
|
120
129
|
}
|
|
121
130
|
};
|
|
122
131
|
var RestateContainer = class extends GenericContainer {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restate_test_environment.js","names":["handler: (\n request: http2.Http2ServerRequest,\n response: http2.Http2ServerResponse\n ) => void","startedRestateHttpServer: http2.Http2Server","startedRestateContainer: StartedTestContainer","containerFactory: () => GenericContainer","adminAPIBaseUrl: string","service: string","serviceKey: string","serde","value"],"sources":["../src/restate_test_environment.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH\n *\n * This file is part of the Restate SDK for Node.js/TypeScript,\n * which is released under the MIT license.\n *\n * You can find a copy of the license in file LICENSE in the root\n * directory of this repository or package, or at\n * https://github.com/restatedev/sdk-typescript/blob/main/LICENSE\n */\n\nimport {\n endpoint,\n createEndpointHandler,\n serde,\n} from \"@restatedev/restate-sdk\";\nimport type {\n TypedState,\n UntypedState,\n Serde,\n RestateEndpoint,\n VirtualObjectDefinition,\n WorkflowDefinition,\n EndpointOptions,\n} from \"@restatedev/restate-sdk\";\n\nimport {\n GenericContainer,\n type StartedTestContainer,\n TestContainers,\n Wait,\n type WaitStrategy,\n type BoundPorts,\n getContainerRuntimeClient,\n} from \"testcontainers\";\nimport { tableFromIPC } from \"apache-arrow\";\nimport * as http2 from \"http2\";\nimport type * as net from \"net\";\n\n/**\n * Custom wait strategy that waits for Restate partitions to be ready by\n * executing a SQL query against the admin API. This ensures all partitions\n * are initialized and queryable before the container is considered ready.\n */\nclass PartitionsReadyWaitStrategy implements WaitStrategy {\n private startupTimeoutMs = 60_000;\n private startupTimeoutSet = false;\n private readonly port: number;\n private readonly pollIntervalMs: number;\n\n constructor(port = 9070, pollIntervalMs = 200) {\n this.port = port;\n this.pollIntervalMs = pollIntervalMs;\n }\n\n public withStartupTimeout(startupTimeoutMs: number): this {\n this.startupTimeoutMs = startupTimeoutMs;\n this.startupTimeoutSet = true;\n return this;\n }\n\n public isStartupTimeoutSet(): boolean {\n return this.startupTimeoutSet;\n }\n\n public getStartupTimeout(): number {\n return this.startupTimeoutMs;\n }\n\n public async waitUntilReady(\n container: { id: string },\n boundPorts: BoundPorts\n ): Promise<void> {\n const client = await getContainerRuntimeClient();\n const host = client.info.containerRuntime.host;\n const mappedPort = boundPorts.getBinding(this.port);\n const adminUrl = `http://${host}:${mappedPort}`;\n\n const startTime = Date.now();\n\n while (Date.now() - startTime < this.startupTimeoutMs) {\n try {\n const res = await fetch(`${adminUrl}/query`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query: \"SELECT count(1) FROM sys_invocation\",\n }),\n });\n\n if (res.ok) {\n // Partitions are ready\n return;\n }\n } catch {\n // Ignore errors, keep polling\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));\n }\n\n throw new Error(\n `Restate partitions not ready after ${this.startupTimeoutMs}ms`\n );\n }\n}\n\n// Prepare the restate server\nasync function prepareRestateEndpoint(\n param: (server: RestateEndpoint) => void\n): Promise<http2.Http2Server>;\nasync function prepareRestateEndpoint(\n param: EndpointOptions\n): Promise<http2.Http2Server>;\nasync function prepareRestateEndpoint(\n param: EndpointOptions | ((server: RestateEndpoint) => void)\n): Promise<http2.Http2Server> {\n // Prepare RestateServer\n let handler: (\n request: http2.Http2ServerRequest,\n response: http2.Http2ServerResponse\n ) => void;\n if (typeof param === \"function\") {\n const restateEndpoint = endpoint();\n param(restateEndpoint);\n handler = restateEndpoint.http2Handler();\n } else {\n handler = createEndpointHandler(param);\n }\n\n // Start HTTP2 server on random port\n const restateHttpServer = http2.createServer(handler);\n await new Promise((resolve, reject) => {\n restateHttpServer\n .listen(0)\n .once(\"listening\", resolve)\n .once(\"error\", reject);\n });\n const restateServerPort = (restateHttpServer.address() as net.AddressInfo)\n .port;\n console.info(`Restate container listening on port ${restateServerPort}`);\n\n return restateHttpServer;\n}\n\n// Prepare the restate testcontainer\nasync function prepareRestateTestContainer(\n restateServerPort: number,\n restateContainerFactory: () => GenericContainer\n): Promise<StartedTestContainer> {\n const restateContainer = restateContainerFactory()\n // Expose ports\n .withExposedPorts(8080, 9070)\n // Wait start on health checks and partition readiness\n .withWaitStrategy(\n Wait.forAll([\n Wait.forHttp(\"/restate/health\", 8080),\n Wait.forHttp(\"/health\", 9070),\n new PartitionsReadyWaitStrategy(),\n ])\n );\n\n // This MUST be executed before starting the restate container\n // Expose host port to access the restate server\n await TestContainers.exposeHostPorts(restateServerPort);\n\n // Start restate container\n const startedRestateContainer = await restateContainer.start();\n\n // From now on, if something fails, stop the container to cleanup the environment\n try {\n console.info(\n `Registering services at http://host.testcontainers.internal:${restateServerPort}...`\n );\n\n // Register this service endpoint\n const res = await fetch(\n `http://${startedRestateContainer.getHost()}:${startedRestateContainer.getMappedPort(\n 9070\n )}/deployments`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n // See https://node.testcontainers.org/features/networking/#expose-host-ports-to-container\n uri: `http://host.testcontainers.internal:${restateServerPort}`,\n }),\n }\n );\n if (!res.ok) {\n const badResponse = await res.text();\n throw new Error(\n `Error ${res.status} during registration: ${badResponse}`\n );\n }\n\n const resp = (await res.json()) as { services: { name: string }[] };\n console.info(\n \"Registered services:\",\n resp?.services?.map((s) => s.name)\n );\n return startedRestateContainer;\n } catch (e) {\n await startedRestateContainer.stop();\n throw e;\n }\n}\n\nexport interface TestEnvironmentOptions extends EndpointOptions {\n /**\n * Forces restate-server to always replay on a suspension point.\n * This is useful to hunt non-deterministic bugs that might prevent\n * your code from replaying correctly.\n */\n alwaysReplay?: boolean;\n\n /**\n * Disables retries in the restate-server invoker.\n * This is useful in tests so that failures surface immediately\n * instead of hanging through retry backoff.\n */\n disableRetries?: boolean;\n}\n\nexport class RestateTestEnvironment {\n constructor(\n readonly startedRestateHttpServer: http2.Http2Server,\n readonly startedRestateContainer: StartedTestContainer\n ) {}\n\n public baseUrl(): string {\n return `http://${this.startedRestateContainer.getHost()}:${this.startedRestateContainer.getMappedPort(\n 8080\n )}`;\n }\n\n public adminAPIBaseUrl(): string {\n return `http://${this.startedRestateContainer.getHost()}:${this.startedRestateContainer.getMappedPort(\n 9070\n )}`;\n }\n\n // Create a handle that allows read/write of state under a given Virtual Object/Workflow key.\n public stateOf<TState extends TypedState = UntypedState>(\n service:\n | VirtualObjectDefinition<string, unknown>\n | WorkflowDefinition<string, unknown>,\n key: string\n ): StateProxy<TState> {\n return new StateProxy(this.adminAPIBaseUrl(), service.name, key);\n }\n\n public async stop() {\n await this.startedRestateContainer.stop();\n this.startedRestateHttpServer.close();\n }\n\n /**\n *\n * @deprecated Please use {@link TestEnvironmentOptions} instead of this.\n * @example\n * ```\n * RestateTestEnvironment.start({ services: [mysService] })\n * ```\n */\n public static async start(\n mountServicesFn: (server: RestateEndpoint) => void,\n restateContainerFactory?: () => GenericContainer\n ): Promise<RestateTestEnvironment>;\n public static async start(\n options: TestEnvironmentOptions,\n restateContainerFactory?: () => GenericContainer\n ): Promise<RestateTestEnvironment>;\n public static async start(\n param: TestEnvironmentOptions | ((server: RestateEndpoint) => void),\n restateContainerFactory?: () => GenericContainer\n ): Promise<RestateTestEnvironment> {\n let containerFactory: () => GenericContainer;\n if (restateContainerFactory) {\n containerFactory = restateContainerFactory;\n } else if (typeof param !== \"function\") {\n containerFactory = () => {\n const container = new RestateContainer();\n if (param.alwaysReplay) {\n container.alwaysReplay();\n }\n if (param.disableRetries) {\n container.disableRetries();\n }\n return container;\n };\n } else {\n containerFactory = () => new RestateContainer();\n }\n\n const startedRestateHttpServer =\n typeof param === \"function\"\n ? await prepareRestateEndpoint(param)\n : await prepareRestateEndpoint(param);\n const startedRestateContainer = await prepareRestateTestContainer(\n (startedRestateHttpServer.address() as net.AddressInfo).port,\n containerFactory\n );\n return new RestateTestEnvironment(\n startedRestateHttpServer,\n startedRestateContainer\n );\n }\n}\n\nexport class RestateContainer extends GenericContainer {\n constructor(version = \"latest\") {\n super(`docker.io/restatedev/restate:${version}`);\n }\n\n /**\n * Forces restate-server to always replay on a suspension point.\n * This is useful to hunt non-deterministic bugs that might prevent\n * your code from replaying correctly.\n */\n alwaysReplay(): this {\n this.withEnvironment({\n RESTATE_WORKER__INVOKER__INACTIVITY_TIMEOUT: \"0s\",\n });\n return this;\n }\n\n /**\n * Disables retries in the restate-server invoker.\n * This is useful in tests so that failures surface immediately\n * instead of hanging through retry backoff.\n */\n disableRetries(): this {\n this.withEnvironment({\n RESTATE_DEFAULT_RETRY_POLICY__MAX_ATTEMPTS: \"1\",\n RESTATE_DEFAULT_RETRY_POLICY__ON_MAX_ATTEMPTS: \"kill\",\n });\n return this;\n }\n}\nexport class StateProxy<TState extends TypedState> {\n constructor(\n private adminAPIBaseUrl: string,\n private service: string,\n private serviceKey: string\n ) {}\n\n // Read a single value from state under a given Virtual Object or Workflow key\n public async get<TValue, TKey extends keyof TState = string>(\n name: TState extends UntypedState ? string : TKey,\n serde?: Serde<TState extends UntypedState ? TValue : TState[TKey]>\n ): Promise<(TState extends UntypedState ? TValue : TState[TKey]) | null> {\n serde = serde ?? defaultSerde();\n\n const res = await fetch(`${this.adminAPIBaseUrl}/query`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n query: `SELECT value from state where service_name = '${\n this.service\n }' and service_key = '${this.serviceKey}' and key = '${String(name)}';`,\n }),\n });\n\n if (!res.ok) {\n const badResponse = await res.text();\n throw new Error(`Error ${res.status} during read state: ${badResponse}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/await-thenable\n const table = (await tableFromIPC(res.body)).toArray() as {\n key: string;\n value: Uint8Array;\n }[];\n\n if (table.length === 0) {\n return null;\n }\n\n return serde.deserialize(table[0]!.value);\n }\n\n // Read all values from state under a given Virtual Object or Workflow key\n public async getAll<TValues extends TypedState>(\n serde?: Serde<\n TState extends UntypedState\n ? TValues[keyof TValues]\n : TState[keyof TState]\n >\n ): Promise<TState extends UntypedState ? TValues : TState> {\n serde = serde ?? defaultSerde();\n\n const items = await this.getAllRaw();\n\n return Object.fromEntries(\n items.map(({ key, value }) => {\n return [key, serde.deserialize(value)];\n })\n ) as TState extends UntypedState ? TValues : TState;\n }\n\n private async getAllRaw(): Promise<{ key: string; value: Uint8Array }[]> {\n const res = await fetch(`${this.adminAPIBaseUrl}/query`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n query: `SELECT key, value from state where service_name = '${this.service}' and service_key = '${this.serviceKey}';`,\n }),\n });\n\n if (!res.ok) {\n const badResponse = await res.text();\n throw new Error(`Error ${res.status} during read state: ${badResponse}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/await-thenable\n const table = (await tableFromIPC(res.body)).toArray() as {\n key: string;\n value: Uint8Array;\n }[];\n\n return table;\n }\n\n // Asynchronously set a single value from state under a given Virtual Object or Workflow key.\n // This will first read all values, then insert the update and submit the new set of values to Restate;\n // as such it is possible to overwrite changes that happened between the read and the mutation being applied.\n // A successful return from this function does not imply that the set has finished, only that the mutation\n // was submitted to Restate for processing.\n public async set<TValue, TKey extends keyof TState = string>(\n name: TState extends UntypedState ? string : TKey,\n value: TState extends UntypedState ? TValue : TState[TKey],\n serde?: Serde<TState extends UntypedState ? TValue : TState[TKey]>\n ): Promise<void> {\n serde = serde ?? defaultSerde();\n const serialisedValue = serde.serialize(value);\n\n const items = await this.getAllRaw();\n\n items.push({ key: String(name), value: serialisedValue });\n\n await this.setAllRaw(items.map(({ key, value }) => [key, value]));\n }\n\n // Asynchronously set all state values under a given Virtual Object or Workflow key.\n // A successful return from this function does not imply that the set has finished,\n // only that the mutation was submitted to Restate for processing.\n public async setAll<TValues extends TypedState>(\n values: TState extends UntypedState ? TValues : TState,\n serde?: Serde<\n TState extends UntypedState\n ? TValues[keyof TValues]\n : TState[keyof TState]\n >\n ) {\n serde = serde ?? defaultSerde();\n\n return this.setAllRaw(\n Object.entries<\n TState extends UntypedState\n ? TValues[keyof TValues]\n : TState[keyof TState]\n >(values).map(([key, value]) => {\n return [key, serde.serialize(value)];\n })\n );\n }\n\n private async setAllRaw(\n entries: [key: string, value: Uint8Array][],\n version?: string\n ) {\n const res = await fetch(\n `${this.adminAPIBaseUrl}/services/${this.service}/state`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n {\n version,\n object_key: this.serviceKey,\n new_state: Object.fromEntries(entries),\n },\n (key, value) => {\n if (value instanceof Uint8Array) {\n return Array.from(value);\n } else {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n }\n }\n ),\n }\n );\n\n if (!res.ok) {\n const badResponse = await res.text();\n throw new Error(\n `Error ${res.status} during modify state: ${badResponse}`\n );\n }\n }\n}\n\nexport const defaultSerde = <T>(): Serde<T> => {\n return serde.json as Serde<T>;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"restate_test_environment.js","names":["DEFAULT_START_OPTIONS: ResolvedTestEnvironmentOptions","handler: (\n request: http2.Http2ServerRequest,\n response: http2.Http2ServerResponse\n ) => void","startedRestateHttpServer: http2.Http2Server","startedRestateContainer: StartedTestContainer","containerFactory: () => GenericContainer","resolvedStartOptions: ResolvedTestEnvironmentOptions","adminAPIBaseUrl: string","service: string","serviceKey: string","serde","value"],"sources":["../src/restate_test_environment.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH\n *\n * This file is part of the Restate SDK for Node.js/TypeScript,\n * which is released under the MIT license.\n *\n * You can find a copy of the license in file LICENSE in the root\n * directory of this repository or package, or at\n * https://github.com/restatedev/sdk-typescript/blob/main/LICENSE\n */\n\nimport { createEndpointHandler, serde } from \"@restatedev/restate-sdk\";\nimport type {\n TypedState,\n UntypedState,\n Serde,\n VirtualObjectDefinition,\n WorkflowDefinition,\n EndpointOptions,\n} from \"@restatedev/restate-sdk\";\n\nimport {\n GenericContainer,\n type StartedTestContainer,\n TestContainers,\n Wait,\n type WaitStrategy,\n type BoundPorts,\n getContainerRuntimeClient,\n} from \"testcontainers\";\nimport { tableFromIPC } from \"apache-arrow\";\nimport * as http2 from \"http2\";\nimport type * as net from \"net\";\n\nexport type ServiceEndpointAccess = \"testcontainers\" | \"docker-host\";\n\nexport type TestEnvironmentStorage = \"disk\" | \"memory\";\n\ninterface ResolvedTestEnvironmentOptions {\n serviceEndpointAccess: ServiceEndpointAccess;\n storage: TestEnvironmentStorage;\n}\n\nconst DEFAULT_START_OPTIONS: ResolvedTestEnvironmentOptions = {\n serviceEndpointAccess: \"docker-host\",\n storage: \"memory\",\n};\n\n/**\n * Custom wait strategy that waits for Restate partitions to be ready by\n * executing a SQL query against the admin API. This ensures all partitions\n * are initialized and queryable before the container is considered ready.\n */\nclass PartitionsReadyWaitStrategy implements WaitStrategy {\n private startupTimeoutMs = 60_000;\n private startupTimeoutSet = false;\n private readonly port: number;\n private readonly pollIntervalMs: number;\n\n constructor(port = 9070, pollIntervalMs = 200) {\n this.port = port;\n this.pollIntervalMs = pollIntervalMs;\n }\n\n public withStartupTimeout(startupTimeoutMs: number): this {\n this.startupTimeoutMs = startupTimeoutMs;\n this.startupTimeoutSet = true;\n return this;\n }\n\n public isStartupTimeoutSet(): boolean {\n return this.startupTimeoutSet;\n }\n\n public getStartupTimeout(): number {\n return this.startupTimeoutMs;\n }\n\n public async waitUntilReady(\n container: { id: string },\n boundPorts: BoundPorts\n ): Promise<void> {\n const client = await getContainerRuntimeClient();\n const host = client.info.containerRuntime.host;\n const mappedPort = boundPorts.getBinding(this.port);\n const adminUrl = `http://${host}:${mappedPort}`;\n\n const startTime = Date.now();\n\n while (Date.now() - startTime < this.startupTimeoutMs) {\n try {\n const res = await fetch(`${adminUrl}/query`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query: \"SELECT count(1) FROM sys_invocation\",\n }),\n });\n\n if (res.ok) {\n // Partitions are ready\n return;\n }\n } catch {\n // Ignore errors, keep polling\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));\n }\n\n throw new Error(\n `Restate partitions not ready after ${this.startupTimeoutMs}ms`\n );\n }\n}\n\n// Prepare the restate server\nasync function prepareRestateEndpoint(\n param: EndpointOptions\n): Promise<http2.Http2Server> {\n // Prepare RestateServer\n const handler: (\n request: http2.Http2ServerRequest,\n response: http2.Http2ServerResponse\n ) => void = createEndpointHandler(param);\n\n // Start HTTP2 server on random port\n const restateHttpServer = http2.createServer(handler);\n await new Promise((resolve, reject) => {\n restateHttpServer\n .listen(0)\n .once(\"listening\", resolve)\n .once(\"error\", reject);\n });\n const restateServerPort = (restateHttpServer.address() as net.AddressInfo)\n .port;\n console.info(`Restate container listening on port ${restateServerPort}`);\n\n return restateHttpServer;\n}\n\n// Prepare the restate testcontainer\nasync function prepareRestateTestContainer(\n restateServerPort: number,\n restateContainerFactory: () => GenericContainer,\n options: ResolvedTestEnvironmentOptions\n): Promise<StartedTestContainer> {\n let restateContainer = restateContainerFactory()\n // Expose ports\n .withExposedPorts(8080, 9070)\n // Wait start on health checks and partition readiness\n .withWaitStrategy(\n Wait.forAll([\n Wait.forHttp(\"/restate/health\", 8080),\n Wait.forHttp(\"/health\", 9070),\n new PartitionsReadyWaitStrategy(),\n ])\n );\n\n if (options.storage === \"memory\") {\n restateContainer = restateContainer.withTmpFs({ \"/restate-data\": \"rw\" });\n }\n\n const serviceEndpointHost =\n options.serviceEndpointAccess === \"docker-host\"\n ? \"host.docker.internal\"\n : \"host.testcontainers.internal\";\n\n if (options.serviceEndpointAccess === \"docker-host\") {\n restateContainer = restateContainer.withExtraHosts([\n { host: \"host.docker.internal\", ipAddress: \"host-gateway\" },\n ]);\n } else {\n // This MUST be executed before starting the restate container.\n // Expose host port to access the restate server.\n await TestContainers.exposeHostPorts(restateServerPort);\n }\n\n // Start restate container\n const startedRestateContainer = await restateContainer.start();\n\n // From now on, if something fails, stop the container to cleanup the environment\n try {\n console.info(\n `Registering services at http://${serviceEndpointHost}:${restateServerPort}...`\n );\n\n // Register this service endpoint\n const res = await fetch(\n `http://${startedRestateContainer.getHost()}:${startedRestateContainer.getMappedPort(\n 9070\n )}/deployments`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n uri: `http://${serviceEndpointHost}:${restateServerPort}`,\n }),\n }\n );\n if (!res.ok) {\n const badResponse = await res.text();\n throw new Error(\n `Error ${res.status} during registration: ${badResponse}`\n );\n }\n\n const resp = (await res.json()) as { services: { name: string }[] };\n console.info(\n \"Registered services:\",\n resp?.services?.map((s) => s.name)\n );\n return startedRestateContainer;\n } catch (e) {\n await startedRestateContainer.stop();\n throw e;\n }\n}\n\nexport interface TestEnvironmentOptions extends EndpointOptions {\n /**\n * Factory for the Restate container used by the test environment.\n *\n * Use this to customize the Restate image or container settings before the\n * helper applies its own ports, wait strategy, networking, and storage\n * configuration.\n *\n * For backwards compatibility, the second `start(options, factory)` argument\n * is still supported and takes precedence over this option.\n *\n * @defaultValue `() => new RestateContainer()`\n */\n container?: () => GenericContainer;\n\n /**\n * Controls how the Restate container reaches the SDK service endpoint running\n * on the test host.\n *\n * - `\"testcontainers\"` exposes the host port through Testcontainers and\n * registers `http://host.testcontainers.internal:<port>`.\n * - `\"docker-host\"` skips Testcontainers port exposure, adds\n * `host.docker.internal:host-gateway` to the Restate container, and\n * registers `http://host.docker.internal:<port>`.\n *\n * @defaultValue `\"docker-host\"`\n */\n serviceEndpointAccess?: ServiceEndpointAccess;\n\n /**\n * Controls where Restate stores container data.\n *\n * - `\"disk\"` keeps the current Testcontainers/Docker storage behavior.\n * - `\"memory\"` mounts `/restate-data` as tmpfs for faster disposable tests.\n *\n * @defaultValue `\"memory\"`\n */\n storage?: TestEnvironmentStorage;\n\n /**\n * Forces restate-server to always replay on a suspension point.\n * This is useful to hunt non-deterministic bugs that might prevent\n * your code from replaying correctly.\n */\n alwaysReplay?: boolean;\n\n /**\n * Disables retries in the restate-server invoker.\n * This is useful in tests so that failures surface immediately\n * instead of hanging through retry backoff.\n */\n disableRetries?: boolean;\n}\n\nexport class RestateTestEnvironment {\n constructor(\n readonly startedRestateHttpServer: http2.Http2Server,\n readonly startedRestateContainer: StartedTestContainer\n ) {}\n\n public baseUrl(): string {\n return `http://${this.startedRestateContainer.getHost()}:${this.startedRestateContainer.getMappedPort(\n 8080\n )}`;\n }\n\n public adminAPIBaseUrl(): string {\n return `http://${this.startedRestateContainer.getHost()}:${this.startedRestateContainer.getMappedPort(\n 9070\n )}`;\n }\n\n // Create a handle that allows read/write of state under a given Virtual Object/Workflow key.\n public stateOf<TState extends TypedState = UntypedState>(\n service:\n | VirtualObjectDefinition<string, unknown>\n | WorkflowDefinition<string, unknown>,\n key: string\n ): StateProxy<TState> {\n return new StateProxy(this.adminAPIBaseUrl(), service.name, key);\n }\n\n public async stop() {\n await this.startedRestateContainer.stop();\n this.startedRestateHttpServer.close();\n }\n\n public static async start(\n options: TestEnvironmentOptions,\n restateContainerFactory?: () => GenericContainer\n ): Promise<RestateTestEnvironment> {\n let containerFactory: () => GenericContainer;\n if (restateContainerFactory) {\n containerFactory = restateContainerFactory;\n } else if (options.container) {\n containerFactory = options.container;\n } else {\n containerFactory = () => {\n const container = new RestateContainer();\n if (options.alwaysReplay) {\n container.alwaysReplay();\n }\n if (options.disableRetries) {\n container.disableRetries();\n }\n return container;\n };\n }\n const resolvedStartOptions: ResolvedTestEnvironmentOptions = {\n serviceEndpointAccess:\n options.serviceEndpointAccess ??\n DEFAULT_START_OPTIONS.serviceEndpointAccess,\n storage: options.storage ?? DEFAULT_START_OPTIONS.storage,\n };\n\n const startedRestateHttpServer = await prepareRestateEndpoint(options);\n const startedRestateContainer = await prepareRestateTestContainer(\n (startedRestateHttpServer.address() as net.AddressInfo).port,\n containerFactory,\n resolvedStartOptions\n );\n return new RestateTestEnvironment(\n startedRestateHttpServer,\n startedRestateContainer\n );\n }\n}\n\nexport class RestateContainer extends GenericContainer {\n constructor(version = \"latest\") {\n super(`docker.io/restatedev/restate:${version}`);\n }\n\n /**\n * Forces restate-server to always replay on a suspension point.\n * This is useful to hunt non-deterministic bugs that might prevent\n * your code from replaying correctly.\n */\n alwaysReplay(): this {\n this.withEnvironment({\n RESTATE_WORKER__INVOKER__INACTIVITY_TIMEOUT: \"0s\",\n });\n return this;\n }\n\n /**\n * Disables retries in the restate-server invoker.\n * This is useful in tests so that failures surface immediately\n * instead of hanging through retry backoff.\n */\n disableRetries(): this {\n this.withEnvironment({\n RESTATE_DEFAULT_RETRY_POLICY__MAX_ATTEMPTS: \"1\",\n RESTATE_DEFAULT_RETRY_POLICY__ON_MAX_ATTEMPTS: \"kill\",\n });\n return this;\n }\n}\nexport class StateProxy<TState extends TypedState> {\n constructor(\n private adminAPIBaseUrl: string,\n private service: string,\n private serviceKey: string\n ) {}\n\n // Read a single value from state under a given Virtual Object or Workflow key\n public async get<TValue, TKey extends keyof TState = string>(\n name: TState extends UntypedState ? string : TKey,\n serde?: Serde<TState extends UntypedState ? TValue : TState[TKey]>\n ): Promise<(TState extends UntypedState ? TValue : TState[TKey]) | null> {\n serde = serde ?? defaultSerde();\n\n const res = await fetch(`${this.adminAPIBaseUrl}/query`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n query: `SELECT value from state where service_name = '${\n this.service\n }' and service_key = '${this.serviceKey}' and key = '${String(name)}';`,\n }),\n });\n\n if (!res.ok) {\n const badResponse = await res.text();\n throw new Error(`Error ${res.status} during read state: ${badResponse}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/await-thenable\n const table = (await tableFromIPC(res.body)).toArray() as {\n key: string;\n value: Uint8Array;\n }[];\n\n if (table.length === 0) {\n return null;\n }\n\n return serde.deserialize(table[0]!.value);\n }\n\n // Read all values from state under a given Virtual Object or Workflow key\n public async getAll<TValues extends TypedState>(\n serde?: Serde<\n TState extends UntypedState\n ? TValues[keyof TValues]\n : TState[keyof TState]\n >\n ): Promise<TState extends UntypedState ? TValues : TState> {\n serde = serde ?? defaultSerde();\n\n const items = await this.getAllRaw();\n\n return Object.fromEntries(\n items.map(({ key, value }) => {\n return [key, serde.deserialize(value)];\n })\n ) as TState extends UntypedState ? TValues : TState;\n }\n\n private async getAllRaw(): Promise<{ key: string; value: Uint8Array }[]> {\n const res = await fetch(`${this.adminAPIBaseUrl}/query`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n query: `SELECT key, value from state where service_name = '${this.service}' and service_key = '${this.serviceKey}';`,\n }),\n });\n\n if (!res.ok) {\n const badResponse = await res.text();\n throw new Error(`Error ${res.status} during read state: ${badResponse}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/await-thenable\n const table = (await tableFromIPC(res.body)).toArray() as {\n key: string;\n value: Uint8Array;\n }[];\n\n return table;\n }\n\n // Asynchronously set a single value from state under a given Virtual Object or Workflow key.\n // This will first read all values, then insert the update and submit the new set of values to Restate;\n // as such it is possible to overwrite changes that happened between the read and the mutation being applied.\n // A successful return from this function does not imply that the set has finished, only that the mutation\n // was submitted to Restate for processing.\n public async set<TValue, TKey extends keyof TState = string>(\n name: TState extends UntypedState ? string : TKey,\n value: TState extends UntypedState ? TValue : TState[TKey],\n serde?: Serde<TState extends UntypedState ? TValue : TState[TKey]>\n ): Promise<void> {\n serde = serde ?? defaultSerde();\n const serialisedValue = serde.serialize(value);\n\n const items = await this.getAllRaw();\n\n items.push({ key: String(name), value: serialisedValue });\n\n await this.setAllRaw(items.map(({ key, value }) => [key, value]));\n }\n\n // Asynchronously set all state values under a given Virtual Object or Workflow key.\n // A successful return from this function does not imply that the set has finished,\n // only that the mutation was submitted to Restate for processing.\n public async setAll<TValues extends TypedState>(\n values: TState extends UntypedState ? TValues : TState,\n serde?: Serde<\n TState extends UntypedState\n ? TValues[keyof TValues]\n : TState[keyof TState]\n >\n ) {\n serde = serde ?? defaultSerde();\n\n return this.setAllRaw(\n Object.entries<\n TState extends UntypedState\n ? TValues[keyof TValues]\n : TState[keyof TState]\n >(values).map(([key, value]) => {\n return [key, serde.serialize(value)];\n })\n );\n }\n\n private async setAllRaw(\n entries: [key: string, value: Uint8Array][],\n version?: string\n ) {\n const res = await fetch(\n `${this.adminAPIBaseUrl}/services/${this.service}/state`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n {\n version,\n object_key: this.serviceKey,\n new_state: Object.fromEntries(entries),\n },\n (key, value) => {\n if (value instanceof Uint8Array) {\n return Array.from(value);\n } else {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n }\n }\n ),\n }\n );\n\n if (!res.ok) {\n const badResponse = await res.text();\n throw new Error(\n `Error ${res.status} during modify state: ${badResponse}`\n );\n }\n }\n}\n\nexport const defaultSerde = <T>(): Serde<T> => {\n return serde.json as Serde<T>;\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@restatedev/restate-sdk-testcontainers",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.1",
|
|
4
4
|
"description": "Typescript SDK for Restate",
|
|
5
5
|
"author": "Restate Developers",
|
|
6
6
|
"email": "code@restate.dev",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"apache-arrow": "^18.0.0",
|
|
36
36
|
"testcontainers": "^11.12.0",
|
|
37
|
-
"@restatedev/restate-sdk": "1.
|
|
38
|
-
"@restatedev/restate-sdk-clients": "1.
|
|
37
|
+
"@restatedev/restate-sdk": "1.14.1",
|
|
38
|
+
"@restatedev/restate-sdk-clients": "1.14.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {},
|
|
41
41
|
"scripts": {
|