@fulmenhq/tsfulmen 0.2.2 → 0.2.4

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, readdir, stat } from 'fs/promises';
2
2
  import { dirname, join, extname, relative } from 'path';
3
3
  import { parse, stringify, parseDocument } 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';
@@ -730,6 +730,27 @@ var init_types = __esm({
730
730
  "src/telemetry/types.ts"() {
731
731
  }
732
732
  });
733
+ function applyFulmenAjvFormats(ajv, options = {}) {
734
+ const mode = options.mode ?? "fast";
735
+ const formats = options.formats ?? DEFAULT_FORMATS;
736
+ addFormats(ajv, { mode, formats });
737
+ return ajv;
738
+ }
739
+ var DEFAULT_FORMATS;
740
+ var init_ajv_formats = __esm({
741
+ "src/schema/ajv-formats.ts"() {
742
+ DEFAULT_FORMATS = [
743
+ "date-time",
744
+ "email",
745
+ "hostname",
746
+ "ipv4",
747
+ "ipv6",
748
+ "uri",
749
+ "uri-reference",
750
+ "uuid"
751
+ ];
752
+ }
753
+ });
733
754
 
734
755
  // src/schema/errors.ts
735
756
  var errors_exports = {};
@@ -1557,10 +1578,7 @@ function createAjv(dialect) {
1557
1578
  // Enable async schema loading for YAML references
1558
1579
  loadSchema: loadReferencedSchema
1559
1580
  });
1560
- addFormats(ajv, {
1561
- mode: "fast",
1562
- formats: ["date-time", "email", "hostname", "ipv4", "ipv6", "uri", "uri-reference"]
1563
- });
1581
+ applyFulmenAjvFormats(ajv);
1564
1582
  return ajv;
1565
1583
  }
1566
1584
  async function getAjv(dialect) {
@@ -1806,6 +1824,7 @@ var ajvInstances, metaschemaReady, schemaCache;
1806
1824
  var init_validator = __esm({
1807
1825
  "src/schema/validator.ts"() {
1808
1826
  init_telemetry();
1827
+ init_ajv_formats();
1809
1828
  init_errors();
1810
1829
  init_registry2();
1811
1830
  init_utils();
@@ -3765,6 +3784,224 @@ var init_capabilities2 = __esm({
3765
3784
  }
3766
3785
  });
3767
3786
 
3787
+ // src/foundry/signals/config-reload-endpoint.ts
3788
+ function createConfigReloadEndpoint(options) {
3789
+ const { loader, validator, onReload: onReload2, auth, rateLimit, logger, telemetry } = options;
3790
+ return async (payload, req) => {
3791
+ const correlationId = payload.correlation_id ?? generateCorrelationId();
3792
+ const authResult = await auth(req);
3793
+ if (!authResult.authenticated) {
3794
+ if (logger) {
3795
+ logger.warn("Config reload endpoint: authentication failed", {
3796
+ correlation_id: correlationId,
3797
+ reason: authResult.reason
3798
+ });
3799
+ }
3800
+ if (telemetry) {
3801
+ telemetry.emit("fulmen.config.http_endpoint.auth_failed", {
3802
+ correlation_id: correlationId
3803
+ });
3804
+ }
3805
+ return {
3806
+ status: "error",
3807
+ error: "authentication_failed",
3808
+ message: authResult.reason || "Authentication required",
3809
+ statusCode: 401
3810
+ };
3811
+ }
3812
+ const identity = authResult.identity || "unknown";
3813
+ if (rateLimit) {
3814
+ const rateLimitResult = await rateLimit(identity);
3815
+ if (!rateLimitResult.allowed) {
3816
+ if (logger) {
3817
+ logger.warn("Config reload endpoint: rate limit exceeded", {
3818
+ correlation_id: correlationId,
3819
+ identity
3820
+ });
3821
+ }
3822
+ if (telemetry) {
3823
+ telemetry.emit("fulmen.config.http_endpoint.rate_limited", {
3824
+ correlation_id: correlationId
3825
+ });
3826
+ }
3827
+ return {
3828
+ status: "error",
3829
+ error: "rate_limit_exceeded",
3830
+ message: "Rate limit exceeded. Please try again later.",
3831
+ statusCode: 429
3832
+ };
3833
+ }
3834
+ }
3835
+ if (telemetry) {
3836
+ telemetry.emit("fulmen.config.http_endpoint.reload_requested", {
3837
+ correlation_id: correlationId
3838
+ });
3839
+ }
3840
+ try {
3841
+ const config = await loader();
3842
+ if (validator) {
3843
+ const validation = await validator(config);
3844
+ if (!validation.valid) {
3845
+ if (logger) {
3846
+ logger.warn("Config reload endpoint: validation failed", {
3847
+ correlation_id: correlationId,
3848
+ error_count: validation.errors?.length ?? 0
3849
+ });
3850
+ }
3851
+ if (telemetry) {
3852
+ telemetry.emit("fulmen.config.http_endpoint.reload_rejected", {
3853
+ correlation_id: correlationId,
3854
+ reason: "validation_failed"
3855
+ });
3856
+ }
3857
+ return {
3858
+ status: "error",
3859
+ error: "validation_failed",
3860
+ message: "Configuration validation failed",
3861
+ validation_errors: validation.errors,
3862
+ statusCode: 422
3863
+ };
3864
+ }
3865
+ }
3866
+ if (onReload2) {
3867
+ await onReload2(config);
3868
+ }
3869
+ if (telemetry) {
3870
+ telemetry.emit("fulmen.config.http_endpoint.reload_accepted", {
3871
+ correlation_id: correlationId
3872
+ });
3873
+ }
3874
+ if (logger) {
3875
+ logger.info("Config reload endpoint: reload accepted", {
3876
+ correlation_id: correlationId,
3877
+ reason: payload.reason
3878
+ });
3879
+ }
3880
+ return {
3881
+ status: "reloaded",
3882
+ correlation_id: correlationId,
3883
+ message: "Configuration reloaded",
3884
+ statusCode: 200
3885
+ };
3886
+ } catch (error) {
3887
+ if (logger) {
3888
+ logger.warn("Config reload endpoint: reload failed", {
3889
+ correlation_id: correlationId,
3890
+ error: error instanceof Error ? error.message : String(error)
3891
+ });
3892
+ }
3893
+ if (telemetry) {
3894
+ telemetry.emit("fulmen.config.http_endpoint.reload_error", {
3895
+ correlation_id: correlationId,
3896
+ error_type: error instanceof Error ? error.constructor.name : "unknown"
3897
+ });
3898
+ }
3899
+ return {
3900
+ status: "error",
3901
+ error: "reload_failed",
3902
+ message: error instanceof Error ? error.message : String(error),
3903
+ statusCode: 500
3904
+ };
3905
+ }
3906
+ };
3907
+ }
3908
+ function generateCorrelationId() {
3909
+ return `cfg-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
3910
+ }
3911
+ var init_config_reload_endpoint = __esm({
3912
+ "src/foundry/signals/config-reload-endpoint.ts"() {
3913
+ }
3914
+ });
3915
+
3916
+ // src/appidentity/runtime.ts
3917
+ function detectRuntime() {
3918
+ const versions = process.versions;
3919
+ if (typeof versions.bun === "string" && versions.bun.length > 0) {
3920
+ return { name: "bun", version: versions.bun };
3921
+ }
3922
+ if (typeof versions.node === "string" && versions.node.length > 0) {
3923
+ return { name: "node", version: versions.node };
3924
+ }
3925
+ return { name: "unknown" };
3926
+ }
3927
+ function buildRuntimeInfo(options = {}) {
3928
+ const runtime = detectRuntime();
3929
+ const serviceName = options.serviceName ?? options.identity?.app.binary_name ?? "unknown-service";
3930
+ const vendor = options.vendor ?? options.identity?.app.vendor;
3931
+ return {
3932
+ service: {
3933
+ name: serviceName,
3934
+ vendor,
3935
+ version: options.version
3936
+ },
3937
+ runtime,
3938
+ platform: {
3939
+ os: process.platform,
3940
+ arch: process.arch
3941
+ }
3942
+ };
3943
+ }
3944
+ var init_runtime = __esm({
3945
+ "src/appidentity/runtime.ts"() {
3946
+ }
3947
+ });
3948
+
3949
+ // src/foundry/signals/control-discovery-endpoint.ts
3950
+ function createControlDiscoveryEndpoint(options) {
3951
+ const { identity, version, endpoints, auth, authSummary, logger, telemetry } = options;
3952
+ return async (req) => {
3953
+ if (auth) {
3954
+ const authResult = await auth(req);
3955
+ if (!authResult.authenticated) {
3956
+ if (logger) {
3957
+ logger.warn("Control discovery endpoint: authentication failed", {
3958
+ reason: authResult.reason
3959
+ });
3960
+ }
3961
+ if (telemetry) {
3962
+ telemetry.emit("fulmen.control.discovery.auth_failed", {
3963
+ service: identity.app.binary_name
3964
+ });
3965
+ }
3966
+ return {
3967
+ status: "error",
3968
+ error: "authentication_failed",
3969
+ message: authResult.reason || "Authentication required",
3970
+ statusCode: 401
3971
+ };
3972
+ }
3973
+ }
3974
+ if (telemetry) {
3975
+ telemetry.emit("fulmen.control.discovery.served", {
3976
+ service: identity.app.binary_name
3977
+ });
3978
+ }
3979
+ const runtime = buildRuntimeInfo({ identity, version });
3980
+ return {
3981
+ status: "ok",
3982
+ service: {
3983
+ name: identity.app.binary_name,
3984
+ vendor: identity.app.vendor,
3985
+ version
3986
+ },
3987
+ runtime: {
3988
+ name: runtime.runtime.name,
3989
+ version: runtime.runtime.version,
3990
+ platform: runtime.platform.os,
3991
+ arch: runtime.platform.arch
3992
+ },
3993
+ auth_summary: authSummary,
3994
+ endpoints,
3995
+ statusCode: 200
3996
+ };
3997
+ };
3998
+ }
3999
+ var init_control_discovery_endpoint = __esm({
4000
+ "src/foundry/signals/control-discovery-endpoint.ts"() {
4001
+ init_runtime();
4002
+ }
4003
+ });
4004
+
3768
4005
  // src/foundry/signals/convenience.ts
3769
4006
  async function onShutdown(manager, handler, options = {}) {
3770
4007
  await manager.register("SIGTERM", handler, options);
@@ -4024,7 +4261,7 @@ var init_guards = __esm({
4024
4261
  function createSignalEndpoint(options) {
4025
4262
  const { manager, auth, rateLimit, logger, telemetry, allowedSignals } = options;
4026
4263
  return async (payload, req) => {
4027
- const correlationId = payload.correlation_id ?? generateCorrelationId();
4264
+ const correlationId = payload.correlation_id ?? generateCorrelationId2();
4028
4265
  const authResult = await auth(req);
4029
4266
  if (!authResult.authenticated) {
4030
4267
  if (logger) {
@@ -4147,7 +4384,7 @@ function normalizeSignalName(signal) {
4147
4384
  }
4148
4385
  return `SIG${upper}`;
4149
4386
  }
4150
- function generateCorrelationId() {
4387
+ function generateCorrelationId2() {
4151
4388
  return `sig-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
4152
4389
  }
4153
4390
  function createBearerTokenAuth(expectedToken) {
@@ -4614,6 +4851,8 @@ var init_signals = __esm({
4614
4851
  "src/foundry/signals/index.ts"() {
4615
4852
  init_capabilities2();
4616
4853
  init_catalog();
4854
+ init_config_reload_endpoint();
4855
+ init_control_discovery_endpoint();
4617
4856
  init_convenience();
4618
4857
  init_double_tap();
4619
4858
  init_guards();
@@ -4759,7 +4998,9 @@ __export(foundry_exports, {
4759
4998
  clearMimeTypeCache: () => clearMimeTypeCache,
4760
4999
  clearPatternCache: () => clearPatternCache,
4761
5000
  createBearerTokenAuth: () => createBearerTokenAuth,
5001
+ createConfigReloadEndpoint: () => createConfigReloadEndpoint,
4762
5002
  createConfigReloadHandler: () => createConfigReloadHandler,
5003
+ createControlDiscoveryEndpoint: () => createControlDiscoveryEndpoint,
4763
5004
  createDoubleTapTracker: () => createDoubleTapTracker,
4764
5005
  createSignalEndpoint: () => createSignalEndpoint,
4765
5006
  createSignalManager: () => createSignalManager,
@@ -5815,6 +6056,7 @@ var init_cli = __esm({
5815
6056
  // src/schema/index.ts
5816
6057
  var init_schema = __esm({
5817
6058
  "src/schema/index.ts"() {
6059
+ init_ajv_formats();
5818
6060
  init_cli();
5819
6061
  init_errors();
5820
6062
  init_export();