@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.
Files changed (111) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +61 -7
  3. package/config/crucible-ts/agentic/roles/README.md +3 -3
  4. package/config/crucible-ts/library/fulencode/fixtures/README.md +18 -0
  5. package/config/crucible-ts/library/fulencode/fixtures/bom/bom.yaml +14 -0
  6. package/config/crucible-ts/library/fulencode/fixtures/detection/detection.yaml +12 -0
  7. package/config/crucible-ts/library/fulencode/fixtures/invalid-encodings/base64.yaml +10 -0
  8. package/config/crucible-ts/library/fulencode/fixtures/normalization/text-safe.yaml +10 -0
  9. package/config/crucible-ts/library/fulencode/fixtures/telemetry/telemetry-test-cases.yaml +24 -0
  10. package/config/crucible-ts/library/fulencode/fixtures/valid-encodings/base64.yaml +11 -0
  11. package/config/crucible-ts/taxonomy/library/platform-modules/v1.0.0/modules.yaml +2 -2
  12. package/config/crucible-ts/taxonomy/metrics.yaml +79 -1
  13. package/dist/appidentity/index.d.ts +31 -109
  14. package/dist/appidentity/index.js +369 -60
  15. package/dist/appidentity/index.js.map +1 -1
  16. package/dist/config/index.d.ts +46 -1
  17. package/dist/config/index.js +427 -62
  18. package/dist/config/index.js.map +1 -1
  19. package/dist/crucible/index.js +367 -59
  20. package/dist/crucible/index.js.map +1 -1
  21. package/dist/errors/index.d.ts +1 -1
  22. package/dist/errors/index.js +367 -59
  23. package/dist/errors/index.js.map +1 -1
  24. package/dist/foundry/index.d.ts +2 -1
  25. package/dist/foundry/index.js +368 -60
  26. package/dist/foundry/index.js.map +1 -1
  27. package/dist/fulencode/index.d.ts +102 -0
  28. package/dist/fulencode/index.js +806 -0
  29. package/dist/fulencode/index.js.map +1 -0
  30. package/dist/index.d.ts +4 -3
  31. package/dist/index.js +370 -61
  32. package/dist/index.js.map +1 -1
  33. package/dist/pathfinder/index.d.ts +1 -1
  34. package/dist/pathfinder/index.js +367 -59
  35. package/dist/pathfinder/index.js.map +1 -1
  36. package/dist/reports/license-inventory.csv +31 -24
  37. package/dist/schema/index.d.ts +16 -3
  38. package/dist/schema/index.js +368 -60
  39. package/dist/schema/index.js.map +1 -1
  40. package/dist/signals/index.d.ts +483 -395
  41. package/dist/signals/index.js +368 -60
  42. package/dist/signals/index.js.map +1 -1
  43. package/dist/telemetry/http/index.js +368 -59
  44. package/dist/telemetry/http/index.js.map +1 -1
  45. package/dist/telemetry/index.d.ts +1 -1
  46. package/dist/telemetry/index.js +367 -59
  47. package/dist/telemetry/index.js.map +1 -1
  48. package/dist/telemetry/prometheus/index.d.ts +1 -1
  49. package/dist/telemetry/prometheus/index.js +369 -59
  50. package/dist/telemetry/prometheus/index.js.map +1 -1
  51. package/dist/{types-BJswWpQC.d.ts → types-DdoeE7F5.d.ts} +1 -1
  52. package/dist/types-Dv5TERCM.d.ts +108 -0
  53. package/package.json +13 -8
  54. package/schemas/crucible-ts/library/fulencode/v1.0.0/README.md +37 -0
  55. package/schemas/crucible-ts/library/fulencode/v1.0.0/bom-result.schema.json +48 -0
  56. package/schemas/crucible-ts/library/fulencode/v1.0.0/decode-options.schema.json +60 -0
  57. package/schemas/crucible-ts/library/fulencode/v1.0.0/decoding-result.schema.json +70 -0
  58. package/schemas/crucible-ts/library/fulencode/v1.0.0/detect-options.schema.json +25 -0
  59. package/schemas/crucible-ts/library/fulencode/v1.0.0/detection-result.schema.json +57 -0
  60. package/schemas/crucible-ts/library/fulencode/v1.0.0/encode-options.schema.json +71 -0
  61. package/schemas/crucible-ts/library/fulencode/v1.0.0/encoding-result.schema.json +57 -0
  62. package/schemas/crucible-ts/library/fulencode/v1.0.0/fulencode-config.schema.json +8 -4
  63. package/schemas/crucible-ts/library/fulencode/v1.0.0/fulencode-error.schema.json +66 -0
  64. package/schemas/crucible-ts/library/fulencode/v1.0.0/normalization-result.schema.json +73 -0
  65. package/schemas/crucible-ts/library/fulencode/v1.0.0/normalize-options.schema.json +44 -0
  66. package/schemas/crucible-ts/meta/README.md +38 -2
  67. package/schemas/crucible-ts/meta/draft-04/schema.json +222 -0
  68. package/schemas/crucible-ts/meta/draft-06/schema.json +218 -0
  69. package/schemas/crucible-ts/meta/draft-2019-09/meta/applicator.json +93 -0
  70. package/schemas/crucible-ts/meta/draft-2019-09/meta/content.json +21 -0
  71. package/schemas/crucible-ts/meta/draft-2019-09/meta/core.json +58 -0
  72. package/schemas/crucible-ts/meta/draft-2019-09/meta/format.json +15 -0
  73. package/schemas/crucible-ts/meta/draft-2019-09/meta/meta-data.json +35 -0
  74. package/schemas/crucible-ts/meta/draft-2019-09/meta/validation.json +119 -0
  75. package/schemas/crucible-ts/meta/draft-2019-09/offline.schema.json +148 -0
  76. package/schemas/crucible-ts/meta/draft-2019-09/schema.json +62 -0
  77. package/schemas/crucible-ts/meta/fixtures/draft-04-sample.json +16 -0
  78. package/schemas/crucible-ts/meta/fixtures/draft-06-sample.json +16 -0
  79. package/schemas/crucible-ts/meta/fixtures/draft-07-sample.json +34 -0
  80. package/schemas/crucible-ts/meta/fixtures/draft-2019-09-sample.json +21 -0
  81. package/schemas/crucible-ts/meta/fixtures/draft-2020-12-sample.json +21 -0
  82. package/schemas/crucible-ts/taxonomy/library/fulencode/normalization-profiles/v1.0.0/profiles.yaml +16 -0
  83. package/schemas/crucible-ts/upstream/3leaps/crucible/PROVENANCE.md +64 -0
  84. package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/access-tier.dimension.json +103 -0
  85. package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/retention-lifecycle.dimension.json +103 -0
  86. package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/schema-stability.dimension.json +100 -0
  87. package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/sensitivity.dimension.json +130 -0
  88. package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/velocity-mode.dimension.json +79 -0
  89. package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/volatility.dimension.json +72 -0
  90. package/schemas/crucible-ts/upstream/3leaps/crucible/config/classifiers/dimensions/volume-tier.dimension.json +66 -0
  91. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/catalog/classifiers/README.md +29 -0
  92. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/access-tier-classification.md +163 -0
  93. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/classifiers-framework.md +157 -0
  94. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/data-sensitivity-classification.md +259 -0
  95. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/retention-lifecycle-classification.md +200 -0
  96. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/schema-stability-classification.md +205 -0
  97. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/velocity-mode-classification.md +222 -0
  98. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/volatility-classification.md +209 -0
  99. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/volume-tier-classification.md +200 -0
  100. package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/ailink/v0/README.md +48 -0
  101. package/schemas/crucible-ts/upstream/3leaps/{ailink → crucible/schemas/ailink}/v0/prompt.schema.json +4 -18
  102. package/schemas/crucible-ts/upstream/3leaps/{ailink → crucible/schemas/ailink}/v0/search-response.schema.json +7 -37
  103. package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/classifiers/v0/dimension-definition.schema.json +247 -0
  104. package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/classifiers/v0/sensitivity-level.schema.json +67 -0
  105. package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/error-response.schema.json +59 -0
  106. package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/lifecycle-phases.data.json +102 -0
  107. package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/lifecycle-phases.schema.json +101 -0
  108. package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/release-phase.schema.json +18 -0
  109. package/schemas/crucible-ts/upstream/3leaps/crucible/schemas/foundation/v0/types.schema.json +177 -0
  110. package/schemas/crucible-ts/upstream/3leaps/PROVENANCE.md +0 -43
  111. /package/schemas/crucible-ts/upstream/3leaps/{agentic → crucible/schemas/agentic}/v0/role-prompt.schema.json +0 -0
@@ -1,3 +1,4 @@
1
+ import addFormats from 'ajv-formats';
1
2
  import { spawn } from 'child_process';
2
3
  import { access, readFile, mkdir, writeFile } from 'fs/promises';
3
4
  import { parse, stringify } from 'yaml';
@@ -5,7 +6,9 @@ import { dirname, extname, join, relative } from 'path';
5
6
  import { fileURLToPath } from 'url';
6
7
  import glob from 'fast-glob';
7
8
  import Ajv from 'ajv';
8
- import addFormats from 'ajv-formats';
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';
@@ -21,6 +24,27 @@ var __export = (target, all) => {
21
24
  for (var name in all)
22
25
  __defProp(target, name, { get: all[name], enumerable: true });
23
26
  };
27
+ function applyFulmenAjvFormats(ajv, options = {}) {
28
+ const mode = options.mode ?? "fast";
29
+ const formats = options.formats ?? DEFAULT_FORMATS;
30
+ addFormats(ajv, { mode, formats });
31
+ return ajv;
32
+ }
33
+ var DEFAULT_FORMATS;
34
+ var init_ajv_formats = __esm({
35
+ "src/schema/ajv-formats.ts"() {
36
+ DEFAULT_FORMATS = [
37
+ "date-time",
38
+ "email",
39
+ "hostname",
40
+ "ipv4",
41
+ "ipv6",
42
+ "uri",
43
+ "uri-reference",
44
+ "uuid"
45
+ ];
46
+ }
47
+ });
24
48
 
25
49
  // src/schema/errors.ts
26
50
  var errors_exports = {};
@@ -1519,20 +1543,14 @@ async function loadMetaSchema(draft) {
1519
1543
  const content = await readFile(metaSchemaPath, "utf-8");
1520
1544
  return JSON.parse(content);
1521
1545
  }
1522
- async function loadVocabularySchemas() {
1546
+ async function loadVocabularySchemas(draft) {
1547
+ if (draft !== "draft-2019-09" && draft !== "draft-2020-12") {
1548
+ return [];
1549
+ }
1523
1550
  const __filename3 = fileURLToPath(import.meta.url);
1524
1551
  const __dirname4 = dirname(__filename3);
1525
- const vocabDir = join(
1526
- __dirname4,
1527
- "..",
1528
- "..",
1529
- "schemas",
1530
- "crucible-ts",
1531
- "meta",
1532
- "draft-2020-12",
1533
- "meta"
1534
- );
1535
- const vocabFiles = [
1552
+ const vocabDir = join(__dirname4, "..", "..", "schemas", "crucible-ts", "meta", draft, "meta");
1553
+ const vocabFiles = draft === "draft-2020-12" ? [
1536
1554
  "core.json",
1537
1555
  "applicator.json",
1538
1556
  "unevaluated.json",
@@ -1540,6 +1558,13 @@ async function loadVocabularySchemas() {
1540
1558
  "meta-data.json",
1541
1559
  "format-annotation.json",
1542
1560
  "content.json"
1561
+ ] : [
1562
+ "core.json",
1563
+ "applicator.json",
1564
+ "validation.json",
1565
+ "meta-data.json",
1566
+ "format.json",
1567
+ "content.json"
1543
1568
  ];
1544
1569
  const schemas = [];
1545
1570
  for (const file of vocabFiles) {
@@ -1594,47 +1619,65 @@ async function loadReferencedSchema(uri) {
1594
1619
  }
1595
1620
  return JSON.parse(content);
1596
1621
  }
1597
- function getAjv() {
1598
- if (!ajvInstance) {
1599
- ajvInstance = new Ajv({
1600
- strict: false,
1601
- allErrors: true,
1602
- verbose: true,
1603
- // Allow schemas with $id to be added without replacing existing ones
1604
- addUsedSchema: false,
1605
- // Enable async schema loading for YAML references
1606
- loadSchema: loadReferencedSchema
1607
- });
1608
- addFormats(ajvInstance, {
1609
- mode: "fast",
1610
- formats: ["date-time", "email", "hostname", "ipv4", "ipv6", "uri", "uri-reference"]
1611
- });
1612
- metaschemaReady = Promise.all([loadVocabularySchemas(), loadMetaSchema("draft-2020-12")]).then(([vocabSchemas, metaSchema]) => {
1613
- if (ajvInstance) {
1614
- for (const vocabSchema of vocabSchemas) {
1615
- try {
1616
- ajvInstance.addMetaSchema(vocabSchema);
1617
- } catch {
1618
- }
1619
- }
1620
- ajvInstance.addMetaSchema(metaSchema);
1621
- }
1622
- }).catch((error) => {
1623
- throw new Error(`Failed to load metaschemas: ${error}`);
1624
- });
1622
+ function detectDialect(schema) {
1623
+ if (schema && typeof schema === "object" && !Array.isArray(schema)) {
1624
+ const maybeSchema = schema;
1625
+ const declared = maybeSchema.$schema;
1626
+ if (typeof declared === "string") {
1627
+ if (declared.includes("draft-04")) return "draft-04";
1628
+ if (declared.includes("draft-06")) return "draft-06";
1629
+ if (declared.includes("draft-07")) return "draft-07";
1630
+ if (declared.includes("draft/2019-09")) return "draft-2019-09";
1631
+ if (declared.includes("draft/2020-12")) return "draft-2020-12";
1632
+ }
1625
1633
  }
1626
- return ajvInstance;
1634
+ return "draft-2020-12";
1635
+ }
1636
+ function createAjv(dialect) {
1637
+ const AjvCtor = dialect === "draft-2020-12" ? Ajv2020 : dialect === "draft-2019-09" ? Ajv2019 : dialect === "draft-04" ? AjvDraft04 : Ajv;
1638
+ const ajv = new AjvCtor({
1639
+ strict: false,
1640
+ allErrors: true,
1641
+ verbose: true,
1642
+ // Allow schemas with $id to be added without replacing existing ones
1643
+ addUsedSchema: false,
1644
+ // draft-04 uses "id"; later drafts use "$id"
1645
+ schemaId: dialect === "draft-04" ? "id" : "$id",
1646
+ // Enable async schema loading for YAML references
1647
+ loadSchema: loadReferencedSchema
1648
+ });
1649
+ applyFulmenAjvFormats(ajv);
1650
+ return ajv;
1651
+ }
1652
+ async function getAjv(dialect) {
1653
+ const existing = ajvInstances.get(dialect);
1654
+ if (existing) {
1655
+ const ready = metaschemaReady.get(dialect);
1656
+ if (ready) await ready;
1657
+ return existing;
1658
+ }
1659
+ const ajv = createAjv(dialect);
1660
+ ajvInstances.set(dialect, ajv);
1661
+ const readyPromise = Promise.all([loadVocabularySchemas(dialect), loadMetaSchema(dialect)]).then(([vocabSchemas, metaSchema]) => {
1662
+ for (const vocabSchema of vocabSchemas) {
1663
+ try {
1664
+ ajv.addMetaSchema(vocabSchema);
1665
+ } catch {
1666
+ }
1667
+ }
1668
+ try {
1669
+ ajv.addMetaSchema(metaSchema);
1670
+ } catch {
1671
+ }
1672
+ }).catch((error) => {
1673
+ throw new Error(`Failed to load metaschemas (${dialect}): ${error}`);
1674
+ });
1675
+ metaschemaReady.set(dialect, readyPromise);
1676
+ await readyPromise;
1677
+ return ajv;
1627
1678
  }
1628
1679
  async function compileSchema(schema, options = {}) {
1629
- const ajv = getAjv();
1630
- if (metaschemaReady) {
1631
- await metaschemaReady;
1632
- }
1633
- const cacheKey = typeof schema === "string" ? schema : JSON.stringify(schema);
1634
- const cached = schemaCache.get(cacheKey);
1635
- if (cached !== void 0) {
1636
- return cached;
1637
- }
1680
+ const baseKey = typeof schema === "string" ? schema : JSON.stringify(schema);
1638
1681
  let parsedSchema;
1639
1682
  if (typeof schema === "string") {
1640
1683
  try {
@@ -1652,18 +1695,27 @@ async function compileSchema(schema, options = {}) {
1652
1695
  } else {
1653
1696
  parsedSchema = schema;
1654
1697
  }
1698
+ const dialect = detectDialect(parsedSchema);
1699
+ const ajv = await getAjv(dialect);
1700
+ const cacheKey = `${dialect}:${baseKey}`;
1701
+ const cached = schemaCache.get(cacheKey);
1702
+ if (cached !== void 0) {
1703
+ return cached;
1704
+ }
1655
1705
  try {
1656
1706
  if (options.aliases && options.aliases.length > 0) {
1657
1707
  for (const alias of options.aliases) {
1658
1708
  if (alias && ajv.getSchema(alias) === void 0) {
1659
1709
  try {
1660
- ajv.addSchema(parsedSchema, alias);
1710
+ if (typeof parsedSchema === "object" && parsedSchema !== null) {
1711
+ ajv.addSchema(parsedSchema, alias);
1712
+ }
1661
1713
  } catch {
1662
1714
  }
1663
1715
  }
1664
1716
  }
1665
1717
  }
1666
- const validator = await ajv.compileAsync(parsedSchema);
1718
+ const validator = typeof parsedSchema === "boolean" ? ajv.compile(parsedSchema) : await ajv.compileAsync(parsedSchema);
1667
1719
  schemaCache.set(cacheKey, validator);
1668
1720
  return validator;
1669
1721
  } catch (error) {
@@ -1733,8 +1785,39 @@ async function validateFile(filePath, validator) {
1733
1785
  }
1734
1786
  async function validateSchema(schema) {
1735
1787
  try {
1736
- const validator = await compileSchema(schema);
1737
- validateData({}, validator);
1788
+ let parsedSchema;
1789
+ if (typeof schema === "string") {
1790
+ try {
1791
+ parsedSchema = JSON.parse(schema);
1792
+ } catch {
1793
+ parsedSchema = parse(schema);
1794
+ }
1795
+ } else if (Buffer.isBuffer(schema)) {
1796
+ const content = schema.toString("utf-8");
1797
+ try {
1798
+ parsedSchema = JSON.parse(content);
1799
+ } catch {
1800
+ parsedSchema = parse(content);
1801
+ }
1802
+ } else {
1803
+ parsedSchema = schema;
1804
+ }
1805
+ const dialect = detectDialect(parsedSchema);
1806
+ const ajv = await getAjv(dialect);
1807
+ const metaValid = ajv.validateSchema(parsedSchema);
1808
+ if (!metaValid && ajv.errors) {
1809
+ const diagnostics = ajv.errors.map(
1810
+ (error) => createDiagnostic(
1811
+ error.instancePath || "",
1812
+ error.message || "Schema meta-validation failed",
1813
+ error.keyword || "unknown",
1814
+ "ERROR",
1815
+ "ajv"
1816
+ )
1817
+ );
1818
+ return { valid: false, diagnostics, source: "ajv" };
1819
+ }
1820
+ await compileSchema(parsedSchema);
1738
1821
  return {
1739
1822
  valid: true,
1740
1823
  diagnostics: [],
@@ -1805,14 +1888,16 @@ async function validateFileBySchemaId(filePath, schemaId, registryOptions) {
1805
1888
  throw error;
1806
1889
  }
1807
1890
  }
1808
- var ajvInstance, metaschemaReady, schemaCache;
1891
+ var ajvInstances, metaschemaReady, schemaCache;
1809
1892
  var init_validator = __esm({
1810
1893
  "src/schema/validator.ts"() {
1811
1894
  init_telemetry();
1895
+ init_ajv_formats();
1812
1896
  init_errors();
1813
1897
  init_registry();
1814
1898
  init_utils();
1815
- metaschemaReady = null;
1899
+ ajvInstances = /* @__PURE__ */ new Map();
1900
+ metaschemaReady = /* @__PURE__ */ new Map();
1816
1901
  schemaCache = /* @__PURE__ */ new Map();
1817
1902
  }
1818
1903
  });
@@ -3767,6 +3852,224 @@ var init_capabilities2 = __esm({
3767
3852
  }
3768
3853
  });
3769
3854
 
3855
+ // src/foundry/signals/config-reload-endpoint.ts
3856
+ function createConfigReloadEndpoint(options) {
3857
+ const { loader, validator, onReload: onReload2, auth, rateLimit, logger, telemetry } = options;
3858
+ return async (payload, req) => {
3859
+ const correlationId = payload.correlation_id ?? generateCorrelationId();
3860
+ const authResult = await auth(req);
3861
+ if (!authResult.authenticated) {
3862
+ if (logger) {
3863
+ logger.warn("Config reload endpoint: authentication failed", {
3864
+ correlation_id: correlationId,
3865
+ reason: authResult.reason
3866
+ });
3867
+ }
3868
+ if (telemetry) {
3869
+ telemetry.emit("fulmen.config.http_endpoint.auth_failed", {
3870
+ correlation_id: correlationId
3871
+ });
3872
+ }
3873
+ return {
3874
+ status: "error",
3875
+ error: "authentication_failed",
3876
+ message: authResult.reason || "Authentication required",
3877
+ statusCode: 401
3878
+ };
3879
+ }
3880
+ const identity = authResult.identity || "unknown";
3881
+ if (rateLimit) {
3882
+ const rateLimitResult = await rateLimit(identity);
3883
+ if (!rateLimitResult.allowed) {
3884
+ if (logger) {
3885
+ logger.warn("Config reload endpoint: rate limit exceeded", {
3886
+ correlation_id: correlationId,
3887
+ identity
3888
+ });
3889
+ }
3890
+ if (telemetry) {
3891
+ telemetry.emit("fulmen.config.http_endpoint.rate_limited", {
3892
+ correlation_id: correlationId
3893
+ });
3894
+ }
3895
+ return {
3896
+ status: "error",
3897
+ error: "rate_limit_exceeded",
3898
+ message: "Rate limit exceeded. Please try again later.",
3899
+ statusCode: 429
3900
+ };
3901
+ }
3902
+ }
3903
+ if (telemetry) {
3904
+ telemetry.emit("fulmen.config.http_endpoint.reload_requested", {
3905
+ correlation_id: correlationId
3906
+ });
3907
+ }
3908
+ try {
3909
+ const config = await loader();
3910
+ if (validator) {
3911
+ const validation = await validator(config);
3912
+ if (!validation.valid) {
3913
+ if (logger) {
3914
+ logger.warn("Config reload endpoint: validation failed", {
3915
+ correlation_id: correlationId,
3916
+ error_count: validation.errors?.length ?? 0
3917
+ });
3918
+ }
3919
+ if (telemetry) {
3920
+ telemetry.emit("fulmen.config.http_endpoint.reload_rejected", {
3921
+ correlation_id: correlationId,
3922
+ reason: "validation_failed"
3923
+ });
3924
+ }
3925
+ return {
3926
+ status: "error",
3927
+ error: "validation_failed",
3928
+ message: "Configuration validation failed",
3929
+ validation_errors: validation.errors,
3930
+ statusCode: 422
3931
+ };
3932
+ }
3933
+ }
3934
+ if (onReload2) {
3935
+ await onReload2(config);
3936
+ }
3937
+ if (telemetry) {
3938
+ telemetry.emit("fulmen.config.http_endpoint.reload_accepted", {
3939
+ correlation_id: correlationId
3940
+ });
3941
+ }
3942
+ if (logger) {
3943
+ logger.info("Config reload endpoint: reload accepted", {
3944
+ correlation_id: correlationId,
3945
+ reason: payload.reason
3946
+ });
3947
+ }
3948
+ return {
3949
+ status: "reloaded",
3950
+ correlation_id: correlationId,
3951
+ message: "Configuration reloaded",
3952
+ statusCode: 200
3953
+ };
3954
+ } catch (error) {
3955
+ if (logger) {
3956
+ logger.warn("Config reload endpoint: reload failed", {
3957
+ correlation_id: correlationId,
3958
+ error: error instanceof Error ? error.message : String(error)
3959
+ });
3960
+ }
3961
+ if (telemetry) {
3962
+ telemetry.emit("fulmen.config.http_endpoint.reload_error", {
3963
+ correlation_id: correlationId,
3964
+ error_type: error instanceof Error ? error.constructor.name : "unknown"
3965
+ });
3966
+ }
3967
+ return {
3968
+ status: "error",
3969
+ error: "reload_failed",
3970
+ message: error instanceof Error ? error.message : String(error),
3971
+ statusCode: 500
3972
+ };
3973
+ }
3974
+ };
3975
+ }
3976
+ function generateCorrelationId() {
3977
+ return `cfg-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
3978
+ }
3979
+ var init_config_reload_endpoint = __esm({
3980
+ "src/foundry/signals/config-reload-endpoint.ts"() {
3981
+ }
3982
+ });
3983
+
3984
+ // src/appidentity/runtime.ts
3985
+ function detectRuntime() {
3986
+ const versions = process.versions;
3987
+ if (typeof versions.bun === "string" && versions.bun.length > 0) {
3988
+ return { name: "bun", version: versions.bun };
3989
+ }
3990
+ if (typeof versions.node === "string" && versions.node.length > 0) {
3991
+ return { name: "node", version: versions.node };
3992
+ }
3993
+ return { name: "unknown" };
3994
+ }
3995
+ function buildRuntimeInfo(options = {}) {
3996
+ const runtime = detectRuntime();
3997
+ const serviceName = options.serviceName ?? options.identity?.app.binary_name ?? "unknown-service";
3998
+ const vendor = options.vendor ?? options.identity?.app.vendor;
3999
+ return {
4000
+ service: {
4001
+ name: serviceName,
4002
+ vendor,
4003
+ version: options.version
4004
+ },
4005
+ runtime,
4006
+ platform: {
4007
+ os: process.platform,
4008
+ arch: process.arch
4009
+ }
4010
+ };
4011
+ }
4012
+ var init_runtime = __esm({
4013
+ "src/appidentity/runtime.ts"() {
4014
+ }
4015
+ });
4016
+
4017
+ // src/foundry/signals/control-discovery-endpoint.ts
4018
+ function createControlDiscoveryEndpoint(options) {
4019
+ const { identity, version, endpoints, auth, authSummary, logger, telemetry } = options;
4020
+ return async (req) => {
4021
+ if (auth) {
4022
+ const authResult = await auth(req);
4023
+ if (!authResult.authenticated) {
4024
+ if (logger) {
4025
+ logger.warn("Control discovery endpoint: authentication failed", {
4026
+ reason: authResult.reason
4027
+ });
4028
+ }
4029
+ if (telemetry) {
4030
+ telemetry.emit("fulmen.control.discovery.auth_failed", {
4031
+ service: identity.app.binary_name
4032
+ });
4033
+ }
4034
+ return {
4035
+ status: "error",
4036
+ error: "authentication_failed",
4037
+ message: authResult.reason || "Authentication required",
4038
+ statusCode: 401
4039
+ };
4040
+ }
4041
+ }
4042
+ if (telemetry) {
4043
+ telemetry.emit("fulmen.control.discovery.served", {
4044
+ service: identity.app.binary_name
4045
+ });
4046
+ }
4047
+ const runtime = buildRuntimeInfo({ identity, version });
4048
+ return {
4049
+ status: "ok",
4050
+ service: {
4051
+ name: identity.app.binary_name,
4052
+ vendor: identity.app.vendor,
4053
+ version
4054
+ },
4055
+ runtime: {
4056
+ name: runtime.runtime.name,
4057
+ version: runtime.runtime.version,
4058
+ platform: runtime.platform.os,
4059
+ arch: runtime.platform.arch
4060
+ },
4061
+ auth_summary: authSummary,
4062
+ endpoints,
4063
+ statusCode: 200
4064
+ };
4065
+ };
4066
+ }
4067
+ var init_control_discovery_endpoint = __esm({
4068
+ "src/foundry/signals/control-discovery-endpoint.ts"() {
4069
+ init_runtime();
4070
+ }
4071
+ });
4072
+
3770
4073
  // src/foundry/signals/convenience.ts
3771
4074
  async function onShutdown(manager, handler, options = {}) {
3772
4075
  await manager.register("SIGTERM", handler, options);
@@ -4026,7 +4329,7 @@ var init_guards = __esm({
4026
4329
  function createSignalEndpoint(options) {
4027
4330
  const { manager, auth, rateLimit, logger, telemetry, allowedSignals } = options;
4028
4331
  return async (payload, req) => {
4029
- const correlationId = payload.correlation_id ?? generateCorrelationId();
4332
+ const correlationId = payload.correlation_id ?? generateCorrelationId2();
4030
4333
  const authResult = await auth(req);
4031
4334
  if (!authResult.authenticated) {
4032
4335
  if (logger) {
@@ -4149,7 +4452,7 @@ function normalizeSignalName(signal) {
4149
4452
  }
4150
4453
  return `SIG${upper}`;
4151
4454
  }
4152
- function generateCorrelationId() {
4455
+ function generateCorrelationId2() {
4153
4456
  return `sig-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
4154
4457
  }
4155
4458
  function createBearerTokenAuth(expectedToken) {
@@ -4616,6 +4919,8 @@ var init_signals = __esm({
4616
4919
  "src/foundry/signals/index.ts"() {
4617
4920
  init_capabilities2();
4618
4921
  init_catalog();
4922
+ init_config_reload_endpoint();
4923
+ init_control_discovery_endpoint();
4619
4924
  init_convenience();
4620
4925
  init_double_tap();
4621
4926
  init_guards();
@@ -4761,7 +5066,9 @@ __export(foundry_exports, {
4761
5066
  clearMimeTypeCache: () => clearMimeTypeCache,
4762
5067
  clearPatternCache: () => clearPatternCache,
4763
5068
  createBearerTokenAuth: () => createBearerTokenAuth,
5069
+ createConfigReloadEndpoint: () => createConfigReloadEndpoint,
4764
5070
  createConfigReloadHandler: () => createConfigReloadHandler,
5071
+ createControlDiscoveryEndpoint: () => createControlDiscoveryEndpoint,
4765
5072
  createDoubleTapTracker: () => createDoubleTapTracker,
4766
5073
  createSignalEndpoint: () => createSignalEndpoint,
4767
5074
  createSignalManager: () => createSignalManager,
@@ -5818,6 +6125,7 @@ var init_cli = __esm({
5818
6125
  var VERSION2;
5819
6126
  var init_schema = __esm({
5820
6127
  "src/schema/index.ts"() {
6128
+ init_ajv_formats();
5821
6129
  init_cli();
5822
6130
  init_errors();
5823
6131
  init_export();
@@ -5831,6 +6139,6 @@ var init_schema = __esm({
5831
6139
  });
5832
6140
  init_schema();
5833
6141
 
5834
- export { ExportErrorReason, SchemaExportError, SchemaRegistry, SchemaValidationError, VERSION2 as VERSION, clearCache, compareSchemas, compileSchema, compileSchemaById, countDiagnostics, createCLI, createDiagnostic, detectGoneat, exportSchema, formatDiagnostics, formatValidationResult, getCacheSize, getSchema, getSchemaByPath, getSchemaRegistry, groupDiagnosticsBySeverity, hasSchema, isGoneatAvailable, isValidationError, listSchemas, normalizePointer, normalizeSchema, runGoneatValidation, stripProvenance, validateData, validateDataBySchemaId, validateFile, validateFileBySchemaId, validateSchema };
6142
+ export { ExportErrorReason, SchemaExportError, SchemaRegistry, SchemaValidationError, VERSION2 as VERSION, applyFulmenAjvFormats, clearCache, compareSchemas, compileSchema, compileSchemaById, countDiagnostics, createCLI, createDiagnostic, detectGoneat, exportSchema, formatDiagnostics, formatValidationResult, getCacheSize, getSchema, getSchemaByPath, getSchemaRegistry, groupDiagnosticsBySeverity, hasSchema, isGoneatAvailable, isValidationError, listSchemas, normalizePointer, normalizeSchema, runGoneatValidation, stripProvenance, validateData, validateDataBySchemaId, validateFile, validateFileBySchemaId, validateSchema };
5835
6143
  //# sourceMappingURL=index.js.map
5836
6144
  //# sourceMappingURL=index.js.map