@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,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';
@@ -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';
@@ -24,6 +24,27 @@ var __export = (target, all) => {
24
24
  for (var name in all)
25
25
  __defProp(target, name, { get: all[name], enumerable: true });
26
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
+ });
27
48
 
28
49
  // src/schema/errors.ts
29
50
  var errors_exports = {};
@@ -1625,10 +1646,7 @@ function createAjv(dialect) {
1625
1646
  // Enable async schema loading for YAML references
1626
1647
  loadSchema: loadReferencedSchema
1627
1648
  });
1628
- addFormats(ajv, {
1629
- mode: "fast",
1630
- formats: ["date-time", "email", "hostname", "ipv4", "ipv6", "uri", "uri-reference"]
1631
- });
1649
+ applyFulmenAjvFormats(ajv);
1632
1650
  return ajv;
1633
1651
  }
1634
1652
  async function getAjv(dialect) {
@@ -1874,6 +1892,7 @@ var ajvInstances, metaschemaReady, schemaCache;
1874
1892
  var init_validator = __esm({
1875
1893
  "src/schema/validator.ts"() {
1876
1894
  init_telemetry();
1895
+ init_ajv_formats();
1877
1896
  init_errors();
1878
1897
  init_registry();
1879
1898
  init_utils();
@@ -3833,6 +3852,224 @@ var init_capabilities2 = __esm({
3833
3852
  }
3834
3853
  });
3835
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
+
3836
4073
  // src/foundry/signals/convenience.ts
3837
4074
  async function onShutdown(manager, handler, options = {}) {
3838
4075
  await manager.register("SIGTERM", handler, options);
@@ -4092,7 +4329,7 @@ var init_guards = __esm({
4092
4329
  function createSignalEndpoint(options) {
4093
4330
  const { manager, auth, rateLimit, logger, telemetry, allowedSignals } = options;
4094
4331
  return async (payload, req) => {
4095
- const correlationId = payload.correlation_id ?? generateCorrelationId();
4332
+ const correlationId = payload.correlation_id ?? generateCorrelationId2();
4096
4333
  const authResult = await auth(req);
4097
4334
  if (!authResult.authenticated) {
4098
4335
  if (logger) {
@@ -4215,7 +4452,7 @@ function normalizeSignalName(signal) {
4215
4452
  }
4216
4453
  return `SIG${upper}`;
4217
4454
  }
4218
- function generateCorrelationId() {
4455
+ function generateCorrelationId2() {
4219
4456
  return `sig-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
4220
4457
  }
4221
4458
  function createBearerTokenAuth(expectedToken) {
@@ -4682,6 +4919,8 @@ var init_signals = __esm({
4682
4919
  "src/foundry/signals/index.ts"() {
4683
4920
  init_capabilities2();
4684
4921
  init_catalog();
4922
+ init_config_reload_endpoint();
4923
+ init_control_discovery_endpoint();
4685
4924
  init_convenience();
4686
4925
  init_double_tap();
4687
4926
  init_guards();
@@ -4827,7 +5066,9 @@ __export(foundry_exports, {
4827
5066
  clearMimeTypeCache: () => clearMimeTypeCache,
4828
5067
  clearPatternCache: () => clearPatternCache,
4829
5068
  createBearerTokenAuth: () => createBearerTokenAuth,
5069
+ createConfigReloadEndpoint: () => createConfigReloadEndpoint,
4830
5070
  createConfigReloadHandler: () => createConfigReloadHandler,
5071
+ createControlDiscoveryEndpoint: () => createControlDiscoveryEndpoint,
4831
5072
  createDoubleTapTracker: () => createDoubleTapTracker,
4832
5073
  createSignalEndpoint: () => createSignalEndpoint,
4833
5074
  createSignalManager: () => createSignalManager,
@@ -5884,6 +6125,7 @@ var init_cli = __esm({
5884
6125
  var VERSION2;
5885
6126
  var init_schema = __esm({
5886
6127
  "src/schema/index.ts"() {
6128
+ init_ajv_formats();
5887
6129
  init_cli();
5888
6130
  init_errors();
5889
6131
  init_export();
@@ -5897,6 +6139,6 @@ var init_schema = __esm({
5897
6139
  });
5898
6140
  init_schema();
5899
6141
 
5900
- 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 };
5901
6143
  //# sourceMappingURL=index.js.map
5902
6144
  //# sourceMappingURL=index.js.map