@fonoster/common 0.27.0 → 0.30.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.
Files changed (176) hide show
  1. package/dist/assistants/index.d.ts +2 -6
  2. package/dist/assistants/index.js +2 -6
  3. package/dist/assistants/sessionAssistantSchema.d.ts +741 -0
  4. package/dist/assistants/sessionAssistantSchema.js +112 -0
  5. package/dist/assistants/testCasesSchema.d.ts +4 -4
  6. package/dist/{voice/Dial.d.ts → calls/index.d.ts} +16 -13
  7. package/dist/calls/index.js +44 -0
  8. package/dist/cellsecrets/index.d.ts +91 -0
  9. package/dist/cellsecrets/index.js +299 -0
  10. package/dist/config/cli/check.d.ts +6 -0
  11. package/dist/config/cli/check.js +202 -0
  12. package/dist/config/cli/envFile.d.ts +23 -0
  13. package/dist/config/cli/envFile.js +81 -0
  14. package/dist/config/cli/exposure.d.ts +10 -0
  15. package/dist/config/cli/exposure.js +93 -0
  16. package/dist/config/cli/index.d.ts +2 -0
  17. package/dist/{identity/tokenHasAccessKeyId.js → config/cli/index.js} +7 -8
  18. package/dist/config/cli/info.d.ts +6 -0
  19. package/dist/config/cli/info.js +62 -0
  20. package/dist/config/cli/init.d.ts +9 -0
  21. package/dist/config/cli/init.js +152 -0
  22. package/dist/config/cli/main.d.ts +11 -0
  23. package/dist/config/cli/main.js +155 -0
  24. package/dist/config/cli/render.d.ts +44 -0
  25. package/dist/config/cli/render.js +129 -0
  26. package/dist/config/cli/secrets.d.ts +21 -0
  27. package/dist/config/cli/secrets.js +117 -0
  28. package/dist/{utils/findIntegrationsCredentials.d.ts → config/cli/types.d.ts} +6 -5
  29. package/dist/config/cli/types.js +7 -0
  30. package/dist/config/configHints.d.ts +39 -0
  31. package/dist/config/configHints.js +61 -0
  32. package/dist/{voice → config}/index.d.ts +12 -13
  33. package/dist/config/index.js +46 -0
  34. package/dist/config/integrationsSchema.d.ts +32 -0
  35. package/dist/config/integrationsSchema.js +56 -0
  36. package/dist/config/interpolateEnv.d.ts +34 -0
  37. package/dist/config/interpolateEnv.js +70 -0
  38. package/dist/config/loadServiceConfig.d.ts +33 -0
  39. package/dist/config/loadServiceConfig.js +121 -0
  40. package/dist/config/logsSchema.d.ts +76 -0
  41. package/dist/config/logsSchema.js +49 -0
  42. package/dist/config/natsConnection.d.ts +53 -0
  43. package/dist/config/natsConnection.js +58 -0
  44. package/dist/config/parseConfigFile.d.ts +7 -0
  45. package/dist/config/parseConfigFile.js +60 -0
  46. package/dist/config/resolveConfigFile.d.ts +17 -0
  47. package/dist/config/resolveConfigFile.js +54 -0
  48. package/dist/config/resolveSecretRefs.d.ts +35 -0
  49. package/dist/config/resolveSecretRefs.js +129 -0
  50. package/dist/{assistants/audioFiltersSchema.d.ts → config/strictDeep.d.ts} +9 -12
  51. package/dist/config/strictDeep.js +58 -0
  52. package/dist/config/telemetrySchema.d.ts +39 -0
  53. package/dist/config/telemetrySchema.js +44 -0
  54. package/dist/config/toJsonSchema.d.ts +30 -0
  55. package/dist/config/toJsonSchema.js +161 -0
  56. package/dist/constants.d.ts +1 -4
  57. package/dist/constants.js +4 -5
  58. package/dist/envs.d.ts +2 -1
  59. package/dist/envs.js +13 -11
  60. package/dist/identity/createAuthInterceptor.d.ts +9 -2
  61. package/dist/identity/createAuthInterceptor.js +36 -30
  62. package/dist/identity/hasAccess.d.ts +9 -3
  63. package/dist/identity/hasAccess.js +32 -8
  64. package/dist/identity/index.d.ts +1 -0
  65. package/dist/identity/index.js +1 -0
  66. package/dist/identity/isValidToken.d.ts +12 -2
  67. package/dist/identity/isValidToken.js +25 -9
  68. package/dist/identity/roles.js +22 -6
  69. package/dist/identity/types.d.ts +6 -1
  70. package/dist/identity/types.js +1 -0
  71. package/dist/{assistants/LanguageModelProvider.js → identity/verifyAccessToken.d.ts} +10 -11
  72. package/dist/identity/verifyAccessToken.js +44 -0
  73. package/dist/index.d.ts +11 -1
  74. package/dist/index.js +14 -2
  75. package/dist/net/assertPublicDestination.d.ts +52 -0
  76. package/dist/net/assertPublicDestination.js +342 -0
  77. package/dist/{voice/PlayDtmf.d.ts → net/index.d.ts} +1 -5
  78. package/dist/{voice → net}/index.js +1 -13
  79. package/dist/notifications/createSendEmail.js +3 -1
  80. package/dist/protos/applications.proto +124 -3
  81. package/dist/protos/authz.proto +23 -4
  82. package/dist/protos/capabilities.proto +94 -0
  83. package/dist/protos/identity.proto +26 -1
  84. package/dist/protos/providers.proto +135 -0
  85. package/dist/protos/webhooks.proto +140 -0
  86. package/dist/{voice/StopSay.d.ts → regions/hub/index.d.ts} +1 -6
  87. package/dist/regions/hub/index.js +35 -0
  88. package/dist/regions/hub/natsJwt.d.ts +63 -0
  89. package/dist/regions/hub/natsJwt.js +195 -0
  90. package/dist/registry/Registry.d.ts +79 -0
  91. package/dist/registry/Registry.js +418 -0
  92. package/dist/registry/cli.d.ts +20 -0
  93. package/dist/registry/cli.js +424 -0
  94. package/dist/{assistants/audioFiltersSchema.js → registry/features.d.ts} +13 -14
  95. package/dist/registry/features.js +36 -0
  96. package/dist/{assistants/LanguageModelProvider.d.ts → registry/index.d.ts} +6 -8
  97. package/dist/registry/index.js +40 -0
  98. package/dist/registry/prisma.d.ts +67 -0
  99. package/dist/registry/prisma.js +391 -0
  100. package/dist/registry/stores.d.ts +21 -0
  101. package/dist/{assistants/eventsHookSchema.js → registry/stores.js} +55 -18
  102. package/dist/registry/types.d.ts +98 -0
  103. package/dist/{voice/Say.d.ts → registry/types.js} +4 -10
  104. package/dist/registry/workspaceKeys.d.ts +41 -0
  105. package/dist/registry/workspaceKeys.js +64 -0
  106. package/dist/session/index.d.ts +19 -0
  107. package/dist/session/index.js +35 -0
  108. package/dist/session/schema.d.ts +1951 -0
  109. package/dist/session/schema.js +397 -0
  110. package/dist/sessions/index.d.ts +93 -0
  111. package/dist/sessions/index.js +194 -0
  112. package/dist/telemetry.d.ts +76 -0
  113. package/dist/telemetry.js +360 -0
  114. package/dist/types.d.ts +3 -5
  115. package/dist/utils/{findIntegrationsCredentials.js → WriteBehind.d.ts} +13 -10
  116. package/dist/utils/WriteBehind.js +64 -0
  117. package/dist/utils/index.d.ts +1 -1
  118. package/dist/utils/index.js +1 -1
  119. package/dist/{voice/Play.d.ts → utils/logUnhandledRejections.d.ts} +8 -12
  120. package/dist/utils/logUnhandledRejections.js +37 -0
  121. package/dist/validators/calls.d.ts +2 -2
  122. package/dist/validators/calls.js +5 -2
  123. package/dist/validators/identity.d.ts +37 -8
  124. package/dist/validators/identity.js +22 -3
  125. package/dist/validators/index.d.ts +1 -0
  126. package/dist/validators/index.js +1 -0
  127. package/dist/validators/sip.d.ts +40 -0
  128. package/dist/validators/sip.js +99 -0
  129. package/dist/validators/sipnet/credentials.d.ts +2 -2
  130. package/dist/validators/sipnet/domains.js +7 -7
  131. package/dist/validators/sipnet/trunks.d.ts +14 -14
  132. package/dist/validators/sipnet/trunks.js +4 -2
  133. package/dist/webhooks/Dispatcher.d.ts +87 -0
  134. package/dist/webhooks/Dispatcher.js +225 -0
  135. package/dist/webhooks/bus.d.ts +49 -0
  136. package/dist/webhooks/bus.js +170 -0
  137. package/dist/webhooks/events.d.ts +66 -0
  138. package/dist/webhooks/events.js +62 -0
  139. package/dist/webhooks/index.d.ts +23 -0
  140. package/dist/webhooks/index.js +39 -0
  141. package/dist/webhooks/prisma.d.ts +55 -0
  142. package/dist/webhooks/prisma.js +242 -0
  143. package/dist/webhooks/signing.d.ts +8 -0
  144. package/dist/webhooks/signing.js +53 -0
  145. package/package.json +25 -12
  146. package/schema/session.v1.json +791 -0
  147. package/dist/assistants/assistantSchema.d.ts +0 -739
  148. package/dist/assistants/assistantSchema.js +0 -37
  149. package/dist/assistants/conversationSettingsSchema.d.ts +0 -122
  150. package/dist/assistants/conversationSettingsSchema.js +0 -133
  151. package/dist/assistants/eventsHookSchema.d.ts +0 -38
  152. package/dist/assistants/languageModelConfigSchema.d.ts +0 -206
  153. package/dist/assistants/languageModelConfigSchema.js +0 -91
  154. package/dist/identity/tokenHasAccessKeyId.d.ts +0 -2
  155. package/dist/protos/voice.proto +0 -557
  156. package/dist/voice/Dial.js +0 -20
  157. package/dist/voice/Gather.d.ts +0 -37
  158. package/dist/voice/Gather.js +0 -9
  159. package/dist/voice/Mute.d.ts +0 -31
  160. package/dist/voice/Mute.js +0 -9
  161. package/dist/voice/Play.js +0 -2
  162. package/dist/voice/PlayDtmf.js +0 -2
  163. package/dist/voice/PlaybackControl.d.ts +0 -31
  164. package/dist/voice/PlaybackControl.js +0 -11
  165. package/dist/voice/Record.d.ts +0 -36
  166. package/dist/voice/Record.js +0 -7
  167. package/dist/voice/Say.js +0 -2
  168. package/dist/voice/StopSay.js +0 -2
  169. package/dist/voice/Stream.d.ts +0 -53
  170. package/dist/voice/Stream.js +0 -19
  171. package/dist/voice/StreamGather.d.ts +0 -34
  172. package/dist/voice/StreamGather.js +0 -9
  173. package/dist/voice/Verb.d.ts +0 -27
  174. package/dist/voice/Verb.js +0 -2
  175. package/dist/voice/voice.d.ts +0 -171
  176. package/dist/voice/voice.js +0 -65
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
19
+ * http://github.com/fonoster/fonoster
20
+ *
21
+ * This file is part of Fonoster
22
+ *
23
+ * Licensed under the MIT License (the "License");
24
+ * you may not use this file except in compliance with
25
+ * the License. You may obtain a copy of the License at
26
+ *
27
+ * https://opensource.org/licenses/MIT
28
+ *
29
+ * Unless required by applicable law or agreed to in writing, software
30
+ * distributed under the License is distributed on an "AS IS" BASIS,
31
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32
+ * See the License for the specific language governing permissions and
33
+ * limitations under the License.
34
+ */
35
+ __exportStar(require("./configHints"), exports);
36
+ __exportStar(require("./integrationsSchema"), exports);
37
+ __exportStar(require("./interpolateEnv"), exports);
38
+ __exportStar(require("./loadServiceConfig"), exports);
39
+ __exportStar(require("./logsSchema"), exports);
40
+ __exportStar(require("./parseConfigFile"), exports);
41
+ __exportStar(require("./resolveConfigFile"), exports);
42
+ __exportStar(require("./resolveSecretRefs"), exports);
43
+ __exportStar(require("./strictDeep"), exports);
44
+ __exportStar(require("./telemetrySchema"), exports);
45
+ __exportStar(require("./natsConnection"), exports);
46
+ __exportStar(require("./toJsonSchema"), exports);
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ declare const integrationsConfigSchema: z.ZodArray<z.ZodObject<{
3
+ name: z.ZodString;
4
+ productRef: z.ZodString;
5
+ type: z.ZodEnum<["tts", "stt", "llm"]>;
6
+ credentials: z.ZodRecord<z.ZodString, z.ZodUnknown>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ type?: "tts" | "stt" | "llm";
9
+ name?: string;
10
+ productRef?: string;
11
+ credentials?: Record<string, unknown>;
12
+ }, {
13
+ type?: "tts" | "stt" | "llm";
14
+ name?: string;
15
+ productRef?: string;
16
+ credentials?: Record<string, unknown>;
17
+ }>, "many">;
18
+ /** Spelled out so callers get required fields regardless of tsconfig strictness. */
19
+ type IntegrationsConfig = Array<{
20
+ name: string;
21
+ productRef: string;
22
+ type: "tts" | "stt" | "llm";
23
+ credentials: Record<string, unknown>;
24
+ }>;
25
+ /**
26
+ * Reads and validates the retired integrations file. Only `fonoster-migrate-legacy --integrations`
27
+ * reads it now, to move its keys into operator config by credentialRef (add-provider-registry 5.3).
28
+ * YAML (`.yaml`/`.yml`) or JSON with comments (`.json`/`.jsonc`). Throws with the
29
+ * file path when the file can't be read or doesn't validate.
30
+ */
31
+ declare function getIntegrationsFromFile(pathToIntegrations: string): IntegrationsConfig;
32
+ export { integrationsConfigSchema, IntegrationsConfig, getIntegrationsFromFile };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.integrationsConfigSchema = void 0;
7
+ exports.getIntegrationsFromFile = getIntegrationsFromFile;
8
+ /**
9
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
10
+ * http://github.com/fonoster/fonoster
11
+ *
12
+ * This file is part of Fonoster
13
+ *
14
+ * Licensed under the MIT License (the "License");
15
+ * you may not use this file except in compliance with
16
+ * the License. You may obtain a copy of the License at
17
+ *
18
+ * https://opensource.org/licenses/MIT
19
+ *
20
+ * Unless required by applicable law or agreed to in writing, software
21
+ * distributed under the License is distributed on an "AS IS" BASIS,
22
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
+ * See the License for the specific language governing permissions and
24
+ * limitations under the License.
25
+ */
26
+ const fs_1 = __importDefault(require("fs"));
27
+ const zod_1 = require("zod");
28
+ const zod_validation_error_1 = require("zod-validation-error");
29
+ const parseConfigFile_1 = require("./parseConfigFile");
30
+ const integrationsConfigSchema = zod_1.z.array(zod_1.z.object({
31
+ name: zod_1.z.string(),
32
+ productRef: zod_1.z.string(),
33
+ type: zod_1.z.enum(["tts", "stt", "llm"]),
34
+ credentials: zod_1.z.record(zod_1.z.unknown())
35
+ }));
36
+ exports.integrationsConfigSchema = integrationsConfigSchema;
37
+ /**
38
+ * Reads and validates the retired integrations file. Only `fonoster-migrate-legacy --integrations`
39
+ * reads it now, to move its keys into operator config by credentialRef (add-provider-registry 5.3).
40
+ * YAML (`.yaml`/`.yml`) or JSON with comments (`.json`/`.jsonc`). Throws with the
41
+ * file path when the file can't be read or doesn't validate.
42
+ */
43
+ function getIntegrationsFromFile(pathToIntegrations) {
44
+ let raw;
45
+ try {
46
+ raw = (0, parseConfigFile_1.parseConfigFile)(pathToIntegrations, fs_1.default.readFileSync(pathToIntegrations, "utf8"));
47
+ }
48
+ catch (e) {
49
+ throw new Error(`unable to read integrations at ${pathToIntegrations}: ${e.message}`);
50
+ }
51
+ const result = integrationsConfigSchema.safeParse(raw);
52
+ if (!result.success) {
53
+ throw new Error(`invalid integrations at ${pathToIntegrations}: ${(0, zod_validation_error_1.fromError)(result.error, { prefix: null }).toString()}`);
54
+ }
55
+ return result.data;
56
+ }
@@ -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 `influxdb.*`
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,33 @@
1
+ import { z, ZodTypeAny } from "zod";
2
+ import { MovedKeys } from "./configHints";
3
+ type Env = Record<string, string | undefined>;
4
+ type LoadServiceConfigOptions<S extends ZodTypeAny> = {
5
+ /** Service name, used in messages. */
6
+ service: string;
7
+ /** File name without extension. Defaults to `service`. */
8
+ fileBase?: string;
9
+ /** Zod schema that validates (and applies defaults to) the config. */
10
+ schema: S;
11
+ /** Defaults to `process.argv`; `--config <path>` picks the file. */
12
+ argv?: string[];
13
+ /** Only used to resolve `${VAR}` placeholders. Defaults to `process.env`. */
14
+ env?: Env;
15
+ /** Directories searched when `--config` is absent. */
16
+ searchDirs?: string[];
17
+ /**
18
+ * Key paths that may reference `${VAR}` (values Compose passes from `.env`). `["*"]` allows
19
+ * every key (the default for Fonoster services, unify-config-placeholders); `${...}` anywhere
20
+ * else is an error.
21
+ */
22
+ interpolatePaths?: string[];
23
+ /** Old key path → new key path, reported as hints. */
24
+ movedKeys?: MovedKeys;
25
+ /** Env var prefixes of the old env-based config, reported as a warning. */
26
+ legacyEnvPrefixes?: string[];
27
+ };
28
+ /**
29
+ * Loads, interpolates and strictly validates a service's config file.
30
+ * Throws with the file path and the offending key path on any problem.
31
+ */
32
+ declare function loadServiceConfig<S extends ZodTypeAny>(options: LoadServiceConfigOptions<S>): z.output<S>;
33
+ export { loadServiceConfig, LoadServiceConfigOptions };
@@ -0,0 +1,121 @@
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 configHints_1 = require("./configHints");
25
+ const interpolateEnv_1 = require("./interpolateEnv");
26
+ const parseConfigFile_1 = require("./parseConfigFile");
27
+ const resolveConfigFile_1 = require("./resolveConfigFile");
28
+ const resolveSecretRefs_1 = require("./resolveSecretRefs");
29
+ const strictDeep_1 = require("./strictDeep");
30
+ const logger = (0, logger_1.getLogger)({ service: "common", filePath: __filename });
31
+ /**
32
+ * One line per problem, each led by the key path:
33
+ * `smtp: unknown key "hsot"`, `features.auth.methods[1]: Invalid enum value ...`.
34
+ */
35
+ function formatIssues(error) {
36
+ return error.issues
37
+ .map((issue) => {
38
+ const path = issue.path
39
+ .map((segment, index) => typeof segment === "number"
40
+ ? `[${segment}]`
41
+ : index === 0
42
+ ? segment
43
+ : `.${segment}`)
44
+ .join("");
45
+ const where = path || "(root)";
46
+ if (issue.code === "unrecognized_keys") {
47
+ const keys = issue.keys.map((key) => `"${key}"`).join(", ");
48
+ return `${where}: unknown key${issue.keys.length > 1 ? "s" : ""} ${keys}`;
49
+ }
50
+ return `${where}: ${issue.message}`;
51
+ })
52
+ .join("; ");
53
+ }
54
+ /**
55
+ * Loads, interpolates and strictly validates a service's config file.
56
+ * Throws with the file path and the offending key path on any problem.
57
+ */
58
+ function loadServiceConfig(options) {
59
+ var _a, _b, _c, _d, _e, _f, _g;
60
+ const { service, schema } = options;
61
+ const fileBase = (_a = options.fileBase) !== null && _a !== void 0 ? _a : service;
62
+ const argv = (_b = options.argv) !== null && _b !== void 0 ? _b : process.argv;
63
+ const env = (_c = options.env) !== null && _c !== void 0 ? _c : process.env;
64
+ const legacy = (0, configHints_1.findLegacyEnv)((_d = options.legacyEnvPrefixes) !== null && _d !== void 0 ? _d : [], env);
65
+ if (legacy.length > 0) {
66
+ logger.warn(`ignoring ${legacy.length} legacy environment variable(s); ${service} now reads its config file only: ${legacy.join(", ")}`);
67
+ }
68
+ const resolved = (0, resolveConfigFile_1.resolveConfigFile)(fileBase, argv, options.searchDirs);
69
+ const where = (_e = resolved.path) !== null && _e !== void 0 ? _e : "(built-in defaults)";
70
+ let raw = {};
71
+ if ("searched" in resolved) {
72
+ logger.warn(`no ${service} config file found (looked for ${resolved.searched.join(", ")}); using built-in defaults`);
73
+ }
74
+ else if (!(0, fs_1.existsSync)(resolved.path)) {
75
+ throw new Error(`unable to read ${service} config at ${resolved.path}: file not found`);
76
+ }
77
+ else {
78
+ try {
79
+ raw = (0, parseConfigFile_1.parseConfigFile)(resolved.path, (0, fs_1.readFileSync)(resolved.path, "utf8"));
80
+ }
81
+ catch (e) {
82
+ throw new Error(`unable to read ${service} config at ${resolved.path}: ${e.message}`);
83
+ }
84
+ }
85
+ // "$schema" points editors at the JSON Schema for autocomplete; it isn't config.
86
+ if (raw !== null && typeof raw === "object" && "$schema" in raw) {
87
+ const rest = Object.assign({}, raw);
88
+ delete rest.$schema;
89
+ raw = rest;
90
+ }
91
+ const moved = (0, configHints_1.findMovedKeys)(raw, (_f = options.movedKeys) !== null && _f !== void 0 ? _f : {});
92
+ if (moved.length > 0) {
93
+ throw new Error(`invalid ${service} config at ${where}: ${moved.join("; ")}`);
94
+ }
95
+ let interpolated;
96
+ try {
97
+ interpolated = (0, interpolateEnv_1.interpolateEnv)(raw, env, {
98
+ allowedPaths: (_g = options.interpolatePaths) !== null && _g !== void 0 ? _g : []
99
+ });
100
+ }
101
+ catch (e) {
102
+ throw new Error(`invalid ${service} config at ${where}: ${e.message}`);
103
+ }
104
+ // `secret://` references (D8): resolved here so the schema sees real values.
105
+ let withSecrets;
106
+ try {
107
+ withSecrets = (0, resolveSecretRefs_1.resolveSecretRefs)(interpolated, { env });
108
+ }
109
+ catch (e) {
110
+ throw new Error(`invalid ${service} config at ${where}: ${e.message}`);
111
+ }
112
+ const strictSchema = (0, strictDeep_1.strictDeep)(schema);
113
+ const result = strictSchema.safeParse(withSecrets);
114
+ if (!result.success) {
115
+ throw new Error(`invalid ${service} config at ${where}: ${formatIssues(result.error)}`);
116
+ }
117
+ if (resolved.path) {
118
+ logger.verbose(`loaded ${service} config`, { path: resolved.path });
119
+ }
120
+ return result.data;
121
+ }
@@ -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 };