every-plugin
Version:
75 lines (64 loc) • 2.18 kB
text/typescript
import { Context, Effect } from "effect";
import * as z from "zod";
import type { SecretsConfig } from "../../types";
import { PluginRuntimeError } from "../errors";
const configSchema = z
.object({
secrets: z.record(z.string(), z.unknown()),
})
.passthrough();
export class SecretsConfigTag extends Context.Tag("SecretsConfig")<
SecretsConfigTag,
SecretsConfig
>() {}
export class SecretsService extends Effect.Service<SecretsService>()("SecretsService", {
effect: Effect.gen(function* () {
const secrets = yield* SecretsConfigTag;
const hydrateValue = (value: unknown): unknown => {
if (typeof value === "string") {
let result = value;
for (const [key, secretValue] of Object.entries(secrets)) {
const pattern = new RegExp(`{{${key}}}`, "g");
result = result.replace(pattern, String(secretValue));
}
return result;
}
if (Array.isArray(value)) {
return value.map(hydrateValue);
}
if (value && typeof value === "object") {
const isPlainObject = value.constructor === Object || value.constructor === undefined;
if (isPlainObject) {
const hydrated: Record<string, unknown> = {};
for (const [key, val] of Object.entries(value)) {
hydrated[key] = hydrateValue(val);
}
return hydrated;
}
const hydrated = Object.create(Object.getPrototypeOf(value));
for (const [key, val] of Object.entries(value)) {
hydrated[key] = hydrateValue(val);
}
return hydrated;
}
return value;
};
return {
hydrateSecrets: <T>(config: T) =>
Effect.gen(function* () {
const parseResult = configSchema.parse(config);
try {
return hydrateValue(parseResult) as T;
} catch (error) {
return yield* Effect.fail(
new PluginRuntimeError({
operation: "hydrate-secrets",
cause: error instanceof Error ? error : new Error(String(error)),
retryable: false,
}),
);
}
}),
};
}),
}) {}