@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.
Files changed (47) hide show
  1. package/README.md +12 -9
  2. package/dist/endpoint/components.cjs +70 -12
  3. package/dist/endpoint/components.d.ts.map +1 -1
  4. package/dist/endpoint/components.js +70 -12
  5. package/dist/endpoint/components.js.map +1 -1
  6. package/dist/endpoint/handlers/fetch.cjs +5 -3
  7. package/dist/endpoint/handlers/fetch.d.ts.map +1 -1
  8. package/dist/endpoint/handlers/fetch.js +6 -4
  9. package/dist/endpoint/handlers/fetch.js.map +1 -1
  10. package/dist/endpoint/handlers/generic.cjs +11 -10
  11. package/dist/endpoint/handlers/generic.d.ts.map +1 -1
  12. package/dist/endpoint/handlers/generic.js +11 -10
  13. package/dist/endpoint/handlers/generic.js.map +1 -1
  14. package/dist/endpoint/handlers/lambda.cjs +6 -3
  15. package/dist/endpoint/handlers/lambda.d.ts.map +1 -1
  16. package/dist/endpoint/handlers/lambda.js +7 -4
  17. package/dist/endpoint/handlers/lambda.js.map +1 -1
  18. package/dist/endpoint/handlers/preview.cjs +97 -0
  19. package/dist/endpoint/handlers/preview.d.ts +5 -0
  20. package/dist/endpoint/handlers/preview.d.ts.map +1 -0
  21. package/dist/endpoint/handlers/preview.js +98 -0
  22. package/dist/endpoint/handlers/preview.js.map +1 -0
  23. package/dist/endpoint/handlers/types.d.ts.map +1 -1
  24. package/dist/endpoint/handlers/utils.cjs +26 -11
  25. package/dist/endpoint/handlers/utils.d.ts +12 -0
  26. package/dist/endpoint/handlers/utils.d.ts.map +1 -1
  27. package/dist/endpoint/handlers/utils.js +26 -12
  28. package/dist/endpoint/handlers/utils.js.map +1 -1
  29. package/dist/endpoint/node_endpoint.cjs +9 -6
  30. package/dist/endpoint/node_endpoint.js +9 -6
  31. package/dist/endpoint/node_endpoint.js.map +1 -1
  32. package/dist/io.cjs +7 -2
  33. package/dist/io.d.ts.map +1 -1
  34. package/dist/io.js +7 -2
  35. package/dist/io.js.map +1 -1
  36. package/dist/package.cjs +1 -1
  37. package/dist/package.js +1 -1
  38. package/dist/package.js.map +1 -1
  39. package/dist/promises.cjs +21 -10
  40. package/dist/promises.js +21 -10
  41. package/dist/promises.js.map +1 -1
  42. package/dist/types/rpc.d.cts +11 -0
  43. package/dist/types/rpc.d.cts.map +1 -1
  44. package/dist/types/rpc.d.ts +11 -0
  45. package/dist/types/rpc.d.ts.map +1 -1
  46. package/dist/types/rpc.js.map +1 -1
  47. 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,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAK5B,OAAO,CAAC,KAAK,EAAE;QACb,WAAW,EAAE,WAAW,CAAC;QACzB,YAAY,EAAE,YAAY,CAAC;QAC3B,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"}
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
- statusCode,
32
- async process({ inputReader, outputWriter }) {
33
- if (inputReader !== void 0) while (true) {
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,CAkBjB;AAED,wBAAgB,gBAAgB,IAAI,WAAW,CAE9C"}
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
- statusCode,
32
- async process({ inputReader, outputWriter }) {
33
- if (inputReader !== void 0) while (true) {
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 headers,\n statusCode,\n async process({ inputReader, outputWriter }): Promise<void> {\n if (inputReader !== undefined) {\n // Drain the input stream\n while (true) {\n const { done } = await inputReader.next();\n if (done) break;\n }\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"],"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;EACA;EACA,MAAM,QAAQ,EAAE,aAAa,gBAA+B;AAC1D,OAAI,gBAAgB,OAElB,QAAO,MAAM;IACX,MAAM,EAAE,SAAS,MAAM,YAAY,MAAM;AACzC,QAAI,KAAM;;AAId,SAAM,aAAa,MAAM,KAAK;AAE9B,SAAM,aAAa,OAAO;;EAE7B;;AAGH,SAAgB,mBAAgC;AAC9C,SAAQ,mBAAmB,KAAK,CAAC,OAAO,gBAAgB"}
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 restateResponse = handler.handle({
84
+ const writeHead = res.writeHead.bind(res);
85
+ handler.handle({
82
86
  url,
83
87
  headers: httpRequest.headers,
84
88
  extraArgs: []
85
- });
86
- httpResponse.writeHead(restateResponse.statusCode, restateResponse.headers);
87
- restateResponse.process({
88
- inputReader: inputReaderAdapter(httpRequest),
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 restateResponse = handler.handle({
82
+ const writeHead = res.writeHead.bind(res);
83
+ handler.handle({
80
84
  url,
81
85
  headers: httpRequest.headers,
82
86
  extraArgs: []
83
- });
84
- httpResponse.writeHead(restateResponse.statusCode, restateResponse.headers);
85
- restateResponse.process({
86
- inputReader: inputReaderAdapter(httpRequest),
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) this.coreVm.notify_input_closed();
29
- else if (nextValue.value !== void 0) this.coreVm.notify_input(nextValue.value);
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;IAIlB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,aAAa;IALhC,OAAO,CAAC,WAAW,CAAC,CAAgB;gBAGjB,MAAM,EAAE,EAAE,CAAC,MAAM,EACjB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI;IAMlD,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;YAYpB,QAAQ;CAevB;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"}
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) this.coreVm.notify_input_closed();
29
- else if (nextValue.value !== void 0) this.coreVm.notify_input(nextValue.value);
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;;CAMnB,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;EAEtC,IAAI;AACJ,MAAI;AACF,eAAY,MAAM,KAAK,YAAY,MAAM;WAClC,GAAG;AACV,QAAK,cAAc,EAAE;AACrB,UAAO,gBAAsB;;AAE/B,MAAI,UAAU,KACZ,MAAK,OAAO,qBAAqB;WACxB,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"}
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
@@ -1,6 +1,6 @@
1
1
 
2
2
  //#region package.json
3
- var version = "1.12.0";
3
+ var version = "1.14.0";
4
4
 
5
5
  //#endregion
6
6
  Object.defineProperty(exports, 'version', {
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "1.12.0";
2
+ var version = "1.14.0";
3
3
 
4
4
  //#endregion
5
5
  export { version };
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@restatedev/restate-sdk\",\n \"version\": \"1.12.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"}
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
- constructor(constPromise, settled) {
178
+ _constPromise;
179
+ constructor(promiseFactory, settled) {
175
180
  super();
176
- this.constPromise = constPromise;
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
- return ConstRestatePromise.fromPromise(this.constPromise.then((value) => mapper(value, void 0), (reason) => mapper(void 0, reason)), this.settled);
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") await this.inputPump.awaitNextProgress();
247
- else if (doProgressResult === "WaitingPendingRun") await this.runClosuresTracker.awaitNextCompletedRun();
248
- else if (doProgressResult === "CancelSignalReceived") {
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 {