@configu/sdk
Version:
Configu TypeScript SDK
1,033 lines (1,019 loc) • 36.2 kB
JavaScript
var _9 = require('lodash');
var Ajv = require('ajv');
var addFormats = require('ajv-formats');
var ajvHumanErrors = require('@segment/ajv-human-errors');
var acorn = require('acorn');
var walk = require('acorn-walk');
require('ses');
var validator = require('validator');
var zod = require('zod');
var chai = require('chai');
var Subset = require('chai-subset');
var expect = require('@vitest/expect');
var matchers = require('jest-extended');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var _9__default = /*#__PURE__*/_interopDefault(_9);
var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
var addFormats__default = /*#__PURE__*/_interopDefault(addFormats);
var acorn__namespace = /*#__PURE__*/_interopNamespace(acorn);
var walk__namespace = /*#__PURE__*/_interopNamespace(walk);
var validator__default = /*#__PURE__*/_interopDefault(validator);
var chai__namespace = /*#__PURE__*/_interopNamespace(chai);
var Subset__default = /*#__PURE__*/_interopDefault(Subset);
var matchers__namespace = /*#__PURE__*/_interopNamespace(matchers);
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var ConfigKey = class _ConfigKey {
static {
__name(this, "ConfigKey");
}
static pattern = "^[A-Za-z0-9_-]+$";
static reserved = [
"_",
"-",
"$",
"this",
"Cfgu",
"ConfigStore",
"ConfigSet",
"ConfigKey",
"Key",
"ConfigValue",
"Value",
"ConfigSchema",
"Configu"
];
static normalizedReserved = _ConfigKey.reserved.map(_ConfigKey.normalize);
static normalize(key) {
return _9__default.default.camelCase(key).toLowerCase();
}
static validate({ key, errorPrefix = "ConfigKey" }) {
try {
const isValid = RegExp(_ConfigKey.pattern).test(key) && !_ConfigKey.normalizedReserved.includes(_ConfigKey.normalize(key));
if (!isValid) {
throw new Error();
}
} catch (error) {
throw new Error(
`${errorPrefix} "${key}" must match ${_ConfigKey.pattern} and not be one of ${_ConfigKey.reserved.join(", ")}`
);
}
}
};
var JSONSchema = class _JSONSchema {
static {
__name(this, "JSONSchema");
}
static ajv = addFormats__default.default(
new Ajv__default.default({ allErrors: true, verbose: true, allowUnionTypes: true, useDefaults: "empty" })
);
static validate(schema, data) {
const isValid = _JSONSchema.ajv.validate(schema, data);
if (!isValid) {
const errors = new ajvHumanErrors.AggregateAjvError(_JSONSchema.ajv.errors);
throw new Error(errors.message);
}
}
static AnyPropertySchema = {
type: ["string", "number", "boolean", "object", "array"],
oneOf: [{ type: "string" }, { type: "number" }, { type: "boolean" }, { type: "object" }, { type: "array" }]
};
static AnyArrayPropertySchema = {
type: "array",
uniqueItems: true,
items: _JSONSchema.AnyPropertySchema
};
static createPropertyExclusiveSchema({
property,
exclusive
}) {
return {
if: {
required: [property]
},
then: {
properties: {
..._9__default.default.chain(exclusive).keyBy().mapValues(() => false).value()
}
}
};
}
};
// src/Cfgu.ts
var CfguStringProperty = {
type: "string",
minLength: 1
};
var CfguBooleanProperty = {
type: "boolean"
};
var CfguObjectProperty = {
type: "object",
minProperties: 1
};
var CfguStringArrayProperty = {
type: "array",
minItems: 1,
uniqueItems: true,
items: CfguStringProperty
};
var CfguStringOrStringArrayProperty = {
type: ["string", "array"],
oneOf: [CfguStringProperty, CfguStringArrayProperty]
};
var CfguSchema = {
type: "object",
required: [],
additionalProperties: false,
nullable: true,
properties: {
description: CfguStringProperty,
label: CfguStringOrStringArrayProperty,
hidden: CfguBooleanProperty,
lazy: CfguBooleanProperty,
const: CfguStringProperty,
default: JSONSchema.AnyPropertySchema,
required: CfguBooleanProperty,
pattern: CfguStringProperty,
enum: JSONSchema.AnyArrayPropertySchema,
schema: CfguObjectProperty,
test: CfguStringOrStringArrayProperty
},
allOf: [
JSONSchema.createPropertyExclusiveSchema({
property: "lazy",
exclusive: ["const", "default"]
}),
JSONSchema.createPropertyExclusiveSchema({
property: "const",
// todo: consider if its a stupid but valid pair with required
// exclusive: ['lazy', 'default']
exclusive: ["lazy", "default", "required"]
}),
JSONSchema.createPropertyExclusiveSchema({
property: "default",
exclusive: ["lazy", "const", "required"]
}),
JSONSchema.createPropertyExclusiveSchema({
property: "required",
exclusive: ["const", "default"]
})
]
};
chai__namespace.use(expect.JestExtend);
chai__namespace.use(expect.JestChaiExpect);
chai__namespace.use(Subset__default.default);
chai__namespace.use(expect.JestAsymmetricMatchers);
chai__namespace.expect.extend(chai__namespace.expect, matchers__namespace);
// src/ConfigExpression.ts
var ConfigExpression = class _ConfigExpression {
static {
__name(this, "ConfigExpression");
}
static globals = /* @__PURE__ */ new Map();
static suffix = "Expression";
static marker = { start: "${", end: "}" };
static delimiters = [
{ start: "{{", end: "}}" },
{ start: "<%", end: "%>" }
];
static {
_ConfigExpression.register("_", _9__default.default);
_ConfigExpression.register("validator", validator__default.default);
_ConfigExpression.register("JSONSchema", JSONSchema);
_ConfigExpression.register("jsonschema", JSONSchema);
_ConfigExpression.register("z", zod.z);
_ConfigExpression.register("assert", chai.assert);
_ConfigExpression.register("expect", chai.expect);
_ConfigExpression.register("should", chai.should);
}
static escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
static pattern = new RegExp(
_ConfigExpression.delimiters.map(({ start, end }) => `${_ConfigExpression.escapeRegex(start)}(.*?)${_ConfigExpression.escapeRegex(end)}`).join("|"),
"g"
);
static register(key, registeree) {
if (key.endsWith(_ConfigExpression.suffix)) {
_ConfigExpression.globals.set(key.slice(0, -_ConfigExpression.suffix.length), registeree);
} else {
_ConfigExpression.globals.set(key, registeree);
}
}
static parse(raw) {
try {
const expression = raw.replace(_ConfigExpression.pattern, (match, group) => {
return `${_ConfigExpression.marker.start}${group}${_ConfigExpression.marker.end}`;
});
const ast = acorn__namespace.parse(expression, { ecmaVersion: "latest" });
return {
raw,
expression,
ast
};
} catch (error) {
throw new Error(`Failed to parse expression "${raw}"
${error}`);
}
}
static evaluate(expression, context = {}) {
try {
const parsed = _ConfigExpression.parse(expression);
const compartment = new Compartment({ ...context, ...Object.fromEntries(_ConfigExpression.globals) });
return compartment.evaluate(parsed.expression);
} catch (error) {
throw new Error(`Failed to evaluate expression "${expression}"
${error.message}`);
}
}
static evaluateBoolean(expression, context) {
return _ConfigExpression.evaluate(`Boolean(${expression})`, context);
}
static evaluateTemplateString(expression, context) {
return _ConfigExpression.evaluate(`\`${expression}\``, context);
}
static references(expression) {
const parsed = _ConfigExpression.parse(expression);
const references = /* @__PURE__ */ new Set();
walk__namespace.simple(parsed.ast, {
Identifier(node) {
references.add(node.name);
}
});
return Array.from(references);
}
static sort(expressionsDict) {
const graph = _9__default.default.chain(expressionsDict).mapValues((expression) => _ConfigExpression.references(expression)).value();
const sorted = [];
const visited = /* @__PURE__ */ new Set();
const visiting = /* @__PURE__ */ new Set();
const visit = /* @__PURE__ */ __name((node, ancestors = []) => {
if (visiting.has(node)) {
throw new Error(`Cyclic dependency detected: ${ancestors.join(" -> ")} -> ${node}`);
}
if (!visited.has(node)) {
visiting.add(node);
(graph[node] || []).forEach((neighbor) => {
visit(neighbor, [...ancestors, node]);
});
visiting.delete(node);
visited.add(node);
sorted.push(node);
}
}, "visit");
_9__default.default.forEach(graph, (referances, key) => {
if (!visited.has(key)) {
visit(key);
}
});
return sorted.filter((key) => Object.prototype.hasOwnProperty.call(expressionsDict, key));
}
};
// src/ConfigValue.ts
var ConfigValue = class _ConfigValue {
static {
__name(this, "ConfigValue");
}
static parse(value) {
try {
return JSON.parse(value);
} catch (error) {
return value;
}
}
static stringify(value) {
if (_9__default.default.isString(value)) {
return value;
}
return JSON.stringify(value);
}
static createEvaluationContext(context) {
const configs = _9__default.default.mapValues(context.configs, (current) => ({
...current,
storedValue: current.value,
value: _ConfigValue.parse(current.value),
labels: Array.isArray(current.cfgu?.label) ? current.cfgu.label : _9__default.default.compact([current.cfgu?.label])
}));
let $ = {
configs
};
if (context.store && context.set && context.schema) {
$ = {
input: {
store: { ...context.store },
set: { ...context.set },
schema: { ...context.schema }
},
...$
};
}
if (context.current) {
const currentConfig = configs[context.current];
if (!currentConfig) {
throw new Error(`Failed to create evaluation context for key "${context.current}"`);
}
$ = { ...currentConfig, ...$ };
}
return { $ };
}
static test({
test,
errorSuffix = `test "${test}"`,
context
}) {
try {
const isValid = ConfigExpression.evaluateBoolean(test, _ConfigValue.createEvaluationContext(context));
if (!isValid) {
throw new Error();
}
} catch (error) {
throw new Error(`ConfigValue failed ${errorSuffix}
${error.message}`);
}
}
static validate(context) {
const currentConfig = context.configs[context.current];
if (!currentConfig) {
throw new Error(`Failed to create evaluation context for key "${context.current}"`);
}
const { cfgu } = currentConfig;
if (cfgu?.pattern) {
_ConfigValue.test({
test: `JSONSchema.validate({ "type": "string", "pattern": $.cfgu.pattern }, $.storedValue) || true`,
errorSuffix: "Cfgu.pattern test",
context
});
}
if (cfgu?.enum) {
_ConfigValue.test({
test: `JSONSchema.validate({ "enum": $.cfgu.enum }, $.value) || true`,
errorSuffix: "Cfgu.enum test",
context
});
}
if (cfgu?.schema) {
_ConfigValue.test({
test: `JSONSchema.validate($.cfgu.schema, $.value) || true`,
errorSuffix: "Cfgu.schema test",
context
});
}
if (cfgu?.test) {
const tests = Array.isArray(cfgu.test) ? cfgu.test : [cfgu.test];
tests.forEach((test, idx) => {
_ConfigValue.test({
test,
errorSuffix: `Cfgu.test[${idx}] "${test}"`,
context
});
});
}
}
};
// src/ConfigSchema.ts
var LEGACY_CFGU_VALUE_TYPE_VALIDATORS = {
Boolean: "validator.isBoolean($.storedValue, { loose: true })",
Number: "validator.isNumeric($.storedValue)",
String: "true",
RegEx: "expect($.cfgu.pattern).to.exist",
UUID: "validator.isUUID($.storedValue)",
SemVer: "validator.isSemVer($.storedValue)",
Email: "validator.isEmail($.storedValue)",
MobilePhone: "validator.isMobilePhone($.storedValue)",
Locale: "validator.isLocale($.storedValue)",
LatLong: "validator.isLatLong($.storedValue)",
Color: "validator.isHexColor($.storedValue) || validator.isHSL($.storedValue) || validator.isRgbColor($.storedValue)",
IPv4: "validator.isIP($.storedValue, 4)",
IPv6: "validator.isIP($.storedValue, 6)",
Domain: "validator.isFQDN($.storedValue)",
URL: "validator.isURL($.storedValue)",
Hex: "validator.isHexadecimal($.storedValue)",
Base64: "validator.isBase64($.storedValue)",
MD5: 'validator.isHash($.storedValue, "md5")',
SHA: 'validator.isHash($.storedValue, "sha1") || validator.isHash($.storedValue, "sha256") || validator.isHash($.storedValue, "sha384") || validator.isHash($.storedValue, "sha512")',
Country: "validator.isISO31661Alpha2($.storedValue) || validator.isISO31661Alpha3($.storedValue)",
Currency: "validator.isISO4217($.storedValue)",
DockerImage: "/^((?:[a-z0-9]([-a-z0-9]*[a-z0-9])?.)+[a-z]{2,6}(?::d{1,5})?/)?[a-z0-9]+(?:[._-/:][a-z0-9]+)*$/gm.test($.storedValue)",
ARN: "/^arn:([^:\n]+):([^:\n]+):(?:[^:\n]*):(?:([^:\n]*)):([^:/\n]+)(?:(:[^\n]+)|(/[^:\n]+))?$/gm.test($.storedValue)",
MACAddress: "validator.isMACAddress($.storedValue)",
MIMEType: "validator.isMimeType($.storedValue)",
MongoId: "validator.isMongoId($.storedValue)",
AWSRegion: 'new Set(["af-south-1","ap-east-1","ap-northeast-1","ap-northeast-2","ap-northeast-3","ap-south-1","ap-southeast-1","ap-southeast-2","ca-central-1","cn-north-1","cn-northwest-1","eu-central-1","eu-north-1","eu-south-1","eu-west-1","eu-west-2","eu-west-3","me-south-1","sa-east-1","us-east-1","us-east-2","us-gov-east-1","us-gov-west-1","us-west-1","us-west-2"]).has($.storedValue)',
AZRegion: 'new Set(["eastus","eastus2","centralus","northcentralus","southcentralus","westcentralus","westus","westus2","canadacentral","canadaeast","brazilsouth","brazilsoutheast","northeurope","westeurope","uksouth","ukwest","francecentral","francesouth","switzerlandnorth","switzerlandwest","germanywestcentral","norwayeast","norwaywest","eastasia","southeastasia","australiaeast","australiasoutheast","australiacentral","australiacentral2","japaneast","japanwest","koreacentral","koreasouth","southafricanorth","southafricawest","uaenorth","uaecentral","usgovarizona","usgovtexas","usdodeast","usdodcentral","usgovvirginia","usgoviowa","usgovcalifornia","ussecwest","usseceast"]).has($.storedValue)',
GCPRegion: 'new Set(["us-east1","us-east4","us-west1","us-west2","us-west3","us-central1","northamerica-northeast1","southamerica-east1","europe-north1","europe-west1","europe-west2","europe-west3","europe-west4","europe-west6","asia-east1","asia-east2","asia-northeast1","asia-northeast2","asia-northeast3","asia-south1","asia-southeast1","australia-southeast1","australia-southeast2","southasia-east1","northamerica-northeast2","europe-central2","asia-southeast2","asia-east3","europe-west7","us-west4","europe-west8","asia-northeast4","asia-southeast3","us-west5","us-central2","us-east5","us-north1","northamerica-northeast3","us-west6"]).has($.storedValue)',
OracleRegion: 'new Set(["us-ashburn-1","us-phoenix-1","ca-toronto-1","sa-saopaulo-1","uk-london-1","uk-gov-london-1","eu-frankfurt-1","eu-zurich-1","eu-amsterdam-1","me-jeddah-1","ap-mumbai-1","ap-osaka-1","ap-seoul-1","ap-sydney-1","ap-tokyo-1","ap-chuncheon-1","ap-melbourne-1","ap-hyderabad-1","ca-montreal-1","us-sanjose-1","us-luke-1","me-dubai-1","us-gov-ashburn-1","us-gov-chicago-1","us-gov-phoenix-1","us-gov-orlando-1","us-gov-sanjose-1","us-gov-ashburn-2"]).has($.storedValue)',
IBMRegion: 'new Set(["us-south","us-east","us-north","us-west","eu-gb","eu-de","eu-nl","eu-fr","eu-it","ap-north","ap-south","ap-east","ap-jp","ap-au","ca-toronto","ca-central","sa-saopaulo","sa-mexico","sa-buenosaires","sa-lima","sa-santiago","af-za","af-eg","af-dz","af-ma"]).has($.storedValue)',
AlibabaRegion: 'new Set(["cn-hangzhou","cn-shanghai","cn-beijing","cn-shenzhen","cn-zhangjiakou","cn-huhehaote","cn-wulanchabu","ap-southeast-1","ap-southeast-2","ap-southeast-3","ap-southeast-5","ap-northeast-1","ap-south-1","ap-south-2","us-west-1","us-east-1","eu-west-1","eu-central-1","me-east-1","ap-southwest-1"]).has($.storedValue)',
Language: "validator.isISO6391($.storedValue)",
DateTime: "validator.isDate($.storedValue) || validator.isTime($.storedValue) || !Number.isNaN(new Date($.storedValue).getTime())",
JSONSchema: "expect($.cfgu.schema).to.exist"
};
var ConfigSchemaKeysSchema = {
type: "object",
required: [],
minProperties: 1,
// todo: patternProperties is not supported by OpenAPI and has limited error resolution support. Thats why we currently use additionalProperties and check key Naming separately.
// additionalProperties: false,
// patternProperties: {
// [Naming.pattern]: CfguSchema,
// },
additionalProperties: CfguSchema
};
var ConfigSchema = class _ConfigSchema {
constructor(keys = {}) {
this.keys = keys;
if (_9__default.default.isEmpty(this.keys)) {
throw new Error("ConfigSchema.keys is required");
}
_9__default.default.chain(this.keys).entries().forEach(([key, cfgu]) => {
ConfigKey.validate({ key, errorPrefix: "ConfigSchema.keys" });
});
try {
JSONSchema.validate(ConfigSchemaKeysSchema, this.keys);
} catch (error) {
throw new Error(`ConfigSchema.keys are invalid
${error.message}`);
}
}
static {
__name(this, "ConfigSchema");
}
static fromLegacyConfigSchema(contents) {
const migratedContents = _9__default.default(contents).mapValues((value, key) => {
const { type, options, depends, labels, template, ...restCfguProps } = value;
const migratedCfgu = { ...restCfguProps, test: [] };
if (type) {
migratedCfgu.test.push(LEGACY_CFGU_VALUE_TYPE_VALIDATORS[type]);
}
if (options) {
migratedCfgu.enum = options.map((option) => ConfigValue.parse(option));
}
if (labels) {
migratedCfgu.label = labels;
}
if (depends) {
depends.forEach((dependencyKey) => {
migratedCfgu.test.push(
`expect($.configs.${dependencyKey}.storedValue, 'Dependency ${dependencyKey} is missing for ${key}').to.not.be.empty`
);
});
}
if (template) {
migratedCfgu.const = template.replace(ConfigExpression.pattern, (match, group) => {
if (contents[group]) {
return `{{$.configs.${group}.storedValue}}`;
}
if (group === "CONFIGU_STORE.type") {
return `{{$.input.store.type}}`;
}
if (group === "CONFIGU_SET.path") {
return `{{$.input.set.path}}`;
}
if (group === "CONFIGU_SET.hierarchy") {
return `{{$.input.set.hierarchy}}`;
}
if (group === "CONFIGU_SET.first") {
return `{{_.first($.input.set.hierarchy)}}`;
}
if (group === "CONFIGU_SET.last") {
return `{{_.last($.input.set.hierarchy)}}`;
}
return match;
});
}
return migratedCfgu;
}).value();
return new _ConfigSchema(migratedContents);
}
};
var ConfigSet = class _ConfigSet {
constructor(path = _ConfigSet.root) {
this.path = path;
this.path = this.path.trim();
if (this.path.startsWith(_ConfigSet.rootLabel)) {
this.path = this.path.slice(1);
}
if (this.path.endsWith(_ConfigSet.separator)) {
this.path = this.path.slice(0, -1);
}
if (this.path === _ConfigSet.root) {
this.hierarchy = [_ConfigSet.root];
return;
}
this.hierarchy = this.path.split(_ConfigSet.separator).map((cur, idx, sets) => {
ConfigKey.validate({ key: cur, errorPrefix: "ConfigSet.path" });
return _9__default.default.take(sets, idx + 1).join(_ConfigSet.separator);
});
this.hierarchy.unshift(_ConfigSet.root);
}
static {
__name(this, "ConfigSet");
}
static separator = "/";
static root = "";
static rootLabel = "/";
hierarchy = [];
};
// src/ConfigStore.ts
var ConfigStore = class _ConfigStore {
static {
__name(this, "ConfigStore");
}
static stores = /* @__PURE__ */ new Map();
// todo: verify if this is needed except for jsonify
type = this.constructor.name;
static get type() {
if (!this.name.endsWith(_ConfigStore.name)) {
throw new Error(`ConfigStore class name must end with "${_ConfigStore.name}". (${this.name})`);
}
const nameWithoutSuffix = this.name.slice(0, -_ConfigStore.name.length);
const type = ConfigKey.normalize(nameWithoutSuffix);
return type;
}
static register(store) {
_ConfigStore.stores.set(store.type, store);
}
static has(type) {
const normalizedType = ConfigKey.normalize(type);
return _ConfigStore.stores.has(normalizedType);
}
static construct(type, configuration = {}) {
const normalizedType = ConfigKey.normalize(type);
const StoreCtor = _ConfigStore.stores.get(normalizedType);
if (!StoreCtor) {
throw new Error(`unknown store type ${type}`);
}
return new StoreCtor(configuration);
}
async init() {
}
};
// src/stores/Noop.ts
var NoopConfigStore = class extends ConfigStore {
static {
__name(this, "NoopConfigStore");
}
get(queries) {
return Promise.resolve([]);
}
set(configs) {
return Promise.resolve();
}
};
var InMemoryConfigStore = class extends ConfigStore {
static {
__name(this, "InMemoryConfigStore");
}
data = {};
async get(queries) {
return _9__default.default.chain(queries).map(({ set, key }) => _9__default.default.get(this.data, [set, key], { set, key, value: "" })).filter("value").value();
}
async set(configs) {
configs.forEach((config) => {
if (!config.value) {
_9__default.default.unset(this.data, [config.set, config.key]);
}
_9__default.default.set(this.data, [config.set, config.key], config);
});
}
};
// package.json
var package_default = {
name: "@configu/sdk",
version: "1.1.0",
description: "Configu TypeScript SDK",
keywords: [
"configu-sdk",
"configu-ts",
"configu-typescript",
"sdk",
"typescript",
"typescript-sdk"
],
homepage: "https://configu.com",
repository: {
type: "git",
url: "git+https://github.com/configu/configu",
directory: "packages/sdk"
},
bugs: "https://github.com/configu/configu/issues",
license: "Apache-2.0",
author: {
name: "@configu/dev",
email: "dev@configu.com",
url: "https://configu.com"
},
type: "module",
types: "./dist/index.d.ts",
main: "./dist/index.cjs",
module: "./dist/index.mjs",
exports: {
"./package.json": "./package.json",
".": {
import: {
types: "./dist/index.d.ts",
default: "./dist/index.mjs"
},
require: {
types: "./dist/index.d.cts",
default: "./dist/index.cjs"
}
}
},
files: [
"dist"
],
config: {
entry: "./src/index.ts"
},
scripts: {
clean: "shx rm -rf dist",
build: "tsup $npm_package_config_entry"
},
dependencies: {
"@segment/ajv-human-errors": "^2.14.1",
"@vitest/expect": "^2.1.8",
acorn: "^8.14.0",
"acorn-walk": "^8.3.4",
ajv: "^8.17.1",
"ajv-formats": "^3.0.1",
chai: "^5.1.2",
"chai-subset": "^1.6.0",
"jest-extended": "^4.0.2",
"json-schema-to-ts": "^3.1.1",
lodash: "^4.17.21",
ses: "^1.10.0",
validator: "^13.12.0",
zod: "^3.24.1"
},
devDependencies: {
"@types/chai": "^5.0.1",
"@types/chai-subset": "^1.3.5",
"@types/validator": "^13.12.2",
"type-fest": "^4.30.2"
}
};
// src/ConfigCommand.ts
var ConfigCommand = class {
constructor(input) {
this.input = input;
}
static {
__name(this, "ConfigCommand");
}
async run() {
const start = performance.now();
const result = await this.execute();
const end = performance.now();
const duration = end - start;
return {
metadata: { version: package_default.version, start, end, duration },
result
};
}
};
var EvaluatedConfigOrigin = /* @__PURE__ */ ((EvaluatedConfigOrigin2) => {
EvaluatedConfigOrigin2["Const"] = "const";
EvaluatedConfigOrigin2["Override"] = "override";
EvaluatedConfigOrigin2["Store"] = "store";
EvaluatedConfigOrigin2["Default"] = "default";
EvaluatedConfigOrigin2["Empty"] = "empty";
return EvaluatedConfigOrigin2;
})(EvaluatedConfigOrigin || {});
var EvalCommand = class extends ConfigCommand {
static {
__name(this, "EvalCommand");
}
async execute() {
const { store } = this.input;
await store.init();
let result = { ...this.evalEmpty() };
result = { ...result, ...this.evalOverride(result) };
result = { ...result, ...await this.evalStore(result) };
result = { ...result, ...this.evalDefault(result) };
result = { ...result, ...this.evalPipe(result) };
result = { ...result, ...this.evalConst(result) };
this.validateResult(result);
return result;
}
evalEmpty() {
const { schema } = this.input;
return _9__default.default.mapValues(schema.keys, (cfgu, key) => {
let origin = "empty" /* Empty */;
if (cfgu?.const) {
origin = "const" /* Const */;
}
return {
set: this.input.set.path,
key,
value: "",
cfgu,
origin
};
});
}
evalOverride(result) {
const { configs = {} } = this.input;
return _9__default.default.mapValues(result, (current) => {
if (current.origin !== "empty" /* Empty */) {
return current;
}
const isOverridden = Object.prototype.hasOwnProperty.call(configs, current.key);
const isLazy = Boolean(current.cfgu?.lazy);
if (!isOverridden && !isLazy) {
return current;
}
const overrideValue = configs?.[current.key] ?? "";
return {
...current,
value: ConfigValue.stringify(overrideValue),
origin: "override" /* Override */
};
});
}
async evalStore(result) {
const { store, set } = this.input;
const storeQueries = _9__default.default.chain(result).values().filter((current) => current.origin === "empty" /* Empty */).flatMap((current) => set.hierarchy.map((node) => ({ set: node, key: current.key }))).value();
const storeConfigsArray = await store.get(storeQueries);
const storeConfigsDict = _9__default.default.chain(storeConfigsArray).orderBy([(config) => set.hierarchy.indexOf(config.set)], ["asc"]).keyBy((config) => config.key).value();
return _9__default.default.mapValues(result, (current) => {
if (current.origin !== "empty" /* Empty */) {
return current;
}
const storeConfig = storeConfigsDict?.[current.key];
if (!storeConfig || !storeConfig.value) {
return current;
}
return _9__default.default.merge(current, storeConfig, {
origin: "store" /* Store */
});
});
}
evalDefault(result) {
return _9__default.default.mapValues(result, (current) => {
if (current.origin !== "empty" /* Empty */) {
return current;
}
if (current.cfgu?.default) {
return {
...current,
value: ConfigValue.stringify(current.cfgu.default),
origin: "default" /* Default */
};
}
return current;
});
}
evalPipe(result) {
const { pipe } = this.input;
if (!pipe) {
return result;
}
const mergedResults = _9__default.default.assignWith(result, pipe, (current, piped) => {
if (piped.origin === "empty" /* Empty */) {
return current;
}
if (current.origin === "empty" /* Empty */) {
return piped;
}
const isCurrentDefault = current.origin === "default" /* Default */;
const isPipedDefault = piped.origin === "default" /* Default */;
if (isCurrentDefault && !isPipedDefault) {
return piped;
}
return current;
});
return mergedResults;
}
evalConst(result) {
const { store, set, schema } = this.input;
const resultWithConstExpressions = { ...result };
const constExpressionsDict = _9__default.default.chain(result).pickBy((current) => current.origin === "const" /* Const */).mapValues((current) => current.cfgu?.const ? `\`${current.cfgu.const}\`` : "").value();
ConfigExpression.sort(constExpressionsDict).forEach((key) => {
const expression = constExpressionsDict[key];
const value = ConfigExpression.evaluate(
expression,
ConfigValue.createEvaluationContext({
store,
set,
schema,
current: key,
configs: resultWithConstExpressions
})
) ?? "";
resultWithConstExpressions[key].value = value;
});
return resultWithConstExpressions;
}
validateResult(result) {
const { store, set, schema, validate = true } = this.input;
if (!validate) {
return;
}
_9__default.default.chain(result).values().forEach((current) => {
const { cfgu, origin, key } = current;
try {
if (cfgu?.required && origin === "empty" /* Empty */) {
throw new Error("ConfigValue is required");
}
ConfigValue.validate({
store,
set,
schema,
current: key,
configs: result
});
} catch (error) {
throw new Error(`Validation failed for Config: "${current.key}"
${error.message}`);
}
}).value();
}
};
var ConfigDiffAction = /* @__PURE__ */ ((ConfigDiffAction2) => {
ConfigDiffAction2["Add"] = "add";
ConfigDiffAction2["Update"] = "update";
ConfigDiffAction2["Delete"] = "delete";
return ConfigDiffAction2;
})(ConfigDiffAction || {});
var UpsertCommand = class extends ConfigCommand {
static {
__name(this, "UpsertCommand");
}
async execute() {
const { store, set, schema, configs = {}, pipe = {} } = this.input;
await store.init();
const keys = Object.keys(schema.keys);
const storeQueries = _9__default.default.chain(keys).map((key) => ({ set: set.path, key })).value();
const storeConfigsArray = await store.get(storeQueries);
const storeConfigsDict = _9__default.default.chain(storeConfigsArray).keyBy((config) => config.key).mapValues((config) => config.value).value();
const currentConfigs = _9__default.default.chain(keys).keyBy().mapValues((key) => ({ set: set.path, key, value: storeConfigsDict[key] ?? "", cfgu: schema.keys[key] })).value();
let result = {};
if (_9__default.default.isEmpty(configs) && _9__default.default.isEmpty(pipe)) {
result = _9__default.default.chain(schema.keys).mapValues((cfgu, key) => ({
set: set.path,
key,
value: "",
cfgu,
prev: currentConfigs[key]?.value ?? "",
next: "",
action: "delete" /* Delete */
})).pickBy((diff) => diff.prev !== diff.next).value();
} else {
const kvConfigs = _9__default.default.mapValues(configs, (value) => ConfigValue.stringify(value));
const pipeConfigs = _9__default.default.chain(pipe).pickBy((value, key) => {
const cfgu = schema.keys[key];
return cfgu && // key exists in current schema
!cfgu.const && // key is not a const in current schema
!cfgu.lazy && // key is not lazy in current schema
value.origin === "store" /* Store */;
}).mapValues((value) => value.value).value();
const upsertConfigsDict = { ...pipeConfigs, ...kvConfigs };
result = _9__default.default.chain(upsertConfigsDict).mapValues((value, key) => {
try {
const cfgu = schema.keys[key];
if (!cfgu) {
throw new Error(`Key is not declared on schema`);
}
const prev = currentConfigs[key]?.value ?? "";
const next = value;
const context = {
set: set.path,
key,
value,
cfgu,
prev,
next,
action: "update" /* Update */
};
if (prev === next) {
return context;
}
if (next === "") {
return { ...context, action: "delete" /* Delete */ };
}
if (prev) {
return { ...context, action: "update" /* Update */ };
}
return { ...context, action: "add" /* Add */ };
} catch (error) {
throw new Error(`Validation failed for Config: "${key}"
${error.message}`);
}
}).pickBy((diff) => diff.prev !== diff.next).value();
}
_9__default.default.chain(result).entries().forEach(([key, current]) => {
try {
if (current.value) {
if (current.cfgu?.lazy) {
throw new Error(`Key declared as "lazy" cannot be assigned a value`);
}
if (current.cfgu?.const) {
throw new Error(`Key declared as "const" cannot be assigned a value`);
}
ConfigValue.validate({
store,
set,
schema,
current: key,
configs: result
});
}
} catch (error) {
throw new Error(`Validation failed for Config: "${key}"
${error.message}`);
}
}).value();
if (!this.input.dry) {
const upsertConfigsArray = _9__default.default.chain(result).entries().map(([key, diff]) => ({ set: set.path, key, value: diff.next })).value();
await store.set(upsertConfigsArray);
}
return result;
}
};
var ExportCommand = class extends ConfigCommand {
static {
__name(this, "ExportCommand");
}
async execute() {
const { pipe } = this.input;
const filteredPipe = _9__default.default.pickBy(pipe, (config) => !config.cfgu?.hidden);
this.validatePipe(filteredPipe);
const mappedPipe = this.kv(filteredPipe);
return mappedPipe;
}
validatePipe(pipe) {
_9__default.default.chain(pipe).values().forEach((current) => {
ConfigKey.validate({ key: current.key });
});
}
kv(pipe) {
const { coerce = true } = this.input;
if (!coerce) {
return _9__default.default.chain(pipe).keyBy("key").mapValues("value").value();
}
return _9__default.default.chain(pipe).keyBy("key").mapValues(({ value }) => ConfigValue.parse(value)).value();
}
};
Object.defineProperty(exports, "_", {
enumerable: true,
get: function () { return _9__default.default; }
});
Object.defineProperty(exports, "validator", {
enumerable: true,
get: function () { return validator__default.default; }
});
Object.defineProperty(exports, "z", {
enumerable: true,
get: function () { return zod.z; }
});
Object.defineProperty(exports, "assert", {
enumerable: true,
get: function () { return chai.assert; }
});
Object.defineProperty(exports, "expect", {
enumerable: true,
get: function () { return chai.expect; }
});
Object.defineProperty(exports, "should", {
enumerable: true,
get: function () { return chai.should; }
});
exports.CfguSchema = CfguSchema;
exports.ConfigCommand = ConfigCommand;
exports.ConfigDiffAction = ConfigDiffAction;
exports.ConfigExpression = ConfigExpression;
exports.ConfigKey = ConfigKey;
exports.ConfigSchema = ConfigSchema;
exports.ConfigSchemaKeysSchema = ConfigSchemaKeysSchema;
exports.ConfigSet = ConfigSet;
exports.ConfigStore = ConfigStore;
exports.ConfigValue = ConfigValue;
exports.EvalCommand = EvalCommand;
exports.EvaluatedConfigOrigin = EvaluatedConfigOrigin;
exports.ExportCommand = ExportCommand;
exports.InMemoryConfigStore = InMemoryConfigStore;
exports.JSONSchema = JSONSchema;
exports.NoopConfigStore = NoopConfigStore;
exports.UpsertCommand = UpsertCommand;
//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map
;