@fonoster/common 0.27.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{voice/PlayDtmf.d.ts → agents/index.d.ts} +3 -5
- package/dist/{assistants → agents}/index.js +2 -6
- package/dist/agents/sessionAgentSchema.d.ts +755 -0
- package/dist/agents/sessionAgentSchema.js +117 -0
- package/dist/{voice/Dial.d.ts → calls/index.d.ts} +16 -13
- package/dist/calls/index.js +44 -0
- package/dist/cellsecrets/index.d.ts +91 -0
- package/dist/cellsecrets/index.js +299 -0
- package/dist/config/cli/check.d.ts +6 -0
- package/dist/config/cli/check.js +202 -0
- package/dist/config/cli/envFile.d.ts +23 -0
- package/dist/config/cli/envFile.js +81 -0
- package/dist/config/cli/exposure.d.ts +10 -0
- package/dist/config/cli/exposure.js +93 -0
- package/dist/config/cli/index.d.ts +2 -0
- package/dist/{identity/tokenHasAccessKeyId.js → config/cli/index.js} +7 -8
- package/dist/config/cli/info.d.ts +6 -0
- package/dist/config/cli/info.js +62 -0
- package/dist/config/cli/init.d.ts +9 -0
- package/dist/config/cli/init.js +152 -0
- package/dist/config/cli/main.d.ts +11 -0
- package/dist/config/cli/main.js +155 -0
- package/dist/config/cli/render.d.ts +44 -0
- package/dist/config/cli/render.js +129 -0
- package/dist/config/cli/secrets.d.ts +21 -0
- package/dist/config/cli/secrets.js +117 -0
- package/dist/config/cli/types.d.ts +24 -0
- package/dist/config/cli/types.js +7 -0
- package/dist/{assistants/index.d.ts → config/configHints.d.ts} +8 -7
- package/dist/config/configHints.js +47 -0
- package/dist/{voice → config}/index.d.ts +11 -13
- package/dist/{voice → config}/index.js +11 -13
- package/dist/config/interpolateEnv.d.ts +34 -0
- package/dist/config/interpolateEnv.js +70 -0
- package/dist/config/loadServiceConfig.d.ts +28 -0
- package/dist/config/loadServiceConfig.js +112 -0
- package/dist/config/logsSchema.d.ts +76 -0
- package/dist/config/logsSchema.js +49 -0
- package/dist/config/natsConnection.d.ts +53 -0
- package/dist/config/natsConnection.js +58 -0
- package/dist/config/parseConfigFile.d.ts +7 -0
- package/dist/config/parseConfigFile.js +60 -0
- package/dist/config/resolveConfigFile.d.ts +17 -0
- package/dist/config/resolveConfigFile.js +54 -0
- package/dist/config/resolveSecretRefs.d.ts +35 -0
- package/dist/config/resolveSecretRefs.js +129 -0
- package/dist/{assistants/audioFiltersSchema.d.ts → config/strictDeep.d.ts} +9 -12
- package/dist/config/strictDeep.js +58 -0
- package/dist/config/telemetrySchema.d.ts +39 -0
- package/dist/config/telemetrySchema.js +44 -0
- package/dist/config/toJsonSchema.d.ts +30 -0
- package/dist/config/toJsonSchema.js +161 -0
- package/dist/constants.d.ts +1 -6
- package/dist/constants.js +4 -7
- package/dist/envs.d.ts +2 -1
- package/dist/envs.js +13 -11
- package/dist/errors/handleZodError.js +3 -1
- package/dist/filters/index.d.ts +70 -0
- package/dist/filters/index.js +101 -0
- package/dist/identity/createAuthInterceptor.d.ts +9 -2
- package/dist/identity/createAuthInterceptor.js +36 -30
- package/dist/identity/hasAccess.d.ts +9 -3
- package/dist/identity/hasAccess.js +32 -8
- package/dist/identity/index.d.ts +1 -0
- package/dist/identity/index.js +1 -0
- package/dist/identity/isValidToken.d.ts +12 -2
- package/dist/identity/isValidToken.js +25 -9
- package/dist/identity/roles.js +33 -7
- package/dist/identity/types.d.ts +6 -1
- package/dist/identity/types.js +1 -0
- package/dist/{assistants/LanguageModelProvider.js → identity/verifyAccessToken.d.ts} +10 -11
- package/dist/identity/verifyAccessToken.js +44 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +18 -3
- package/dist/net/assertPublicDestination.d.ts +52 -0
- package/dist/net/assertPublicDestination.js +342 -0
- package/dist/{voice/StopSay.d.ts → net/index.d.ts} +1 -6
- package/dist/net/index.js +35 -0
- package/dist/notifications/createSendEmail.js +3 -1
- package/dist/protos/applications.proto +138 -3
- package/dist/protos/authz.proto +26 -4
- package/dist/protos/billing.proto +92 -0
- package/dist/protos/calls.proto +4 -0
- package/dist/protos/capabilities.proto +102 -0
- package/dist/protos/identity.proto +26 -1
- package/dist/protos/providers.proto +139 -0
- package/dist/protos/roomr.proto +146 -0
- package/dist/protos/session.proto +194 -0
- package/dist/protos/usage.proto +59 -0
- package/dist/protos/webhooks.proto +140 -0
- package/dist/{utils/types.d.ts → regions/hub/index.d.ts} +1 -5
- package/dist/regions/hub/index.js +35 -0
- package/dist/regions/hub/natsJwt.d.ts +63 -0
- package/dist/regions/hub/natsJwt.js +195 -0
- package/dist/registry/Registry.d.ts +87 -0
- package/dist/registry/Registry.js +432 -0
- package/dist/registry/cli.d.ts +20 -0
- package/dist/registry/cli.js +436 -0
- package/dist/registry/features.d.ts +31 -0
- package/dist/registry/features.js +38 -0
- package/dist/registry/index.d.ts +24 -0
- package/dist/registry/index.js +40 -0
- package/dist/registry/prisma.d.ts +67 -0
- package/dist/registry/prisma.js +399 -0
- package/dist/registry/stores.d.ts +21 -0
- package/dist/{assistants/languageModelConfigSchema.js → registry/stores.js} +55 -38
- package/dist/registry/types.d.ts +110 -0
- package/dist/{assistants/LanguageModelProvider.d.ts → registry/types.js} +6 -8
- package/dist/registry/workspaceKeys.d.ts +41 -0
- package/dist/registry/workspaceKeys.js +64 -0
- package/dist/roomr/health.d.ts +9 -0
- package/dist/{assistants/eventsHookSchema.js → roomr/health.js} +22 -18
- package/dist/roomr/index.d.ts +75 -0
- package/dist/roomr/index.js +146 -0
- package/dist/roomr/session.d.ts +133 -0
- package/dist/roomr/session.js +132 -0
- package/dist/session/index.d.ts +19 -0
- package/dist/session/index.js +35 -0
- package/dist/session/schema.d.ts +2140 -0
- package/dist/session/schema.js +448 -0
- package/dist/sessions/index.d.ts +96 -0
- package/dist/sessions/index.js +197 -0
- package/dist/telemetry.d.ts +76 -0
- package/dist/telemetry.js +360 -0
- package/dist/types.d.ts +3 -5
- package/dist/{voice/Gather.d.ts → usage/CallUsage.d.ts} +19 -18
- package/dist/usage/CallUsage.js +76 -0
- package/dist/usage/index.d.ts +22 -0
- package/dist/usage/index.js +38 -0
- package/dist/usage/meters.d.ts +113 -0
- package/dist/usage/meters.js +90 -0
- package/dist/usage/types.d.ts +159 -0
- package/dist/usage/types.js +84 -0
- package/dist/usage/usageId.d.ts +6 -0
- package/dist/usage/usageId.js +45 -0
- package/dist/utils/{findIntegrationsCredentials.js → WriteBehind.d.ts} +13 -10
- package/dist/utils/WriteBehind.js +64 -0
- package/dist/utils/index.d.ts +1 -3
- package/dist/utils/index.js +1 -3
- package/dist/utils/{createFetchSingleCallByCallId.d.ts → logUnhandledRejections.d.ts} +8 -4
- package/dist/{assistants/audioFiltersSchema.js → utils/logUnhandledRejections.js} +17 -12
- package/dist/utils/withErrorHandling.js +1 -1
- package/dist/validators/calls.d.ts +3 -0
- package/dist/validators/calls.js +12 -2
- package/dist/validators/identity.d.ts +37 -8
- package/dist/validators/identity.js +22 -3
- package/dist/validators/index.d.ts +1 -0
- package/dist/validators/index.js +1 -0
- package/dist/validators/sip.d.ts +40 -0
- package/dist/validators/sip.js +99 -0
- package/dist/validators/sipnet/credentials.d.ts +2 -2
- package/dist/validators/sipnet/domains.js +7 -7
- package/dist/validators/sipnet/trunks.d.ts +14 -14
- package/dist/validators/sipnet/trunks.js +4 -2
- package/dist/webhooks/Dispatcher.d.ts +87 -0
- package/dist/webhooks/Dispatcher.js +225 -0
- package/dist/webhooks/bus.d.ts +68 -0
- package/dist/webhooks/bus.js +178 -0
- package/dist/webhooks/events.d.ts +66 -0
- package/dist/webhooks/events.js +62 -0
- package/dist/webhooks/index.d.ts +23 -0
- package/dist/webhooks/index.js +39 -0
- package/dist/webhooks/prisma.d.ts +55 -0
- package/dist/webhooks/prisma.js +242 -0
- package/dist/webhooks/signing.d.ts +8 -0
- package/dist/webhooks/signing.js +53 -0
- package/package.json +25 -11
- package/schema/session.v1.json +871 -0
- package/dist/assistants/assistantSchema.d.ts +0 -739
- package/dist/assistants/assistantSchema.js +0 -37
- package/dist/assistants/conversationSettingsSchema.d.ts +0 -122
- package/dist/assistants/conversationSettingsSchema.js +0 -133
- package/dist/assistants/eventsHookSchema.d.ts +0 -38
- package/dist/assistants/languageModelConfigSchema.d.ts +0 -206
- package/dist/identity/tokenHasAccessKeyId.d.ts +0 -2
- package/dist/protos/voice.proto +0 -557
- package/dist/utils/createFetchSingleCallByCallId.js +0 -33
- package/dist/utils/findIntegrationsCredentials.d.ts +0 -23
- package/dist/utils/types.js +0 -2
- package/dist/voice/Dial.js +0 -20
- package/dist/voice/Gather.js +0 -9
- package/dist/voice/Mute.d.ts +0 -31
- package/dist/voice/Mute.js +0 -9
- package/dist/voice/Play.d.ts +0 -30
- package/dist/voice/Play.js +0 -2
- package/dist/voice/PlayDtmf.js +0 -2
- package/dist/voice/PlaybackControl.d.ts +0 -31
- package/dist/voice/PlaybackControl.js +0 -11
- package/dist/voice/Record.d.ts +0 -36
- package/dist/voice/Record.js +0 -7
- package/dist/voice/Say.d.ts +0 -28
- package/dist/voice/Say.js +0 -2
- package/dist/voice/StopSay.js +0 -2
- package/dist/voice/Stream.d.ts +0 -53
- package/dist/voice/Stream.js +0 -19
- package/dist/voice/StreamGather.d.ts +0 -34
- package/dist/voice/StreamGather.js +0 -9
- package/dist/voice/Verb.d.ts +0 -27
- package/dist/voice/Verb.js +0 -2
- package/dist/voice/voice.d.ts +0 -171
- package/dist/voice/voice.js +0 -65
- package/dist/{assistants → agents}/testCasesSchema.d.ts +4 -4
- /package/dist/{assistants → agents}/testCasesSchema.js +0 -0
- /package/dist/{assistants → agents}/tools/index.d.ts +0 -0
- /package/dist/{assistants → agents}/tools/index.js +0 -0
- /package/dist/{assistants → agents}/tools/propertySchema.d.ts +0 -0
- /package/dist/{assistants → agents}/tools/propertySchema.js +0 -0
- /package/dist/{assistants → agents}/tools/toolSchema.d.ts +0 -0
- /package/dist/{assistants → agents}/tools/toolSchema.js +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
3
|
+
* http://github.com/fonoster/fonoster
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Fonoster
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the MIT License (the "License");
|
|
8
|
+
* you may not use this file except in compliance with
|
|
9
|
+
* the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* https://opensource.org/licenses/MIT
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
type Env = Record<string, string | undefined>;
|
|
20
|
+
type InterpolateOptions = {
|
|
21
|
+
/**
|
|
22
|
+
* Key paths where `${VAR}` may appear, e.g. `database.url` or `nats.*`
|
|
23
|
+
* (`*` matches the key and everything below it; `*` alone matches every key). When given,
|
|
24
|
+
* `${...}` at any other path is an error. When omitted, every string is interpolated.
|
|
25
|
+
*/
|
|
26
|
+
allowedPaths?: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Recursively walks an already-parsed config value and interpolates `${VAR}`
|
|
30
|
+
* references in its strings. Returns a new value; the input is not mutated.
|
|
31
|
+
* Errors name the key path where they happened.
|
|
32
|
+
*/
|
|
33
|
+
declare function interpolateEnv<T>(input: T, env?: Env, options?: InterpolateOptions): T;
|
|
34
|
+
export { interpolateEnv, InterpolateOptions };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.interpolateEnv = interpolateEnv;
|
|
4
|
+
/**
|
|
5
|
+
* Shell / docker-compose style variable interpolation for config files.
|
|
6
|
+
*
|
|
7
|
+
* Supported forms inside any string value:
|
|
8
|
+
* - `${VAR}` -> value of VAR; throws if VAR is unset or empty
|
|
9
|
+
* - `${VAR:-default}` -> value of VAR, or `default` when VAR is unset or empty
|
|
10
|
+
*
|
|
11
|
+
* Anything that is not a `${...}` reference is left untouched, so plain literals
|
|
12
|
+
* (`http://asterisk:8088`, `$5.00`, ...) pass through unchanged. Services limit
|
|
13
|
+
* it to values shared with other containers (see `allowedPaths`), so each value
|
|
14
|
+
* is written once.
|
|
15
|
+
*/
|
|
16
|
+
const VAR_PATTERN = /\$\{([A-Za-z_][A-Za-z0-9_]*)(:-([^}]*))?\}/g;
|
|
17
|
+
function interpolateString(value, env) {
|
|
18
|
+
return value.replace(VAR_PATTERN, (_match, name, hasDefault, fallback) => {
|
|
19
|
+
const current = env[name];
|
|
20
|
+
if (current !== undefined && current !== "") {
|
|
21
|
+
return current;
|
|
22
|
+
}
|
|
23
|
+
if (hasDefault !== undefined) {
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
26
|
+
throw new Error(`references undefined environment variable \${${name}} and no default was given`);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const HAS_REFERENCE = /\$\{[^}]*\}/;
|
|
30
|
+
function isAllowed(path, allowedPaths) {
|
|
31
|
+
return allowedPaths.some((pattern) => pattern === "*"
|
|
32
|
+
? true
|
|
33
|
+
: pattern.endsWith(".*")
|
|
34
|
+
? path === pattern.slice(0, -2) ||
|
|
35
|
+
path.startsWith(`${pattern.slice(0, -2)}.`)
|
|
36
|
+
: path === pattern);
|
|
37
|
+
}
|
|
38
|
+
function walk(input, env, options, path) {
|
|
39
|
+
if (typeof input === "string") {
|
|
40
|
+
if (!HAS_REFERENCE.test(input)) {
|
|
41
|
+
return input;
|
|
42
|
+
}
|
|
43
|
+
const where = path || "(root)";
|
|
44
|
+
if (options.allowedPaths && !isAllowed(path, options.allowedPaths)) {
|
|
45
|
+
throw new Error(`${where}: \${...} is only allowed for values shared with other containers (${options.allowedPaths.join(", ") || "none here"})`);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return interpolateString(input, env);
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
throw new Error(`${where}: ${e.message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(input)) {
|
|
55
|
+
return input.map((item, index) => walk(item, env, options, `${path}[${index}]`));
|
|
56
|
+
}
|
|
57
|
+
if (input !== null && typeof input === "object") {
|
|
58
|
+
const entries = Object.entries(input).map(([key, value]) => [key, walk(value, env, options, path ? `${path}.${key}` : key)]);
|
|
59
|
+
return Object.fromEntries(entries);
|
|
60
|
+
}
|
|
61
|
+
return input;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Recursively walks an already-parsed config value and interpolates `${VAR}`
|
|
65
|
+
* references in its strings. Returns a new value; the input is not mutated.
|
|
66
|
+
* Errors name the key path where they happened.
|
|
67
|
+
*/
|
|
68
|
+
function interpolateEnv(input, env = process.env, options = {}) {
|
|
69
|
+
return walk(input, env, options, "");
|
|
70
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z, ZodTypeAny } from "zod";
|
|
2
|
+
type Env = Record<string, string | undefined>;
|
|
3
|
+
type LoadServiceConfigOptions<S extends ZodTypeAny> = {
|
|
4
|
+
/** Service name, used in messages. */
|
|
5
|
+
service: string;
|
|
6
|
+
/** File name without extension. Defaults to `service`. */
|
|
7
|
+
fileBase?: string;
|
|
8
|
+
/** Zod schema that validates (and applies defaults to) the config. */
|
|
9
|
+
schema: S;
|
|
10
|
+
/** Defaults to `process.argv`; `--config <path>` picks the file. */
|
|
11
|
+
argv?: string[];
|
|
12
|
+
/** Only used to resolve `${VAR}` placeholders. Defaults to `process.env`. */
|
|
13
|
+
env?: Env;
|
|
14
|
+
/** Directories searched when `--config` is absent. */
|
|
15
|
+
searchDirs?: string[];
|
|
16
|
+
/**
|
|
17
|
+
* Key paths that may reference `${VAR}` (values Compose passes from `.env`). `["*"]` allows
|
|
18
|
+
* every key (the default for Fonoster services, unify-config-placeholders); `${...}` anywhere
|
|
19
|
+
* else is an error.
|
|
20
|
+
*/
|
|
21
|
+
interpolatePaths?: string[];
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Loads, interpolates and strictly validates a service's config file.
|
|
25
|
+
* Throws with the file path and the offending key path on any problem.
|
|
26
|
+
*/
|
|
27
|
+
declare function loadServiceConfig<S extends ZodTypeAny>(options: LoadServiceConfigOptions<S>): z.output<S>;
|
|
28
|
+
export { loadServiceConfig, LoadServiceConfigOptions };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadServiceConfig = loadServiceConfig;
|
|
4
|
+
/**
|
|
5
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
6
|
+
* http://github.com/fonoster/fonoster
|
|
7
|
+
*
|
|
8
|
+
* This file is part of Fonoster
|
|
9
|
+
*
|
|
10
|
+
* Licensed under the MIT License (the "License");
|
|
11
|
+
* you may not use this file except in compliance with
|
|
12
|
+
* the License. You may obtain a copy of the License at
|
|
13
|
+
*
|
|
14
|
+
* https://opensource.org/licenses/MIT
|
|
15
|
+
*
|
|
16
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
17
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
18
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
19
|
+
* See the License for the specific language governing permissions and
|
|
20
|
+
* limitations under the License.
|
|
21
|
+
*/
|
|
22
|
+
const fs_1 = require("fs");
|
|
23
|
+
const logger_1 = require("@fonoster/logger");
|
|
24
|
+
const interpolateEnv_1 = require("./interpolateEnv");
|
|
25
|
+
const parseConfigFile_1 = require("./parseConfigFile");
|
|
26
|
+
const resolveConfigFile_1 = require("./resolveConfigFile");
|
|
27
|
+
const resolveSecretRefs_1 = require("./resolveSecretRefs");
|
|
28
|
+
const strictDeep_1 = require("./strictDeep");
|
|
29
|
+
const logger = (0, logger_1.getLogger)({ service: "common", filePath: __filename });
|
|
30
|
+
/**
|
|
31
|
+
* One line per problem, each led by the key path:
|
|
32
|
+
* `smtp: unknown key "hsot"`, `features.auth.methods[1]: Invalid enum value ...`.
|
|
33
|
+
*/
|
|
34
|
+
function formatIssues(error) {
|
|
35
|
+
return error.issues
|
|
36
|
+
.map((issue) => {
|
|
37
|
+
const path = issue.path
|
|
38
|
+
.map((segment, index) => typeof segment === "number"
|
|
39
|
+
? `[${segment}]`
|
|
40
|
+
: index === 0
|
|
41
|
+
? segment
|
|
42
|
+
: `.${segment}`)
|
|
43
|
+
.join("");
|
|
44
|
+
const where = path || "(root)";
|
|
45
|
+
if (issue.code === "unrecognized_keys") {
|
|
46
|
+
const keys = issue.keys.map((key) => `"${key}"`).join(", ");
|
|
47
|
+
return `${where}: unknown key${issue.keys.length > 1 ? "s" : ""} ${keys}`;
|
|
48
|
+
}
|
|
49
|
+
return `${where}: ${issue.message}`;
|
|
50
|
+
})
|
|
51
|
+
.join("; ");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Loads, interpolates and strictly validates a service's config file.
|
|
55
|
+
* Throws with the file path and the offending key path on any problem.
|
|
56
|
+
*/
|
|
57
|
+
function loadServiceConfig(options) {
|
|
58
|
+
var _a, _b, _c, _d, _e;
|
|
59
|
+
const { service, schema } = options;
|
|
60
|
+
const fileBase = (_a = options.fileBase) !== null && _a !== void 0 ? _a : service;
|
|
61
|
+
const argv = (_b = options.argv) !== null && _b !== void 0 ? _b : process.argv;
|
|
62
|
+
const env = (_c = options.env) !== null && _c !== void 0 ? _c : process.env;
|
|
63
|
+
const resolved = (0, resolveConfigFile_1.resolveConfigFile)(fileBase, argv, options.searchDirs);
|
|
64
|
+
const where = (_d = resolved.path) !== null && _d !== void 0 ? _d : "(built-in defaults)";
|
|
65
|
+
let raw = {};
|
|
66
|
+
if ("searched" in resolved) {
|
|
67
|
+
logger.warn(`no ${service} config file found (looked for ${resolved.searched.join(", ")}); using built-in defaults`);
|
|
68
|
+
}
|
|
69
|
+
else if (!(0, fs_1.existsSync)(resolved.path)) {
|
|
70
|
+
throw new Error(`unable to read ${service} config at ${resolved.path}: file not found`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
try {
|
|
74
|
+
raw = (0, parseConfigFile_1.parseConfigFile)(resolved.path, (0, fs_1.readFileSync)(resolved.path, "utf8"));
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
throw new Error(`unable to read ${service} config at ${resolved.path}: ${e.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// "$schema" points editors at the JSON Schema for autocomplete; it isn't config.
|
|
81
|
+
if (raw !== null && typeof raw === "object" && "$schema" in raw) {
|
|
82
|
+
const rest = Object.assign({}, raw);
|
|
83
|
+
delete rest.$schema;
|
|
84
|
+
raw = rest;
|
|
85
|
+
}
|
|
86
|
+
let interpolated;
|
|
87
|
+
try {
|
|
88
|
+
interpolated = (0, interpolateEnv_1.interpolateEnv)(raw, env, {
|
|
89
|
+
allowedPaths: (_e = options.interpolatePaths) !== null && _e !== void 0 ? _e : []
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
throw new Error(`invalid ${service} config at ${where}: ${e.message}`);
|
|
94
|
+
}
|
|
95
|
+
// `secret://` references (D8): resolved here so the schema sees real values.
|
|
96
|
+
let withSecrets;
|
|
97
|
+
try {
|
|
98
|
+
withSecrets = (0, resolveSecretRefs_1.resolveSecretRefs)(interpolated, { env });
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
throw new Error(`invalid ${service} config at ${where}: ${e.message}`);
|
|
102
|
+
}
|
|
103
|
+
const strictSchema = (0, strictDeep_1.strictDeep)(schema);
|
|
104
|
+
const result = strictSchema.safeParse(withSecrets);
|
|
105
|
+
if (!result.success) {
|
|
106
|
+
throw new Error(`invalid ${service} config at ${where}: ${formatIssues(result.error)}`);
|
|
107
|
+
}
|
|
108
|
+
if (resolved.path) {
|
|
109
|
+
logger.verbose(`loaded ${service} config`, { path: resolved.path });
|
|
110
|
+
}
|
|
111
|
+
return result.data;
|
|
112
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
3
|
+
* http://github.com/fonoster/fonoster
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Fonoster
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the MIT License (the "License");
|
|
8
|
+
* you may not use this file except in compliance with
|
|
9
|
+
* the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* https://opensource.org/licenses/MIT
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
/** The `logs` section shared by every Fonoster service's config file. */
|
|
21
|
+
declare const logsSchema: z.ZodDefault<z.ZodEffects<z.ZodObject<{
|
|
22
|
+
level: z.ZodDefault<z.ZodEnum<["error", "warn", "info", "http", "verbose", "debug", "silly"]>>;
|
|
23
|
+
format: z.ZodDefault<z.ZodEnum<["json", "text"]>>;
|
|
24
|
+
transport: z.ZodDefault<z.ZodEnum<["console", "fluent"]>>;
|
|
25
|
+
fluent: z.ZodOptional<z.ZodObject<{
|
|
26
|
+
host: z.ZodString;
|
|
27
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
28
|
+
tagPrefix: z.ZodDefault<z.ZodString>;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
host?: string;
|
|
31
|
+
port?: number;
|
|
32
|
+
tagPrefix?: string;
|
|
33
|
+
}, {
|
|
34
|
+
host?: string;
|
|
35
|
+
port?: number;
|
|
36
|
+
tagPrefix?: string;
|
|
37
|
+
}>>;
|
|
38
|
+
}, "strip", z.ZodTypeAny, {
|
|
39
|
+
format?: "text" | "json";
|
|
40
|
+
level?: "error" | "warn" | "info" | "http" | "verbose" | "debug" | "silly";
|
|
41
|
+
fluent?: {
|
|
42
|
+
host?: string;
|
|
43
|
+
port?: number;
|
|
44
|
+
tagPrefix?: string;
|
|
45
|
+
};
|
|
46
|
+
transport?: "console" | "fluent";
|
|
47
|
+
}, {
|
|
48
|
+
format?: "text" | "json";
|
|
49
|
+
level?: "error" | "warn" | "info" | "http" | "verbose" | "debug" | "silly";
|
|
50
|
+
fluent?: {
|
|
51
|
+
host?: string;
|
|
52
|
+
port?: number;
|
|
53
|
+
tagPrefix?: string;
|
|
54
|
+
};
|
|
55
|
+
transport?: "console" | "fluent";
|
|
56
|
+
}>, {
|
|
57
|
+
format?: "text" | "json";
|
|
58
|
+
level?: "error" | "warn" | "info" | "http" | "verbose" | "debug" | "silly";
|
|
59
|
+
fluent?: {
|
|
60
|
+
host?: string;
|
|
61
|
+
port?: number;
|
|
62
|
+
tagPrefix?: string;
|
|
63
|
+
};
|
|
64
|
+
transport?: "console" | "fluent";
|
|
65
|
+
}, {
|
|
66
|
+
format?: "text" | "json";
|
|
67
|
+
level?: "error" | "warn" | "info" | "http" | "verbose" | "debug" | "silly";
|
|
68
|
+
fluent?: {
|
|
69
|
+
host?: string;
|
|
70
|
+
port?: number;
|
|
71
|
+
tagPrefix?: string;
|
|
72
|
+
};
|
|
73
|
+
transport?: "console" | "fluent";
|
|
74
|
+
}>>;
|
|
75
|
+
type LogsConfig = z.infer<typeof logsSchema>;
|
|
76
|
+
export { logsSchema, LogsConfig };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logsSchema = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
6
|
+
* http://github.com/fonoster/fonoster
|
|
7
|
+
*
|
|
8
|
+
* This file is part of Fonoster
|
|
9
|
+
*
|
|
10
|
+
* Licensed under the MIT License (the "License");
|
|
11
|
+
* you may not use this file except in compliance with
|
|
12
|
+
* the License. You may obtain a copy of the License at
|
|
13
|
+
*
|
|
14
|
+
* https://opensource.org/licenses/MIT
|
|
15
|
+
*
|
|
16
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
17
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
18
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
19
|
+
* See the License for the specific language governing permissions and
|
|
20
|
+
* limitations under the License.
|
|
21
|
+
*/
|
|
22
|
+
const zod_1 = require("zod");
|
|
23
|
+
/** The `logs` section shared by every Fonoster service's config file. */
|
|
24
|
+
const logsSchema = zod_1.z
|
|
25
|
+
.object({
|
|
26
|
+
level: zod_1.z
|
|
27
|
+
.enum(["error", "warn", "info", "http", "verbose", "debug", "silly"])
|
|
28
|
+
.default("info"),
|
|
29
|
+
format: zod_1.z.enum(["json", "text"]).default("json"),
|
|
30
|
+
transport: zod_1.z.enum(["console", "fluent"]).default("console"),
|
|
31
|
+
fluent: zod_1.z
|
|
32
|
+
.object({
|
|
33
|
+
host: zod_1.z.string(),
|
|
34
|
+
port: zod_1.z.number().int().positive().default(24224),
|
|
35
|
+
tagPrefix: zod_1.z.string().default("fonoster-logs")
|
|
36
|
+
})
|
|
37
|
+
.optional()
|
|
38
|
+
})
|
|
39
|
+
.superRefine((logs, ctx) => {
|
|
40
|
+
if (logs.transport === "fluent" && !logs.fluent) {
|
|
41
|
+
ctx.addIssue({
|
|
42
|
+
code: "custom",
|
|
43
|
+
path: ["fluent"],
|
|
44
|
+
message: "required when transport is fluent"
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.default({});
|
|
49
|
+
exports.logsSchema = logsSchema;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
3
|
+
* http://github.com/fonoster/fonoster
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Fonoster
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the MIT License (the "License");
|
|
8
|
+
* you may not use this file except in compliance with
|
|
9
|
+
* the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* https://opensource.org/licenses/MIT
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
/**
|
|
21
|
+
* A service's NATS connection settings (add-platform 4.1): the URL plus, when the server has
|
|
22
|
+
* per-service users, the service's user and password. The password is usually a `secret://`
|
|
23
|
+
* reference, resolved by the config loader like any other value.
|
|
24
|
+
*/
|
|
25
|
+
export declare const natsConnectionSchema: z.ZodObject<{
|
|
26
|
+
url: z.ZodString;
|
|
27
|
+
user: z.ZodOptional<z.ZodString>;
|
|
28
|
+
password: z.ZodOptional<z.ZodString>;
|
|
29
|
+
}, "strict", z.ZodTypeAny, {
|
|
30
|
+
url?: string;
|
|
31
|
+
user?: string;
|
|
32
|
+
password?: string;
|
|
33
|
+
}, {
|
|
34
|
+
url?: string;
|
|
35
|
+
user?: string;
|
|
36
|
+
password?: string;
|
|
37
|
+
}>;
|
|
38
|
+
export type NatsConnectionConfig = z.infer<typeof natsConnectionSchema>;
|
|
39
|
+
/** A NATS URL or full connection settings. */
|
|
40
|
+
export type NatsTarget = string | NatsConnectionConfig;
|
|
41
|
+
/**
|
|
42
|
+
* The inbox prefix of a NATS user: replies to its requests (and JetStream deliveries) arrive
|
|
43
|
+
* under `_INBOX_<user>.`, the only inbox its permissions let it subscribe to, so no service can
|
|
44
|
+
* read another's replies (nats-permissions/*.conf).
|
|
45
|
+
*/
|
|
46
|
+
export declare function natsInboxPrefix(user: string): string;
|
|
47
|
+
/** nats.js `connect` options for a URL or a `{ url, user, password }` setting. */
|
|
48
|
+
export declare function natsConnectOptions(nats: NatsTarget): {
|
|
49
|
+
servers: string;
|
|
50
|
+
user?: string;
|
|
51
|
+
pass?: string;
|
|
52
|
+
inboxPrefix?: string;
|
|
53
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.natsConnectionSchema = void 0;
|
|
4
|
+
exports.natsInboxPrefix = natsInboxPrefix;
|
|
5
|
+
exports.natsConnectOptions = natsConnectOptions;
|
|
6
|
+
/**
|
|
7
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
8
|
+
* http://github.com/fonoster/fonoster
|
|
9
|
+
*
|
|
10
|
+
* This file is part of Fonoster
|
|
11
|
+
*
|
|
12
|
+
* Licensed under the MIT License (the "License");
|
|
13
|
+
* you may not use this file except in compliance with
|
|
14
|
+
* the License. You may obtain a copy of the License at
|
|
15
|
+
*
|
|
16
|
+
* https://opensource.org/licenses/MIT
|
|
17
|
+
*
|
|
18
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
* See the License for the specific language governing permissions and
|
|
22
|
+
* limitations under the License.
|
|
23
|
+
*/
|
|
24
|
+
const zod_1 = require("zod");
|
|
25
|
+
/**
|
|
26
|
+
* A service's NATS connection settings (add-platform 4.1): the URL plus, when the server has
|
|
27
|
+
* per-service users, the service's user and password. The password is usually a `secret://`
|
|
28
|
+
* reference, resolved by the config loader like any other value.
|
|
29
|
+
*/
|
|
30
|
+
exports.natsConnectionSchema = zod_1.z
|
|
31
|
+
.object({
|
|
32
|
+
url: zod_1.z.string().min(1),
|
|
33
|
+
user: zod_1.z.string().min(1).optional(),
|
|
34
|
+
password: zod_1.z.string().min(1).optional()
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
/**
|
|
38
|
+
* The inbox prefix of a NATS user: replies to its requests (and JetStream deliveries) arrive
|
|
39
|
+
* under `_INBOX_<user>.`, the only inbox its permissions let it subscribe to, so no service can
|
|
40
|
+
* read another's replies (nats-permissions/*.conf).
|
|
41
|
+
*/
|
|
42
|
+
function natsInboxPrefix(user) {
|
|
43
|
+
return `_INBOX_${user}`;
|
|
44
|
+
}
|
|
45
|
+
/** nats.js `connect` options for a URL or a `{ url, user, password }` setting. */
|
|
46
|
+
function natsConnectOptions(nats) {
|
|
47
|
+
var _a;
|
|
48
|
+
if (typeof nats === "string")
|
|
49
|
+
return { servers: nats };
|
|
50
|
+
return nats.user
|
|
51
|
+
? {
|
|
52
|
+
servers: nats.url,
|
|
53
|
+
user: nats.user,
|
|
54
|
+
pass: (_a = nats.password) !== null && _a !== void 0 ? _a : "",
|
|
55
|
+
inboxPrefix: natsInboxPrefix(nats.user)
|
|
56
|
+
}
|
|
57
|
+
: { servers: nats.url };
|
|
58
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
declare const CONFIG_EXTENSIONS: string[];
|
|
2
|
+
/**
|
|
3
|
+
* Parses a config file's text. The extension picks the format: `.yaml`/`.yml`
|
|
4
|
+
* as YAML, `.json`/`.jsonc` as JSON with comments and trailing commas.
|
|
5
|
+
*/
|
|
6
|
+
declare function parseConfigFile(path: string, text: string): unknown;
|
|
7
|
+
export { parseConfigFile, CONFIG_EXTENSIONS };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CONFIG_EXTENSIONS = void 0;
|
|
4
|
+
exports.parseConfigFile = parseConfigFile;
|
|
5
|
+
/**
|
|
6
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
7
|
+
* http://github.com/fonoster/fonoster
|
|
8
|
+
*
|
|
9
|
+
* This file is part of Fonoster
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the MIT License (the "License");
|
|
12
|
+
* you may not use this file except in compliance with
|
|
13
|
+
* the License. You may obtain a copy of the License at
|
|
14
|
+
*
|
|
15
|
+
* https://opensource.org/licenses/MIT
|
|
16
|
+
*
|
|
17
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
* See the License for the specific language governing permissions and
|
|
21
|
+
* limitations under the License.
|
|
22
|
+
*/
|
|
23
|
+
const path_1 = require("path");
|
|
24
|
+
const jsonc_parser_1 = require("jsonc-parser");
|
|
25
|
+
const yaml_1 = require("yaml");
|
|
26
|
+
const YAML_EXTENSIONS = [".yaml", ".yml"];
|
|
27
|
+
const JSON_EXTENSIONS = [".json", ".jsonc"];
|
|
28
|
+
const CONFIG_EXTENSIONS = [...YAML_EXTENSIONS, ...JSON_EXTENSIONS];
|
|
29
|
+
exports.CONFIG_EXTENSIONS = CONFIG_EXTENSIONS;
|
|
30
|
+
function lineAndColumn(text, offset) {
|
|
31
|
+
const before = text.slice(0, offset);
|
|
32
|
+
const line = before.split("\n").length;
|
|
33
|
+
const column = offset - before.lastIndexOf("\n");
|
|
34
|
+
return { line, column };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Parses a config file's text. The extension picks the format: `.yaml`/`.yml`
|
|
38
|
+
* as YAML, `.json`/`.jsonc` as JSON with comments and trailing commas.
|
|
39
|
+
*/
|
|
40
|
+
function parseConfigFile(path, text) {
|
|
41
|
+
var _a;
|
|
42
|
+
const extension = (0, path_1.extname)(path).toLowerCase();
|
|
43
|
+
if (YAML_EXTENSIONS.includes(extension)) {
|
|
44
|
+
return (_a = (0, yaml_1.parse)(text)) !== null && _a !== void 0 ? _a : {};
|
|
45
|
+
}
|
|
46
|
+
if (JSON_EXTENSIONS.includes(extension)) {
|
|
47
|
+
const errors = [];
|
|
48
|
+
const value = (0, jsonc_parser_1.parse)(text, errors, {
|
|
49
|
+
allowTrailingComma: true,
|
|
50
|
+
disallowComments: false
|
|
51
|
+
});
|
|
52
|
+
if (errors.length > 0) {
|
|
53
|
+
const first = errors[0];
|
|
54
|
+
const { line, column } = lineAndColumn(text, first.offset);
|
|
55
|
+
throw new Error(`${(0, jsonc_parser_1.printParseErrorCode)(first.error)} at line ${line}, column ${column}`);
|
|
56
|
+
}
|
|
57
|
+
return value !== null && value !== void 0 ? value : {};
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`unsupported extension "${extension}" (use ${CONFIG_EXTENSIONS.join(", ")})`);
|
|
60
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
declare const DEFAULT_SEARCH_DIRS: string[];
|
|
2
|
+
type ResolvedConfigFile = {
|
|
3
|
+
path: string;
|
|
4
|
+
explicit: boolean;
|
|
5
|
+
} | {
|
|
6
|
+
path: undefined;
|
|
7
|
+
explicit: false;
|
|
8
|
+
searched: string[];
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Finds a service's config file. `--config <path>` wins; otherwise each search
|
|
12
|
+
* directory is tried in order for `<fileBase>` with a supported extension.
|
|
13
|
+
* Two candidates in the same directory is an error: the operator would not
|
|
14
|
+
* know which one is in effect.
|
|
15
|
+
*/
|
|
16
|
+
declare function resolveConfigFile(fileBase: string, argv: string[], searchDirs?: string[]): ResolvedConfigFile;
|
|
17
|
+
export { resolveConfigFile, DEFAULT_SEARCH_DIRS, ResolvedConfigFile };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_SEARCH_DIRS = void 0;
|
|
4
|
+
exports.resolveConfigFile = resolveConfigFile;
|
|
5
|
+
/**
|
|
6
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
7
|
+
* http://github.com/fonoster/fonoster
|
|
8
|
+
*
|
|
9
|
+
* This file is part of Fonoster
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the MIT License (the "License");
|
|
12
|
+
* you may not use this file except in compliance with
|
|
13
|
+
* the License. You may obtain a copy of the License at
|
|
14
|
+
*
|
|
15
|
+
* https://opensource.org/licenses/MIT
|
|
16
|
+
*
|
|
17
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
* See the License for the specific language governing permissions and
|
|
21
|
+
* limitations under the License.
|
|
22
|
+
*/
|
|
23
|
+
const fs_1 = require("fs");
|
|
24
|
+
const path_1 = require("path");
|
|
25
|
+
const parseConfigFile_1 = require("./parseConfigFile");
|
|
26
|
+
// `/config` is where the bundle mounts each service's file (unify-config-placeholders).
|
|
27
|
+
const DEFAULT_SEARCH_DIRS = ["/config", "/opt/fonoster", "./config"];
|
|
28
|
+
exports.DEFAULT_SEARCH_DIRS = DEFAULT_SEARCH_DIRS;
|
|
29
|
+
/**
|
|
30
|
+
* Finds a service's config file. `--config <path>` wins; otherwise each search
|
|
31
|
+
* directory is tried in order for `<fileBase>` with a supported extension.
|
|
32
|
+
* Two candidates in the same directory is an error: the operator would not
|
|
33
|
+
* know which one is in effect.
|
|
34
|
+
*/
|
|
35
|
+
function resolveConfigFile(fileBase, argv, searchDirs = DEFAULT_SEARCH_DIRS) {
|
|
36
|
+
const flagIndex = argv.indexOf("--config");
|
|
37
|
+
const fromFlag = flagIndex >= 0 ? argv[flagIndex + 1] : undefined;
|
|
38
|
+
if (fromFlag) {
|
|
39
|
+
return { path: (0, path_1.resolve)(process.cwd(), fromFlag), explicit: true };
|
|
40
|
+
}
|
|
41
|
+
const searched = [];
|
|
42
|
+
for (const dir of searchDirs) {
|
|
43
|
+
const candidates = parseConfigFile_1.CONFIG_EXTENSIONS.map((extension) => (0, path_1.resolve)(process.cwd(), (0, path_1.join)(dir, `${fileBase}${extension}`)));
|
|
44
|
+
searched.push(...candidates);
|
|
45
|
+
const found = candidates.filter((candidate) => (0, fs_1.existsSync)(candidate));
|
|
46
|
+
if (found.length > 1) {
|
|
47
|
+
throw new Error(`found more than one ${fileBase} config file (${found.join(", ")}); keep only one`);
|
|
48
|
+
}
|
|
49
|
+
if (found.length === 1) {
|
|
50
|
+
return { path: found[0], explicit: false };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { path: undefined, explicit: false, searched };
|
|
54
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type Env = Record<string, string | undefined>;
|
|
2
|
+
/**
|
|
3
|
+
* `secret://` references in config values (add-platform, decision D8). A string value that is
|
|
4
|
+
* exactly a reference is replaced at startup by the secret it names, so YAML never holds the raw
|
|
5
|
+
* secret:
|
|
6
|
+
*
|
|
7
|
+
* secret://env/NAME the environment variable NAME
|
|
8
|
+
* secret://file/<absolute path> a file's contents (e.g. secret://file/run/secrets/db-url)
|
|
9
|
+
* secret://k8s/<secret>#<key> a Kubernetes Secret mounted as a volume, read from
|
|
10
|
+
* secret://k8s/<ns>/<secret>#<key> <FONOSTER_SECRETS_DIR>/<secret>/<key>
|
|
11
|
+
* (default /var/run/fonoster/secrets; the Helm chart mounts
|
|
12
|
+
* every referenced Secret there). The namespace, when given,
|
|
13
|
+
* must be the pod's (POD_NAMESPACE) if that is known.
|
|
14
|
+
*
|
|
15
|
+
* File contents lose one trailing newline. Errors name the key path and the reference, never a
|
|
16
|
+
* value. Values that only contain `secret://` somewhere else are left alone.
|
|
17
|
+
*/
|
|
18
|
+
export declare const SECRET_PREFIX = "secret://";
|
|
19
|
+
export declare const DEFAULT_SECRETS_DIR = "/var/run/fonoster/secrets";
|
|
20
|
+
export type SecretRefOptions = {
|
|
21
|
+
env?: Env;
|
|
22
|
+
/** Where Kubernetes Secrets are mounted (default FONOSTER_SECRETS_DIR or /var/run/fonoster/secrets). */
|
|
23
|
+
secretsDir?: string;
|
|
24
|
+
/** Reads a file (tests). */
|
|
25
|
+
readFile?: (path: string) => string;
|
|
26
|
+
};
|
|
27
|
+
export declare function isSecretRef(value: unknown): value is string;
|
|
28
|
+
/** Resolves one `secret://` reference. Throws with a message that never contains the secret. */
|
|
29
|
+
export declare function resolveSecretRef(ref: string, options?: SecretRefOptions): string;
|
|
30
|
+
/**
|
|
31
|
+
* Returns a copy of a parsed config with every `secret://` value resolved. Errors name the key
|
|
32
|
+
* path (`providers.deepgram.credential.value: secret://env/DG: environment variable DG is not set`).
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveSecretRefs<T>(input: T, options?: SecretRefOptions): T;
|
|
35
|
+
export {};
|