@hatchet-dev/typescript-sdk 1.33.2 → 1.34.0-alpha.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/clients/admin/admin-client.d.ts +6 -1
- package/clients/admin/admin-client.js +9 -4
- package/clients/admin/rpc.d.ts +13 -0
- package/clients/admin/rpc.js +23 -0
- package/clients/event/event-client.d.ts +2 -1
- package/clients/event/event-client.js +6 -3
- package/clients/event/rpc.d.ts +7 -0
- package/clients/event/rpc.js +13 -0
- package/clients/hatchet-client/hatchet-logger.js +2 -1
- package/clients/rest/generated/data-contracts.d.ts +2 -0
- package/clients/transport/grpc-target.d.ts +19 -0
- package/clients/transport/grpc-target.js +85 -0
- package/clients/transport/index.d.ts +4 -0
- package/clients/transport/index.js +15 -0
- package/clients/transport/message-bridge.d.ts +32 -0
- package/clients/transport/message-bridge.js +20 -0
- package/clients/transport/node-transport.d.ts +50 -0
- package/clients/transport/node-transport.js +123 -0
- package/clients/transport/transport.d.ts +14 -0
- package/clients/transport/transport.js +24 -0
- package/clients/transport/ts-proto-client.d.ts +41 -0
- package/clients/transport/ts-proto-client.js +143 -0
- package/core/index.d.ts +9 -0
- package/core/index.js +12 -0
- package/dist/check-exports.mjs +171 -0
- package/legacy/legacy-client.d.ts +4 -0
- package/legacy/legacy-client.js +5 -3
- package/package.json +95 -2
- package/protoc-es/dispatcher/dispatcher_pb.d.ts +1357 -0
- package/protoc-es/dispatcher/dispatcher_pb.js +371 -0
- package/protoc-es/events/events_pb.d.ts +294 -0
- package/protoc-es/events/events_pb.js +61 -0
- package/protoc-es/google/rpc/status_pb.d.ts +48 -0
- package/protoc-es/google/rpc/status_pb.js +27 -0
- package/protoc-es/v1/dispatcher_pb.d.ts +676 -0
- package/protoc-es/v1/dispatcher_pb.js +155 -0
- package/protoc-es/v1/shared/condition_pb.d.ts +166 -0
- package/protoc-es/v1/shared/condition_pb.js +68 -0
- package/protoc-es/v1/shared/trigger_pb.d.ts +160 -0
- package/protoc-es/v1/shared/trigger_pb.js +55 -0
- package/protoc-es/v1/workflows_pb.d.ts +995 -0
- package/protoc-es/v1/workflows_pb.js +280 -0
- package/protoc-es/workflows/workflows_pb.d.ts +715 -0
- package/protoc-es/workflows/workflows_pb.js +216 -0
- package/scripts/check-exports.mjs +171 -0
- package/util/grpc-error.d.ts +3 -1
- package/util/grpc-error.js +13 -4
- package/v1/client/admin.d.ts +2 -1
- package/v1/client/admin.js +34 -114
- package/v1/client/client.d.ts +1 -0
- package/v1/client/client.js +8 -5
- package/version.d.ts +1 -1
- package/version.js +1 -1
|
@@ -5,6 +5,7 @@ import { Logger } from '../../util/logger';
|
|
|
5
5
|
import WorkflowRunRef from '../../util/workflow-run-ref';
|
|
6
6
|
import { AdminServiceClient, CreateWorkflowVersionRequest } from '../../protoc/v1/workflows';
|
|
7
7
|
import { Priority, RunsClient, WorkerLabelComparator } from '../../v1';
|
|
8
|
+
import { type Transport } from '../transport';
|
|
8
9
|
import { Api } from '../rest';
|
|
9
10
|
import { WebhookWorkerCreateRequest, WorkflowRunStatus, WorkflowRunStatusList } from '../rest/generated/data-contracts';
|
|
10
11
|
import { RunListenerClient } from '../listeners/run-listener/child-listener-client';
|
|
@@ -50,7 +51,11 @@ export declare class AdminClient {
|
|
|
50
51
|
logger: Logger;
|
|
51
52
|
listenerClient: RunListenerClient;
|
|
52
53
|
workflows: RunsClient | undefined;
|
|
53
|
-
|
|
54
|
+
/**
|
|
55
|
+
* The positional `channel` and `factory` parameters are part of the public constructor
|
|
56
|
+
* signature; the unary calls go over `transport` and the streaming clients own the channel.
|
|
57
|
+
*/
|
|
58
|
+
constructor(config: ClientConfig, _channel: Channel, _factory: ClientFactory, api: Api, tenantId: string, listenerClient: RunListenerClient, workflows: RunsClient | undefined, transport?: Transport);
|
|
54
59
|
/**
|
|
55
60
|
* @deprecated use putWorkflow instead
|
|
56
61
|
*/
|
|
@@ -29,8 +29,9 @@ const hatchet_error_1 = require("../../util/errors/hatchet-error");
|
|
|
29
29
|
const v0_deprecation_warning_1 = require("../../util/v0-deprecation-warning");
|
|
30
30
|
const retrier_1 = require("../../util/retrier");
|
|
31
31
|
const workflow_run_ref_1 = __importDefault(require("../../util/workflow-run-ref"));
|
|
32
|
-
const workflows_2 = require("../../protoc/v1/workflows");
|
|
33
32
|
const apply_namespace_1 = require("../../util/apply-namespace");
|
|
33
|
+
const transport_1 = require("../transport");
|
|
34
|
+
const rpc_1 = require("./rpc");
|
|
34
35
|
function convertDesiredWorkerLabels(labels) {
|
|
35
36
|
return Object.fromEntries(Object.entries(labels).map(([key, label]) => [
|
|
36
37
|
key,
|
|
@@ -44,10 +45,14 @@ function convertDesiredWorkerLabels(labels) {
|
|
|
44
45
|
]));
|
|
45
46
|
}
|
|
46
47
|
class AdminClient {
|
|
47
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The positional `channel` and `factory` parameters are part of the public constructor
|
|
50
|
+
* signature; the unary calls go over `transport` and the streaming clients own the channel.
|
|
51
|
+
*/
|
|
52
|
+
constructor(config, _channel, _factory, api, tenantId, listenerClient, workflows, transport = (0, transport_1.createNodeTransport)(config)) {
|
|
48
53
|
this.config = config;
|
|
49
|
-
this.client =
|
|
50
|
-
this.v1Client =
|
|
54
|
+
this.client = (0, rpc_1.createWorkflowsRpc)(transport);
|
|
55
|
+
this.v1Client = (0, rpc_1.createV1AdminRpc)(transport);
|
|
51
56
|
this.api = api;
|
|
52
57
|
this.tenantId = tenantId;
|
|
53
58
|
this.logger = config.logger(`Admin`, config.log_level);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { WorkflowServiceClient } from '../../protoc/workflows/workflows';
|
|
2
|
+
import { AdminServiceClient } from '../../protoc/v1/workflows';
|
|
3
|
+
import { type Transport } from '../transport';
|
|
4
|
+
/**
|
|
5
|
+
* The `WorkflowService` client, every RPC of the generated `WorkflowServiceClient` interface,
|
|
6
|
+
* served by a Connect client on the given transport.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createWorkflowsRpc(transport: Transport): WorkflowServiceClient;
|
|
9
|
+
/**
|
|
10
|
+
* The v1 `AdminService` client, every RPC of the generated `AdminServiceClient` interface,
|
|
11
|
+
* served by a Connect client on the given transport.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createV1AdminRpc(transport: Transport): AdminServiceClient;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWorkflowsRpc = createWorkflowsRpc;
|
|
4
|
+
exports.createV1AdminRpc = createV1AdminRpc;
|
|
5
|
+
const workflows_1 = require("../../protoc/workflows/workflows");
|
|
6
|
+
const workflows_pb_1 = require("../../protoc-es/workflows/workflows_pb");
|
|
7
|
+
const workflows_2 = require("../../protoc/v1/workflows");
|
|
8
|
+
const workflows_pb_2 = require("../../protoc-es/v1/workflows_pb");
|
|
9
|
+
const transport_1 = require("../transport");
|
|
10
|
+
/**
|
|
11
|
+
* The `WorkflowService` client, every RPC of the generated `WorkflowServiceClient` interface,
|
|
12
|
+
* served by a Connect client on the given transport.
|
|
13
|
+
*/
|
|
14
|
+
function createWorkflowsRpc(transport) {
|
|
15
|
+
return (0, transport_1.createTsProtoClient)(workflows_1.WorkflowServiceDefinition, workflows_pb_1.WorkflowService, transport);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The v1 `AdminService` client, every RPC of the generated `AdminServiceClient` interface,
|
|
19
|
+
* served by a Connect client on the given transport.
|
|
20
|
+
*/
|
|
21
|
+
function createV1AdminRpc(transport) {
|
|
22
|
+
return (0, transport_1.createTsProtoClient)(workflows_2.AdminServiceDefinition, workflows_pb_2.AdminService, transport);
|
|
23
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Channel, ClientFactory } from 'nice-grpc';
|
|
2
2
|
import { EventsServiceClient } from '../../protoc/events/events';
|
|
3
|
+
import { type Transport } from '../transport';
|
|
3
4
|
import { ClientConfig } from '../hatchet-client/client-config';
|
|
4
5
|
import { Logger } from '../../util/logger';
|
|
5
6
|
import { retrier } from '../../util/retrier';
|
|
@@ -28,7 +29,7 @@ export declare class EventClient {
|
|
|
28
29
|
api: HatchetClient['api'];
|
|
29
30
|
tenantId: string;
|
|
30
31
|
logger: Logger;
|
|
31
|
-
constructor(config: ClientConfig,
|
|
32
|
+
constructor(config: ClientConfig, _channel: Channel, _factory: ClientFactory, api: HatchetClient['api'], transport?: Transport);
|
|
32
33
|
/**
|
|
33
34
|
* @important This method is instrumented by HatchetInstrumentor._patchPushEvent.
|
|
34
35
|
* Keep the signature in sync with the instrumentor wrapper.
|
|
@@ -10,7 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.EventClient = exports.LogLevel = void 0;
|
|
13
|
-
const
|
|
13
|
+
const transport_1 = require("../transport");
|
|
14
|
+
const rpc_1 = require("./rpc");
|
|
14
15
|
const hatchet_error_1 = require("../../util/errors/hatchet-error");
|
|
15
16
|
const retrier_1 = require("../../util/retrier");
|
|
16
17
|
const apply_namespace_1 = require("../../util/apply-namespace");
|
|
@@ -30,9 +31,11 @@ function injectSourceInfo(metadata) {
|
|
|
30
31
|
return Object.assign(Object.assign({}, metadata), { hatchet__source_workflow_run_id: ctx.parentId, hatchet__source_step_run_id: ctx.parentTaskRunExternalId });
|
|
31
32
|
}
|
|
32
33
|
class EventClient {
|
|
33
|
-
|
|
34
|
+
// The positional channel and factory parameters are part of the public constructor signature;
|
|
35
|
+
// unary event calls go over the transport and do not use them.
|
|
36
|
+
constructor(config, _channel, _factory, api, transport = (0, transport_1.createNodeTransport)(config)) {
|
|
34
37
|
this.config = config;
|
|
35
|
-
this.client =
|
|
38
|
+
this.client = (0, rpc_1.createEventsRpc)(transport);
|
|
36
39
|
this.logger = config.logger(`Dispatcher`, config.log_level);
|
|
37
40
|
this.retrier = retrier_1.retrier;
|
|
38
41
|
this.api = api;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { EventsServiceClient } from '../../protoc/events/events';
|
|
2
|
+
import { type Transport } from '../transport';
|
|
3
|
+
/**
|
|
4
|
+
* The `EventsService` client, every RPC of the generated `EventsServiceClient` interface,
|
|
5
|
+
* served by a Connect client on the given transport.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createEventsRpc(transport: Transport): EventsServiceClient;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEventsRpc = createEventsRpc;
|
|
4
|
+
const events_1 = require("../../protoc/events/events");
|
|
5
|
+
const events_pb_1 = require("../../protoc-es/events/events_pb");
|
|
6
|
+
const transport_1 = require("../transport");
|
|
7
|
+
/**
|
|
8
|
+
* The `EventsService` client, every RPC of the generated `EventsServiceClient` interface,
|
|
9
|
+
* served by a Connect client on the given transport.
|
|
10
|
+
*/
|
|
11
|
+
function createEventsRpc(transport) {
|
|
12
|
+
return (0, transport_1.createTsProtoClient)(events_1.EventsServiceDefinition, events_pb_1.EventsService, transport);
|
|
13
|
+
}
|
|
@@ -20,7 +20,8 @@ class HatchetLogger {
|
|
|
20
20
|
}
|
|
21
21
|
log(level, message, color = '37') {
|
|
22
22
|
var _a;
|
|
23
|
-
|
|
23
|
+
// OFF disables all logger output, regardless of message level.
|
|
24
|
+
if (this.logLevel !== 'OFF' && logger_1.LogLevelEnum[level] >= logger_1.LogLevelEnum[this.logLevel]) {
|
|
24
25
|
const time = new Date().toLocaleString('en-US', {
|
|
25
26
|
month: '2-digit',
|
|
26
27
|
day: '2-digit',
|
|
@@ -900,6 +900,8 @@ export interface Tenant {
|
|
|
900
900
|
serverUrl?: string;
|
|
901
901
|
/** Control-plane shard region for the tenant (e.g. aws:us-west-2). */
|
|
902
902
|
region?: string;
|
|
903
|
+
/** The data retention period for the tenant, e.g. 720h. */
|
|
904
|
+
dataRetentionPeriod?: string;
|
|
903
905
|
}
|
|
904
906
|
export interface V1EventWorkflowRunSummary {
|
|
905
907
|
/**
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a gRPC target points: the host and port to dial and the `:authority` grpc-js sends for
|
|
3
|
+
* it, which is the target's path as written (the first address for the IP schemes).
|
|
4
|
+
*/
|
|
5
|
+
export interface GrpcTarget {
|
|
6
|
+
host: string;
|
|
7
|
+
port: number;
|
|
8
|
+
authority: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parses the target forms grpc-js accepts for `host_port`, so the unary transport dials the
|
|
12
|
+
* same endpoint the streaming channel does: `host:port`, `dns:host:port`, `dns:///host:port`,
|
|
13
|
+
* `ipv4:address:port` and `ipv6:[address]:port` (the first address of an address list). A
|
|
14
|
+
* missing port is grpc-js's default, 443. `unix:` sockets and a `dns://nameserver/` authority
|
|
15
|
+
* have no HTTP/2 equivalent here and are refused with a clear error.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseGrpcTarget(target: string): GrpcTarget;
|
|
18
|
+
/** The base URL Connect dials for a target: an IPv6 host is bracketed as a URL requires. */
|
|
19
|
+
export declare function grpcTargetBaseUrl(target: GrpcTarget, protocol: 'http' | 'https'): string;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseGrpcTarget = parseGrpcTarget;
|
|
4
|
+
exports.grpcTargetBaseUrl = grpcTargetBaseUrl;
|
|
5
|
+
const net_1 = require("net");
|
|
6
|
+
/** The port grpc-js dials when a target names none. */
|
|
7
|
+
const DEFAULT_PORT = 443;
|
|
8
|
+
/*
|
|
9
|
+
* grpc-js parses a target as `scheme:` `//authority/` `path`, all but the path optional; a
|
|
10
|
+
* scheme it has no resolver for (which is what `host:port` looks like) makes the whole string a
|
|
11
|
+
* `dns` path.
|
|
12
|
+
*/
|
|
13
|
+
const URI_REGEX = /^(?:([A-Za-z0-9+.-]+):)?(?:\/\/([^/]*)\/)?(.+)$/;
|
|
14
|
+
const RESOLVER_SCHEMES = new Set(['dns', 'ipv4', 'ipv6', 'unix']);
|
|
15
|
+
/**
|
|
16
|
+
* Parses the target forms grpc-js accepts for `host_port`, so the unary transport dials the
|
|
17
|
+
* same endpoint the streaming channel does: `host:port`, `dns:host:port`, `dns:///host:port`,
|
|
18
|
+
* `ipv4:address:port` and `ipv6:[address]:port` (the first address of an address list). A
|
|
19
|
+
* missing port is grpc-js's default, 443. `unix:` sockets and a `dns://nameserver/` authority
|
|
20
|
+
* have no HTTP/2 equivalent here and are refused with a clear error.
|
|
21
|
+
*/
|
|
22
|
+
function parseGrpcTarget(target) {
|
|
23
|
+
var _a;
|
|
24
|
+
const match = URI_REGEX.exec(target);
|
|
25
|
+
if (!match) {
|
|
26
|
+
throw new Error(`host_port ${JSON.stringify(target)} is not a gRPC target`);
|
|
27
|
+
}
|
|
28
|
+
const [, rawScheme, authority, rawPath] = match;
|
|
29
|
+
const known = rawScheme !== undefined && RESOLVER_SCHEMES.has(rawScheme);
|
|
30
|
+
const scheme = known ? rawScheme : 'dns';
|
|
31
|
+
const path = known ? rawPath : target;
|
|
32
|
+
if (scheme === 'unix') {
|
|
33
|
+
throw new Error(`host_port ${JSON.stringify(target)}: unix domain socket targets are not supported by the unary transport; use a host:port target`);
|
|
34
|
+
}
|
|
35
|
+
if (known && authority) {
|
|
36
|
+
throw new Error(`host_port ${JSON.stringify(target)}: a target-specific DNS server is not supported by the unary transport; use dns:///host:port`);
|
|
37
|
+
}
|
|
38
|
+
const address = scheme === 'dns' ? path : path.split(',')[0];
|
|
39
|
+
const hostPort = splitHostPort(address);
|
|
40
|
+
if (!hostPort) {
|
|
41
|
+
throw new Error(`host_port ${JSON.stringify(target)} is not a valid host and port`);
|
|
42
|
+
}
|
|
43
|
+
if (scheme === 'ipv4' && !(0, net_1.isIPv4)(hostPort.host)) {
|
|
44
|
+
throw new Error(`host_port ${JSON.stringify(target)} is not an IPv4 address`);
|
|
45
|
+
}
|
|
46
|
+
if (scheme === 'ipv6' && !(0, net_1.isIPv6)(hostPort.host)) {
|
|
47
|
+
throw new Error(`host_port ${JSON.stringify(target)} is not an IPv6 address`);
|
|
48
|
+
}
|
|
49
|
+
return { host: hostPort.host, port: (_a = hostPort.port) !== null && _a !== void 0 ? _a : DEFAULT_PORT, authority: address };
|
|
50
|
+
}
|
|
51
|
+
/** The base URL Connect dials for a target: an IPv6 host is bracketed as a URL requires. */
|
|
52
|
+
function grpcTargetBaseUrl(target, protocol) {
|
|
53
|
+
const host = target.host.includes(':') ? `[${target.host}]` : target.host;
|
|
54
|
+
return `${protocol}://${host}:${target.port}`;
|
|
55
|
+
}
|
|
56
|
+
/*
|
|
57
|
+
* grpc-js's host:port split: a bracketed host is IPv6 with an optional `:port`, exactly one
|
|
58
|
+
* colon separates a host from a numeric port, and any other number of colons is a bare IPv6
|
|
59
|
+
* address with no port.
|
|
60
|
+
*/
|
|
61
|
+
function splitHostPort(address) {
|
|
62
|
+
if (address.startsWith('[')) {
|
|
63
|
+
const end = address.indexOf(']');
|
|
64
|
+
if (end === -1) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const host = address.slice(1, end);
|
|
68
|
+
if (!host.includes(':')) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const rest = address.slice(end + 1);
|
|
72
|
+
if (rest === '') {
|
|
73
|
+
return { host };
|
|
74
|
+
}
|
|
75
|
+
if (rest.startsWith(':') && /^\d+$/.test(rest.slice(1))) {
|
|
76
|
+
return { host, port: Number(rest.slice(1)) };
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const parts = address.split(':');
|
|
81
|
+
if (parts.length === 2) {
|
|
82
|
+
return /^\d+$/.test(parts[1]) ? { host: parts[0], port: Number(parts[1]) } : null;
|
|
83
|
+
}
|
|
84
|
+
return { host: address };
|
|
85
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createAuthInterceptor, type Transport } from './transport';
|
|
2
|
+
export { createNodeTransport } from './node-transport';
|
|
3
|
+
export { fromProtobufEs, toProtobufEs, type DeepPartial, type TsProtoCodec, } from './message-bridge';
|
|
4
|
+
export { createTsProtoClient, headersToMetadata, metadataToHeaders, toConnectCallOptions, type UnaryCallOptions, type UnaryCallOptionsExt, } from './ts-proto-client';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toConnectCallOptions = exports.metadataToHeaders = exports.headersToMetadata = exports.createTsProtoClient = exports.toProtobufEs = exports.fromProtobufEs = exports.createNodeTransport = exports.createAuthInterceptor = void 0;
|
|
4
|
+
var transport_1 = require("./transport");
|
|
5
|
+
Object.defineProperty(exports, "createAuthInterceptor", { enumerable: true, get: function () { return transport_1.createAuthInterceptor; } });
|
|
6
|
+
var node_transport_1 = require("./node-transport");
|
|
7
|
+
Object.defineProperty(exports, "createNodeTransport", { enumerable: true, get: function () { return node_transport_1.createNodeTransport; } });
|
|
8
|
+
var message_bridge_1 = require("./message-bridge");
|
|
9
|
+
Object.defineProperty(exports, "fromProtobufEs", { enumerable: true, get: function () { return message_bridge_1.fromProtobufEs; } });
|
|
10
|
+
Object.defineProperty(exports, "toProtobufEs", { enumerable: true, get: function () { return message_bridge_1.toProtobufEs; } });
|
|
11
|
+
var ts_proto_client_1 = require("./ts-proto-client");
|
|
12
|
+
Object.defineProperty(exports, "createTsProtoClient", { enumerable: true, get: function () { return ts_proto_client_1.createTsProtoClient; } });
|
|
13
|
+
Object.defineProperty(exports, "headersToMetadata", { enumerable: true, get: function () { return ts_proto_client_1.headersToMetadata; } });
|
|
14
|
+
Object.defineProperty(exports, "metadataToHeaders", { enumerable: true, get: function () { return ts_proto_client_1.metadataToHeaders; } });
|
|
15
|
+
Object.defineProperty(exports, "toConnectCallOptions", { enumerable: true, get: function () { return ts_proto_client_1.toConnectCallOptions; } });
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type DescMessage, type MessageShape } from '@bufbuild/protobuf';
|
|
2
|
+
type Builtin = Date | ((...args: never[]) => unknown) | Uint8Array | string | number | boolean | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* The partial message shape the SDK's clients accept, matching the `DeepPartial` type each
|
|
5
|
+
* `src/protoc` module generates for its own messages.
|
|
6
|
+
*/
|
|
7
|
+
export type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
|
|
8
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
9
|
+
} : Partial<T>;
|
|
10
|
+
/**
|
|
11
|
+
* The part of a `ts-proto` message codec (what `src/protoc` exports under a message's name)
|
|
12
|
+
* the bridge needs: the wire codec and the partial-to-full normalizer.
|
|
13
|
+
*/
|
|
14
|
+
export interface TsProtoCodec<T> {
|
|
15
|
+
encode(message: T): {
|
|
16
|
+
finish(): Uint8Array;
|
|
17
|
+
};
|
|
18
|
+
decode(input: Uint8Array): T;
|
|
19
|
+
fromPartial(object: DeepPartial<T>): T;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Converts a `ts-proto` message to the protobuf-es message a Connect client sends. The two
|
|
23
|
+
* bindings share the wire format, so an encode/decode round trip is an exact translation and
|
|
24
|
+
* the SDK keeps its `ts-proto` types as the public request types.
|
|
25
|
+
*/
|
|
26
|
+
export declare function toProtobufEs<T, S extends DescMessage>(schema: S, codec: TsProtoCodec<T>, message: DeepPartial<T>): MessageShape<S>;
|
|
27
|
+
/**
|
|
28
|
+
* Converts a protobuf-es message a Connect client received to the `ts-proto` message callers
|
|
29
|
+
* expect, the inverse of `toProtobufEs`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function fromProtobufEs<T, S extends DescMessage>(codec: TsProtoCodec<T>, schema: S, message: MessageShape<S>): T;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toProtobufEs = toProtobufEs;
|
|
4
|
+
exports.fromProtobufEs = fromProtobufEs;
|
|
5
|
+
const protobuf_1 = require("@bufbuild/protobuf");
|
|
6
|
+
/**
|
|
7
|
+
* Converts a `ts-proto` message to the protobuf-es message a Connect client sends. The two
|
|
8
|
+
* bindings share the wire format, so an encode/decode round trip is an exact translation and
|
|
9
|
+
* the SDK keeps its `ts-proto` types as the public request types.
|
|
10
|
+
*/
|
|
11
|
+
function toProtobufEs(schema, codec, message) {
|
|
12
|
+
return (0, protobuf_1.fromBinary)(schema, codec.encode(codec.fromPartial(message)).finish());
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Converts a protobuf-es message a Connect client received to the `ts-proto` message callers
|
|
16
|
+
* expect, the inverse of `toProtobufEs`.
|
|
17
|
+
*/
|
|
18
|
+
function fromProtobufEs(codec, schema, message) {
|
|
19
|
+
return codec.decode((0, protobuf_1.toBinary)(schema, message));
|
|
20
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { SecureClientSessionOptions } from 'http2';
|
|
2
|
+
import { type GrpcTransportOptions } from '@connectrpc/connect-node';
|
|
3
|
+
import type { ClientConfig } from '../hatchet-client/client-config';
|
|
4
|
+
import { type Transport } from './transport';
|
|
5
|
+
/**
|
|
6
|
+
* The largest message size Connect can enforce (a 32-bit length prefix). The config schema
|
|
7
|
+
* accepts any positive integer, as grpc-js does, so a larger configured limit is clamped to it
|
|
8
|
+
* rather than refused at the first call.
|
|
9
|
+
*/
|
|
10
|
+
export declare const MAX_MESSAGE_BYTES = 4294967295;
|
|
11
|
+
/**
|
|
12
|
+
* The connection settings the `nice-grpc` channel uses (`grpc.keepalive_time_ms`,
|
|
13
|
+
* `grpc.keepalive_timeout_ms`, `grpc.keepalive_permit_without_calls` and
|
|
14
|
+
* `grpc.client_idle_timeout_ms` in `util/grpc-helpers.ts`), so a unary connection is kept alive,
|
|
15
|
+
* given up on and idled exactly as a streaming one.
|
|
16
|
+
*/
|
|
17
|
+
export declare const SESSION_OPTIONS: {
|
|
18
|
+
readonly pingIntervalMs: number;
|
|
19
|
+
readonly pingTimeoutMs: number;
|
|
20
|
+
readonly pingIdleConnection: true;
|
|
21
|
+
readonly idleConnectionTimeoutMs: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Builds the TLS session options for the engine connection from the client's `tls_config`:
|
|
25
|
+
* `none` means plaintext, `tls` verifies the server against the trusted roots, and `mtls` (the
|
|
26
|
+
* default when no strategy is set) additionally presents `cert_file` and `key_file`.
|
|
27
|
+
* `server_name` overrides the hostname used for SNI and certificate verification, which is what
|
|
28
|
+
* lets a client reach an engine through an address its certificate does not name.
|
|
29
|
+
*
|
|
30
|
+
* The roots and cipher suites follow grpc-js, which the streaming channel uses: `ca_file`, else
|
|
31
|
+
* the bundle `GRPC_DEFAULT_SSL_ROOTS_FILE_PATH` names, else the platform roots; and
|
|
32
|
+
* `GRPC_SSL_CIPHER_SUITES` when set.
|
|
33
|
+
*/
|
|
34
|
+
export declare function tlsSessionOptions(tls: ClientConfig['tls_config']): SecureClientSessionOptions;
|
|
35
|
+
/**
|
|
36
|
+
* Creates the Node transport: the gRPC protocol over HTTP/2 (`createGrpcTransport` speaks
|
|
37
|
+
* nothing else), the same wire the SDK's `nice-grpc` clients speak, so an engine sees no
|
|
38
|
+
* difference between the two. The bearer token from the config is attached to every call and
|
|
39
|
+
* the connection is kept alive with pings the way the `nice-grpc` channel is.
|
|
40
|
+
*
|
|
41
|
+
* The transport is built on the first call so that constructing a client reads no TLS files;
|
|
42
|
+
* a client whose unary RPCs are never used never touches them.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createNodeTransport(config: ClientConfig): Transport;
|
|
45
|
+
/**
|
|
46
|
+
* The options `createNodeTransport` builds its transport from, derived from the client config.
|
|
47
|
+
* The session manager is built here from `nodeOptions` and the session settings; Connect takes
|
|
48
|
+
* the connection from it and leaves those transport-level copies as the record of what it uses.
|
|
49
|
+
*/
|
|
50
|
+
export declare function nodeTransportOptions(config: ClientConfig): GrpcTransportOptions;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SESSION_OPTIONS = exports.MAX_MESSAGE_BYTES = void 0;
|
|
4
|
+
exports.tlsSessionOptions = tlsSessionOptions;
|
|
5
|
+
exports.createNodeTransport = createNodeTransport;
|
|
6
|
+
exports.nodeTransportOptions = nodeTransportOptions;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const connect_node_1 = require("@connectrpc/connect-node");
|
|
9
|
+
const grpc_target_1 = require("./grpc-target");
|
|
10
|
+
const transport_1 = require("./transport");
|
|
11
|
+
const DEFAULT_MAX_MESSAGE_BYTES = 4 * 1024 * 1024;
|
|
12
|
+
/**
|
|
13
|
+
* The largest message size Connect can enforce (a 32-bit length prefix). The config schema
|
|
14
|
+
* accepts any positive integer, as grpc-js does, so a larger configured limit is clamped to it
|
|
15
|
+
* rather than refused at the first call.
|
|
16
|
+
*/
|
|
17
|
+
exports.MAX_MESSAGE_BYTES = 0xffffffff;
|
|
18
|
+
function messageLimit(configured) {
|
|
19
|
+
return Math.min(configured !== null && configured !== void 0 ? configured : DEFAULT_MAX_MESSAGE_BYTES, exports.MAX_MESSAGE_BYTES);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The connection settings the `nice-grpc` channel uses (`grpc.keepalive_time_ms`,
|
|
23
|
+
* `grpc.keepalive_timeout_ms`, `grpc.keepalive_permit_without_calls` and
|
|
24
|
+
* `grpc.client_idle_timeout_ms` in `util/grpc-helpers.ts`), so a unary connection is kept alive,
|
|
25
|
+
* given up on and idled exactly as a streaming one.
|
|
26
|
+
*/
|
|
27
|
+
exports.SESSION_OPTIONS = {
|
|
28
|
+
pingIntervalMs: 10 * 1000,
|
|
29
|
+
pingTimeoutMs: 60 * 1000,
|
|
30
|
+
pingIdleConnection: true,
|
|
31
|
+
idleConnectionTimeoutMs: 60 * 1000,
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Builds the TLS session options for the engine connection from the client's `tls_config`:
|
|
35
|
+
* `none` means plaintext, `tls` verifies the server against the trusted roots, and `mtls` (the
|
|
36
|
+
* default when no strategy is set) additionally presents `cert_file` and `key_file`.
|
|
37
|
+
* `server_name` overrides the hostname used for SNI and certificate verification, which is what
|
|
38
|
+
* lets a client reach an engine through an address its certificate does not name.
|
|
39
|
+
*
|
|
40
|
+
* The roots and cipher suites follow grpc-js, which the streaming channel uses: `ca_file`, else
|
|
41
|
+
* the bundle `GRPC_DEFAULT_SSL_ROOTS_FILE_PATH` names, else the platform roots; and
|
|
42
|
+
* `GRPC_SSL_CIPHER_SUITES` when set.
|
|
43
|
+
*/
|
|
44
|
+
function tlsSessionOptions(tls) {
|
|
45
|
+
// grpc-js verifies the peer regardless of NODE_TLS_REJECT_UNAUTHORIZED, which is Node's
|
|
46
|
+
// process-wide switch; set explicitly, the switch cannot weaken this connection either.
|
|
47
|
+
const options = { rejectUnauthorized: true };
|
|
48
|
+
const rootsFile = tls.ca_file || process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH;
|
|
49
|
+
if (rootsFile) {
|
|
50
|
+
options.ca = (0, fs_1.readFileSync)(rootsFile);
|
|
51
|
+
}
|
|
52
|
+
const ciphers = process.env.GRPC_SSL_CIPHER_SUITES;
|
|
53
|
+
if (ciphers) {
|
|
54
|
+
options.ciphers = ciphers;
|
|
55
|
+
}
|
|
56
|
+
if (tls.tls_strategy !== 'tls') {
|
|
57
|
+
// grpc-js refuses half a client identity with these messages rather than connecting without
|
|
58
|
+
// one, which an endpoint that does not require client certificates would silently accept.
|
|
59
|
+
if (tls.key_file && !tls.cert_file) {
|
|
60
|
+
throw new Error('Private key must be given with accompanying certificate chain');
|
|
61
|
+
}
|
|
62
|
+
if (tls.cert_file && !tls.key_file) {
|
|
63
|
+
throw new Error('Certificate chain must be given with accompanying private key');
|
|
64
|
+
}
|
|
65
|
+
if (tls.key_file && tls.cert_file) {
|
|
66
|
+
options.key = (0, fs_1.readFileSync)(tls.key_file);
|
|
67
|
+
options.cert = (0, fs_1.readFileSync)(tls.cert_file);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (tls.server_name) {
|
|
71
|
+
options.servername = tls.server_name;
|
|
72
|
+
}
|
|
73
|
+
return options;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Creates the Node transport: the gRPC protocol over HTTP/2 (`createGrpcTransport` speaks
|
|
77
|
+
* nothing else), the same wire the SDK's `nice-grpc` clients speak, so an engine sees no
|
|
78
|
+
* difference between the two. The bearer token from the config is attached to every call and
|
|
79
|
+
* the connection is kept alive with pings the way the `nice-grpc` channel is.
|
|
80
|
+
*
|
|
81
|
+
* The transport is built on the first call so that constructing a client reads no TLS files;
|
|
82
|
+
* a client whose unary RPCs are never used never touches them.
|
|
83
|
+
*/
|
|
84
|
+
function createNodeTransport(config) {
|
|
85
|
+
let transport;
|
|
86
|
+
const get = () => {
|
|
87
|
+
if (!transport) {
|
|
88
|
+
transport = (0, connect_node_1.createGrpcTransport)(nodeTransportOptions(config));
|
|
89
|
+
}
|
|
90
|
+
return transport;
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
unary: (...args) => get().unary(...args),
|
|
94
|
+
stream: (...args) => get().stream(...args),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The options `createNodeTransport` builds its transport from, derived from the client config.
|
|
99
|
+
* The session manager is built here from `nodeOptions` and the session settings; Connect takes
|
|
100
|
+
* the connection from it and leaves those transport-level copies as the record of what it uses.
|
|
101
|
+
*/
|
|
102
|
+
function nodeTransportOptions(config) {
|
|
103
|
+
const insecure = config.tls_config.tls_strategy === 'none';
|
|
104
|
+
const target = (0, grpc_target_1.parseGrpcTarget)(config.host_port);
|
|
105
|
+
const baseUrl = (0, grpc_target_1.grpcTargetBaseUrl)(target, insecure ? 'http' : 'https');
|
|
106
|
+
const nodeOptions = insecure ? undefined : tlsSessionOptions(config.tls_config);
|
|
107
|
+
return Object.assign({ baseUrl,
|
|
108
|
+
nodeOptions, sessionManager: createSessionManager(baseUrl, target.authority, nodeOptions), interceptors: [(0, transport_1.createAuthInterceptor)(config.token)], sendCompression: connect_node_1.compressionGzip, readMaxBytes: messageLimit(config.grpc_max_recv_message_length), writeMaxBytes: messageLimit(config.grpc_max_send_message_length) }, exports.SESSION_OPTIONS);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The HTTP/2 session for the transport, sending `:authority` as grpc-js does: the target as
|
|
112
|
+
* written, so `server_name` changes only SNI and certificate verification. Node otherwise
|
|
113
|
+
* derives the authority from `servername` when it is set, which would also change the virtual
|
|
114
|
+
* host a proxy in front of the engine routes on.
|
|
115
|
+
*/
|
|
116
|
+
function createSessionManager(baseUrl, authority, nodeOptions) {
|
|
117
|
+
const manager = new connect_node_1.Http2SessionManager(baseUrl, exports.SESSION_OPTIONS, nodeOptions);
|
|
118
|
+
return {
|
|
119
|
+
authority: manager.authority,
|
|
120
|
+
request: (method, path, headers, options) => manager.request(method, path, Object.assign({ ':authority': authority }, headers), options),
|
|
121
|
+
notifyResponseByteRead: (stream) => manager.notifyResponseByteRead(stream),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Interceptor, Transport } from '@connectrpc/connect';
|
|
2
|
+
/**
|
|
3
|
+
* The seam every Connect-backed client calls through. A transport carries the protocol
|
|
4
|
+
* (gRPC over HTTP/2 in Node, Connect over fetch elsewhere), the connection settings and the
|
|
5
|
+
* interceptors that apply to every call.
|
|
6
|
+
*/
|
|
7
|
+
export type { Transport };
|
|
8
|
+
/**
|
|
9
|
+
* Sets the bearer token the engine authenticates every call with. The transport applies it to
|
|
10
|
+
* each request, so callers never pass credentials per call. A token that cannot be carried in a
|
|
11
|
+
* header is refused here with a fixed message, so the token's value never reaches a log or an
|
|
12
|
+
* error.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createAuthInterceptor(token: string): Interceptor;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAuthInterceptor = createAuthInterceptor;
|
|
4
|
+
/**
|
|
5
|
+
* The characters a token may contain and still travel in an HTTP header: the printable ASCII
|
|
6
|
+
* range, which is also what grpc-js accepts in metadata. Anything else would make the header
|
|
7
|
+
* layer reject the request with an error quoting the token.
|
|
8
|
+
*/
|
|
9
|
+
const HEADER_SAFE = /^[ -~]*$/;
|
|
10
|
+
/**
|
|
11
|
+
* Sets the bearer token the engine authenticates every call with. The transport applies it to
|
|
12
|
+
* each request, so callers never pass credentials per call. A token that cannot be carried in a
|
|
13
|
+
* header is refused here with a fixed message, so the token's value never reaches a log or an
|
|
14
|
+
* error.
|
|
15
|
+
*/
|
|
16
|
+
function createAuthInterceptor(token) {
|
|
17
|
+
if (!HEADER_SAFE.test(token)) {
|
|
18
|
+
throw new Error('The Hatchet client token contains characters that cannot be sent in an HTTP header; check HATCHET_CLIENT_TOKEN for stray whitespace or line breaks');
|
|
19
|
+
}
|
|
20
|
+
return (next) => (req) => {
|
|
21
|
+
req.header.set('authorization', `Bearer ${token}`);
|
|
22
|
+
return next(req);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { DescService } from '@bufbuild/protobuf';
|
|
2
|
+
import { type CallOptions as ConnectCallOptions, type Transport } from '@connectrpc/connect';
|
|
3
|
+
import type { Client, TsProtoServiceDefinition } from 'nice-grpc';
|
|
4
|
+
import { Metadata, type CallOptions } from 'nice-grpc-common';
|
|
5
|
+
/**
|
|
6
|
+
* The per-call options the Connect-backed clients accept: `nice-grpc`'s `CallOptions`
|
|
7
|
+
* (`signal`, `metadata`, `onHeader`, `onTrailer`) plus the `deadline` its deadline middleware
|
|
8
|
+
* adds, an absolute time as a `Date` or epoch milliseconds.
|
|
9
|
+
*/
|
|
10
|
+
export interface UnaryCallOptionsExt {
|
|
11
|
+
deadline?: Date | number;
|
|
12
|
+
}
|
|
13
|
+
export type UnaryCallOptions = CallOptions & UnaryCallOptionsExt;
|
|
14
|
+
/**
|
|
15
|
+
* Builds the client a `ts-proto` service definition describes, with every method served by a
|
|
16
|
+
* Connect client for the matching protobuf-es service on `transport`. The result has the exact
|
|
17
|
+
* surface `nice-grpc`'s `ClientFactory.create(definition, channel)` produced: every RPC of the
|
|
18
|
+
* service as `(request, options?) => Promise<response>` with the SDK's `ts-proto` message types,
|
|
19
|
+
* so a caller holding one of the public client properties sees no difference.
|
|
20
|
+
*
|
|
21
|
+
* Both bindings are generated from the same proto, so a method's client name is the same in
|
|
22
|
+
* each and the protobuf-es descriptor can be looked up by it.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createTsProtoClient<Def extends TsProtoServiceDefinition>(definition: Def, service: DescService, transport: Transport): Client<Def, UnaryCallOptionsExt>;
|
|
25
|
+
/**
|
|
26
|
+
* Translates `nice-grpc` call options to Connect's: the signal passes through, an absolute
|
|
27
|
+
* deadline becomes the remaining time, request metadata becomes headers and the header and
|
|
28
|
+
* trailer callbacks receive `Metadata` built from the response headers.
|
|
29
|
+
*/
|
|
30
|
+
export declare function toConnectCallOptions(options?: UnaryCallOptions): ConnectCallOptions | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* gRPC metadata as HTTP headers: binary values (keys ending in `-bin`) are base64 encoded,
|
|
33
|
+
* which is how they travel on the wire in every gRPC implementation.
|
|
34
|
+
*/
|
|
35
|
+
export declare function metadataToHeaders(metadata: Metadata): Headers;
|
|
36
|
+
/**
|
|
37
|
+
* Response headers as gRPC metadata, the inverse of `metadataToHeaders`. `Headers` joins
|
|
38
|
+
* repeated values with a comma, so a binary header is split back into its values before each
|
|
39
|
+
* is decoded.
|
|
40
|
+
*/
|
|
41
|
+
export declare function headersToMetadata(headers: Headers): Metadata;
|