@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,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 {};
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_SECRETS_DIR = exports.SECRET_PREFIX = void 0;
4
+ exports.isSecretRef = isSecretRef;
5
+ exports.resolveSecretRef = resolveSecretRef;
6
+ exports.resolveSecretRefs = resolveSecretRefs;
7
+ /**
8
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
9
+ * http://github.com/fonoster/fonoster
10
+ *
11
+ * This file is part of Fonoster
12
+ *
13
+ * Licensed under the MIT License (the "License");
14
+ * you may not use this file except in compliance with
15
+ * the License. You may obtain a copy of the License at
16
+ *
17
+ * https://opensource.org/licenses/MIT
18
+ *
19
+ * Unless required by applicable law or agreed to in writing, software
20
+ * distributed under the License is distributed on an "AS IS" BASIS,
21
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ * See the License for the specific language governing permissions and
23
+ * limitations under the License.
24
+ */
25
+ const fs_1 = require("fs");
26
+ const path_1 = require("path");
27
+ /**
28
+ * `secret://` references in config values (add-platform, decision D8). A string value that is
29
+ * exactly a reference is replaced at startup by the secret it names, so YAML never holds the raw
30
+ * secret:
31
+ *
32
+ * secret://env/NAME the environment variable NAME
33
+ * secret://file/<absolute path> a file's contents (e.g. secret://file/run/secrets/db-url)
34
+ * secret://k8s/<secret>#<key> a Kubernetes Secret mounted as a volume, read from
35
+ * secret://k8s/<ns>/<secret>#<key> <FONOSTER_SECRETS_DIR>/<secret>/<key>
36
+ * (default /var/run/fonoster/secrets; the Helm chart mounts
37
+ * every referenced Secret there). The namespace, when given,
38
+ * must be the pod's (POD_NAMESPACE) if that is known.
39
+ *
40
+ * File contents lose one trailing newline. Errors name the key path and the reference, never a
41
+ * value. Values that only contain `secret://` somewhere else are left alone.
42
+ */
43
+ exports.SECRET_PREFIX = "secret://";
44
+ exports.DEFAULT_SECRETS_DIR = "/var/run/fonoster/secrets";
45
+ const NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
46
+ const K8S_NAME = /^[a-z0-9]([-a-z0-9.]*[a-z0-9])?$/;
47
+ const K8S_KEY = /^[-._a-zA-Z0-9]+$/;
48
+ function isSecretRef(value) {
49
+ return typeof value === "string" && value.startsWith(exports.SECRET_PREFIX);
50
+ }
51
+ function readSecretFile(ref, path, options) {
52
+ var _a;
53
+ const read = (_a = options.readFile) !== null && _a !== void 0 ? _a : ((p) => (0, fs_1.readFileSync)(p, { encoding: "utf8" }));
54
+ try {
55
+ return read(path).replace(/\r?\n$/, "");
56
+ }
57
+ catch (e) {
58
+ const code = e.code;
59
+ throw new Error(`${ref}: cannot read ${path}${code ? ` (${code})` : ""}`);
60
+ }
61
+ }
62
+ /** Resolves one `secret://` reference. Throws with a message that never contains the secret. */
63
+ function resolveSecretRef(ref, options = {}) {
64
+ var _a, _b, _c;
65
+ const env = (_a = options.env) !== null && _a !== void 0 ? _a : process.env;
66
+ const rest = ref.slice(exports.SECRET_PREFIX.length);
67
+ const slash = rest.indexOf("/");
68
+ const kind = slash < 0 ? rest : rest.slice(0, slash);
69
+ const target = slash < 0 ? "" : rest.slice(slash + 1);
70
+ if (kind === "env") {
71
+ if (!NAME.test(target))
72
+ throw new Error(`invalid variable name in ${ref}`);
73
+ const value = env[target];
74
+ if (value === undefined || value === "")
75
+ throw new Error(`${ref}: environment variable ${target} is not set`);
76
+ return value;
77
+ }
78
+ if (kind === "file") {
79
+ if (!target)
80
+ throw new Error(`${ref}: missing file path`);
81
+ const path = (0, path_1.resolve)("/", target);
82
+ return readSecretFile(ref, path, options);
83
+ }
84
+ if (kind === "k8s") {
85
+ const hash = target.indexOf("#");
86
+ if (hash < 0)
87
+ throw new Error(`${ref}: missing #<key>`);
88
+ const parts = target.slice(0, hash).split("/");
89
+ const key = target.slice(hash + 1);
90
+ if (parts.length > 2 || !parts.every((p) => K8S_NAME.test(p)))
91
+ throw new Error(`${ref}: expected secret://k8s/[<namespace>/]<secret>#<key>`);
92
+ if (!K8S_KEY.test(key))
93
+ throw new Error(`${ref}: invalid key`);
94
+ const [namespace, name] = parts.length === 2 ? parts : [undefined, parts[0]];
95
+ const podNamespace = env.POD_NAMESPACE;
96
+ if (namespace && podNamespace && namespace !== podNamespace)
97
+ throw new Error(`${ref}: Secrets of namespace ${namespace} are not mounted here (${podNamespace})`);
98
+ const dir = (_c = (_b = options.secretsDir) !== null && _b !== void 0 ? _b : env.FONOSTER_SECRETS_DIR) !== null && _c !== void 0 ? _c : exports.DEFAULT_SECRETS_DIR;
99
+ const base = (0, path_1.isAbsolute)(dir) ? dir : (0, path_1.resolve)(dir);
100
+ return readSecretFile(ref, (0, path_1.join)(base, name, key), options);
101
+ }
102
+ throw new Error(`unsupported reference ${ref} (use secret://env/NAME, secret://file/<path> or secret://k8s/<secret>#<key>)`);
103
+ }
104
+ function walk(input, options, path) {
105
+ if (isSecretRef(input)) {
106
+ try {
107
+ return resolveSecretRef(input, options);
108
+ }
109
+ catch (e) {
110
+ throw new Error(`${path || "(root)"}: ${e.message}`);
111
+ }
112
+ }
113
+ if (Array.isArray(input))
114
+ return input.map((item, i) => walk(item, options, `${path}[${i}]`));
115
+ if (input !== null && typeof input === "object") {
116
+ return Object.fromEntries(Object.entries(input).map(([k, v]) => [
117
+ k,
118
+ walk(v, options, path ? `${path}.${k}` : k)
119
+ ]));
120
+ }
121
+ return input;
122
+ }
123
+ /**
124
+ * Returns a copy of a parsed config with every `secret://` value resolved. Errors name the key
125
+ * path (`providers.deepgram.credential.value: secret://env/DG: environment variable DG is not set`).
126
+ */
127
+ function resolveSecretRefs(input, options = {}) {
128
+ return walk(input, options, "");
129
+ }
@@ -16,15 +16,12 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
- import { z } from "zod";
20
- declare const audioFiltersSchema: z.ZodDefault<z.ZodArray<z.ZodObject<{
21
- name: z.ZodString;
22
- options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
23
- }, "strip", z.ZodTypeAny, {
24
- options?: Record<string, unknown>;
25
- name?: string;
26
- }, {
27
- options?: Record<string, unknown>;
28
- name?: string;
29
- }>, "many">>;
30
- export { audioFiltersSchema };
19
+ import { ZodTypeAny } from "zod";
20
+ /**
21
+ * Returns a copy of `schema` in which every object rejects unknown keys, so a
22
+ * misspelled config key fails validation instead of being silently dropped.
23
+ * Objects declared with `.passthrough()` (free-form blocks such as provider
24
+ * credentials) are left as they are.
25
+ */
26
+ declare function strictDeep<T extends ZodTypeAny>(schema: T): T;
27
+ export { strictDeep };
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.strictDeep = strictDeep;
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
+ /**
24
+ * Returns a copy of `schema` in which every object rejects unknown keys, so a
25
+ * misspelled config key fails validation instead of being silently dropped.
26
+ * Objects declared with `.passthrough()` (free-form blocks such as provider
27
+ * credentials) are left as they are.
28
+ */
29
+ function strictDeep(schema) {
30
+ if (schema instanceof zod_1.ZodObject) {
31
+ const shape = schema.shape;
32
+ const strictShape = Object.fromEntries(Object.entries(shape).map(([key, value]) => [key, strictDeep(value)]));
33
+ const unknownKeys = schema._def.unknownKeys === "passthrough" ? "passthrough" : "strict";
34
+ return new zod_1.ZodObject(Object.assign(Object.assign({}, schema._def), { shape: () => strictShape, unknownKeys }));
35
+ }
36
+ if (schema instanceof zod_1.ZodOptional) {
37
+ return new zod_1.ZodOptional(Object.assign(Object.assign({}, schema._def), { innerType: strictDeep(schema._def.innerType) }));
38
+ }
39
+ if (schema instanceof zod_1.ZodNullable) {
40
+ return new zod_1.ZodNullable(Object.assign(Object.assign({}, schema._def), { innerType: strictDeep(schema._def.innerType) }));
41
+ }
42
+ if (schema instanceof zod_1.ZodDefault) {
43
+ return new zod_1.ZodDefault(Object.assign(Object.assign({}, schema._def), { innerType: strictDeep(schema._def.innerType) }));
44
+ }
45
+ if (schema instanceof zod_1.ZodArray) {
46
+ return new zod_1.ZodArray(Object.assign(Object.assign({}, schema._def), { type: strictDeep(schema._def.type) }));
47
+ }
48
+ if (schema instanceof zod_1.ZodEffects) {
49
+ return new zod_1.ZodEffects(Object.assign(Object.assign({}, schema._def), { schema: strictDeep(schema._def.schema) }));
50
+ }
51
+ if (schema instanceof zod_1.ZodUnion) {
52
+ return new zod_1.ZodUnion(Object.assign(Object.assign({}, schema._def), { options: schema._def.options.map((option) => strictDeep(option)) }));
53
+ }
54
+ if (schema instanceof zod_1.ZodRecord) {
55
+ return new zod_1.ZodRecord(Object.assign(Object.assign({}, schema._def), { valueType: strictDeep(schema._def.valueType) }));
56
+ }
57
+ return schema;
58
+ }
@@ -0,0 +1,39 @@
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
+ * The `telemetry` section shared by every Fonoster service's config file
22
+ * (unify-config-placeholders): the OTLP/HTTP endpoint telemetry goes to. Empty or absent means
23
+ * off, unless the container environment sets `OTEL_EXPORTER_OTLP_ENDPOINT`.
24
+ */
25
+ declare const telemetrySchema: z.ZodOptional<z.ZodObject<{
26
+ /** Usually `"${OTEL_EXPORTER_OTLP_ENDPOINT:-}"`, e.g. http://otel-collector:4318. */
27
+ otlpEndpoint: z.ZodOptional<z.ZodString>;
28
+ }, "strip", z.ZodTypeAny, {
29
+ otlpEndpoint?: string;
30
+ }, {
31
+ otlpEndpoint?: string;
32
+ }>>;
33
+ type TelemetryConfig = z.infer<typeof telemetrySchema>;
34
+ /**
35
+ * The environment `initTelemetry` reads, with the config's endpoint (when set) in
36
+ * `OTEL_EXPORTER_OTLP_ENDPOINT`.
37
+ */
38
+ declare function telemetryEnv(config: TelemetryConfig, env?: Record<string, string | undefined>): Record<string, string | undefined>;
39
+ export { telemetrySchema, telemetryEnv, TelemetryConfig };
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.telemetrySchema = void 0;
4
+ exports.telemetryEnv = telemetryEnv;
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 zod_1 = require("zod");
24
+ /**
25
+ * The `telemetry` section shared by every Fonoster service's config file
26
+ * (unify-config-placeholders): the OTLP/HTTP endpoint telemetry goes to. Empty or absent means
27
+ * off, unless the container environment sets `OTEL_EXPORTER_OTLP_ENDPOINT`.
28
+ */
29
+ const telemetrySchema = zod_1.z
30
+ .object({
31
+ /** Usually `"${OTEL_EXPORTER_OTLP_ENDPOINT:-}"`, e.g. http://otel-collector:4318. */
32
+ otlpEndpoint: zod_1.z.string().optional()
33
+ })
34
+ .optional();
35
+ exports.telemetrySchema = telemetrySchema;
36
+ /**
37
+ * The environment `initTelemetry` reads, with the config's endpoint (when set) in
38
+ * `OTEL_EXPORTER_OTLP_ENDPOINT`.
39
+ */
40
+ function telemetryEnv(config, env = process.env) {
41
+ var _a;
42
+ const endpoint = (_a = config === null || config === void 0 ? void 0 : config.otlpEndpoint) === null || _a === void 0 ? void 0 : _a.trim();
43
+ return endpoint ? Object.assign(Object.assign({}, env), { OTEL_EXPORTER_OTLP_ENDPOINT: endpoint }) : env;
44
+ }
@@ -0,0 +1,30 @@
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 { ZodTypeAny } from "zod";
20
+ export type JsonSchema = Record<string, unknown>;
21
+ /**
22
+ * The JSON Schema (draft 2020-12) of a service config schema. Unknown keys are rejected
23
+ * (`additionalProperties: false`) wherever the service rejects them: every object, as
24
+ * `strictDeep` makes them, except `.passthrough()` blocks.
25
+ */
26
+ declare function toJsonSchema(schema: ZodTypeAny, options?: {
27
+ id?: string;
28
+ title?: string;
29
+ }): JsonSchema;
30
+ export { toJsonSchema };
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toJsonSchema = toJsonSchema;
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
+ const strictDeep_1 = require("./strictDeep");
24
+ function stringSchema(checks) {
25
+ const out = { type: "string" };
26
+ for (const c of checks) {
27
+ if (c.kind === "min")
28
+ out.minLength = c.value;
29
+ else if (c.kind === "max")
30
+ out.maxLength = c.value;
31
+ else if (c.kind === "length")
32
+ out.minLength = out.maxLength = c.value;
33
+ else if (c.kind === "regex")
34
+ out.pattern = c.regex.source;
35
+ else if (c.kind === "url")
36
+ out.format = "uri";
37
+ else if (c.kind === "email")
38
+ out.format = "email";
39
+ }
40
+ return out;
41
+ }
42
+ function numberSchema(checks) {
43
+ const out = { type: "number" };
44
+ for (const c of checks) {
45
+ if (c.kind === "int")
46
+ out.type = "integer";
47
+ else if (c.kind === "min")
48
+ out[c.inclusive ? "minimum" : "exclusiveMinimum"] = c.value;
49
+ else if (c.kind === "max")
50
+ out[c.inclusive ? "maximum" : "exclusiveMaximum"] = c.value;
51
+ else if (c.kind === "multipleOf")
52
+ out.multipleOf = c.value;
53
+ }
54
+ return out;
55
+ }
56
+ /** Whether an object key may be left out of the input (optional, or has a default). */
57
+ function isOptionalInput(schema) {
58
+ const kind = schema._def.typeName;
59
+ if (kind === zod_1.ZodFirstPartyTypeKind.ZodOptional ||
60
+ kind === zod_1.ZodFirstPartyTypeKind.ZodDefault)
61
+ return true;
62
+ if (kind === zod_1.ZodFirstPartyTypeKind.ZodEffects)
63
+ return isOptionalInput(schema._def.schema);
64
+ if (kind === zod_1.ZodFirstPartyTypeKind.ZodNullable)
65
+ return isOptionalInput(schema._def.innerType);
66
+ if (kind === zod_1.ZodFirstPartyTypeKind.ZodAny ||
67
+ kind === zod_1.ZodFirstPartyTypeKind.ZodUnknown)
68
+ return true;
69
+ return false;
70
+ }
71
+ function convert(schema, path) {
72
+ const def = schema._def;
73
+ const description = schema.description
74
+ ? { description: schema.description }
75
+ : {};
76
+ switch (def.typeName) {
77
+ case zod_1.ZodFirstPartyTypeKind.ZodString:
78
+ return Object.assign(Object.assign({}, stringSchema(def.checks)), description);
79
+ case zod_1.ZodFirstPartyTypeKind.ZodNumber:
80
+ return Object.assign(Object.assign({}, numberSchema(def.checks)), description);
81
+ case zod_1.ZodFirstPartyTypeKind.ZodBoolean:
82
+ return Object.assign({ type: "boolean" }, description);
83
+ case zod_1.ZodFirstPartyTypeKind.ZodLiteral:
84
+ return Object.assign({ const: def.value }, description);
85
+ case zod_1.ZodFirstPartyTypeKind.ZodEnum:
86
+ return Object.assign({ type: "string", enum: [...def.values] }, description);
87
+ case zod_1.ZodFirstPartyTypeKind.ZodAny:
88
+ case zod_1.ZodFirstPartyTypeKind.ZodUnknown:
89
+ return Object.assign({}, description);
90
+ case zod_1.ZodFirstPartyTypeKind.ZodNull:
91
+ return { type: "null" };
92
+ case zod_1.ZodFirstPartyTypeKind.ZodObject: {
93
+ const shape = def.shape();
94
+ const properties = {};
95
+ const required = [];
96
+ for (const [key, value] of Object.entries(shape)) {
97
+ properties[key] = convert(value, path ? `${path}.${key}` : key);
98
+ if (!isOptionalInput(value))
99
+ required.push(key);
100
+ }
101
+ const catchall = def.catchall;
102
+ const hasCatchall = catchall && catchall._def.typeName !== zod_1.ZodFirstPartyTypeKind.ZodNever;
103
+ return Object.assign(Object.assign(Object.assign({ type: "object", properties }, (required.length ? { required } : {})), { additionalProperties: hasCatchall
104
+ ? convert(catchall, `${path}.*`)
105
+ : def.unknownKeys !== "strict" }), description);
106
+ }
107
+ case zod_1.ZodFirstPartyTypeKind.ZodArray: {
108
+ const out = Object.assign({ type: "array", items: convert(def.type, `${path}[]`) }, description);
109
+ if (def.minLength)
110
+ out.minItems = def.minLength.value;
111
+ if (def.maxLength)
112
+ out.maxItems = def.maxLength.value;
113
+ if (def.exactLength)
114
+ out.minItems = out.maxItems = def.exactLength.value;
115
+ return out;
116
+ }
117
+ case zod_1.ZodFirstPartyTypeKind.ZodRecord:
118
+ return Object.assign({ type: "object", additionalProperties: convert(def.valueType, `${path}.*`) }, description);
119
+ case zod_1.ZodFirstPartyTypeKind.ZodUnion:
120
+ case zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion: {
121
+ const options = Array.isArray(def.options)
122
+ ? def.options
123
+ : [...def.options.values()];
124
+ return Object.assign({ anyOf: options.map((o, i) => convert(o, `${path}|${i}`)) }, description);
125
+ }
126
+ case zod_1.ZodFirstPartyTypeKind.ZodOptional:
127
+ return Object.assign(Object.assign({}, convert(def.innerType, path)), description);
128
+ case zod_1.ZodFirstPartyTypeKind.ZodNullable:
129
+ return Object.assign({ anyOf: [convert(def.innerType, path), { type: "null" }] }, description);
130
+ case zod_1.ZodFirstPartyTypeKind.ZodDefault: {
131
+ const inner = convert(def.innerType, path);
132
+ // Object defaults such as `{}` are filled in by the inner schema; only scalars are shown.
133
+ const value = def.defaultValue();
134
+ return Object.assign(Object.assign(Object.assign({}, inner), (value === null || typeof value !== "object"
135
+ ? { default: value }
136
+ : {})), description);
137
+ }
138
+ case zod_1.ZodFirstPartyTypeKind.ZodEffects:
139
+ return Object.assign(Object.assign({}, convert(def.schema, path)), description);
140
+ case zod_1.ZodFirstPartyTypeKind.ZodBranded:
141
+ return convert(def.type, path);
142
+ case zod_1.ZodFirstPartyTypeKind.ZodCatch:
143
+ return convert(def.innerType, path);
144
+ case zod_1.ZodFirstPartyTypeKind.ZodReadonly:
145
+ return convert(def.innerType, path);
146
+ case zod_1.ZodFirstPartyTypeKind.ZodPipeline:
147
+ return convert(def.in, path);
148
+ case zod_1.ZodFirstPartyTypeKind.ZodLazy:
149
+ return convert(def.getter(), path);
150
+ default:
151
+ throw new Error(`toJsonSchema: unsupported Zod type ${def.typeName} at ${path || "(root)"}`);
152
+ }
153
+ }
154
+ /**
155
+ * The JSON Schema (draft 2020-12) of a service config schema. Unknown keys are rejected
156
+ * (`additionalProperties: false`) wherever the service rejects them: every object, as
157
+ * `strictDeep` makes them, except `.passthrough()` blocks.
158
+ */
159
+ function toJsonSchema(schema, options = {}) {
160
+ return Object.assign(Object.assign(Object.assign({ $schema: "https://json-schema.org/draft/2020-12/schema" }, (options.id ? { $id: options.id } : {})), (options.title ? { title: options.title } : {})), convert((0, strictDeep_1.strictDeep)(schema), ""));
161
+ }