@arcote.tech/arc-cli 0.7.5 → 0.7.7

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/dist/index.js CHANGED
@@ -2754,17 +2754,15 @@ var init_strip_ansi = __esm(() => {
2754
2754
  regex = ansiRegex();
2755
2755
  });
2756
2756
 
2757
- // ../../node_modules/.bun/get-east-asian-width@1.5.0/node_modules/get-east-asian-width/lookup-data.js
2758
- var ambiguousRanges, fullwidthRanges, halfwidthRanges, narrowRanges, wideRanges;
2757
+ // ../../node_modules/.bun/get-east-asian-width@1.6.0/node_modules/get-east-asian-width/lookup-data.js
2758
+ var ambiguousMinimalCodePoint = 161, ambiguousMaximumCodePoint = 1114109, ambiguousRanges, fullwidthMinimalCodePoint = 12288, fullwidthMaximumCodePoint = 65510, fullwidthRanges, wideMinimalCodePoint = 4352, wideMaximumCodePoint = 262141, wideRanges;
2759
2759
  var init_lookup_data = __esm(() => {
2760
2760
  ambiguousRanges = [161, 161, 164, 164, 167, 168, 170, 170, 173, 174, 176, 180, 182, 186, 188, 191, 198, 198, 208, 208, 215, 216, 222, 225, 230, 230, 232, 234, 236, 237, 240, 240, 242, 243, 247, 250, 252, 252, 254, 254, 257, 257, 273, 273, 275, 275, 283, 283, 294, 295, 299, 299, 305, 307, 312, 312, 319, 322, 324, 324, 328, 331, 333, 333, 338, 339, 358, 359, 363, 363, 462, 462, 464, 464, 466, 466, 468, 468, 470, 470, 472, 472, 474, 474, 476, 476, 593, 593, 609, 609, 708, 708, 711, 711, 713, 715, 717, 717, 720, 720, 728, 731, 733, 733, 735, 735, 768, 879, 913, 929, 931, 937, 945, 961, 963, 969, 1025, 1025, 1040, 1103, 1105, 1105, 8208, 8208, 8211, 8214, 8216, 8217, 8220, 8221, 8224, 8226, 8228, 8231, 8240, 8240, 8242, 8243, 8245, 8245, 8251, 8251, 8254, 8254, 8308, 8308, 8319, 8319, 8321, 8324, 8364, 8364, 8451, 8451, 8453, 8453, 8457, 8457, 8467, 8467, 8470, 8470, 8481, 8482, 8486, 8486, 8491, 8491, 8531, 8532, 8539, 8542, 8544, 8555, 8560, 8569, 8585, 8585, 8592, 8601, 8632, 8633, 8658, 8658, 8660, 8660, 8679, 8679, 8704, 8704, 8706, 8707, 8711, 8712, 8715, 8715, 8719, 8719, 8721, 8721, 8725, 8725, 8730, 8730, 8733, 8736, 8739, 8739, 8741, 8741, 8743, 8748, 8750, 8750, 8756, 8759, 8764, 8765, 8776, 8776, 8780, 8780, 8786, 8786, 8800, 8801, 8804, 8807, 8810, 8811, 8814, 8815, 8834, 8835, 8838, 8839, 8853, 8853, 8857, 8857, 8869, 8869, 8895, 8895, 8978, 8978, 9312, 9449, 9451, 9547, 9552, 9587, 9600, 9615, 9618, 9621, 9632, 9633, 9635, 9641, 9650, 9651, 9654, 9655, 9660, 9661, 9664, 9665, 9670, 9672, 9675, 9675, 9678, 9681, 9698, 9701, 9711, 9711, 9733, 9734, 9737, 9737, 9742, 9743, 9756, 9756, 9758, 9758, 9792, 9792, 9794, 9794, 9824, 9825, 9827, 9829, 9831, 9834, 9836, 9837, 9839, 9839, 9886, 9887, 9919, 9919, 9926, 9933, 9935, 9939, 9941, 9953, 9955, 9955, 9960, 9961, 9963, 9969, 9972, 9972, 9974, 9977, 9979, 9980, 9982, 9983, 10045, 10045, 10102, 10111, 11094, 11097, 12872, 12879, 57344, 63743, 65024, 65039, 65533, 65533, 127232, 127242, 127248, 127277, 127280, 127337, 127344, 127373, 127375, 127376, 127387, 127404, 917760, 917999, 983040, 1048573, 1048576, 1114109];
2761
2761
  fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
2762
- halfwidthRanges = [8361, 8361, 65377, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65512, 65518];
2763
- narrowRanges = [32, 126, 162, 163, 165, 166, 172, 172, 175, 175, 10214, 10221, 10629, 10630];
2764
2762
  wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101589, 101631, 101662, 101760, 101874, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128728, 128732, 128735, 128747, 128748, 128756, 128764, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129674, 129678, 129734, 129736, 129736, 129741, 129756, 129759, 129770, 129775, 129784, 131072, 196605, 196608, 262141];
2765
2763
  });
2766
2764
 
2767
- // ../../node_modules/.bun/get-east-asian-width@1.5.0/node_modules/get-east-asian-width/utilities.js
2765
+ // ../../node_modules/.bun/get-east-asian-width@1.6.0/node_modules/get-east-asian-width/utilities.js
2768
2766
  var isInRange = (ranges, codePoint) => {
2769
2767
  let low = 0;
2770
2768
  let high = Math.floor(ranges.length / 2) - 1;
@@ -2782,7 +2780,7 @@ var isInRange = (ranges, codePoint) => {
2782
2780
  return false;
2783
2781
  };
2784
2782
 
2785
- // ../../node_modules/.bun/get-east-asian-width@1.5.0/node_modules/get-east-asian-width/lookup.js
2783
+ // ../../node_modules/.bun/get-east-asian-width@1.6.0/node_modules/get-east-asian-width/lookup.js
2786
2784
  function findWideFastPathRange(ranges) {
2787
2785
  let fastPathStart = ranges[0];
2788
2786
  let fastPathEnd = ranges[1];
@@ -2799,13 +2797,13 @@ function findWideFastPathRange(ranges) {
2799
2797
  }
2800
2798
  return [fastPathStart, fastPathEnd];
2801
2799
  }
2802
- var minimumAmbiguousCodePoint, maximumAmbiguousCodePoint, minimumFullWidthCodePoint, maximumFullWidthCodePoint, minimumHalfWidthCodePoint, maximumHalfWidthCodePoint, minimumNarrowCodePoint, maximumNarrowCodePoint, minimumWideCodePoint, maximumWideCodePoint, commonCjkCodePoint = 19968, wideFastPathStart, wideFastPathEnd, isAmbiguous = (codePoint) => {
2803
- if (codePoint < minimumAmbiguousCodePoint || codePoint > maximumAmbiguousCodePoint) {
2800
+ var commonCjkCodePoint = 19968, wideFastPathStart, wideFastPathEnd, isAmbiguous = (codePoint) => {
2801
+ if (codePoint < ambiguousMinimalCodePoint || codePoint > ambiguousMaximumCodePoint) {
2804
2802
  return false;
2805
2803
  }
2806
2804
  return isInRange(ambiguousRanges, codePoint);
2807
2805
  }, isFullWidth = (codePoint) => {
2808
- if (codePoint < minimumFullWidthCodePoint || codePoint > maximumFullWidthCodePoint) {
2806
+ if (codePoint < fullwidthMinimalCodePoint || codePoint > fullwidthMaximumCodePoint) {
2809
2807
  return false;
2810
2808
  }
2811
2809
  return isInRange(fullwidthRanges, codePoint);
@@ -2813,27 +2811,17 @@ var minimumAmbiguousCodePoint, maximumAmbiguousCodePoint, minimumFullWidthCodePo
2813
2811
  if (codePoint >= wideFastPathStart && codePoint <= wideFastPathEnd) {
2814
2812
  return true;
2815
2813
  }
2816
- if (codePoint < minimumWideCodePoint || codePoint > maximumWideCodePoint) {
2814
+ if (codePoint < wideMinimalCodePoint || codePoint > wideMaximumCodePoint) {
2817
2815
  return false;
2818
2816
  }
2819
2817
  return isInRange(wideRanges, codePoint);
2820
2818
  };
2821
2819
  var init_lookup = __esm(() => {
2822
2820
  init_lookup_data();
2823
- minimumAmbiguousCodePoint = ambiguousRanges[0];
2824
- maximumAmbiguousCodePoint = ambiguousRanges.at(-1);
2825
- minimumFullWidthCodePoint = fullwidthRanges[0];
2826
- maximumFullWidthCodePoint = fullwidthRanges.at(-1);
2827
- minimumHalfWidthCodePoint = halfwidthRanges[0];
2828
- maximumHalfWidthCodePoint = halfwidthRanges.at(-1);
2829
- minimumNarrowCodePoint = narrowRanges[0];
2830
- maximumNarrowCodePoint = narrowRanges.at(-1);
2831
- minimumWideCodePoint = wideRanges[0];
2832
- maximumWideCodePoint = wideRanges.at(-1);
2833
- [wideFastPathStart, wideFastPathEnd] = findWideFastPathRange(wideRanges);
2821
+ [wideFastPathStart, wideFastPathEnd] = /* @__PURE__ */ findWideFastPathRange(wideRanges);
2834
2822
  });
2835
2823
 
2836
- // ../../node_modules/.bun/get-east-asian-width@1.5.0/node_modules/get-east-asian-width/index.js
2824
+ // ../../node_modules/.bun/get-east-asian-width@1.6.0/node_modules/get-east-asian-width/index.js
2837
2825
  function validate(codePoint) {
2838
2826
  if (!Number.isSafeInteger(codePoint)) {
2839
2827
  throw new TypeError(`Expected a code point, got \`${typeof codePoint}\`.`);
@@ -3687,7 +3675,7 @@ var require_balanced_match = __commonJS((exports, module) => {
3687
3675
  }
3688
3676
  });
3689
3677
 
3690
- // ../../node_modules/.bun/brace-expansion@2.0.3/node_modules/brace-expansion/index.js
3678
+ // ../../node_modules/.bun/brace-expansion@2.1.0/node_modules/brace-expansion/index.js
3691
3679
  var require_brace_expansion = __commonJS((exports, module) => {
3692
3680
  var balanced = require_balanced_match();
3693
3681
  module.exports = expandTop;
@@ -3725,13 +3713,15 @@ var require_brace_expansion = __commonJS((exports, module) => {
3725
3713
  parts.push.apply(parts, p);
3726
3714
  return parts;
3727
3715
  }
3728
- function expandTop(str) {
3716
+ function expandTop(str, options) {
3729
3717
  if (!str)
3730
3718
  return [];
3719
+ options = options || {};
3720
+ var max = options.max == null ? Infinity : options.max;
3731
3721
  if (str.substr(0, 2) === "{}") {
3732
3722
  str = "\\{\\}" + str.substr(2);
3733
3723
  }
3734
- return expand(escapeBraces(str), true).map(unescapeBraces);
3724
+ return expand(escapeBraces(str), max, true).map(unescapeBraces);
3735
3725
  }
3736
3726
  function embrace(str) {
3737
3727
  return "{" + str + "}";
@@ -3745,15 +3735,15 @@ var require_brace_expansion = __commonJS((exports, module) => {
3745
3735
  function gte(i, y) {
3746
3736
  return i >= y;
3747
3737
  }
3748
- function expand(str, isTop) {
3738
+ function expand(str, max, isTop) {
3749
3739
  var expansions = [];
3750
3740
  var m = balanced("{", "}", str);
3751
3741
  if (!m)
3752
3742
  return [str];
3753
3743
  var pre = m.pre;
3754
- var post = m.post.length ? expand(m.post, false) : [""];
3744
+ var post = m.post.length ? expand(m.post, max, false) : [""];
3755
3745
  if (/\$$/.test(m.pre)) {
3756
- for (var k = 0;k < post.length; k++) {
3746
+ for (var k = 0;k < post.length && k < max; k++) {
3757
3747
  var expansion = pre + "{" + m.body + "}" + post[k];
3758
3748
  expansions.push(expansion);
3759
3749
  }
@@ -3765,7 +3755,7 @@ var require_brace_expansion = __commonJS((exports, module) => {
3765
3755
  if (!isSequence && !isOptions) {
3766
3756
  if (m.post.match(/,(?!,).*\}/)) {
3767
3757
  str = m.pre + "{" + m.body + escClose + m.post;
3768
- return expand(str);
3758
+ return expand(str, max, true);
3769
3759
  }
3770
3760
  return [str];
3771
3761
  }
@@ -3775,7 +3765,7 @@ var require_brace_expansion = __commonJS((exports, module) => {
3775
3765
  } else {
3776
3766
  n = parseCommaParts(m.body);
3777
3767
  if (n.length === 1) {
3778
- n = expand(n[0], false).map(embrace);
3768
+ n = expand(n[0], max, false).map(embrace);
3779
3769
  if (n.length === 1) {
3780
3770
  return post.map(function(p) {
3781
3771
  return m.pre + n[0] + p;
@@ -3821,11 +3811,11 @@ var require_brace_expansion = __commonJS((exports, module) => {
3821
3811
  } else {
3822
3812
  N = [];
3823
3813
  for (var j = 0;j < n.length; j++) {
3824
- N.push.apply(N, expand(n[j], false));
3814
+ N.push.apply(N, expand(n[j], max, false));
3825
3815
  }
3826
3816
  }
3827
3817
  for (var j = 0;j < N.length; j++) {
3828
- for (var k = 0;k < post.length; k++) {
3818
+ for (var k = 0;k < post.length && expansions.length < max; k++) {
3829
3819
  var expansion = pre + N[j] + post[k];
3830
3820
  if (!isTop || isSequence || expansion)
3831
3821
  expansions.push(expansion);
@@ -10327,7 +10317,7 @@ var require_timespan = __commonJS((exports, module) => {
10327
10317
  };
10328
10318
  });
10329
10319
 
10330
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/internal/constants.js
10320
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/internal/constants.js
10331
10321
  var require_constants4 = __commonJS((exports, module) => {
10332
10322
  var SEMVER_SPEC_VERSION = "2.0.0";
10333
10323
  var MAX_LENGTH = 256;
@@ -10355,13 +10345,13 @@ var require_constants4 = __commonJS((exports, module) => {
10355
10345
  };
10356
10346
  });
10357
10347
 
10358
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/internal/debug.js
10348
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/internal/debug.js
10359
10349
  var require_debug = __commonJS((exports, module) => {
10360
10350
  var debug = typeof process === "object" && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG) ? (...args) => console.error("SEMVER", ...args) : () => {};
10361
10351
  module.exports = debug;
10362
10352
  });
10363
10353
 
10364
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/internal/re.js
10354
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/internal/re.js
10365
10355
  var require_re = __commonJS((exports, module) => {
10366
10356
  var {
10367
10357
  MAX_SAFE_COMPONENT_LENGTH,
@@ -10446,7 +10436,7 @@ var require_re = __commonJS((exports, module) => {
10446
10436
  createToken("GTE0PRE", "^\\s*>=\\s*0\\.0\\.0-0\\s*$");
10447
10437
  });
10448
10438
 
10449
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/internal/parse-options.js
10439
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/internal/parse-options.js
10450
10440
  var require_parse_options = __commonJS((exports, module) => {
10451
10441
  var looseOption = Object.freeze({ loose: true });
10452
10442
  var emptyOpts = Object.freeze({});
@@ -10462,7 +10452,7 @@ var require_parse_options = __commonJS((exports, module) => {
10462
10452
  module.exports = parseOptions;
10463
10453
  });
10464
10454
 
10465
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/internal/identifiers.js
10455
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/internal/identifiers.js
10466
10456
  var require_identifiers = __commonJS((exports, module) => {
10467
10457
  var numeric = /^[0-9]+$/;
10468
10458
  var compareIdentifiers = (a2, b2) => {
@@ -10484,7 +10474,7 @@ var require_identifiers = __commonJS((exports, module) => {
10484
10474
  };
10485
10475
  });
10486
10476
 
10487
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/classes/semver.js
10477
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/classes/semver.js
10488
10478
  var require_semver = __commonJS((exports, module) => {
10489
10479
  var debug = require_debug();
10490
10480
  var { MAX_LENGTH, MAX_SAFE_INTEGER } = require_constants4();
@@ -10753,7 +10743,7 @@ var require_semver = __commonJS((exports, module) => {
10753
10743
  module.exports = SemVer;
10754
10744
  });
10755
10745
 
10756
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/parse.js
10746
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/parse.js
10757
10747
  var require_parse3 = __commonJS((exports, module) => {
10758
10748
  var SemVer = require_semver();
10759
10749
  var parse = (version, options, throwErrors = false) => {
@@ -10772,7 +10762,7 @@ var require_parse3 = __commonJS((exports, module) => {
10772
10762
  module.exports = parse;
10773
10763
  });
10774
10764
 
10775
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/valid.js
10765
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/valid.js
10776
10766
  var require_valid = __commonJS((exports, module) => {
10777
10767
  var parse = require_parse3();
10778
10768
  var valid = (version, options) => {
@@ -10782,7 +10772,7 @@ var require_valid = __commonJS((exports, module) => {
10782
10772
  module.exports = valid;
10783
10773
  });
10784
10774
 
10785
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/clean.js
10775
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/clean.js
10786
10776
  var require_clean = __commonJS((exports, module) => {
10787
10777
  var parse = require_parse3();
10788
10778
  var clean = (version, options) => {
@@ -10792,7 +10782,7 @@ var require_clean = __commonJS((exports, module) => {
10792
10782
  module.exports = clean;
10793
10783
  });
10794
10784
 
10795
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/inc.js
10785
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/inc.js
10796
10786
  var require_inc = __commonJS((exports, module) => {
10797
10787
  var SemVer = require_semver();
10798
10788
  var inc = (version, release, options, identifier, identifierBase) => {
@@ -10810,7 +10800,7 @@ var require_inc = __commonJS((exports, module) => {
10810
10800
  module.exports = inc;
10811
10801
  });
10812
10802
 
10813
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/diff.js
10803
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/diff.js
10814
10804
  var require_diff = __commonJS((exports, module) => {
10815
10805
  var parse = require_parse3();
10816
10806
  var diff = (version1, version2) => {
@@ -10851,28 +10841,28 @@ var require_diff = __commonJS((exports, module) => {
10851
10841
  module.exports = diff;
10852
10842
  });
10853
10843
 
10854
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/major.js
10844
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/major.js
10855
10845
  var require_major = __commonJS((exports, module) => {
10856
10846
  var SemVer = require_semver();
10857
10847
  var major = (a2, loose) => new SemVer(a2, loose).major;
10858
10848
  module.exports = major;
10859
10849
  });
10860
10850
 
10861
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/minor.js
10851
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/minor.js
10862
10852
  var require_minor = __commonJS((exports, module) => {
10863
10853
  var SemVer = require_semver();
10864
10854
  var minor = (a2, loose) => new SemVer(a2, loose).minor;
10865
10855
  module.exports = minor;
10866
10856
  });
10867
10857
 
10868
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/patch.js
10858
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/patch.js
10869
10859
  var require_patch = __commonJS((exports, module) => {
10870
10860
  var SemVer = require_semver();
10871
10861
  var patch = (a2, loose) => new SemVer(a2, loose).patch;
10872
10862
  module.exports = patch;
10873
10863
  });
10874
10864
 
10875
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/prerelease.js
10865
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/prerelease.js
10876
10866
  var require_prerelease = __commonJS((exports, module) => {
10877
10867
  var parse = require_parse3();
10878
10868
  var prerelease = (version, options) => {
@@ -10882,28 +10872,28 @@ var require_prerelease = __commonJS((exports, module) => {
10882
10872
  module.exports = prerelease;
10883
10873
  });
10884
10874
 
10885
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/compare.js
10875
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/compare.js
10886
10876
  var require_compare = __commonJS((exports, module) => {
10887
10877
  var SemVer = require_semver();
10888
10878
  var compare = (a2, b2, loose) => new SemVer(a2, loose).compare(new SemVer(b2, loose));
10889
10879
  module.exports = compare;
10890
10880
  });
10891
10881
 
10892
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/rcompare.js
10882
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/rcompare.js
10893
10883
  var require_rcompare = __commonJS((exports, module) => {
10894
10884
  var compare = require_compare();
10895
10885
  var rcompare = (a2, b2, loose) => compare(b2, a2, loose);
10896
10886
  module.exports = rcompare;
10897
10887
  });
10898
10888
 
10899
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/compare-loose.js
10889
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/compare-loose.js
10900
10890
  var require_compare_loose = __commonJS((exports, module) => {
10901
10891
  var compare = require_compare();
10902
10892
  var compareLoose = (a2, b2) => compare(a2, b2, true);
10903
10893
  module.exports = compareLoose;
10904
10894
  });
10905
10895
 
10906
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/compare-build.js
10896
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/compare-build.js
10907
10897
  var require_compare_build = __commonJS((exports, module) => {
10908
10898
  var SemVer = require_semver();
10909
10899
  var compareBuild = (a2, b2, loose) => {
@@ -10914,63 +10904,63 @@ var require_compare_build = __commonJS((exports, module) => {
10914
10904
  module.exports = compareBuild;
10915
10905
  });
10916
10906
 
10917
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/sort.js
10907
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/sort.js
10918
10908
  var require_sort = __commonJS((exports, module) => {
10919
10909
  var compareBuild = require_compare_build();
10920
10910
  var sort = (list, loose) => list.sort((a2, b2) => compareBuild(a2, b2, loose));
10921
10911
  module.exports = sort;
10922
10912
  });
10923
10913
 
10924
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/rsort.js
10914
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/rsort.js
10925
10915
  var require_rsort = __commonJS((exports, module) => {
10926
10916
  var compareBuild = require_compare_build();
10927
10917
  var rsort = (list, loose) => list.sort((a2, b2) => compareBuild(b2, a2, loose));
10928
10918
  module.exports = rsort;
10929
10919
  });
10930
10920
 
10931
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/gt.js
10921
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/gt.js
10932
10922
  var require_gt = __commonJS((exports, module) => {
10933
10923
  var compare = require_compare();
10934
10924
  var gt = (a2, b2, loose) => compare(a2, b2, loose) > 0;
10935
10925
  module.exports = gt;
10936
10926
  });
10937
10927
 
10938
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/lt.js
10928
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/lt.js
10939
10929
  var require_lt = __commonJS((exports, module) => {
10940
10930
  var compare = require_compare();
10941
10931
  var lt = (a2, b2, loose) => compare(a2, b2, loose) < 0;
10942
10932
  module.exports = lt;
10943
10933
  });
10944
10934
 
10945
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/eq.js
10935
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/eq.js
10946
10936
  var require_eq = __commonJS((exports, module) => {
10947
10937
  var compare = require_compare();
10948
10938
  var eq = (a2, b2, loose) => compare(a2, b2, loose) === 0;
10949
10939
  module.exports = eq;
10950
10940
  });
10951
10941
 
10952
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/neq.js
10942
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/neq.js
10953
10943
  var require_neq = __commonJS((exports, module) => {
10954
10944
  var compare = require_compare();
10955
10945
  var neq = (a2, b2, loose) => compare(a2, b2, loose) !== 0;
10956
10946
  module.exports = neq;
10957
10947
  });
10958
10948
 
10959
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/gte.js
10949
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/gte.js
10960
10950
  var require_gte = __commonJS((exports, module) => {
10961
10951
  var compare = require_compare();
10962
10952
  var gte = (a2, b2, loose) => compare(a2, b2, loose) >= 0;
10963
10953
  module.exports = gte;
10964
10954
  });
10965
10955
 
10966
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/lte.js
10956
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/lte.js
10967
10957
  var require_lte = __commonJS((exports, module) => {
10968
10958
  var compare = require_compare();
10969
10959
  var lte = (a2, b2, loose) => compare(a2, b2, loose) <= 0;
10970
10960
  module.exports = lte;
10971
10961
  });
10972
10962
 
10973
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/cmp.js
10963
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/cmp.js
10974
10964
  var require_cmp = __commonJS((exports, module) => {
10975
10965
  var eq = require_eq();
10976
10966
  var neq = require_neq();
@@ -11017,7 +11007,7 @@ var require_cmp = __commonJS((exports, module) => {
11017
11007
  module.exports = cmp;
11018
11008
  });
11019
11009
 
11020
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/coerce.js
11010
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/coerce.js
11021
11011
  var require_coerce = __commonJS((exports, module) => {
11022
11012
  var SemVer = require_semver();
11023
11013
  var parse = require_parse3();
@@ -11060,7 +11050,45 @@ var require_coerce = __commonJS((exports, module) => {
11060
11050
  module.exports = coerce;
11061
11051
  });
11062
11052
 
11063
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/internal/lrucache.js
11053
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/truncate.js
11054
+ var require_truncate = __commonJS((exports, module) => {
11055
+ var parse = require_parse3();
11056
+ var constants = require_constants4();
11057
+ var SemVer = require_semver();
11058
+ var truncate = (version, truncation, options) => {
11059
+ if (!constants.RELEASE_TYPES.includes(truncation)) {
11060
+ return null;
11061
+ }
11062
+ const clonedVersion = cloneInputVersion(version, options);
11063
+ return clonedVersion && doTruncation(clonedVersion, truncation);
11064
+ };
11065
+ var cloneInputVersion = (version, options) => {
11066
+ const versionStringToParse = version instanceof SemVer ? version.version : version;
11067
+ return parse(versionStringToParse, options);
11068
+ };
11069
+ var doTruncation = (version, truncation) => {
11070
+ if (isPrerelease(truncation)) {
11071
+ return version.version;
11072
+ }
11073
+ version.prerelease = [];
11074
+ switch (truncation) {
11075
+ case "major":
11076
+ version.minor = 0;
11077
+ version.patch = 0;
11078
+ break;
11079
+ case "minor":
11080
+ version.patch = 0;
11081
+ break;
11082
+ }
11083
+ return version.format();
11084
+ };
11085
+ var isPrerelease = (type) => {
11086
+ return type.startsWith("pre");
11087
+ };
11088
+ module.exports = truncate;
11089
+ });
11090
+
11091
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/internal/lrucache.js
11064
11092
  var require_lrucache = __commonJS((exports, module) => {
11065
11093
  class LRUCache2 {
11066
11094
  constructor() {
@@ -11095,7 +11123,7 @@ var require_lrucache = __commonJS((exports, module) => {
11095
11123
  module.exports = LRUCache2;
11096
11124
  });
11097
11125
 
11098
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/classes/range.js
11126
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/classes/range.js
11099
11127
  var require_range = __commonJS((exports, module) => {
11100
11128
  var SPACE_CHARACTERS = /\s+/g;
11101
11129
 
@@ -11469,7 +11497,7 @@ var require_range = __commonJS((exports, module) => {
11469
11497
  };
11470
11498
  });
11471
11499
 
11472
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/classes/comparator.js
11500
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/classes/comparator.js
11473
11501
  var require_comparator = __commonJS((exports, module) => {
11474
11502
  var ANY = Symbol("SemVer ANY");
11475
11503
 
@@ -11580,7 +11608,7 @@ var require_comparator = __commonJS((exports, module) => {
11580
11608
  var Range = require_range();
11581
11609
  });
11582
11610
 
11583
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/functions/satisfies.js
11611
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/functions/satisfies.js
11584
11612
  var require_satisfies = __commonJS((exports, module) => {
11585
11613
  var Range = require_range();
11586
11614
  var satisfies = (version, range, options) => {
@@ -11594,14 +11622,14 @@ var require_satisfies = __commonJS((exports, module) => {
11594
11622
  module.exports = satisfies;
11595
11623
  });
11596
11624
 
11597
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/to-comparators.js
11625
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/to-comparators.js
11598
11626
  var require_to_comparators = __commonJS((exports, module) => {
11599
11627
  var Range = require_range();
11600
11628
  var toComparators = (range, options) => new Range(range, options).set.map((comp) => comp.map((c2) => c2.value).join(" ").trim().split(" "));
11601
11629
  module.exports = toComparators;
11602
11630
  });
11603
11631
 
11604
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/max-satisfying.js
11632
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/max-satisfying.js
11605
11633
  var require_max_satisfying = __commonJS((exports, module) => {
11606
11634
  var SemVer = require_semver();
11607
11635
  var Range = require_range();
@@ -11627,7 +11655,7 @@ var require_max_satisfying = __commonJS((exports, module) => {
11627
11655
  module.exports = maxSatisfying;
11628
11656
  });
11629
11657
 
11630
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/min-satisfying.js
11658
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/min-satisfying.js
11631
11659
  var require_min_satisfying = __commonJS((exports, module) => {
11632
11660
  var SemVer = require_semver();
11633
11661
  var Range = require_range();
@@ -11653,7 +11681,7 @@ var require_min_satisfying = __commonJS((exports, module) => {
11653
11681
  module.exports = minSatisfying;
11654
11682
  });
11655
11683
 
11656
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/min-version.js
11684
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/min-version.js
11657
11685
  var require_min_version = __commonJS((exports, module) => {
11658
11686
  var SemVer = require_semver();
11659
11687
  var Range = require_range();
@@ -11707,7 +11735,7 @@ var require_min_version = __commonJS((exports, module) => {
11707
11735
  module.exports = minVersion;
11708
11736
  });
11709
11737
 
11710
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/valid.js
11738
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/valid.js
11711
11739
  var require_valid2 = __commonJS((exports, module) => {
11712
11740
  var Range = require_range();
11713
11741
  var validRange = (range, options) => {
@@ -11720,7 +11748,7 @@ var require_valid2 = __commonJS((exports, module) => {
11720
11748
  module.exports = validRange;
11721
11749
  });
11722
11750
 
11723
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/outside.js
11751
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/outside.js
11724
11752
  var require_outside = __commonJS((exports, module) => {
11725
11753
  var SemVer = require_semver();
11726
11754
  var Comparator = require_comparator();
@@ -11786,21 +11814,21 @@ var require_outside = __commonJS((exports, module) => {
11786
11814
  module.exports = outside;
11787
11815
  });
11788
11816
 
11789
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/gtr.js
11817
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/gtr.js
11790
11818
  var require_gtr = __commonJS((exports, module) => {
11791
11819
  var outside = require_outside();
11792
11820
  var gtr = (version, range, options) => outside(version, range, ">", options);
11793
11821
  module.exports = gtr;
11794
11822
  });
11795
11823
 
11796
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/ltr.js
11824
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/ltr.js
11797
11825
  var require_ltr = __commonJS((exports, module) => {
11798
11826
  var outside = require_outside();
11799
11827
  var ltr = (version, range, options) => outside(version, range, "<", options);
11800
11828
  module.exports = ltr;
11801
11829
  });
11802
11830
 
11803
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/intersects.js
11831
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/intersects.js
11804
11832
  var require_intersects = __commonJS((exports, module) => {
11805
11833
  var Range = require_range();
11806
11834
  var intersects = (r1, r2, options) => {
@@ -11811,7 +11839,7 @@ var require_intersects = __commonJS((exports, module) => {
11811
11839
  module.exports = intersects;
11812
11840
  });
11813
11841
 
11814
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/simplify.js
11842
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/simplify.js
11815
11843
  var require_simplify = __commonJS((exports, module) => {
11816
11844
  var satisfies = require_satisfies();
11817
11845
  var compare = require_compare();
@@ -11858,7 +11886,7 @@ var require_simplify = __commonJS((exports, module) => {
11858
11886
  };
11859
11887
  });
11860
11888
 
11861
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/ranges/subset.js
11889
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/ranges/subset.js
11862
11890
  var require_subset = __commonJS((exports, module) => {
11863
11891
  var Range = require_range();
11864
11892
  var Comparator = require_comparator();
@@ -12018,7 +12046,7 @@ var require_subset = __commonJS((exports, module) => {
12018
12046
  module.exports = subset;
12019
12047
  });
12020
12048
 
12021
- // ../../node_modules/.bun/semver@7.7.4/node_modules/semver/index.js
12049
+ // ../../node_modules/.bun/semver@7.8.0/node_modules/semver/index.js
12022
12050
  var require_semver2 = __commonJS((exports, module) => {
12023
12051
  var internalRe = require_re();
12024
12052
  var constants = require_constants4();
@@ -12047,6 +12075,7 @@ var require_semver2 = __commonJS((exports, module) => {
12047
12075
  var lte = require_lte();
12048
12076
  var cmp = require_cmp();
12049
12077
  var coerce = require_coerce();
12078
+ var truncate = require_truncate();
12050
12079
  var Comparator = require_comparator();
12051
12080
  var Range = require_range();
12052
12081
  var satisfies = require_satisfies();
@@ -12085,6 +12114,7 @@ var require_semver2 = __commonJS((exports, module) => {
12085
12114
  lte,
12086
12115
  cmp,
12087
12116
  coerce,
12117
+ truncate,
12088
12118
  Comparator,
12089
12119
  Range,
12090
12120
  satisfies,
@@ -25734,6 +25764,394 @@ var init_dist2 = __esm(() => {
25734
25764
  };
25735
25765
  });
25736
25766
 
25767
+ // ../observability/dist/init-server.js
25768
+ var exports_init_server = {};
25769
+ __export(exports_init_server, {
25770
+ wrapDbAdapter: () => wrapDbAdapter,
25771
+ initServerTelemetry: () => initServerTelemetry
25772
+ });
25773
+ import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
25774
+ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
25775
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
25776
+ import { Resource } from "@opentelemetry/resources";
25777
+ import {
25778
+ BatchLogRecordProcessor,
25779
+ LoggerProvider
25780
+ } from "@opentelemetry/sdk-logs";
25781
+ import {
25782
+ MeterProvider,
25783
+ PeriodicExportingMetricReader
25784
+ } from "@opentelemetry/sdk-metrics";
25785
+ import {
25786
+ BatchSpanProcessor,
25787
+ ParentBasedSampler,
25788
+ TraceIdRatioBasedSampler
25789
+ } from "@opentelemetry/sdk-trace-base";
25790
+ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
25791
+ import {
25792
+ ATTR_DEPLOYMENT_ENVIRONMENT_NAME,
25793
+ ATTR_SERVICE_NAME,
25794
+ ATTR_SERVICE_VERSION
25795
+ } from "@opentelemetry/semantic-conventions/incubating";
25796
+ import {
25797
+ context,
25798
+ propagation,
25799
+ SpanStatusCode,
25800
+ trace
25801
+ } from "@opentelemetry/api";
25802
+ import {
25803
+ logs,
25804
+ SeverityNumber
25805
+ } from "@opentelemetry/api-logs";
25806
+ function sanitizeAttrs(input, opts = {}) {
25807
+ if (!input)
25808
+ return {};
25809
+ const redactPattern = opts.redactKeyPattern ?? DEFAULT_REDACT_KEY_PATTERN;
25810
+ const maxStr = opts.maxStringLen ?? DEFAULT_MAX_STRING_LEN;
25811
+ const maxJson = opts.maxJsonLen ?? DEFAULT_MAX_JSON_LEN;
25812
+ const out = {};
25813
+ for (const [key, raw] of Object.entries(input)) {
25814
+ if (redactPattern.test(key))
25815
+ continue;
25816
+ const value = sanitizeValue(raw, redactPattern, maxStr, maxJson);
25817
+ if (value !== undefined)
25818
+ out[key] = value;
25819
+ }
25820
+ return out;
25821
+ }
25822
+ function sanitizeValue(raw, redactPattern, maxStr, maxJson) {
25823
+ if (raw === null || raw === undefined)
25824
+ return;
25825
+ if (typeof raw === "boolean" || typeof raw === "number")
25826
+ return raw;
25827
+ if (typeof raw === "string") {
25828
+ return raw.length > maxStr ? `${raw.slice(0, maxStr)}\u2026(truncated:${raw.length})` : raw;
25829
+ }
25830
+ try {
25831
+ const filtered = filterRedacted(raw, redactPattern);
25832
+ const json = JSON.stringify(filtered);
25833
+ if (json === undefined)
25834
+ return;
25835
+ return json.length > maxJson ? `${json.slice(0, maxJson)}\u2026(truncated:${json.length})` : json;
25836
+ } catch {
25837
+ return "[unserializable]";
25838
+ }
25839
+ }
25840
+ function filterRedacted(node, pattern, seen = new WeakSet) {
25841
+ if (node === null || typeof node !== "object")
25842
+ return node;
25843
+ if (seen.has(node))
25844
+ return "[circular]";
25845
+ seen.add(node);
25846
+ if (Array.isArray(node)) {
25847
+ return node.map((v3) => filterRedacted(v3, pattern, seen));
25848
+ }
25849
+ const out = {};
25850
+ for (const [k4, v3] of Object.entries(node)) {
25851
+ if (pattern.test(k4))
25852
+ continue;
25853
+ out[k4] = filterRedacted(v3, pattern, seen);
25854
+ }
25855
+ return out;
25856
+ }
25857
+
25858
+ class ArcTelemetry {
25859
+ config;
25860
+ tracer = null;
25861
+ logger = null;
25862
+ meter = null;
25863
+ histograms = new Map;
25864
+ counters = new Map;
25865
+ constructor(config) {
25866
+ const mode = config.mode ?? "development";
25867
+ const enabled = config.enabled ?? mode !== "disabled";
25868
+ const sampleRate = config.sampleRate ?? (config.environment === "server" ? 1 : 0.1);
25869
+ this.config = {
25870
+ ...config,
25871
+ enabled,
25872
+ sampleRate,
25873
+ mode,
25874
+ debug: config.debug ?? false
25875
+ };
25876
+ }
25877
+ attach(opts) {
25878
+ this.tracer = opts.tracer;
25879
+ this.logger = opts.logger ?? null;
25880
+ this.meter = opts.meter ?? null;
25881
+ }
25882
+ get active() {
25883
+ return this.config.enabled && this.tracer !== null;
25884
+ }
25885
+ shouldIncludePayloads() {
25886
+ if (this.config.includePayloads !== undefined)
25887
+ return this.config.includePayloads;
25888
+ return this.config.mode === "development";
25889
+ }
25890
+ async startSpan(name, fn, options = {}) {
25891
+ if (!this.active || !this.tracer) {
25892
+ return fn(trace.getActiveSpan() ?? noopSpan());
25893
+ }
25894
+ const attributes = this.toAttributes(options.attributes, options.unsafeAttrs);
25895
+ return this.tracer.startActiveSpan(name, { kind: options.kind, attributes }, async (span) => {
25896
+ try {
25897
+ const result = await fn(span);
25898
+ span.setStatus({ code: SpanStatusCode.OK });
25899
+ return result;
25900
+ } catch (error) {
25901
+ this.recordError(span, error);
25902
+ throw error;
25903
+ } finally {
25904
+ span.end();
25905
+ }
25906
+ });
25907
+ }
25908
+ createSpan(name, options = {}) {
25909
+ if (!this.active || !this.tracer)
25910
+ return noopSpan();
25911
+ const attributes = this.toAttributes(options.attributes, options.unsafeAttrs);
25912
+ return this.tracer.startSpan(name, { kind: options.kind, attributes });
25913
+ }
25914
+ getCurrentSpan() {
25915
+ return trace.getActiveSpan();
25916
+ }
25917
+ withSpan(parent, fn) {
25918
+ return context.with(trace.setSpan(context.active(), parent), fn);
25919
+ }
25920
+ runWithExtractedContext(carrier, fn) {
25921
+ if (!this.active)
25922
+ return fn();
25923
+ const flat = {};
25924
+ if (typeof Headers !== "undefined" && carrier instanceof Headers) {
25925
+ carrier.forEach((value, key) => {
25926
+ flat[key.toLowerCase()] = value;
25927
+ });
25928
+ } else if (carrier) {
25929
+ for (const [k4, v3] of Object.entries(carrier)) {
25930
+ if (typeof v3 === "string")
25931
+ flat[k4.toLowerCase()] = v3;
25932
+ }
25933
+ }
25934
+ const parent = propagation.extract(context.active(), flat);
25935
+ return context.with(parent, fn);
25936
+ }
25937
+ recordError(span, error) {
25938
+ const err3 = error instanceof Error ? error : new Error(String(error ?? "unknown error"));
25939
+ try {
25940
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err3.message });
25941
+ span.recordException(err3);
25942
+ } catch {}
25943
+ }
25944
+ addAttributes(attrs, unsafeAttrs = false) {
25945
+ const span = this.getCurrentSpan();
25946
+ if (!span)
25947
+ return;
25948
+ span.setAttributes(this.toAttributes(attrs, unsafeAttrs));
25949
+ }
25950
+ log(level, body, attrs = {}, unsafeAttrs = false) {
25951
+ if (!this.active)
25952
+ return;
25953
+ const logger = this.logger ?? logs.getLogger(this.config.serviceName);
25954
+ const record = {
25955
+ severityNumber: severityFor(level),
25956
+ severityText: level.toUpperCase(),
25957
+ body,
25958
+ attributes: this.toAttributes(attrs, unsafeAttrs)
25959
+ };
25960
+ try {
25961
+ logger.emit(record);
25962
+ } catch {}
25963
+ }
25964
+ incrementCounter(name, value = 1, attrs = {}) {
25965
+ if (!this.active || !this.meter)
25966
+ return;
25967
+ let counter = this.counters.get(name);
25968
+ if (!counter) {
25969
+ counter = this.meter.createCounter(name);
25970
+ this.counters.set(name, counter);
25971
+ }
25972
+ try {
25973
+ counter.add(value, attrs);
25974
+ } catch {}
25975
+ }
25976
+ recordHistogram(name, value, attrs = {}) {
25977
+ if (!this.active || !this.meter)
25978
+ return;
25979
+ let histogram = this.histograms.get(name);
25980
+ if (!histogram) {
25981
+ histogram = this.meter.createHistogram(name, { unit: "ms" });
25982
+ this.histograms.set(name, histogram);
25983
+ }
25984
+ try {
25985
+ histogram.record(value, attrs);
25986
+ } catch {}
25987
+ }
25988
+ measureSince(name, start, attrs = {}) {
25989
+ this.recordHistogram(name, Date.now() - start, attrs);
25990
+ }
25991
+ toAttributes(raw, unsafe) {
25992
+ if (!raw)
25993
+ return {};
25994
+ if (unsafe)
25995
+ return raw;
25996
+ return sanitizeAttrs(raw, this.config.sanitize);
25997
+ }
25998
+ }
25999
+ function severityFor(level) {
26000
+ switch (level) {
26001
+ case "debug":
26002
+ return SeverityNumber.DEBUG;
26003
+ case "info":
26004
+ return SeverityNumber.INFO;
26005
+ case "warn":
26006
+ return SeverityNumber.WARN;
26007
+ case "error":
26008
+ return SeverityNumber.ERROR;
26009
+ default:
26010
+ return SeverityNumber.INFO;
26011
+ }
26012
+ }
26013
+ function noopSpan() {
26014
+ return trace.getActiveSpan() ?? trace.wrapSpanContext({
26015
+ traceId: "00000000000000000000000000000000",
26016
+ spanId: "0000000000000000",
26017
+ traceFlags: 0
26018
+ });
26019
+ }
26020
+ function wrapDbAdapter(adapter, telemetry, dbSystem) {
26021
+ if (!telemetry || !telemetry.active)
26022
+ return adapter;
26023
+ const wrapRead = (tx) => ({
26024
+ find: async (store, options) => telemetry.startSpan(`db.find ${store}`, async (span) => {
26025
+ const start = Date.now();
26026
+ try {
26027
+ const rows = await tx.find(store, options);
26028
+ span.setAttribute("db.response.row_count", rows.length);
26029
+ return rows;
26030
+ } finally {
26031
+ telemetry.measureSince("arc.db.find_ms", start, {
26032
+ "db.system": dbSystem,
26033
+ "db.collection.name": store
26034
+ });
26035
+ }
26036
+ }, {
26037
+ kind: 3,
26038
+ attributes: {
26039
+ "db.system": dbSystem,
26040
+ "db.operation.name": "find",
26041
+ "db.collection.name": store
26042
+ }
26043
+ })
26044
+ });
26045
+ const wrapReadWrite = (tx) => ({
26046
+ ...wrapRead(tx),
26047
+ set: async (store, data) => telemetry.startSpan(`db.set ${store}`, () => tx.set(store, data), {
26048
+ kind: 3,
26049
+ attributes: {
26050
+ "db.system": dbSystem,
26051
+ "db.operation.name": "set",
26052
+ "db.collection.name": store
26053
+ }
26054
+ }),
26055
+ remove: async (store, id3) => telemetry.startSpan(`db.remove ${store}`, () => tx.remove(store, id3), {
26056
+ kind: 3,
26057
+ attributes: {
26058
+ "db.system": dbSystem,
26059
+ "db.operation.name": "remove",
26060
+ "db.collection.name": store
26061
+ }
26062
+ }),
26063
+ commit: async () => telemetry.startSpan("db.commit", () => tx.commit(), {
26064
+ kind: 3,
26065
+ attributes: {
26066
+ "db.system": dbSystem,
26067
+ "db.operation.name": "commit"
26068
+ }
26069
+ })
26070
+ });
26071
+ return new Proxy(adapter, {
26072
+ get(target, prop) {
26073
+ const orig = target[prop];
26074
+ if (prop === "readTransaction") {
26075
+ return (...args) => wrapRead(orig.apply(target, args));
26076
+ }
26077
+ if (prop === "readWriteTransaction") {
26078
+ return (...args) => wrapReadWrite(orig.apply(target, args));
26079
+ }
26080
+ return typeof orig === "function" ? orig.bind(target) : orig;
26081
+ }
26082
+ });
26083
+ }
26084
+ function initServerTelemetry(config) {
26085
+ const telemetry = new ArcTelemetry({ ...config, environment: "server" });
26086
+ if (!telemetry.config.enabled) {
26087
+ return { telemetry, shutdown: async () => {} };
26088
+ }
26089
+ const endpoint = config.endpoint ?? process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? "http://localhost:4318";
26090
+ const resource = new Resource({
26091
+ [ATTR_SERVICE_NAME]: config.serviceName,
26092
+ [ATTR_SERVICE_VERSION]: process.env.ARC_VERSION ?? "unknown",
26093
+ [ATTR_DEPLOYMENT_ENVIRONMENT_NAME]: "development"
26094
+ });
26095
+ const tracerProvider = new NodeTracerProvider({
26096
+ resource,
26097
+ sampler: new ParentBasedSampler({
26098
+ root: new TraceIdRatioBasedSampler(telemetry.config.sampleRate)
26099
+ }),
26100
+ spanProcessors: [
26101
+ new BatchSpanProcessor(new OTLPTraceExporter({ url: `${endpoint}/v1/traces` }), {
26102
+ maxQueueSize: 1000,
26103
+ maxExportBatchSize: 50,
26104
+ scheduledDelayMillis: 5000
26105
+ })
26106
+ ]
26107
+ });
26108
+ tracerProvider.register();
26109
+ const loggerProvider = new LoggerProvider({ resource });
26110
+ loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(new OTLPLogExporter({ url: `${endpoint}/v1/logs` }), {
26111
+ maxQueueSize: 1000,
26112
+ maxExportBatchSize: 50,
26113
+ scheduledDelayMillis: 5000
26114
+ }));
26115
+ const meterProvider = new MeterProvider({
26116
+ resource,
26117
+ readers: [
26118
+ new PeriodicExportingMetricReader({
26119
+ exporter: new OTLPMetricExporter({ url: `${endpoint}/v1/metrics` }),
26120
+ exportIntervalMillis: 15000
26121
+ })
26122
+ ]
26123
+ });
26124
+ telemetry.attach({
26125
+ tracer: tracerProvider.getTracer(config.serviceName),
26126
+ logger: loggerProvider.getLogger(config.serviceName),
26127
+ meter: meterProvider.getMeter(config.serviceName)
26128
+ });
26129
+ if (telemetry.config.debug) {
26130
+ console.log("[arc-otel] server init", {
26131
+ serviceName: config.serviceName,
26132
+ endpoint,
26133
+ sampleRate: telemetry.config.sampleRate,
26134
+ mode: telemetry.config.mode
26135
+ });
26136
+ }
26137
+ const shutdown = async () => {
26138
+ try {
26139
+ await Promise.all([
26140
+ tracerProvider.shutdown(),
26141
+ loggerProvider.shutdown(),
26142
+ meterProvider.shutdown()
26143
+ ]);
26144
+ } catch (err3) {
26145
+ console.error("[arc-otel] shutdown error", err3);
26146
+ }
26147
+ };
26148
+ return { telemetry, shutdown };
26149
+ }
26150
+ var DEFAULT_REDACT_KEY_PATTERN, DEFAULT_MAX_STRING_LEN = 2048, DEFAULT_MAX_JSON_LEN = 4096;
26151
+ var init_init_server = __esm(() => {
26152
+ DEFAULT_REDACT_KEY_PATTERN = /(password|passwd|token|secret|authorization|jwt|api[_-]?key|cookie|email|credit[_-]?card|ssn)/i;
26153
+ });
26154
+
25737
26155
  // ../../node_modules/.bun/commander@11.1.0/node_modules/commander/esm.mjs
25738
26156
  var import__ = __toESM(require_commander(), 1);
25739
26157
  var {
@@ -33964,7 +34382,7 @@ ${colors3.yellow}Type declaration errors:${colors3.reset}`);
33964
34382
 
33965
34383
  // src/platform/shared.ts
33966
34384
  import { copyFileSync, existsSync as existsSync10, mkdirSync as mkdirSync9, readdirSync as readdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "fs";
33967
- import { dirname as dirname7, join as join11 } from "path";
34385
+ import { dirname as dirname8, join as join11 } from "path";
33968
34386
 
33969
34387
  // src/builder/module-builder.ts
33970
34388
  import { execSync } from "child_process";
@@ -34794,13 +35212,27 @@ function resolveChunk(moduleName, access) {
34794
35212
  // src/builder/dependency-collector.ts
34795
35213
  import { createHash } from "crypto";
34796
35214
  import { existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
34797
- import { basename as basename4, join as join10 } from "path";
35215
+ import { basename as basename4, dirname as dirname7, join as join10 } from "path";
35216
+ import { fileURLToPath as fileURLToPath6 } from "url";
34798
35217
  function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = []) {
34799
35218
  mkdirSync8(arcDir, { recursive: true });
34800
35219
  const versions = resolveFrameworkVersions(rootDir, packages);
34801
35220
  for (const { name, version } of sharedDeps) {
34802
35221
  versions[name] = version;
34803
35222
  }
35223
+ try {
35224
+ const cliDir = dirname7(fileURLToPath6(import.meta.url));
35225
+ const arcOtelPkgPath = Bun.resolveSync("@arcote.tech/arc-otel/package.json", cliDir);
35226
+ const arcOtelPkg = JSON.parse(readFileSync9(arcOtelPkgPath, "utf-8"));
35227
+ for (const [name, spec] of Object.entries(arcOtelPkg.dependencies ?? {})) {
35228
+ if (name.startsWith("@opentelemetry/")) {
35229
+ versions[name] = spec;
35230
+ }
35231
+ }
35232
+ versions["@arcote.tech/arc-otel"] = `^${arcOtelPkg.version}`;
35233
+ } catch (e) {
35234
+ console.warn(`[arc-otel] could not resolve @arcote.tech/arc-otel \u2014 image will run without telemetry deps: ${e.message}`);
35235
+ }
34804
35236
  const manifest = {
34805
35237
  name: "arc-platform-framework",
34806
35238
  private: true,
@@ -34877,7 +35309,7 @@ function resolveWorkspace() {
34877
35309
  err("No package.json found");
34878
35310
  process.exit(1);
34879
35311
  }
34880
- const rootDir = dirname7(packageJsonPath);
35312
+ const rootDir = dirname8(packageJsonPath);
34881
35313
  const rootPkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
34882
35314
  const appName = rootPkg.name ?? "Arc App";
34883
35315
  const arcDir = join11(rootDir, ".arc", "platform");
@@ -35054,7 +35486,7 @@ async function copyBrowserAssets(ws, cache, noCache) {
35054
35486
  const outputHashes = {};
35055
35487
  for (const asset of assets) {
35056
35488
  const dest = join11(ws.assetsDir, asset.to);
35057
- mkdirSync9(dirname7(dest), { recursive: true });
35489
+ mkdirSync9(dirname8(dest), { recursive: true });
35058
35490
  copyFileSync(asset.src, dest);
35059
35491
  outputHashes[asset.to] = sha256Hex(readFileSync10(dest));
35060
35492
  }
@@ -35113,14 +35545,14 @@ async function platformBuild(opts = {}) {
35113
35545
 
35114
35546
  // src/commands/platform-deploy.ts
35115
35547
  import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
35116
- import { dirname as dirname9, join as join19 } from "path";
35117
- import { fileURLToPath as fileURLToPath7 } from "url";
35548
+ import { dirname as dirname11, join as join19 } from "path";
35549
+ import { fileURLToPath as fileURLToPath8 } from "url";
35118
35550
 
35119
35551
  // src/deploy/bootstrap.ts
35120
35552
  var {spawn: spawn4 } = globalThis.Bun;
35121
35553
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync13 } from "fs";
35122
35554
  import { tmpdir as tmpdir2 } from "os";
35123
- import { join as join17 } from "path";
35555
+ import { dirname as dirname9, join as join17 } from "path";
35124
35556
 
35125
35557
  // src/deploy/ansible.ts
35126
35558
  import { spawn as nodeSpawn } from "child_process";
@@ -35477,10 +35909,34 @@ function generateCaddyfile(cfg) {
35477
35909
  lines.push("");
35478
35910
  for (const [name, env2] of Object.entries(cfg.envs)) {
35479
35911
  lines.push(`${env2.domain} {${tlsDirective}`);
35480
- lines.push(` reverse_proxy arc-${name}:5005`);
35912
+ if (cfg.observability?.enabled) {
35913
+ lines.push(" handle_path /otel/* {");
35914
+ lines.push(" reverse_proxy otel-collector:4318");
35915
+ lines.push(" }");
35916
+ lines.push(" handle {");
35917
+ lines.push(` reverse_proxy arc-${name}:5005`);
35918
+ lines.push(" }");
35919
+ } else {
35920
+ lines.push(` reverse_proxy arc-${name}:5005`);
35921
+ }
35481
35922
  lines.push("}");
35482
35923
  lines.push("");
35483
35924
  }
35925
+ if (cfg.observability?.enabled) {
35926
+ const firstEnv = Object.values(cfg.envs)[0];
35927
+ if (firstEnv) {
35928
+ const subdomain = cfg.observability.subdomain ?? "observability";
35929
+ const apex = apexOf(firstEnv.domain);
35930
+ const observabilityDomain = `${subdomain}.${apex}`;
35931
+ lines.push(`${observabilityDomain} {${tlsDirective}`);
35932
+ lines.push(" basic_auth {");
35933
+ lines.push(" import /etc/caddy/observability-htpasswd");
35934
+ lines.push(" }");
35935
+ lines.push(" reverse_proxy grafana:3000");
35936
+ lines.push("}");
35937
+ lines.push("");
35938
+ }
35939
+ }
35484
35940
  lines.push(`${cfg.registry.domain} {${tlsDirective}`);
35485
35941
  lines.push(" reverse_proxy registry:5000 {");
35486
35942
  lines.push(" header_up Host {host}");
@@ -35493,6 +35949,12 @@ function generateCaddyfile(cfg) {
35493
35949
  `) + `
35494
35950
  `;
35495
35951
  }
35952
+ function apexOf(host) {
35953
+ const parts = host.split(".");
35954
+ if (parts.length <= 2)
35955
+ return host;
35956
+ return parts.slice(-2).join(".");
35957
+ }
35496
35958
 
35497
35959
  // src/deploy/compose.ts
35498
35960
  function generateCompose({ cfg }) {
@@ -35508,6 +35970,9 @@ function generateCompose({ cfg }) {
35508
35970
  lines.push(' - "443:443"');
35509
35971
  lines.push(" volumes:");
35510
35972
  lines.push(" - ./Caddyfile:/etc/caddy/Caddyfile:ro");
35973
+ if (cfg.observability?.enabled) {
35974
+ lines.push(" - ./observability-htpasswd:/etc/caddy/observability-htpasswd:ro");
35975
+ }
35511
35976
  lines.push(" - caddy_data:/data");
35512
35977
  lines.push(" - caddy_config:/config");
35513
35978
  lines.push(" networks:");
@@ -35554,7 +36019,20 @@ function generateCompose({ cfg }) {
35554
36019
  if (usePostgres) {
35555
36020
  lines.push(` DATABASE_URL: "postgresql://arc:\${ARC_PG_PASSWORD_${upperName}:?missing ARC_PG_PASSWORD_${upperName}}@arc-db-${name}:5432/arc"`);
35556
36021
  }
35557
- const reserved = new Set(["PORT", "DATABASE_URL"]);
36022
+ if (cfg.observability?.enabled) {
36023
+ lines.push(' ARC_OTEL_ENABLED: "true"');
36024
+ lines.push(" OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4318");
36025
+ lines.push(` OTEL_SERVICE_NAME: arc-${name}`);
36026
+ lines.push(` OTEL_RESOURCE_ATTRIBUTES: "service.namespace=arc,deployment.environment=${name}"`);
36027
+ }
36028
+ const reserved = new Set([
36029
+ "PORT",
36030
+ "DATABASE_URL",
36031
+ "ARC_OTEL_ENABLED",
36032
+ "OTEL_EXPORTER_OTLP_ENDPOINT",
36033
+ "OTEL_SERVICE_NAME",
36034
+ "OTEL_RESOURCE_ATTRIBUTES"
36035
+ ]);
35558
36036
  for (const [k, v] of Object.entries(userEnv)) {
35559
36037
  if (reserved.has(k))
35560
36038
  continue;
@@ -35590,6 +36068,93 @@ function generateCompose({ cfg }) {
35590
36068
  lines.push(" - arc-net");
35591
36069
  lines.push("");
35592
36070
  }
36071
+ if (cfg.observability?.enabled) {
36072
+ lines.push(" otel-collector:");
36073
+ lines.push(" image: otel/opentelemetry-collector-contrib:0.114.0");
36074
+ lines.push(" container_name: arc-otel-collector");
36075
+ lines.push(" restart: unless-stopped");
36076
+ lines.push(' command: ["--config=/etc/otelcol-contrib/config.yaml"]');
36077
+ lines.push(" volumes:");
36078
+ lines.push(" - ./observability/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml:ro");
36079
+ lines.push(" networks: [arc-net]");
36080
+ lines.push(" expose:");
36081
+ lines.push(' - "4317" # OTLP gRPC');
36082
+ lines.push(' - "4318" # OTLP HTTP');
36083
+ lines.push(' - "8888" # collector self-metrics (Prom scrape)');
36084
+ lines.push(" depends_on:");
36085
+ lines.push(" - tempo");
36086
+ lines.push(" - loki");
36087
+ lines.push(" - prometheus");
36088
+ lines.push("");
36089
+ lines.push(" tempo:");
36090
+ lines.push(" image: grafana/tempo:2.6.1");
36091
+ lines.push(" container_name: arc-tempo");
36092
+ lines.push(" restart: unless-stopped");
36093
+ lines.push(' command: ["-config.file=/etc/tempo.yaml"]');
36094
+ lines.push(' user: "0" # tempo writes to /var/tempo, owned by root in the image');
36095
+ lines.push(" volumes:");
36096
+ lines.push(" - ./observability/tempo.yaml:/etc/tempo.yaml:ro");
36097
+ lines.push(" - tempo_data:/var/tempo");
36098
+ lines.push(" networks: [arc-net]");
36099
+ lines.push(" expose:");
36100
+ lines.push(' - "3200" # HTTP API for Grafana');
36101
+ lines.push(' - "4317" # OTLP from collector');
36102
+ lines.push("");
36103
+ lines.push(" loki:");
36104
+ lines.push(" image: grafana/loki:3.3.2");
36105
+ lines.push(" container_name: arc-loki");
36106
+ lines.push(" restart: unless-stopped");
36107
+ lines.push(' command: ["-config.file=/etc/loki/local-config.yaml"]');
36108
+ lines.push(' user: "0"');
36109
+ lines.push(" volumes:");
36110
+ lines.push(" - ./observability/loki-config.yaml:/etc/loki/local-config.yaml:ro");
36111
+ lines.push(" - loki_data:/loki");
36112
+ lines.push(" networks: [arc-net]");
36113
+ lines.push(" expose:");
36114
+ lines.push(' - "3100" # HTTP API');
36115
+ lines.push("");
36116
+ const metricsRetention = cfg.observability.retention?.metrics ?? "30d";
36117
+ lines.push(" prometheus:");
36118
+ lines.push(" image: prom/prometheus:v2.55.1");
36119
+ lines.push(" container_name: arc-prometheus");
36120
+ lines.push(" restart: unless-stopped");
36121
+ lines.push(" command:");
36122
+ lines.push(' - "--config.file=/etc/prometheus/prometheus.yml"');
36123
+ lines.push(' - "--storage.tsdb.path=/prometheus"');
36124
+ lines.push(` - "--storage.tsdb.retention.time=${metricsRetention}"`);
36125
+ lines.push(' - "--web.enable-remote-write-receiver"');
36126
+ lines.push(' - "--enable-feature=exemplar-storage"');
36127
+ lines.push(" volumes:");
36128
+ lines.push(" - ./observability/prometheus.yml:/etc/prometheus/prometheus.yml:ro");
36129
+ lines.push(" - prometheus_data:/prometheus");
36130
+ lines.push(" networks: [arc-net]");
36131
+ lines.push(" expose:");
36132
+ lines.push(' - "9090" # HTTP API + remote_write receiver');
36133
+ lines.push("");
36134
+ const adminPasswordEnv = cfg.observability.adminPasswordEnv ?? "ARC_OBSERVABILITY_PASSWORD";
36135
+ lines.push(" grafana:");
36136
+ lines.push(" image: grafana/grafana:11.4.0");
36137
+ lines.push(" container_name: arc-grafana");
36138
+ lines.push(" restart: unless-stopped");
36139
+ lines.push(" environment:");
36140
+ lines.push(" GF_SECURITY_ADMIN_USER: admin");
36141
+ lines.push(` GF_SECURITY_ADMIN_PASSWORD: \${${adminPasswordEnv}:?missing ${adminPasswordEnv}}`);
36142
+ lines.push(' GF_USERS_ALLOW_SIGN_UP: "false"');
36143
+ lines.push(' GF_AUTH_ANONYMOUS_ENABLED: "false"');
36144
+ lines.push(" volumes:");
36145
+ lines.push(" - ./observability/grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:ro");
36146
+ lines.push(" - ./observability/grafana-dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml:ro");
36147
+ lines.push(" - ./observability/grafana-dashboards:/etc/grafana/provisioning/dashboards/arc:ro");
36148
+ lines.push(" - grafana_data:/var/lib/grafana");
36149
+ lines.push(" networks: [arc-net]");
36150
+ lines.push(" expose:");
36151
+ lines.push(' - "3000" # Grafana UI (behind Caddy basic-auth)');
36152
+ lines.push(" depends_on:");
36153
+ lines.push(" - tempo");
36154
+ lines.push(" - loki");
36155
+ lines.push(" - prometheus");
36156
+ lines.push("");
36157
+ }
35593
36158
  lines.push("networks:");
35594
36159
  lines.push(" arc-net:");
35595
36160
  lines.push("");
@@ -35604,6 +36169,12 @@ function generateCompose({ cfg }) {
35604
36169
  lines.push(` arc-data-${name}:`);
35605
36170
  }
35606
36171
  }
36172
+ if (cfg.observability?.enabled) {
36173
+ lines.push(" tempo_data:");
36174
+ lines.push(" loki_data:");
36175
+ lines.push(" prometheus_data:");
36176
+ lines.push(" grafana_data:");
36177
+ }
35607
36178
  return lines.join(`
35608
36179
  `) + `
35609
36180
  `;
@@ -35633,6 +36204,707 @@ async function generateHtpasswd(user, password) {
35633
36204
  return `${user}:${hash}
35634
36205
  `;
35635
36206
  }
36207
+ async function generateCaddyBasicAuthLine(user, password) {
36208
+ if (!user || !password) {
36209
+ throw new Error("caddy basic_auth: user and password must both be non-empty");
36210
+ }
36211
+ const hash = await Bun.password.hash(password, {
36212
+ algorithm: "bcrypt",
36213
+ cost: 10
36214
+ });
36215
+ return `${user} ${hash}
36216
+ `;
36217
+ }
36218
+
36219
+ // src/deploy/observability-configs.ts
36220
+ var DEFAULT_RETENTION = {
36221
+ traces: "168h",
36222
+ logs: "168h",
36223
+ metrics: "30d"
36224
+ };
36225
+ function pickRetention(o) {
36226
+ return {
36227
+ traces: o?.retention?.traces ?? DEFAULT_RETENTION.traces,
36228
+ logs: o?.retention?.logs ?? DEFAULT_RETENTION.logs,
36229
+ metrics: o?.retention?.metrics ?? DEFAULT_RETENTION.metrics
36230
+ };
36231
+ }
36232
+ function generateOtelCollectorConfig(cfg) {
36233
+ const envNames = Object.keys(cfg.envs);
36234
+ return `# Generated by \`arc platform deploy\` \u2014 do not edit by hand.
36235
+ receivers:
36236
+ otlp:
36237
+ protocols:
36238
+ grpc:
36239
+ endpoint: 0.0.0.0:4317
36240
+ http:
36241
+ endpoint: 0.0.0.0:4318
36242
+ cors:
36243
+ allowed_origins:
36244
+ ${envNames.map((name) => ` - "https://${cfg.envs[name].domain}"`).join(`
36245
+ `)}
36246
+ allowed_headers:
36247
+ - traceparent
36248
+ - tracestate
36249
+ - content-type
36250
+
36251
+ processors:
36252
+ batch:
36253
+ timeout: 5s
36254
+ send_batch_size: 512
36255
+ send_batch_max_size: 1024
36256
+
36257
+ # Tail-based sampling \u2014 applied after a full trace has been assembled.
36258
+ # Errors and slow traces are kept 100%, everything else at 10%.
36259
+ tail_sampling:
36260
+ decision_wait: 10s
36261
+ num_traces: 50000
36262
+ expected_new_traces_per_sec: 100
36263
+ policies:
36264
+ - name: errors
36265
+ type: status_code
36266
+ status_code: { status_codes: [ERROR] }
36267
+ - name: slow
36268
+ type: latency
36269
+ latency: { threshold_ms: 500 }
36270
+ - name: random_10pct
36271
+ type: probabilistic
36272
+ probabilistic: { sampling_percentage: 10 }
36273
+
36274
+ # Drop high-cardinality / PII attributes that might slip past app-side
36275
+ # sanitization. Belt-and-suspenders before they hit long-term storage.
36276
+ attributes:
36277
+ actions:
36278
+ - key: http.request.header.authorization
36279
+ action: delete
36280
+ - key: http.request.header.cookie
36281
+ action: delete
36282
+
36283
+ exporters:
36284
+ otlp/tempo:
36285
+ endpoint: tempo:4317
36286
+ tls:
36287
+ insecure: true
36288
+
36289
+ otlphttp/loki:
36290
+ endpoint: http://loki:3100/otlp
36291
+ tls:
36292
+ insecure: true
36293
+
36294
+ prometheusremotewrite:
36295
+ endpoint: http://prometheus:9090/api/v1/write
36296
+ tls:
36297
+ insecure: true
36298
+
36299
+ extensions:
36300
+ health_check: {}
36301
+ zpages: {}
36302
+
36303
+ service:
36304
+ extensions: [health_check, zpages]
36305
+ pipelines:
36306
+ traces:
36307
+ receivers: [otlp]
36308
+ processors: [tail_sampling, attributes, batch]
36309
+ exporters: [otlp/tempo]
36310
+ logs:
36311
+ receivers: [otlp]
36312
+ processors: [attributes, batch]
36313
+ exporters: [otlphttp/loki]
36314
+ metrics:
36315
+ receivers: [otlp]
36316
+ processors: [batch]
36317
+ exporters: [prometheusremotewrite]
36318
+ `;
36319
+ }
36320
+ function generateTempoConfig(cfg) {
36321
+ const retention = pickRetention(cfg.observability);
36322
+ return `# Generated by \`arc platform deploy\` \u2014 do not edit by hand.
36323
+ server:
36324
+ http_listen_port: 3200
36325
+ grpc_listen_port: 9095
36326
+
36327
+ distributor:
36328
+ receivers:
36329
+ otlp:
36330
+ protocols:
36331
+ grpc:
36332
+ endpoint: 0.0.0.0:4317
36333
+ http:
36334
+ endpoint: 0.0.0.0:4318
36335
+
36336
+ ingester:
36337
+ trace_idle_period: 10s
36338
+ max_block_bytes: 1048576
36339
+ max_block_duration: 5m
36340
+
36341
+ compactor:
36342
+ compaction:
36343
+ block_retention: ${retention.traces}
36344
+
36345
+ storage:
36346
+ trace:
36347
+ backend: local
36348
+ local:
36349
+ path: /var/tempo/blocks
36350
+ wal:
36351
+ path: /var/tempo/wal
36352
+
36353
+ metrics_generator:
36354
+ registry:
36355
+ external_labels:
36356
+ source: tempo
36357
+ storage:
36358
+ path: /var/tempo/generator/wal
36359
+ remote_write:
36360
+ - url: http://prometheus:9090/api/v1/write
36361
+ send_exemplars: true
36362
+
36363
+ overrides:
36364
+ defaults:
36365
+ metrics_generator:
36366
+ processors: [service-graphs, span-metrics]
36367
+ `;
36368
+ }
36369
+ function generateLokiConfig(cfg) {
36370
+ const retention = pickRetention(cfg.observability);
36371
+ return `# Generated by \`arc platform deploy\` \u2014 do not edit by hand.
36372
+ auth_enabled: false
36373
+
36374
+ server:
36375
+ http_listen_port: 3100
36376
+
36377
+ common:
36378
+ instance_addr: 127.0.0.1
36379
+ path_prefix: /loki
36380
+ storage:
36381
+ filesystem:
36382
+ chunks_directory: /loki/chunks
36383
+ rules_directory: /loki/rules
36384
+ replication_factor: 1
36385
+ ring:
36386
+ kvstore:
36387
+ store: inmemory
36388
+
36389
+ schema_config:
36390
+ configs:
36391
+ - from: 2024-01-01
36392
+ store: tsdb
36393
+ object_store: filesystem
36394
+ schema: v13
36395
+ index:
36396
+ prefix: index_
36397
+ period: 24h
36398
+
36399
+ limits_config:
36400
+ retention_period: ${retention.logs}
36401
+ allow_structured_metadata: true
36402
+
36403
+ compactor:
36404
+ working_directory: /loki/compactor
36405
+ retention_enabled: true
36406
+ delete_request_store: filesystem
36407
+ `;
36408
+ }
36409
+ function generatePrometheusConfig(_cfg) {
36410
+ return `# Generated by \`arc platform deploy\` \u2014 do not edit by hand.
36411
+ global:
36412
+ scrape_interval: 15s
36413
+ evaluation_interval: 15s
36414
+
36415
+ scrape_configs:
36416
+ - job_name: prometheus
36417
+ static_configs:
36418
+ - targets: [localhost:9090]
36419
+ - job_name: otel-collector
36420
+ static_configs:
36421
+ - targets: [otel-collector:8888]
36422
+
36423
+ # remote-write inbound is enabled via the --web.enable-remote-write-receiver
36424
+ # command-line flag (compose.ts). Retention via --storage.tsdb.retention.time.
36425
+ `;
36426
+ }
36427
+ function generateGrafanaDatasources() {
36428
+ return `# Generated by \`arc platform deploy\` \u2014 do not edit by hand.
36429
+ apiVersion: 1
36430
+ datasources:
36431
+ - name: Tempo
36432
+ type: tempo
36433
+ access: proxy
36434
+ url: http://tempo:3200
36435
+ uid: tempo
36436
+ jsonData:
36437
+ tracesToLogsV2:
36438
+ datasourceUid: loki
36439
+ spanStartTimeShift: -5m
36440
+ spanEndTimeShift: 5m
36441
+ serviceMap:
36442
+ datasourceUid: prometheus
36443
+ - name: Loki
36444
+ type: loki
36445
+ access: proxy
36446
+ url: http://loki:3100
36447
+ uid: loki
36448
+ jsonData:
36449
+ derivedFields:
36450
+ - datasourceUid: tempo
36451
+ matcherRegex: "trace_id=(\\\\w+)"
36452
+ name: TraceID
36453
+ url: $\${__value.raw}
36454
+ - name: Prometheus
36455
+ type: prometheus
36456
+ access: proxy
36457
+ url: http://prometheus:9090
36458
+ uid: prometheus
36459
+ isDefault: true
36460
+ `;
36461
+ }
36462
+ function generateGrafanaDashboardsProvider() {
36463
+ return `# Generated by \`arc platform deploy\` \u2014 do not edit by hand.
36464
+ apiVersion: 1
36465
+ providers:
36466
+ - name: arc
36467
+ orgId: 1
36468
+ folder: Arc
36469
+ type: file
36470
+ disableDeletion: false
36471
+ editable: true
36472
+ updateIntervalSeconds: 30
36473
+ allowUiUpdates: true
36474
+ options:
36475
+ path: /etc/grafana/provisioning/dashboards/arc
36476
+ foldersFromFilesStructure: false
36477
+ `;
36478
+ }
36479
+ function generateArcOverviewDashboard() {
36480
+ const dashboard = {
36481
+ title: "Arc Service Overview",
36482
+ uid: "arc-overview",
36483
+ schemaVersion: 39,
36484
+ version: 1,
36485
+ refresh: "30s",
36486
+ time: { from: "now-1h", to: "now" },
36487
+ timepicker: {},
36488
+ tags: ["arc", "auto-provisioned"],
36489
+ templating: {
36490
+ list: [
36491
+ {
36492
+ name: "service",
36493
+ label: "Service",
36494
+ type: "query",
36495
+ datasource: { type: "prometheus", uid: "prometheus" },
36496
+ query: "label_values(traces_spanmetrics_calls_total, service_name)",
36497
+ refresh: 2,
36498
+ includeAll: false,
36499
+ multi: false,
36500
+ current: { text: "arc-prod", value: "arc-prod" }
36501
+ }
36502
+ ]
36503
+ },
36504
+ panels: [
36505
+ panelStat("Request rate (req/s)", { x: 0, y: 0, w: 6, h: 4 }, 'sum(rate(traces_spanmetrics_calls_total{service_name="$service", span_kind="SPAN_KIND_SERVER"}[5m]))', "reqps"),
36506
+ panelStat("Error rate (%)", { x: 6, y: 0, w: 6, h: 4 }, 'sum(rate(traces_spanmetrics_calls_total{service_name="$service", span_kind="SPAN_KIND_SERVER", status_code="STATUS_CODE_ERROR"}[5m])) / clamp_min(sum(rate(traces_spanmetrics_calls_total{service_name="$service", span_kind="SPAN_KIND_SERVER"}[5m])), 0.001) * 100', "percent", { red: 1, orange: 0.1 }),
36507
+ panelStat("P99 latency", { x: 12, y: 0, w: 6, h: 4 }, 'histogram_quantile(0.99, sum(rate(traces_spanmetrics_latency_bucket{service_name="$service", span_kind="SPAN_KIND_SERVER"}[5m])) by (le))', "ms", { red: 1000, orange: 300 }),
36508
+ panelStat("Active commands/sec", { x: 18, y: 0, w: 6, h: 4 }, 'sum(rate(arc_commands_total{service_name="$service"}[5m]))', "ops"),
36509
+ panelTimeseries("Request rate by route", { x: 0, y: 4, w: 12, h: 8 }, 'sum by (span_name) (rate(traces_spanmetrics_calls_total{service_name="$service", span_kind="SPAN_KIND_SERVER"}[1m]))', "{{span_name}}", "reqps"),
36510
+ panelTimeseries("Latency percentiles", { x: 12, y: 4, w: 12, h: 8 }, [
36511
+ {
36512
+ expr: 'histogram_quantile(0.5, sum(rate(traces_spanmetrics_latency_bucket{service_name="$service", span_kind="SPAN_KIND_SERVER"}[5m])) by (le))',
36513
+ legend: "p50"
36514
+ },
36515
+ {
36516
+ expr: 'histogram_quantile(0.95, sum(rate(traces_spanmetrics_latency_bucket{service_name="$service", span_kind="SPAN_KIND_SERVER"}[5m])) by (le))',
36517
+ legend: "p95"
36518
+ },
36519
+ {
36520
+ expr: 'histogram_quantile(0.99, sum(rate(traces_spanmetrics_latency_bucket{service_name="$service", span_kind="SPAN_KIND_SERVER"}[5m])) by (le))',
36521
+ legend: "p99"
36522
+ }
36523
+ ], "ms"),
36524
+ panelTimeseries("Commands per second", { x: 0, y: 12, w: 12, h: 8 }, 'sum by (arc_command_name) (rate(arc_commands_total{service_name="$service"}[1m]))', "{{arc_command_name}}", "ops"),
36525
+ panelTimeseries("Command p95 latency", { x: 12, y: 12, w: 12, h: 8 }, 'histogram_quantile(0.95, sum by (arc_command_name, le) (rate(arc_command_duration_ms_milliseconds_bucket{service_name="$service"}[5m])))', "{{arc_command_name}}", "ms"),
36526
+ panelTimeseries("DB find ops/sec by collection", { x: 0, y: 20, w: 12, h: 8 }, 'sum by (db_collection_name) (rate(arc_db_find_ms_milliseconds_count{service_name="$service"}[1m]))', "{{db_collection_name}}", "ops"),
36527
+ panelTimeseries("DB find p95 latency", { x: 12, y: 20, w: 12, h: 8 }, 'histogram_quantile(0.95, sum by (db_collection_name, le) (rate(arc_db_find_ms_milliseconds_bucket{service_name="$service"}[5m])))', "{{db_collection_name}}", "ms"),
36528
+ {
36529
+ title: "Recent error logs",
36530
+ type: "logs",
36531
+ gridPos: { x: 0, y: 28, w: 24, h: 8 },
36532
+ datasource: { type: "loki", uid: "loki" },
36533
+ targets: [
36534
+ {
36535
+ expr: '{service_name="$service"} |= `ERROR`',
36536
+ refId: "A"
36537
+ }
36538
+ ],
36539
+ options: {
36540
+ showTime: true,
36541
+ showLabels: false,
36542
+ showCommonLabels: false,
36543
+ wrapLogMessage: true,
36544
+ enableLogDetails: true,
36545
+ dedupStrategy: "none",
36546
+ sortOrder: "Descending"
36547
+ }
36548
+ }
36549
+ ]
36550
+ };
36551
+ return JSON.stringify(dashboard, null, 2);
36552
+ }
36553
+ function generateArcTracesDashboard() {
36554
+ const dashboard = {
36555
+ title: "Arc Recent Traces",
36556
+ uid: "arc-traces",
36557
+ schemaVersion: 39,
36558
+ version: 1,
36559
+ refresh: "1m",
36560
+ time: { from: "now-1h", to: "now" },
36561
+ tags: ["arc", "auto-provisioned"],
36562
+ templating: {
36563
+ list: [
36564
+ {
36565
+ name: "service",
36566
+ label: "Service",
36567
+ type: "query",
36568
+ datasource: { type: "prometheus", uid: "prometheus" },
36569
+ query: "label_values(traces_spanmetrics_calls_total, service_name)",
36570
+ refresh: 2,
36571
+ current: { text: "arc-prod", value: "arc-prod" }
36572
+ }
36573
+ ]
36574
+ },
36575
+ panels: [
36576
+ {
36577
+ title: "Slowest traces (p95 \u2265 500ms)",
36578
+ type: "traces",
36579
+ gridPos: { x: 0, y: 0, w: 24, h: 14 },
36580
+ datasource: { type: "tempo", uid: "tempo" },
36581
+ targets: [
36582
+ {
36583
+ queryType: "traceql",
36584
+ query: '{resource.service.name = "$service" && duration > 500ms}',
36585
+ refId: "A",
36586
+ limit: 20
36587
+ }
36588
+ ]
36589
+ },
36590
+ {
36591
+ title: "Recent errors",
36592
+ type: "traces",
36593
+ gridPos: { x: 0, y: 14, w: 24, h: 14 },
36594
+ datasource: { type: "tempo", uid: "tempo" },
36595
+ targets: [
36596
+ {
36597
+ queryType: "traceql",
36598
+ query: '{resource.service.name = "$service" && status = error}',
36599
+ refId: "A",
36600
+ limit: 20
36601
+ }
36602
+ ]
36603
+ }
36604
+ ]
36605
+ };
36606
+ return JSON.stringify(dashboard, null, 2);
36607
+ }
36608
+ function generateArcServiceMapDashboard() {
36609
+ const dashboard = {
36610
+ title: "Arc Service Map",
36611
+ uid: "arc-service-map",
36612
+ schemaVersion: 39,
36613
+ version: 1,
36614
+ refresh: "30s",
36615
+ time: { from: "now-1h", to: "now" },
36616
+ tags: ["arc", "auto-provisioned"],
36617
+ panels: [
36618
+ panelTimeseries("Service-to-service request rate", { x: 0, y: 0, w: 24, h: 9 }, "sum by (client, server) (rate(traces_service_graph_request_total[1m]))", "{{client}} \u2192 {{server}}", "reqps"),
36619
+ panelTimeseries("Inter-service p95 latency", { x: 0, y: 9, w: 24, h: 9 }, "histogram_quantile(0.95, sum by (client, server, le) (rate(traces_service_graph_request_server_seconds_bucket[5m]))) * 1000", "{{client}} \u2192 {{server}}", "ms"),
36620
+ {
36621
+ title: "Service-graph edges (last 5m)",
36622
+ type: "table",
36623
+ gridPos: { x: 0, y: 18, w: 24, h: 8 },
36624
+ datasource: { type: "prometheus", uid: "prometheus" },
36625
+ targets: [
36626
+ {
36627
+ expr: "sum by (client, server) (increase(traces_service_graph_request_total[5m]))",
36628
+ refId: "A",
36629
+ instant: true,
36630
+ format: "table"
36631
+ }
36632
+ ],
36633
+ transformations: [
36634
+ { id: "organize", options: { excludeByName: { Time: true } } },
36635
+ { id: "sortBy", options: { sort: [{ field: "Value", desc: true }] } }
36636
+ ]
36637
+ }
36638
+ ]
36639
+ };
36640
+ return JSON.stringify(dashboard, null, 2);
36641
+ }
36642
+ function generateArcLogsDashboard() {
36643
+ const dashboard = {
36644
+ title: "Arc Logs Explorer",
36645
+ uid: "arc-logs",
36646
+ schemaVersion: 39,
36647
+ version: 1,
36648
+ refresh: "30s",
36649
+ time: { from: "now-1h", to: "now" },
36650
+ tags: ["arc", "auto-provisioned"],
36651
+ templating: {
36652
+ list: [
36653
+ {
36654
+ name: "service",
36655
+ label: "Service",
36656
+ type: "query",
36657
+ datasource: { type: "loki", uid: "loki" },
36658
+ query: "label_values(service_name)",
36659
+ refresh: 2,
36660
+ current: { text: "arc-prod", value: "arc-prod" }
36661
+ },
36662
+ {
36663
+ name: "search",
36664
+ label: "Filter",
36665
+ type: "textbox",
36666
+ query: "",
36667
+ current: { text: "", value: "" }
36668
+ }
36669
+ ]
36670
+ },
36671
+ panels: [
36672
+ panelStat("Logs ingested (1h)", { x: 0, y: 0, w: 6, h: 4 }, 'sum(increase({service_name="$service"}[1h]))', "short"),
36673
+ panelStat("Errors (1h)", { x: 6, y: 0, w: 6, h: 4 }, 'sum(increase({service_name="$service", severity_text=~"ERROR|FATAL"}[1h]))', "short", { orange: 1, red: 50 }),
36674
+ {
36675
+ title: "Log volume by severity",
36676
+ type: "timeseries",
36677
+ gridPos: { x: 12, y: 0, w: 12, h: 8 },
36678
+ datasource: { type: "loki", uid: "loki" },
36679
+ targets: [
36680
+ {
36681
+ expr: 'sum by (severity_text) (count_over_time({service_name="$service"} |~ "$search" [$__interval]))',
36682
+ refId: "A",
36683
+ legendFormat: "{{severity_text}}"
36684
+ }
36685
+ ],
36686
+ fieldConfig: {
36687
+ defaults: {
36688
+ unit: "short",
36689
+ custom: {
36690
+ drawStyle: "bars",
36691
+ fillOpacity: 50,
36692
+ lineWidth: 0,
36693
+ stacking: { mode: "normal", group: "A" }
36694
+ }
36695
+ },
36696
+ overrides: []
36697
+ },
36698
+ options: {
36699
+ legend: { displayMode: "list", placement: "bottom", showLegend: true },
36700
+ tooltip: { mode: "multi", sort: "desc" }
36701
+ }
36702
+ },
36703
+ {
36704
+ title: "Live tail (filtered by $search)",
36705
+ type: "logs",
36706
+ gridPos: { x: 0, y: 8, w: 24, h: 18 },
36707
+ datasource: { type: "loki", uid: "loki" },
36708
+ targets: [
36709
+ {
36710
+ expr: '{service_name="$service"} |~ "$search"',
36711
+ refId: "A"
36712
+ }
36713
+ ],
36714
+ options: {
36715
+ showTime: true,
36716
+ showLabels: false,
36717
+ showCommonLabels: false,
36718
+ wrapLogMessage: true,
36719
+ enableLogDetails: true,
36720
+ dedupStrategy: "none",
36721
+ sortOrder: "Descending"
36722
+ }
36723
+ }
36724
+ ]
36725
+ };
36726
+ return JSON.stringify(dashboard, null, 2);
36727
+ }
36728
+ function generateArcSamplingDashboard() {
36729
+ const dashboard = {
36730
+ title: "Arc Tail Sampling & Collector Health",
36731
+ uid: "arc-sampling",
36732
+ schemaVersion: 39,
36733
+ version: 1,
36734
+ refresh: "30s",
36735
+ time: { from: "now-3h", to: "now" },
36736
+ tags: ["arc", "auto-provisioned"],
36737
+ panels: [
36738
+ panelStat("Spans received/sec", { x: 0, y: 0, w: 6, h: 4 }, "sum(rate(otelcol_receiver_accepted_spans[5m]))", "ops"),
36739
+ panelStat("Spans exported/sec (sampled)", { x: 6, y: 0, w: 6, h: 4 }, "sum(rate(otelcol_exporter_sent_spans[5m]))", "ops"),
36740
+ panelStat("Spans dropped (refused) / 5m", { x: 12, y: 0, w: 6, h: 4 }, "sum(increase(otelcol_receiver_refused_spans[5m]))", "short", { orange: 1, red: 100 }),
36741
+ panelStat("Export failures / 5m", { x: 18, y: 0, w: 6, h: 4 }, "sum(increase(otelcol_exporter_send_failed_spans[5m]))", "short", { orange: 1, red: 50 }),
36742
+ panelTimeseries("Tail-sampling policy decisions", { x: 0, y: 4, w: 12, h: 8 }, 'sum by (policy) (rate(otelcol_processor_tail_sampling_count_traces_sampled{sampled="true"}[1m]))', "{{policy}} sampled", "ops"),
36743
+ panelTimeseries("Receiver vs Exporter (effective sampling rate)", { x: 12, y: 4, w: 12, h: 8 }, [
36744
+ {
36745
+ expr: "sum(rate(otelcol_receiver_accepted_spans[1m]))",
36746
+ legend: "received"
36747
+ },
36748
+ {
36749
+ expr: "sum(rate(otelcol_exporter_sent_spans[1m]))",
36750
+ legend: "exported"
36751
+ }
36752
+ ], "ops"),
36753
+ panelTimeseries("Collector queue size (BatchSpanProcessor)", { x: 0, y: 12, w: 12, h: 8 }, "otelcol_processor_batch_batch_send_size_sum / clamp_min(otelcol_processor_batch_batch_send_size_count, 1)", "avg batch size", "short"),
36754
+ panelTimeseries("Collector process memory", { x: 12, y: 12, w: 12, h: 8 }, 'process_resident_memory_bytes{job="otel-collector"}', "RSS", "bytes")
36755
+ ]
36756
+ };
36757
+ return JSON.stringify(dashboard, null, 2);
36758
+ }
36759
+ function generateArcCommandDashboard() {
36760
+ const dashboard = {
36761
+ title: "Arc Command Drill-Down",
36762
+ uid: "arc-command",
36763
+ schemaVersion: 39,
36764
+ version: 1,
36765
+ refresh: "30s",
36766
+ time: { from: "now-3h", to: "now" },
36767
+ tags: ["arc", "auto-provisioned"],
36768
+ templating: {
36769
+ list: [
36770
+ {
36771
+ name: "service",
36772
+ label: "Service",
36773
+ type: "query",
36774
+ datasource: { type: "prometheus", uid: "prometheus" },
36775
+ query: "label_values(arc_commands_total, service_name)",
36776
+ refresh: 2,
36777
+ current: { text: "arc-prod", value: "arc-prod" }
36778
+ },
36779
+ {
36780
+ name: "command",
36781
+ label: "Command",
36782
+ type: "query",
36783
+ datasource: { type: "prometheus", uid: "prometheus" },
36784
+ query: 'label_values(arc_commands_total{service_name="$service"}, arc_command_name)',
36785
+ refresh: 2,
36786
+ includeAll: false,
36787
+ multi: false
36788
+ }
36789
+ ]
36790
+ },
36791
+ panels: [
36792
+ panelStat("Call rate", { x: 0, y: 0, w: 6, h: 4 }, 'sum(rate(arc_commands_total{service_name="$service", arc_command_name="$command"}[5m]))', "ops"),
36793
+ panelStat("P50 latency", { x: 6, y: 0, w: 6, h: 4 }, 'histogram_quantile(0.5, sum by (le) (rate(arc_command_duration_ms_milliseconds_bucket{service_name="$service", arc_command_name="$command"}[5m])))', "ms"),
36794
+ panelStat("P95 latency", { x: 12, y: 0, w: 6, h: 4 }, 'histogram_quantile(0.95, sum by (le) (rate(arc_command_duration_ms_milliseconds_bucket{service_name="$service", arc_command_name="$command"}[5m])))', "ms", { orange: 200, red: 1000 }),
36795
+ panelStat("P99 latency", { x: 18, y: 0, w: 6, h: 4 }, 'histogram_quantile(0.99, sum by (le) (rate(arc_command_duration_ms_milliseconds_bucket{service_name="$service", arc_command_name="$command"}[5m])))', "ms", { orange: 500, red: 2000 }),
36796
+ panelTimeseries("Call rate over time", { x: 0, y: 4, w: 12, h: 8 }, 'sum(rate(arc_commands_total{service_name="$service", arc_command_name="$command"}[1m]))', "calls/s", "ops"),
36797
+ panelTimeseries("Latency percentiles", { x: 12, y: 4, w: 12, h: 8 }, [
36798
+ {
36799
+ expr: 'histogram_quantile(0.5, sum by (le) (rate(arc_command_duration_ms_milliseconds_bucket{service_name="$service", arc_command_name="$command"}[5m])))',
36800
+ legend: "p50"
36801
+ },
36802
+ {
36803
+ expr: 'histogram_quantile(0.95, sum by (le) (rate(arc_command_duration_ms_milliseconds_bucket{service_name="$service", arc_command_name="$command"}[5m])))',
36804
+ legend: "p95"
36805
+ },
36806
+ {
36807
+ expr: 'histogram_quantile(0.99, sum by (le) (rate(arc_command_duration_ms_milliseconds_bucket{service_name="$service", arc_command_name="$command"}[5m])))',
36808
+ legend: "p99"
36809
+ }
36810
+ ], "ms"),
36811
+ {
36812
+ title: "Recent traces (sampled)",
36813
+ type: "traces",
36814
+ gridPos: { x: 0, y: 12, w: 24, h: 14 },
36815
+ datasource: { type: "tempo", uid: "tempo" },
36816
+ targets: [
36817
+ {
36818
+ queryType: "traceql",
36819
+ query: '{resource.service.name = "$service" && name = "command.$command"}',
36820
+ refId: "A",
36821
+ limit: 20
36822
+ }
36823
+ ]
36824
+ }
36825
+ ]
36826
+ };
36827
+ return JSON.stringify(dashboard, null, 2);
36828
+ }
36829
+ function generateObservabilityConfigs(cfg) {
36830
+ return {
36831
+ "observability/otel-collector-config.yaml": generateOtelCollectorConfig(cfg),
36832
+ "observability/tempo.yaml": generateTempoConfig(cfg),
36833
+ "observability/loki-config.yaml": generateLokiConfig(cfg),
36834
+ "observability/prometheus.yml": generatePrometheusConfig(cfg),
36835
+ "observability/grafana-datasources.yaml": generateGrafanaDatasources(),
36836
+ "observability/grafana-dashboards.yaml": generateGrafanaDashboardsProvider(),
36837
+ "observability/grafana-dashboards/arc-overview.json": generateArcOverviewDashboard(),
36838
+ "observability/grafana-dashboards/arc-traces.json": generateArcTracesDashboard(),
36839
+ "observability/grafana-dashboards/arc-service-map.json": generateArcServiceMapDashboard(),
36840
+ "observability/grafana-dashboards/arc-logs.json": generateArcLogsDashboard(),
36841
+ "observability/grafana-dashboards/arc-sampling.json": generateArcSamplingDashboard(),
36842
+ "observability/grafana-dashboards/arc-command.json": generateArcCommandDashboard()
36843
+ };
36844
+ }
36845
+ function panelStat(title, gridPos, expr, unit, thresholds) {
36846
+ const steps = [
36847
+ { color: "green", value: null }
36848
+ ];
36849
+ if (thresholds?.orange !== undefined) {
36850
+ steps.push({ color: "orange", value: thresholds.orange });
36851
+ }
36852
+ if (thresholds?.red !== undefined) {
36853
+ steps.push({ color: "red", value: thresholds.red });
36854
+ }
36855
+ return {
36856
+ title,
36857
+ type: "stat",
36858
+ gridPos,
36859
+ datasource: { type: "prometheus", uid: "prometheus" },
36860
+ targets: [{ expr, refId: "A", legendFormat: title }],
36861
+ fieldConfig: {
36862
+ defaults: {
36863
+ unit,
36864
+ thresholds: { mode: "absolute", steps }
36865
+ },
36866
+ overrides: []
36867
+ },
36868
+ options: {
36869
+ colorMode: "value",
36870
+ graphMode: "area",
36871
+ justifyMode: "auto",
36872
+ reduceOptions: { calcs: ["lastNotNull"], fields: "", values: false },
36873
+ textMode: "auto"
36874
+ }
36875
+ };
36876
+ }
36877
+ function panelTimeseries(title, gridPos, query, legend, unit) {
36878
+ const targets = Array.isArray(query) ? query.map((q, i) => ({
36879
+ expr: q.expr,
36880
+ refId: String.fromCharCode(65 + i),
36881
+ legendFormat: q.legend
36882
+ })) : [{ expr: query, refId: "A", legendFormat: legend }];
36883
+ return {
36884
+ title,
36885
+ type: "timeseries",
36886
+ gridPos,
36887
+ datasource: { type: "prometheus", uid: "prometheus" },
36888
+ targets,
36889
+ fieldConfig: {
36890
+ defaults: {
36891
+ unit,
36892
+ custom: {
36893
+ drawStyle: "line",
36894
+ lineInterpolation: "smooth",
36895
+ lineWidth: 1.5,
36896
+ fillOpacity: 10,
36897
+ showPoints: "never"
36898
+ }
36899
+ },
36900
+ overrides: []
36901
+ },
36902
+ options: {
36903
+ legend: { displayMode: "list", placement: "bottom", showLegend: true },
36904
+ tooltip: { mode: "multi", sort: "desc" }
36905
+ }
36906
+ };
36907
+ }
35636
36908
 
35637
36909
  // src/deploy/terraform.ts
35638
36910
  import { spawn as nodeSpawn2 } from "child_process";
@@ -35742,10 +37014,11 @@ function applyDeployGlobals(globals) {
35742
37014
  }
35743
37015
  }
35744
37016
  }
35745
- function ensurePersistedSecret(rootDir, envName, key, generate) {
37017
+ function ensurePersistedSecret(rootDir, scope, key, generate) {
35746
37018
  if (process.env[key])
35747
37019
  return process.env[key];
35748
- const path4 = join14(rootDir, `deploy.arc.${envName}.env`);
37020
+ const fileName = scope === "globals" ? "deploy.arc.env" : `deploy.arc.${scope}.env`;
37021
+ const path4 = join14(rootDir, fileName);
35749
37022
  if (existsSync13(path4)) {
35750
37023
  const existing = parseEnvFile(readFileSync11(path4, "utf-8"), path4);
35751
37024
  if (existing[key]) {
@@ -35923,6 +37196,31 @@ function validateDeployConfig(input) {
35923
37196
  }
35924
37197
  validated.envs[name] = { domain, envVars, db };
35925
37198
  }
37199
+ const observabilityRaw = input.observability;
37200
+ if (observabilityRaw !== undefined) {
37201
+ if (!isObject(observabilityRaw))
37202
+ throw cfgErr("observability", "object");
37203
+ const enabledRaw = observabilityRaw.enabled;
37204
+ if (typeof enabledRaw !== "boolean")
37205
+ throw cfgErr("observability.enabled", "boolean");
37206
+ const retentionRaw = observabilityRaw.retention;
37207
+ let retention;
37208
+ if (retentionRaw !== undefined) {
37209
+ if (!isObject(retentionRaw))
37210
+ throw cfgErr("observability.retention", "object");
37211
+ retention = {
37212
+ traces: optionalString(retentionRaw, "observability.retention.traces"),
37213
+ logs: optionalString(retentionRaw, "observability.retention.logs"),
37214
+ metrics: optionalString(retentionRaw, "observability.retention.metrics")
37215
+ };
37216
+ }
37217
+ validated.observability = {
37218
+ enabled: enabledRaw,
37219
+ subdomain: optionalString(observabilityRaw, "observability.subdomain") ?? "observability",
37220
+ adminPasswordEnv: optionalString(observabilityRaw, "observability.adminPasswordEnv") ?? "ARC_OBSERVABILITY_PASSWORD",
37221
+ retention
37222
+ };
37223
+ }
35926
37224
  const provision = input.provision;
35927
37225
  if (provision !== undefined) {
35928
37226
  if (!isObject(provision))
@@ -36221,6 +37519,12 @@ async function bootstrap(inputs) {
36221
37519
  await upStack(inputs);
36222
37520
  ok("Docker stack up");
36223
37521
  }
37522
+ if (cfg.observability?.enabled) {
37523
+ log2("Ensuring observability sidecars are running...");
37524
+ const obsServices = ["otel-collector", "tempo", "loki", "prometheus", "grafana"];
37525
+ await assertExec(cfg.target, `cd ${cfg.target.remoteDir} && docker compose pull --ignore-pull-failures ${obsServices.join(" ")} && docker compose up -d ${obsServices.join(" ")}`);
37526
+ ok("Observability stack up");
37527
+ }
36224
37528
  await writeStateMarker(cfg.target, {
36225
37529
  cliVersion: inputs.cliVersion,
36226
37530
  configHash: inputs.configHash,
@@ -36258,6 +37562,23 @@ async function upStack(inputs) {
36258
37562
  writeFileSync13(join17(workDir, "htpasswd"), htpasswdLine);
36259
37563
  writeFileSync13(join17(workDir, "Caddyfile"), generateCaddyfile(cfg));
36260
37564
  writeFileSync13(join17(workDir, "docker-compose.yml"), generateCompose({ cfg }));
37565
+ let observabilityFiles = null;
37566
+ let observabilityHtpasswd = null;
37567
+ if (cfg.observability?.enabled) {
37568
+ observabilityFiles = generateObservabilityConfigs(cfg);
37569
+ const adminPasswordEnv = cfg.observability.adminPasswordEnv ?? "ARC_OBSERVABILITY_PASSWORD";
37570
+ const adminPassword = process.env[adminPasswordEnv];
37571
+ if (!adminPassword) {
37572
+ throw new Error(`bootstrap: ${adminPasswordEnv} not set \u2014 observability needs a Grafana admin password.`);
37573
+ }
37574
+ observabilityHtpasswd = await generateCaddyBasicAuthLine("admin", adminPassword);
37575
+ for (const [relPath, contents] of Object.entries(observabilityFiles)) {
37576
+ const fullPath = join17(workDir, relPath);
37577
+ mkdirSync12(dirname9(fullPath), { recursive: true });
37578
+ writeFileSync13(fullPath, contents);
37579
+ }
37580
+ writeFileSync13(join17(workDir, "observability-htpasswd"), observabilityHtpasswd);
37581
+ }
36261
37582
  await assertExec(cfg.target, `sudo mkdir -p ${cfg.target.remoteDir} && sudo chown ${cfg.target.user}:${cfg.target.user} ${cfg.target.remoteDir}`);
36262
37583
  for (const name of Object.keys(cfg.envs)) {
36263
37584
  await assertExec(cfg.target, `mkdir -p ${cfg.target.remoteDir}/${name}`);
@@ -36266,7 +37587,26 @@ async function upStack(inputs) {
36266
37587
  await scpUpload(cfg.target, join17(workDir, "Caddyfile"), `${cfg.target.remoteDir}/Caddyfile`);
36267
37588
  await scpUpload(cfg.target, join17(workDir, "docker-compose.yml"), `${cfg.target.remoteDir}/docker-compose.yml`);
36268
37589
  await scpUpload(cfg.target, join17(workDir, "htpasswd"), `${cfg.target.remoteDir}/registry-auth/htpasswd`);
37590
+ if (observabilityFiles && observabilityHtpasswd) {
37591
+ await assertExec(cfg.target, `mkdir -p ${cfg.target.remoteDir}/observability/grafana-dashboards`);
37592
+ for (const relPath of Object.keys(observabilityFiles)) {
37593
+ const localDir = dirname9(join17(workDir, relPath));
37594
+ mkdirSync12(localDir, { recursive: true });
37595
+ }
37596
+ for (const relPath of Object.keys(observabilityFiles)) {
37597
+ await scpUpload(cfg.target, join17(workDir, relPath), `${cfg.target.remoteDir}/${relPath}`);
37598
+ }
37599
+ await scpUpload(cfg.target, join17(workDir, "observability-htpasswd"), `${cfg.target.remoteDir}/observability-htpasswd`);
37600
+ }
36269
37601
  await assertExec(cfg.target, `touch ${cfg.target.remoteDir}/.env`);
37602
+ if (cfg.observability?.enabled) {
37603
+ const key = cfg.observability.adminPasswordEnv ?? "ARC_OBSERVABILITY_PASSWORD";
37604
+ const value = process.env[key];
37605
+ if (!value) {
37606
+ throw new Error(`bootstrap: ${key} not set \u2014 observability needs a Grafana admin password.`);
37607
+ }
37608
+ await writeEnvLine(cfg.target, `${cfg.target.remoteDir}/.env`, key, value);
37609
+ }
36270
37610
  for (const [name, env2] of Object.entries(cfg.envs)) {
36271
37611
  if (env2.db?.type !== "postgres")
36272
37612
  continue;
@@ -36429,8 +37769,8 @@ import {
36429
37769
  writeFileSync as writeFileSync14
36430
37770
  } from "fs";
36431
37771
  import { tmpdir as tmpdir3 } from "os";
36432
- import { dirname as dirname8, join as join18 } from "path";
36433
- import { fileURLToPath as fileURLToPath6 } from "url";
37772
+ import { dirname as dirname10, join as join18 } from "path";
37773
+ import { fileURLToPath as fileURLToPath7 } from "url";
36434
37774
 
36435
37775
  // src/deploy/image-template.ts
36436
37776
  function generateDockerfile(inputs) {
@@ -36522,8 +37862,8 @@ function embedCliBundle(ws) {
36522
37862
  copyFileSync2(source, target);
36523
37863
  }
36524
37864
  function locateCliBundle() {
36525
- const here = fileURLToPath6(import.meta.url);
36526
- let cur = dirname8(here);
37865
+ const here = fileURLToPath7(import.meta.url);
37866
+ let cur = dirname10(here);
36527
37867
  while (cur !== "/" && cur !== "") {
36528
37868
  const candidate = join18(cur, "package.json");
36529
37869
  if (existsSync16(candidate)) {
@@ -36541,7 +37881,7 @@ function locateCliBundle() {
36541
37881
  throw e;
36542
37882
  }
36543
37883
  }
36544
- const parent = dirname8(cur);
37884
+ const parent = dirname10(cur);
36545
37885
  if (parent === cur)
36546
37886
  break;
36547
37887
  cur = parent;
@@ -37394,6 +38734,10 @@ async function platformDeploy(envArg, options = {}) {
37394
38734
  for (const pg of pgEnvs) {
37395
38735
  ensurePersistedSecret(ws.rootDir, pg.name, pg.passwordKey, () => crypto.randomUUID().replace(/-/g, ""));
37396
38736
  }
38737
+ if (cfg.observability?.enabled) {
38738
+ const key = cfg.observability.adminPasswordEnv ?? "ARC_OBSERVABILITY_PASSWORD";
38739
+ ensurePersistedSecret(ws.rootDir, "globals", key, () => crypto.randomUUID().replace(/-/g, ""));
38740
+ }
37397
38741
  const targetEnvs = envArg ? envArg in cfg.envs ? [envArg] : (() => {
37398
38742
  err(`Unknown env "${envArg}". Known: ${Object.keys(cfg.envs).join(", ")}`);
37399
38743
  process.exit(1);
@@ -37468,8 +38812,8 @@ async function platformDeploy(envArg, options = {}) {
37468
38812
  }
37469
38813
  function readCliVersion2() {
37470
38814
  try {
37471
- let cur = dirname9(fileURLToPath7(import.meta.url));
37472
- const root = dirname9(cur).startsWith("/") ? "/" : ".";
38815
+ let cur = dirname11(fileURLToPath8(import.meta.url));
38816
+ const root = dirname11(cur).startsWith("/") ? "/" : ".";
37473
38817
  while (cur !== root && cur !== "") {
37474
38818
  const candidate = join19(cur, "package.json");
37475
38819
  if (existsSync17(candidate)) {
@@ -37478,7 +38822,7 @@ function readCliVersion2() {
37478
38822
  return pkg.version ?? "unknown";
37479
38823
  }
37480
38824
  }
37481
- const parent = dirname9(cur);
38825
+ const parent = dirname11(cur);
37482
38826
  if (parent === cur)
37483
38827
  break;
37484
38828
  cur = parent;
@@ -37493,6 +38837,7 @@ async function hashDeployConfig(rootDir) {
37493
38837
  const content = readFileSync14(p2);
37494
38838
  const hasher = new Bun.CryptoHasher("sha256");
37495
38839
  hasher.update(content);
38840
+ hasher.update(readCliVersion2());
37496
38841
  return hasher.digest("hex").slice(0, 16);
37497
38842
  }
37498
38843
 
@@ -37668,14 +39013,16 @@ function filterEventsForTokens(tokens, events, eventDefinitions) {
37668
39013
  // ../host/src/context-handler.ts
37669
39014
  class ContextHandler {
37670
39015
  context;
39016
+ telemetry;
37671
39017
  model;
37672
39018
  dataStorage;
37673
39019
  eventPublisher;
37674
39020
  eventDefinitions = new Map;
37675
39021
  hostEventIdCounter = 0;
37676
39022
  initialized = false;
37677
- constructor(context, dbAdapter) {
39023
+ constructor(context, dbAdapter, telemetry) {
37678
39024
  this.context = context;
39025
+ this.telemetry = telemetry;
37679
39026
  this.dataStorage = new MasterDataStorage(dbAdapter);
37680
39027
  this.eventPublisher = new LocalEventPublisher(this.dataStorage);
37681
39028
  this.model = new Model(context, {
@@ -37723,27 +39070,49 @@ class ContextHandler {
37723
39070
  }
37724
39071
  }
37725
39072
  async executeCommand(commandName, params, rawToken) {
37726
- const scoped = new ScopedModel(this.model, "request");
37727
- if (rawToken)
37728
- scoped.setToken(rawToken);
37729
- const mutations = mutationExecutor(scoped);
37730
- let command;
37731
- if (commandName.includes(".")) {
37732
- const [elementName, methodName] = commandName.split(".");
37733
- const element = mutations[elementName];
37734
- command = element?.[methodName];
37735
- } else {
37736
- command = mutations[commandName];
37737
- }
37738
- if (!command) {
37739
- throw new Error(`Command '${commandName}' not found`);
37740
- }
39073
+ const includePayloads = this.telemetry?.shouldIncludePayloads() ?? false;
39074
+ const baseAttrs = {
39075
+ "rpc.system": "arc",
39076
+ "rpc.method": commandName,
39077
+ "arc.command.name": commandName,
39078
+ "arc.command.params_size": params ? JSON.stringify(params).length : 0,
39079
+ ...includePayloads ? { "arc.command.params": params } : {}
39080
+ };
39081
+ const runCommand = async () => {
39082
+ const scoped = new ScopedModel(this.model, "request");
39083
+ if (rawToken)
39084
+ scoped.setToken(rawToken);
39085
+ const mutations = mutationExecutor(scoped);
39086
+ let command;
39087
+ if (commandName.includes(".")) {
39088
+ const [elementName, methodName] = commandName.split(".");
39089
+ const element = mutations[elementName];
39090
+ command = element?.[methodName];
39091
+ } else {
39092
+ command = mutations[commandName];
39093
+ }
39094
+ if (!command) {
39095
+ throw new Error(`Command '${commandName}' not found`);
39096
+ }
39097
+ try {
39098
+ return await command(params);
39099
+ } catch (error) {
39100
+ console.error(`[ARC] Command '${commandName}' failed:`, error);
39101
+ throw error;
39102
+ }
39103
+ };
39104
+ if (!this.telemetry)
39105
+ return runCommand();
39106
+ const start = Date.now();
37741
39107
  try {
37742
- const result = await command(params);
37743
- return result;
37744
- } catch (error) {
37745
- console.error(`[ARC] Command '${commandName}' failed:`, error);
37746
- throw error;
39108
+ return await this.telemetry.startSpan(`command.${commandName}`, runCommand, { attributes: baseAttrs });
39109
+ } finally {
39110
+ this.telemetry.measureSince("arc.command.duration_ms", start, {
39111
+ "arc.command.name": commandName
39112
+ });
39113
+ this.telemetry.incrementCounter("arc.commands.total", 1, {
39114
+ "arc.command.name": commandName
39115
+ });
37747
39116
  }
37748
39117
  }
37749
39118
  async persistEvents(events, clientId, token) {
@@ -38806,7 +40175,7 @@ async function createArcServer(config) {
38806
40175
  const jwtSecret = config.jwtSecret || process.env.JWT_SECRET || "arc-host-secret-change-in-production";
38807
40176
  const port = config.port || 5005;
38808
40177
  const dbAdapter = config.dbAdapterFactory(config.context);
38809
- const contextHandler = new ContextHandler(config.context, dbAdapter);
40178
+ const contextHandler = new ContextHandler(config.context, dbAdapter, config.telemetry);
38810
40179
  await contextHandler.init();
38811
40180
  const cronScheduler = new CronScheduler(contextHandler);
38812
40181
  cronScheduler.start();
@@ -38871,39 +40240,51 @@ async function createArcServer(config) {
38871
40240
  if (req.method === "OPTIONS") {
38872
40241
  return new Response(null, { headers: corsHeaders2 });
38873
40242
  }
38874
- const authHeader = req.headers.get("Authorization");
38875
- let rawToken = authHeader?.replace("Bearer ", "") || url.searchParams.get("token");
38876
- if (!rawToken) {
38877
- const cookieHeader = req.headers.get("Cookie");
38878
- if (cookieHeader) {
38879
- const match2 = cookieHeader.match(/arc_token=([^;]+)/);
38880
- if (match2)
38881
- rawToken = decodeURIComponent(match2[1]);
40243
+ const handleRequest = async (span) => {
40244
+ const authHeader = req.headers.get("Authorization");
40245
+ let rawToken = authHeader?.replace("Bearer ", "") || url.searchParams.get("token");
40246
+ if (!rawToken) {
40247
+ const cookieHeader = req.headers.get("Cookie");
40248
+ if (cookieHeader) {
40249
+ const match2 = cookieHeader.match(/arc_token=([^;]+)/);
40250
+ if (match2)
40251
+ rawToken = decodeURIComponent(match2[1]);
40252
+ }
38882
40253
  }
38883
- }
38884
- const tokenPayload = rawToken ? verifyToken(rawToken) : null;
38885
- if (url.pathname === "/ws" && req.headers.get("Upgrade") === "websocket") {
38886
- if (server2.upgrade(req, { data: { clientId: "" } }))
38887
- return;
38888
- return new Response("WebSocket upgrade failed", {
38889
- status: 500,
38890
- headers: corsHeaders2
38891
- });
38892
- }
38893
- const reqCtx = {
38894
- rawToken,
38895
- tokenPayload,
38896
- corsHeaders: corsHeaders2
40254
+ const tokenPayload = rawToken ? verifyToken(rawToken) : null;
40255
+ if (url.pathname === "/ws" && req.headers.get("Upgrade") === "websocket") {
40256
+ if (server2.upgrade(req, { data: { clientId: "" } }))
40257
+ return;
40258
+ return new Response("WebSocket upgrade failed", {
40259
+ status: 500,
40260
+ headers: corsHeaders2
40261
+ });
40262
+ }
40263
+ const reqCtx = { rawToken, tokenPayload, corsHeaders: corsHeaders2 };
40264
+ for (const handler of httpHandlers) {
40265
+ const response = await handler(req, url, reqCtx);
40266
+ if (response) {
40267
+ span?.setAttribute("http.response.status_code", response.status);
40268
+ return response;
40269
+ }
40270
+ }
40271
+ span?.setAttribute("http.response.status_code", 404);
40272
+ return new Response("Not Found", { status: 404, headers: corsHeaders2 });
38897
40273
  };
38898
- for (const handler of httpHandlers) {
38899
- const response = await handler(req, url, reqCtx);
38900
- if (response)
38901
- return response;
38902
- }
38903
- return new Response("Not Found", {
38904
- status: 404,
38905
- headers: corsHeaders2
38906
- });
40274
+ const telemetry = config.telemetry;
40275
+ if (!telemetry)
40276
+ return handleRequest(undefined);
40277
+ return telemetry.runWithExtractedContext(req.headers, () => telemetry.startSpan(`${req.method} ${url.pathname}`, (span) => handleRequest(span), {
40278
+ kind: 2,
40279
+ attributes: {
40280
+ "http.request.method": req.method,
40281
+ "http.route": url.pathname,
40282
+ "url.scheme": url.protocol.replace(":", ""),
40283
+ "url.path": url.pathname,
40284
+ "server.address": url.host,
40285
+ "user_agent.original": req.headers.get("user-agent") ?? undefined
40286
+ }
40287
+ }));
38907
40288
  },
38908
40289
  websocket: {
38909
40290
  open(ws) {
@@ -38913,16 +40294,43 @@ async function createArcServer(config) {
38913
40294
  const client = connectionManager.getClientByWs(ws);
38914
40295
  if (!client)
38915
40296
  return;
40297
+ let message;
38916
40298
  try {
38917
- const message = JSON.parse(messageStr);
38918
- for (const handler of wsHandlers) {
38919
- const handled = await handler(client, message, wsCtx);
38920
- if (handled)
38921
- break;
38922
- }
40299
+ message = JSON.parse(messageStr);
38923
40300
  } catch (error) {
38924
40301
  console.error("Failed to parse WS message:", error);
40302
+ return;
40303
+ }
40304
+ const dispatch = async () => {
40305
+ try {
40306
+ for (const handler of wsHandlers) {
40307
+ const handled = await handler(client, message, wsCtx);
40308
+ if (handled)
40309
+ break;
40310
+ }
40311
+ } catch (error) {
40312
+ console.error("WS handler error:", error);
40313
+ }
40314
+ };
40315
+ const telemetry = config.telemetry;
40316
+ if (!telemetry) {
40317
+ await dispatch();
40318
+ return;
38925
40319
  }
40320
+ const carrier = {};
40321
+ if (typeof message?.traceparent === "string")
40322
+ carrier.traceparent = message.traceparent;
40323
+ if (typeof message?.tracestate === "string")
40324
+ carrier.tracestate = message.tracestate;
40325
+ await telemetry.runWithExtractedContext(carrier, () => telemetry.startSpan(`ws.${message?.type ?? "message"}`, () => dispatch(), {
40326
+ kind: 2,
40327
+ attributes: {
40328
+ "messaging.system": "arc-ws",
40329
+ "messaging.operation": "process",
40330
+ "messaging.message.type": message?.type,
40331
+ "arc.ws.client_id": client.id
40332
+ }
40333
+ }));
38926
40334
  },
38927
40335
  close(ws) {
38928
40336
  const client = connectionManager.getClientByWs(ws);
@@ -38964,6 +40372,15 @@ async function resolveDbAdapterFactory(dbPath) {
38964
40372
  return createBunSQLiteAdapterFactory2(dbPath);
38965
40373
  }
38966
40374
  function generateShellHtml(appName, manifest, initial, stylesHash) {
40375
+ const otelConfig = process.env.ARC_OTEL_ENABLED === "true" ? {
40376
+ enabled: true,
40377
+ endpoint: "/otel",
40378
+ serviceName: process.env.OTEL_SERVICE_NAME ?? `${appName}-browser`,
40379
+ environment: "development",
40380
+ sampleRate: Number(process.env.ARC_OTEL_BROWSER_SAMPLE_RATE ?? "0.1")
40381
+ } : null;
40382
+ const otelTag = otelConfig ? `
40383
+ <script>window.__ARC_OTEL_CONFIG=${JSON.stringify(otelConfig)};</script>` : "";
38967
40384
  const initialUrl = initial ? `/browser/${initial.file}` : null;
38968
40385
  if (!initialUrl) {
38969
40386
  throw new Error("generateShellHtml: initial bundle missing from manifest");
@@ -38979,7 +40396,7 @@ function generateShellHtml(appName, manifest, initial, stylesHash) {
38979
40396
  <link rel="manifest" href="/manifest.json">` : ""}
38980
40397
  <link rel="stylesheet" href="/styles.css${stylesQs}" />
38981
40398
  <link rel="stylesheet" href="/theme.css${stylesQs}" />
38982
- <link rel="modulepreload" href="${initialUrl}" />
40399
+ <link rel="modulepreload" href="${initialUrl}" />${otelTag}
38983
40400
  </head>
38984
40401
  <body>
38985
40402
  <div id="root"></div>
@@ -39227,8 +40644,27 @@ function spaFallbackHandler(getShellHtml) {
39227
40644
  };
39228
40645
  }
39229
40646
  async function startPlatformServer(opts) {
39230
- const { ws, port, devMode, context } = opts;
40647
+ const { ws, port, devMode, context: context2 } = opts;
39231
40648
  ensureModuleSigSecret(ws, !!devMode);
40649
+ let telemetry;
40650
+ let telemetryShutdown;
40651
+ if (process.env.ARC_OTEL_ENABLED === "true") {
40652
+ try {
40653
+ const { initServerTelemetry: initServerTelemetry2 } = await Promise.resolve().then(() => (init_init_server(), exports_init_server));
40654
+ const init2 = initServerTelemetry2({
40655
+ serviceName: process.env.OTEL_SERVICE_NAME ?? ws.appName,
40656
+ environment: "server",
40657
+ endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
40658
+ mode: devMode ? "development" : "production",
40659
+ sampleRate: devMode ? 1 : 1
40660
+ });
40661
+ telemetry = init2.telemetry;
40662
+ telemetryShutdown = init2.shutdown;
40663
+ ok("Telemetry enabled \u2014 exporting to " + process.env.OTEL_EXPORTER_OTLP_ENDPOINT);
40664
+ } catch (e2) {
40665
+ err(`Failed to init telemetry: ${e2.message}`);
40666
+ }
40667
+ }
39232
40668
  const moduleAccessMap = opts.moduleAccess ?? new Map;
39233
40669
  let manifest = opts.manifest;
39234
40670
  const getManifest = () => manifest;
@@ -39249,7 +40685,7 @@ async function startPlatformServer(opts) {
39249
40685
  }
39250
40686
  }
39251
40687
  };
39252
- if (!context) {
40688
+ if (!context2) {
39253
40689
  const cors = {
39254
40690
  "Access-Control-Allow-Origin": "*",
39255
40691
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
@@ -39293,9 +40729,18 @@ async function startPlatformServer(opts) {
39293
40729
  };
39294
40730
  }
39295
40731
  const dbPath = opts.dbPath || join20(ws.arcDir, "data", "arc.db");
39296
- const dbAdapterFactory = await resolveDbAdapterFactory(dbPath);
40732
+ const baseDbFactory = await resolveDbAdapterFactory(dbPath);
40733
+ let dbAdapterFactory = baseDbFactory;
40734
+ if (telemetry) {
40735
+ const { wrapDbAdapter: wrapDbAdapter2 } = await Promise.resolve().then(() => (init_init_server(), exports_init_server));
40736
+ const dbSystem = process.env.DATABASE_URL ? "postgresql" : "sqlite";
40737
+ dbAdapterFactory = async (ctx) => {
40738
+ const a2 = await baseDbFactory(ctx);
40739
+ return wrapDbAdapter2(a2, telemetry, dbSystem);
40740
+ };
40741
+ }
39297
40742
  const arcServer = await createArcServer({
39298
- context,
40743
+ context: context2,
39299
40744
  dbAdapterFactory,
39300
40745
  port,
39301
40746
  httpHandlers: [
@@ -39304,7 +40749,8 @@ async function startPlatformServer(opts) {
39304
40749
  staticFilesHandler(ws, !!devMode, getManifest),
39305
40750
  spaFallbackHandler(getShellHtml)
39306
40751
  ],
39307
- onWsClose: (clientId) => cleanupClientSubs(clientId)
40752
+ onWsClose: (clientId) => cleanupClientSubs(clientId),
40753
+ telemetry
39308
40754
  });
39309
40755
  return {
39310
40756
  server: arcServer.server,
@@ -39312,7 +40758,10 @@ async function startPlatformServer(opts) {
39312
40758
  connectionManager: arcServer.connectionManager,
39313
40759
  setManifest,
39314
40760
  notifyReload,
39315
- stop: () => arcServer.stop()
40761
+ stop: () => {
40762
+ arcServer.stop();
40763
+ telemetryShutdown?.();
40764
+ }
39316
40765
  };
39317
40766
  }
39318
40767
 
@@ -39333,8 +40782,8 @@ async function startPlatform(opts) {
39333
40782
  manifest = JSON.parse(readFileSync15(manifestPath, "utf-8"));
39334
40783
  }
39335
40784
  log2("Loading server context...");
39336
- const { context, moduleAccess } = await loadServerContext(ws);
39337
- if (context) {
40785
+ const { context: context2, moduleAccess } = await loadServerContext(ws);
40786
+ if (context2) {
39338
40787
  ok("Context loaded");
39339
40788
  } else {
39340
40789
  log2("No context \u2014 server endpoints skipped");
@@ -39343,7 +40792,7 @@ async function startPlatform(opts) {
39343
40792
  ws,
39344
40793
  port,
39345
40794
  manifest,
39346
- context,
40795
+ context: context2,
39347
40796
  moduleAccess,
39348
40797
  dbPath,
39349
40798
  devMode