@uns-kit/core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +44 -0
- package/dist/app-config.d.ts +177 -0
- package/dist/app-config.js +1 -0
- package/dist/base-path.d.ts +1 -0
- package/dist/base-path.js +5 -0
- package/dist/config/project.config.extension.d.ts +3 -0
- package/dist/config/project.config.extension.js +3 -0
- package/dist/config-file.d.ts +12 -0
- package/dist/config-file.js +44 -0
- package/dist/examples/data-example.d.ts +1 -0
- package/dist/examples/data-example.js +44 -0
- package/dist/examples/load-test-data.d.ts +1 -0
- package/dist/examples/load-test-data.js +72 -0
- package/dist/examples/table-example.d.ts +4 -0
- package/dist/examples/table-example.js +52 -0
- package/dist/examples/uns-gateway.d.ts +1 -0
- package/dist/examples/uns-gateway.js +5 -0
- package/dist/graphql/schema.d.ts +377 -0
- package/dist/graphql/schema.js +13 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +18 -0
- package/dist/tools/auth/auth-client.d.ts +23 -0
- package/dist/tools/auth/auth-client.js +172 -0
- package/dist/tools/auth/index.d.ts +1 -0
- package/dist/tools/auth/index.js +1 -0
- package/dist/tools/auth/secure-store.d.ts +17 -0
- package/dist/tools/auth/secure-store.js +110 -0
- package/dist/tools/base-path.d.ts +1 -0
- package/dist/tools/base-path.js +5 -0
- package/dist/tools/generate-config-schema.d.ts +1 -0
- package/dist/tools/generate-config-schema.js +23 -0
- package/dist/tools/initialize.d.ts +1 -0
- package/dist/tools/initialize.js +103 -0
- package/dist/tools/make.d.ts +1 -0
- package/dist/tools/make.js +27 -0
- package/dist/tools/pull-request.d.ts +1 -0
- package/dist/tools/pull-request.js +157 -0
- package/dist/tools/refresh-uns.d.ts +1 -0
- package/dist/tools/refresh-uns.js +109 -0
- package/dist/tools/schema.d.ts +208 -0
- package/dist/tools/schema.js +1 -0
- package/dist/tools/update-rtt.d.ts +1 -0
- package/dist/tools/update-rtt.js +169 -0
- package/dist/tools/update-tools.d.ts +1 -0
- package/dist/tools/update-tools.js +72 -0
- package/dist/uns/handover-manager-event-emitter.d.ts +6 -0
- package/dist/uns/handover-manager-event-emitter.js +19 -0
- package/dist/uns/handover-manager.d.ts +34 -0
- package/dist/uns/handover-manager.js +227 -0
- package/dist/uns/process-config.d.ts +10 -0
- package/dist/uns/process-config.js +12 -0
- package/dist/uns/process-name-service.d.ts +7 -0
- package/dist/uns/process-name-service.js +28 -0
- package/dist/uns/status-monitor.d.ts +35 -0
- package/dist/uns/status-monitor.js +82 -0
- package/dist/uns/uns-event-emitter.d.ts +6 -0
- package/dist/uns/uns-event-emitter.js +19 -0
- package/dist/uns/uns-interfaces.d.ts +156 -0
- package/dist/uns/uns-interfaces.js +5 -0
- package/dist/uns/uns-measurements.d.ts +95 -0
- package/dist/uns/uns-measurements.js +146 -0
- package/dist/uns/uns-packet.d.ts +28 -0
- package/dist/uns/uns-packet.js +223 -0
- package/dist/uns/uns-proxy-process.d.ts +56 -0
- package/dist/uns/uns-proxy-process.js +179 -0
- package/dist/uns/uns-proxy.d.ts +31 -0
- package/dist/uns/uns-proxy.js +120 -0
- package/dist/uns/uns-tags.d.ts +1 -0
- package/dist/uns/uns-tags.js +1 -0
- package/dist/uns/uns-topic-matcher.d.ts +9 -0
- package/dist/uns/uns-topic-matcher.js +34 -0
- package/dist/uns/uns-topics.d.ts +1 -0
- package/dist/uns/uns-topics.js +1 -0
- package/dist/uns-config/config-schema.d.ts +7 -0
- package/dist/uns-config/config-schema.js +5 -0
- package/dist/uns-config/host-placeholders.d.ts +139 -0
- package/dist/uns-config/host-placeholders.js +70 -0
- package/dist/uns-config/schema-tolls.d.ts +2 -0
- package/dist/uns-config/schema-tolls.js +4 -0
- package/dist/uns-config/schema-tools.d.ts +2 -0
- package/dist/uns-config/schema-tools.js +18 -0
- package/dist/uns-config/secret-placeholders.d.ts +128 -0
- package/dist/uns-config/secret-placeholders.js +64 -0
- package/dist/uns-config/secret-resolver.d.ts +77 -0
- package/dist/uns-config/secret-resolver.js +285 -0
- package/dist/uns-config/uns-core-schema.d.ts +705 -0
- package/dist/uns-config/uns-core-schema.js +25 -0
- package/dist/uns-grpc/uns-gateway-cli.d.ts +2 -0
- package/dist/uns-grpc/uns-gateway-cli.js +32 -0
- package/dist/uns-grpc/uns-gateway-server.d.ts +47 -0
- package/dist/uns-grpc/uns-gateway-server.js +424 -0
- package/dist/uns-mqtt/mqtt-interfaces.d.ts +22 -0
- package/dist/uns-mqtt/mqtt-interfaces.js +1 -0
- package/dist/uns-mqtt/mqtt-proxy.d.ts +34 -0
- package/dist/uns-mqtt/mqtt-proxy.js +245 -0
- package/dist/uns-mqtt/mqtt-topic-builder.d.ts +51 -0
- package/dist/uns-mqtt/mqtt-topic-builder.js +70 -0
- package/dist/uns-mqtt/mqtt-worker-init.d.ts +1 -0
- package/dist/uns-mqtt/mqtt-worker-init.js +5 -0
- package/dist/uns-mqtt/mqtt-worker.d.ts +20 -0
- package/dist/uns-mqtt/mqtt-worker.js +120 -0
- package/dist/uns-mqtt/throttled-queue.d.ts +166 -0
- package/dist/uns-mqtt/throttled-queue.js +388 -0
- package/dist/uns-mqtt/uns-mqtt-proxy.d.ts +107 -0
- package/dist/uns-mqtt/uns-mqtt-proxy.js +349 -0
- package/dist/uns-mqtt/ws-proxy.d.ts +38 -0
- package/dist/uns-mqtt/ws-proxy.js +86 -0
- package/package.json +48 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
declare const envSecretSchema: z.ZodObject<{
|
|
3
|
+
provider: z.ZodLiteral<"env">;
|
|
4
|
+
key: z.ZodString;
|
|
5
|
+
optional: z.ZodOptional<z.ZodBoolean>;
|
|
6
|
+
default: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}, "strict", z.ZodTypeAny, {
|
|
8
|
+
provider?: "env";
|
|
9
|
+
key?: string;
|
|
10
|
+
optional?: boolean;
|
|
11
|
+
default?: string;
|
|
12
|
+
}, {
|
|
13
|
+
provider?: "env";
|
|
14
|
+
key?: string;
|
|
15
|
+
optional?: boolean;
|
|
16
|
+
default?: string;
|
|
17
|
+
}>;
|
|
18
|
+
declare const infisicalSecretSchema: z.ZodObject<{
|
|
19
|
+
provider: z.ZodLiteral<"infisical">;
|
|
20
|
+
path: z.ZodString;
|
|
21
|
+
key: z.ZodString;
|
|
22
|
+
optional: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
environment: z.ZodOptional<z.ZodString>;
|
|
24
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
25
|
+
default: z.ZodOptional<z.ZodString>;
|
|
26
|
+
}, "strict", z.ZodTypeAny, {
|
|
27
|
+
provider?: "infisical";
|
|
28
|
+
key?: string;
|
|
29
|
+
optional?: boolean;
|
|
30
|
+
default?: string;
|
|
31
|
+
path?: string;
|
|
32
|
+
environment?: string;
|
|
33
|
+
projectId?: string;
|
|
34
|
+
}, {
|
|
35
|
+
provider?: "infisical";
|
|
36
|
+
key?: string;
|
|
37
|
+
optional?: boolean;
|
|
38
|
+
default?: string;
|
|
39
|
+
path?: string;
|
|
40
|
+
environment?: string;
|
|
41
|
+
projectId?: string;
|
|
42
|
+
}>;
|
|
43
|
+
export declare const secretPlaceholderSchema: z.ZodDiscriminatedUnion<"provider", [z.ZodObject<{
|
|
44
|
+
provider: z.ZodLiteral<"env">;
|
|
45
|
+
key: z.ZodString;
|
|
46
|
+
optional: z.ZodOptional<z.ZodBoolean>;
|
|
47
|
+
default: z.ZodOptional<z.ZodString>;
|
|
48
|
+
}, "strict", z.ZodTypeAny, {
|
|
49
|
+
provider?: "env";
|
|
50
|
+
key?: string;
|
|
51
|
+
optional?: boolean;
|
|
52
|
+
default?: string;
|
|
53
|
+
}, {
|
|
54
|
+
provider?: "env";
|
|
55
|
+
key?: string;
|
|
56
|
+
optional?: boolean;
|
|
57
|
+
default?: string;
|
|
58
|
+
}>, z.ZodObject<{
|
|
59
|
+
provider: z.ZodLiteral<"infisical">;
|
|
60
|
+
path: z.ZodString;
|
|
61
|
+
key: z.ZodString;
|
|
62
|
+
optional: z.ZodOptional<z.ZodBoolean>;
|
|
63
|
+
environment: z.ZodOptional<z.ZodString>;
|
|
64
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
65
|
+
default: z.ZodOptional<z.ZodString>;
|
|
66
|
+
}, "strict", z.ZodTypeAny, {
|
|
67
|
+
provider?: "infisical";
|
|
68
|
+
key?: string;
|
|
69
|
+
optional?: boolean;
|
|
70
|
+
default?: string;
|
|
71
|
+
path?: string;
|
|
72
|
+
environment?: string;
|
|
73
|
+
projectId?: string;
|
|
74
|
+
}, {
|
|
75
|
+
provider?: "infisical";
|
|
76
|
+
key?: string;
|
|
77
|
+
optional?: boolean;
|
|
78
|
+
default?: string;
|
|
79
|
+
path?: string;
|
|
80
|
+
environment?: string;
|
|
81
|
+
projectId?: string;
|
|
82
|
+
}>]>;
|
|
83
|
+
export declare const secretValueSchema: z.ZodUnion<[z.ZodString, z.ZodDiscriminatedUnion<"provider", [z.ZodObject<{
|
|
84
|
+
provider: z.ZodLiteral<"env">;
|
|
85
|
+
key: z.ZodString;
|
|
86
|
+
optional: z.ZodOptional<z.ZodBoolean>;
|
|
87
|
+
default: z.ZodOptional<z.ZodString>;
|
|
88
|
+
}, "strict", z.ZodTypeAny, {
|
|
89
|
+
provider?: "env";
|
|
90
|
+
key?: string;
|
|
91
|
+
optional?: boolean;
|
|
92
|
+
default?: string;
|
|
93
|
+
}, {
|
|
94
|
+
provider?: "env";
|
|
95
|
+
key?: string;
|
|
96
|
+
optional?: boolean;
|
|
97
|
+
default?: string;
|
|
98
|
+
}>, z.ZodObject<{
|
|
99
|
+
provider: z.ZodLiteral<"infisical">;
|
|
100
|
+
path: z.ZodString;
|
|
101
|
+
key: z.ZodString;
|
|
102
|
+
optional: z.ZodOptional<z.ZodBoolean>;
|
|
103
|
+
environment: z.ZodOptional<z.ZodString>;
|
|
104
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
105
|
+
default: z.ZodOptional<z.ZodString>;
|
|
106
|
+
}, "strict", z.ZodTypeAny, {
|
|
107
|
+
provider?: "infisical";
|
|
108
|
+
key?: string;
|
|
109
|
+
optional?: boolean;
|
|
110
|
+
default?: string;
|
|
111
|
+
path?: string;
|
|
112
|
+
environment?: string;
|
|
113
|
+
projectId?: string;
|
|
114
|
+
}, {
|
|
115
|
+
provider?: "infisical";
|
|
116
|
+
key?: string;
|
|
117
|
+
optional?: boolean;
|
|
118
|
+
default?: string;
|
|
119
|
+
path?: string;
|
|
120
|
+
environment?: string;
|
|
121
|
+
projectId?: string;
|
|
122
|
+
}>]>]>;
|
|
123
|
+
export type SecretPlaceholder = z.infer<typeof secretPlaceholderSchema>;
|
|
124
|
+
export type SecretValue = z.infer<typeof secretValueSchema>;
|
|
125
|
+
export type EnvSecretPlaceholder = z.infer<typeof envSecretSchema>;
|
|
126
|
+
export type InfisicalSecretPlaceholder = z.infer<typeof infisicalSecretSchema>;
|
|
127
|
+
export declare function isSecretPlaceholder(value: unknown): value is SecretPlaceholder;
|
|
128
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// A SecretPlaceholder marks values that should be resolved from external secret stores
|
|
3
|
+
// instead of being stored in plain text within config files. It supports loading from
|
|
4
|
+
// environment variables ("env") and Infisical ("infisical"). The union below is kept
|
|
5
|
+
// minimal so the same shape can be reused across core/project config schemas.
|
|
6
|
+
const envSecretSchema = z
|
|
7
|
+
.object({
|
|
8
|
+
provider: z.literal("env").describe("Load the secret from an environment variable."),
|
|
9
|
+
key: z
|
|
10
|
+
.string()
|
|
11
|
+
.min(1, "Environment variable key is required")
|
|
12
|
+
.describe("Name of the environment variable to read."),
|
|
13
|
+
optional: z
|
|
14
|
+
.boolean()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Allow the variable to be absent without throwing during resolution."),
|
|
17
|
+
default: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Fallback value when optional is true and the variable is missing."),
|
|
21
|
+
})
|
|
22
|
+
.strict()
|
|
23
|
+
.describe("Secret placeholder resolved from process.env.");
|
|
24
|
+
const infisicalSecretSchema = z
|
|
25
|
+
.object({
|
|
26
|
+
provider: z.literal("infisical").describe("Load the secret from Infisical."),
|
|
27
|
+
path: z
|
|
28
|
+
.string()
|
|
29
|
+
.min(1, "Secret path is required")
|
|
30
|
+
.describe("Secret folder path in Infisical, e.g. '/app/database'."),
|
|
31
|
+
key: z
|
|
32
|
+
.string()
|
|
33
|
+
.min(1, "Secret key is required")
|
|
34
|
+
.describe("Secret key/name inside the given path."),
|
|
35
|
+
optional: z
|
|
36
|
+
.boolean()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Allow the secret to be absent without throwing during resolution."),
|
|
39
|
+
environment: z
|
|
40
|
+
.string()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Infisical environment override (defaults to current mode if omitted)."),
|
|
43
|
+
projectId: z
|
|
44
|
+
.string()
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("Optional Infisical project identifier when not using the default."),
|
|
47
|
+
default: z
|
|
48
|
+
.string()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe("Fallback value when the secret is missing and optional resolution is allowed."),
|
|
51
|
+
})
|
|
52
|
+
.strict()
|
|
53
|
+
.describe("Secret placeholder resolved from Infisical.");
|
|
54
|
+
export const secretPlaceholderSchema = z.discriminatedUnion("provider", [
|
|
55
|
+
envSecretSchema,
|
|
56
|
+
infisicalSecretSchema,
|
|
57
|
+
]);
|
|
58
|
+
export const secretValueSchema = z.union([
|
|
59
|
+
z.string(),
|
|
60
|
+
secretPlaceholderSchema,
|
|
61
|
+
]);
|
|
62
|
+
export function isSecretPlaceholder(value) {
|
|
63
|
+
return secretPlaceholderSchema.safeParse(value).success;
|
|
64
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { NetworkInterfaceInfo } from "node:os";
|
|
2
|
+
import type { AppConfig } from "../app-config.js";
|
|
3
|
+
import { type SecretPlaceholder } from "./secret-placeholders.js";
|
|
4
|
+
import { type HostPlaceholder } from "./host-placeholders.js";
|
|
5
|
+
export type SecretValueResolved = string | undefined;
|
|
6
|
+
export type HostValueResolved = string | undefined;
|
|
7
|
+
type SecretPlaceholderCandidate = {
|
|
8
|
+
provider: "env";
|
|
9
|
+
key: string;
|
|
10
|
+
} | {
|
|
11
|
+
provider: "infisical";
|
|
12
|
+
key: string;
|
|
13
|
+
path: string;
|
|
14
|
+
};
|
|
15
|
+
type HostPlaceholderCandidate = HostPlaceholder;
|
|
16
|
+
export type ResolvedConfig<T> = T extends SecretPlaceholderCandidate ? SecretValueResolved : T extends HostPlaceholderCandidate ? HostValueResolved : T extends (infer U)[] ? ResolvedConfig<U>[] : T extends Record<string, unknown> ? {
|
|
17
|
+
[K in keyof T]: ResolvedConfig<T[K]>;
|
|
18
|
+
} : T;
|
|
19
|
+
export type ResolvedAppConfig = ResolvedConfig<AppConfig>;
|
|
20
|
+
export interface InfisicalFetchRequest {
|
|
21
|
+
path: string;
|
|
22
|
+
key: string;
|
|
23
|
+
environment?: string;
|
|
24
|
+
projectId?: string;
|
|
25
|
+
type?: "shared" | "personal";
|
|
26
|
+
}
|
|
27
|
+
export type InfisicalFetcher = (request: InfisicalFetchRequest) => Promise<string | undefined>;
|
|
28
|
+
export interface InfisicalResolverOptions {
|
|
29
|
+
/**
|
|
30
|
+
* Provide a custom fetcher. If omitted, the resolver tries to lazily instantiate
|
|
31
|
+
* an Infisical client using @infisical/sdk based on the supplied token/siteUrl/options.
|
|
32
|
+
*/
|
|
33
|
+
fetchSecret?: InfisicalFetcher;
|
|
34
|
+
/**
|
|
35
|
+
* Machine token or personal token used when creating the default Infisical client.
|
|
36
|
+
* Falls back to the INFISICAL_TOKEN or INFISICAL_PERSONAL_TOKEN environment variables.
|
|
37
|
+
*/
|
|
38
|
+
token?: string;
|
|
39
|
+
/** Optional Infisical site URL override. Defaults to INFISICAL_SITE_URL when present. */
|
|
40
|
+
siteUrl?: string;
|
|
41
|
+
/** Default environment used when a placeholder does not specify one explicitly. */
|
|
42
|
+
environment?: string;
|
|
43
|
+
/** Default project id used when a placeholder does not provide one. */
|
|
44
|
+
projectId?: string;
|
|
45
|
+
/** Default secret type. Shared secrets are used by default. */
|
|
46
|
+
type?: "shared" | "personal";
|
|
47
|
+
/** Disable in-memory caching when set to false. Enabled by default. */
|
|
48
|
+
cache?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface SecretResolverOptions {
|
|
51
|
+
/** Environment map used for `env` placeholders. Defaults to process.env. */
|
|
52
|
+
env?: NodeJS.ProcessEnv;
|
|
53
|
+
/** Configuration for resolving Infisical placeholders. */
|
|
54
|
+
infisical?: InfisicalResolverOptions;
|
|
55
|
+
/** Callback invoked before throwing when a required secret cannot be resolved. */
|
|
56
|
+
onMissingSecret?: (placeholder: SecretPlaceholder, source: "env" | "infisical") => void;
|
|
57
|
+
/** Configuration for resolving host placeholders. */
|
|
58
|
+
hosts?: HostResolverOptions;
|
|
59
|
+
}
|
|
60
|
+
export interface HostResolverOptions {
|
|
61
|
+
/** Optional environment map used when falling back to process.env lookups. */
|
|
62
|
+
env?: NodeJS.ProcessEnv;
|
|
63
|
+
/** Static mapping of external host keys to concrete host strings. */
|
|
64
|
+
externalHosts?: Record<string, string | undefined>;
|
|
65
|
+
/**
|
|
66
|
+
* Custom resolver invoked when an external host needs to be resolved.
|
|
67
|
+
* It can return synchronously or asynchronously.
|
|
68
|
+
*/
|
|
69
|
+
resolveExternal?: (key: string) => string | undefined | Promise<string | undefined>;
|
|
70
|
+
/** Override for os.networkInterfaces (handy for tests). */
|
|
71
|
+
networkInterfaces?: () => Record<string, NetworkInterfaceInfo[] | undefined>;
|
|
72
|
+
/** Callback invoked before throwing when a required host cannot be resolved. */
|
|
73
|
+
onMissingHost?: (placeholder: HostPlaceholder) => void;
|
|
74
|
+
}
|
|
75
|
+
export declare function resolveConfigSecrets(config: AppConfig, options?: SecretResolverOptions): Promise<ResolvedAppConfig>;
|
|
76
|
+
export declare function clearSecretResolverCaches(): void;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import { isSecretPlaceholder, } from "./secret-placeholders.js";
|
|
3
|
+
import { isHostPlaceholder, } from "./host-placeholders.js";
|
|
4
|
+
const envCache = new Map();
|
|
5
|
+
const infisicalCache = new Map();
|
|
6
|
+
const structuredCloneFallback = (value) => typeof structuredClone === "function"
|
|
7
|
+
? structuredClone(value)
|
|
8
|
+
: JSON.parse(JSON.stringify(value));
|
|
9
|
+
export async function resolveConfigSecrets(config, options = {}) {
|
|
10
|
+
const working = structuredCloneFallback(config);
|
|
11
|
+
await resolveNode(working, options);
|
|
12
|
+
return working;
|
|
13
|
+
}
|
|
14
|
+
export function clearSecretResolverCaches() {
|
|
15
|
+
envCache.clear();
|
|
16
|
+
infisicalCache.clear();
|
|
17
|
+
defaultInfisicalFetcherCache.clear();
|
|
18
|
+
}
|
|
19
|
+
async function resolveNode(node, options) {
|
|
20
|
+
if (isSecretPlaceholder(node)) {
|
|
21
|
+
return resolveSecretValue(node, options);
|
|
22
|
+
}
|
|
23
|
+
if (isHostPlaceholder(node)) {
|
|
24
|
+
return resolveHostValue(node, options.hosts);
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(node)) {
|
|
27
|
+
const resolvedArray = await Promise.all(node.map(item => resolveNode(item, options)));
|
|
28
|
+
return resolvedArray;
|
|
29
|
+
}
|
|
30
|
+
if (node && typeof node === "object") {
|
|
31
|
+
const obj = node;
|
|
32
|
+
for (const key of Object.keys(obj)) {
|
|
33
|
+
const current = obj[key];
|
|
34
|
+
if (isSecretPlaceholder(current)) {
|
|
35
|
+
const resolved = await resolveSecretValue(current, options);
|
|
36
|
+
if (resolved === undefined) {
|
|
37
|
+
delete obj[key];
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
obj[key] = resolved;
|
|
41
|
+
}
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (isHostPlaceholder(current)) {
|
|
45
|
+
const resolved = await resolveHostValue(current, options.hosts);
|
|
46
|
+
if (resolved === undefined) {
|
|
47
|
+
delete obj[key];
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
obj[key] = resolved;
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const resolvedChild = await resolveNode(current, options);
|
|
55
|
+
obj[key] = resolvedChild;
|
|
56
|
+
}
|
|
57
|
+
return obj;
|
|
58
|
+
}
|
|
59
|
+
return node;
|
|
60
|
+
}
|
|
61
|
+
async function resolveSecretValue(placeholder, options) {
|
|
62
|
+
switch (placeholder.provider) {
|
|
63
|
+
case "env":
|
|
64
|
+
return resolveEnvSecret(placeholder, options);
|
|
65
|
+
case "infisical":
|
|
66
|
+
return resolveInfisicalSecret(placeholder, options);
|
|
67
|
+
default:
|
|
68
|
+
// Exhaustive check to guard future provider additions.
|
|
69
|
+
return assertNeverProvider(placeholder);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function assertNeverProvider(x) {
|
|
73
|
+
throw new Error(`Unsupported secret provider: ${JSON.stringify(x)}`);
|
|
74
|
+
}
|
|
75
|
+
async function resolveHostValue(placeholder, options) {
|
|
76
|
+
const effectiveOptions = options ?? {};
|
|
77
|
+
switch (placeholder.provider) {
|
|
78
|
+
case "inline":
|
|
79
|
+
return placeholder.value;
|
|
80
|
+
case "external": {
|
|
81
|
+
const envMap = effectiveOptions.env ?? process.env;
|
|
82
|
+
let resolved = await maybeResolveExternal(placeholder.key, effectiveOptions.resolveExternal);
|
|
83
|
+
if (resolved === undefined) {
|
|
84
|
+
resolved = effectiveOptions.externalHosts?.[placeholder.key];
|
|
85
|
+
}
|
|
86
|
+
if (resolved === undefined) {
|
|
87
|
+
resolved = envMap?.[placeholder.key];
|
|
88
|
+
}
|
|
89
|
+
if (resolved === undefined) {
|
|
90
|
+
if (placeholder.default !== undefined) {
|
|
91
|
+
return placeholder.default;
|
|
92
|
+
}
|
|
93
|
+
if (placeholder.optional) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
effectiveOptions.onMissingHost?.(placeholder);
|
|
97
|
+
throw new Error(`External host '${placeholder.key}' could not be resolved.`);
|
|
98
|
+
}
|
|
99
|
+
return resolved;
|
|
100
|
+
}
|
|
101
|
+
case "system":
|
|
102
|
+
return resolveSystemHost(placeholder, effectiveOptions);
|
|
103
|
+
default:
|
|
104
|
+
return assertNeverHostProvider(placeholder);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function maybeResolveExternal(key, resolver) {
|
|
108
|
+
if (!resolver) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
return await resolver(key);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw new Error(`Failed to resolve external host '${key}' via custom resolver: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function assertNeverHostProvider(x) {
|
|
119
|
+
throw new Error(`Unsupported host provider: ${JSON.stringify(x)}`);
|
|
120
|
+
}
|
|
121
|
+
function resolveSystemHost(placeholder, options) {
|
|
122
|
+
const getInterfaces = options.networkInterfaces ?? os.networkInterfaces;
|
|
123
|
+
const interfaces = getInterfaces();
|
|
124
|
+
const family = placeholder.family ?? "IPv4";
|
|
125
|
+
const targetName = placeholder.interfaceName;
|
|
126
|
+
const interfaceEntries = targetName
|
|
127
|
+
? [[targetName, interfaces[targetName]]]
|
|
128
|
+
: Object.entries(interfaces);
|
|
129
|
+
for (const [name, ifaceList] of interfaceEntries) {
|
|
130
|
+
if (!ifaceList) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
for (const iface of ifaceList) {
|
|
134
|
+
if (iface &&
|
|
135
|
+
iface.family === family &&
|
|
136
|
+
iface.internal !== true &&
|
|
137
|
+
typeof iface.address === "string" &&
|
|
138
|
+
iface.address.length > 0) {
|
|
139
|
+
return iface.address;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (targetName) {
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (placeholder.default !== undefined) {
|
|
147
|
+
return placeholder.default;
|
|
148
|
+
}
|
|
149
|
+
if (placeholder.optional) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
options.onMissingHost?.(placeholder);
|
|
153
|
+
const targetDescription = targetName ? `interface '${targetName}'` : "available interfaces";
|
|
154
|
+
throw new Error(`System host lookup failed for ${targetDescription} (family ${family}).`);
|
|
155
|
+
}
|
|
156
|
+
async function resolveEnvSecret(placeholder, options) {
|
|
157
|
+
const envMap = options.env ?? process.env;
|
|
158
|
+
const cacheKey = placeholder.key;
|
|
159
|
+
if (envCache.has(cacheKey)) {
|
|
160
|
+
return envCache.get(cacheKey) ?? undefined;
|
|
161
|
+
}
|
|
162
|
+
const value = envMap[cacheKey];
|
|
163
|
+
if (value === undefined || value === null) {
|
|
164
|
+
if (placeholder.default !== undefined) {
|
|
165
|
+
envCache.set(cacheKey, placeholder.default);
|
|
166
|
+
return placeholder.default;
|
|
167
|
+
}
|
|
168
|
+
if (placeholder.optional) {
|
|
169
|
+
envCache.set(cacheKey, undefined);
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
options.onMissingSecret?.(placeholder, "env");
|
|
173
|
+
throw new Error(`Required environment variable '${cacheKey}' is not set.`);
|
|
174
|
+
}
|
|
175
|
+
envCache.set(cacheKey, value);
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
async function resolveInfisicalSecret(placeholder, options) {
|
|
179
|
+
const infisicalOptions = options.infisical;
|
|
180
|
+
const fetcher = await getInfisicalFetcher(infisicalOptions);
|
|
181
|
+
if (!fetcher) {
|
|
182
|
+
options.onMissingSecret?.(placeholder, "infisical");
|
|
183
|
+
throw new Error("Infisical secret requested but no resolver is configured. Provide SecretResolverOptions.infisical.");
|
|
184
|
+
}
|
|
185
|
+
const environment = placeholder.environment ?? infisicalOptions?.environment ?? process.env.INFISICAL_ENVIRONMENT;
|
|
186
|
+
const projectId = placeholder.projectId ?? infisicalOptions?.projectId ?? process.env.INFISICAL_PROJECT_ID;
|
|
187
|
+
const type = infisicalOptions?.type ?? "shared";
|
|
188
|
+
if (!environment) {
|
|
189
|
+
throw new Error(`Infisical secret '${placeholder.path}:${placeholder.key}' is missing an environment. ` +
|
|
190
|
+
"Set it on the placeholder, pass SecretResolverOptions.infisical.environment, or define INFISICAL_ENVIRONMENT.");
|
|
191
|
+
}
|
|
192
|
+
if (!projectId) {
|
|
193
|
+
throw new Error(`Infisical secret '${placeholder.path}:${placeholder.key}' is missing a project id. ` +
|
|
194
|
+
"Set it on the placeholder, pass SecretResolverOptions.infisical.projectId, or define INFISICAL_PROJECT_ID.");
|
|
195
|
+
}
|
|
196
|
+
const cacheKey = JSON.stringify({
|
|
197
|
+
path: placeholder.path,
|
|
198
|
+
key: placeholder.key,
|
|
199
|
+
environment,
|
|
200
|
+
projectId,
|
|
201
|
+
type,
|
|
202
|
+
});
|
|
203
|
+
if (infisicalOptions?.cache !== false && infisicalCache.has(cacheKey)) {
|
|
204
|
+
return infisicalCache.get(cacheKey) ?? undefined;
|
|
205
|
+
}
|
|
206
|
+
const fetchPromise = fetcher({
|
|
207
|
+
path: placeholder.path,
|
|
208
|
+
key: placeholder.key,
|
|
209
|
+
environment,
|
|
210
|
+
projectId,
|
|
211
|
+
type,
|
|
212
|
+
}).then(secret => {
|
|
213
|
+
if (secret === undefined || secret === null) {
|
|
214
|
+
if (placeholder.default !== undefined) {
|
|
215
|
+
return placeholder.default;
|
|
216
|
+
}
|
|
217
|
+
if (placeholder.optional) {
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
options.onMissingSecret?.(placeholder, "infisical");
|
|
221
|
+
throw new Error(`Secret '${placeholder.path}:${placeholder.key}' not found in Infisical.`);
|
|
222
|
+
}
|
|
223
|
+
return secret;
|
|
224
|
+
});
|
|
225
|
+
if (infisicalOptions?.cache !== false) {
|
|
226
|
+
infisicalCache.set(cacheKey, fetchPromise);
|
|
227
|
+
}
|
|
228
|
+
return fetchPromise;
|
|
229
|
+
}
|
|
230
|
+
async function getInfisicalFetcher(options) {
|
|
231
|
+
if (!options) {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
if (options.fetchSecret) {
|
|
235
|
+
return options.fetchSecret;
|
|
236
|
+
}
|
|
237
|
+
const token = options.token ??
|
|
238
|
+
process.env.INFISICAL_TOKEN ??
|
|
239
|
+
process.env.INFISICAL_PERSONAL_TOKEN ??
|
|
240
|
+
"";
|
|
241
|
+
if (!token) {
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
const siteUrlKey = options.siteUrl ?? process.env.INFISICAL_SITE_URL ?? "";
|
|
245
|
+
const cacheKey = `${token}::${siteUrlKey}`;
|
|
246
|
+
if (!defaultInfisicalFetcherCache.has(cacheKey)) {
|
|
247
|
+
defaultInfisicalFetcherCache.set(cacheKey, createDefaultInfisicalFetcher(token, options.siteUrl));
|
|
248
|
+
}
|
|
249
|
+
const baseFetcher = await defaultInfisicalFetcherCache.get(cacheKey);
|
|
250
|
+
return baseFetcher;
|
|
251
|
+
}
|
|
252
|
+
const defaultInfisicalFetcherCache = new Map();
|
|
253
|
+
async function createDefaultInfisicalFetcher(token, siteUrl) {
|
|
254
|
+
try {
|
|
255
|
+
const sdkModule = await import("@infisical/sdk");
|
|
256
|
+
const { InfisicalSDK, SecretType } = sdkModule;
|
|
257
|
+
if (!InfisicalSDK) {
|
|
258
|
+
throw new Error("@infisical/sdk does not export InfisicalSDK");
|
|
259
|
+
}
|
|
260
|
+
const sdkInstance = new InfisicalSDK({ siteUrl });
|
|
261
|
+
const authenticatedSdk = sdkInstance.auth().accessToken(token);
|
|
262
|
+
return async ({ path, key, environment, projectId, type = "shared" }) => {
|
|
263
|
+
if (!environment) {
|
|
264
|
+
throw new Error(`Infisical secret '${path}:${key}' is missing an environment.`);
|
|
265
|
+
}
|
|
266
|
+
if (!projectId) {
|
|
267
|
+
throw new Error(`Infisical secret '${path}:${key}' is missing a project id.`);
|
|
268
|
+
}
|
|
269
|
+
const secret = await authenticatedSdk
|
|
270
|
+
.secrets()
|
|
271
|
+
.getSecret({
|
|
272
|
+
secretName: key,
|
|
273
|
+
secretPath: path,
|
|
274
|
+
environment,
|
|
275
|
+
projectId,
|
|
276
|
+
viewSecretValue: true,
|
|
277
|
+
type: type === "personal" ? SecretType.Personal : SecretType.Shared,
|
|
278
|
+
});
|
|
279
|
+
return secret?.secretValue ?? undefined;
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
throw new Error("Failed to initialize @infisical/sdk. Install the package or provide SecretResolverOptions.infisical.fetchSecret.", { cause: error });
|
|
284
|
+
}
|
|
285
|
+
}
|