@restatedev/restate-sdk 1.12.0 → 1.14.0
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/README.md +12 -9
- package/dist/endpoint/components.cjs +70 -12
- package/dist/endpoint/components.d.ts.map +1 -1
- package/dist/endpoint/components.js +70 -12
- package/dist/endpoint/components.js.map +1 -1
- package/dist/endpoint/handlers/fetch.cjs +5 -3
- package/dist/endpoint/handlers/fetch.d.ts.map +1 -1
- package/dist/endpoint/handlers/fetch.js +6 -4
- package/dist/endpoint/handlers/fetch.js.map +1 -1
- package/dist/endpoint/handlers/generic.cjs +11 -10
- package/dist/endpoint/handlers/generic.d.ts.map +1 -1
- package/dist/endpoint/handlers/generic.js +11 -10
- package/dist/endpoint/handlers/generic.js.map +1 -1
- package/dist/endpoint/handlers/lambda.cjs +6 -3
- package/dist/endpoint/handlers/lambda.d.ts.map +1 -1
- package/dist/endpoint/handlers/lambda.js +7 -4
- package/dist/endpoint/handlers/lambda.js.map +1 -1
- package/dist/endpoint/handlers/preview.cjs +97 -0
- package/dist/endpoint/handlers/preview.d.ts +5 -0
- package/dist/endpoint/handlers/preview.d.ts.map +1 -0
- package/dist/endpoint/handlers/preview.js +98 -0
- package/dist/endpoint/handlers/preview.js.map +1 -0
- package/dist/endpoint/handlers/types.d.ts.map +1 -1
- package/dist/endpoint/handlers/utils.cjs +26 -11
- package/dist/endpoint/handlers/utils.d.ts +12 -0
- package/dist/endpoint/handlers/utils.d.ts.map +1 -1
- package/dist/endpoint/handlers/utils.js +26 -12
- package/dist/endpoint/handlers/utils.js.map +1 -1
- package/dist/endpoint/node_endpoint.cjs +9 -6
- package/dist/endpoint/node_endpoint.js +9 -6
- package/dist/endpoint/node_endpoint.js.map +1 -1
- package/dist/io.cjs +7 -2
- package/dist/io.d.ts.map +1 -1
- package/dist/io.js +7 -2
- package/dist/io.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/dist/promises.cjs +21 -10
- package/dist/promises.js +21 -10
- package/dist/promises.js.map +1 -1
- package/dist/types/rpc.d.cts +11 -0
- package/dist/types/rpc.d.cts.map +1 -1
- package/dist/types/rpc.d.ts +11 -0
- package/dist/types/rpc.d.ts.map +1 -1
- package/dist/types/rpc.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ensureError } from "../../types/errors.js";
|
|
2
|
+
import { X_RESTATE_SERVER } from "../../user_agent.js";
|
|
3
|
+
import { errorResponse } from "./utils.js";
|
|
4
|
+
|
|
5
|
+
//#region src/endpoint/handlers/preview.ts
|
|
6
|
+
function handlePreview(endpoint, previewPathComponent) {
|
|
7
|
+
const service = endpoint.components.get(previewPathComponent.componentName);
|
|
8
|
+
if (!service) {
|
|
9
|
+
const msg = `No service found for name: ${previewPathComponent.componentName}`;
|
|
10
|
+
endpoint.rlog.error(msg);
|
|
11
|
+
return errorResponse(404, msg);
|
|
12
|
+
}
|
|
13
|
+
const resolvedSerde = service.serdeMatching(previewPathComponent.serdeName);
|
|
14
|
+
if (!resolvedSerde?.preview) {
|
|
15
|
+
const msg = `No previewable serde found for URL: ${JSON.stringify(previewPathComponent)}`;
|
|
16
|
+
endpoint.rlog.error(msg);
|
|
17
|
+
return errorResponse(404, msg);
|
|
18
|
+
}
|
|
19
|
+
return new RestatePreviewResponse(resolvedSerde, previewPathComponent.operation);
|
|
20
|
+
}
|
|
21
|
+
var RestatePreviewResponse = class {
|
|
22
|
+
constructor(serde, operation) {
|
|
23
|
+
this.serde = serde;
|
|
24
|
+
this.operation = operation;
|
|
25
|
+
}
|
|
26
|
+
async process({ inputReader, outputWriter, writeHead }) {
|
|
27
|
+
const response = await this.computeResponse(inputReader);
|
|
28
|
+
writeHead(response.statusCode, response.headers);
|
|
29
|
+
try {
|
|
30
|
+
await outputWriter.write(response.body);
|
|
31
|
+
} finally {
|
|
32
|
+
await outputWriter.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async computeResponse(inputReader) {
|
|
36
|
+
try {
|
|
37
|
+
const body = await readAllInput(inputReader);
|
|
38
|
+
return this.operation === "decode" ? await this.decode(body) : await this.encode(body);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
return previewErrorResponse(ensureError(e).message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async decode(requestBody) {
|
|
44
|
+
const value = this.serde.deserialize(requestBody);
|
|
45
|
+
const json = await this.serde.preview.toJsonString(value);
|
|
46
|
+
return {
|
|
47
|
+
statusCode: 200,
|
|
48
|
+
headers: {
|
|
49
|
+
"content-type": "application/json",
|
|
50
|
+
"x-restate-server": X_RESTATE_SERVER
|
|
51
|
+
},
|
|
52
|
+
body: new TextEncoder().encode(json)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async encode(requestBody) {
|
|
56
|
+
const json = new TextDecoder().decode(requestBody);
|
|
57
|
+
const value = await this.serde.preview.fromJsonString(json);
|
|
58
|
+
return {
|
|
59
|
+
statusCode: 200,
|
|
60
|
+
headers: {
|
|
61
|
+
"content-type": this.serde.contentType ?? "application/octet-stream",
|
|
62
|
+
"x-restate-server": X_RESTATE_SERVER
|
|
63
|
+
},
|
|
64
|
+
body: this.serde.serialize(value)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function previewErrorResponse(message) {
|
|
69
|
+
return {
|
|
70
|
+
statusCode: 422,
|
|
71
|
+
headers: {
|
|
72
|
+
"content-type": "application/json",
|
|
73
|
+
"x-restate-server": X_RESTATE_SERVER
|
|
74
|
+
},
|
|
75
|
+
body: new TextEncoder().encode(JSON.stringify({ message }))
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function readAllInput(inputReader) {
|
|
79
|
+
const chunks = [];
|
|
80
|
+
let totalLength = 0;
|
|
81
|
+
while (true) {
|
|
82
|
+
const chunk = await inputReader.next();
|
|
83
|
+
if (chunk.done) break;
|
|
84
|
+
chunks.push(chunk.value);
|
|
85
|
+
totalLength += chunk.value.length;
|
|
86
|
+
}
|
|
87
|
+
const combined = new Uint8Array(totalLength);
|
|
88
|
+
let offset = 0;
|
|
89
|
+
for (const chunk of chunks) {
|
|
90
|
+
combined.set(chunk, offset);
|
|
91
|
+
offset += chunk.length;
|
|
92
|
+
}
|
|
93
|
+
return combined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { handlePreview };
|
|
98
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","names":["serde: Serde<unknown>","operation: \"decode\" | \"encode\"","chunks: Uint8Array[]"],"sources":["../../../src/endpoint/handlers/preview.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 type { Serde } from \"@restatedev/restate-sdk-core\";\nimport type { Endpoint } from \"../endpoint.js\";\nimport type { PreviewPathComponents } from \"../components.js\";\nimport { X_RESTATE_SERVER } from \"../../user_agent.js\";\nimport { ensureError } from \"../../types/errors.js\";\nimport type {\n InputReader,\n OutputWriter,\n ResponseHeaders,\n RestateResponse,\n} from \"./types.js\";\nimport { errorResponse } from \"./utils.js\";\n\nexport function handlePreview(\n endpoint: Endpoint,\n previewPathComponent: PreviewPathComponents\n): RestateResponse {\n const service = endpoint.components.get(previewPathComponent.componentName);\n if (!service) {\n const msg = `No service found for name: ${previewPathComponent.componentName}`;\n endpoint.rlog.error(msg);\n return errorResponse(404, msg);\n }\n\n const resolvedSerde = service.serdeMatching(previewPathComponent.serdeName);\n if (!resolvedSerde?.preview) {\n const msg = `No previewable serde found for URL: ${JSON.stringify(previewPathComponent)}`;\n endpoint.rlog.error(msg);\n return errorResponse(404, msg);\n }\n\n return new RestatePreviewResponse(\n resolvedSerde,\n previewPathComponent.operation\n );\n}\n\ntype PreviewResponse = {\n body: Uint8Array;\n headers: ResponseHeaders;\n statusCode: number;\n};\n\nclass RestatePreviewResponse implements RestateResponse {\n constructor(\n private readonly serde: Serde<unknown>,\n private readonly operation: \"decode\" | \"encode\"\n ) {}\n\n async process({\n inputReader,\n outputWriter,\n writeHead,\n }: {\n inputReader: InputReader;\n outputWriter: OutputWriter;\n writeHead: (statusCode: number, headers: ResponseHeaders) => void;\n abortSignal: AbortSignal;\n }): Promise<void> {\n const response = await this.computeResponse(inputReader);\n\n writeHead(response.statusCode, response.headers);\n try {\n await outputWriter.write(response.body);\n } finally {\n await outputWriter.close();\n }\n }\n\n private async computeResponse(\n inputReader: InputReader\n ): Promise<PreviewResponse> {\n try {\n const body = await readAllInput(inputReader);\n return this.operation === \"decode\"\n ? await this.decode(body)\n : await this.encode(body);\n } catch (e) {\n return previewErrorResponse(ensureError(e).message);\n }\n }\n\n private async decode(requestBody: Uint8Array): Promise<PreviewResponse> {\n const value = this.serde.deserialize(requestBody);\n const json = await this.serde.preview!.toJsonString(value);\n return {\n statusCode: 200,\n headers: {\n \"content-type\": \"application/json\",\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n body: new TextEncoder().encode(json),\n };\n }\n\n private async encode(requestBody: Uint8Array): Promise<PreviewResponse> {\n const json = new TextDecoder().decode(requestBody);\n const value = await this.serde.preview!.fromJsonString(json);\n return {\n statusCode: 200,\n headers: {\n \"content-type\": this.serde.contentType ?? \"application/octet-stream\",\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n body: this.serde.serialize(value),\n };\n }\n}\n\nfunction previewErrorResponse(message: string): PreviewResponse {\n return {\n statusCode: 422,\n headers: {\n \"content-type\": \"application/json\",\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n body: new TextEncoder().encode(JSON.stringify({ message })),\n };\n}\n\nasync function readAllInput(inputReader: InputReader): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n while (true) {\n const chunk = await inputReader.next();\n if (chunk.done) {\n break;\n }\n chunks.push(chunk.value);\n totalLength += chunk.value.length;\n }\n\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n return combined;\n}\n"],"mappings":";;;;;AAwBA,SAAgB,cACd,UACA,sBACiB;CACjB,MAAM,UAAU,SAAS,WAAW,IAAI,qBAAqB,cAAc;AAC3E,KAAI,CAAC,SAAS;EACZ,MAAM,MAAM,8BAA8B,qBAAqB;AAC/D,WAAS,KAAK,MAAM,IAAI;AACxB,SAAO,cAAc,KAAK,IAAI;;CAGhC,MAAM,gBAAgB,QAAQ,cAAc,qBAAqB,UAAU;AAC3E,KAAI,CAAC,eAAe,SAAS;EAC3B,MAAM,MAAM,uCAAuC,KAAK,UAAU,qBAAqB;AACvF,WAAS,KAAK,MAAM,IAAI;AACxB,SAAO,cAAc,KAAK,IAAI;;AAGhC,QAAO,IAAI,uBACT,eACA,qBAAqB,UACtB;;AASH,IAAM,yBAAN,MAAwD;CACtD,YACE,AAAiBA,OACjB,AAAiBC,WACjB;EAFiB;EACA;;CAGnB,MAAM,QAAQ,EACZ,aACA,cACA,aAMgB;EAChB,MAAM,WAAW,MAAM,KAAK,gBAAgB,YAAY;AAExD,YAAU,SAAS,YAAY,SAAS,QAAQ;AAChD,MAAI;AACF,SAAM,aAAa,MAAM,SAAS,KAAK;YAC/B;AACR,SAAM,aAAa,OAAO;;;CAI9B,MAAc,gBACZ,aAC0B;AAC1B,MAAI;GACF,MAAM,OAAO,MAAM,aAAa,YAAY;AAC5C,UAAO,KAAK,cAAc,WACtB,MAAM,KAAK,OAAO,KAAK,GACvB,MAAM,KAAK,OAAO,KAAK;WACpB,GAAG;AACV,UAAO,qBAAqB,YAAY,EAAE,CAAC,QAAQ;;;CAIvD,MAAc,OAAO,aAAmD;EACtE,MAAM,QAAQ,KAAK,MAAM,YAAY,YAAY;EACjD,MAAM,OAAO,MAAM,KAAK,MAAM,QAAS,aAAa,MAAM;AAC1D,SAAO;GACL,YAAY;GACZ,SAAS;IACP,gBAAgB;IAChB,oBAAoB;IACrB;GACD,MAAM,IAAI,aAAa,CAAC,OAAO,KAAK;GACrC;;CAGH,MAAc,OAAO,aAAmD;EACtE,MAAM,OAAO,IAAI,aAAa,CAAC,OAAO,YAAY;EAClD,MAAM,QAAQ,MAAM,KAAK,MAAM,QAAS,eAAe,KAAK;AAC5D,SAAO;GACL,YAAY;GACZ,SAAS;IACP,gBAAgB,KAAK,MAAM,eAAe;IAC1C,oBAAoB;IACrB;GACD,MAAM,KAAK,MAAM,UAAU,MAAM;GAClC;;;AAIL,SAAS,qBAAqB,SAAkC;AAC9D,QAAO;EACL,YAAY;EACZ,SAAS;GACP,gBAAgB;GAChB,oBAAoB;GACrB;EACD,MAAM,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,EAAE,SAAS,CAAC,CAAC;EAC5D;;AAGH,eAAe,aAAa,aAA+C;CACzE,MAAMC,SAAuB,EAAE;CAC/B,IAAI,cAAc;AAElB,QAAO,MAAM;EACX,MAAM,QAAQ,MAAM,YAAY,MAAM;AACtC,MAAI,MAAM,KACR;AAEF,SAAO,KAAK,MAAM,MAAM;AACxB,iBAAe,MAAM,MAAM;;CAG7B,MAAM,WAAW,IAAI,WAAW,YAAY;CAC5C,IAAI,SAAS;AACb,MAAK,MAAM,SAAS,QAAQ;AAC1B,WAAS,IAAI,OAAO,OAAO;AAC3B,YAAU,MAAM;;AAElB,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/endpoint/handlers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,OAAO;IACtB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC;CAC/B;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAErC,MAAM,MAAM,WAAW,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;AAEpD,MAAM,WAAW,YAAY;IAE3B,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/endpoint/handlers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,OAAO;IACtB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC;CAC/B;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAErC,MAAM,MAAM,WAAW,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;AAEpD,MAAM,WAAW,YAAY;IAE3B,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,OAAO,CAAC,KAAK,EAAE;QACb,WAAW,EAAE,WAAW,CAAC;QACzB,YAAY,EAAE,YAAY,CAAC;QAC3B,SAAS,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;QAClE,WAAW,EAAE,WAAW,CAAC;KAC1B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAE7B,QAAQ,EAAE,QAAQ,CAAC;IAEnB,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,eAAe,CAAC;CAC/E"}
|
|
@@ -26,24 +26,39 @@ function errorResponse(code, message) {
|
|
|
26
26
|
}, new TextEncoder().encode(JSON.stringify({ message })));
|
|
27
27
|
}
|
|
28
28
|
function simpleResponse(statusCode, headers, body) {
|
|
29
|
-
return {
|
|
30
|
-
headers
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
const { done } = await inputReader.next();
|
|
35
|
-
if (done) break;
|
|
36
|
-
}
|
|
37
|
-
await outputWriter.write(body);
|
|
38
|
-
await outputWriter.close();
|
|
29
|
+
return { async process({ inputReader, outputWriter, writeHead }) {
|
|
30
|
+
writeHead(statusCode, headers);
|
|
31
|
+
while (true) {
|
|
32
|
+
const { done } = await inputReader.next();
|
|
33
|
+
if (done) break;
|
|
39
34
|
}
|
|
40
|
-
|
|
35
|
+
await outputWriter.write(body);
|
|
36
|
+
await outputWriter.close();
|
|
37
|
+
} };
|
|
41
38
|
}
|
|
42
39
|
function emptyInputReader() {
|
|
43
40
|
return (async function* () {})()[Symbol.asyncIterator]();
|
|
44
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Bundles a `writeHead` callback with a Promise that resolves once the head
|
|
44
|
+
* is committed. Used by adapters (fetch, lambda) that need to observe the
|
|
45
|
+
* head commit from outside the `process()` call.
|
|
46
|
+
*/
|
|
47
|
+
function captureHead() {
|
|
48
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
49
|
+
return {
|
|
50
|
+
writeHead: (statusCode, headers) => {
|
|
51
|
+
resolve({
|
|
52
|
+
statusCode,
|
|
53
|
+
headers: { ...headers }
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
head: promise
|
|
57
|
+
};
|
|
58
|
+
}
|
|
45
59
|
|
|
46
60
|
//#endregion
|
|
61
|
+
exports.captureHead = captureHead;
|
|
47
62
|
exports.emptyInputReader = emptyInputReader;
|
|
48
63
|
exports.errorResponse = errorResponse;
|
|
49
64
|
exports.invocationIdFromHeaders = invocationIdFromHeaders;
|
|
@@ -8,4 +8,16 @@ export declare function invocationIdFromHeaders(headers: Headers): string;
|
|
|
8
8
|
export declare function errorResponse(code: number, message: string): RestateResponse;
|
|
9
9
|
export declare function simpleResponse(statusCode: number, headers: ResponseHeaders, body: Uint8Array): RestateResponse;
|
|
10
10
|
export declare function emptyInputReader(): InputReader;
|
|
11
|
+
/**
|
|
12
|
+
* Bundles a `writeHead` callback with a Promise that resolves once the head
|
|
13
|
+
* is committed. Used by adapters (fetch, lambda) that need to observe the
|
|
14
|
+
* head commit from outside the `process()` call.
|
|
15
|
+
*/
|
|
16
|
+
export declare function captureHead(): {
|
|
17
|
+
writeHead: (statusCode: number, headers: ResponseHeaders) => void;
|
|
18
|
+
head: Promise<{
|
|
19
|
+
statusCode: number;
|
|
20
|
+
headers: ResponseHeaders;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
11
23
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/endpoint/handlers/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EAChB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EACV,OAAO,EACP,WAAW,EACX,eAAe,EACf,eAAe,EAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAI/D,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,eAAe,EAChC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,EAChB,iBAAiB,CAAC,EAAE;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAC7C,MAAM,GAAG,SAAS,CAuBpB;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,UASvD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAS5E;AAED,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,UAAU,GACf,eAAe,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/endpoint/handlers/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EAChB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EACV,OAAO,EACP,WAAW,EACX,eAAe,EACf,eAAe,EAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAI/D,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,eAAe,EAChC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,EAChB,iBAAiB,CAAC,EAAE;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAC7C,MAAM,GAAG,SAAS,CAuBpB;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,UASvD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAS5E;AAED,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,UAAU,GACf,eAAe,CAgBjB;AAED,wBAAgB,gBAAgB,IAAI,WAAW,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,IAAI;IAC7B,SAAS,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClE,IAAI,EAAE,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;CACjE,CAWA"}
|
|
@@ -26,23 +26,37 @@ function errorResponse(code, message) {
|
|
|
26
26
|
}, new TextEncoder().encode(JSON.stringify({ message })));
|
|
27
27
|
}
|
|
28
28
|
function simpleResponse(statusCode, headers, body) {
|
|
29
|
-
return {
|
|
30
|
-
headers
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
const { done } = await inputReader.next();
|
|
35
|
-
if (done) break;
|
|
36
|
-
}
|
|
37
|
-
await outputWriter.write(body);
|
|
38
|
-
await outputWriter.close();
|
|
29
|
+
return { async process({ inputReader, outputWriter, writeHead }) {
|
|
30
|
+
writeHead(statusCode, headers);
|
|
31
|
+
while (true) {
|
|
32
|
+
const { done } = await inputReader.next();
|
|
33
|
+
if (done) break;
|
|
39
34
|
}
|
|
40
|
-
|
|
35
|
+
await outputWriter.write(body);
|
|
36
|
+
await outputWriter.close();
|
|
37
|
+
} };
|
|
41
38
|
}
|
|
42
39
|
function emptyInputReader() {
|
|
43
40
|
return (async function* () {})()[Symbol.asyncIterator]();
|
|
44
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Bundles a `writeHead` callback with a Promise that resolves once the head
|
|
44
|
+
* is committed. Used by adapters (fetch, lambda) that need to observe the
|
|
45
|
+
* head commit from outside the `process()` call.
|
|
46
|
+
*/
|
|
47
|
+
function captureHead() {
|
|
48
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
49
|
+
return {
|
|
50
|
+
writeHead: (statusCode, headers) => {
|
|
51
|
+
resolve({
|
|
52
|
+
statusCode,
|
|
53
|
+
headers: { ...headers }
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
head: promise
|
|
57
|
+
};
|
|
58
|
+
}
|
|
45
59
|
|
|
46
60
|
//#endregion
|
|
47
|
-
export { emptyInputReader, errorResponse, invocationIdFromHeaders, simpleResponse, tryCreateContextualLogger };
|
|
61
|
+
export { captureHead, emptyInputReader, errorResponse, invocationIdFromHeaders, simpleResponse, tryCreateContextualLogger };
|
|
48
62
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/endpoint/handlers/utils.ts"],"sourcesContent":["import {\n LoggerContext,\n LogSource,\n LoggerTransport,\n} from \"../../logging/logger_transport.js\";\nimport type {\n Headers,\n InputReader,\n ResponseHeaders,\n RestateResponse,\n} from \"./types.js\";\nimport { createLogger, Logger } from \"../../logging/logger.js\";\nimport { parseUrlComponents } from \"../components.js\";\nimport { X_RESTATE_SERVER } from \"../../user_agent.js\";\n\nexport function tryCreateContextualLogger(\n loggerTransport: LoggerTransport,\n url: string,\n headers: Headers,\n additionalContext?: { [name: string]: string }\n): Logger | undefined {\n try {\n const path = new URL(url, \"https://example.com\").pathname;\n const parsed = parseUrlComponents(path);\n if (parsed.type !== \"invoke\") {\n return undefined;\n }\n const invocationId = invocationIdFromHeaders(headers);\n return createLogger(\n loggerTransport,\n LogSource.SYSTEM,\n new LoggerContext(\n invocationId,\n parsed.componentName,\n parsed.handlerName,\n undefined,\n undefined,\n additionalContext\n )\n );\n } catch {\n return undefined;\n }\n}\n\nexport function invocationIdFromHeaders(headers: Headers) {\n const invocationIdHeader = headers[\"x-restate-invocation-id\"];\n const invocationId =\n typeof invocationIdHeader === \"string\"\n ? invocationIdHeader\n : Array.isArray(invocationIdHeader)\n ? (invocationIdHeader[0] ?? \"unknown id\")\n : \"unknown id\";\n return invocationId;\n}\n\nexport function errorResponse(code: number, message: string): RestateResponse {\n return simpleResponse(\n code,\n {\n \"content-type\": \"application/json\",\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n new TextEncoder().encode(JSON.stringify({ message }))\n );\n}\n\nexport function simpleResponse(\n statusCode: number,\n headers: ResponseHeaders,\n body: Uint8Array\n): RestateResponse {\n return {\n
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/endpoint/handlers/utils.ts"],"sourcesContent":["import {\n LoggerContext,\n LogSource,\n LoggerTransport,\n} from \"../../logging/logger_transport.js\";\nimport type {\n Headers,\n InputReader,\n ResponseHeaders,\n RestateResponse,\n} from \"./types.js\";\nimport { createLogger, Logger } from \"../../logging/logger.js\";\nimport { parseUrlComponents } from \"../components.js\";\nimport { X_RESTATE_SERVER } from \"../../user_agent.js\";\n\nexport function tryCreateContextualLogger(\n loggerTransport: LoggerTransport,\n url: string,\n headers: Headers,\n additionalContext?: { [name: string]: string }\n): Logger | undefined {\n try {\n const path = new URL(url, \"https://example.com\").pathname;\n const parsed = parseUrlComponents(path);\n if (parsed.type !== \"invoke\") {\n return undefined;\n }\n const invocationId = invocationIdFromHeaders(headers);\n return createLogger(\n loggerTransport,\n LogSource.SYSTEM,\n new LoggerContext(\n invocationId,\n parsed.componentName,\n parsed.handlerName,\n undefined,\n undefined,\n additionalContext\n )\n );\n } catch {\n return undefined;\n }\n}\n\nexport function invocationIdFromHeaders(headers: Headers) {\n const invocationIdHeader = headers[\"x-restate-invocation-id\"];\n const invocationId =\n typeof invocationIdHeader === \"string\"\n ? invocationIdHeader\n : Array.isArray(invocationIdHeader)\n ? (invocationIdHeader[0] ?? \"unknown id\")\n : \"unknown id\";\n return invocationId;\n}\n\nexport function errorResponse(code: number, message: string): RestateResponse {\n return simpleResponse(\n code,\n {\n \"content-type\": \"application/json\",\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n new TextEncoder().encode(JSON.stringify({ message }))\n );\n}\n\nexport function simpleResponse(\n statusCode: number,\n headers: ResponseHeaders,\n body: Uint8Array\n): RestateResponse {\n return {\n async process({ inputReader, outputWriter, writeHead }): Promise<void> {\n writeHead(statusCode, headers);\n\n // Drain the input stream\n while (true) {\n const { done } = await inputReader.next();\n if (done) break;\n }\n\n await outputWriter.write(body);\n // This closes both the writer and the stream!!!\n await outputWriter.close();\n },\n };\n}\n\nexport function emptyInputReader(): InputReader {\n return (async function* () {})()[Symbol.asyncIterator]();\n}\n\n/**\n * Bundles a `writeHead` callback with a Promise that resolves once the head\n * is committed. Used by adapters (fetch, lambda) that need to observe the\n * head commit from outside the `process()` call.\n */\nexport function captureHead(): {\n writeHead: (statusCode: number, headers: ResponseHeaders) => void;\n head: Promise<{ statusCode: number; headers: ResponseHeaders }>;\n} {\n const { promise, resolve } = Promise.withResolvers<{\n statusCode: number;\n headers: ResponseHeaders;\n }>();\n return {\n writeHead: (statusCode, headers) => {\n resolve({ statusCode, headers: { ...headers } });\n },\n head: promise,\n };\n}\n"],"mappings":";;;;;;AAeA,SAAgB,0BACd,iBACA,KACA,SACA,mBACoB;AACpB,KAAI;EACF,MAAM,OAAO,IAAI,IAAI,KAAK,sBAAsB,CAAC;EACjD,MAAM,SAAS,mBAAmB,KAAK;AACvC,MAAI,OAAO,SAAS,SAClB;EAEF,MAAM,eAAe,wBAAwB,QAAQ;AACrD,SAAO,aACL,iBACA,UAAU,QACV,IAAI,cACF,cACA,OAAO,eACP,OAAO,aACP,QACA,QACA,kBACD,CACF;SACK;AACN;;;AAIJ,SAAgB,wBAAwB,SAAkB;CACxD,MAAM,qBAAqB,QAAQ;AAOnC,QALE,OAAO,uBAAuB,WAC1B,qBACA,MAAM,QAAQ,mBAAmB,GAC9B,mBAAmB,MAAM,eAC1B;;AAIV,SAAgB,cAAc,MAAc,SAAkC;AAC5E,QAAO,eACL,MACA;EACE,gBAAgB;EAChB,oBAAoB;EACrB,EACD,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,EAAE,SAAS,CAAC,CAAC,CACtD;;AAGH,SAAgB,eACd,YACA,SACA,MACiB;AACjB,QAAO,EACL,MAAM,QAAQ,EAAE,aAAa,cAAc,aAA4B;AACrE,YAAU,YAAY,QAAQ;AAG9B,SAAO,MAAM;GACX,MAAM,EAAE,SAAS,MAAM,YAAY,MAAM;AACzC,OAAI,KAAM;;AAGZ,QAAM,aAAa,MAAM,KAAK;AAE9B,QAAM,aAAa,OAAO;IAE7B;;AAGH,SAAgB,mBAAgC;AAC9C,SAAQ,mBAAmB,KAAK,CAAC,OAAO,gBAAgB;;;;;;;AAQ1D,SAAgB,cAGd;CACA,MAAM,EAAE,SAAS,YAAY,QAAQ,eAGjC;AACJ,QAAO;EACL,YAAY,YAAY,YAAY;AAClC,WAAQ;IAAE;IAAY,SAAS,EAAE,GAAG,SAAS;IAAE,CAAC;;EAElD,MAAM;EACP"}
|
|
@@ -74,19 +74,22 @@ function nodeHandlerImpl(endpoint, protocolMode) {
|
|
|
74
74
|
const handler = require_generic.createRestateHandler(endpoint, protocolMode, {});
|
|
75
75
|
return (httpRequest, httpResponse) => {
|
|
76
76
|
const url = httpRequest.url;
|
|
77
|
+
const inputReader = inputReaderAdapter(httpRequest);
|
|
78
|
+
const outputWriter = outputWriterAdapter(httpResponse);
|
|
79
|
+
const res = httpResponse;
|
|
77
80
|
const abortController = new AbortController();
|
|
78
81
|
httpRequest.on("close", () => {
|
|
79
82
|
abortController.abort();
|
|
80
83
|
});
|
|
81
|
-
const
|
|
84
|
+
const writeHead = res.writeHead.bind(res);
|
|
85
|
+
handler.handle({
|
|
82
86
|
url,
|
|
83
87
|
headers: httpRequest.headers,
|
|
84
88
|
extraArgs: []
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
outputWriter: outputWriterAdapter(httpResponse),
|
|
89
|
+
}).process({
|
|
90
|
+
inputReader,
|
|
91
|
+
outputWriter,
|
|
92
|
+
writeHead,
|
|
90
93
|
abortSignal: abortController.signal
|
|
91
94
|
}).catch((e) => {
|
|
92
95
|
const error = require_errors.ensureError(e);
|
|
@@ -72,19 +72,22 @@ function nodeHandlerImpl(endpoint, protocolMode) {
|
|
|
72
72
|
const handler = createRestateHandler(endpoint, protocolMode, {});
|
|
73
73
|
return (httpRequest, httpResponse) => {
|
|
74
74
|
const url = httpRequest.url;
|
|
75
|
+
const inputReader = inputReaderAdapter(httpRequest);
|
|
76
|
+
const outputWriter = outputWriterAdapter(httpResponse);
|
|
77
|
+
const res = httpResponse;
|
|
75
78
|
const abortController = new AbortController();
|
|
76
79
|
httpRequest.on("close", () => {
|
|
77
80
|
abortController.abort();
|
|
78
81
|
});
|
|
79
|
-
const
|
|
82
|
+
const writeHead = res.writeHead.bind(res);
|
|
83
|
+
handler.handle({
|
|
80
84
|
url,
|
|
81
85
|
headers: httpRequest.headers,
|
|
82
86
|
extraArgs: []
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
outputWriter: outputWriterAdapter(httpResponse),
|
|
87
|
+
}).process({
|
|
88
|
+
inputReader,
|
|
89
|
+
outputWriter,
|
|
90
|
+
writeHead,
|
|
88
91
|
abortSignal: abortController.signal
|
|
89
92
|
}).catch((e) => {
|
|
90
93
|
const error = ensureError(e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node_endpoint.js","names":[],"sources":["../../src/endpoint/node_endpoint.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 type { RestateEndpoint } from \"../index.js\";\nimport type {\n JournalValueCodec,\n ServiceDefinition,\n VirtualObjectDefinition,\n WorkflowDefinition,\n} from \"@restatedev/restate-sdk-core\";\nimport { IncomingMessage, ServerResponse } from \"node:http\";\nimport { Http2ServerRequest, Http2ServerResponse } from \"node:http2\";\nimport * as http2 from \"node:http2\";\nimport type { Endpoint } from \"./endpoint.js\";\nimport { EndpointBuilder } from \"./endpoint.js\";\nimport { createRestateHandler } from \"./handlers/generic.js\";\nimport { ensureError } from \"../types/errors.js\";\nimport type { LoggerTransport } from \"../logging/logger_transport.js\";\nimport type { DefaultServiceOptions } from \"../endpoint.js\";\nimport { tryCreateContextualLogger } from \"./handlers/utils.js\";\nimport type { InputReader, OutputWriter } from \"./handlers/types.js\";\nimport type { ProtocolMode } from \"./discovery.js\";\n\nexport class NodeEndpoint implements RestateEndpoint {\n private builder: EndpointBuilder = new EndpointBuilder();\n\n public bind<P extends string, M>(\n definition:\n | ServiceDefinition<P, M>\n | VirtualObjectDefinition<P, M>\n | WorkflowDefinition<P, M>\n ): RestateEndpoint {\n this.builder.bind(definition);\n return this;\n }\n\n public withIdentityV1(...keys: string[]): RestateEndpoint {\n this.builder.addIdentityKeys(...keys);\n return this;\n }\n\n public defaultServiceOptions(\n options: DefaultServiceOptions\n ): RestateEndpoint {\n this.builder.setDefaultServiceOptions(options);\n return this;\n }\n\n public setLogger(logger: LoggerTransport): RestateEndpoint {\n this.builder.setLogger(logger);\n return this;\n }\n\n public journalValueCodecProvider(\n codecProvider: () => Promise<JournalValueCodec>\n ): RestateEndpoint {\n this.builder.setJournalValueCodecProvider(codecProvider);\n return this;\n }\n\n http2Handler(options?: {\n bidirectional?: boolean;\n }): (request: Http2ServerRequest, response: Http2ServerResponse) => void {\n return nodeHttp2Handler(\n this.builder.build(),\n options?.bidirectional === false ? \"REQUEST_RESPONSE\" : \"BIDI_STREAM\"\n );\n }\n\n http1Handler(options?: {\n bidirectional?: boolean;\n }): (request: IncomingMessage, response: ServerResponse) => void {\n return nodeHttp1Handler(\n this.builder.build(),\n options?.bidirectional ? \"BIDI_STREAM\" : \"REQUEST_RESPONSE\"\n );\n }\n\n handler(options?: { bidirectional?: boolean }): {\n (request: IncomingMessage, response: ServerResponse): void;\n (request: Http2ServerRequest, response: Http2ServerResponse): void;\n } {\n const endpoint = this.builder.build();\n const h2Handler = nodeHttp2Handler(\n endpoint,\n options?.bidirectional === false ? \"REQUEST_RESPONSE\" : \"BIDI_STREAM\"\n );\n const h1Handler = nodeHttp1Handler(\n endpoint,\n options?.bidirectional ? \"BIDI_STREAM\" : \"REQUEST_RESPONSE\"\n );\n\n return ((\n request: IncomingMessage | Http2ServerRequest,\n response: ServerResponse | Http2ServerResponse\n ) => {\n if (request.httpVersionMajor >= 2) {\n h2Handler(\n request as Http2ServerRequest,\n response as Http2ServerResponse\n );\n } else {\n h1Handler(request as IncomingMessage, response as ServerResponse);\n }\n }) as {\n (request: IncomingMessage, response: ServerResponse): void;\n (request: Http2ServerRequest, response: Http2ServerResponse): void;\n };\n }\n\n listen(port?: number): Promise<number> {\n const endpoint = this.builder.build();\n\n const actualPort = port ?? parseInt(process.env.PORT ?? \"9080\");\n endpoint.rlog.info(`Restate SDK started listening on ${actualPort}...`);\n\n const server = http2.createServer(\n nodeHttp2Handler(endpoint, \"BIDI_STREAM\")\n );\n\n return new Promise((resolve, reject) => {\n let failed = false;\n server.once(\"error\", (e: Error) => {\n failed = true;\n reject(e);\n });\n server.listen(actualPort, () => {\n if (failed) {\n return;\n }\n const address = server.address();\n if (address === null || typeof address === \"string\") {\n reject(\n new TypeError(\n \"endpoint.listen() currently supports only binding to a PORT\"\n )\n );\n } else {\n resolve(address.port);\n }\n });\n });\n }\n}\n\nfunction nodeHttp1Handler(\n endpoint: Endpoint,\n protocolMode: ProtocolMode\n): (request: IncomingMessage, response: ServerResponse) => void {\n return nodeHandlerImpl(endpoint, protocolMode);\n}\n\nfunction nodeHttp2Handler(\n endpoint: Endpoint,\n protocolMode: ProtocolMode\n): (request: Http2ServerRequest, response: Http2ServerResponse) => void {\n return nodeHandlerImpl(endpoint, protocolMode);\n}\n\nfunction nodeHandlerImpl(\n endpoint: Endpoint,\n protocolMode: ProtocolMode\n): (\n request: Http2ServerRequest | IncomingMessage,\n response: Http2ServerResponse | ServerResponse\n) => void {\n const handler = createRestateHandler(endpoint, protocolMode, {});\n\n return (httpRequest, httpResponse) => {\n const url = httpRequest.url!;\n\n // Abort controller used to cleanup resources at the end of this stream lifecycle\n const abortController = new AbortController();\n httpRequest.on(\"close\", () => {\n abortController.abort();\n });\n\n const restateResponse = handler.handle({\n url,\n headers: httpRequest.headers,\n extraArgs: [],\n });\n const res = httpResponse as NodeWritableResponse;\n res.writeHead(restateResponse.statusCode, restateResponse.headers);\n\n restateResponse\n .process({\n inputReader: inputReaderAdapter(httpRequest),\n outputWriter: outputWriterAdapter(httpResponse),\n abortSignal: abortController.signal,\n })\n .catch((e) => {\n // handle should never throw\n const error = ensureError(e);\n const logger =\n tryCreateContextualLogger(\n endpoint.loggerTransport,\n url,\n httpRequest.headers\n ) ?? endpoint.rlog;\n logger.error(\"Unexpected error: \" + (error.stack ?? error.message));\n });\n };\n}\n\n// Both ServerResponse and Http2ServerResponse satisfy this interface.\n// We use it to avoid TS union overload incompatibilities.\ninterface NodeWritableResponse {\n writeHead(statusCode: number, headers: Record<string, string>): void;\n write(chunk: Uint8Array, callback: (err?: Error | null) => void): boolean;\n end(callback: () => void): void;\n}\n\nfunction inputReaderAdapter(\n request: Http2ServerRequest | IncomingMessage\n): InputReader {\n return (request as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]();\n}\n\nfunction outputWriterAdapter(\n response: Http2ServerResponse | ServerResponse\n): OutputWriter {\n const res = response as NodeWritableResponse;\n return {\n write: function (value: Uint8Array): Promise<void> {\n return new Promise((resolve, reject) => {\n res.write(value, (err) => (err ? reject(err) : resolve()));\n });\n },\n close: function (): Promise<void> {\n return new Promise((resolve) => {\n res.end(() => resolve());\n });\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"node_endpoint.js","names":[],"sources":["../../src/endpoint/node_endpoint.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 type { RestateEndpoint } from \"../index.js\";\nimport type {\n JournalValueCodec,\n ServiceDefinition,\n VirtualObjectDefinition,\n WorkflowDefinition,\n} from \"@restatedev/restate-sdk-core\";\nimport { IncomingMessage, ServerResponse } from \"node:http\";\nimport { Http2ServerRequest, Http2ServerResponse } from \"node:http2\";\nimport * as http2 from \"node:http2\";\nimport type { Endpoint } from \"./endpoint.js\";\nimport { EndpointBuilder } from \"./endpoint.js\";\nimport { createRestateHandler } from \"./handlers/generic.js\";\nimport { ensureError } from \"../types/errors.js\";\nimport type { LoggerTransport } from \"../logging/logger_transport.js\";\nimport type { DefaultServiceOptions } from \"../endpoint.js\";\nimport { tryCreateContextualLogger } from \"./handlers/utils.js\";\nimport type { InputReader, OutputWriter } from \"./handlers/types.js\";\nimport type { ProtocolMode } from \"./discovery.js\";\n\nexport class NodeEndpoint implements RestateEndpoint {\n private builder: EndpointBuilder = new EndpointBuilder();\n\n public bind<P extends string, M>(\n definition:\n | ServiceDefinition<P, M>\n | VirtualObjectDefinition<P, M>\n | WorkflowDefinition<P, M>\n ): RestateEndpoint {\n this.builder.bind(definition);\n return this;\n }\n\n public withIdentityV1(...keys: string[]): RestateEndpoint {\n this.builder.addIdentityKeys(...keys);\n return this;\n }\n\n public defaultServiceOptions(\n options: DefaultServiceOptions\n ): RestateEndpoint {\n this.builder.setDefaultServiceOptions(options);\n return this;\n }\n\n public setLogger(logger: LoggerTransport): RestateEndpoint {\n this.builder.setLogger(logger);\n return this;\n }\n\n public journalValueCodecProvider(\n codecProvider: () => Promise<JournalValueCodec>\n ): RestateEndpoint {\n this.builder.setJournalValueCodecProvider(codecProvider);\n return this;\n }\n\n http2Handler(options?: {\n bidirectional?: boolean;\n }): (request: Http2ServerRequest, response: Http2ServerResponse) => void {\n return nodeHttp2Handler(\n this.builder.build(),\n options?.bidirectional === false ? \"REQUEST_RESPONSE\" : \"BIDI_STREAM\"\n );\n }\n\n http1Handler(options?: {\n bidirectional?: boolean;\n }): (request: IncomingMessage, response: ServerResponse) => void {\n return nodeHttp1Handler(\n this.builder.build(),\n options?.bidirectional ? \"BIDI_STREAM\" : \"REQUEST_RESPONSE\"\n );\n }\n\n handler(options?: { bidirectional?: boolean }): {\n (request: IncomingMessage, response: ServerResponse): void;\n (request: Http2ServerRequest, response: Http2ServerResponse): void;\n } {\n const endpoint = this.builder.build();\n const h2Handler = nodeHttp2Handler(\n endpoint,\n options?.bidirectional === false ? \"REQUEST_RESPONSE\" : \"BIDI_STREAM\"\n );\n const h1Handler = nodeHttp1Handler(\n endpoint,\n options?.bidirectional ? \"BIDI_STREAM\" : \"REQUEST_RESPONSE\"\n );\n\n return ((\n request: IncomingMessage | Http2ServerRequest,\n response: ServerResponse | Http2ServerResponse\n ) => {\n if (request.httpVersionMajor >= 2) {\n h2Handler(\n request as Http2ServerRequest,\n response as Http2ServerResponse\n );\n } else {\n h1Handler(request as IncomingMessage, response as ServerResponse);\n }\n }) as {\n (request: IncomingMessage, response: ServerResponse): void;\n (request: Http2ServerRequest, response: Http2ServerResponse): void;\n };\n }\n\n listen(port?: number): Promise<number> {\n const endpoint = this.builder.build();\n\n const actualPort = port ?? parseInt(process.env.PORT ?? \"9080\");\n endpoint.rlog.info(`Restate SDK started listening on ${actualPort}...`);\n\n const server = http2.createServer(\n nodeHttp2Handler(endpoint, \"BIDI_STREAM\")\n );\n\n return new Promise((resolve, reject) => {\n let failed = false;\n server.once(\"error\", (e: Error) => {\n failed = true;\n reject(e);\n });\n server.listen(actualPort, () => {\n if (failed) {\n return;\n }\n const address = server.address();\n if (address === null || typeof address === \"string\") {\n reject(\n new TypeError(\n \"endpoint.listen() currently supports only binding to a PORT\"\n )\n );\n } else {\n resolve(address.port);\n }\n });\n });\n }\n}\n\nfunction nodeHttp1Handler(\n endpoint: Endpoint,\n protocolMode: ProtocolMode\n): (request: IncomingMessage, response: ServerResponse) => void {\n return nodeHandlerImpl(endpoint, protocolMode);\n}\n\nfunction nodeHttp2Handler(\n endpoint: Endpoint,\n protocolMode: ProtocolMode\n): (request: Http2ServerRequest, response: Http2ServerResponse) => void {\n return nodeHandlerImpl(endpoint, protocolMode);\n}\n\nfunction nodeHandlerImpl(\n endpoint: Endpoint,\n protocolMode: ProtocolMode\n): (\n request: Http2ServerRequest | IncomingMessage,\n response: Http2ServerResponse | ServerResponse\n) => void {\n const handler = createRestateHandler(endpoint, protocolMode, {});\n\n return (httpRequest, httpResponse) => {\n const url = httpRequest.url!;\n const inputReader = inputReaderAdapter(httpRequest);\n const outputWriter = outputWriterAdapter(httpResponse);\n const res = httpResponse as NodeWritableResponse;\n\n // Abort controller used to cleanup resources at the end of this stream lifecycle\n const abortController = new AbortController();\n httpRequest.on(\"close\", () => {\n abortController.abort();\n });\n\n const writeHead = res.writeHead.bind(res);\n\n // handle should never throw\n const restateResponse = handler.handle({\n url,\n headers: httpRequest.headers,\n extraArgs: [],\n });\n\n restateResponse\n .process({\n inputReader,\n outputWriter,\n writeHead,\n abortSignal: abortController.signal,\n })\n .catch((e) => {\n // Responses handle their own errors before rejecting; anything\n // reaching here is an unexpected failure — just log.\n const error = ensureError(e);\n const logger =\n tryCreateContextualLogger(\n endpoint.loggerTransport,\n url,\n httpRequest.headers\n ) ?? endpoint.rlog;\n logger.error(\"Unexpected error: \" + (error.stack ?? error.message));\n });\n };\n}\n\n// Both ServerResponse and Http2ServerResponse satisfy this interface.\n// We use it to avoid TS union overload incompatibilities.\ninterface NodeWritableResponse {\n writeHead(statusCode: number, headers: Record<string, string>): void;\n write(chunk: Uint8Array, callback: (err?: Error | null) => void): boolean;\n end(callback: () => void): void;\n}\n\nfunction inputReaderAdapter(\n request: Http2ServerRequest | IncomingMessage\n): InputReader {\n return (request as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]();\n}\n\nfunction outputWriterAdapter(\n response: Http2ServerResponse | ServerResponse\n): OutputWriter {\n const res = response as NodeWritableResponse;\n return {\n write: function (value: Uint8Array): Promise<void> {\n return new Promise((resolve, reject) => {\n res.write(value, (err) => (err ? reject(err) : resolve()));\n });\n },\n close: function (): Promise<void> {\n return new Promise((resolve) => {\n res.end(() => resolve());\n });\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/io.cjs
CHANGED
|
@@ -6,10 +6,12 @@ const require_promises = require('./promises.cjs');
|
|
|
6
6
|
*/
|
|
7
7
|
var InputPump = class {
|
|
8
8
|
currentRead;
|
|
9
|
+
closed;
|
|
9
10
|
constructor(coreVm, inputReader, errorCallback) {
|
|
10
11
|
this.coreVm = coreVm;
|
|
11
12
|
this.inputReader = inputReader;
|
|
12
13
|
this.errorCallback = errorCallback;
|
|
14
|
+
this.closed = false;
|
|
13
15
|
}
|
|
14
16
|
awaitNextProgress() {
|
|
15
17
|
if (this.currentRead === void 0) this.currentRead = this.readNext().finally(() => {
|
|
@@ -18,6 +20,7 @@ var InputPump = class {
|
|
|
18
20
|
return new Promise((resolve) => this.currentRead?.finally(resolve));
|
|
19
21
|
}
|
|
20
22
|
async readNext() {
|
|
23
|
+
if (this.closed) return require_promises.pendingPromise();
|
|
21
24
|
let nextValue;
|
|
22
25
|
try {
|
|
23
26
|
nextValue = await this.inputReader.next();
|
|
@@ -25,8 +28,10 @@ var InputPump = class {
|
|
|
25
28
|
this.errorCallback(e);
|
|
26
29
|
return require_promises.pendingPromise();
|
|
27
30
|
}
|
|
28
|
-
if (nextValue.done)
|
|
29
|
-
|
|
31
|
+
if (nextValue.done) {
|
|
32
|
+
this.closed = true;
|
|
33
|
+
this.coreVm.notify_input_closed();
|
|
34
|
+
} else if (nextValue.value !== void 0) this.coreVm.notify_input(nextValue.value);
|
|
30
35
|
}
|
|
31
36
|
};
|
|
32
37
|
/**
|
package/dist/io.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,KAAK,EAAE,MAAM,yDAAyD,CAAC;AAEnF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEzE;;GAEG;AACH,qBAAa,SAAS;
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,KAAK,EAAE,MAAM,yDAAyD,CAAC;AAEnF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEzE;;GAEG;AACH,qBAAa,SAAS;IAKlB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,aAAa;IANhC,OAAO,CAAC,WAAW,CAAC,CAAgB;IACpC,OAAO,CAAC,MAAM,CAAU;gBAGL,MAAM,EAAE,EAAE,CAAC,MAAM,EACjB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI;IAQlD,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;YAYpB,QAAQ;CAmBvB;AAED;;GAEG;AACH,qBAAa,UAAU;IAEnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,MAAM,EAAE,EAAE,CAAC,MAAM,EACjB,YAAY,EAAE,YAAY;IAGvC,iBAAiB;CASxB"}
|
package/dist/io.js
CHANGED
|
@@ -6,10 +6,12 @@ import { pendingPromise } from "./promises.js";
|
|
|
6
6
|
*/
|
|
7
7
|
var InputPump = class {
|
|
8
8
|
currentRead;
|
|
9
|
+
closed;
|
|
9
10
|
constructor(coreVm, inputReader, errorCallback) {
|
|
10
11
|
this.coreVm = coreVm;
|
|
11
12
|
this.inputReader = inputReader;
|
|
12
13
|
this.errorCallback = errorCallback;
|
|
14
|
+
this.closed = false;
|
|
13
15
|
}
|
|
14
16
|
awaitNextProgress() {
|
|
15
17
|
if (this.currentRead === void 0) this.currentRead = this.readNext().finally(() => {
|
|
@@ -18,6 +20,7 @@ var InputPump = class {
|
|
|
18
20
|
return new Promise((resolve) => this.currentRead?.finally(resolve));
|
|
19
21
|
}
|
|
20
22
|
async readNext() {
|
|
23
|
+
if (this.closed) return pendingPromise();
|
|
21
24
|
let nextValue;
|
|
22
25
|
try {
|
|
23
26
|
nextValue = await this.inputReader.next();
|
|
@@ -25,8 +28,10 @@ var InputPump = class {
|
|
|
25
28
|
this.errorCallback(e);
|
|
26
29
|
return pendingPromise();
|
|
27
30
|
}
|
|
28
|
-
if (nextValue.done)
|
|
29
|
-
|
|
31
|
+
if (nextValue.done) {
|
|
32
|
+
this.closed = true;
|
|
33
|
+
this.coreVm.notify_input_closed();
|
|
34
|
+
} else if (nextValue.value !== void 0) this.coreVm.notify_input(nextValue.value);
|
|
30
35
|
}
|
|
31
36
|
};
|
|
32
37
|
/**
|
package/dist/io.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io.js","names":["coreVm: vm.WasmVM","inputReader: InputReader","errorCallback: (e: any) => void","outputWriter: OutputWriter"],"sources":["../src/io.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2025 - 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\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type * as vm from \"./endpoint/handlers/vm/sdk_shared_core_wasm_bindings.js\";\nimport { pendingPromise } from \"./promises.js\";\nimport { InputReader, OutputWriter } from \"./endpoint/handlers/types.js\";\n\n/**\n * Adapter between input stream and vm. It moves forward when [awaitNextProgress] is invoked.\n */\nexport class InputPump {\n private currentRead?: Promise<void>;\n\n constructor(\n private readonly coreVm: vm.WasmVM,\n private readonly inputReader: InputReader,\n private readonly errorCallback: (e: any) => void\n ) {}\n\n // This function triggers a read on the input reader,\n // and will notify the caller that a read was executed\n // and the result was piped in the state machine.\n awaitNextProgress(): Promise<void> {\n if (this.currentRead === undefined) {\n // Register a new read\n this.currentRead = this.readNext().finally(() => {\n this.currentRead = undefined;\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n return new Promise<void>((resolve) => this.currentRead?.finally(resolve));\n }\n\n private async readNext(): Promise<void> {\n // Take input, and notify it to the vm\n let nextValue;\n try {\n nextValue = await this.inputReader.next();\n } catch (e) {\n this.errorCallback(e);\n return pendingPromise<void>();\n }\n if (nextValue.done) {\n this.coreVm.notify_input_closed();\n } else if (nextValue.value !== undefined) {\n this.coreVm.notify_input(nextValue.value);\n }\n }\n}\n\n/**\n * Adapter between output stream and vm. It moves forward when [awaitNextProgress] is invoked.\n */\nexport class OutputPump {\n constructor(\n private readonly coreVm: vm.WasmVM,\n private readonly outputWriter: OutputWriter\n ) {}\n\n async awaitNextProgress() {\n const nextOutput = this.coreVm.take_output() as\n | Uint8Array\n | null\n | undefined;\n if (nextOutput instanceof Uint8Array) {\n await this.outputWriter.write(nextOutput);\n }\n }\n}\n"],"mappings":";;;;;;AAoBA,IAAa,YAAb,MAAuB;CACrB,AAAQ;CAER,YACE,AAAiBA,QACjB,AAAiBC,aACjB,AAAiBC,eACjB;EAHiB;EACA;EACA;;
|
|
1
|
+
{"version":3,"file":"io.js","names":["coreVm: vm.WasmVM","inputReader: InputReader","errorCallback: (e: any) => void","outputWriter: OutputWriter"],"sources":["../src/io.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2025 - 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\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type * as vm from \"./endpoint/handlers/vm/sdk_shared_core_wasm_bindings.js\";\nimport { pendingPromise } from \"./promises.js\";\nimport { InputReader, OutputWriter } from \"./endpoint/handlers/types.js\";\n\n/**\n * Adapter between input stream and vm. It moves forward when [awaitNextProgress] is invoked.\n */\nexport class InputPump {\n private currentRead?: Promise<void>;\n private closed: boolean;\n\n constructor(\n private readonly coreVm: vm.WasmVM,\n private readonly inputReader: InputReader,\n private readonly errorCallback: (e: any) => void\n ) {\n this.closed = false;\n }\n\n // This function triggers a read on the input reader,\n // and will notify the caller that a read was executed\n // and the result was piped in the state machine.\n awaitNextProgress(): Promise<void> {\n if (this.currentRead === undefined) {\n // Register a new read\n this.currentRead = this.readNext().finally(() => {\n this.currentRead = undefined;\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n return new Promise<void>((resolve) => this.currentRead?.finally(resolve));\n }\n\n private async readNext(): Promise<void> {\n if (this.closed) {\n return pendingPromise<void>();\n }\n // Take input, and notify it to the vm\n let nextValue;\n try {\n nextValue = await this.inputReader.next();\n } catch (e) {\n this.errorCallback(e);\n return pendingPromise<void>();\n }\n if (nextValue.done) {\n this.closed = true;\n this.coreVm.notify_input_closed();\n } else if (nextValue.value !== undefined) {\n this.coreVm.notify_input(nextValue.value);\n }\n }\n}\n\n/**\n * Adapter between output stream and vm. It moves forward when [awaitNextProgress] is invoked.\n */\nexport class OutputPump {\n constructor(\n private readonly coreVm: vm.WasmVM,\n private readonly outputWriter: OutputWriter\n ) {}\n\n async awaitNextProgress() {\n const nextOutput = this.coreVm.take_output() as\n | Uint8Array\n | null\n | undefined;\n if (nextOutput instanceof Uint8Array) {\n await this.outputWriter.write(nextOutput);\n }\n }\n}\n"],"mappings":";;;;;;AAoBA,IAAa,YAAb,MAAuB;CACrB,AAAQ;CACR,AAAQ;CAER,YACE,AAAiBA,QACjB,AAAiBC,aACjB,AAAiBC,eACjB;EAHiB;EACA;EACA;AAEjB,OAAK,SAAS;;CAMhB,oBAAmC;AACjC,MAAI,KAAK,gBAAgB,OAEvB,MAAK,cAAc,KAAK,UAAU,CAAC,cAAc;AAC/C,QAAK,cAAc;IACnB;AAIJ,SAAO,IAAI,SAAe,YAAY,KAAK,aAAa,QAAQ,QAAQ,CAAC;;CAG3E,MAAc,WAA0B;AACtC,MAAI,KAAK,OACP,QAAO,gBAAsB;EAG/B,IAAI;AACJ,MAAI;AACF,eAAY,MAAM,KAAK,YAAY,MAAM;WAClC,GAAG;AACV,QAAK,cAAc,EAAE;AACrB,UAAO,gBAAsB;;AAE/B,MAAI,UAAU,MAAM;AAClB,QAAK,SAAS;AACd,QAAK,OAAO,qBAAqB;aACxB,UAAU,UAAU,OAC7B,MAAK,OAAO,aAAa,UAAU,MAAM;;;;;;AAQ/C,IAAa,aAAb,MAAwB;CACtB,YACE,AAAiBF,QACjB,AAAiBG,cACjB;EAFiB;EACA;;CAGnB,MAAM,oBAAoB;EACxB,MAAM,aAAa,KAAK,OAAO,aAAa;AAI5C,MAAI,sBAAsB,WACxB,OAAM,KAAK,aAAa,MAAM,WAAW"}
|
package/dist/package.cjs
CHANGED
package/dist/package.js
CHANGED
package/dist/package.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@restatedev/restate-sdk\",\n \"version\": \"1.
|
|
1
|
+
{"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@restatedev/restate-sdk\",\n \"version\": \"1.14.0\",\n \"description\": \"Typescript SDK for Restate\",\n \"author\": \"Restate Developers\",\n \"email\": \"code@restate.dev\",\n \"license\": \"MIT\",\n \"homepage\": \"https://github.com/restatedev/sdk-typescript#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/restatedev/sdk-typescript.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/restatedev/sdk-typescript/issues\"\n },\n \"type\": \"module\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.cts\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./fetch\": {\n \"import\": \"./dist/fetch.js\",\n \"require\": \"./dist/fetch.cjs\"\n },\n \"./lambda\": {\n \"import\": \"./dist/lambda.js\",\n \"require\": \"./dist/lambda.cjs\"\n },\n \"./node\": {\n \"import\": \"./dist/node.js\",\n \"require\": \"./dist/node.cjs\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"test\": \"turbo run _test --filter={.}...\",\n \"_test\": \"vitest run\",\n \"build\": \"turbo run _build --filter={.}...\",\n \"_build\": \"tsc --noEmit && tsdown\",\n \"dev\": \"tsc --noEmit --watch\",\n \"clean\": \"rm -rf dist *.tsbuildinfo .turbo\",\n \"check:types\": \"turbo run _check:types --filter={.}...\",\n \"_check:types\": \"tsc --noEmit --project tsconfig.build.json\",\n \"lint\": \"eslint .\",\n \"check:exports\": \"turbo run _check:exports --filter={.}...\",\n \"_check:exports\": \"attw --pack .\",\n \"check:api\": \"turbo run _check:api --filter={.}...\",\n \"_check:api\": \"api-extractor run --local && api-extractor run --local --config api-extractor.fetch.json && api-extractor run --local --config api-extractor.lambda.json && api-extractor run --local --config api-extractor.node.json\",\n \"prepublishOnly\": \"pnpm -w verify\"\n },\n \"dependencies\": {\n \"@restatedev/restate-sdk-core\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@types/aws-lambda\": \"^8.10.115\"\n },\n \"typesVersions\": {\n \"*\": {\n \"fetch\": [\n \"./dist/fetch.d.ts\"\n ],\n \"lambda\": [\n \"./dist/lambda.d.ts\"\n ],\n \"node\": [\n \"./dist/node.d.ts\"\n ]\n }\n }\n}\n"],"mappings":";cAEa"}
|
package/dist/promises.cjs
CHANGED
|
@@ -140,6 +140,7 @@ var CombinatorRestatePromise = class CombinatorRestatePromise extends BaseRestat
|
|
|
140
140
|
};
|
|
141
141
|
var MappedRestatePromise = class extends BaseRestatePromise {
|
|
142
142
|
publicPromiseMapper;
|
|
143
|
+
_mappedPromise;
|
|
143
144
|
constructor(ctx, inner, mapper) {
|
|
144
145
|
super(ctx);
|
|
145
146
|
this.inner = inner;
|
|
@@ -162,6 +163,9 @@ var MappedRestatePromise = class extends BaseRestatePromise {
|
|
|
162
163
|
return this.inner.uncompletedLeaves();
|
|
163
164
|
}
|
|
164
165
|
publicPromise() {
|
|
166
|
+
return this._mappedPromise ??= this.buildMappedPromise();
|
|
167
|
+
}
|
|
168
|
+
buildMappedPromise() {
|
|
165
169
|
const promiseMapper = this.publicPromiseMapper;
|
|
166
170
|
return this.inner.publicPromise().then((t) => promiseMapper(t, void 0), (error) => {
|
|
167
171
|
if (error instanceof require_errors.RestateError) return promiseMapper(void 0, error);
|
|
@@ -171,22 +175,26 @@ var MappedRestatePromise = class extends BaseRestatePromise {
|
|
|
171
175
|
[Symbol.toStringTag] = "RestateMappedPromise";
|
|
172
176
|
};
|
|
173
177
|
var ConstRestatePromise = class ConstRestatePromise extends InternalRestatePromise {
|
|
174
|
-
|
|
178
|
+
_constPromise;
|
|
179
|
+
constructor(promiseFactory, settled) {
|
|
175
180
|
super();
|
|
176
|
-
this.
|
|
181
|
+
this.promiseFactory = promiseFactory;
|
|
177
182
|
this.settled = settled;
|
|
178
183
|
}
|
|
184
|
+
get constPromise() {
|
|
185
|
+
return this._constPromise ??= this.promiseFactory();
|
|
186
|
+
}
|
|
179
187
|
static resolve(value) {
|
|
180
|
-
return new ConstRestatePromise(Promise.resolve(value), true);
|
|
188
|
+
return new ConstRestatePromise(() => Promise.resolve(value), true);
|
|
181
189
|
}
|
|
182
190
|
static reject(reason) {
|
|
183
|
-
return new ConstRestatePromise(Promise.reject(reason), true);
|
|
191
|
+
return new ConstRestatePromise(() => Promise.reject(reason), true);
|
|
184
192
|
}
|
|
185
193
|
static pending() {
|
|
186
|
-
return new ConstRestatePromise(pendingPromise(), false);
|
|
194
|
+
return new ConstRestatePromise(() => pendingPromise(), false);
|
|
187
195
|
}
|
|
188
196
|
static fromPromise(promise, settled) {
|
|
189
|
-
return new ConstRestatePromise(promise, settled);
|
|
197
|
+
return new ConstRestatePromise(() => promise, settled);
|
|
190
198
|
}
|
|
191
199
|
then(onfulfilled, onrejected) {
|
|
192
200
|
return this.constPromise.then(onfulfilled, onrejected);
|
|
@@ -202,7 +210,9 @@ var ConstRestatePromise = class ConstRestatePromise extends InternalRestatePromi
|
|
|
202
210
|
return ConstRestatePromise.reject(new require_errors.TimeoutError());
|
|
203
211
|
}
|
|
204
212
|
map(mapper) {
|
|
205
|
-
|
|
213
|
+
if (!this.settled) return this;
|
|
214
|
+
const selfConstPromise = this.constPromise;
|
|
215
|
+
return new ConstRestatePromise(() => selfConstPromise.then((value) => mapper(value, void 0), (reason) => mapper(void 0, reason)), this.settled);
|
|
206
216
|
}
|
|
207
217
|
tryCancel() {}
|
|
208
218
|
publicPromise() {
|
|
@@ -243,9 +253,10 @@ var PromisesExecutor = class {
|
|
|
243
253
|
const handles = restatePromise.uncompletedLeaves();
|
|
244
254
|
if (handles.length === 0) return;
|
|
245
255
|
const doProgressResult = this.coreVm.do_progress(new Uint32Array(handles));
|
|
246
|
-
if (doProgressResult === "AnyCompleted") {} else if (doProgressResult === "ReadFromInput"
|
|
247
|
-
|
|
248
|
-
|
|
256
|
+
if (doProgressResult === "AnyCompleted") {} else if (doProgressResult === "ReadFromInput" || doProgressResult === "WaitingPendingRun") {
|
|
257
|
+
await this.outputPump.awaitNextProgress();
|
|
258
|
+
await Promise.race([this.inputPump.awaitNextProgress(), this.runClosuresTracker.awaitNextCompletedRun()]);
|
|
259
|
+
} else if (doProgressResult === "CancelSignalReceived") {
|
|
249
260
|
restatePromise.tryCancel();
|
|
250
261
|
return;
|
|
251
262
|
} else {
|