@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 @@
|
|
|
1
|
+
{"version":3,"file":"generic.js","names":["endpoint: Endpoint","protocolMode: ProtocolMode","additionalDiscoveryFields: Partial<EndpointManifest>","vm.WasmIdentityVerifier","vm.WasmHeader","journalValueCodec: JournalValueCodec","vm.WasmVM","headers","invocationRequest: Request","error","invocationLoggers: Map<number, Logger>"],"sources":["../../../src/endpoint/handlers/generic.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH\n *\n * This file is part of the Restate SDK for Node.js/TypeScript,\n * which is released under the MIT license.\n *\n * You can find a copy of the license in file LICENSE in the root\n * directory of this repository or package, or at\n * https://github.com/restatedev/sdk-typescript/blob/main/LICENSE\n */\n\nimport {\n ensureError,\n logError,\n RestateError,\n RetryableError,\n TerminalError,\n} from \"../../types/errors.js\";\nimport type {\n Endpoint as EndpointManifest,\n ProtocolMode,\n} from \"../discovery.js\";\nimport type { Component, ComponentHandler } from \"../components.js\";\nimport { parseUrlComponents } from \"../components.js\";\nimport { X_RESTATE_SERVER } from \"../../user_agent.js\";\nimport { type ReadableStream, TransformStream } from \"node:stream/web\";\nimport { OnceStream } from \"../../utils/streams.js\";\nimport { ContextImpl } from \"../../context_impl.js\";\nimport type { Request } from \"../../context.js\";\nimport * as vm from \"./vm/sdk_shared_core_wasm_bindings.js\";\nimport { CompletablePromise } from \"../../utils/completable_promise.js\";\nimport { HandlerKind } from \"../../types/rpc.js\";\nimport { createLogger, type Logger } from \"../../logging/logger.js\";\nimport {\n DEFAULT_CONSOLE_LOGGER_LOG_LEVEL,\n defaultLoggerTransport,\n} from \"../../logging/console_logger_transport.js\";\nimport {\n LoggerContext,\n type LoggerTransport,\n LogSource,\n RestateLogLevel,\n} from \"../../logging/logger_transport.js\";\nimport {\n type JournalValueCodec,\n millisOrDurationToMillis,\n} from \"@restatedev/restate-sdk-core\";\nimport type { Endpoint } from \"../endpoint.js\";\n\nexport interface Headers {\n [name: string]: string | string[] | undefined;\n}\n\nexport interface ResponseHeaders {\n [name: string]: string;\n}\n\nexport interface AdditionalContext {\n [name: string]: string;\n}\n\nexport interface RestateRequest {\n readonly url: string;\n readonly headers: Headers;\n readonly body: ReadableStream<Uint8Array> | null;\n readonly extraArgs: unknown[];\n readonly abortSignal: AbortSignal;\n}\n\nexport interface RestateResponse {\n readonly headers: ResponseHeaders;\n readonly statusCode: number;\n readonly body: ReadableStream<Uint8Array>;\n}\n\nexport interface RestateHandler {\n handle(\n request: RestateRequest,\n context?: AdditionalContext\n ): Promise<RestateResponse>;\n}\n\nconst ENDPOINT_MANIFEST_V2 = \"application/vnd.restate.endpointmanifest.v2+json\";\nconst ENDPOINT_MANIFEST_V3 = \"application/vnd.restate.endpointmanifest.v3+json\";\nconst ENDPOINT_MANIFEST_V4 = \"application/vnd.restate.endpointmanifest.v4+json\";\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\nfunction 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\n/**\n * This is an internal API to support 'fetch' like handlers.\n * It supports both request-reply mode and bidirectional streaming mode.\n *\n * An individual handler will have to convert the shape of the incoming request\n * to a RestateRequest, and then pass it to this handler, and eventually convert back\n * the response.\n * Different runtimes have slightly different shapes of the incoming request, and responses.\n */\nexport class GenericHandler implements RestateHandler {\n private readonly identityVerifier?: vm.WasmIdentityVerifier;\n\n constructor(\n readonly endpoint: Endpoint,\n private readonly protocolMode: ProtocolMode,\n private readonly additionalDiscoveryFields: Partial<EndpointManifest>\n ) {\n // Setup identity verifier\n if (\n this.endpoint.keySet === undefined ||\n this.endpoint.keySet.length === 0\n ) {\n this.endpoint.rlog.warn(\n `Accepting requests without validating request signatures; handler access must be restricted`\n );\n } else {\n this.endpoint.rlog.info(\n `Validating requests using signing keys [${this.endpoint.keySet}]`\n );\n this.identityVerifier = new vm.WasmIdentityVerifier(this.endpoint.keySet);\n }\n\n // Set the logging level in the shared core too!\n vm.set_log_level(\n restateLogLevelToWasmLogLevel(DEFAULT_CONSOLE_LOGGER_LOG_LEVEL)\n );\n }\n\n // handle does not throw.\n public async handle(\n request: RestateRequest,\n context?: AdditionalContext\n ): Promise<RestateResponse> {\n try {\n return await this._handle(request, context);\n } catch (e) {\n const error = ensureError(e);\n (\n tryCreateContextualLogger(\n this.endpoint.loggerTransport,\n request.url,\n request.headers\n ) ?? this.endpoint.rlog\n ).error(\n \"Error while handling request: \" + (error.stack ?? error.message)\n );\n return this.toErrorResponse(\n error instanceof RestateError ? error.code : 500,\n error.message\n );\n }\n }\n\n private async _handle(\n request: RestateRequest,\n context?: AdditionalContext\n ): Promise<RestateResponse> {\n // this is the recommended way to get the relative path from a url that may be relative or absolute\n const path = new URL(request.url, \"https://example.com\").pathname;\n const parsed = parseUrlComponents(path);\n\n if (parsed.type === \"unknown\") {\n const msg = `Invalid path. Allowed are /health, or /discover, or /invoke/SvcName/handlerName, but was: ${path}`;\n this.endpoint.rlog.trace(msg);\n return this.toErrorResponse(404, msg);\n }\n\n if (parsed.type === \"health\") {\n return {\n body: OnceStream(new TextEncoder().encode(\"OK\")),\n headers: {\n \"content-type\": \"application/text\",\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n statusCode: 200,\n };\n }\n\n const error = this.validateConnectionSignature(path, request.headers);\n if (error !== null) {\n return error;\n }\n if (parsed.type === \"discover\") {\n return this.handleDiscovery(request.headers[\"accept\"]);\n }\n const serviceProtocolVersionString = request.headers[\"content-type\"];\n if (typeof serviceProtocolVersionString !== \"string\") {\n const errorMessage = \"Missing content-type header\";\n this.endpoint.rlog.warn(errorMessage);\n return this.toErrorResponse(415, errorMessage);\n }\n const service = this.endpoint.components.get(parsed.componentName);\n if (!service) {\n const msg = `No service found for URL: ${JSON.stringify(parsed)}`;\n this.endpoint.rlog.error(msg);\n return this.toErrorResponse(404, msg);\n }\n const handler = service?.handlerMatching(parsed);\n if (!handler) {\n const msg = `No service found for URL: ${JSON.stringify(parsed)}`;\n this.endpoint.rlog.error(msg);\n return this.toErrorResponse(404, msg);\n }\n if (!request.body) {\n const msg = \"The incoming message body was null\";\n this.endpoint.rlog.error(msg);\n return this.toErrorResponse(400, msg);\n }\n\n return this.handleInvoke(\n service,\n handler,\n request.body,\n request.headers,\n request.extraArgs,\n request.abortSignal,\n context ?? {}\n );\n }\n\n private validateConnectionSignature(\n path: string,\n headers: Headers\n ): RestateResponse | null {\n if (!this.identityVerifier) {\n // not validating\n return null;\n }\n\n const vmHeaders = Object.entries(headers)\n .filter(([, v]) => v !== undefined)\n .map(\n ([k, v]) =>\n new vm.WasmHeader(k, v instanceof Array ? v[0]! : (v as string))\n );\n\n try {\n this.identityVerifier.verify_identity(path, vmHeaders);\n return null;\n } catch (e) {\n this.endpoint.rlog.error(\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Rejecting request as its JWT did not validate: ${e}`\n );\n return this.toErrorResponse(401, \"Unauthorized\");\n }\n }\n\n private async handleInvoke(\n service: Component,\n handler: ComponentHandler,\n body: ReadableStream<Uint8Array>,\n headers: Headers,\n extraArgs: unknown[],\n abortSignal: AbortSignal,\n additionalContext: AdditionalContext\n ): Promise<RestateResponse> {\n const journalValueCodec: JournalValueCodec = this.endpoint.journalValueCodec\n ? await this.endpoint.journalValueCodec\n : {\n encode: (entry) => entry,\n decode: (entry) => Promise.resolve(entry),\n };\n const loggerId = Math.floor(Math.random() * 4_294_967_295 /* u32::MAX */);\n\n try {\n // Instantiate core vm and prepare response headers\n const vmHeaders = Object.entries(headers)\n .filter(([, v]) => v !== undefined)\n .map(\n ([k, v]) =>\n new vm.WasmHeader(k, v instanceof Array ? v[0]! : (v as string))\n );\n const coreVm = new vm.WasmVM(\n vmHeaders,\n restateLogLevelToWasmLogLevel(DEFAULT_CONSOLE_LOGGER_LOG_LEVEL),\n loggerId,\n this.endpoint.journalValueCodec !== undefined\n );\n const responseHead = coreVm.get_response_head();\n const responseHeaders = responseHead.headers.reduce(\n (headers, { key, value }) => ({\n [key]: value,\n ...headers,\n }),\n {\n \"x-restate-server\": X_RESTATE_SERVER,\n }\n );\n\n // Use a default logger that still respects the endpoint custom logger\n // We will override this later with a logger that has a LoggerContext\n // See vm_log below for more details\n invocationLoggers.set(\n loggerId,\n createLogger(\n this.endpoint.loggerTransport,\n LogSource.JOURNAL,\n new LoggerContext(\n invocationIdFromHeaders(headers),\n service.name(),\n handler.name(),\n undefined,\n undefined,\n additionalContext\n )\n )\n );\n\n const inputReader = body.getReader();\n abortSignal.addEventListener(\n \"abort\",\n () => {\n invocationLoggers.delete(loggerId);\n void inputReader.cancel();\n },\n { once: true }\n );\n\n // Now buffer input entries\n while (!coreVm.is_ready_to_execute()) {\n const nextValue = await inputReader.read();\n if (nextValue.value !== undefined) {\n coreVm.notify_input(nextValue.value);\n }\n if (nextValue.done) {\n coreVm.notify_input_closed();\n break;\n }\n }\n\n // Get input\n const input = coreVm.sys_input();\n\n const invocationRequest: Request = {\n id: input.invocation_id,\n headers: input.headers.reduce((headers, { key, value }) => {\n headers.set(key, value);\n return headers;\n }, new Map()),\n attemptHeaders: Object.entries(headers).reduce(\n (headers, [key, value]) => {\n if (value !== undefined) {\n headers.set(key, value instanceof Array ? value[0] : value);\n }\n return headers;\n },\n new Map()\n ),\n body: input.input,\n extraArgs,\n attemptCompletedSignal: abortSignal,\n };\n\n // Prepare logger\n const loggerContext = new LoggerContext(\n input.invocation_id,\n handler.component().name(),\n handler.name(),\n handler.kind() === HandlerKind.SERVICE ? undefined : input.key,\n invocationRequest,\n additionalContext\n );\n const ctxLogger = createLogger(\n this.endpoint.loggerTransport,\n LogSource.USER,\n loggerContext,\n () => !coreVm.is_processing()\n );\n const vmLogger = createLogger(\n this.endpoint.loggerTransport,\n LogSource.JOURNAL,\n loggerContext\n // Filtering is done within the shared core\n );\n // See vm_log below for more details\n invocationLoggers.set(loggerId, vmLogger);\n if (!coreVm.is_processing()) {\n vmLogger.info(\"Replaying invocation.\");\n } else {\n vmLogger.info(\"Starting invocation.\");\n }\n\n // This promise is used to signal the end of the computation,\n // which can be either the user returns a value,\n // or an exception gets catched, or the state machine fails/suspends.\n //\n // The last case is handled internally within the ContextImpl.\n const invocationEndPromise = new CompletablePromise<void>();\n\n // Prepare response stream\n const responseTransformStream = new TransformStream<Uint8Array>();\n const outputWriter = responseTransformStream.writable.getWriter();\n\n // Prepare context\n const ctx = new ContextImpl(\n coreVm,\n input,\n ctxLogger,\n handler.kind(),\n vmLogger,\n invocationRequest,\n invocationEndPromise,\n inputReader,\n outputWriter,\n journalValueCodec,\n service.options?.serde,\n service.options?.asTerminalError\n );\n\n journalValueCodec\n .decode(input.input)\n .catch((e) =>\n Promise.reject(\n new TerminalError(\n `Failed to decode input using journal value codec: ${\n ensureError(e).message\n }`,\n {\n errorCode: 400,\n }\n )\n )\n )\n .then((decodedInput) =>\n // Invoke user handler code\n handler.invoke(ctx, decodedInput)\n )\n .then((output) => {\n // Write output result\n coreVm.sys_write_output_success(journalValueCodec.encode(output));\n coreVm.sys_end();\n vmLogger.info(\"Invocation completed successfully.\");\n })\n .catch((e) => {\n // Convert to Error\n const error = ensureError(e, service.options?.asTerminalError);\n logError(vmLogger, error);\n\n // If TerminalError, handle it here.\n // NOTE: this can still fail!\n if (error instanceof TerminalError) {\n coreVm.sys_write_output_failure({\n code: error.code,\n message: error.message,\n });\n coreVm.sys_end();\n return;\n }\n\n // Not a terminal error, have the below catch handle it\n throw error;\n })\n .catch((e) => {\n // Handle any other error now (retryable errors)\n const error = ensureError(e);\n if (error instanceof RetryableError) {\n coreVm.notify_error_with_delay_override(\n error.message,\n error.stack,\n error.retryAfter !== undefined\n ? BigInt(millisOrDurationToMillis(error.retryAfter))\n : undefined\n );\n } else {\n coreVm.notify_error(error.message, error.stack);\n }\n })\n .finally(() => {\n invocationEndPromise.resolve();\n });\n\n // Let's wire up invocationEndPromise with consuming all the output and closing the streams.\n invocationEndPromise.promise\n .then(async () => {\n // Consume output till the end, write it out, then close the stream\n let nextOutput = coreVm.take_output() as\n | Uint8Array\n | null\n | undefined;\n while (nextOutput !== null && nextOutput !== undefined) {\n await outputWriter.write(nextOutput);\n nextOutput = coreVm.take_output() as Uint8Array | null | undefined;\n }\n await outputWriter.close();\n // Let's cancel the input reader, if it's still here\n inputReader.cancel().catch(() => {});\n })\n .finally(() => {\n invocationLoggers.delete(loggerId);\n })\n .catch(() => {});\n\n return {\n headers: responseHeaders,\n statusCode: responseHead.status_code,\n body: responseTransformStream.readable as ReadableStream<Uint8Array>,\n };\n } catch (error) {\n invocationLoggers.delete(loggerId);\n throw error;\n }\n }\n\n private handleDiscovery(\n acceptVersionsString: string | string[] | undefined\n ): RestateResponse {\n if (typeof acceptVersionsString !== \"string\") {\n const errorMessage = \"Missing accept header\";\n this.endpoint.rlog.warn(errorMessage);\n return this.toErrorResponse(415, errorMessage);\n }\n\n // Negotiate version to use\n let manifestVersion;\n if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V4)) {\n manifestVersion = 4;\n } else if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V3)) {\n manifestVersion = 3;\n } else if (acceptVersionsString.includes(ENDPOINT_MANIFEST_V2)) {\n manifestVersion = 2;\n } else {\n const errorMessage = `Unsupported service discovery protocol version '${acceptVersionsString}'`;\n this.endpoint.rlog.warn(errorMessage);\n return this.toErrorResponse(415, errorMessage);\n }\n\n const discovery = {\n ...this.endpoint.discoveryMetadata,\n ...this.additionalDiscoveryFields,\n protocolMode: this.protocolMode,\n };\n\n const checkUnsupportedFeature = <T extends object>(\n obj: T,\n ...fields: Array<keyof T>\n ) => {\n for (const field of fields) {\n if (field in obj && obj[field] !== undefined) {\n return this.toErrorResponse(\n 500,\n `The code uses the new discovery feature '${String(\n field\n )}' but the runtime doesn't support it yet (discovery protocol negotiated version ${manifestVersion}). Either remove the usage of this feature, or upgrade the runtime.`\n );\n }\n }\n return;\n };\n\n // Verify none of the manifest v3 configuration options are used.\n if (manifestVersion < 3) {\n for (const service of discovery.services) {\n const error = checkUnsupportedFeature(\n service,\n \"journalRetention\",\n \"idempotencyRetention\",\n \"inactivityTimeout\",\n \"abortTimeout\",\n \"enableLazyState\",\n \"ingressPrivate\"\n );\n if (error !== undefined) {\n return error;\n }\n for (const handler of service.handlers) {\n const error = checkUnsupportedFeature(\n handler,\n \"journalRetention\",\n \"idempotencyRetention\",\n \"workflowCompletionRetention\",\n \"inactivityTimeout\",\n \"abortTimeout\",\n \"enableLazyState\",\n \"ingressPrivate\"\n );\n if (error !== undefined) {\n return error;\n }\n }\n }\n }\n\n if (manifestVersion < 4) {\n // Blank the lambda compression field. No need to fail in this case.\n discovery.lambdaCompression = undefined;\n for (const service of discovery.services) {\n const error = checkUnsupportedFeature(\n service,\n \"retryPolicyExponentiationFactor\",\n \"retryPolicyInitialInterval\",\n \"retryPolicyMaxAttempts\",\n \"retryPolicyMaxInterval\",\n \"retryPolicyOnMaxAttempts\"\n );\n if (error !== undefined) {\n return error;\n }\n for (const handler of service.handlers) {\n const error = checkUnsupportedFeature(\n handler,\n \"retryPolicyExponentiationFactor\",\n \"retryPolicyInitialInterval\",\n \"retryPolicyMaxAttempts\",\n \"retryPolicyMaxInterval\",\n \"retryPolicyOnMaxAttempts\"\n );\n if (error !== undefined) {\n return error;\n }\n }\n }\n }\n\n const body = JSON.stringify(discovery);\n return {\n headers: {\n \"content-type\":\n manifestVersion === 2\n ? ENDPOINT_MANIFEST_V2\n : manifestVersion === 3\n ? ENDPOINT_MANIFEST_V3\n : ENDPOINT_MANIFEST_V4,\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n statusCode: 200,\n body: OnceStream(new TextEncoder().encode(body)),\n };\n }\n\n private toErrorResponse(code: number, message: string): RestateResponse {\n return {\n headers: {\n \"content-type\": \"application/json\",\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n statusCode: code,\n body: OnceStream(new TextEncoder().encode(JSON.stringify({ message }))),\n };\n }\n}\n\n// See vm_log below for more details\nconst invocationLoggers: Map<number, Logger> = new Map<number, Logger>();\nconst logsTextDecoder = new TextDecoder(\"utf-8\", { fatal: false });\n\n/**\n * The shared core propagates logs to the SDK invoking this method.\n * When possible it provides an invocationId, which is used to access the registered invocationLoggers, that should contain the logger per invocation id.\n */\nexport function vm_log(\n level: vm.LogLevel,\n strBytes: Uint8Array,\n loggerId?: number\n) {\n try {\n const logger = (loggerId && invocationLoggers.get(loggerId)) || undefined;\n const str = logsTextDecoder.decode(strBytes);\n if (logger !== undefined) {\n logger.logForLevel(wasmLogLevelToRestateLogLevel(level), str);\n } else {\n defaultLoggerTransport(\n {\n level: wasmLogLevelToRestateLogLevel(level),\n replaying: false,\n source: LogSource.JOURNAL,\n },\n str\n );\n }\n } catch (e) {\n // This function CAN'T EVER propagate an error,\n // because otherwise it will cause an awesome error in the shared core due to concurrent usage of it.\n defaultLoggerTransport(\n {\n level: RestateLogLevel.ERROR,\n replaying: false,\n source: LogSource.SYSTEM,\n },\n \"Unexpected error thrown while trying to log: \" + e?.toString()\n );\n }\n}\n\nfunction wasmLogLevelToRestateLogLevel(level: vm.LogLevel): RestateLogLevel {\n switch (level) {\n case vm.LogLevel.TRACE:\n return RestateLogLevel.TRACE;\n case vm.LogLevel.DEBUG:\n return RestateLogLevel.DEBUG;\n case vm.LogLevel.INFO:\n return RestateLogLevel.INFO;\n case vm.LogLevel.WARN:\n return RestateLogLevel.WARN;\n case vm.LogLevel.ERROR:\n return RestateLogLevel.ERROR;\n }\n}\n\nfunction restateLogLevelToWasmLogLevel(level: RestateLogLevel): vm.LogLevel {\n switch (level) {\n case RestateLogLevel.TRACE:\n return vm.LogLevel.TRACE;\n case RestateLogLevel.DEBUG:\n return vm.LogLevel.DEBUG;\n case RestateLogLevel.INFO:\n return vm.LogLevel.INFO;\n case RestateLogLevel.WARN:\n return vm.LogLevel.WARN;\n case RestateLogLevel.ERROR:\n return vm.LogLevel.ERROR;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_errors = require('../../types/errors.cjs');
|
|
3
|
+
const require_user_agent = require('../../user_agent.cjs');
|
|
4
|
+
const require_streams = require('../../utils/streams.cjs');
|
|
5
|
+
const require_generic = require('./generic.cjs');
|
|
6
|
+
let node_stream_web = require("node:stream/web");
|
|
7
|
+
node_stream_web = require_rolldown_runtime.__toESM(node_stream_web);
|
|
8
|
+
let node_buffer = require("node:buffer");
|
|
9
|
+
node_buffer = require_rolldown_runtime.__toESM(node_buffer);
|
|
10
|
+
let node_zlib = require("node:zlib");
|
|
11
|
+
node_zlib = require_rolldown_runtime.__toESM(node_zlib);
|
|
12
|
+
|
|
13
|
+
//#region src/endpoint/handlers/lambda.ts
|
|
14
|
+
const RESPONSE_COMPRESSION_THRESHOLD = 3 * 1024 * 1024;
|
|
15
|
+
var LambdaHandler = class {
|
|
16
|
+
constructor(handler, compressionSupported) {
|
|
17
|
+
this.handler = handler;
|
|
18
|
+
this.compressionSupported = compressionSupported;
|
|
19
|
+
}
|
|
20
|
+
async handleRequest(event, context) {
|
|
21
|
+
const path = "path" in event ? event.path : event.rawPath;
|
|
22
|
+
let requestContentEncoding;
|
|
23
|
+
let requestAcceptEncoding;
|
|
24
|
+
for (const [key, value] of Object.entries(event.headers)) if (key.localeCompare("content-encoding", void 0, { sensitivity: "accent" }) === 0) requestContentEncoding = value;
|
|
25
|
+
else if (key.localeCompare("accept-encoding", void 0, { sensitivity: "accent" }) === 0) requestAcceptEncoding = value;
|
|
26
|
+
let bodyStream;
|
|
27
|
+
if (!event.body) bodyStream = null;
|
|
28
|
+
else {
|
|
29
|
+
let bodyBuffer;
|
|
30
|
+
if (event.isBase64Encoded) bodyBuffer = node_buffer.Buffer.from(event.body, "base64");
|
|
31
|
+
else bodyBuffer = node_buffer.Buffer.from(new TextEncoder().encode(event.body));
|
|
32
|
+
if (requestContentEncoding && requestContentEncoding.includes("zstd")) {
|
|
33
|
+
if (!this.compressionSupported) throw new Error("The input is compressed using zstd, but this lambda deployment doesn't support compression. Make sure to deploy the Lambda using Node > 22");
|
|
34
|
+
bodyBuffer = node_zlib.zstdDecompressSync(bodyBuffer);
|
|
35
|
+
}
|
|
36
|
+
bodyStream = require_streams.OnceStream(bodyBuffer);
|
|
37
|
+
}
|
|
38
|
+
const abortController = new AbortController();
|
|
39
|
+
const request = {
|
|
40
|
+
body: bodyStream,
|
|
41
|
+
headers: event.headers,
|
|
42
|
+
url: path,
|
|
43
|
+
extraArgs: [context],
|
|
44
|
+
abortSignal: abortController.signal
|
|
45
|
+
};
|
|
46
|
+
let response;
|
|
47
|
+
try {
|
|
48
|
+
response = await this.handler.handle(request, { AWSRequestId: context.awsRequestId });
|
|
49
|
+
} catch (e) {
|
|
50
|
+
abortController.abort();
|
|
51
|
+
throw e;
|
|
52
|
+
}
|
|
53
|
+
const chunks = [];
|
|
54
|
+
try {
|
|
55
|
+
await response.body.pipeTo(new node_stream_web.WritableStream({ write: (chunk) => {
|
|
56
|
+
chunks.push(chunk);
|
|
57
|
+
} }));
|
|
58
|
+
} catch (e) {
|
|
59
|
+
const error = require_errors.ensureError(e);
|
|
60
|
+
(require_generic.tryCreateContextualLogger(this.handler.endpoint.loggerTransport, request.url, request.headers) ?? this.handler.endpoint.rlog).error("Error while collecting invocation response: " + (error.stack ?? error.message));
|
|
61
|
+
return {
|
|
62
|
+
headers: {
|
|
63
|
+
"content-type": "application/json",
|
|
64
|
+
"x-restate-server": require_user_agent.X_RESTATE_SERVER
|
|
65
|
+
},
|
|
66
|
+
statusCode: 500,
|
|
67
|
+
isBase64Encoded: false,
|
|
68
|
+
body: JSON.stringify({ message: error.message })
|
|
69
|
+
};
|
|
70
|
+
} finally {
|
|
71
|
+
abortController.abort();
|
|
72
|
+
}
|
|
73
|
+
const responseBodyBuffer = node_buffer.Buffer.concat(chunks);
|
|
74
|
+
let responseBody;
|
|
75
|
+
if (this.compressionSupported && responseBodyBuffer.length > RESPONSE_COMPRESSION_THRESHOLD && requestAcceptEncoding && requestAcceptEncoding.includes("zstd")) {
|
|
76
|
+
response.headers["content-encoding"] = "zstd";
|
|
77
|
+
responseBody = node_zlib.zstdCompressSync(responseBodyBuffer).toString("base64");
|
|
78
|
+
} else responseBody = responseBodyBuffer.toString("base64");
|
|
79
|
+
return {
|
|
80
|
+
headers: response.headers,
|
|
81
|
+
statusCode: response.statusCode,
|
|
82
|
+
isBase64Encoded: true,
|
|
83
|
+
body: responseBody
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
function isCompressionSupported() {
|
|
88
|
+
return "zstdDecompressSync" in node_zlib && "zstdCompressSync" in node_zlib;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
//#endregion
|
|
92
|
+
exports.LambdaHandler = LambdaHandler;
|
|
93
|
+
exports.isCompressionSupported = isCompressionSupported;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ensureError } from "../../types/errors.js";
|
|
2
|
+
import { X_RESTATE_SERVER } from "../../user_agent.js";
|
|
3
|
+
import { OnceStream } from "../../utils/streams.js";
|
|
4
|
+
import { tryCreateContextualLogger } from "./generic.js";
|
|
5
|
+
import { WritableStream } from "node:stream/web";
|
|
6
|
+
import { Buffer } from "node:buffer";
|
|
7
|
+
import * as zlib from "node:zlib";
|
|
8
|
+
|
|
9
|
+
//#region src/endpoint/handlers/lambda.ts
|
|
10
|
+
const RESPONSE_COMPRESSION_THRESHOLD = 3 * 1024 * 1024;
|
|
11
|
+
var LambdaHandler = class {
|
|
12
|
+
constructor(handler, compressionSupported) {
|
|
13
|
+
this.handler = handler;
|
|
14
|
+
this.compressionSupported = compressionSupported;
|
|
15
|
+
}
|
|
16
|
+
async handleRequest(event, context) {
|
|
17
|
+
const path = "path" in event ? event.path : event.rawPath;
|
|
18
|
+
let requestContentEncoding;
|
|
19
|
+
let requestAcceptEncoding;
|
|
20
|
+
for (const [key, value] of Object.entries(event.headers)) if (key.localeCompare("content-encoding", void 0, { sensitivity: "accent" }) === 0) requestContentEncoding = value;
|
|
21
|
+
else if (key.localeCompare("accept-encoding", void 0, { sensitivity: "accent" }) === 0) requestAcceptEncoding = value;
|
|
22
|
+
let bodyStream;
|
|
23
|
+
if (!event.body) bodyStream = null;
|
|
24
|
+
else {
|
|
25
|
+
let bodyBuffer;
|
|
26
|
+
if (event.isBase64Encoded) bodyBuffer = Buffer.from(event.body, "base64");
|
|
27
|
+
else bodyBuffer = Buffer.from(new TextEncoder().encode(event.body));
|
|
28
|
+
if (requestContentEncoding && requestContentEncoding.includes("zstd")) {
|
|
29
|
+
if (!this.compressionSupported) throw new Error("The input is compressed using zstd, but this lambda deployment doesn't support compression. Make sure to deploy the Lambda using Node > 22");
|
|
30
|
+
bodyBuffer = zlib.zstdDecompressSync(bodyBuffer);
|
|
31
|
+
}
|
|
32
|
+
bodyStream = OnceStream(bodyBuffer);
|
|
33
|
+
}
|
|
34
|
+
const abortController = new AbortController();
|
|
35
|
+
const request = {
|
|
36
|
+
body: bodyStream,
|
|
37
|
+
headers: event.headers,
|
|
38
|
+
url: path,
|
|
39
|
+
extraArgs: [context],
|
|
40
|
+
abortSignal: abortController.signal
|
|
41
|
+
};
|
|
42
|
+
let response;
|
|
43
|
+
try {
|
|
44
|
+
response = await this.handler.handle(request, { AWSRequestId: context.awsRequestId });
|
|
45
|
+
} catch (e) {
|
|
46
|
+
abortController.abort();
|
|
47
|
+
throw e;
|
|
48
|
+
}
|
|
49
|
+
const chunks = [];
|
|
50
|
+
try {
|
|
51
|
+
await response.body.pipeTo(new WritableStream({ write: (chunk) => {
|
|
52
|
+
chunks.push(chunk);
|
|
53
|
+
} }));
|
|
54
|
+
} catch (e) {
|
|
55
|
+
const error = ensureError(e);
|
|
56
|
+
(tryCreateContextualLogger(this.handler.endpoint.loggerTransport, request.url, request.headers) ?? this.handler.endpoint.rlog).error("Error while collecting invocation response: " + (error.stack ?? error.message));
|
|
57
|
+
return {
|
|
58
|
+
headers: {
|
|
59
|
+
"content-type": "application/json",
|
|
60
|
+
"x-restate-server": X_RESTATE_SERVER
|
|
61
|
+
},
|
|
62
|
+
statusCode: 500,
|
|
63
|
+
isBase64Encoded: false,
|
|
64
|
+
body: JSON.stringify({ message: error.message })
|
|
65
|
+
};
|
|
66
|
+
} finally {
|
|
67
|
+
abortController.abort();
|
|
68
|
+
}
|
|
69
|
+
const responseBodyBuffer = Buffer.concat(chunks);
|
|
70
|
+
let responseBody;
|
|
71
|
+
if (this.compressionSupported && responseBodyBuffer.length > RESPONSE_COMPRESSION_THRESHOLD && requestAcceptEncoding && requestAcceptEncoding.includes("zstd")) {
|
|
72
|
+
response.headers["content-encoding"] = "zstd";
|
|
73
|
+
responseBody = zlib.zstdCompressSync(responseBodyBuffer).toString("base64");
|
|
74
|
+
} else responseBody = responseBodyBuffer.toString("base64");
|
|
75
|
+
return {
|
|
76
|
+
headers: response.headers,
|
|
77
|
+
statusCode: response.statusCode,
|
|
78
|
+
isBase64Encoded: true,
|
|
79
|
+
body: responseBody
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
function isCompressionSupported() {
|
|
84
|
+
return "zstdDecompressSync" in zlib && "zstdCompressSync" in zlib;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
export { LambdaHandler, isCompressionSupported };
|
|
89
|
+
//# sourceMappingURL=lambda.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda.js","names":["handler: GenericHandler","compressionSupported: boolean","bodyStream: ReadableStream<Uint8Array> | null","bodyBuffer: Buffer | undefined","request: RestateRequest","response: RestateResponse","chunks: Uint8Array[]"],"sources":["../../../src/endpoint/handlers/lambda.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 {\n APIGatewayProxyEvent,\n APIGatewayProxyEventV2,\n APIGatewayProxyResult,\n APIGatewayProxyStructuredResultV2,\n Context,\n} from \"aws-lambda\";\nimport { Buffer } from \"node:buffer\";\nimport type {\n GenericHandler,\n RestateRequest,\n RestateResponse,\n} from \"./generic.js\";\nimport { tryCreateContextualLogger } from \"./generic.js\";\nimport { WritableStream, type ReadableStream } from \"node:stream/web\";\nimport { OnceStream } from \"../../utils/streams.js\";\nimport { X_RESTATE_SERVER } from \"../../user_agent.js\";\nimport { ensureError } from \"../../types/errors.js\";\nimport * as zlib from \"node:zlib\";\n\nconst RESPONSE_COMPRESSION_THRESHOLD = 3 * 1024 * 1024;\n\nexport class LambdaHandler {\n constructor(\n private readonly handler: GenericHandler,\n private readonly compressionSupported: boolean\n ) {}\n\n async handleRequest(\n event: APIGatewayProxyEvent | APIGatewayProxyEventV2,\n context: Context\n ): Promise<APIGatewayProxyResult | APIGatewayProxyStructuredResultV2> {\n //\n // Request path\n //\n const path = \"path\" in event ? event.path : event.rawPath;\n\n // Deal with content-encoding\n let requestContentEncoding;\n let requestAcceptEncoding;\n for (const [key, value] of Object.entries(event.headers)) {\n if (\n key.localeCompare(\"content-encoding\", undefined, {\n sensitivity: \"accent\",\n }) === 0\n ) {\n requestContentEncoding = value;\n } else if (\n key.localeCompare(\"accept-encoding\", undefined, {\n sensitivity: \"accent\",\n }) === 0\n ) {\n requestAcceptEncoding = value;\n }\n }\n\n //\n // Convert the request body to a Uint8Array stream\n // Lambda functions receive the body as base64 encoded string\n //\n let bodyStream: ReadableStream<Uint8Array> | null;\n if (!event.body) {\n bodyStream = null;\n } else {\n let bodyBuffer: Buffer | undefined;\n if (event.isBase64Encoded) {\n bodyBuffer = Buffer.from(event.body, \"base64\");\n } else {\n bodyBuffer = Buffer.from(new TextEncoder().encode(event.body));\n }\n\n // Now decode if needed\n if (requestContentEncoding && requestContentEncoding.includes(\"zstd\")) {\n if (!this.compressionSupported) {\n throw new Error(\n \"The input is compressed using zstd, but this lambda deployment doesn't support compression. Make sure to deploy the Lambda using Node > 22\"\n );\n }\n\n // Input encoded with zstd, let's decode it!\n bodyBuffer = (\n zlib as unknown as { zstdDecompressSync: (b: Buffer) => Buffer }\n ).zstdDecompressSync(bodyBuffer);\n }\n\n // Prep the stream to pass through the endpoint handler\n bodyStream = OnceStream(bodyBuffer);\n }\n\n const abortController = new AbortController();\n\n const request: RestateRequest = {\n body: bodyStream,\n headers: event.headers,\n url: path,\n extraArgs: [context],\n abortSignal: abortController.signal,\n };\n\n let response: RestateResponse;\n\n try {\n response = await this.handler.handle(request, {\n AWSRequestId: context.awsRequestId,\n });\n } catch (e) {\n abortController.abort();\n throw e;\n }\n\n const chunks: Uint8Array[] = [];\n\n try {\n await response.body.pipeTo(\n new WritableStream<Uint8Array>({\n write: (chunk) => {\n chunks.push(chunk);\n },\n })\n );\n } catch (e) {\n // unlike in the streaming case, we can actually catch errors in the response body and form a nicer error\n const error = ensureError(e);\n (\n tryCreateContextualLogger(\n this.handler.endpoint.loggerTransport,\n request.url,\n request.headers\n ) ?? this.handler.endpoint.rlog\n ).error(\n \"Error while collecting invocation response: \" +\n (error.stack ?? error.message)\n );\n return {\n headers: {\n \"content-type\": \"application/json\",\n \"x-restate-server\": X_RESTATE_SERVER,\n },\n statusCode: 500,\n isBase64Encoded: false,\n body: JSON.stringify({ message: error.message }),\n };\n } finally {\n abortController.abort();\n }\n\n const responseBodyBuffer = Buffer.concat(chunks);\n let responseBody;\n\n // Now let's encode if we need to.\n if (\n this.compressionSupported &&\n responseBodyBuffer.length > RESPONSE_COMPRESSION_THRESHOLD &&\n requestAcceptEncoding &&\n requestAcceptEncoding.includes(\"zstd\")\n ) {\n response.headers[\"content-encoding\"] = \"zstd\";\n\n responseBody = (\n zlib as unknown as { zstdCompressSync: (b: Buffer) => Buffer }\n )\n .zstdCompressSync(responseBodyBuffer)\n .toString(\"base64\");\n } else {\n responseBody = responseBodyBuffer.toString(\"base64\");\n }\n return {\n headers: response.headers,\n statusCode: response.statusCode,\n isBase64Encoded: true,\n body: responseBody,\n };\n }\n}\n\nexport function isCompressionSupported() {\n return \"zstdDecompressSync\" in zlib && \"zstdCompressSync\" in zlib;\n}\n"],"mappings":";;;;;;;;;AA+BA,MAAM,iCAAiC,IAAI,OAAO;AAElD,IAAa,gBAAb,MAA2B;CACzB,YACE,AAAiBA,SACjB,AAAiBC,sBACjB;EAFiB;EACA;;CAGnB,MAAM,cACJ,OACA,SACoE;EAIpE,MAAM,OAAO,UAAU,QAAQ,MAAM,OAAO,MAAM;EAGlD,IAAI;EACJ,IAAI;AACJ,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,QAAQ,CACtD,KACE,IAAI,cAAc,oBAAoB,QAAW,EAC/C,aAAa,UACd,CAAC,KAAK,EAEP,0BAAyB;WAEzB,IAAI,cAAc,mBAAmB,QAAW,EAC9C,aAAa,UACd,CAAC,KAAK,EAEP,yBAAwB;EAQ5B,IAAIC;AACJ,MAAI,CAAC,MAAM,KACT,cAAa;OACR;GACL,IAAIC;AACJ,OAAI,MAAM,gBACR,cAAa,OAAO,KAAK,MAAM,MAAM,SAAS;OAE9C,cAAa,OAAO,KAAK,IAAI,aAAa,CAAC,OAAO,MAAM,KAAK,CAAC;AAIhE,OAAI,0BAA0B,uBAAuB,SAAS,OAAO,EAAE;AACrE,QAAI,CAAC,KAAK,qBACR,OAAM,IAAI,MACR,6IACD;AAIH,iBACE,KACA,mBAAmB,WAAW;;AAIlC,gBAAa,WAAW,WAAW;;EAGrC,MAAM,kBAAkB,IAAI,iBAAiB;EAE7C,MAAMC,UAA0B;GAC9B,MAAM;GACN,SAAS,MAAM;GACf,KAAK;GACL,WAAW,CAAC,QAAQ;GACpB,aAAa,gBAAgB;GAC9B;EAED,IAAIC;AAEJ,MAAI;AACF,cAAW,MAAM,KAAK,QAAQ,OAAO,SAAS,EAC5C,cAAc,QAAQ,cACvB,CAAC;WACK,GAAG;AACV,mBAAgB,OAAO;AACvB,SAAM;;EAGR,MAAMC,SAAuB,EAAE;AAE/B,MAAI;AACF,SAAM,SAAS,KAAK,OAClB,IAAI,eAA2B,EAC7B,QAAQ,UAAU;AAChB,WAAO,KAAK,MAAM;MAErB,CAAC,CACH;WACM,GAAG;GAEV,MAAM,QAAQ,YAAY,EAAE;AAC5B,IACE,0BACE,KAAK,QAAQ,SAAS,iBACtB,QAAQ,KACR,QAAQ,QACT,IAAI,KAAK,QAAQ,SAAS,MAC3B,MACA,kDACG,MAAM,SAAS,MAAM,SACzB;AACD,UAAO;IACL,SAAS;KACP,gBAAgB;KAChB,oBAAoB;KACrB;IACD,YAAY;IACZ,iBAAiB;IACjB,MAAM,KAAK,UAAU,EAAE,SAAS,MAAM,SAAS,CAAC;IACjD;YACO;AACR,mBAAgB,OAAO;;EAGzB,MAAM,qBAAqB,OAAO,OAAO,OAAO;EAChD,IAAI;AAGJ,MACE,KAAK,wBACL,mBAAmB,SAAS,kCAC5B,yBACA,sBAAsB,SAAS,OAAO,EACtC;AACA,YAAS,QAAQ,sBAAsB;AAEvC,kBACE,KAEC,iBAAiB,mBAAmB,CACpC,SAAS,SAAS;QAErB,gBAAe,mBAAmB,SAAS,SAAS;AAEtD,SAAO;GACL,SAAS,SAAS;GAClB,YAAY,SAAS;GACrB,iBAAiB;GACjB,MAAM;GACP;;;AAIL,SAAgB,yBAAyB;AACvC,QAAO,wBAAwB,QAAQ,sBAAsB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const require_generic = require('./handlers/generic.cjs');
|
|
2
|
+
const require_endpoint = require('./endpoint.cjs');
|
|
3
|
+
const require_lambda = require('./handlers/lambda.cjs');
|
|
4
|
+
|
|
5
|
+
//#region src/endpoint/lambda_endpoint.ts
|
|
6
|
+
var LambdaEndpointImpl = class {
|
|
7
|
+
builder = new require_endpoint.EndpointBuilder();
|
|
8
|
+
bind(definition) {
|
|
9
|
+
this.builder.bind(definition);
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
withIdentityV1(...keys) {
|
|
13
|
+
this.builder.addIdentityKeys(...keys);
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
defaultServiceOptions(options) {
|
|
17
|
+
this.builder.setDefaultServiceOptions(options);
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
setLogger(logger) {
|
|
21
|
+
this.builder.setLogger(logger);
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
journalValueCodecProvider(codecProvider) {
|
|
25
|
+
this.builder.setJournalValueCodecProvider(codecProvider);
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
handler() {
|
|
29
|
+
const compressionEnabled = require_lambda.isCompressionSupported();
|
|
30
|
+
const lambdaHandler = new require_lambda.LambdaHandler(new require_generic.GenericHandler(this.builder.build(), "REQUEST_RESPONSE", compressionEnabled ? { lambdaCompression: "zstd" } : {}), compressionEnabled);
|
|
31
|
+
return lambdaHandler.handleRequest.bind(lambdaHandler);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
exports.LambdaEndpointImpl = LambdaEndpointImpl;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "../logging/logger_transport.cjs";
|
|
2
|
+
import { RestateEndpointBase } from "../endpoint.cjs";
|
|
3
|
+
import { JournalValueCodec, ServiceDefinition, VirtualObjectDefinition, WorkflowDefinition } from "@restatedev/restate-sdk-core";
|
|
4
|
+
|
|
5
|
+
//#region src/endpoint/lambda_endpoint.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* LambdaEndpoint encapsulates all the Restate services served by this endpoint.
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* A typical endpoint served as Lambda would look like this:
|
|
13
|
+
* ```
|
|
14
|
+
* import * as restate from "@restatedev/restate-sdk/lambda";
|
|
15
|
+
*
|
|
16
|
+
* export const handler = restate
|
|
17
|
+
* .endpoint()
|
|
18
|
+
* .bind(myService)
|
|
19
|
+
* .handler();
|
|
20
|
+
*/
|
|
21
|
+
interface LambdaEndpoint extends RestateEndpointBase<LambdaEndpoint> {
|
|
22
|
+
handler(): (event: any, ctx: any) => Promise<any>;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { LambdaEndpoint };
|
|
26
|
+
//# sourceMappingURL=lambda_endpoint.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda_endpoint.d.cts","names":[],"sources":["../../src/endpoint/lambda_endpoint.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAwCA;;;;;;;;;;;;UAAiB,cAAA,SAAuB,oBAAoB;uCAErB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "../logging/logger_transport.js";
|
|
2
|
+
import { RestateEndpointBase } from "../endpoint.js";
|
|
3
|
+
import { JournalValueCodec, ServiceDefinition, VirtualObjectDefinition, WorkflowDefinition } from "@restatedev/restate-sdk-core";
|
|
4
|
+
|
|
5
|
+
//#region src/endpoint/lambda_endpoint.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* LambdaEndpoint encapsulates all the Restate services served by this endpoint.
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* A typical endpoint served as Lambda would look like this:
|
|
13
|
+
* ```
|
|
14
|
+
* import * as restate from "@restatedev/restate-sdk/lambda";
|
|
15
|
+
*
|
|
16
|
+
* export const handler = restate
|
|
17
|
+
* .endpoint()
|
|
18
|
+
* .bind(myService)
|
|
19
|
+
* .handler();
|
|
20
|
+
*/
|
|
21
|
+
interface LambdaEndpoint extends RestateEndpointBase<LambdaEndpoint> {
|
|
22
|
+
handler(): (event: any, ctx: any) => Promise<any>;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { LambdaEndpoint };
|
|
26
|
+
//# sourceMappingURL=lambda_endpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda_endpoint.d.ts","names":[],"sources":["../../src/endpoint/lambda_endpoint.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAwCA;;;;;;;;;;;;UAAiB,cAAA,SAAuB,oBAAoB;uCAErB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { GenericHandler } from "./handlers/generic.js";
|
|
2
|
+
import { EndpointBuilder } from "./endpoint.js";
|
|
3
|
+
import { LambdaHandler, isCompressionSupported } from "./handlers/lambda.js";
|
|
4
|
+
|
|
5
|
+
//#region src/endpoint/lambda_endpoint.ts
|
|
6
|
+
var LambdaEndpointImpl = class {
|
|
7
|
+
builder = new EndpointBuilder();
|
|
8
|
+
bind(definition) {
|
|
9
|
+
this.builder.bind(definition);
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
withIdentityV1(...keys) {
|
|
13
|
+
this.builder.addIdentityKeys(...keys);
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
defaultServiceOptions(options) {
|
|
17
|
+
this.builder.setDefaultServiceOptions(options);
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
setLogger(logger) {
|
|
21
|
+
this.builder.setLogger(logger);
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
journalValueCodecProvider(codecProvider) {
|
|
25
|
+
this.builder.setJournalValueCodecProvider(codecProvider);
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
handler() {
|
|
29
|
+
const compressionEnabled = isCompressionSupported();
|
|
30
|
+
const lambdaHandler = new LambdaHandler(new GenericHandler(this.builder.build(), "REQUEST_RESPONSE", compressionEnabled ? { lambdaCompression: "zstd" } : {}), compressionEnabled);
|
|
31
|
+
return lambdaHandler.handleRequest.bind(lambdaHandler);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { LambdaEndpointImpl };
|
|
37
|
+
//# sourceMappingURL=lambda_endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda_endpoint.js","names":[],"sources":["../../src/endpoint/lambda_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 {\n JournalValueCodec,\n ServiceDefinition,\n VirtualObjectDefinition,\n WorkflowDefinition,\n} from \"@restatedev/restate-sdk-core\";\nimport { EndpointBuilder } from \"./endpoint.js\";\nimport type {\n DefaultServiceOptions,\n RestateEndpointBase,\n} from \"../endpoint.js\";\nimport { GenericHandler } from \"./handlers/generic.js\";\nimport { isCompressionSupported, LambdaHandler } from \"./handlers/lambda.js\";\nimport type { LoggerTransport } from \"../logging/logger_transport.js\";\n\n/**\n * LambdaEndpoint encapsulates all the Restate services served by this endpoint.\n *\n *\n * @example\n * A typical endpoint served as Lambda would look like this:\n * ```\n * import * as restate from \"@restatedev/restate-sdk/lambda\";\n *\n * export const handler = restate\n * .endpoint()\n * .bind(myService)\n * .handler();\n */\nexport interface LambdaEndpoint extends RestateEndpointBase<LambdaEndpoint> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handler(): (event: any, ctx: any) => Promise<any>;\n}\n\nexport class LambdaEndpointImpl implements LambdaEndpoint {\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 ): LambdaEndpoint {\n this.builder.bind(definition);\n return this;\n }\n\n public withIdentityV1(...keys: string[]): LambdaEndpoint {\n this.builder.addIdentityKeys(...keys);\n return this;\n }\n\n public defaultServiceOptions(options: DefaultServiceOptions): LambdaEndpoint {\n this.builder.setDefaultServiceOptions(options);\n return this;\n }\n\n public setLogger(logger: LoggerTransport): LambdaEndpoint {\n this.builder.setLogger(logger);\n return this;\n }\n\n public journalValueCodecProvider(\n codecProvider: () => Promise<JournalValueCodec>\n ): LambdaEndpoint {\n this.builder.setJournalValueCodecProvider(codecProvider);\n return this;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handler(): (event: any, ctx: any) => Promise<any> {\n const compressionEnabled = isCompressionSupported();\n\n const genericHandler = new GenericHandler(\n this.builder.build(),\n \"REQUEST_RESPONSE\",\n compressionEnabled\n ? {\n lambdaCompression: \"zstd\",\n }\n : {}\n );\n const lambdaHandler = new LambdaHandler(genericHandler, compressionEnabled);\n return lambdaHandler.handleRequest.bind(lambdaHandler);\n }\n}\n"],"mappings":";;;;;AA6CA,IAAa,qBAAb,MAA0D;CACxD,AAAQ,UAA2B,IAAI,iBAAiB;CAExD,AAAO,KACL,YAIgB;AAChB,OAAK,QAAQ,KAAK,WAAW;AAC7B,SAAO;;CAGT,AAAO,eAAe,GAAG,MAAgC;AACvD,OAAK,QAAQ,gBAAgB,GAAG,KAAK;AACrC,SAAO;;CAGT,AAAO,sBAAsB,SAAgD;AAC3E,OAAK,QAAQ,yBAAyB,QAAQ;AAC9C,SAAO;;CAGT,AAAO,UAAU,QAAyC;AACxD,OAAK,QAAQ,UAAU,OAAO;AAC9B,SAAO;;CAGT,AAAO,0BACL,eACgB;AAChB,OAAK,QAAQ,6BAA6B,cAAc;AACxD,SAAO;;CAIT,UAAkD;EAChD,MAAM,qBAAqB,wBAAwB;EAWnD,MAAM,gBAAgB,IAAI,cATH,IAAI,eACzB,KAAK,QAAQ,OAAO,EACpB,oBACA,qBACI,EACE,mBAAmB,QACpB,GACD,EAAE,CACP,EACuD,mBAAmB;AAC3E,SAAO,cAAc,cAAc,KAAK,cAAc"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_errors = require('../types/errors.cjs');
|
|
3
|
+
const require_generic = require('./handlers/generic.cjs');
|
|
4
|
+
const require_endpoint = require('./endpoint.cjs');
|
|
5
|
+
let http2 = require("http2");
|
|
6
|
+
http2 = require_rolldown_runtime.__toESM(http2);
|
|
7
|
+
let node_stream = require("node:stream");
|
|
8
|
+
node_stream = require_rolldown_runtime.__toESM(node_stream);
|
|
9
|
+
|
|
10
|
+
//#region src/endpoint/node_endpoint.ts
|
|
11
|
+
var NodeEndpoint = class {
|
|
12
|
+
builder = new require_endpoint.EndpointBuilder();
|
|
13
|
+
bind(definition) {
|
|
14
|
+
this.builder.bind(definition);
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
withIdentityV1(...keys) {
|
|
18
|
+
this.builder.addIdentityKeys(...keys);
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
defaultServiceOptions(options) {
|
|
22
|
+
this.builder.setDefaultServiceOptions(options);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
setLogger(logger) {
|
|
26
|
+
this.builder.setLogger(logger);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
journalValueCodecProvider(codecProvider) {
|
|
30
|
+
this.builder.setJournalValueCodecProvider(codecProvider);
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
http2Handler() {
|
|
34
|
+
return nodeHttp2Handler(this.builder.build());
|
|
35
|
+
}
|
|
36
|
+
listen(port) {
|
|
37
|
+
const endpoint = this.builder.build();
|
|
38
|
+
const actualPort = port ?? parseInt(process.env.PORT ?? "9080");
|
|
39
|
+
endpoint.rlog.info(`Restate SDK started listening on ${actualPort}...`);
|
|
40
|
+
const server = http2.createServer(nodeHttp2Handler(endpoint));
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
let failed = false;
|
|
43
|
+
server.once("error", (e) => {
|
|
44
|
+
failed = true;
|
|
45
|
+
reject(e);
|
|
46
|
+
});
|
|
47
|
+
server.listen(actualPort, () => {
|
|
48
|
+
if (failed) return;
|
|
49
|
+
const address = server.address();
|
|
50
|
+
if (address === null || typeof address === "string") reject(/* @__PURE__ */ new TypeError("endpoint.listen() currently supports only binding to a PORT"));
|
|
51
|
+
else resolve(address.port);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
function nodeHttp2Handler(endpoint) {
|
|
57
|
+
const handler = new require_generic.GenericHandler(endpoint, "BIDI_STREAM", {});
|
|
58
|
+
return (request, response) => {
|
|
59
|
+
(async () => {
|
|
60
|
+
const abortController = new AbortController();
|
|
61
|
+
request.once("aborted", () => {
|
|
62
|
+
abortController.abort();
|
|
63
|
+
});
|
|
64
|
+
request.once("close", () => {
|
|
65
|
+
abortController.abort();
|
|
66
|
+
});
|
|
67
|
+
request.once("error", () => {
|
|
68
|
+
abortController.abort();
|
|
69
|
+
});
|
|
70
|
+
if (request.destroyed || request.aborted) {
|
|
71
|
+
endpoint.rlog.error("Client disconnected");
|
|
72
|
+
abortController.abort();
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const url = request.url;
|
|
76
|
+
const webRequestBody = node_stream.Readable.toWeb(request);
|
|
77
|
+
const resp = await handler.handle({
|
|
78
|
+
url,
|
|
79
|
+
headers: request.headers,
|
|
80
|
+
body: webRequestBody,
|
|
81
|
+
extraArgs: [],
|
|
82
|
+
abortSignal: abortController.signal
|
|
83
|
+
});
|
|
84
|
+
if (response.destroyed) return;
|
|
85
|
+
response.writeHead(resp.statusCode, resp.headers);
|
|
86
|
+
const responseWeb = node_stream.Writable.toWeb(response);
|
|
87
|
+
await resp.body.pipeTo(responseWeb);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
const error = require_errors.ensureError(e);
|
|
90
|
+
const logger = require_generic.tryCreateContextualLogger(endpoint.loggerTransport, request.url, request.headers) ?? endpoint.rlog;
|
|
91
|
+
if (error.name === "AbortError") logger.error("Got abort error from connection: " + error.message + "\nThis might indicate that:\n* The restate-server aborted the connection after hitting the 'abort-timeout'\n* The connection with the restate-server was lost\n\nPlease check the invocation in the Restate UI for more details.");
|
|
92
|
+
else logger.error("Error while handling request: " + (error.stack ?? error.message));
|
|
93
|
+
response.destroy(error);
|
|
94
|
+
abortController.abort();
|
|
95
|
+
}
|
|
96
|
+
})().catch(() => {});
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
exports.NodeEndpoint = NodeEndpoint;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ensureError } from "../types/errors.js";
|
|
2
|
+
import { GenericHandler, tryCreateContextualLogger } from "./handlers/generic.js";
|
|
3
|
+
import { EndpointBuilder } from "./endpoint.js";
|
|
4
|
+
import * as http2 from "http2";
|
|
5
|
+
import { Readable, Writable } from "node:stream";
|
|
6
|
+
|
|
7
|
+
//#region src/endpoint/node_endpoint.ts
|
|
8
|
+
var NodeEndpoint = class {
|
|
9
|
+
builder = new EndpointBuilder();
|
|
10
|
+
bind(definition) {
|
|
11
|
+
this.builder.bind(definition);
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
withIdentityV1(...keys) {
|
|
15
|
+
this.builder.addIdentityKeys(...keys);
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
defaultServiceOptions(options) {
|
|
19
|
+
this.builder.setDefaultServiceOptions(options);
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
setLogger(logger) {
|
|
23
|
+
this.builder.setLogger(logger);
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
journalValueCodecProvider(codecProvider) {
|
|
27
|
+
this.builder.setJournalValueCodecProvider(codecProvider);
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
http2Handler() {
|
|
31
|
+
return nodeHttp2Handler(this.builder.build());
|
|
32
|
+
}
|
|
33
|
+
listen(port) {
|
|
34
|
+
const endpoint = this.builder.build();
|
|
35
|
+
const actualPort = port ?? parseInt(process.env.PORT ?? "9080");
|
|
36
|
+
endpoint.rlog.info(`Restate SDK started listening on ${actualPort}...`);
|
|
37
|
+
const server = http2.createServer(nodeHttp2Handler(endpoint));
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
let failed = false;
|
|
40
|
+
server.once("error", (e) => {
|
|
41
|
+
failed = true;
|
|
42
|
+
reject(e);
|
|
43
|
+
});
|
|
44
|
+
server.listen(actualPort, () => {
|
|
45
|
+
if (failed) return;
|
|
46
|
+
const address = server.address();
|
|
47
|
+
if (address === null || typeof address === "string") reject(/* @__PURE__ */ new TypeError("endpoint.listen() currently supports only binding to a PORT"));
|
|
48
|
+
else resolve(address.port);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
function nodeHttp2Handler(endpoint) {
|
|
54
|
+
const handler = new GenericHandler(endpoint, "BIDI_STREAM", {});
|
|
55
|
+
return (request, response) => {
|
|
56
|
+
(async () => {
|
|
57
|
+
const abortController = new AbortController();
|
|
58
|
+
request.once("aborted", () => {
|
|
59
|
+
abortController.abort();
|
|
60
|
+
});
|
|
61
|
+
request.once("close", () => {
|
|
62
|
+
abortController.abort();
|
|
63
|
+
});
|
|
64
|
+
request.once("error", () => {
|
|
65
|
+
abortController.abort();
|
|
66
|
+
});
|
|
67
|
+
if (request.destroyed || request.aborted) {
|
|
68
|
+
endpoint.rlog.error("Client disconnected");
|
|
69
|
+
abortController.abort();
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const url = request.url;
|
|
73
|
+
const webRequestBody = Readable.toWeb(request);
|
|
74
|
+
const resp = await handler.handle({
|
|
75
|
+
url,
|
|
76
|
+
headers: request.headers,
|
|
77
|
+
body: webRequestBody,
|
|
78
|
+
extraArgs: [],
|
|
79
|
+
abortSignal: abortController.signal
|
|
80
|
+
});
|
|
81
|
+
if (response.destroyed) return;
|
|
82
|
+
response.writeHead(resp.statusCode, resp.headers);
|
|
83
|
+
const responseWeb = Writable.toWeb(response);
|
|
84
|
+
await resp.body.pipeTo(responseWeb);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
const error = ensureError(e);
|
|
87
|
+
const logger = tryCreateContextualLogger(endpoint.loggerTransport, request.url, request.headers) ?? endpoint.rlog;
|
|
88
|
+
if (error.name === "AbortError") logger.error("Got abort error from connection: " + error.message + "\nThis might indicate that:\n* The restate-server aborted the connection after hitting the 'abort-timeout'\n* The connection with the restate-server was lost\n\nPlease check the invocation in the Restate UI for more details.");
|
|
89
|
+
else logger.error("Error while handling request: " + (error.stack ?? error.message));
|
|
90
|
+
response.destroy(error);
|
|
91
|
+
abortController.abort();
|
|
92
|
+
}
|
|
93
|
+
})().catch(() => {});
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
export { NodeEndpoint };
|
|
99
|
+
//# sourceMappingURL=node_endpoint.js.map
|
|
@@ -0,0 +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\";\n\nimport type { Http2ServerRequest, Http2ServerResponse } from \"http2\";\nimport * as http2 from \"http2\";\nimport type { Endpoint } from \"./endpoint.js\";\nimport { EndpointBuilder } from \"./endpoint.js\";\nimport {\n GenericHandler,\n tryCreateContextualLogger,\n} from \"./handlers/generic.js\";\nimport { Readable, Writable } from \"node:stream\";\nimport type { WritableStream } from \"node:stream/web\";\nimport { ensureError } from \"../types/errors.js\";\nimport type { LoggerTransport } from \"../logging/logger_transport.js\";\nimport type { DefaultServiceOptions } from \"../endpoint.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(): (\n request: Http2ServerRequest,\n response: Http2ServerResponse\n ) => void {\n return nodeHttp2Handler(this.builder.build());\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(nodeHttp2Handler(endpoint));\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 nodeHttp2Handler(\n endpoint: Endpoint\n): (request: Http2ServerRequest, response: Http2ServerResponse) => void {\n const handler = new GenericHandler(endpoint, \"BIDI_STREAM\", {});\n\n return (request, response) => {\n (async () => {\n const abortController = new AbortController();\n\n request.once(\"aborted\", () => {\n abortController.abort();\n });\n request.once(\"close\", () => {\n abortController.abort();\n });\n request.once(\"error\", () => {\n abortController.abort();\n });\n\n if (request.destroyed || request.aborted) {\n endpoint.rlog.error(\"Client disconnected\");\n abortController.abort();\n }\n\n try {\n const url = request.url;\n const webRequestBody = Readable.toWeb(request);\n\n const resp = await handler.handle({\n url,\n headers: request.headers,\n body: webRequestBody,\n extraArgs: [],\n abortSignal: abortController.signal,\n });\n\n if (response.destroyed) {\n return;\n }\n\n response.writeHead(resp.statusCode, resp.headers);\n const responseWeb = Writable.toWeb(\n response\n ) as WritableStream<Uint8Array>;\n await resp.body.pipeTo(responseWeb);\n } catch (e) {\n const error = ensureError(e);\n\n const logger =\n tryCreateContextualLogger(\n endpoint.loggerTransport,\n request.url,\n request.headers\n ) ?? endpoint.rlog;\n if (error.name === \"AbortError\") {\n logger.error(\n \"Got abort error from connection: \" +\n error.message +\n \"\\n\" +\n \"This might indicate that:\\n\" +\n \"* The restate-server aborted the connection after hitting the 'abort-timeout'\\n\" +\n \"* The connection with the restate-server was lost\\n\" +\n \"\\n\" +\n \"Please check the invocation in the Restate UI for more details.\"\n );\n } else {\n logger.error(\n \"Error while handling request: \" + (error.stack ?? error.message)\n );\n }\n\n response.destroy(error);\n abortController.abort();\n }\n })().catch(() => {});\n };\n}\n"],"mappings":";;;;;;;AAiCA,IAAa,eAAb,MAAqD;CACnD,AAAQ,UAA2B,IAAI,iBAAiB;CAExD,AAAO,KACL,YAIiB;AACjB,OAAK,QAAQ,KAAK,WAAW;AAC7B,SAAO;;CAGT,AAAO,eAAe,GAAG,MAAiC;AACxD,OAAK,QAAQ,gBAAgB,GAAG,KAAK;AACrC,SAAO;;CAGT,AAAO,sBACL,SACiB;AACjB,OAAK,QAAQ,yBAAyB,QAAQ;AAC9C,SAAO;;CAGT,AAAO,UAAU,QAA0C;AACzD,OAAK,QAAQ,UAAU,OAAO;AAC9B,SAAO;;CAGT,AAAO,0BACL,eACiB;AACjB,OAAK,QAAQ,6BAA6B,cAAc;AACxD,SAAO;;CAGT,eAGU;AACR,SAAO,iBAAiB,KAAK,QAAQ,OAAO,CAAC;;CAG/C,OAAO,MAAgC;EACrC,MAAM,WAAW,KAAK,QAAQ,OAAO;EAErC,MAAM,aAAa,QAAQ,SAAS,QAAQ,IAAI,QAAQ,OAAO;AAC/D,WAAS,KAAK,KAAK,oCAAoC,WAAW,KAAK;EAEvE,MAAM,SAAS,MAAM,aAAa,iBAAiB,SAAS,CAAC;AAE7D,SAAO,IAAI,SAAS,SAAS,WAAW;GACtC,IAAI,SAAS;AACb,UAAO,KAAK,UAAU,MAAa;AACjC,aAAS;AACT,WAAO,EAAE;KACT;AACF,UAAO,OAAO,kBAAkB;AAC9B,QAAI,OACF;IAEF,MAAM,UAAU,OAAO,SAAS;AAChC,QAAI,YAAY,QAAQ,OAAO,YAAY,SACzC,wBACE,IAAI,UACF,8DACD,CACF;QAED,SAAQ,QAAQ,KAAK;KAEvB;IACF;;;AAIN,SAAS,iBACP,UACsE;CACtE,MAAM,UAAU,IAAI,eAAe,UAAU,eAAe,EAAE,CAAC;AAE/D,SAAQ,SAAS,aAAa;AAC5B,GAAC,YAAY;GACX,MAAM,kBAAkB,IAAI,iBAAiB;AAE7C,WAAQ,KAAK,iBAAiB;AAC5B,oBAAgB,OAAO;KACvB;AACF,WAAQ,KAAK,eAAe;AAC1B,oBAAgB,OAAO;KACvB;AACF,WAAQ,KAAK,eAAe;AAC1B,oBAAgB,OAAO;KACvB;AAEF,OAAI,QAAQ,aAAa,QAAQ,SAAS;AACxC,aAAS,KAAK,MAAM,sBAAsB;AAC1C,oBAAgB,OAAO;;AAGzB,OAAI;IACF,MAAM,MAAM,QAAQ;IACpB,MAAM,iBAAiB,SAAS,MAAM,QAAQ;IAE9C,MAAM,OAAO,MAAM,QAAQ,OAAO;KAChC;KACA,SAAS,QAAQ;KACjB,MAAM;KACN,WAAW,EAAE;KACb,aAAa,gBAAgB;KAC9B,CAAC;AAEF,QAAI,SAAS,UACX;AAGF,aAAS,UAAU,KAAK,YAAY,KAAK,QAAQ;IACjD,MAAM,cAAc,SAAS,MAC3B,SACD;AACD,UAAM,KAAK,KAAK,OAAO,YAAY;YAC5B,GAAG;IACV,MAAM,QAAQ,YAAY,EAAE;IAE5B,MAAM,SACJ,0BACE,SAAS,iBACT,QAAQ,KACR,QAAQ,QACT,IAAI,SAAS;AAChB,QAAI,MAAM,SAAS,aACjB,QAAO,MACL,sCACE,MAAM,UACN,mOAMH;QAED,QAAO,MACL,oCAAoC,MAAM,SAAS,MAAM,SAC1D;AAGH,aAAS,QAAQ,MAAM;AACvB,oBAAgB,OAAO;;MAEvB,CAAC,YAAY,GAAG"}
|