@fulmenhq/tsfulmen 0.2.2 → 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.
@@ -1,6 +1,7 @@
1
1
  import { readFile, access, mkdir, writeFile } from 'fs/promises';
2
2
  import { dirname, extname, join, relative } from 'path';
3
3
  import { parse, stringify } from 'yaml';
4
+ import addFormats from 'ajv-formats';
4
5
  import { spawn } from 'child_process';
5
6
  import { fileURLToPath } from 'url';
6
7
  import glob from 'fast-glob';
@@ -8,7 +9,6 @@ import Ajv from 'ajv';
8
9
  import Ajv2019 from 'ajv/dist/2019';
9
10
  import Ajv2020 from 'ajv/dist/2020';
10
11
  import AjvDraft04 from 'ajv-draft-04';
11
- import addFormats from 'ajv-formats';
12
12
  import { Readable } from 'stream';
13
13
  import picomatch from 'picomatch';
14
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';
@@ -801,6 +801,27 @@ var init_types = __esm({
801
801
  "src/telemetry/types.ts"() {
802
802
  }
803
803
  });
804
+ function applyFulmenAjvFormats(ajv, options = {}) {
805
+ const mode = options.mode ?? "fast";
806
+ const formats = options.formats ?? DEFAULT_FORMATS;
807
+ addFormats(ajv, { mode, formats });
808
+ return ajv;
809
+ }
810
+ var DEFAULT_FORMATS;
811
+ var init_ajv_formats = __esm({
812
+ "src/schema/ajv-formats.ts"() {
813
+ DEFAULT_FORMATS = [
814
+ "date-time",
815
+ "email",
816
+ "hostname",
817
+ "ipv4",
818
+ "ipv6",
819
+ "uri",
820
+ "uri-reference",
821
+ "uuid"
822
+ ];
823
+ }
824
+ });
804
825
 
805
826
  // src/schema/errors.ts
806
827
  var errors_exports = {};
@@ -1628,10 +1649,7 @@ function createAjv(dialect) {
1628
1649
  // Enable async schema loading for YAML references
1629
1650
  loadSchema: loadReferencedSchema
1630
1651
  });
1631
- addFormats(ajv, {
1632
- mode: "fast",
1633
- formats: ["date-time", "email", "hostname", "ipv4", "ipv6", "uri", "uri-reference"]
1634
- });
1652
+ applyFulmenAjvFormats(ajv);
1635
1653
  return ajv;
1636
1654
  }
1637
1655
  async function getAjv(dialect) {
@@ -1877,6 +1895,7 @@ var ajvInstances, metaschemaReady, schemaCache;
1877
1895
  var init_validator = __esm({
1878
1896
  "src/schema/validator.ts"() {
1879
1897
  init_telemetry();
1898
+ init_ajv_formats();
1880
1899
  init_errors();
1881
1900
  init_registry2();
1882
1901
  init_utils();
@@ -3836,6 +3855,224 @@ var init_capabilities2 = __esm({
3836
3855
  }
3837
3856
  });
3838
3857
 
3858
+ // src/foundry/signals/config-reload-endpoint.ts
3859
+ function createConfigReloadEndpoint(options) {
3860
+ const { loader, validator, onReload: onReload2, auth, rateLimit, logger, telemetry } = options;
3861
+ return async (payload, req) => {
3862
+ const correlationId = payload.correlation_id ?? generateCorrelationId();
3863
+ const authResult = await auth(req);
3864
+ if (!authResult.authenticated) {
3865
+ if (logger) {
3866
+ logger.warn("Config reload endpoint: authentication failed", {
3867
+ correlation_id: correlationId,
3868
+ reason: authResult.reason
3869
+ });
3870
+ }
3871
+ if (telemetry) {
3872
+ telemetry.emit("fulmen.config.http_endpoint.auth_failed", {
3873
+ correlation_id: correlationId
3874
+ });
3875
+ }
3876
+ return {
3877
+ status: "error",
3878
+ error: "authentication_failed",
3879
+ message: authResult.reason || "Authentication required",
3880
+ statusCode: 401
3881
+ };
3882
+ }
3883
+ const identity = authResult.identity || "unknown";
3884
+ if (rateLimit) {
3885
+ const rateLimitResult = await rateLimit(identity);
3886
+ if (!rateLimitResult.allowed) {
3887
+ if (logger) {
3888
+ logger.warn("Config reload endpoint: rate limit exceeded", {
3889
+ correlation_id: correlationId,
3890
+ identity
3891
+ });
3892
+ }
3893
+ if (telemetry) {
3894
+ telemetry.emit("fulmen.config.http_endpoint.rate_limited", {
3895
+ correlation_id: correlationId
3896
+ });
3897
+ }
3898
+ return {
3899
+ status: "error",
3900
+ error: "rate_limit_exceeded",
3901
+ message: "Rate limit exceeded. Please try again later.",
3902
+ statusCode: 429
3903
+ };
3904
+ }
3905
+ }
3906
+ if (telemetry) {
3907
+ telemetry.emit("fulmen.config.http_endpoint.reload_requested", {
3908
+ correlation_id: correlationId
3909
+ });
3910
+ }
3911
+ try {
3912
+ const config = await loader();
3913
+ if (validator) {
3914
+ const validation = await validator(config);
3915
+ if (!validation.valid) {
3916
+ if (logger) {
3917
+ logger.warn("Config reload endpoint: validation failed", {
3918
+ correlation_id: correlationId,
3919
+ error_count: validation.errors?.length ?? 0
3920
+ });
3921
+ }
3922
+ if (telemetry) {
3923
+ telemetry.emit("fulmen.config.http_endpoint.reload_rejected", {
3924
+ correlation_id: correlationId,
3925
+ reason: "validation_failed"
3926
+ });
3927
+ }
3928
+ return {
3929
+ status: "error",
3930
+ error: "validation_failed",
3931
+ message: "Configuration validation failed",
3932
+ validation_errors: validation.errors,
3933
+ statusCode: 422
3934
+ };
3935
+ }
3936
+ }
3937
+ if (onReload2) {
3938
+ await onReload2(config);
3939
+ }
3940
+ if (telemetry) {
3941
+ telemetry.emit("fulmen.config.http_endpoint.reload_accepted", {
3942
+ correlation_id: correlationId
3943
+ });
3944
+ }
3945
+ if (logger) {
3946
+ logger.info("Config reload endpoint: reload accepted", {
3947
+ correlation_id: correlationId,
3948
+ reason: payload.reason
3949
+ });
3950
+ }
3951
+ return {
3952
+ status: "reloaded",
3953
+ correlation_id: correlationId,
3954
+ message: "Configuration reloaded",
3955
+ statusCode: 200
3956
+ };
3957
+ } catch (error) {
3958
+ if (logger) {
3959
+ logger.warn("Config reload endpoint: reload failed", {
3960
+ correlation_id: correlationId,
3961
+ error: error instanceof Error ? error.message : String(error)
3962
+ });
3963
+ }
3964
+ if (telemetry) {
3965
+ telemetry.emit("fulmen.config.http_endpoint.reload_error", {
3966
+ correlation_id: correlationId,
3967
+ error_type: error instanceof Error ? error.constructor.name : "unknown"
3968
+ });
3969
+ }
3970
+ return {
3971
+ status: "error",
3972
+ error: "reload_failed",
3973
+ message: error instanceof Error ? error.message : String(error),
3974
+ statusCode: 500
3975
+ };
3976
+ }
3977
+ };
3978
+ }
3979
+ function generateCorrelationId() {
3980
+ return `cfg-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
3981
+ }
3982
+ var init_config_reload_endpoint = __esm({
3983
+ "src/foundry/signals/config-reload-endpoint.ts"() {
3984
+ }
3985
+ });
3986
+
3987
+ // src/appidentity/runtime.ts
3988
+ function detectRuntime() {
3989
+ const versions = process.versions;
3990
+ if (typeof versions.bun === "string" && versions.bun.length > 0) {
3991
+ return { name: "bun", version: versions.bun };
3992
+ }
3993
+ if (typeof versions.node === "string" && versions.node.length > 0) {
3994
+ return { name: "node", version: versions.node };
3995
+ }
3996
+ return { name: "unknown" };
3997
+ }
3998
+ function buildRuntimeInfo(options = {}) {
3999
+ const runtime = detectRuntime();
4000
+ const serviceName = options.serviceName ?? options.identity?.app.binary_name ?? "unknown-service";
4001
+ const vendor = options.vendor ?? options.identity?.app.vendor;
4002
+ return {
4003
+ service: {
4004
+ name: serviceName,
4005
+ vendor,
4006
+ version: options.version
4007
+ },
4008
+ runtime,
4009
+ platform: {
4010
+ os: process.platform,
4011
+ arch: process.arch
4012
+ }
4013
+ };
4014
+ }
4015
+ var init_runtime = __esm({
4016
+ "src/appidentity/runtime.ts"() {
4017
+ }
4018
+ });
4019
+
4020
+ // src/foundry/signals/control-discovery-endpoint.ts
4021
+ function createControlDiscoveryEndpoint(options) {
4022
+ const { identity, version, endpoints, auth, authSummary, logger, telemetry } = options;
4023
+ return async (req) => {
4024
+ if (auth) {
4025
+ const authResult = await auth(req);
4026
+ if (!authResult.authenticated) {
4027
+ if (logger) {
4028
+ logger.warn("Control discovery endpoint: authentication failed", {
4029
+ reason: authResult.reason
4030
+ });
4031
+ }
4032
+ if (telemetry) {
4033
+ telemetry.emit("fulmen.control.discovery.auth_failed", {
4034
+ service: identity.app.binary_name
4035
+ });
4036
+ }
4037
+ return {
4038
+ status: "error",
4039
+ error: "authentication_failed",
4040
+ message: authResult.reason || "Authentication required",
4041
+ statusCode: 401
4042
+ };
4043
+ }
4044
+ }
4045
+ if (telemetry) {
4046
+ telemetry.emit("fulmen.control.discovery.served", {
4047
+ service: identity.app.binary_name
4048
+ });
4049
+ }
4050
+ const runtime = buildRuntimeInfo({ identity, version });
4051
+ return {
4052
+ status: "ok",
4053
+ service: {
4054
+ name: identity.app.binary_name,
4055
+ vendor: identity.app.vendor,
4056
+ version
4057
+ },
4058
+ runtime: {
4059
+ name: runtime.runtime.name,
4060
+ version: runtime.runtime.version,
4061
+ platform: runtime.platform.os,
4062
+ arch: runtime.platform.arch
4063
+ },
4064
+ auth_summary: authSummary,
4065
+ endpoints,
4066
+ statusCode: 200
4067
+ };
4068
+ };
4069
+ }
4070
+ var init_control_discovery_endpoint = __esm({
4071
+ "src/foundry/signals/control-discovery-endpoint.ts"() {
4072
+ init_runtime();
4073
+ }
4074
+ });
4075
+
3839
4076
  // src/foundry/signals/convenience.ts
3840
4077
  async function onShutdown(manager, handler, options = {}) {
3841
4078
  await manager.register("SIGTERM", handler, options);
@@ -4095,7 +4332,7 @@ var init_guards = __esm({
4095
4332
  function createSignalEndpoint(options) {
4096
4333
  const { manager, auth, rateLimit, logger, telemetry, allowedSignals } = options;
4097
4334
  return async (payload, req) => {
4098
- const correlationId = payload.correlation_id ?? generateCorrelationId();
4335
+ const correlationId = payload.correlation_id ?? generateCorrelationId2();
4099
4336
  const authResult = await auth(req);
4100
4337
  if (!authResult.authenticated) {
4101
4338
  if (logger) {
@@ -4218,7 +4455,7 @@ function normalizeSignalName(signal) {
4218
4455
  }
4219
4456
  return `SIG${upper}`;
4220
4457
  }
4221
- function generateCorrelationId() {
4458
+ function generateCorrelationId2() {
4222
4459
  return `sig-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
4223
4460
  }
4224
4461
  function createBearerTokenAuth(expectedToken) {
@@ -4685,6 +4922,8 @@ var init_signals = __esm({
4685
4922
  "src/foundry/signals/index.ts"() {
4686
4923
  init_capabilities2();
4687
4924
  init_catalog();
4925
+ init_config_reload_endpoint();
4926
+ init_control_discovery_endpoint();
4688
4927
  init_convenience();
4689
4928
  init_double_tap();
4690
4929
  init_guards();
@@ -4830,7 +5069,9 @@ __export(foundry_exports, {
4830
5069
  clearMimeTypeCache: () => clearMimeTypeCache,
4831
5070
  clearPatternCache: () => clearPatternCache,
4832
5071
  createBearerTokenAuth: () => createBearerTokenAuth,
5072
+ createConfigReloadEndpoint: () => createConfigReloadEndpoint,
4833
5073
  createConfigReloadHandler: () => createConfigReloadHandler,
5074
+ createControlDiscoveryEndpoint: () => createControlDiscoveryEndpoint,
4834
5075
  createDoubleTapTracker: () => createDoubleTapTracker,
4835
5076
  createSignalEndpoint: () => createSignalEndpoint,
4836
5077
  createSignalManager: () => createSignalManager,
@@ -5886,6 +6127,7 @@ var init_cli = __esm({
5886
6127
  // src/schema/index.ts
5887
6128
  var init_schema = __esm({
5888
6129
  "src/schema/index.ts"() {
6130
+ init_ajv_formats();
5889
6131
  init_cli();
5890
6132
  init_errors();
5891
6133
  init_export();