@temporalio/envconfig 1.13.2
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.md +23 -0
- package/README.md +5 -0
- package/lib/envconfig-toml.d.ts +57 -0
- package/lib/envconfig-toml.js +279 -0
- package/lib/envconfig-toml.js.map +1 -0
- package/lib/envconfig.d.ts +9 -0
- package/lib/envconfig.js +63 -0
- package/lib/envconfig.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +17 -0
- package/lib/index.js.map +1 -0
- package/lib/types.d.ts +111 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/utils.d.ts +48 -0
- package/lib/utils.js +164 -0
- package/lib/utils.js.map +1 -0
- package/package.json +43 -0
- package/src/envconfig-toml.ts +341 -0
- package/src/envconfig.ts +78 -0
- package/src/index.ts +20 -0
- package/src/types.ts +116 -0
- package/src/utils.ts +172 -0
package/lib/utils.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadConfigData = loadConfigData;
|
|
4
|
+
exports.fromTomlProfile = fromTomlProfile;
|
|
5
|
+
exports.toTomlProfile = toTomlProfile;
|
|
6
|
+
exports.fromTomlTLS = fromTomlTLS;
|
|
7
|
+
exports.toTomlTLS = toTomlTLS;
|
|
8
|
+
exports.fromTomlConfig = fromTomlConfig;
|
|
9
|
+
exports.toTomlConfig = toTomlConfig;
|
|
10
|
+
exports.toPathAndData = toPathAndData;
|
|
11
|
+
const fs_1 = require("fs");
|
|
12
|
+
const internal_workflow_1 = require("@temporalio/common/lib/internal-workflow");
|
|
13
|
+
const encoding_1 = require("@temporalio/common/lib/encoding");
|
|
14
|
+
const envconfig_toml_1 = require("./envconfig-toml");
|
|
15
|
+
/**
|
|
16
|
+
* Loads configuration data from a {@link ConfigDataSource} and returns it as a Uint8Array.
|
|
17
|
+
*
|
|
18
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
19
|
+
*/
|
|
20
|
+
function loadConfigData(source) {
|
|
21
|
+
if (!source)
|
|
22
|
+
return undefined;
|
|
23
|
+
if ('path' in source) {
|
|
24
|
+
return Uint8Array.from((0, fs_1.readFileSync)(source.path));
|
|
25
|
+
}
|
|
26
|
+
return typeof source.data === 'string' ? (0, encoding_1.encode)(source.data) : source.data;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Converts a TOML profile structure to a {@link ClientConfigProfile}.
|
|
30
|
+
*
|
|
31
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
32
|
+
*/
|
|
33
|
+
function fromTomlProfile(tomlProfile) {
|
|
34
|
+
let grpcMeta = undefined;
|
|
35
|
+
if (tomlProfile.grpc_meta !== undefined) {
|
|
36
|
+
grpcMeta = {};
|
|
37
|
+
// Normalize GRPC meta keys.
|
|
38
|
+
for (const [key, value] of Object.entries(tomlProfile.grpc_meta)) {
|
|
39
|
+
grpcMeta[(0, envconfig_toml_1.normalizeGrpcMetaKey)(key)] = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const profile = {
|
|
43
|
+
address: tomlProfile.address,
|
|
44
|
+
namespace: tomlProfile.namespace,
|
|
45
|
+
apiKey: tomlProfile.api_key,
|
|
46
|
+
tls: fromTomlTLS(tomlProfile.tls),
|
|
47
|
+
grpcMeta,
|
|
48
|
+
};
|
|
49
|
+
return (0, internal_workflow_1.filterNullAndUndefined)(profile);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Converts a {@link ClientConfigProfile} to a TOML profile structure.
|
|
53
|
+
*
|
|
54
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
55
|
+
*/
|
|
56
|
+
function toTomlProfile(profile) {
|
|
57
|
+
let grpc_meta = undefined;
|
|
58
|
+
if (profile.grpcMeta !== undefined) {
|
|
59
|
+
grpc_meta = {};
|
|
60
|
+
// Normalize GRPC meta keys.
|
|
61
|
+
for (const [key, value] of Object.entries(profile.grpcMeta)) {
|
|
62
|
+
grpc_meta[(0, envconfig_toml_1.normalizeGrpcMetaKey)(key)] = value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const tomlProfile = {
|
|
66
|
+
address: profile.address,
|
|
67
|
+
namespace: profile.namespace,
|
|
68
|
+
api_key: profile.apiKey,
|
|
69
|
+
tls: toTomlTLS(profile.tls),
|
|
70
|
+
grpc_meta,
|
|
71
|
+
};
|
|
72
|
+
return (0, internal_workflow_1.filterNullAndUndefined)(tomlProfile);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Converts a TOML TLS configuration structure to a {@link ClientConfigTLS}.
|
|
76
|
+
*
|
|
77
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
78
|
+
*/
|
|
79
|
+
function fromTomlTLS(tomlTLS) {
|
|
80
|
+
if (tomlTLS === undefined) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const clientConfigTLS = {
|
|
84
|
+
disabled: tomlTLS.disabled,
|
|
85
|
+
serverName: tomlTLS.server_name,
|
|
86
|
+
clientCert: toConfigDataSource(tomlTLS.client_cert_path, tomlTLS.client_cert_data, 'client_cert'),
|
|
87
|
+
clientKey: toConfigDataSource(tomlTLS.client_key_path, tomlTLS.client_key_data, 'client_key'),
|
|
88
|
+
serverCACert: toConfigDataSource(tomlTLS.server_ca_cert_path, tomlTLS.server_ca_cert_data, 'server_ca_cert'),
|
|
89
|
+
};
|
|
90
|
+
return (0, internal_workflow_1.filterNullAndUndefined)(clientConfigTLS);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Converts a {@link ClientConfigTLS} to a TOML TLS configuration structure.
|
|
94
|
+
*
|
|
95
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
96
|
+
*/
|
|
97
|
+
function toTomlTLS(tlsConfig) {
|
|
98
|
+
if (tlsConfig === undefined) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
const clientCert = toPathAndData(tlsConfig.clientCert);
|
|
102
|
+
const clientKey = toPathAndData(tlsConfig.clientKey);
|
|
103
|
+
const serverCACert = toPathAndData(tlsConfig.serverCACert);
|
|
104
|
+
const tomlConfigTLS = {
|
|
105
|
+
disabled: tlsConfig.disabled,
|
|
106
|
+
server_name: tlsConfig.serverName,
|
|
107
|
+
client_cert_path: clientCert?.path,
|
|
108
|
+
client_cert_data: clientCert?.data && (0, encoding_1.decode)(clientCert?.data),
|
|
109
|
+
client_key_path: clientKey?.path,
|
|
110
|
+
client_key_data: clientKey?.data && (0, encoding_1.decode)(clientKey?.data),
|
|
111
|
+
server_ca_cert_path: serverCACert?.path,
|
|
112
|
+
server_ca_cert_data: serverCACert?.data && (0, encoding_1.decode)(serverCACert?.data),
|
|
113
|
+
};
|
|
114
|
+
return (0, internal_workflow_1.filterNullAndUndefined)(tomlConfigTLS);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Converts a TOML client configuration structure to a {@link ClientConfig}.
|
|
118
|
+
*
|
|
119
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
120
|
+
*/
|
|
121
|
+
function fromTomlConfig(tomlConfig) {
|
|
122
|
+
const profiles = {};
|
|
123
|
+
for (const [profileName, profile] of Object.entries(tomlConfig.profile)) {
|
|
124
|
+
profiles[profileName] = fromTomlProfile(profile);
|
|
125
|
+
}
|
|
126
|
+
return { profiles };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Converts a {@link ClientConfig} to a TOML client configuration structure.
|
|
130
|
+
*
|
|
131
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
132
|
+
*/
|
|
133
|
+
function toTomlConfig(config) {
|
|
134
|
+
const profile = {};
|
|
135
|
+
for (const [profileName, configProfile] of Object.entries(config.profiles)) {
|
|
136
|
+
profile[profileName] = toTomlProfile(configProfile);
|
|
137
|
+
}
|
|
138
|
+
return { profile };
|
|
139
|
+
}
|
|
140
|
+
function toPathAndData(source) {
|
|
141
|
+
if (source === undefined) {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
if ('path' in source) {
|
|
145
|
+
return { path: source.path };
|
|
146
|
+
}
|
|
147
|
+
if (typeof source.data === 'string') {
|
|
148
|
+
return { data: (0, encoding_1.encode)(source.data) };
|
|
149
|
+
}
|
|
150
|
+
return { data: source.data };
|
|
151
|
+
}
|
|
152
|
+
function toConfigDataSource(path, data, fieldName) {
|
|
153
|
+
if (path !== undefined && data !== undefined) {
|
|
154
|
+
throw new Error(`Cannot specify both ${fieldName}_path and ${fieldName}_data`);
|
|
155
|
+
}
|
|
156
|
+
if (data !== undefined) {
|
|
157
|
+
return { data: (0, encoding_1.encode)(data) };
|
|
158
|
+
}
|
|
159
|
+
if (path !== undefined) {
|
|
160
|
+
return { path };
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=utils.js.map
|
package/lib/utils.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@temporalio/envconfig",
|
|
3
|
+
"version": "1.13.2",
|
|
4
|
+
"description": "Temporal.io SDK Environment Configuration sub-package",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "./lib/index.d.ts",
|
|
7
|
+
"scripts": {},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"temporal",
|
|
10
|
+
"environment",
|
|
11
|
+
"configuration",
|
|
12
|
+
"client"
|
|
13
|
+
],
|
|
14
|
+
"author": "Temporal Technologies Inc. <sdk@temporal.io>",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@temporalio/common": "1.13.2",
|
|
18
|
+
"smol-toml": "1.4.2"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@temporalio/worker": "1.13.2"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">= 18.0.0"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/temporalio/sdk-typescript/issues"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/temporalio/sdk-typescript.git",
|
|
32
|
+
"directory": "packages/envconfig"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/temporalio/sdk-typescript/tree/main/packages/envconfig",
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"src",
|
|
40
|
+
"lib"
|
|
41
|
+
],
|
|
42
|
+
"gitHead": "cccc54c72f85377ac520b5d6cdd9a9a847027c27"
|
|
43
|
+
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { parse, stringify, TomlTable } from 'smol-toml';
|
|
5
|
+
import { filterNullAndUndefined } from '@temporalio/common/lib/internal-workflow/objects-helpers';
|
|
6
|
+
import { decode, encode } from '@temporalio/common/lib/encoding';
|
|
7
|
+
import { ConfigDataSource, LoadClientConfigOptions, LoadClientProfileOptions } from './types';
|
|
8
|
+
|
|
9
|
+
export function normalizeGrpcMetaKey(key: string): string {
|
|
10
|
+
return key.toLocaleLowerCase().replace('_', '-');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Raw TOML structure representing the client configuration file.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
18
|
+
*/
|
|
19
|
+
export interface TomlClientConfig {
|
|
20
|
+
profile: Record<string, TomlClientConfigProfile>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Raw TOML structure for a client configuration profile.
|
|
25
|
+
* Note: field names use snake_case to match TOML file fields for correct parser deserialization.
|
|
26
|
+
*
|
|
27
|
+
* @internal
|
|
28
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
29
|
+
*/
|
|
30
|
+
export interface TomlClientConfigProfile {
|
|
31
|
+
address?: string;
|
|
32
|
+
namespace?: string;
|
|
33
|
+
api_key?: string;
|
|
34
|
+
tls?: TomlClientConfigTLS;
|
|
35
|
+
codec?: TomlClientConfigCodec;
|
|
36
|
+
grpc_meta?: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Raw TOML structure for client configuration TLS.
|
|
41
|
+
*
|
|
42
|
+
* @internal
|
|
43
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
44
|
+
*/
|
|
45
|
+
export interface TomlClientConfigTLS {
|
|
46
|
+
disabled?: boolean;
|
|
47
|
+
client_cert_path?: string;
|
|
48
|
+
client_cert_data?: string;
|
|
49
|
+
client_key_path?: string;
|
|
50
|
+
client_key_data?: string;
|
|
51
|
+
server_ca_cert_path?: string;
|
|
52
|
+
server_ca_cert_data?: string;
|
|
53
|
+
server_name?: string;
|
|
54
|
+
disable_host_verification?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Raw TOML structure for client configuration codec.
|
|
59
|
+
*
|
|
60
|
+
* @internal
|
|
61
|
+
* @experimental Environment configuration is new feature and subject to change.
|
|
62
|
+
*/
|
|
63
|
+
export interface TomlClientConfigCodec {
|
|
64
|
+
endpoint?: string;
|
|
65
|
+
auth?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function sourceToStringData(source: ConfigDataSource | undefined): string | undefined {
|
|
69
|
+
if (source === undefined) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
if ('path' in source) {
|
|
73
|
+
return readFileSync(source.path, { encoding: 'utf-8' });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (typeof source.data === 'string') {
|
|
77
|
+
return source.data;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return decode(source.data);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function tomlLoadClientConfig(options: LoadClientConfigOptions): TomlClientConfig {
|
|
84
|
+
const envProvider: Record<string, string | undefined> = options.overrideEnvVars ?? process.env;
|
|
85
|
+
|
|
86
|
+
let configData = undefined;
|
|
87
|
+
try {
|
|
88
|
+
configData = sourceToStringData(options.configSource) ?? getFallbackConfigData(envProvider);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
const isFileNotFound = (error as NodeJS.ErrnoException)?.code === 'ENOENT';
|
|
91
|
+
if (!isFileNotFound) {
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
// File not found is ok
|
|
95
|
+
}
|
|
96
|
+
if (configData !== undefined) {
|
|
97
|
+
return loadFromTomlData(configData, options.configFileStrict ?? false);
|
|
98
|
+
}
|
|
99
|
+
return { profile: {} }; // default ClientConfig
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function loadFromTomlData(tomlData: string, isStrict: boolean): TomlClientConfig {
|
|
103
|
+
const parsed = parse(tomlData);
|
|
104
|
+
if (isStrict) {
|
|
105
|
+
strictValidateTomlStructure(parsed);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return parsed as unknown as TomlClientConfig;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function configToTomlData(config: TomlClientConfig): Uint8Array {
|
|
112
|
+
return encode(stringify(config));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function strictValidateTomlStructure(parsed: TomlTable): void {
|
|
116
|
+
const allowedTopLevel = new Set(['profile']);
|
|
117
|
+
const allowedProfile = new Set(['address', 'namespace', 'api_key', 'tls', 'codec', 'grpc_meta']);
|
|
118
|
+
const allowedTLS = new Set([
|
|
119
|
+
'disabled',
|
|
120
|
+
'client_cert_path',
|
|
121
|
+
'client_key_path',
|
|
122
|
+
'client_cert_data',
|
|
123
|
+
'client_key_data',
|
|
124
|
+
'server_ca_cert_path',
|
|
125
|
+
'server_ca_cert_data',
|
|
126
|
+
'server_name',
|
|
127
|
+
]);
|
|
128
|
+
const allowedCodec = new Set(['endpoint', 'auth']);
|
|
129
|
+
|
|
130
|
+
// Check top-level keys
|
|
131
|
+
const unknownTopLevel = Object.keys(parsed).filter((k) => !allowedTopLevel.has(k));
|
|
132
|
+
if (unknownTopLevel.length > 0) {
|
|
133
|
+
throw new Error(`Validation error: key(s) unrecognized: ${unknownTopLevel.join(', ')}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const profiles = parsed.profile;
|
|
137
|
+
if (profiles === undefined) return;
|
|
138
|
+
|
|
139
|
+
// Ensure it's a TomlTable (not a primitive or array)
|
|
140
|
+
if (typeof profiles !== 'object' || Array.isArray(profiles)) {
|
|
141
|
+
throw new Error('Validation error: profile must be a table');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
for (const [profileName, profileData] of Object.entries(profiles)) {
|
|
145
|
+
// Ensure profile is a table
|
|
146
|
+
if (typeof profileData !== 'object' || Array.isArray(profileData)) {
|
|
147
|
+
throw new Error(`Validation error: profile.${profileName} must be a table`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const unknownProfile = Object.keys(profileData).filter((k) => !allowedProfile.has(k));
|
|
151
|
+
if (unknownProfile.length > 0) {
|
|
152
|
+
throw new Error(`Validation error: key(s) unrecognized in profile.${profileName}: ${unknownProfile.join(', ')}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Validate TLS
|
|
156
|
+
const tls = profileData.tls;
|
|
157
|
+
if (tls !== undefined) {
|
|
158
|
+
if (typeof tls !== 'object' || Array.isArray(tls)) {
|
|
159
|
+
throw new Error(`Validation error: profile.${profileName}.tls must be a table`);
|
|
160
|
+
}
|
|
161
|
+
const unknownTLS = Object.keys(tls).filter((k) => !allowedTLS.has(k));
|
|
162
|
+
if (unknownTLS.length > 0) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Validation error: key(s) unrecognized in profile.${profileName}.tls: ${unknownTLS.join(', ')}`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Validate codec
|
|
170
|
+
const codec = profileData.codec;
|
|
171
|
+
if (codec !== undefined) {
|
|
172
|
+
if (typeof codec !== 'object' || Array.isArray(codec)) {
|
|
173
|
+
throw new Error(`Validation error: profile.${profileName}.codec must be a table`);
|
|
174
|
+
}
|
|
175
|
+
const unknownCodec = Object.keys(codec).filter((k) => !allowedCodec.has(k));
|
|
176
|
+
if (unknownCodec.length > 0) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`Validation error: key(s) unrecognized in profile.${profileName}.codec: ${unknownCodec.join(', ')}`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function getFallbackConfigData(envProvider: Record<string, string | undefined>): string | undefined {
|
|
186
|
+
// configSource was not set - fallback to TEMPORAL_CONFIG_FILE, then the default file path
|
|
187
|
+
let filePath = envProvider['TEMPORAL_CONFIG_FILE'];
|
|
188
|
+
if (filePath === undefined) {
|
|
189
|
+
filePath = getDefaultConfigFilePath();
|
|
190
|
+
}
|
|
191
|
+
return readFileSync(filePath, { encoding: 'utf-8' });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function tomlLoadClientConfigProfile(options: LoadClientProfileOptions): TomlClientConfigProfile {
|
|
195
|
+
if (options.disableEnv && options.disableFile) {
|
|
196
|
+
throw new Error('Cannot disable both file and environment loading');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const envProvider: Record<string, string | undefined> = options.overrideEnvVars ?? process.env;
|
|
200
|
+
|
|
201
|
+
let profile: TomlClientConfigProfile = {};
|
|
202
|
+
|
|
203
|
+
if (!options.disableFile) {
|
|
204
|
+
const tomlClientConfig = tomlLoadClientConfig({
|
|
205
|
+
configSource: options.configSource,
|
|
206
|
+
configFileStrict: options.configFileStrict,
|
|
207
|
+
overrideEnvVars: options.overrideEnvVars,
|
|
208
|
+
});
|
|
209
|
+
// If profile name not provided, fallback to env variable.
|
|
210
|
+
const profileName = options.profile ?? envProvider['TEMPORAL_PROFILE'];
|
|
211
|
+
// If env var also not provided, fallback to default profile name.
|
|
212
|
+
const tomlProfile = tomlClientConfig.profile[profileName ?? DEFAULT_CONFIG_FILE_PROFILE];
|
|
213
|
+
// If toml profile does not exist and an explicit profile was requested, error.
|
|
214
|
+
if (tomlProfile === undefined && profileName) {
|
|
215
|
+
throw new Error(`Profile '${profileName}' not found in config data`);
|
|
216
|
+
}
|
|
217
|
+
// Use loaded profile if exists, otherwise fallback to default profile.
|
|
218
|
+
profile = tomlProfile ?? {};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (!options.disableEnv) {
|
|
222
|
+
applyProfileEnvVars(profile, envProvider);
|
|
223
|
+
}
|
|
224
|
+
return profile;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function applyProfileEnvVars(profile: TomlClientConfigProfile, envProvider: Record<string, string | undefined>) {
|
|
228
|
+
profile.address = envProvider['TEMPORAL_ADDRESS'] ?? profile.address;
|
|
229
|
+
profile.namespace = envProvider['TEMPORAL_NAMESPACE'] ?? profile.namespace;
|
|
230
|
+
profile.api_key = envProvider['TEMPORAL_API_KEY'] ?? profile.api_key;
|
|
231
|
+
const tlsFromEnv = getTLSFromEnvVars(envProvider);
|
|
232
|
+
profile.tls = profile.tls || tlsFromEnv ? { ...profile.tls, ...tlsFromEnv } : undefined;
|
|
233
|
+
const codecFromEnv = getCodecFromEnvVars(envProvider);
|
|
234
|
+
profile.codec = profile.codec || codecFromEnv ? { ...profile.codec, ...codecFromEnv } : undefined;
|
|
235
|
+
applyGrpcMetaFromEnvVars(profile, envProvider);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function getTLSFromEnvVars(envProvider: Record<string, string | undefined>): TomlClientConfigTLS | undefined {
|
|
239
|
+
const tlsConfig: TomlClientConfigTLS = filterNullAndUndefined({
|
|
240
|
+
disabled: envVarToBool(envProvider['TEMPORAL_TLS']),
|
|
241
|
+
client_cert_path: envProvider['TEMPORAL_TLS_CLIENT_CERT_PATH'],
|
|
242
|
+
client_cert_data: envProvider['TEMPORAL_TLS_CLIENT_CERT_DATA'],
|
|
243
|
+
client_key_path: envProvider['TEMPORAL_TLS_CLIENT_KEY_PATH'],
|
|
244
|
+
client_key_data: envProvider['TEMPORAL_TLS_CLIENT_KEY_DATA'],
|
|
245
|
+
server_ca_cert_path: envProvider['TEMPORAL_TLS_SERVER_CA_CERT_PATH'],
|
|
246
|
+
server_ca_cert_data: envProvider['TEMPORAL_TLS_SERVER_CA_CERT_DATA'],
|
|
247
|
+
server_name: envProvider['TEMPORAL_TLS_SERVER_NAME'],
|
|
248
|
+
disable_host_verification: envVarToBool(envProvider['TEMPORAL_TLS_DISABLE_HOST_VERIFICATION']),
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// If no properties were added, return undefined
|
|
252
|
+
return Object.keys(tlsConfig).length > 0 ? tlsConfig : undefined;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function getCodecFromEnvVars(envProvider: Record<string, string | undefined>): TomlClientConfigCodec | undefined {
|
|
256
|
+
const codec: TomlClientConfigCodec = {};
|
|
257
|
+
const endpoint = envProvider['TEMPORAL_CODEC_ENDPOINT'];
|
|
258
|
+
if (endpoint !== undefined) {
|
|
259
|
+
codec.endpoint = endpoint;
|
|
260
|
+
}
|
|
261
|
+
const auth = envProvider['TEMPORAL_CODEC_AUTH'];
|
|
262
|
+
if (auth !== undefined) {
|
|
263
|
+
codec.auth = auth;
|
|
264
|
+
}
|
|
265
|
+
// If no properties were added, return undefined
|
|
266
|
+
return Object.keys(codec).length > 0 ? codec : undefined;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function applyGrpcMetaFromEnvVars(profile: TomlClientConfigProfile, envProvider: Record<string, string | undefined>) {
|
|
270
|
+
const PREFIX = 'TEMPORAL_GRPC_META_';
|
|
271
|
+
|
|
272
|
+
for (const [key, value] of Object.entries(envProvider)) {
|
|
273
|
+
if (key.startsWith(PREFIX)) {
|
|
274
|
+
const headerName = key.slice(PREFIX.length);
|
|
275
|
+
const normalizedKey = normalizeGrpcMetaKey(headerName);
|
|
276
|
+
if (profile.grpc_meta === undefined) {
|
|
277
|
+
profile.grpc_meta = {};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Empty values remove the key, non-empty values set it
|
|
281
|
+
if (value === '' || value == null) {
|
|
282
|
+
delete profile.grpc_meta[normalizedKey];
|
|
283
|
+
} else {
|
|
284
|
+
profile.grpc_meta[normalizedKey] = value;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function envVarToBool(envVar?: string): boolean | undefined {
|
|
291
|
+
if (envVar === undefined) {
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
return envVar === '1' || envVar === 'true';
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const DEFAULT_CONFIG_FILE_PROFILE = 'default';
|
|
298
|
+
const DEFAULT_CONFIG_FILE = 'config.toml';
|
|
299
|
+
|
|
300
|
+
function getDefaultConfigFilePath(): string {
|
|
301
|
+
const configDir = getUserConfigDir();
|
|
302
|
+
const configPath = path.join(configDir, 'temporalio', DEFAULT_CONFIG_FILE);
|
|
303
|
+
return configPath;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function getUserConfigDir(): string {
|
|
307
|
+
const platform = os.platform();
|
|
308
|
+
|
|
309
|
+
switch (platform) {
|
|
310
|
+
case 'win32': {
|
|
311
|
+
const dir = process.env.APPDATA;
|
|
312
|
+
if (!dir) {
|
|
313
|
+
throw new Error('%AppData% is not defined');
|
|
314
|
+
}
|
|
315
|
+
return dir;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
case 'darwin': {
|
|
319
|
+
const dir = process.env.HOME;
|
|
320
|
+
if (!dir) {
|
|
321
|
+
throw new Error('$HOME is not defined');
|
|
322
|
+
}
|
|
323
|
+
return path.join(dir, 'Library', 'Application Support');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
default: {
|
|
327
|
+
// Unix/Linux
|
|
328
|
+
let dir = process.env.XDG_CONFIG_HOME;
|
|
329
|
+
if (!dir) {
|
|
330
|
+
const home = process.env.HOME;
|
|
331
|
+
if (!home) {
|
|
332
|
+
throw new Error('neither $XDG_CONFIG_HOME nor $HOME are defined');
|
|
333
|
+
}
|
|
334
|
+
dir = path.join(home, '.config');
|
|
335
|
+
} else if (!path.isAbsolute(dir)) {
|
|
336
|
+
throw new Error('path in $XDG_CONFIG_HOME is relative');
|
|
337
|
+
}
|
|
338
|
+
return dir;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
package/src/envconfig.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { TLSConfig } from '@temporalio/common/lib/internal-non-workflow';
|
|
2
|
+
import { decode } from '@temporalio/common/lib/encoding';
|
|
3
|
+
import {
|
|
4
|
+
configToTomlData,
|
|
5
|
+
loadFromTomlData,
|
|
6
|
+
tomlLoadClientConfig,
|
|
7
|
+
tomlLoadClientConfigProfile,
|
|
8
|
+
} from './envconfig-toml';
|
|
9
|
+
import {
|
|
10
|
+
ClientConfig,
|
|
11
|
+
ClientConfigFromTomlOptions,
|
|
12
|
+
ClientConfigProfile,
|
|
13
|
+
ClientConfigTLS,
|
|
14
|
+
ClientConnectConfig,
|
|
15
|
+
LoadClientConfigOptions,
|
|
16
|
+
LoadClientProfileOptions,
|
|
17
|
+
} from './types';
|
|
18
|
+
import { fromTomlConfig, fromTomlProfile, loadConfigData, toTomlConfig } from './utils';
|
|
19
|
+
|
|
20
|
+
export function loadClientConfig(options: LoadClientConfigOptions): ClientConfig {
|
|
21
|
+
return fromTomlConfig(tomlLoadClientConfig(options));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function loadClientConfigFromToml(tomlData: Uint8Array, options: ClientConfigFromTomlOptions): ClientConfig {
|
|
25
|
+
return fromTomlConfig(loadFromTomlData(decode(tomlData), options.strict));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function clientConfigToToml(config: ClientConfig): Uint8Array {
|
|
29
|
+
return configToTomlData(toTomlConfig(config));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function loadClientConfigProfile(options: LoadClientProfileOptions = {}): ClientConfigProfile {
|
|
33
|
+
return fromTomlProfile(tomlLoadClientConfigProfile(options));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function loadClientConnectConfig(options: LoadClientProfileOptions = {}): ClientConnectConfig {
|
|
37
|
+
return toClientOptions(loadClientConfigProfile(options));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function toClientOptions(profile: ClientConfigProfile): ClientConnectConfig {
|
|
41
|
+
// TLS is enabled if we have an explicit TLS config, or if an api key is provided.
|
|
42
|
+
const tls = toTLSConfig(profile.tls) ?? (profile.apiKey !== undefined ? true : undefined);
|
|
43
|
+
return {
|
|
44
|
+
namespace: profile.namespace,
|
|
45
|
+
connectionOptions: {
|
|
46
|
+
address: profile.address,
|
|
47
|
+
apiKey: profile.apiKey,
|
|
48
|
+
tls,
|
|
49
|
+
metadata: profile.grpcMeta,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function toTLSConfig(config?: ClientConfigTLS): TLSConfig | boolean | undefined {
|
|
55
|
+
if (config === undefined) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
if (config.disabled === true) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const serverRootCACert = loadConfigData(config.serverCACert);
|
|
63
|
+
const crtBuffer = loadConfigData(config.clientCert);
|
|
64
|
+
const keyBuffer = loadConfigData(config.clientKey);
|
|
65
|
+
|
|
66
|
+
const tlsConfig: TLSConfig = {
|
|
67
|
+
serverNameOverride: config.serverName,
|
|
68
|
+
serverRootCACertificate: serverRootCACert,
|
|
69
|
+
clientCertPair:
|
|
70
|
+
crtBuffer && keyBuffer
|
|
71
|
+
? {
|
|
72
|
+
crt: crtBuffer,
|
|
73
|
+
key: keyBuffer,
|
|
74
|
+
}
|
|
75
|
+
: undefined,
|
|
76
|
+
};
|
|
77
|
+
return tlsConfig;
|
|
78
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export {
|
|
2
|
+
loadClientConfig,
|
|
3
|
+
loadClientConfigProfile,
|
|
4
|
+
loadClientConnectConfig,
|
|
5
|
+
loadClientConfigFromToml,
|
|
6
|
+
clientConfigToToml,
|
|
7
|
+
toClientOptions,
|
|
8
|
+
} from './envconfig';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
ClientConfig,
|
|
12
|
+
ClientConfigProfile,
|
|
13
|
+
ClientConfigTLS,
|
|
14
|
+
LoadClientConfigOptions,
|
|
15
|
+
LoadClientProfileOptions,
|
|
16
|
+
ClientConfigFromTomlOptions,
|
|
17
|
+
ConfigDataSource,
|
|
18
|
+
} from './types';
|
|
19
|
+
|
|
20
|
+
export { fromTomlConfig, fromTomlProfile, toTomlConfig, toTomlProfile, loadConfigData } from './utils';
|