@fulmenhq/tsfulmen 0.2.0 → 0.2.3
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/CHANGELOG.md +70 -0
- package/README.md +61 -7
- package/config/crucible-ts/agentic/roles/README.md +3 -3
- package/config/crucible-ts/library/fulencode/fixtures/README.md +18 -0
- package/config/crucible-ts/library/fulencode/fixtures/bom/bom.yaml +14 -0
- package/config/crucible-ts/library/fulencode/fixtures/detection/detection.yaml +12 -0
- package/config/crucible-ts/library/fulencode/fixtures/invalid-encodings/base64.yaml +10 -0
- package/config/crucible-ts/library/fulencode/fixtures/normalization/text-safe.yaml +10 -0
- package/config/crucible-ts/library/fulencode/fixtures/telemetry/telemetry-test-cases.yaml +24 -0
- package/config/crucible-ts/library/fulencode/fixtures/valid-encodings/base64.yaml +11 -0
- package/config/crucible-ts/taxonomy/library/platform-modules/v1.0.0/modules.yaml +2 -2
- package/config/crucible-ts/taxonomy/metrics.yaml +79 -1
- package/dist/appidentity/index.d.ts +31 -109
- package/dist/appidentity/index.js +369 -60
- package/dist/appidentity/index.js.map +1 -1
- package/dist/config/index.d.ts +46 -1
- package/dist/config/index.js +427 -62
- package/dist/config/index.js.map +1 -1
- package/dist/crucible/index.js +367 -59
- package/dist/crucible/index.js.map +1 -1
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +367 -59
- package/dist/errors/index.js.map +1 -1
- package/dist/foundry/index.d.ts +2 -1
- package/dist/foundry/index.js +368 -60
- package/dist/foundry/index.js.map +1 -1
- package/dist/fulencode/index.d.ts +102 -0
- package/dist/fulencode/index.js +806 -0
- package/dist/fulencode/index.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +370 -61
- package/dist/index.js.map +1 -1
- package/dist/pathfinder/index.d.ts +1 -1
- package/dist/pathfinder/index.js +367 -59
- package/dist/pathfinder/index.js.map +1 -1
- package/dist/reports/license-inventory.csv +31 -24
- package/dist/schema/index.d.ts +16 -3
- package/dist/schema/index.js +368 -60
- package/dist/schema/index.js.map +1 -1
- package/dist/signals/index.d.ts +483 -395
- package/dist/signals/index.js +368 -60
- package/dist/signals/index.js.map +1 -1
- package/dist/telemetry/http/index.js +368 -59
- package/dist/telemetry/http/index.js.map +1 -1
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/index.js +367 -59
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/prometheus/index.d.ts +1 -1
- package/dist/telemetry/prometheus/index.js +369 -59
- package/dist/telemetry/prometheus/index.js.map +1 -1
- package/dist/{types-BJswWpQC.d.ts → types-DdoeE7F5.d.ts} +1 -1
- package/dist/types-Dv5TERCM.d.ts +108 -0
- package/package.json +13 -8
- package/schemas/crucible-ts/library/fulencode/v1.0.0/README.md +37 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/bom-result.schema.json +48 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/decode-options.schema.json +60 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/decoding-result.schema.json +70 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/detect-options.schema.json +25 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/detection-result.schema.json +57 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/encode-options.schema.json +71 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/encoding-result.schema.json +57 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/fulencode-config.schema.json +8 -4
- package/schemas/crucible-ts/library/fulencode/v1.0.0/fulencode-error.schema.json +66 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/normalization-result.schema.json +73 -0
- package/schemas/crucible-ts/library/fulencode/v1.0.0/normalize-options.schema.json +44 -0
- package/schemas/crucible-ts/meta/README.md +38 -2
- package/schemas/crucible-ts/meta/draft-04/schema.json +222 -0
- package/schemas/crucible-ts/meta/draft-06/schema.json +218 -0
- package/schemas/crucible-ts/meta/draft-2019-09/meta/applicator.json +93 -0
- package/schemas/crucible-ts/meta/draft-2019-09/meta/content.json +21 -0
- package/schemas/crucible-ts/meta/draft-2019-09/meta/core.json +58 -0
- package/schemas/crucible-ts/meta/draft-2019-09/meta/format.json +15 -0
- package/schemas/crucible-ts/meta/draft-2019-09/meta/meta-data.json +35 -0
- package/schemas/crucible-ts/meta/draft-2019-09/meta/validation.json +119 -0
- package/schemas/crucible-ts/meta/draft-2019-09/offline.schema.json +148 -0
- package/schemas/crucible-ts/meta/draft-2019-09/schema.json +62 -0
- package/schemas/crucible-ts/meta/fixtures/draft-04-sample.json +16 -0
- package/schemas/crucible-ts/meta/fixtures/draft-06-sample.json +16 -0
- package/schemas/crucible-ts/meta/fixtures/draft-07-sample.json +34 -0
- package/schemas/crucible-ts/meta/fixtures/draft-2019-09-sample.json +21 -0
- package/schemas/crucible-ts/meta/fixtures/draft-2020-12-sample.json +21 -0
- package/schemas/crucible-ts/taxonomy/library/fulencode/normalization-profiles/v1.0.0/profiles.yaml +16 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/PROVENANCE.md +64 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/access-tier.dimension.json +103 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/retention-lifecycle.dimension.json +103 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/schema-stability.dimension.json +100 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/sensitivity.dimension.json +130 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/velocity-mode.dimension.json +79 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/volatility.dimension.json +72 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/volume-tier.dimension.json +66 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/catalog/classifiers/README.md +29 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/access-tier-classification.md +163 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/classifiers-framework.md +157 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/data-sensitivity-classification.md +259 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/retention-lifecycle-classification.md +200 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/schema-stability-classification.md +205 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/velocity-mode-classification.md +222 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/volatility-classification.md +209 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/volume-tier-classification.md +200 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/ailink/v0/README.md +48 -0
- package/schemas/crucible-ts/upstream/3leaps/{ailink → crucible/schemas/ailink}/v0/prompt.schema.json +4 -18
- package/schemas/crucible-ts/upstream/3leaps/{ailink → crucible/schemas/ailink}/v0/search-response.schema.json +7 -37
- package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/classifiers/v0/dimension-definition.schema.json +247 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/classifiers/v0/sensitivity-level.schema.json +67 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/error-response.schema.json +59 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/lifecycle-phases.data.json +102 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/lifecycle-phases.schema.json +101 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/release-phase.schema.json +18 -0
- package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/types.schema.json +177 -0
- package/schemas/crucible-ts/upstream/3leaps/PROVENANCE.md +0 -43
- /package/schemas/crucible-ts/upstream/3leaps/{agentic → crucible/schemas/agentic}/v0/role-prompt.schema.json +0 -0
package/dist/config/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import addFormats from 'ajv-formats';
|
|
1
2
|
import { spawn } from 'child_process';
|
|
2
3
|
import { readFile, access, mkdir, writeFile } from 'fs/promises';
|
|
3
4
|
import { parse, stringify } from 'yaml';
|
|
@@ -5,7 +6,9 @@ import { join, dirname, extname, relative, isAbsolute, resolve } from 'path';
|
|
|
5
6
|
import { fileURLToPath } from 'url';
|
|
6
7
|
import glob from 'fast-glob';
|
|
7
8
|
import Ajv from 'ajv';
|
|
8
|
-
import
|
|
9
|
+
import Ajv2019 from 'ajv/dist/2019';
|
|
10
|
+
import Ajv2020 from 'ajv/dist/2020';
|
|
11
|
+
import AjvDraft04 from 'ajv-draft-04';
|
|
9
12
|
import { Readable } from 'stream';
|
|
10
13
|
import picomatch from 'picomatch';
|
|
11
14
|
import { suggest as suggest$1, substringSimilarity, score as score$1, normalize as normalize$1, jaro_winkler, damerau_levenshtein, osa_distance, levenshtein } from '@3leaps/string-metrics-wasm';
|
|
@@ -22,6 +25,27 @@ var __export = (target, all) => {
|
|
|
22
25
|
for (var name in all)
|
|
23
26
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
24
27
|
};
|
|
28
|
+
function applyFulmenAjvFormats(ajv, options = {}) {
|
|
29
|
+
const mode = options.mode ?? "fast";
|
|
30
|
+
const formats = options.formats ?? DEFAULT_FORMATS;
|
|
31
|
+
addFormats(ajv, { mode, formats });
|
|
32
|
+
return ajv;
|
|
33
|
+
}
|
|
34
|
+
var DEFAULT_FORMATS;
|
|
35
|
+
var init_ajv_formats = __esm({
|
|
36
|
+
"src/schema/ajv-formats.ts"() {
|
|
37
|
+
DEFAULT_FORMATS = [
|
|
38
|
+
"date-time",
|
|
39
|
+
"email",
|
|
40
|
+
"hostname",
|
|
41
|
+
"ipv4",
|
|
42
|
+
"ipv6",
|
|
43
|
+
"uri",
|
|
44
|
+
"uri-reference",
|
|
45
|
+
"uuid"
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
25
49
|
|
|
26
50
|
// src/schema/errors.ts
|
|
27
51
|
var errors_exports = {};
|
|
@@ -1474,20 +1498,14 @@ async function loadMetaSchema(draft) {
|
|
|
1474
1498
|
const content = await readFile(metaSchemaPath, "utf-8");
|
|
1475
1499
|
return JSON.parse(content);
|
|
1476
1500
|
}
|
|
1477
|
-
async function loadVocabularySchemas() {
|
|
1501
|
+
async function loadVocabularySchemas(draft) {
|
|
1502
|
+
if (draft !== "draft-2019-09" && draft !== "draft-2020-12") {
|
|
1503
|
+
return [];
|
|
1504
|
+
}
|
|
1478
1505
|
const __filename3 = fileURLToPath(import.meta.url);
|
|
1479
1506
|
const __dirname4 = dirname(__filename3);
|
|
1480
|
-
const vocabDir = join(
|
|
1481
|
-
|
|
1482
|
-
"..",
|
|
1483
|
-
"..",
|
|
1484
|
-
"schemas",
|
|
1485
|
-
"crucible-ts",
|
|
1486
|
-
"meta",
|
|
1487
|
-
"draft-2020-12",
|
|
1488
|
-
"meta"
|
|
1489
|
-
);
|
|
1490
|
-
const vocabFiles = [
|
|
1507
|
+
const vocabDir = join(__dirname4, "..", "..", "schemas", "crucible-ts", "meta", draft, "meta");
|
|
1508
|
+
const vocabFiles = draft === "draft-2020-12" ? [
|
|
1491
1509
|
"core.json",
|
|
1492
1510
|
"applicator.json",
|
|
1493
1511
|
"unevaluated.json",
|
|
@@ -1495,6 +1513,13 @@ async function loadVocabularySchemas() {
|
|
|
1495
1513
|
"meta-data.json",
|
|
1496
1514
|
"format-annotation.json",
|
|
1497
1515
|
"content.json"
|
|
1516
|
+
] : [
|
|
1517
|
+
"core.json",
|
|
1518
|
+
"applicator.json",
|
|
1519
|
+
"validation.json",
|
|
1520
|
+
"meta-data.json",
|
|
1521
|
+
"format.json",
|
|
1522
|
+
"content.json"
|
|
1498
1523
|
];
|
|
1499
1524
|
const schemas = [];
|
|
1500
1525
|
for (const file of vocabFiles) {
|
|
@@ -1549,47 +1574,65 @@ async function loadReferencedSchema(uri) {
|
|
|
1549
1574
|
}
|
|
1550
1575
|
return JSON.parse(content);
|
|
1551
1576
|
}
|
|
1552
|
-
function
|
|
1553
|
-
if (!
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
}
|
|
1563
|
-
addFormats(ajvInstance, {
|
|
1564
|
-
mode: "fast",
|
|
1565
|
-
formats: ["date-time", "email", "hostname", "ipv4", "ipv6", "uri", "uri-reference"]
|
|
1566
|
-
});
|
|
1567
|
-
metaschemaReady = Promise.all([loadVocabularySchemas(), loadMetaSchema("draft-2020-12")]).then(([vocabSchemas, metaSchema]) => {
|
|
1568
|
-
if (ajvInstance) {
|
|
1569
|
-
for (const vocabSchema of vocabSchemas) {
|
|
1570
|
-
try {
|
|
1571
|
-
ajvInstance.addMetaSchema(vocabSchema);
|
|
1572
|
-
} catch {
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
ajvInstance.addMetaSchema(metaSchema);
|
|
1576
|
-
}
|
|
1577
|
-
}).catch((error) => {
|
|
1578
|
-
throw new Error(`Failed to load metaschemas: ${error}`);
|
|
1579
|
-
});
|
|
1577
|
+
function detectDialect(schema) {
|
|
1578
|
+
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
1579
|
+
const maybeSchema = schema;
|
|
1580
|
+
const declared = maybeSchema.$schema;
|
|
1581
|
+
if (typeof declared === "string") {
|
|
1582
|
+
if (declared.includes("draft-04")) return "draft-04";
|
|
1583
|
+
if (declared.includes("draft-06")) return "draft-06";
|
|
1584
|
+
if (declared.includes("draft-07")) return "draft-07";
|
|
1585
|
+
if (declared.includes("draft/2019-09")) return "draft-2019-09";
|
|
1586
|
+
if (declared.includes("draft/2020-12")) return "draft-2020-12";
|
|
1587
|
+
}
|
|
1580
1588
|
}
|
|
1581
|
-
return
|
|
1589
|
+
return "draft-2020-12";
|
|
1590
|
+
}
|
|
1591
|
+
function createAjv(dialect) {
|
|
1592
|
+
const AjvCtor = dialect === "draft-2020-12" ? Ajv2020 : dialect === "draft-2019-09" ? Ajv2019 : dialect === "draft-04" ? AjvDraft04 : Ajv;
|
|
1593
|
+
const ajv = new AjvCtor({
|
|
1594
|
+
strict: false,
|
|
1595
|
+
allErrors: true,
|
|
1596
|
+
verbose: true,
|
|
1597
|
+
// Allow schemas with $id to be added without replacing existing ones
|
|
1598
|
+
addUsedSchema: false,
|
|
1599
|
+
// draft-04 uses "id"; later drafts use "$id"
|
|
1600
|
+
schemaId: dialect === "draft-04" ? "id" : "$id",
|
|
1601
|
+
// Enable async schema loading for YAML references
|
|
1602
|
+
loadSchema: loadReferencedSchema
|
|
1603
|
+
});
|
|
1604
|
+
applyFulmenAjvFormats(ajv);
|
|
1605
|
+
return ajv;
|
|
1606
|
+
}
|
|
1607
|
+
async function getAjv(dialect) {
|
|
1608
|
+
const existing = ajvInstances.get(dialect);
|
|
1609
|
+
if (existing) {
|
|
1610
|
+
const ready = metaschemaReady.get(dialect);
|
|
1611
|
+
if (ready) await ready;
|
|
1612
|
+
return existing;
|
|
1613
|
+
}
|
|
1614
|
+
const ajv = createAjv(dialect);
|
|
1615
|
+
ajvInstances.set(dialect, ajv);
|
|
1616
|
+
const readyPromise = Promise.all([loadVocabularySchemas(dialect), loadMetaSchema(dialect)]).then(([vocabSchemas, metaSchema]) => {
|
|
1617
|
+
for (const vocabSchema of vocabSchemas) {
|
|
1618
|
+
try {
|
|
1619
|
+
ajv.addMetaSchema(vocabSchema);
|
|
1620
|
+
} catch {
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
try {
|
|
1624
|
+
ajv.addMetaSchema(metaSchema);
|
|
1625
|
+
} catch {
|
|
1626
|
+
}
|
|
1627
|
+
}).catch((error) => {
|
|
1628
|
+
throw new Error(`Failed to load metaschemas (${dialect}): ${error}`);
|
|
1629
|
+
});
|
|
1630
|
+
metaschemaReady.set(dialect, readyPromise);
|
|
1631
|
+
await readyPromise;
|
|
1632
|
+
return ajv;
|
|
1582
1633
|
}
|
|
1583
1634
|
async function compileSchema(schema, options = {}) {
|
|
1584
|
-
const
|
|
1585
|
-
if (metaschemaReady) {
|
|
1586
|
-
await metaschemaReady;
|
|
1587
|
-
}
|
|
1588
|
-
const cacheKey = typeof schema === "string" ? schema : JSON.stringify(schema);
|
|
1589
|
-
const cached = schemaCache.get(cacheKey);
|
|
1590
|
-
if (cached !== void 0) {
|
|
1591
|
-
return cached;
|
|
1592
|
-
}
|
|
1635
|
+
const baseKey = typeof schema === "string" ? schema : JSON.stringify(schema);
|
|
1593
1636
|
let parsedSchema;
|
|
1594
1637
|
if (typeof schema === "string") {
|
|
1595
1638
|
try {
|
|
@@ -1607,18 +1650,27 @@ async function compileSchema(schema, options = {}) {
|
|
|
1607
1650
|
} else {
|
|
1608
1651
|
parsedSchema = schema;
|
|
1609
1652
|
}
|
|
1653
|
+
const dialect = detectDialect(parsedSchema);
|
|
1654
|
+
const ajv = await getAjv(dialect);
|
|
1655
|
+
const cacheKey = `${dialect}:${baseKey}`;
|
|
1656
|
+
const cached = schemaCache.get(cacheKey);
|
|
1657
|
+
if (cached !== void 0) {
|
|
1658
|
+
return cached;
|
|
1659
|
+
}
|
|
1610
1660
|
try {
|
|
1611
1661
|
if (options.aliases && options.aliases.length > 0) {
|
|
1612
1662
|
for (const alias of options.aliases) {
|
|
1613
1663
|
if (alias && ajv.getSchema(alias) === void 0) {
|
|
1614
1664
|
try {
|
|
1615
|
-
|
|
1665
|
+
if (typeof parsedSchema === "object" && parsedSchema !== null) {
|
|
1666
|
+
ajv.addSchema(parsedSchema, alias);
|
|
1667
|
+
}
|
|
1616
1668
|
} catch {
|
|
1617
1669
|
}
|
|
1618
1670
|
}
|
|
1619
1671
|
}
|
|
1620
1672
|
}
|
|
1621
|
-
const validator = await ajv.compileAsync(parsedSchema);
|
|
1673
|
+
const validator = typeof parsedSchema === "boolean" ? ajv.compile(parsedSchema) : await ajv.compileAsync(parsedSchema);
|
|
1622
1674
|
schemaCache.set(cacheKey, validator);
|
|
1623
1675
|
return validator;
|
|
1624
1676
|
} catch (error) {
|
|
@@ -1688,8 +1740,39 @@ async function validateFile(filePath, validator) {
|
|
|
1688
1740
|
}
|
|
1689
1741
|
async function validateSchema(schema) {
|
|
1690
1742
|
try {
|
|
1691
|
-
|
|
1692
|
-
|
|
1743
|
+
let parsedSchema;
|
|
1744
|
+
if (typeof schema === "string") {
|
|
1745
|
+
try {
|
|
1746
|
+
parsedSchema = JSON.parse(schema);
|
|
1747
|
+
} catch {
|
|
1748
|
+
parsedSchema = parse(schema);
|
|
1749
|
+
}
|
|
1750
|
+
} else if (Buffer.isBuffer(schema)) {
|
|
1751
|
+
const content = schema.toString("utf-8");
|
|
1752
|
+
try {
|
|
1753
|
+
parsedSchema = JSON.parse(content);
|
|
1754
|
+
} catch {
|
|
1755
|
+
parsedSchema = parse(content);
|
|
1756
|
+
}
|
|
1757
|
+
} else {
|
|
1758
|
+
parsedSchema = schema;
|
|
1759
|
+
}
|
|
1760
|
+
const dialect = detectDialect(parsedSchema);
|
|
1761
|
+
const ajv = await getAjv(dialect);
|
|
1762
|
+
const metaValid = ajv.validateSchema(parsedSchema);
|
|
1763
|
+
if (!metaValid && ajv.errors) {
|
|
1764
|
+
const diagnostics = ajv.errors.map(
|
|
1765
|
+
(error) => createDiagnostic(
|
|
1766
|
+
error.instancePath || "",
|
|
1767
|
+
error.message || "Schema meta-validation failed",
|
|
1768
|
+
error.keyword || "unknown",
|
|
1769
|
+
"ERROR",
|
|
1770
|
+
"ajv"
|
|
1771
|
+
)
|
|
1772
|
+
);
|
|
1773
|
+
return { valid: false, diagnostics, source: "ajv" };
|
|
1774
|
+
}
|
|
1775
|
+
await compileSchema(parsedSchema);
|
|
1693
1776
|
return {
|
|
1694
1777
|
valid: true,
|
|
1695
1778
|
diagnostics: [],
|
|
@@ -1760,14 +1843,16 @@ async function validateFileBySchemaId(filePath, schemaId, registryOptions) {
|
|
|
1760
1843
|
throw error;
|
|
1761
1844
|
}
|
|
1762
1845
|
}
|
|
1763
|
-
var
|
|
1846
|
+
var ajvInstances, metaschemaReady, schemaCache;
|
|
1764
1847
|
var init_validator = __esm({
|
|
1765
1848
|
"src/schema/validator.ts"() {
|
|
1766
1849
|
init_telemetry();
|
|
1850
|
+
init_ajv_formats();
|
|
1767
1851
|
init_errors();
|
|
1768
1852
|
init_registry();
|
|
1769
1853
|
init_utils();
|
|
1770
|
-
|
|
1854
|
+
ajvInstances = /* @__PURE__ */ new Map();
|
|
1855
|
+
metaschemaReady = /* @__PURE__ */ new Map();
|
|
1771
1856
|
schemaCache = /* @__PURE__ */ new Map();
|
|
1772
1857
|
}
|
|
1773
1858
|
});
|
|
@@ -3722,6 +3807,224 @@ var init_capabilities2 = __esm({
|
|
|
3722
3807
|
}
|
|
3723
3808
|
});
|
|
3724
3809
|
|
|
3810
|
+
// src/foundry/signals/config-reload-endpoint.ts
|
|
3811
|
+
function createConfigReloadEndpoint(options) {
|
|
3812
|
+
const { loader, validator, onReload: onReload2, auth, rateLimit, logger, telemetry } = options;
|
|
3813
|
+
return async (payload, req) => {
|
|
3814
|
+
const correlationId = payload.correlation_id ?? generateCorrelationId();
|
|
3815
|
+
const authResult = await auth(req);
|
|
3816
|
+
if (!authResult.authenticated) {
|
|
3817
|
+
if (logger) {
|
|
3818
|
+
logger.warn("Config reload endpoint: authentication failed", {
|
|
3819
|
+
correlation_id: correlationId,
|
|
3820
|
+
reason: authResult.reason
|
|
3821
|
+
});
|
|
3822
|
+
}
|
|
3823
|
+
if (telemetry) {
|
|
3824
|
+
telemetry.emit("fulmen.config.http_endpoint.auth_failed", {
|
|
3825
|
+
correlation_id: correlationId
|
|
3826
|
+
});
|
|
3827
|
+
}
|
|
3828
|
+
return {
|
|
3829
|
+
status: "error",
|
|
3830
|
+
error: "authentication_failed",
|
|
3831
|
+
message: authResult.reason || "Authentication required",
|
|
3832
|
+
statusCode: 401
|
|
3833
|
+
};
|
|
3834
|
+
}
|
|
3835
|
+
const identity = authResult.identity || "unknown";
|
|
3836
|
+
if (rateLimit) {
|
|
3837
|
+
const rateLimitResult = await rateLimit(identity);
|
|
3838
|
+
if (!rateLimitResult.allowed) {
|
|
3839
|
+
if (logger) {
|
|
3840
|
+
logger.warn("Config reload endpoint: rate limit exceeded", {
|
|
3841
|
+
correlation_id: correlationId,
|
|
3842
|
+
identity
|
|
3843
|
+
});
|
|
3844
|
+
}
|
|
3845
|
+
if (telemetry) {
|
|
3846
|
+
telemetry.emit("fulmen.config.http_endpoint.rate_limited", {
|
|
3847
|
+
correlation_id: correlationId
|
|
3848
|
+
});
|
|
3849
|
+
}
|
|
3850
|
+
return {
|
|
3851
|
+
status: "error",
|
|
3852
|
+
error: "rate_limit_exceeded",
|
|
3853
|
+
message: "Rate limit exceeded. Please try again later.",
|
|
3854
|
+
statusCode: 429
|
|
3855
|
+
};
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
if (telemetry) {
|
|
3859
|
+
telemetry.emit("fulmen.config.http_endpoint.reload_requested", {
|
|
3860
|
+
correlation_id: correlationId
|
|
3861
|
+
});
|
|
3862
|
+
}
|
|
3863
|
+
try {
|
|
3864
|
+
const config = await loader();
|
|
3865
|
+
if (validator) {
|
|
3866
|
+
const validation = await validator(config);
|
|
3867
|
+
if (!validation.valid) {
|
|
3868
|
+
if (logger) {
|
|
3869
|
+
logger.warn("Config reload endpoint: validation failed", {
|
|
3870
|
+
correlation_id: correlationId,
|
|
3871
|
+
error_count: validation.errors?.length ?? 0
|
|
3872
|
+
});
|
|
3873
|
+
}
|
|
3874
|
+
if (telemetry) {
|
|
3875
|
+
telemetry.emit("fulmen.config.http_endpoint.reload_rejected", {
|
|
3876
|
+
correlation_id: correlationId,
|
|
3877
|
+
reason: "validation_failed"
|
|
3878
|
+
});
|
|
3879
|
+
}
|
|
3880
|
+
return {
|
|
3881
|
+
status: "error",
|
|
3882
|
+
error: "validation_failed",
|
|
3883
|
+
message: "Configuration validation failed",
|
|
3884
|
+
validation_errors: validation.errors,
|
|
3885
|
+
statusCode: 422
|
|
3886
|
+
};
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
if (onReload2) {
|
|
3890
|
+
await onReload2(config);
|
|
3891
|
+
}
|
|
3892
|
+
if (telemetry) {
|
|
3893
|
+
telemetry.emit("fulmen.config.http_endpoint.reload_accepted", {
|
|
3894
|
+
correlation_id: correlationId
|
|
3895
|
+
});
|
|
3896
|
+
}
|
|
3897
|
+
if (logger) {
|
|
3898
|
+
logger.info("Config reload endpoint: reload accepted", {
|
|
3899
|
+
correlation_id: correlationId,
|
|
3900
|
+
reason: payload.reason
|
|
3901
|
+
});
|
|
3902
|
+
}
|
|
3903
|
+
return {
|
|
3904
|
+
status: "reloaded",
|
|
3905
|
+
correlation_id: correlationId,
|
|
3906
|
+
message: "Configuration reloaded",
|
|
3907
|
+
statusCode: 200
|
|
3908
|
+
};
|
|
3909
|
+
} catch (error) {
|
|
3910
|
+
if (logger) {
|
|
3911
|
+
logger.warn("Config reload endpoint: reload failed", {
|
|
3912
|
+
correlation_id: correlationId,
|
|
3913
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3914
|
+
});
|
|
3915
|
+
}
|
|
3916
|
+
if (telemetry) {
|
|
3917
|
+
telemetry.emit("fulmen.config.http_endpoint.reload_error", {
|
|
3918
|
+
correlation_id: correlationId,
|
|
3919
|
+
error_type: error instanceof Error ? error.constructor.name : "unknown"
|
|
3920
|
+
});
|
|
3921
|
+
}
|
|
3922
|
+
return {
|
|
3923
|
+
status: "error",
|
|
3924
|
+
error: "reload_failed",
|
|
3925
|
+
message: error instanceof Error ? error.message : String(error),
|
|
3926
|
+
statusCode: 500
|
|
3927
|
+
};
|
|
3928
|
+
}
|
|
3929
|
+
};
|
|
3930
|
+
}
|
|
3931
|
+
function generateCorrelationId() {
|
|
3932
|
+
return `cfg-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
3933
|
+
}
|
|
3934
|
+
var init_config_reload_endpoint = __esm({
|
|
3935
|
+
"src/foundry/signals/config-reload-endpoint.ts"() {
|
|
3936
|
+
}
|
|
3937
|
+
});
|
|
3938
|
+
|
|
3939
|
+
// src/appidentity/runtime.ts
|
|
3940
|
+
function detectRuntime() {
|
|
3941
|
+
const versions = process.versions;
|
|
3942
|
+
if (typeof versions.bun === "string" && versions.bun.length > 0) {
|
|
3943
|
+
return { name: "bun", version: versions.bun };
|
|
3944
|
+
}
|
|
3945
|
+
if (typeof versions.node === "string" && versions.node.length > 0) {
|
|
3946
|
+
return { name: "node", version: versions.node };
|
|
3947
|
+
}
|
|
3948
|
+
return { name: "unknown" };
|
|
3949
|
+
}
|
|
3950
|
+
function buildRuntimeInfo(options = {}) {
|
|
3951
|
+
const runtime = detectRuntime();
|
|
3952
|
+
const serviceName = options.serviceName ?? options.identity?.app.binary_name ?? "unknown-service";
|
|
3953
|
+
const vendor = options.vendor ?? options.identity?.app.vendor;
|
|
3954
|
+
return {
|
|
3955
|
+
service: {
|
|
3956
|
+
name: serviceName,
|
|
3957
|
+
vendor,
|
|
3958
|
+
version: options.version
|
|
3959
|
+
},
|
|
3960
|
+
runtime,
|
|
3961
|
+
platform: {
|
|
3962
|
+
os: process.platform,
|
|
3963
|
+
arch: process.arch
|
|
3964
|
+
}
|
|
3965
|
+
};
|
|
3966
|
+
}
|
|
3967
|
+
var init_runtime = __esm({
|
|
3968
|
+
"src/appidentity/runtime.ts"() {
|
|
3969
|
+
}
|
|
3970
|
+
});
|
|
3971
|
+
|
|
3972
|
+
// src/foundry/signals/control-discovery-endpoint.ts
|
|
3973
|
+
function createControlDiscoveryEndpoint(options) {
|
|
3974
|
+
const { identity, version, endpoints, auth, authSummary, logger, telemetry } = options;
|
|
3975
|
+
return async (req) => {
|
|
3976
|
+
if (auth) {
|
|
3977
|
+
const authResult = await auth(req);
|
|
3978
|
+
if (!authResult.authenticated) {
|
|
3979
|
+
if (logger) {
|
|
3980
|
+
logger.warn("Control discovery endpoint: authentication failed", {
|
|
3981
|
+
reason: authResult.reason
|
|
3982
|
+
});
|
|
3983
|
+
}
|
|
3984
|
+
if (telemetry) {
|
|
3985
|
+
telemetry.emit("fulmen.control.discovery.auth_failed", {
|
|
3986
|
+
service: identity.app.binary_name
|
|
3987
|
+
});
|
|
3988
|
+
}
|
|
3989
|
+
return {
|
|
3990
|
+
status: "error",
|
|
3991
|
+
error: "authentication_failed",
|
|
3992
|
+
message: authResult.reason || "Authentication required",
|
|
3993
|
+
statusCode: 401
|
|
3994
|
+
};
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
if (telemetry) {
|
|
3998
|
+
telemetry.emit("fulmen.control.discovery.served", {
|
|
3999
|
+
service: identity.app.binary_name
|
|
4000
|
+
});
|
|
4001
|
+
}
|
|
4002
|
+
const runtime = buildRuntimeInfo({ identity, version });
|
|
4003
|
+
return {
|
|
4004
|
+
status: "ok",
|
|
4005
|
+
service: {
|
|
4006
|
+
name: identity.app.binary_name,
|
|
4007
|
+
vendor: identity.app.vendor,
|
|
4008
|
+
version
|
|
4009
|
+
},
|
|
4010
|
+
runtime: {
|
|
4011
|
+
name: runtime.runtime.name,
|
|
4012
|
+
version: runtime.runtime.version,
|
|
4013
|
+
platform: runtime.platform.os,
|
|
4014
|
+
arch: runtime.platform.arch
|
|
4015
|
+
},
|
|
4016
|
+
auth_summary: authSummary,
|
|
4017
|
+
endpoints,
|
|
4018
|
+
statusCode: 200
|
|
4019
|
+
};
|
|
4020
|
+
};
|
|
4021
|
+
}
|
|
4022
|
+
var init_control_discovery_endpoint = __esm({
|
|
4023
|
+
"src/foundry/signals/control-discovery-endpoint.ts"() {
|
|
4024
|
+
init_runtime();
|
|
4025
|
+
}
|
|
4026
|
+
});
|
|
4027
|
+
|
|
3725
4028
|
// src/foundry/signals/convenience.ts
|
|
3726
4029
|
async function onShutdown(manager, handler, options = {}) {
|
|
3727
4030
|
await manager.register("SIGTERM", handler, options);
|
|
@@ -3981,7 +4284,7 @@ var init_guards = __esm({
|
|
|
3981
4284
|
function createSignalEndpoint(options) {
|
|
3982
4285
|
const { manager, auth, rateLimit, logger, telemetry, allowedSignals } = options;
|
|
3983
4286
|
return async (payload, req) => {
|
|
3984
|
-
const correlationId = payload.correlation_id ??
|
|
4287
|
+
const correlationId = payload.correlation_id ?? generateCorrelationId2();
|
|
3985
4288
|
const authResult = await auth(req);
|
|
3986
4289
|
if (!authResult.authenticated) {
|
|
3987
4290
|
if (logger) {
|
|
@@ -4104,7 +4407,7 @@ function normalizeSignalName(signal) {
|
|
|
4104
4407
|
}
|
|
4105
4408
|
return `SIG${upper}`;
|
|
4106
4409
|
}
|
|
4107
|
-
function
|
|
4410
|
+
function generateCorrelationId2() {
|
|
4108
4411
|
return `sig-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
4109
4412
|
}
|
|
4110
4413
|
function createBearerTokenAuth(expectedToken) {
|
|
@@ -4571,6 +4874,8 @@ var init_signals = __esm({
|
|
|
4571
4874
|
"src/foundry/signals/index.ts"() {
|
|
4572
4875
|
init_capabilities2();
|
|
4573
4876
|
init_catalog();
|
|
4877
|
+
init_config_reload_endpoint();
|
|
4878
|
+
init_control_discovery_endpoint();
|
|
4574
4879
|
init_convenience();
|
|
4575
4880
|
init_double_tap();
|
|
4576
4881
|
init_guards();
|
|
@@ -4716,7 +5021,9 @@ __export(foundry_exports, {
|
|
|
4716
5021
|
clearMimeTypeCache: () => clearMimeTypeCache,
|
|
4717
5022
|
clearPatternCache: () => clearPatternCache,
|
|
4718
5023
|
createBearerTokenAuth: () => createBearerTokenAuth,
|
|
5024
|
+
createConfigReloadEndpoint: () => createConfigReloadEndpoint,
|
|
4719
5025
|
createConfigReloadHandler: () => createConfigReloadHandler,
|
|
5026
|
+
createControlDiscoveryEndpoint: () => createControlDiscoveryEndpoint,
|
|
4720
5027
|
createDoubleTapTracker: () => createDoubleTapTracker,
|
|
4721
5028
|
createSignalEndpoint: () => createSignalEndpoint,
|
|
4722
5029
|
createSignalManager: () => createSignalManager,
|
|
@@ -5772,6 +6079,7 @@ var init_cli = __esm({
|
|
|
5772
6079
|
// src/schema/index.ts
|
|
5773
6080
|
var init_schema = __esm({
|
|
5774
6081
|
"src/schema/index.ts"() {
|
|
6082
|
+
init_ajv_formats();
|
|
5775
6083
|
init_cli();
|
|
5776
6084
|
init_errors();
|
|
5777
6085
|
init_export();
|
|
@@ -5783,6 +6091,32 @@ var init_schema = __esm({
|
|
|
5783
6091
|
}
|
|
5784
6092
|
});
|
|
5785
6093
|
|
|
6094
|
+
// src/config/env-alias.ts
|
|
6095
|
+
function resolveEnvAliases(env, aliasToCanonical) {
|
|
6096
|
+
const out = { ...env };
|
|
6097
|
+
const applied = [];
|
|
6098
|
+
const conflicts = [];
|
|
6099
|
+
for (const [aliasKey, canonicalKey] of Object.entries(aliasToCanonical)) {
|
|
6100
|
+
const aliasValue = env[aliasKey];
|
|
6101
|
+
if (aliasValue === void 0 || aliasValue === "") continue;
|
|
6102
|
+
const canonicalValue = env[canonicalKey];
|
|
6103
|
+
if (canonicalValue === void 0 || canonicalValue === "") {
|
|
6104
|
+
out[canonicalKey] = aliasValue;
|
|
6105
|
+
applied.push({ aliasKey, canonicalKey });
|
|
6106
|
+
continue;
|
|
6107
|
+
}
|
|
6108
|
+
if (canonicalValue !== aliasValue) {
|
|
6109
|
+
conflicts.push({
|
|
6110
|
+
canonicalKey,
|
|
6111
|
+
aliasKey,
|
|
6112
|
+
canonicalValue,
|
|
6113
|
+
aliasValue
|
|
6114
|
+
});
|
|
6115
|
+
}
|
|
6116
|
+
}
|
|
6117
|
+
return { env: out, applied, conflicts };
|
|
6118
|
+
}
|
|
6119
|
+
|
|
5786
6120
|
// src/config/errors.ts
|
|
5787
6121
|
var ConfigPathError = class _ConfigPathError extends Error {
|
|
5788
6122
|
constructor(message, cause) {
|
|
@@ -6134,6 +6468,33 @@ function parseEnvVars(prefix) {
|
|
|
6134
6468
|
}
|
|
6135
6469
|
return config;
|
|
6136
6470
|
}
|
|
6471
|
+
function parseEnvVarsWithReport(prefix) {
|
|
6472
|
+
const config = {};
|
|
6473
|
+
const consumedKeys = [];
|
|
6474
|
+
const prefixWithSeparator = `${prefix}_`;
|
|
6475
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
6476
|
+
if (!value) continue;
|
|
6477
|
+
if (key.startsWith(prefixWithSeparator)) {
|
|
6478
|
+
consumedKeys.push(key);
|
|
6479
|
+
const keyWithoutPrefix = key.slice(prefixWithSeparator.length);
|
|
6480
|
+
const parts = keyWithoutPrefix.split("_").filter((p) => p.length > 0);
|
|
6481
|
+
let current = config;
|
|
6482
|
+
for (let i = 0; i < parts.length; i++) {
|
|
6483
|
+
const part = parts[i].toLowerCase();
|
|
6484
|
+
if (i === parts.length - 1) {
|
|
6485
|
+
current[part] = parseEnvValue(value);
|
|
6486
|
+
} else {
|
|
6487
|
+
if (!current[part] || typeof current[part] !== "object") {
|
|
6488
|
+
current[part] = {};
|
|
6489
|
+
}
|
|
6490
|
+
current = current[part];
|
|
6491
|
+
}
|
|
6492
|
+
}
|
|
6493
|
+
}
|
|
6494
|
+
}
|
|
6495
|
+
consumedKeys.sort();
|
|
6496
|
+
return { config, consumedKeys };
|
|
6497
|
+
}
|
|
6137
6498
|
async function parseConfigFile(path) {
|
|
6138
6499
|
const content = await readFile(path, "utf-8");
|
|
6139
6500
|
const ext = extname(path).toLowerCase();
|
|
@@ -6167,8 +6528,10 @@ async function loadConfig(options) {
|
|
|
6167
6528
|
activeLayers.push("user");
|
|
6168
6529
|
}
|
|
6169
6530
|
const envPrefix = options.envPrefix || (identity.app ? identity.app.toUpperCase().replace(/-/g, "_") : "APP");
|
|
6170
|
-
const
|
|
6171
|
-
|
|
6531
|
+
const includeEnvVarReport = options.includeEnvVarReport === true;
|
|
6532
|
+
const envVars = includeEnvVarReport ? parseEnvVarsWithReport(envPrefix) : null;
|
|
6533
|
+
const envConfig = includeEnvVarReport ? envVars?.config : parseEnvVars(envPrefix);
|
|
6534
|
+
if (envConfig && typeof envConfig === "object" && Object.keys(envConfig).length > 0) {
|
|
6172
6535
|
mergedConfig = deepMerge(mergedConfig, envConfig);
|
|
6173
6536
|
activeLayers.push("env");
|
|
6174
6537
|
}
|
|
@@ -6197,6 +6560,8 @@ async function loadConfig(options) {
|
|
|
6197
6560
|
defaultsPath,
|
|
6198
6561
|
userConfigPath,
|
|
6199
6562
|
envPrefix,
|
|
6563
|
+
envVarsConsumed: includeEnvVarReport ? envVars?.consumedKeys : void 0,
|
|
6564
|
+
envVarsConsumedCount: includeEnvVarReport ? envVars?.consumedKeys.length : void 0,
|
|
6200
6565
|
activeLayers,
|
|
6201
6566
|
schema: {
|
|
6202
6567
|
path: options.schemaPath || null,
|
|
@@ -6209,6 +6574,6 @@ async function loadConfig(options) {
|
|
|
6209
6574
|
// src/config/index.ts
|
|
6210
6575
|
var VERSION2 = "0.1.0";
|
|
6211
6576
|
|
|
6212
|
-
export { ConfigPathError, ConfigValidationError, VERSION2 as VERSION, ensureDirExists, getAppCacheDir, getAppConfigDir, getAppDataDir, getConfigSearchPaths, getFulmenCacheDir, getFulmenConfigDir, getFulmenDataDir, getXDGBaseDirs, loadConfig, resolveConfigPath };
|
|
6577
|
+
export { ConfigPathError, ConfigValidationError, VERSION2 as VERSION, ensureDirExists, getAppCacheDir, getAppConfigDir, getAppDataDir, getConfigSearchPaths, getFulmenCacheDir, getFulmenConfigDir, getFulmenDataDir, getXDGBaseDirs, loadConfig, resolveConfigPath, resolveEnvAliases };
|
|
6213
6578
|
//# sourceMappingURL=index.js.map
|
|
6214
6579
|
//# sourceMappingURL=index.js.map
|