@restatedev/restate-sdk-cloudflare-workers 1.9.1 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/_virtual/rolldown_runtime.cjs +25 -0
- package/dist/common_api.cjs +25 -0
- package/dist/common_api.d.cts +30 -0
- package/dist/common_api.d.cts.map +1 -0
- package/dist/common_api.d.ts +30 -0
- package/dist/common_api.d.ts.map +1 -0
- package/dist/common_api.js +19 -0
- package/dist/common_api.js.map +1 -0
- package/dist/context.cjs +29 -0
- package/dist/context.d.cts +699 -0
- package/dist/context.d.cts.map +1 -0
- package/dist/context.d.ts +699 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +29 -0
- package/dist/context.js.map +1 -0
- package/dist/context_impl.cjs +441 -0
- package/dist/context_impl.js +440 -0
- package/dist/context_impl.js.map +1 -0
- package/dist/endpoint/components.cjs +257 -0
- package/dist/endpoint/components.js +253 -0
- package/dist/endpoint/components.js.map +1 -0
- package/dist/endpoint/endpoint.cjs +117 -0
- package/dist/endpoint/endpoint.js +118 -0
- package/dist/endpoint/endpoint.js.map +1 -0
- package/dist/endpoint/fetch_endpoint.cjs +41 -0
- package/dist/endpoint/fetch_endpoint.d.cts +39 -0
- package/dist/endpoint/fetch_endpoint.d.cts.map +1 -0
- package/dist/endpoint/fetch_endpoint.d.ts +39 -0
- package/dist/endpoint/fetch_endpoint.d.ts.map +1 -0
- package/dist/endpoint/fetch_endpoint.js +42 -0
- package/dist/endpoint/fetch_endpoint.js.map +1 -0
- package/dist/endpoint/handlers/fetch.cjs +21 -0
- package/dist/endpoint/handlers/fetch.js +21 -0
- package/dist/endpoint/handlers/fetch.js.map +1 -0
- package/dist/endpoint/handlers/generic.cjs +328 -0
- package/dist/endpoint/handlers/generic.js +324 -0
- package/dist/endpoint/handlers/generic.js.map +1 -0
- package/dist/endpoint/handlers/lambda.cjs +93 -0
- package/dist/endpoint/handlers/lambda.js +89 -0
- package/dist/endpoint/handlers/lambda.js.map +1 -0
- package/dist/endpoint/lambda_endpoint.cjs +36 -0
- package/dist/endpoint/lambda_endpoint.d.cts +26 -0
- package/dist/endpoint/lambda_endpoint.d.cts.map +1 -0
- package/dist/endpoint/lambda_endpoint.d.ts +26 -0
- package/dist/endpoint/lambda_endpoint.d.ts.map +1 -0
- package/dist/endpoint/lambda_endpoint.js +37 -0
- package/dist/endpoint/lambda_endpoint.js.map +1 -0
- package/dist/endpoint/node_endpoint.cjs +101 -0
- package/dist/endpoint/node_endpoint.js +99 -0
- package/dist/endpoint/node_endpoint.js.map +1 -0
- package/dist/endpoint/types.d.cts +61 -0
- package/dist/endpoint/types.d.cts.map +1 -0
- package/dist/endpoint/types.d.ts +61 -0
- package/dist/endpoint/types.d.ts.map +1 -0
- package/dist/endpoint/withOptions.cjs +15 -0
- package/dist/endpoint/withOptions.js +15 -0
- package/dist/endpoint/withOptions.js.map +1 -0
- package/dist/endpoint.d.cts +112 -0
- package/dist/endpoint.d.cts.map +1 -0
- package/dist/endpoint.d.ts +112 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/fetch.cjs +83 -0
- package/dist/fetch.d.cts +52 -0
- package/dist/fetch.d.cts.map +1 -0
- package/dist/fetch.d.ts +52 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/{esm/src/fetch.js → fetch.js} +15 -18
- package/dist/fetch.js.map +1 -0
- package/dist/index.cjs +48 -0
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/io.cjs +48 -0
- package/dist/io.js +48 -0
- package/dist/io.js.map +1 -0
- package/dist/lambda.cjs +74 -0
- package/dist/lambda.d.cts +32 -0
- package/dist/lambda.d.cts.map +1 -0
- package/dist/lambda.d.ts +32 -0
- package/dist/lambda.d.ts.map +1 -0
- package/dist/lambda.js +35 -0
- package/dist/lambda.js.map +1 -0
- package/dist/logging/console_logger_transport.cjs +54 -0
- package/dist/logging/console_logger_transport.js +54 -0
- package/dist/logging/console_logger_transport.js.map +1 -0
- package/dist/logging/logger.cjs +43 -0
- package/dist/logging/logger.js +44 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/logger_transport.cjs +42 -0
- package/dist/logging/logger_transport.d.cts +57 -0
- package/dist/logging/logger_transport.d.cts.map +1 -0
- package/dist/logging/logger_transport.d.ts +57 -0
- package/dist/logging/logger_transport.d.ts.map +1 -0
- package/dist/logging/logger_transport.js +40 -0
- package/dist/logging/logger_transport.js.map +1 -0
- package/dist/node.cjs +90 -0
- package/dist/node.d.cts +51 -0
- package/dist/node.d.cts.map +1 -0
- package/dist/node.d.ts +51 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +50 -0
- package/dist/node.js.map +1 -0
- package/dist/package.cjs +11 -0
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/promises.cjs +234 -0
- package/dist/promises.js +226 -0
- package/dist/promises.js.map +1 -0
- package/dist/types/errors.cjs +110 -0
- package/dist/types/errors.d.cts +71 -0
- package/dist/types/errors.d.cts.map +1 -0
- package/dist/types/errors.d.ts +71 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +102 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/rpc.cjs +425 -0
- package/dist/types/rpc.d.cts +580 -0
- package/dist/types/rpc.d.cts.map +1 -0
- package/dist/types/rpc.d.ts +580 -0
- package/dist/types/rpc.d.ts.map +1 -0
- package/dist/types/rpc.js +406 -0
- package/dist/types/rpc.js.map +1 -0
- package/dist/user_agent.cjs +7 -0
- package/dist/user_agent.js +8 -0
- package/dist/user_agent.js.map +1 -0
- package/dist/utils/completable_promise.cjs +22 -0
- package/dist/utils/completable_promise.js +22 -0
- package/dist/utils/completable_promise.js.map +1 -0
- package/dist/utils/rand.cjs +72 -0
- package/dist/utils/rand.js +71 -0
- package/dist/utils/rand.js.map +1 -0
- package/dist/utils/streams.cjs +14 -0
- package/dist/utils/streams.js +13 -0
- package/dist/utils/streams.js.map +1 -0
- package/package.json +30 -52
- package/dist/esm/src/common_api.d.ts +0 -37
- package/dist/esm/src/common_api.d.ts.map +0 -1
- package/dist/esm/src/common_api.js +0 -32
- package/dist/esm/src/common_api.js.map +0 -1
- package/dist/esm/src/context.d.ts +0 -695
- package/dist/esm/src/context.d.ts.map +0 -1
- package/dist/esm/src/context.js +0 -87
- package/dist/esm/src/context.js.map +0 -1
- package/dist/esm/src/context_impl.d.ts +0 -69
- package/dist/esm/src/context_impl.d.ts.map +0 -1
- package/dist/esm/src/context_impl.js +0 -592
- package/dist/esm/src/context_impl.js.map +0 -1
- package/dist/esm/src/endpoint/components.d.ts +0 -97
- package/dist/esm/src/endpoint/components.d.ts.map +0 -1
- package/dist/esm/src/endpoint/components.js +0 -343
- package/dist/esm/src/endpoint/components.js.map +0 -1
- package/dist/esm/src/endpoint/discovery.d.ts +0 -184
- package/dist/esm/src/endpoint/discovery.d.ts.map +0 -1
- package/dist/esm/src/endpoint/discovery.js +0 -8
- package/dist/esm/src/endpoint/discovery.js.map +0 -1
- package/dist/esm/src/endpoint/endpoint.d.ts +0 -39
- package/dist/esm/src/endpoint/endpoint.d.ts.map +0 -1
- package/dist/esm/src/endpoint/endpoint.js +0 -155
- package/dist/esm/src/endpoint/endpoint.js.map +0 -1
- package/dist/esm/src/endpoint/fetch_endpoint.d.ts +0 -49
- package/dist/esm/src/endpoint/fetch_endpoint.d.ts.map +0 -1
- package/dist/esm/src/endpoint/fetch_endpoint.js +0 -49
- package/dist/esm/src/endpoint/fetch_endpoint.js.map +0 -1
- package/dist/esm/src/endpoint/handlers/fetch.d.ts +0 -5
- package/dist/esm/src/endpoint/handlers/fetch.d.ts.map +0 -1
- package/dist/esm/src/endpoint/handlers/fetch.js +0 -31
- package/dist/esm/src/endpoint/handlers/fetch.js.map +0 -1
- package/dist/esm/src/endpoint/handlers/generic.d.ts +0 -61
- package/dist/esm/src/endpoint/handlers/generic.d.ts.map +0 -1
- package/dist/esm/src/endpoint/handlers/generic.js +0 -470
- package/dist/esm/src/endpoint/handlers/generic.js.map +0 -1
- package/dist/esm/src/endpoint/handlers/lambda.d.ts +0 -10
- package/dist/esm/src/endpoint/handlers/lambda.d.ts.map +0 -1
- package/dist/esm/src/endpoint/handlers/lambda.js +0 -143
- package/dist/esm/src/endpoint/handlers/lambda.js.map +0 -1
- package/dist/esm/src/endpoint/lambda_endpoint.d.ts +0 -30
- package/dist/esm/src/endpoint/lambda_endpoint.d.ts.map +0 -1
- package/dist/esm/src/endpoint/lambda_endpoint.js +0 -48
- package/dist/esm/src/endpoint/lambda_endpoint.js.map +0 -1
- package/dist/esm/src/endpoint/node_endpoint.d.ts +0 -16
- package/dist/esm/src/endpoint/node_endpoint.d.ts.map +0 -1
- package/dist/esm/src/endpoint/node_endpoint.js +0 -124
- package/dist/esm/src/endpoint/node_endpoint.js.map +0 -1
- package/dist/esm/src/endpoint/types.d.ts +0 -55
- package/dist/esm/src/endpoint/types.d.ts.map +0 -1
- package/dist/esm/src/endpoint/types.js +0 -2
- package/dist/esm/src/endpoint/types.js.map +0 -1
- package/dist/esm/src/endpoint/withOptions.d.ts +0 -4
- package/dist/esm/src/endpoint/withOptions.d.ts.map +0 -1
- package/dist/esm/src/endpoint/withOptions.js +0 -19
- package/dist/esm/src/endpoint/withOptions.js.map +0 -1
- package/dist/esm/src/endpoint.d.ts +0 -108
- package/dist/esm/src/endpoint.d.ts.map +0 -1
- package/dist/esm/src/endpoint.js +0 -12
- package/dist/esm/src/endpoint.js.map +0 -1
- package/dist/esm/src/fetch.d.ts +0 -43
- package/dist/esm/src/fetch.d.ts.map +0 -1
- package/dist/esm/src/fetch.js.map +0 -1
- package/dist/esm/src/generated/version.d.ts +0 -2
- package/dist/esm/src/generated/version.d.ts.map +0 -1
- package/dist/esm/src/generated/version.js +0 -2
- package/dist/esm/src/generated/version.js.map +0 -1
- package/dist/esm/src/io.d.ts +0 -24
- package/dist/esm/src/io.d.ts.map +0 -1
- package/dist/esm/src/io.js +0 -73
- package/dist/esm/src/io.js.map +0 -1
- package/dist/esm/src/lambda.d.ts +0 -23
- package/dist/esm/src/lambda.d.ts.map +0 -1
- package/dist/esm/src/lambda.js +0 -37
- package/dist/esm/src/lambda.js.map +0 -1
- package/dist/esm/src/logging/console_logger_transport.d.ts +0 -5
- package/dist/esm/src/logging/console_logger_transport.d.ts.map +0 -1
- package/dist/esm/src/logging/console_logger_transport.js +0 -94
- package/dist/esm/src/logging/console_logger_transport.js.map +0 -1
- package/dist/esm/src/logging/logger.d.ts +0 -10
- package/dist/esm/src/logging/logger.d.ts.map +0 -1
- package/dist/esm/src/logging/logger.js +0 -57
- package/dist/esm/src/logging/logger.js.map +0 -1
- package/dist/esm/src/logging/logger_transport.d.ts +0 -52
- package/dist/esm/src/logging/logger_transport.d.ts.map +0 -1
- package/dist/esm/src/logging/logger_transport.js +0 -55
- package/dist/esm/src/logging/logger_transport.js.map +0 -1
- package/dist/esm/src/node.d.ts +0 -39
- package/dist/esm/src/node.d.ts.map +0 -1
- package/dist/esm/src/node.js +0 -52
- package/dist/esm/src/node.js.map +0 -1
- package/dist/esm/src/promises.d.ts +0 -111
- package/dist/esm/src/promises.d.ts.map +0 -1
- package/dist/esm/src/promises.js +0 -314
- package/dist/esm/src/promises.js.map +0 -1
- package/dist/esm/src/public_api.d.ts +0 -2
- package/dist/esm/src/public_api.d.ts.map +0 -1
- package/dist/esm/src/public_api.js +0 -12
- package/dist/esm/src/public_api.js.map +0 -1
- package/dist/esm/src/types/errors.d.ts +0 -74
- package/dist/esm/src/types/errors.d.ts.map +0 -1
- package/dist/esm/src/types/errors.js +0 -128
- package/dist/esm/src/types/errors.js.map +0 -1
- package/dist/esm/src/types/rpc.d.ts +0 -620
- package/dist/esm/src/types/rpc.d.ts.map +0 -1
- package/dist/esm/src/types/rpc.js +0 -577
- package/dist/esm/src/types/rpc.js.map +0 -1
- package/dist/esm/src/user_agent.d.ts +0 -2
- package/dist/esm/src/user_agent.d.ts.map +0 -1
- package/dist/esm/src/user_agent.js +0 -13
- package/dist/esm/src/user_agent.js.map +0 -1
- package/dist/esm/src/utils/completable_promise.d.ts +0 -9
- package/dist/esm/src/utils/completable_promise.d.ts.map +0 -1
- package/dist/esm/src/utils/completable_promise.js +0 -30
- package/dist/esm/src/utils/completable_promise.js.map +0 -1
- package/dist/esm/src/utils/rand.d.ts +0 -13
- package/dist/esm/src/utils/rand.d.ts.map +0 -1
- package/dist/esm/src/utils/rand.js +0 -109
- package/dist/esm/src/utils/rand.js.map +0 -1
- package/dist/esm/src/utils/streams.d.ts +0 -3
- package/dist/esm/src/utils/streams.d.ts.map +0 -1
- package/dist/esm/src/utils/streams.js +0 -20
- package/dist/esm/src/utils/streams.js.map +0 -1
- package/dist/esm/tsconfig.tsbuildinfo +0 -1
- /package/dist/{esm/src/endpoint → endpoint}/handlers/vm/sdk_shared_core_wasm_bindings.d.ts +0 -0
- /package/dist/{esm/src/endpoint → endpoint}/handlers/vm/sdk_shared_core_wasm_bindings.js +0 -0
- /package/dist/{esm/src/endpoint → endpoint}/handlers/vm/sdk_shared_core_wasm_bindings_bg.js +0 -0
- /package/dist/{esm/src/endpoint → endpoint}/handlers/vm/sdk_shared_core_wasm_bindings_bg.wasm +0 -0
- /package/dist/{esm/src/endpoint → endpoint}/handlers/vm/sdk_shared_core_wasm_bindings_bg.wasm.d.ts +0 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_errors = require('../../types/errors.cjs');
|
|
3
|
+
const require_rpc = require('../../types/rpc.cjs');
|
|
4
|
+
const require_components = require('../components.cjs');
|
|
5
|
+
const require_user_agent = require('../../user_agent.cjs');
|
|
6
|
+
const require_streams = require('../../utils/streams.cjs');
|
|
7
|
+
const require_completable_promise = require('../../utils/completable_promise.cjs');
|
|
8
|
+
const require_logger_transport = require('../../logging/logger_transport.cjs');
|
|
9
|
+
const require_logger = require('../../logging/logger.cjs');
|
|
10
|
+
const require_console_logger_transport = require('../../logging/console_logger_transport.cjs');
|
|
11
|
+
const require_sdk_shared_core_wasm_bindings = require('./vm/sdk_shared_core_wasm_bindings.cjs');
|
|
12
|
+
const require_context_impl = require('../../context_impl.cjs');
|
|
13
|
+
let __restatedev_restate_sdk_core = require("@restatedev/restate-sdk-core");
|
|
14
|
+
__restatedev_restate_sdk_core = require_rolldown_runtime.__toESM(__restatedev_restate_sdk_core);
|
|
15
|
+
let node_stream_web = require("node:stream/web");
|
|
16
|
+
node_stream_web = require_rolldown_runtime.__toESM(node_stream_web);
|
|
17
|
+
|
|
18
|
+
//#region src/endpoint/handlers/generic.ts
|
|
19
|
+
const ENDPOINT_MANIFEST_V2 = "application/vnd.restate.endpointmanifest.v2+json";
|
|
20
|
+
const ENDPOINT_MANIFEST_V3 = "application/vnd.restate.endpointmanifest.v3+json";
|
|
21
|
+
const ENDPOINT_MANIFEST_V4 = "application/vnd.restate.endpointmanifest.v4+json";
|
|
22
|
+
function tryCreateContextualLogger(loggerTransport, url, headers, additionalContext) {
|
|
23
|
+
try {
|
|
24
|
+
const path = new URL(url, "https://example.com").pathname;
|
|
25
|
+
const parsed = require_components.parseUrlComponents(path);
|
|
26
|
+
if (parsed.type !== "invoke") return;
|
|
27
|
+
const invocationId = invocationIdFromHeaders(headers);
|
|
28
|
+
return require_logger.createLogger(loggerTransport, require_logger_transport.LogSource.SYSTEM, new require_logger_transport.LoggerContext(invocationId, parsed.componentName, parsed.handlerName, void 0, void 0, additionalContext));
|
|
29
|
+
} catch {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function invocationIdFromHeaders(headers) {
|
|
34
|
+
const invocationIdHeader = headers["x-restate-invocation-id"];
|
|
35
|
+
return typeof invocationIdHeader === "string" ? invocationIdHeader : Array.isArray(invocationIdHeader) ? invocationIdHeader[0] ?? "unknown id" : "unknown id";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* This is an internal API to support 'fetch' like handlers.
|
|
39
|
+
* It supports both request-reply mode and bidirectional streaming mode.
|
|
40
|
+
*
|
|
41
|
+
* An individual handler will have to convert the shape of the incoming request
|
|
42
|
+
* to a RestateRequest, and then pass it to this handler, and eventually convert back
|
|
43
|
+
* the response.
|
|
44
|
+
* Different runtimes have slightly different shapes of the incoming request, and responses.
|
|
45
|
+
*/
|
|
46
|
+
var GenericHandler = class {
|
|
47
|
+
identityVerifier;
|
|
48
|
+
constructor(endpoint, protocolMode, additionalDiscoveryFields) {
|
|
49
|
+
this.endpoint = endpoint;
|
|
50
|
+
this.protocolMode = protocolMode;
|
|
51
|
+
this.additionalDiscoveryFields = additionalDiscoveryFields;
|
|
52
|
+
if (this.endpoint.keySet === void 0 || this.endpoint.keySet.length === 0) this.endpoint.rlog.warn(`Accepting requests without validating request signatures; handler access must be restricted`);
|
|
53
|
+
else {
|
|
54
|
+
this.endpoint.rlog.info(`Validating requests using signing keys [${this.endpoint.keySet}]`);
|
|
55
|
+
this.identityVerifier = new require_sdk_shared_core_wasm_bindings.WasmIdentityVerifier(this.endpoint.keySet);
|
|
56
|
+
}
|
|
57
|
+
require_sdk_shared_core_wasm_bindings.set_log_level(restateLogLevelToWasmLogLevel(require_console_logger_transport.DEFAULT_CONSOLE_LOGGER_LOG_LEVEL));
|
|
58
|
+
}
|
|
59
|
+
async handle(request, context) {
|
|
60
|
+
try {
|
|
61
|
+
return await this._handle(request, context);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
const error = require_errors.ensureError(e);
|
|
64
|
+
(tryCreateContextualLogger(this.endpoint.loggerTransport, request.url, request.headers) ?? this.endpoint.rlog).error("Error while handling request: " + (error.stack ?? error.message));
|
|
65
|
+
return this.toErrorResponse(error instanceof require_errors.RestateError ? error.code : 500, error.message);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async _handle(request, context) {
|
|
69
|
+
const path = new URL(request.url, "https://example.com").pathname;
|
|
70
|
+
const parsed = require_components.parseUrlComponents(path);
|
|
71
|
+
if (parsed.type === "unknown") {
|
|
72
|
+
const msg = `Invalid path. Allowed are /health, or /discover, or /invoke/SvcName/handlerName, but was: ${path}`;
|
|
73
|
+
this.endpoint.rlog.trace(msg);
|
|
74
|
+
return this.toErrorResponse(404, msg);
|
|
75
|
+
}
|
|
76
|
+
if (parsed.type === "health") return {
|
|
77
|
+
body: require_streams.OnceStream(new TextEncoder().encode("OK")),
|
|
78
|
+
headers: {
|
|
79
|
+
"content-type": "application/text",
|
|
80
|
+
"x-restate-server": require_user_agent.X_RESTATE_SERVER
|
|
81
|
+
},
|
|
82
|
+
statusCode: 200
|
|
83
|
+
};
|
|
84
|
+
const error = this.validateConnectionSignature(path, request.headers);
|
|
85
|
+
if (error !== null) return error;
|
|
86
|
+
if (parsed.type === "discover") return this.handleDiscovery(request.headers["accept"]);
|
|
87
|
+
if (typeof request.headers["content-type"] !== "string") {
|
|
88
|
+
const errorMessage = "Missing content-type header";
|
|
89
|
+
this.endpoint.rlog.warn(errorMessage);
|
|
90
|
+
return this.toErrorResponse(415, errorMessage);
|
|
91
|
+
}
|
|
92
|
+
const service = this.endpoint.components.get(parsed.componentName);
|
|
93
|
+
if (!service) {
|
|
94
|
+
const msg = `No service found for URL: ${JSON.stringify(parsed)}`;
|
|
95
|
+
this.endpoint.rlog.error(msg);
|
|
96
|
+
return this.toErrorResponse(404, msg);
|
|
97
|
+
}
|
|
98
|
+
const handler = service?.handlerMatching(parsed);
|
|
99
|
+
if (!handler) {
|
|
100
|
+
const msg = `No service found for URL: ${JSON.stringify(parsed)}`;
|
|
101
|
+
this.endpoint.rlog.error(msg);
|
|
102
|
+
return this.toErrorResponse(404, msg);
|
|
103
|
+
}
|
|
104
|
+
if (!request.body) {
|
|
105
|
+
const msg = "The incoming message body was null";
|
|
106
|
+
this.endpoint.rlog.error(msg);
|
|
107
|
+
return this.toErrorResponse(400, msg);
|
|
108
|
+
}
|
|
109
|
+
return this.handleInvoke(service, handler, request.body, request.headers, request.extraArgs, request.abortSignal, context ?? {});
|
|
110
|
+
}
|
|
111
|
+
validateConnectionSignature(path, headers) {
|
|
112
|
+
if (!this.identityVerifier) return null;
|
|
113
|
+
const vmHeaders = Object.entries(headers).filter(([, v]) => v !== void 0).map(([k, v]) => new require_sdk_shared_core_wasm_bindings.WasmHeader(k, v instanceof Array ? v[0] : v));
|
|
114
|
+
try {
|
|
115
|
+
this.identityVerifier.verify_identity(path, vmHeaders);
|
|
116
|
+
return null;
|
|
117
|
+
} catch (e) {
|
|
118
|
+
this.endpoint.rlog.error(`Rejecting request as its JWT did not validate: ${e}`);
|
|
119
|
+
return this.toErrorResponse(401, "Unauthorized");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async handleInvoke(service, handler, body, headers, extraArgs, abortSignal, additionalContext) {
|
|
123
|
+
const journalValueCodec = this.endpoint.journalValueCodec ? await this.endpoint.journalValueCodec : {
|
|
124
|
+
encode: (entry) => entry,
|
|
125
|
+
decode: (entry) => Promise.resolve(entry)
|
|
126
|
+
};
|
|
127
|
+
const loggerId = Math.floor(Math.random() * 4294967295);
|
|
128
|
+
try {
|
|
129
|
+
const vmHeaders = Object.entries(headers).filter(([, v]) => v !== void 0).map(([k, v]) => new require_sdk_shared_core_wasm_bindings.WasmHeader(k, v instanceof Array ? v[0] : v));
|
|
130
|
+
const coreVm = new require_sdk_shared_core_wasm_bindings.WasmVM(vmHeaders, restateLogLevelToWasmLogLevel(require_console_logger_transport.DEFAULT_CONSOLE_LOGGER_LOG_LEVEL), loggerId, this.endpoint.journalValueCodec !== void 0);
|
|
131
|
+
const responseHead = coreVm.get_response_head();
|
|
132
|
+
const responseHeaders = responseHead.headers.reduce((headers$1, { key, value }) => ({
|
|
133
|
+
[key]: value,
|
|
134
|
+
...headers$1
|
|
135
|
+
}), { "x-restate-server": require_user_agent.X_RESTATE_SERVER });
|
|
136
|
+
invocationLoggers.set(loggerId, require_logger.createLogger(this.endpoint.loggerTransport, require_logger_transport.LogSource.JOURNAL, new require_logger_transport.LoggerContext(invocationIdFromHeaders(headers), service.name(), handler.name(), void 0, void 0, additionalContext)));
|
|
137
|
+
const inputReader = body.getReader();
|
|
138
|
+
abortSignal.addEventListener("abort", () => {
|
|
139
|
+
invocationLoggers.delete(loggerId);
|
|
140
|
+
inputReader.cancel();
|
|
141
|
+
}, { once: true });
|
|
142
|
+
while (!coreVm.is_ready_to_execute()) {
|
|
143
|
+
const nextValue = await inputReader.read();
|
|
144
|
+
if (nextValue.value !== void 0) coreVm.notify_input(nextValue.value);
|
|
145
|
+
if (nextValue.done) {
|
|
146
|
+
coreVm.notify_input_closed();
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const input = coreVm.sys_input();
|
|
151
|
+
const invocationRequest = {
|
|
152
|
+
id: input.invocation_id,
|
|
153
|
+
headers: input.headers.reduce((headers$1, { key, value }) => {
|
|
154
|
+
headers$1.set(key, value);
|
|
155
|
+
return headers$1;
|
|
156
|
+
}, /* @__PURE__ */ new Map()),
|
|
157
|
+
attemptHeaders: Object.entries(headers).reduce((headers$1, [key, value]) => {
|
|
158
|
+
if (value !== void 0) headers$1.set(key, value instanceof Array ? value[0] : value);
|
|
159
|
+
return headers$1;
|
|
160
|
+
}, /* @__PURE__ */ new Map()),
|
|
161
|
+
body: input.input,
|
|
162
|
+
extraArgs,
|
|
163
|
+
attemptCompletedSignal: abortSignal
|
|
164
|
+
};
|
|
165
|
+
const loggerContext = new require_logger_transport.LoggerContext(input.invocation_id, handler.component().name(), handler.name(), handler.kind() === require_rpc.HandlerKind.SERVICE ? void 0 : input.key, invocationRequest, additionalContext);
|
|
166
|
+
const ctxLogger = require_logger.createLogger(this.endpoint.loggerTransport, require_logger_transport.LogSource.USER, loggerContext, () => !coreVm.is_processing());
|
|
167
|
+
const vmLogger = require_logger.createLogger(this.endpoint.loggerTransport, require_logger_transport.LogSource.JOURNAL, loggerContext);
|
|
168
|
+
invocationLoggers.set(loggerId, vmLogger);
|
|
169
|
+
if (!coreVm.is_processing()) vmLogger.info("Replaying invocation.");
|
|
170
|
+
else vmLogger.info("Starting invocation.");
|
|
171
|
+
const invocationEndPromise = new require_completable_promise.CompletablePromise();
|
|
172
|
+
const responseTransformStream = new node_stream_web.TransformStream();
|
|
173
|
+
const outputWriter = responseTransformStream.writable.getWriter();
|
|
174
|
+
const ctx = new require_context_impl.ContextImpl(coreVm, input, ctxLogger, handler.kind(), vmLogger, invocationRequest, invocationEndPromise, inputReader, outputWriter, journalValueCodec, service.options?.serde, service.options?.asTerminalError);
|
|
175
|
+
journalValueCodec.decode(input.input).catch((e) => Promise.reject(new require_errors.TerminalError(`Failed to decode input using journal value codec: ${require_errors.ensureError(e).message}`, { errorCode: 400 }))).then((decodedInput) => handler.invoke(ctx, decodedInput)).then((output) => {
|
|
176
|
+
coreVm.sys_write_output_success(journalValueCodec.encode(output));
|
|
177
|
+
coreVm.sys_end();
|
|
178
|
+
vmLogger.info("Invocation completed successfully.");
|
|
179
|
+
}).catch((e) => {
|
|
180
|
+
const error = require_errors.ensureError(e, service.options?.asTerminalError);
|
|
181
|
+
require_errors.logError(vmLogger, error);
|
|
182
|
+
if (error instanceof require_errors.TerminalError) {
|
|
183
|
+
coreVm.sys_write_output_failure({
|
|
184
|
+
code: error.code,
|
|
185
|
+
message: error.message
|
|
186
|
+
});
|
|
187
|
+
coreVm.sys_end();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
throw error;
|
|
191
|
+
}).catch((e) => {
|
|
192
|
+
const error = require_errors.ensureError(e);
|
|
193
|
+
if (error instanceof require_errors.RetryableError) coreVm.notify_error_with_delay_override(error.message, error.stack, error.retryAfter !== void 0 ? BigInt((0, __restatedev_restate_sdk_core.millisOrDurationToMillis)(error.retryAfter)) : void 0);
|
|
194
|
+
else coreVm.notify_error(error.message, error.stack);
|
|
195
|
+
}).finally(() => {
|
|
196
|
+
invocationEndPromise.resolve();
|
|
197
|
+
});
|
|
198
|
+
invocationEndPromise.promise.then(async () => {
|
|
199
|
+
let nextOutput = coreVm.take_output();
|
|
200
|
+
while (nextOutput !== null && nextOutput !== void 0) {
|
|
201
|
+
await outputWriter.write(nextOutput);
|
|
202
|
+
nextOutput = coreVm.take_output();
|
|
203
|
+
}
|
|
204
|
+
await outputWriter.close();
|
|
205
|
+
inputReader.cancel().catch(() => {});
|
|
206
|
+
}).finally(() => {
|
|
207
|
+
invocationLoggers.delete(loggerId);
|
|
208
|
+
}).catch(() => {});
|
|
209
|
+
return {
|
|
210
|
+
headers: responseHeaders,
|
|
211
|
+
statusCode: responseHead.status_code,
|
|
212
|
+
body: responseTransformStream.readable
|
|
213
|
+
};
|
|
214
|
+
} catch (error) {
|
|
215
|
+
invocationLoggers.delete(loggerId);
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
handleDiscovery(acceptVersionsString) {
|
|
220
|
+
if (typeof acceptVersionsString !== "string") {
|
|
221
|
+
const errorMessage = "Missing accept header";
|
|
222
|
+
this.endpoint.rlog.warn(errorMessage);
|
|
223
|
+
return this.toErrorResponse(415, errorMessage);
|
|
224
|
+
}
|
|
225
|
+
let manifestVersion;
|
|
226
|
+
if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V4)) manifestVersion = 4;
|
|
227
|
+
else if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V3)) manifestVersion = 3;
|
|
228
|
+
else if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V2)) manifestVersion = 2;
|
|
229
|
+
else {
|
|
230
|
+
const errorMessage = `Unsupported service discovery protocol version '${acceptVersionsString}'`;
|
|
231
|
+
this.endpoint.rlog.warn(errorMessage);
|
|
232
|
+
return this.toErrorResponse(415, errorMessage);
|
|
233
|
+
}
|
|
234
|
+
const discovery = {
|
|
235
|
+
...this.endpoint.discoveryMetadata,
|
|
236
|
+
...this.additionalDiscoveryFields,
|
|
237
|
+
protocolMode: this.protocolMode
|
|
238
|
+
};
|
|
239
|
+
const checkUnsupportedFeature = (obj, ...fields) => {
|
|
240
|
+
for (const field of fields) if (field in obj && obj[field] !== void 0) return this.toErrorResponse(500, `The code uses the new discovery feature '${String(field)}' but the runtime doesn't support it yet (discovery protocol negotiated version ${manifestVersion}). Either remove the usage of this feature, or upgrade the runtime.`);
|
|
241
|
+
};
|
|
242
|
+
if (manifestVersion < 3) for (const service of discovery.services) {
|
|
243
|
+
const error = checkUnsupportedFeature(service, "journalRetention", "idempotencyRetention", "inactivityTimeout", "abortTimeout", "enableLazyState", "ingressPrivate");
|
|
244
|
+
if (error !== void 0) return error;
|
|
245
|
+
for (const handler of service.handlers) {
|
|
246
|
+
const error$1 = checkUnsupportedFeature(handler, "journalRetention", "idempotencyRetention", "workflowCompletionRetention", "inactivityTimeout", "abortTimeout", "enableLazyState", "ingressPrivate");
|
|
247
|
+
if (error$1 !== void 0) return error$1;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (manifestVersion < 4) {
|
|
251
|
+
discovery.lambdaCompression = void 0;
|
|
252
|
+
for (const service of discovery.services) {
|
|
253
|
+
const error = checkUnsupportedFeature(service, "retryPolicyExponentiationFactor", "retryPolicyInitialInterval", "retryPolicyMaxAttempts", "retryPolicyMaxInterval", "retryPolicyOnMaxAttempts");
|
|
254
|
+
if (error !== void 0) return error;
|
|
255
|
+
for (const handler of service.handlers) {
|
|
256
|
+
const error$1 = checkUnsupportedFeature(handler, "retryPolicyExponentiationFactor", "retryPolicyInitialInterval", "retryPolicyMaxAttempts", "retryPolicyMaxInterval", "retryPolicyOnMaxAttempts");
|
|
257
|
+
if (error$1 !== void 0) return error$1;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const body = JSON.stringify(discovery);
|
|
262
|
+
return {
|
|
263
|
+
headers: {
|
|
264
|
+
"content-type": manifestVersion === 2 ? ENDPOINT_MANIFEST_V2 : manifestVersion === 3 ? ENDPOINT_MANIFEST_V3 : ENDPOINT_MANIFEST_V4,
|
|
265
|
+
"x-restate-server": require_user_agent.X_RESTATE_SERVER
|
|
266
|
+
},
|
|
267
|
+
statusCode: 200,
|
|
268
|
+
body: require_streams.OnceStream(new TextEncoder().encode(body))
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
toErrorResponse(code, message) {
|
|
272
|
+
return {
|
|
273
|
+
headers: {
|
|
274
|
+
"content-type": "application/json",
|
|
275
|
+
"x-restate-server": require_user_agent.X_RESTATE_SERVER
|
|
276
|
+
},
|
|
277
|
+
statusCode: code,
|
|
278
|
+
body: require_streams.OnceStream(new TextEncoder().encode(JSON.stringify({ message })))
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
const invocationLoggers = /* @__PURE__ */ new Map();
|
|
283
|
+
const logsTextDecoder = new TextDecoder("utf-8", { fatal: false });
|
|
284
|
+
/**
|
|
285
|
+
* The shared core propagates logs to the SDK invoking this method.
|
|
286
|
+
* When possible it provides an invocationId, which is used to access the registered invocationLoggers, that should contain the logger per invocation id.
|
|
287
|
+
*/
|
|
288
|
+
function vm_log(level, strBytes, loggerId) {
|
|
289
|
+
try {
|
|
290
|
+
const logger = loggerId && invocationLoggers.get(loggerId) || void 0;
|
|
291
|
+
const str = logsTextDecoder.decode(strBytes);
|
|
292
|
+
if (logger !== void 0) logger.logForLevel(wasmLogLevelToRestateLogLevel(level), str);
|
|
293
|
+
else require_console_logger_transport.defaultLoggerTransport({
|
|
294
|
+
level: wasmLogLevelToRestateLogLevel(level),
|
|
295
|
+
replaying: false,
|
|
296
|
+
source: require_logger_transport.LogSource.JOURNAL
|
|
297
|
+
}, str);
|
|
298
|
+
} catch (e) {
|
|
299
|
+
require_console_logger_transport.defaultLoggerTransport({
|
|
300
|
+
level: require_logger_transport.RestateLogLevel.ERROR,
|
|
301
|
+
replaying: false,
|
|
302
|
+
source: require_logger_transport.LogSource.SYSTEM
|
|
303
|
+
}, "Unexpected error thrown while trying to log: " + e?.toString());
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function wasmLogLevelToRestateLogLevel(level) {
|
|
307
|
+
switch (level) {
|
|
308
|
+
case require_sdk_shared_core_wasm_bindings.LogLevel.TRACE: return require_logger_transport.RestateLogLevel.TRACE;
|
|
309
|
+
case require_sdk_shared_core_wasm_bindings.LogLevel.DEBUG: return require_logger_transport.RestateLogLevel.DEBUG;
|
|
310
|
+
case require_sdk_shared_core_wasm_bindings.LogLevel.INFO: return require_logger_transport.RestateLogLevel.INFO;
|
|
311
|
+
case require_sdk_shared_core_wasm_bindings.LogLevel.WARN: return require_logger_transport.RestateLogLevel.WARN;
|
|
312
|
+
case require_sdk_shared_core_wasm_bindings.LogLevel.ERROR: return require_logger_transport.RestateLogLevel.ERROR;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function restateLogLevelToWasmLogLevel(level) {
|
|
316
|
+
switch (level) {
|
|
317
|
+
case require_logger_transport.RestateLogLevel.TRACE: return require_sdk_shared_core_wasm_bindings.LogLevel.TRACE;
|
|
318
|
+
case require_logger_transport.RestateLogLevel.DEBUG: return require_sdk_shared_core_wasm_bindings.LogLevel.DEBUG;
|
|
319
|
+
case require_logger_transport.RestateLogLevel.INFO: return require_sdk_shared_core_wasm_bindings.LogLevel.INFO;
|
|
320
|
+
case require_logger_transport.RestateLogLevel.WARN: return require_sdk_shared_core_wasm_bindings.LogLevel.WARN;
|
|
321
|
+
case require_logger_transport.RestateLogLevel.ERROR: return require_sdk_shared_core_wasm_bindings.LogLevel.ERROR;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
//#endregion
|
|
326
|
+
exports.GenericHandler = GenericHandler;
|
|
327
|
+
exports.tryCreateContextualLogger = tryCreateContextualLogger;
|
|
328
|
+
exports.vm_log = vm_log;
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { RestateError, RetryableError, TerminalError, ensureError, logError } from "../../types/errors.js";
|
|
2
|
+
import { HandlerKind } from "../../types/rpc.js";
|
|
3
|
+
import { parseUrlComponents } from "../components.js";
|
|
4
|
+
import { X_RESTATE_SERVER } from "../../user_agent.js";
|
|
5
|
+
import { OnceStream } from "../../utils/streams.js";
|
|
6
|
+
import { CompletablePromise } from "../../utils/completable_promise.js";
|
|
7
|
+
import { LogSource, LoggerContext, RestateLogLevel } from "../../logging/logger_transport.js";
|
|
8
|
+
import { createLogger } from "../../logging/logger.js";
|
|
9
|
+
import { DEFAULT_CONSOLE_LOGGER_LOG_LEVEL, defaultLoggerTransport } from "../../logging/console_logger_transport.js";
|
|
10
|
+
import { LogLevel, WasmHeader, WasmIdentityVerifier, WasmVM, set_log_level } from "./vm/sdk_shared_core_wasm_bindings.js";
|
|
11
|
+
import { ContextImpl } from "../../context_impl.js";
|
|
12
|
+
import { millisOrDurationToMillis } from "@restatedev/restate-sdk-core";
|
|
13
|
+
import { TransformStream } from "node:stream/web";
|
|
14
|
+
|
|
15
|
+
//#region src/endpoint/handlers/generic.ts
|
|
16
|
+
const ENDPOINT_MANIFEST_V2 = "application/vnd.restate.endpointmanifest.v2+json";
|
|
17
|
+
const ENDPOINT_MANIFEST_V3 = "application/vnd.restate.endpointmanifest.v3+json";
|
|
18
|
+
const ENDPOINT_MANIFEST_V4 = "application/vnd.restate.endpointmanifest.v4+json";
|
|
19
|
+
function tryCreateContextualLogger(loggerTransport, url, headers, additionalContext) {
|
|
20
|
+
try {
|
|
21
|
+
const path = new URL(url, "https://example.com").pathname;
|
|
22
|
+
const parsed = parseUrlComponents(path);
|
|
23
|
+
if (parsed.type !== "invoke") return;
|
|
24
|
+
const invocationId = invocationIdFromHeaders(headers);
|
|
25
|
+
return createLogger(loggerTransport, LogSource.SYSTEM, new LoggerContext(invocationId, parsed.componentName, parsed.handlerName, void 0, void 0, additionalContext));
|
|
26
|
+
} catch {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function invocationIdFromHeaders(headers) {
|
|
31
|
+
const invocationIdHeader = headers["x-restate-invocation-id"];
|
|
32
|
+
return typeof invocationIdHeader === "string" ? invocationIdHeader : Array.isArray(invocationIdHeader) ? invocationIdHeader[0] ?? "unknown id" : "unknown id";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* This is an internal API to support 'fetch' like handlers.
|
|
36
|
+
* It supports both request-reply mode and bidirectional streaming mode.
|
|
37
|
+
*
|
|
38
|
+
* An individual handler will have to convert the shape of the incoming request
|
|
39
|
+
* to a RestateRequest, and then pass it to this handler, and eventually convert back
|
|
40
|
+
* the response.
|
|
41
|
+
* Different runtimes have slightly different shapes of the incoming request, and responses.
|
|
42
|
+
*/
|
|
43
|
+
var GenericHandler = class {
|
|
44
|
+
identityVerifier;
|
|
45
|
+
constructor(endpoint, protocolMode, additionalDiscoveryFields) {
|
|
46
|
+
this.endpoint = endpoint;
|
|
47
|
+
this.protocolMode = protocolMode;
|
|
48
|
+
this.additionalDiscoveryFields = additionalDiscoveryFields;
|
|
49
|
+
if (this.endpoint.keySet === void 0 || this.endpoint.keySet.length === 0) this.endpoint.rlog.warn(`Accepting requests without validating request signatures; handler access must be restricted`);
|
|
50
|
+
else {
|
|
51
|
+
this.endpoint.rlog.info(`Validating requests using signing keys [${this.endpoint.keySet}]`);
|
|
52
|
+
this.identityVerifier = new WasmIdentityVerifier(this.endpoint.keySet);
|
|
53
|
+
}
|
|
54
|
+
set_log_level(restateLogLevelToWasmLogLevel(DEFAULT_CONSOLE_LOGGER_LOG_LEVEL));
|
|
55
|
+
}
|
|
56
|
+
async handle(request, context) {
|
|
57
|
+
try {
|
|
58
|
+
return await this._handle(request, context);
|
|
59
|
+
} catch (e) {
|
|
60
|
+
const error = ensureError(e);
|
|
61
|
+
(tryCreateContextualLogger(this.endpoint.loggerTransport, request.url, request.headers) ?? this.endpoint.rlog).error("Error while handling request: " + (error.stack ?? error.message));
|
|
62
|
+
return this.toErrorResponse(error instanceof RestateError ? error.code : 500, error.message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async _handle(request, context) {
|
|
66
|
+
const path = new URL(request.url, "https://example.com").pathname;
|
|
67
|
+
const parsed = parseUrlComponents(path);
|
|
68
|
+
if (parsed.type === "unknown") {
|
|
69
|
+
const msg = `Invalid path. Allowed are /health, or /discover, or /invoke/SvcName/handlerName, but was: ${path}`;
|
|
70
|
+
this.endpoint.rlog.trace(msg);
|
|
71
|
+
return this.toErrorResponse(404, msg);
|
|
72
|
+
}
|
|
73
|
+
if (parsed.type === "health") return {
|
|
74
|
+
body: OnceStream(new TextEncoder().encode("OK")),
|
|
75
|
+
headers: {
|
|
76
|
+
"content-type": "application/text",
|
|
77
|
+
"x-restate-server": X_RESTATE_SERVER
|
|
78
|
+
},
|
|
79
|
+
statusCode: 200
|
|
80
|
+
};
|
|
81
|
+
const error = this.validateConnectionSignature(path, request.headers);
|
|
82
|
+
if (error !== null) return error;
|
|
83
|
+
if (parsed.type === "discover") return this.handleDiscovery(request.headers["accept"]);
|
|
84
|
+
if (typeof request.headers["content-type"] !== "string") {
|
|
85
|
+
const errorMessage = "Missing content-type header";
|
|
86
|
+
this.endpoint.rlog.warn(errorMessage);
|
|
87
|
+
return this.toErrorResponse(415, errorMessage);
|
|
88
|
+
}
|
|
89
|
+
const service = this.endpoint.components.get(parsed.componentName);
|
|
90
|
+
if (!service) {
|
|
91
|
+
const msg = `No service found for URL: ${JSON.stringify(parsed)}`;
|
|
92
|
+
this.endpoint.rlog.error(msg);
|
|
93
|
+
return this.toErrorResponse(404, msg);
|
|
94
|
+
}
|
|
95
|
+
const handler = service?.handlerMatching(parsed);
|
|
96
|
+
if (!handler) {
|
|
97
|
+
const msg = `No service found for URL: ${JSON.stringify(parsed)}`;
|
|
98
|
+
this.endpoint.rlog.error(msg);
|
|
99
|
+
return this.toErrorResponse(404, msg);
|
|
100
|
+
}
|
|
101
|
+
if (!request.body) {
|
|
102
|
+
const msg = "The incoming message body was null";
|
|
103
|
+
this.endpoint.rlog.error(msg);
|
|
104
|
+
return this.toErrorResponse(400, msg);
|
|
105
|
+
}
|
|
106
|
+
return this.handleInvoke(service, handler, request.body, request.headers, request.extraArgs, request.abortSignal, context ?? {});
|
|
107
|
+
}
|
|
108
|
+
validateConnectionSignature(path, headers) {
|
|
109
|
+
if (!this.identityVerifier) return null;
|
|
110
|
+
const vmHeaders = Object.entries(headers).filter(([, v]) => v !== void 0).map(([k, v]) => new WasmHeader(k, v instanceof Array ? v[0] : v));
|
|
111
|
+
try {
|
|
112
|
+
this.identityVerifier.verify_identity(path, vmHeaders);
|
|
113
|
+
return null;
|
|
114
|
+
} catch (e) {
|
|
115
|
+
this.endpoint.rlog.error(`Rejecting request as its JWT did not validate: ${e}`);
|
|
116
|
+
return this.toErrorResponse(401, "Unauthorized");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async handleInvoke(service, handler, body, headers, extraArgs, abortSignal, additionalContext) {
|
|
120
|
+
const journalValueCodec = this.endpoint.journalValueCodec ? await this.endpoint.journalValueCodec : {
|
|
121
|
+
encode: (entry) => entry,
|
|
122
|
+
decode: (entry) => Promise.resolve(entry)
|
|
123
|
+
};
|
|
124
|
+
const loggerId = Math.floor(Math.random() * 4294967295);
|
|
125
|
+
try {
|
|
126
|
+
const vmHeaders = Object.entries(headers).filter(([, v]) => v !== void 0).map(([k, v]) => new WasmHeader(k, v instanceof Array ? v[0] : v));
|
|
127
|
+
const coreVm = new WasmVM(vmHeaders, restateLogLevelToWasmLogLevel(DEFAULT_CONSOLE_LOGGER_LOG_LEVEL), loggerId, this.endpoint.journalValueCodec !== void 0);
|
|
128
|
+
const responseHead = coreVm.get_response_head();
|
|
129
|
+
const responseHeaders = responseHead.headers.reduce((headers$1, { key, value }) => ({
|
|
130
|
+
[key]: value,
|
|
131
|
+
...headers$1
|
|
132
|
+
}), { "x-restate-server": X_RESTATE_SERVER });
|
|
133
|
+
invocationLoggers.set(loggerId, createLogger(this.endpoint.loggerTransport, LogSource.JOURNAL, new LoggerContext(invocationIdFromHeaders(headers), service.name(), handler.name(), void 0, void 0, additionalContext)));
|
|
134
|
+
const inputReader = body.getReader();
|
|
135
|
+
abortSignal.addEventListener("abort", () => {
|
|
136
|
+
invocationLoggers.delete(loggerId);
|
|
137
|
+
inputReader.cancel();
|
|
138
|
+
}, { once: true });
|
|
139
|
+
while (!coreVm.is_ready_to_execute()) {
|
|
140
|
+
const nextValue = await inputReader.read();
|
|
141
|
+
if (nextValue.value !== void 0) coreVm.notify_input(nextValue.value);
|
|
142
|
+
if (nextValue.done) {
|
|
143
|
+
coreVm.notify_input_closed();
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const input = coreVm.sys_input();
|
|
148
|
+
const invocationRequest = {
|
|
149
|
+
id: input.invocation_id,
|
|
150
|
+
headers: input.headers.reduce((headers$1, { key, value }) => {
|
|
151
|
+
headers$1.set(key, value);
|
|
152
|
+
return headers$1;
|
|
153
|
+
}, /* @__PURE__ */ new Map()),
|
|
154
|
+
attemptHeaders: Object.entries(headers).reduce((headers$1, [key, value]) => {
|
|
155
|
+
if (value !== void 0) headers$1.set(key, value instanceof Array ? value[0] : value);
|
|
156
|
+
return headers$1;
|
|
157
|
+
}, /* @__PURE__ */ new Map()),
|
|
158
|
+
body: input.input,
|
|
159
|
+
extraArgs,
|
|
160
|
+
attemptCompletedSignal: abortSignal
|
|
161
|
+
};
|
|
162
|
+
const loggerContext = new LoggerContext(input.invocation_id, handler.component().name(), handler.name(), handler.kind() === HandlerKind.SERVICE ? void 0 : input.key, invocationRequest, additionalContext);
|
|
163
|
+
const ctxLogger = createLogger(this.endpoint.loggerTransport, LogSource.USER, loggerContext, () => !coreVm.is_processing());
|
|
164
|
+
const vmLogger = createLogger(this.endpoint.loggerTransport, LogSource.JOURNAL, loggerContext);
|
|
165
|
+
invocationLoggers.set(loggerId, vmLogger);
|
|
166
|
+
if (!coreVm.is_processing()) vmLogger.info("Replaying invocation.");
|
|
167
|
+
else vmLogger.info("Starting invocation.");
|
|
168
|
+
const invocationEndPromise = new CompletablePromise();
|
|
169
|
+
const responseTransformStream = new TransformStream();
|
|
170
|
+
const outputWriter = responseTransformStream.writable.getWriter();
|
|
171
|
+
const ctx = new ContextImpl(coreVm, input, ctxLogger, handler.kind(), vmLogger, invocationRequest, invocationEndPromise, inputReader, outputWriter, journalValueCodec, service.options?.serde, service.options?.asTerminalError);
|
|
172
|
+
journalValueCodec.decode(input.input).catch((e) => Promise.reject(new TerminalError(`Failed to decode input using journal value codec: ${ensureError(e).message}`, { errorCode: 400 }))).then((decodedInput) => handler.invoke(ctx, decodedInput)).then((output) => {
|
|
173
|
+
coreVm.sys_write_output_success(journalValueCodec.encode(output));
|
|
174
|
+
coreVm.sys_end();
|
|
175
|
+
vmLogger.info("Invocation completed successfully.");
|
|
176
|
+
}).catch((e) => {
|
|
177
|
+
const error = ensureError(e, service.options?.asTerminalError);
|
|
178
|
+
logError(vmLogger, error);
|
|
179
|
+
if (error instanceof TerminalError) {
|
|
180
|
+
coreVm.sys_write_output_failure({
|
|
181
|
+
code: error.code,
|
|
182
|
+
message: error.message
|
|
183
|
+
});
|
|
184
|
+
coreVm.sys_end();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
throw error;
|
|
188
|
+
}).catch((e) => {
|
|
189
|
+
const error = ensureError(e);
|
|
190
|
+
if (error instanceof RetryableError) coreVm.notify_error_with_delay_override(error.message, error.stack, error.retryAfter !== void 0 ? BigInt(millisOrDurationToMillis(error.retryAfter)) : void 0);
|
|
191
|
+
else coreVm.notify_error(error.message, error.stack);
|
|
192
|
+
}).finally(() => {
|
|
193
|
+
invocationEndPromise.resolve();
|
|
194
|
+
});
|
|
195
|
+
invocationEndPromise.promise.then(async () => {
|
|
196
|
+
let nextOutput = coreVm.take_output();
|
|
197
|
+
while (nextOutput !== null && nextOutput !== void 0) {
|
|
198
|
+
await outputWriter.write(nextOutput);
|
|
199
|
+
nextOutput = coreVm.take_output();
|
|
200
|
+
}
|
|
201
|
+
await outputWriter.close();
|
|
202
|
+
inputReader.cancel().catch(() => {});
|
|
203
|
+
}).finally(() => {
|
|
204
|
+
invocationLoggers.delete(loggerId);
|
|
205
|
+
}).catch(() => {});
|
|
206
|
+
return {
|
|
207
|
+
headers: responseHeaders,
|
|
208
|
+
statusCode: responseHead.status_code,
|
|
209
|
+
body: responseTransformStream.readable
|
|
210
|
+
};
|
|
211
|
+
} catch (error) {
|
|
212
|
+
invocationLoggers.delete(loggerId);
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
handleDiscovery(acceptVersionsString) {
|
|
217
|
+
if (typeof acceptVersionsString !== "string") {
|
|
218
|
+
const errorMessage = "Missing accept header";
|
|
219
|
+
this.endpoint.rlog.warn(errorMessage);
|
|
220
|
+
return this.toErrorResponse(415, errorMessage);
|
|
221
|
+
}
|
|
222
|
+
let manifestVersion;
|
|
223
|
+
if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V4)) manifestVersion = 4;
|
|
224
|
+
else if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V3)) manifestVersion = 3;
|
|
225
|
+
else if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V2)) manifestVersion = 2;
|
|
226
|
+
else {
|
|
227
|
+
const errorMessage = `Unsupported service discovery protocol version '${acceptVersionsString}'`;
|
|
228
|
+
this.endpoint.rlog.warn(errorMessage);
|
|
229
|
+
return this.toErrorResponse(415, errorMessage);
|
|
230
|
+
}
|
|
231
|
+
const discovery = {
|
|
232
|
+
...this.endpoint.discoveryMetadata,
|
|
233
|
+
...this.additionalDiscoveryFields,
|
|
234
|
+
protocolMode: this.protocolMode
|
|
235
|
+
};
|
|
236
|
+
const checkUnsupportedFeature = (obj, ...fields) => {
|
|
237
|
+
for (const field of fields) if (field in obj && obj[field] !== void 0) return this.toErrorResponse(500, `The code uses the new discovery feature '${String(field)}' but the runtime doesn't support it yet (discovery protocol negotiated version ${manifestVersion}). Either remove the usage of this feature, or upgrade the runtime.`);
|
|
238
|
+
};
|
|
239
|
+
if (manifestVersion < 3) for (const service of discovery.services) {
|
|
240
|
+
const error = checkUnsupportedFeature(service, "journalRetention", "idempotencyRetention", "inactivityTimeout", "abortTimeout", "enableLazyState", "ingressPrivate");
|
|
241
|
+
if (error !== void 0) return error;
|
|
242
|
+
for (const handler of service.handlers) {
|
|
243
|
+
const error$1 = checkUnsupportedFeature(handler, "journalRetention", "idempotencyRetention", "workflowCompletionRetention", "inactivityTimeout", "abortTimeout", "enableLazyState", "ingressPrivate");
|
|
244
|
+
if (error$1 !== void 0) return error$1;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (manifestVersion < 4) {
|
|
248
|
+
discovery.lambdaCompression = void 0;
|
|
249
|
+
for (const service of discovery.services) {
|
|
250
|
+
const error = checkUnsupportedFeature(service, "retryPolicyExponentiationFactor", "retryPolicyInitialInterval", "retryPolicyMaxAttempts", "retryPolicyMaxInterval", "retryPolicyOnMaxAttempts");
|
|
251
|
+
if (error !== void 0) return error;
|
|
252
|
+
for (const handler of service.handlers) {
|
|
253
|
+
const error$1 = checkUnsupportedFeature(handler, "retryPolicyExponentiationFactor", "retryPolicyInitialInterval", "retryPolicyMaxAttempts", "retryPolicyMaxInterval", "retryPolicyOnMaxAttempts");
|
|
254
|
+
if (error$1 !== void 0) return error$1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const body = JSON.stringify(discovery);
|
|
259
|
+
return {
|
|
260
|
+
headers: {
|
|
261
|
+
"content-type": manifestVersion === 2 ? ENDPOINT_MANIFEST_V2 : manifestVersion === 3 ? ENDPOINT_MANIFEST_V3 : ENDPOINT_MANIFEST_V4,
|
|
262
|
+
"x-restate-server": X_RESTATE_SERVER
|
|
263
|
+
},
|
|
264
|
+
statusCode: 200,
|
|
265
|
+
body: OnceStream(new TextEncoder().encode(body))
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
toErrorResponse(code, message) {
|
|
269
|
+
return {
|
|
270
|
+
headers: {
|
|
271
|
+
"content-type": "application/json",
|
|
272
|
+
"x-restate-server": X_RESTATE_SERVER
|
|
273
|
+
},
|
|
274
|
+
statusCode: code,
|
|
275
|
+
body: OnceStream(new TextEncoder().encode(JSON.stringify({ message })))
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
const invocationLoggers = /* @__PURE__ */ new Map();
|
|
280
|
+
const logsTextDecoder = new TextDecoder("utf-8", { fatal: false });
|
|
281
|
+
/**
|
|
282
|
+
* The shared core propagates logs to the SDK invoking this method.
|
|
283
|
+
* When possible it provides an invocationId, which is used to access the registered invocationLoggers, that should contain the logger per invocation id.
|
|
284
|
+
*/
|
|
285
|
+
function vm_log(level, strBytes, loggerId) {
|
|
286
|
+
try {
|
|
287
|
+
const logger = loggerId && invocationLoggers.get(loggerId) || void 0;
|
|
288
|
+
const str = logsTextDecoder.decode(strBytes);
|
|
289
|
+
if (logger !== void 0) logger.logForLevel(wasmLogLevelToRestateLogLevel(level), str);
|
|
290
|
+
else defaultLoggerTransport({
|
|
291
|
+
level: wasmLogLevelToRestateLogLevel(level),
|
|
292
|
+
replaying: false,
|
|
293
|
+
source: LogSource.JOURNAL
|
|
294
|
+
}, str);
|
|
295
|
+
} catch (e) {
|
|
296
|
+
defaultLoggerTransport({
|
|
297
|
+
level: RestateLogLevel.ERROR,
|
|
298
|
+
replaying: false,
|
|
299
|
+
source: LogSource.SYSTEM
|
|
300
|
+
}, "Unexpected error thrown while trying to log: " + e?.toString());
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function wasmLogLevelToRestateLogLevel(level) {
|
|
304
|
+
switch (level) {
|
|
305
|
+
case LogLevel.TRACE: return RestateLogLevel.TRACE;
|
|
306
|
+
case LogLevel.DEBUG: return RestateLogLevel.DEBUG;
|
|
307
|
+
case LogLevel.INFO: return RestateLogLevel.INFO;
|
|
308
|
+
case LogLevel.WARN: return RestateLogLevel.WARN;
|
|
309
|
+
case LogLevel.ERROR: return RestateLogLevel.ERROR;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function restateLogLevelToWasmLogLevel(level) {
|
|
313
|
+
switch (level) {
|
|
314
|
+
case RestateLogLevel.TRACE: return LogLevel.TRACE;
|
|
315
|
+
case RestateLogLevel.DEBUG: return LogLevel.DEBUG;
|
|
316
|
+
case RestateLogLevel.INFO: return LogLevel.INFO;
|
|
317
|
+
case RestateLogLevel.WARN: return LogLevel.WARN;
|
|
318
|
+
case RestateLogLevel.ERROR: return LogLevel.ERROR;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
//#endregion
|
|
323
|
+
export { GenericHandler, tryCreateContextualLogger, vm_log };
|
|
324
|
+
//# sourceMappingURL=generic.js.map
|