@adonis-agora/telescope 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/dist/configure.d.ts +16 -0
  4. package/dist/configure.d.ts.map +1 -0
  5. package/dist/configure.js +75 -0
  6. package/dist/configure.js.map +1 -0
  7. package/dist/providers/telescope_ai_provider.d.ts +20 -0
  8. package/dist/providers/telescope_ai_provider.d.ts.map +1 -0
  9. package/dist/providers/telescope_ai_provider.js +45 -0
  10. package/dist/providers/telescope_ai_provider.js.map +1 -0
  11. package/dist/providers/telescope_alerts_provider.d.ts +23 -0
  12. package/dist/providers/telescope_alerts_provider.d.ts.map +1 -0
  13. package/dist/providers/telescope_alerts_provider.js +72 -0
  14. package/dist/providers/telescope_alerts_provider.js.map +1 -0
  15. package/dist/providers/telescope_provider.d.ts +43 -0
  16. package/dist/providers/telescope_provider.d.ts.map +1 -0
  17. package/dist/providers/telescope_provider.js +103 -0
  18. package/dist/providers/telescope_provider.js.map +1 -0
  19. package/dist/providers/telescope_ui_provider.d.ts +21 -0
  20. package/dist/providers/telescope_ui_provider.d.ts.map +1 -0
  21. package/dist/providers/telescope_ui_provider.js +119 -0
  22. package/dist/providers/telescope_ui_provider.js.map +1 -0
  23. package/dist/providers/telescope_watchers_provider.d.ts +31 -0
  24. package/dist/providers/telescope_watchers_provider.d.ts.map +1 -0
  25. package/dist/providers/telescope_watchers_provider.js +116 -0
  26. package/dist/providers/telescope_watchers_provider.js.map +1 -0
  27. package/dist/src/ai/define_config.d.ts +56 -0
  28. package/dist/src/ai/define_config.d.ts.map +1 -0
  29. package/dist/src/ai/define_config.js +39 -0
  30. package/dist/src/ai/define_config.js.map +1 -0
  31. package/dist/src/ai/diagnoser.d.ts +34 -0
  32. package/dist/src/ai/diagnoser.d.ts.map +1 -0
  33. package/dist/src/ai/diagnoser.js +74 -0
  34. package/dist/src/ai/diagnoser.js.map +1 -0
  35. package/dist/src/ai/diagnosis_cache.d.ts +43 -0
  36. package/dist/src/ai/diagnosis_cache.d.ts.map +1 -0
  37. package/dist/src/ai/diagnosis_cache.js +56 -0
  38. package/dist/src/ai/diagnosis_cache.js.map +1 -0
  39. package/dist/src/ai/factory.d.ts +15 -0
  40. package/dist/src/ai/factory.d.ts.map +1 -0
  41. package/dist/src/ai/factory.js +24 -0
  42. package/dist/src/ai/factory.js.map +1 -0
  43. package/dist/src/ai/index.d.ts +14 -0
  44. package/dist/src/ai/index.d.ts.map +1 -0
  45. package/dist/src/ai/index.js +15 -0
  46. package/dist/src/ai/index.js.map +1 -0
  47. package/dist/src/ai/prompt.d.ts +31 -0
  48. package/dist/src/ai/prompt.d.ts.map +1 -0
  49. package/dist/src/ai/prompt.js +66 -0
  50. package/dist/src/ai/prompt.js.map +1 -0
  51. package/dist/src/ai/telescope_ai_diagnoser.d.ts +79 -0
  52. package/dist/src/ai/telescope_ai_diagnoser.d.ts.map +1 -0
  53. package/dist/src/ai/telescope_ai_diagnoser.js +111 -0
  54. package/dist/src/ai/telescope_ai_diagnoser.js.map +1 -0
  55. package/dist/src/alerts/alert_channel.d.ts +69 -0
  56. package/dist/src/alerts/alert_channel.d.ts.map +1 -0
  57. package/dist/src/alerts/alert_channel.js +114 -0
  58. package/dist/src/alerts/alert_channel.js.map +1 -0
  59. package/dist/src/alerts/alert_rule.d.ts +86 -0
  60. package/dist/src/alerts/alert_rule.d.ts.map +1 -0
  61. package/dist/src/alerts/alert_rule.js +2 -0
  62. package/dist/src/alerts/alert_rule.js.map +1 -0
  63. package/dist/src/alerts/alerter.d.ts +72 -0
  64. package/dist/src/alerts/alerter.d.ts.map +1 -0
  65. package/dist/src/alerts/alerter.js +248 -0
  66. package/dist/src/alerts/alerter.js.map +1 -0
  67. package/dist/src/alerts/define_config.d.ts +68 -0
  68. package/dist/src/alerts/define_config.d.ts.map +1 -0
  69. package/dist/src/alerts/define_config.js +57 -0
  70. package/dist/src/alerts/define_config.js.map +1 -0
  71. package/dist/src/alerts/exception_source.d.ts +44 -0
  72. package/dist/src/alerts/exception_source.d.ts.map +1 -0
  73. package/dist/src/alerts/exception_source.js +79 -0
  74. package/dist/src/alerts/exception_source.js.map +1 -0
  75. package/dist/src/alerts/index.d.ts +16 -0
  76. package/dist/src/alerts/index.d.ts.map +1 -0
  77. package/dist/src/alerts/index.js +17 -0
  78. package/dist/src/alerts/index.js.map +1 -0
  79. package/dist/src/alerts/new_exception_tracker.d.ts +50 -0
  80. package/dist/src/alerts/new_exception_tracker.d.ts.map +1 -0
  81. package/dist/src/alerts/new_exception_tracker.js +74 -0
  82. package/dist/src/alerts/new_exception_tracker.js.map +1 -0
  83. package/dist/src/alerts/parse_duration.d.ts +10 -0
  84. package/dist/src/alerts/parse_duration.d.ts.map +1 -0
  85. package/dist/src/alerts/parse_duration.js +27 -0
  86. package/dist/src/alerts/parse_duration.js.map +1 -0
  87. package/dist/src/alerts/slack_format.d.ts +60 -0
  88. package/dist/src/alerts/slack_format.d.ts.map +1 -0
  89. package/dist/src/alerts/slack_format.js +122 -0
  90. package/dist/src/alerts/slack_format.js.map +1 -0
  91. package/dist/src/context_accessor.d.ts +30 -0
  92. package/dist/src/context_accessor.d.ts.map +1 -0
  93. package/dist/src/context_accessor.js +20 -0
  94. package/dist/src/context_accessor.js.map +1 -0
  95. package/dist/src/define_config.d.ts +109 -0
  96. package/dist/src/define_config.d.ts.map +1 -0
  97. package/dist/src/define_config.js +38 -0
  98. package/dist/src/define_config.js.map +1 -0
  99. package/dist/src/diagnostics_registry.d.ts +46 -0
  100. package/dist/src/diagnostics_registry.d.ts.map +1 -0
  101. package/dist/src/diagnostics_registry.js +34 -0
  102. package/dist/src/diagnostics_registry.js.map +1 -0
  103. package/dist/src/diagnostics_watcher.d.ts +72 -0
  104. package/dist/src/diagnostics_watcher.d.ts.map +1 -0
  105. package/dist/src/diagnostics_watcher.js +119 -0
  106. package/dist/src/diagnostics_watcher.js.map +1 -0
  107. package/dist/src/entry.d.ts +81 -0
  108. package/dist/src/entry.d.ts.map +1 -0
  109. package/dist/src/entry.js +34 -0
  110. package/dist/src/entry.js.map +1 -0
  111. package/dist/src/exception_family_hash.d.ts +29 -0
  112. package/dist/src/exception_family_hash.d.ts.map +1 -0
  113. package/dist/src/exception_family_hash.js +30 -0
  114. package/dist/src/exception_family_hash.js.map +1 -0
  115. package/dist/src/exception_watcher.d.ts +66 -0
  116. package/dist/src/exception_watcher.d.ts.map +1 -0
  117. package/dist/src/exception_watcher.js +94 -0
  118. package/dist/src/exception_watcher.js.map +1 -0
  119. package/dist/src/extension/registry.d.ts +17 -0
  120. package/dist/src/extension/registry.d.ts.map +1 -0
  121. package/dist/src/extension/registry.js +56 -0
  122. package/dist/src/extension/registry.js.map +1 -0
  123. package/dist/src/extension/types.d.ts +158 -0
  124. package/dist/src/extension/types.d.ts.map +1 -0
  125. package/dist/src/extension/types.js +5 -0
  126. package/dist/src/extension/types.js.map +1 -0
  127. package/dist/src/index.d.ts +36 -0
  128. package/dist/src/index.d.ts.map +1 -0
  129. package/dist/src/index.js +28 -0
  130. package/dist/src/index.js.map +1 -0
  131. package/dist/src/redaction/redact.d.ts +93 -0
  132. package/dist/src/redaction/redact.d.ts.map +1 -0
  133. package/dist/src/redaction/redact.js +184 -0
  134. package/dist/src/redaction/redact.js.map +1 -0
  135. package/dist/src/redaction/redacting_store.d.ts +28 -0
  136. package/dist/src/redaction/redacting_store.d.ts.map +1 -0
  137. package/dist/src/redaction/redacting_store.js +49 -0
  138. package/dist/src/redaction/redacting_store.js.map +1 -0
  139. package/dist/src/registry.d.ts +26 -0
  140. package/dist/src/registry.d.ts.map +1 -0
  141. package/dist/src/registry.js +28 -0
  142. package/dist/src/registry.js.map +1 -0
  143. package/dist/src/request_watcher.d.ts +44 -0
  144. package/dist/src/request_watcher.d.ts.map +1 -0
  145. package/dist/src/request_watcher.js +37 -0
  146. package/dist/src/request_watcher.js.map +1 -0
  147. package/dist/src/service.d.ts +36 -0
  148. package/dist/src/service.d.ts.map +1 -0
  149. package/dist/src/service.js +65 -0
  150. package/dist/src/service.js.map +1 -0
  151. package/dist/src/store.d.ts +56 -0
  152. package/dist/src/store.d.ts.map +1 -0
  153. package/dist/src/store.js +2 -0
  154. package/dist/src/store.js.map +1 -0
  155. package/dist/src/stores/factory.d.ts +61 -0
  156. package/dist/src/stores/factory.d.ts.map +1 -0
  157. package/dist/src/stores/factory.js +42 -0
  158. package/dist/src/stores/factory.js.map +1 -0
  159. package/dist/src/stores/lucid.d.ts +138 -0
  160. package/dist/src/stores/lucid.d.ts.map +1 -0
  161. package/dist/src/stores/lucid.js +257 -0
  162. package/dist/src/stores/lucid.js.map +1 -0
  163. package/dist/src/stores/memory.d.ts +31 -0
  164. package/dist/src/stores/memory.d.ts.map +1 -0
  165. package/dist/src/stores/memory.js +117 -0
  166. package/dist/src/stores/memory.js.map +1 -0
  167. package/dist/src/telescope_middleware.d.ts +19 -0
  168. package/dist/src/telescope_middleware.d.ts.map +1 -0
  169. package/dist/src/telescope_middleware.js +56 -0
  170. package/dist/src/telescope_middleware.js.map +1 -0
  171. package/dist/src/ui/api.d.ts +49 -0
  172. package/dist/src/ui/api.d.ts.map +1 -0
  173. package/dist/src/ui/api.js +155 -0
  174. package/dist/src/ui/api.js.map +1 -0
  175. package/dist/src/ui/dashboard.d.ts +8 -0
  176. package/dist/src/ui/dashboard.d.ts.map +1 -0
  177. package/dist/src/ui/dashboard.html +626 -0
  178. package/dist/src/ui/dashboard.js +29 -0
  179. package/dist/src/ui/dashboard.js.map +1 -0
  180. package/dist/src/ui/define_config.d.ts +87 -0
  181. package/dist/src/ui/define_config.d.ts.map +1 -0
  182. package/dist/src/ui/define_config.js +104 -0
  183. package/dist/src/ui/define_config.js.map +1 -0
  184. package/dist/src/ui/extension_api.d.ts +23 -0
  185. package/dist/src/ui/extension_api.d.ts.map +1 -0
  186. package/dist/src/ui/extension_api.js +50 -0
  187. package/dist/src/ui/extension_api.js.map +1 -0
  188. package/dist/src/ui/guard.d.ts +33 -0
  189. package/dist/src/ui/guard.d.ts.map +1 -0
  190. package/dist/src/ui/guard.js +47 -0
  191. package/dist/src/ui/guard.js.map +1 -0
  192. package/dist/src/ui/http.d.ts +47 -0
  193. package/dist/src/ui/http.d.ts.map +1 -0
  194. package/dist/src/ui/http.js +43 -0
  195. package/dist/src/ui/http.js.map +1 -0
  196. package/dist/src/ui/index.d.ts +12 -0
  197. package/dist/src/ui/index.d.ts.map +1 -0
  198. package/dist/src/ui/index.js +13 -0
  199. package/dist/src/ui/index.js.map +1 -0
  200. package/dist/src/watchers/cache_watcher.d.ts +60 -0
  201. package/dist/src/watchers/cache_watcher.d.ts.map +1 -0
  202. package/dist/src/watchers/cache_watcher.js +72 -0
  203. package/dist/src/watchers/cache_watcher.js.map +1 -0
  204. package/dist/src/watchers/define_config.d.ts +38 -0
  205. package/dist/src/watchers/define_config.d.ts.map +1 -0
  206. package/dist/src/watchers/define_config.js +17 -0
  207. package/dist/src/watchers/define_config.js.map +1 -0
  208. package/dist/src/watchers/emitter.d.ts +32 -0
  209. package/dist/src/watchers/emitter.d.ts.map +1 -0
  210. package/dist/src/watchers/emitter.js +2 -0
  211. package/dist/src/watchers/emitter.js.map +1 -0
  212. package/dist/src/watchers/http_client_watcher.d.ts +74 -0
  213. package/dist/src/watchers/http_client_watcher.d.ts.map +1 -0
  214. package/dist/src/watchers/http_client_watcher.js +168 -0
  215. package/dist/src/watchers/http_client_watcher.js.map +1 -0
  216. package/dist/src/watchers/index.d.ts +19 -0
  217. package/dist/src/watchers/index.d.ts.map +1 -0
  218. package/dist/src/watchers/index.js +19 -0
  219. package/dist/src/watchers/index.js.map +1 -0
  220. package/dist/src/watchers/logs_watcher.d.ts +82 -0
  221. package/dist/src/watchers/logs_watcher.d.ts.map +1 -0
  222. package/dist/src/watchers/logs_watcher.js +145 -0
  223. package/dist/src/watchers/logs_watcher.js.map +1 -0
  224. package/dist/src/watchers/lucid_query_watcher.d.ts +64 -0
  225. package/dist/src/watchers/lucid_query_watcher.d.ts.map +1 -0
  226. package/dist/src/watchers/lucid_query_watcher.js +84 -0
  227. package/dist/src/watchers/lucid_query_watcher.js.map +1 -0
  228. package/dist/src/watchers/mail_watcher.d.ts +51 -0
  229. package/dist/src/watchers/mail_watcher.d.ts.map +1 -0
  230. package/dist/src/watchers/mail_watcher.js +93 -0
  231. package/dist/src/watchers/mail_watcher.js.map +1 -0
  232. package/dist/src/watchers/normalize_http_target.d.ts +17 -0
  233. package/dist/src/watchers/normalize_http_target.d.ts.map +1 -0
  234. package/dist/src/watchers/normalize_http_target.js +41 -0
  235. package/dist/src/watchers/normalize_http_target.js.map +1 -0
  236. package/dist/src/watchers/query_family_hash.d.ts +8 -0
  237. package/dist/src/watchers/query_family_hash.d.ts.map +1 -0
  238. package/dist/src/watchers/query_family_hash.js +31 -0
  239. package/dist/src/watchers/query_family_hash.js.map +1 -0
  240. package/dist/src/watchers/record.d.ts +22 -0
  241. package/dist/src/watchers/record.d.ts.map +1 -0
  242. package/dist/src/watchers/record.js +48 -0
  243. package/dist/src/watchers/record.js.map +1 -0
  244. package/dist/stubs/config/telescope.stub +56 -0
  245. package/dist/stubs/config/telescope_ai.stub +36 -0
  246. package/dist/stubs/config/telescope_alerts.stub +47 -0
  247. package/dist/stubs/config/telescope_ui.stub +40 -0
  248. package/dist/stubs/config/telescope_watchers.stub +30 -0
  249. package/dist/stubs/database/migrations/create_telescope_entries_table.stub +39 -0
  250. package/dist/stubs/main.d.ts +6 -0
  251. package/dist/stubs/main.d.ts.map +1 -0
  252. package/dist/stubs/main.js +7 -0
  253. package/dist/stubs/main.js.map +1 -0
  254. package/package.json +140 -0
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Default cap on tracked error families. The map is the ONLY state the
3
+ * `new-exception` rule keeps, and it must stay bounded so a host that throws a
4
+ * long tail of unique error families (e.g. message-embedded ids that defeat the
5
+ * family hash) can never grow it without limit. At the cap we evict the OLDEST
6
+ * inserted family — the one least likely to still be "recently seen" — which is
7
+ * the correct bias for a recency-window dedup.
8
+ */
9
+ const DEFAULT_MAX_FAMILIES = 10_000;
10
+ /**
11
+ * Bounded, in-memory "have we seen this error family recently?" tracker backing
12
+ * the `new-exception` rule. Per-process by design: it lives in process memory, so
13
+ * in a multi-replica deployment the SAME family may be reported as new once per
14
+ * pod (documented caveat — acceptable for v1).
15
+ *
16
+ * Eviction uses a `Map`'s insertion-order iteration: the first key is the oldest
17
+ * INSERTED entry. The window check already discards stale last-seen times, so
18
+ * insertion-order eviction is a sound, O(1) cap with no per-touch bookkeeping.
19
+ *
20
+ * Ported verbatim from the aviary telescope core.
21
+ */
22
+ export class NewExceptionTracker {
23
+ seen = new Map();
24
+ maxFamilies;
25
+ constructor(maxFamilies = DEFAULT_MAX_FAMILIES) {
26
+ this.maxFamilies = maxFamilies;
27
+ }
28
+ /**
29
+ * Record an observation of `familyHash` at `nowMs` and report whether this is a
30
+ * NEW family for the `windowMs` window — i.e. it was either never seen or last
31
+ * seen longer ago than the window (the "re-occurring after being resolved"
32
+ * signal). Always updates the stored last-seen time so repeat occurrences
33
+ * refresh the window. Returns `true` only on a genuine first/expired occurrence
34
+ * (the signal that should fire the alert).
35
+ */
36
+ observe(familyHash, nowMs, windowMs) {
37
+ const lastSeen = this.seen.get(familyHash);
38
+ const isNew = lastSeen === undefined || nowMs - lastSeen >= windowMs;
39
+ // Delete-then-set so a refreshed family moves to the END of insertion order,
40
+ // keeping genuinely-oldest families at the front for eviction.
41
+ this.seen.delete(familyHash);
42
+ this.seen.set(familyHash, nowMs);
43
+ this.evictIfNeeded();
44
+ return isNew;
45
+ }
46
+ /**
47
+ * Forget `familyHash` entirely, so its NEXT occurrence is reported as new again.
48
+ * This is the explicit "resolve" hook: after an operator marks a family resolved
49
+ * (or a self-heal job clears it), the very next occurrence pages again without
50
+ * waiting for the window to elapse.
51
+ */
52
+ resolve(familyHash) {
53
+ this.seen.delete(familyHash);
54
+ }
55
+ /** Forget every tracked family. */
56
+ clear() {
57
+ this.seen.clear();
58
+ }
59
+ /** Number of tracked families (test/observability seam). */
60
+ get size() {
61
+ return this.seen.size;
62
+ }
63
+ /** Evict the oldest entries until the map is within its cap. */
64
+ evictIfNeeded() {
65
+ while (this.seen.size > this.maxFamilies) {
66
+ const oldest = this.seen.keys().next().value;
67
+ if (oldest === undefined)
68
+ break;
69
+ this.seen.delete(oldest);
70
+ }
71
+ }
72
+ }
73
+ export { DEFAULT_MAX_FAMILIES };
74
+ //# sourceMappingURL=new_exception_tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new_exception_tracker.js","sourceRoot":"","sources":["../../../src/alerts/new_exception_tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAEpC;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,mBAAmB;IACb,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACjC,WAAW,CAAS;IAErC,YAAY,cAAsB,oBAAoB;QACpD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,UAAkB,EAAE,KAAa,EAAE,QAAgB;QACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,QAAQ,KAAK,SAAS,IAAI,KAAK,GAAG,QAAQ,IAAI,QAAQ,CAAC;QACrE,6EAA6E;QAC7E,+DAA+D;QAC/D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,UAAkB;QACxB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IAED,mCAAmC;IACnC,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,4DAA4D;IAC5D,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IAED,gEAAgE;IACxD,aAAa;QACnB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC7C,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;CACF;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Convert a duration (a raw ms number, or a `<int><ms|s|m|h|d>` string such as
3
+ * `'15m'`) to milliseconds. Throws on an unparseable string so a typo in config
4
+ * surfaces at boot rather than silently never firing.
5
+ *
6
+ * Ported verbatim from the aviary telescope core's `durationToMs` — this package
7
+ * keeps its own copy so it never depends on a core internal that isn't exported.
8
+ */
9
+ export declare function durationToMs(duration: number | string): number;
10
+ //# sourceMappingURL=parse_duration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse_duration.d.ts","sourceRoot":"","sources":["../../../src/alerts/parse_duration.ts"],"names":[],"mappings":"AAUA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAU9D"}
@@ -0,0 +1,27 @@
1
+ const DURATION_UNITS = {
2
+ ms: 1,
3
+ s: 1_000,
4
+ m: 60_000,
5
+ h: 3_600_000,
6
+ d: 86_400_000,
7
+ };
8
+ /**
9
+ * Convert a duration (a raw ms number, or a `<int><ms|s|m|h|d>` string such as
10
+ * `'15m'`) to milliseconds. Throws on an unparseable string so a typo in config
11
+ * surfaces at boot rather than silently never firing.
12
+ *
13
+ * Ported verbatim from the aviary telescope core's `durationToMs` — this package
14
+ * keeps its own copy so it never depends on a core internal that isn't exported.
15
+ */
16
+ export function durationToMs(duration) {
17
+ if (typeof duration === 'number') {
18
+ return duration;
19
+ }
20
+ const match = /^(\d+)(ms|s|m|h|d)$/.exec(duration.trim());
21
+ if (match === null) {
22
+ throw new Error(`Invalid duration: ${duration}`);
23
+ }
24
+ const unit = match[2];
25
+ return Number(match[1]) * DURATION_UNITS[unit];
26
+ }
27
+ //# sourceMappingURL=parse_duration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse_duration.js","sourceRoot":"","sources":["../../../src/alerts/parse_duration.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG;IACrB,EAAE,EAAE,CAAC;IACL,CAAC,EAAE,KAAK;IACR,CAAC,EAAE,MAAM;IACT,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,UAAU;CACL,CAAC;AAIX;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,QAAyB;IACpD,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1D,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAiB,CAAC;IACtC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,60 @@
1
+ import type { AlertPayload } from './alert_rule.js';
2
+ /**
3
+ * Optional Slack presentation overrides. Most hosts set none of these — the
4
+ * incoming webhook's own default name/icon is used. Provided for hosts that route
5
+ * several Telescope instances into one channel and want them visually distinct.
6
+ */
7
+ export interface SlackChannelOptions {
8
+ /** Override the bot username shown on the message. */
9
+ username?: string;
10
+ /** Override the message icon (a Slack emoji shortcode, e.g. `:rotating_light:`). */
11
+ iconEmoji?: string;
12
+ }
13
+ interface SlackTextObject {
14
+ type: 'plain_text' | 'mrkdwn';
15
+ text: string;
16
+ emoji?: boolean;
17
+ }
18
+ interface SlackHeaderBlock {
19
+ type: 'header';
20
+ text: SlackTextObject;
21
+ }
22
+ interface SlackSectionBlock {
23
+ type: 'section';
24
+ text?: SlackTextObject;
25
+ fields?: SlackTextObject[];
26
+ }
27
+ interface SlackButtonElement {
28
+ type: 'button';
29
+ text: SlackTextObject;
30
+ url: string;
31
+ }
32
+ interface SlackActionsBlock {
33
+ type: 'actions';
34
+ elements: SlackButtonElement[];
35
+ }
36
+ type SlackBlock = SlackHeaderBlock | SlackSectionBlock | SlackActionsBlock;
37
+ /** The full webhook body Slack expects: a fallback `text` plus the rich `blocks`. */
38
+ export interface SlackMessage {
39
+ /** Fallback/notification text shown where blocks can't render. */
40
+ text: string;
41
+ blocks: SlackBlock[];
42
+ username?: string;
43
+ icon_emoji?: string;
44
+ }
45
+ /**
46
+ * Render an {@link AlertPayload} into a Slack Block Kit message. Structure:
47
+ * - a `header` with the severity emoji + rule label;
48
+ * - a `section` whose fields carry the instance/rule context (and — for
49
+ * `new-exception` — route/method/status/user and the occurrence count);
50
+ * - a `section` with a fenced code block of the truncated stack (only when an
51
+ * exception stack is present);
52
+ * - an `actions` block with a single "Open in Telescope" button (only when a
53
+ * `dashboardUrl` + entry id are available to build the deep link).
54
+ *
55
+ * Everything degrades gracefully: a rate rule (no `exception` context) simply
56
+ * renders the header + context fields and skips the stack/button.
57
+ */
58
+ export declare function formatSlackMessage(payload: AlertPayload, options?: SlackChannelOptions): SlackMessage;
59
+ export {};
60
+ //# sourceMappingURL=slack_format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack_format.d.ts","sourceRoot":"","sources":["../../../src/alerts/slack_format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD,UAAU,eAAe;IACvB,IAAI,EAAE,YAAY,GAAG,QAAQ,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AACD,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,eAAe,CAAC;CACvB;AACD,UAAU,iBAAiB;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B;AACD,UAAU,kBAAkB;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,eAAe,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AACD,UAAU,iBAAiB;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AACD,KAAK,UAAU,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE3E,qFAAqF;AACrF,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAkDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,YAAY,CAyDd"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Slack hard limits we format within. A `text` field in a section is capped at
3
+ * 3000 chars; we keep the stack snippet WELL under that and additionally cap by
4
+ * frame count so the message stays scannable rather than a wall of frames.
5
+ */
6
+ const STACK_CHAR_LIMIT = 2_800;
7
+ const STACK_FRAME_LIMIT = 10;
8
+ /**
9
+ * Severity → leading emoji, derived from the rule kind: a brand-new error family
10
+ * or an exception spike is the loudest signal an operator can get.
11
+ */
12
+ function severityEmoji(rule) {
13
+ if (rule.type === 'new-exception' || rule.type === 'exception-rate')
14
+ return ':rotating_light:';
15
+ return ':warning:';
16
+ }
17
+ /** Short, human rule label for the header. */
18
+ function ruleLabel(rule) {
19
+ switch (rule.type) {
20
+ case 'new-exception':
21
+ return 'New exception family';
22
+ case 'exception-rate':
23
+ return 'Exception rate';
24
+ }
25
+ }
26
+ /** A Slack `mrkdwn` field pairing a bold label with a value. */
27
+ function field(label, value) {
28
+ return { type: 'mrkdwn', text: `*${label}:*\n${value}` };
29
+ }
30
+ /**
31
+ * Clip a raw stack to Slack's budget: keep at most {@link STACK_FRAME_LIMIT}
32
+ * lines, then hard-cap the joined string at {@link STACK_CHAR_LIMIT} chars.
33
+ * Returns `null` for an absent stack so the caller can omit the block entirely.
34
+ */
35
+ function clipStack(stack) {
36
+ if (stack === null || stack.trim() === '')
37
+ return null;
38
+ const frames = stack.split('\n').slice(0, STACK_FRAME_LIMIT).join('\n');
39
+ if (frames.length <= STACK_CHAR_LIMIT)
40
+ return frames;
41
+ return `${frames.slice(0, STACK_CHAR_LIMIT)}…`;
42
+ }
43
+ /**
44
+ * Build the deep link to the offending exception entry in the host's external
45
+ * dashboard. Returns `null` when no `dashboardUrl` is configured or there is no
46
+ * entry id to link to (rate rules carry no single id).
47
+ */
48
+ function dashboardLink(payload) {
49
+ const { dashboardUrl, exception } = payload;
50
+ if (dashboardUrl === undefined || exception === undefined)
51
+ return null;
52
+ const base = dashboardUrl.replace(/\/+$/, '');
53
+ return `${base}#/entries/view/${exception.entryId}`;
54
+ }
55
+ /**
56
+ * Render an {@link AlertPayload} into a Slack Block Kit message. Structure:
57
+ * - a `header` with the severity emoji + rule label;
58
+ * - a `section` whose fields carry the instance/rule context (and — for
59
+ * `new-exception` — route/method/status/user and the occurrence count);
60
+ * - a `section` with a fenced code block of the truncated stack (only when an
61
+ * exception stack is present);
62
+ * - an `actions` block with a single "Open in Telescope" button (only when a
63
+ * `dashboardUrl` + entry id are available to build the deep link).
64
+ *
65
+ * Everything degrades gracefully: a rate rule (no `exception` context) simply
66
+ * renders the header + context fields and skips the stack/button.
67
+ */
68
+ export function formatSlackMessage(payload, options) {
69
+ const emoji = severityEmoji(payload.rule);
70
+ const label = ruleLabel(payload.rule);
71
+ const headerText = `${emoji} ${label}`;
72
+ const contextFields = [
73
+ field('Instance', payload.instanceId),
74
+ field('Observed', `${payload.value} (threshold ${payload.threshold})`),
75
+ ];
76
+ const exception = payload.exception;
77
+ if (exception !== undefined) {
78
+ contextFields.push(field('Error', `${exception.class}: ${exception.message}`));
79
+ if (exception.route !== null) {
80
+ const method = exception.method ?? '';
81
+ const status = exception.statusCode === null ? '' : ` → ${exception.statusCode}`;
82
+ contextFields.push(field('Route', `${method} ${exception.route}${status}`.trim()));
83
+ }
84
+ if (exception.user !== null) {
85
+ contextFields.push(field('User', exception.user));
86
+ }
87
+ contextFields.push(field('Occurrences', `${exception.occurrences} in window`));
88
+ }
89
+ else {
90
+ const window = 'window' in payload.rule ? payload.rule.window : null;
91
+ if (window !== null)
92
+ contextFields.push(field('Window', window));
93
+ }
94
+ const blocks = [
95
+ { type: 'header', text: { type: 'plain_text', text: headerText, emoji: true } },
96
+ { type: 'section', fields: contextFields },
97
+ ];
98
+ const stack = exception ? clipStack(exception.stack) : null;
99
+ if (stack !== null) {
100
+ blocks.push({ type: 'section', text: { type: 'mrkdwn', text: `\`\`\`${stack}\`\`\`` } });
101
+ }
102
+ const link = dashboardLink(payload);
103
+ if (link !== null) {
104
+ blocks.push({
105
+ type: 'actions',
106
+ elements: [
107
+ {
108
+ type: 'button',
109
+ text: { type: 'plain_text', text: 'Open in Telescope', emoji: true },
110
+ url: link,
111
+ },
112
+ ],
113
+ });
114
+ }
115
+ return {
116
+ text: headerText,
117
+ blocks,
118
+ ...(options?.username !== undefined ? { username: options.username } : {}),
119
+ ...(options?.iconEmoji !== undefined ? { icon_emoji: options.iconEmoji } : {}),
120
+ };
121
+ }
122
+ //# sourceMappingURL=slack_format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack_format.js","sourceRoot":"","sources":["../../../src/alerts/slack_format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Structural reader for `@adonis-agora/context` — WITHOUT importing it.
3
+ *
4
+ * `@adonis-agora/context` publishes a read-only accessor on the cross-copy-stable global
5
+ * slot `Symbol.for('@agora/context:accessor')` at import time. Telescope is a
6
+ * separate repo and cannot depend on `@adonis-agora/context`, so it reads that slot
7
+ * structurally and degrades to `undefined` when the package is absent. This keeps
8
+ * request correlation (the active trace id) working when both packages are
9
+ * installed, with zero coupling when only one is.
10
+ */
11
+ /** A user reference carried in the context (shape mirrored, not imported). */
12
+ export interface UserRef {
13
+ id: string | number;
14
+ [key: string]: unknown;
15
+ }
16
+ /**
17
+ * The narrow read-only view `@adonis-agora/context` publishes. Mirrors its
18
+ * `ContextAccessor` structurally — consumers read, they never drive the lifecycle.
19
+ */
20
+ export interface ContextAccessor {
21
+ traceId(): string | undefined;
22
+ tenantId(): string | undefined;
23
+ userRef(): UserRef | undefined;
24
+ get(): Record<string, unknown> | undefined;
25
+ }
26
+ /** The accessor `@adonis-agora/context` published, or `undefined` when it is not loaded. */
27
+ export declare function getContextAccessor(): ContextAccessor | undefined;
28
+ /** The active trace id from `@adonis-agora/context`, or `null` when unavailable. */
29
+ export declare function currentTraceId(): string | null;
30
+ //# sourceMappingURL=context_accessor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context_accessor.d.ts","sourceRoot":"","sources":["../../src/context_accessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,IAAI,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,IAAI,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,IAAI,OAAO,GAAG,SAAS,CAAC;IAC/B,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAC5C;AAID,4FAA4F;AAC5F,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,SAAS,CAEhE;AAED,oFAAoF;AACpF,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Structural reader for `@adonis-agora/context` — WITHOUT importing it.
3
+ *
4
+ * `@adonis-agora/context` publishes a read-only accessor on the cross-copy-stable global
5
+ * slot `Symbol.for('@agora/context:accessor')` at import time. Telescope is a
6
+ * separate repo and cannot depend on `@adonis-agora/context`, so it reads that slot
7
+ * structurally and degrades to `undefined` when the package is absent. This keeps
8
+ * request correlation (the active trace id) working when both packages are
9
+ * installed, with zero coupling when only one is.
10
+ */
11
+ const CONTEXT_ACCESSOR = Symbol.for('@agora/context:accessor');
12
+ /** The accessor `@adonis-agora/context` published, or `undefined` when it is not loaded. */
13
+ export function getContextAccessor() {
14
+ return globalThis[CONTEXT_ACCESSOR];
15
+ }
16
+ /** The active trace id from `@adonis-agora/context`, or `null` when unavailable. */
17
+ export function currentTraceId() {
18
+ return getContextAccessor()?.traceId() ?? null;
19
+ }
20
+ //# sourceMappingURL=context_accessor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context_accessor.js","sourceRoot":"","sources":["../../src/context_accessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmBH,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AAE/D,4FAA4F;AAC5F,MAAM,UAAU,kBAAkB;IAChC,OAAQ,UAAsC,CAAC,gBAAgB,CAAgC,CAAC;AAClG,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,cAAc;IAC5B,OAAO,kBAAkB,EAAE,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC;AACjD,CAAC"}
@@ -0,0 +1,109 @@
1
+ import type { TelescopeExtension } from './extension/types.js';
2
+ import type { TelescopeStore } from './store.js';
3
+ import { type StoreProvider, storage } from './stores/factory.js';
4
+ /**
5
+ * Sensitive-data redaction applied to EVERY entry's content before it is
6
+ * persisted. Defaults are on; supply `keys` to extend the masked set or
7
+ * `enabled: false` to opt out entirely.
8
+ */
9
+ export interface RedactConfig {
10
+ /**
11
+ * Master switch for redaction. When `false`, content is persisted verbatim.
12
+ * Default `true`.
13
+ */
14
+ enabled?: boolean;
15
+ /**
16
+ * Extra sensitive key names to mask, merged with the built-in defaults
17
+ * (`authorization`, `cookie`, `password`, `token`, `api_key`, `secret`, …).
18
+ * Matched case-insensitively at any depth.
19
+ */
20
+ keys?: string[];
21
+ }
22
+ /** The set of watchers this headless slice ships. */
23
+ export type WatcherName = 'request' | 'diagnostics';
24
+ /**
25
+ * The shape of `config/telescope.ts`. Everything is optional with sane defaults:
26
+ * the in-memory store, both shipped watchers enabled, a 1000-entry cap.
27
+ */
28
+ export interface TelescopeConfig {
29
+ /**
30
+ * Master switch. When `false`, the provider records nothing and both watchers
31
+ * stay dormant (zero overhead). Default `true`.
32
+ */
33
+ enabled?: boolean;
34
+ /**
35
+ * Which store backs telescope. Three forms are accepted:
36
+ *
37
+ * - a **key of {@link stores}** (the idiomatic form) — e.g. `'memory'` or `'lucid'`,
38
+ * selecting one of the drivers built with the {@link storage} factory;
39
+ * - the literal `'memory'` — the built-in ring buffer, even with no `stores` map;
40
+ * - a {@link TelescopeStore} instance — for a custom backend wired by hand.
41
+ *
42
+ * Default `'memory'`.
43
+ */
44
+ store?: string | TelescopeStore;
45
+ /**
46
+ * Named store drivers, built with the {@link storage} factory. The active one is
47
+ * selected by {@link store}. Each factory returns a lazy thunk; its peer dependency
48
+ * (`@adonisjs/lucid` for `lucid`) is only imported when that driver is the active one.
49
+ */
50
+ stores?: Record<string, StoreProvider>;
51
+ /**
52
+ * Hard cap on retained entries for the in-memory store when selected by the bare
53
+ * `store: 'memory'` shorthand (no `stores` map). Oldest entries are evicted past
54
+ * this. Default 1000. Prefer `storage.memory({ limit })` in the `stores` map.
55
+ */
56
+ maxEntries?: number;
57
+ /**
58
+ * Which watchers are active. Omit a name to disable it. Defaults to both
59
+ * (`request` + `diagnostics`).
60
+ */
61
+ watchers?: WatcherName[];
62
+ /**
63
+ * Extensions contributed by sibling libs (e.g. `@adonis-agora/durable-telescope`) — each adds navigable
64
+ * entry types, dashboard pages, and the data providers those pages bind to. Default none.
65
+ */
66
+ extensions?: TelescopeExtension[];
67
+ /**
68
+ * Sensitive-data redaction applied to every entry's content before persistence.
69
+ * Enabled by default with a built-in set of sensitive keys. Set
70
+ * `redact: { enabled: false }` to opt out, or `redact: { keys: [...] }` to mask
71
+ * additional keys.
72
+ */
73
+ redact?: RedactConfig;
74
+ }
75
+ /** The fully-resolved config the provider acts on (no optionals). */
76
+ export interface ResolvedTelescopeConfig {
77
+ enabled: boolean;
78
+ store: string | TelescopeStore;
79
+ stores: Record<string, StoreProvider>;
80
+ maxEntries: number;
81
+ watchers: Set<WatcherName>;
82
+ extensions: TelescopeExtension[];
83
+ redact: {
84
+ enabled: boolean;
85
+ keys: string[];
86
+ };
87
+ }
88
+ /**
89
+ * Identity helper giving `config/telescope.ts` full type-checking. Mirrors the
90
+ * AdonisJS `defineConfig` convention.
91
+ *
92
+ * ```ts
93
+ * import { defineConfig, storage } from '@adonis-agora/telescope'
94
+ *
95
+ * export default defineConfig({
96
+ * store: 'memory',
97
+ * stores: {
98
+ * memory: storage.memory({ limit: 1000 }),
99
+ * lucid: storage.lucid({ connection: 'pg' }),
100
+ * },
101
+ * })
102
+ * ```
103
+ */
104
+ export declare function defineConfig(config: TelescopeConfig): TelescopeConfig;
105
+ /** Apply defaults to a (possibly partial) config. */
106
+ export declare function resolveConfig(config?: TelescopeConfig): ResolvedTelescopeConfig;
107
+ export { storage };
108
+ export type { LucidStoreConfig, MemoryStoreConfig, StoreContext, StoreProvider, } from './stores/factory.js';
109
+ //# sourceMappingURL=define_config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../src/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,KAAK,aAAa,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,qDAAqD;AACrD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,aAAa,CAAC;AAEpD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC;IAEhC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAEvC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IAEzB;;;OAGG;IACH,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAElC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,cAAc,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IAC3B,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,MAAM,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CAErE;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,MAAM,GAAE,eAAoB,GAAG,uBAAuB,CAcnF;AAED,OAAO,EAAE,OAAO,EAAE,CAAC;AACnB,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { storage } from './stores/factory.js';
2
+ /**
3
+ * Identity helper giving `config/telescope.ts` full type-checking. Mirrors the
4
+ * AdonisJS `defineConfig` convention.
5
+ *
6
+ * ```ts
7
+ * import { defineConfig, storage } from '@adonis-agora/telescope'
8
+ *
9
+ * export default defineConfig({
10
+ * store: 'memory',
11
+ * stores: {
12
+ * memory: storage.memory({ limit: 1000 }),
13
+ * lucid: storage.lucid({ connection: 'pg' }),
14
+ * },
15
+ * })
16
+ * ```
17
+ */
18
+ export function defineConfig(config) {
19
+ return config;
20
+ }
21
+ /** Apply defaults to a (possibly partial) config. */
22
+ export function resolveConfig(config = {}) {
23
+ const watchers = config.watchers ?? ['request', 'diagnostics'];
24
+ return {
25
+ enabled: config.enabled ?? true,
26
+ store: config.store ?? 'memory',
27
+ stores: config.stores ?? {},
28
+ maxEntries: config.maxEntries ?? 1000,
29
+ watchers: new Set(watchers),
30
+ extensions: config.extensions ?? [],
31
+ redact: {
32
+ enabled: config.redact?.enabled ?? true,
33
+ keys: config.redact?.keys ?? [],
34
+ },
35
+ };
36
+ }
37
+ export { storage };
38
+ //# sourceMappingURL=define_config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../src/define_config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,OAAO,EAAE,MAAM,qBAAqB,CAAC;AA6FlE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,YAAY,CAAC,MAAuB;IAClD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,aAAa,CAAC,SAA0B,EAAE;IACxD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAC/D,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI;QAC/B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,QAAQ;QAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;QACrC,QAAQ,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;QACnC,MAAM,EAAE;YACN,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;YACvC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE;SAChC;KACF,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,OAAO,EAAE,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Structural reader for the `@adonis-agora/diagnostics` channel registry — WITHOUT
3
+ * importing it.
4
+ *
5
+ * `@adonis-agora/diagnostics` publishes its registry on the cross-copy-stable global slot
6
+ * `Symbol.for('@agora/diagnostics:registry')`: `{ channels: Set<string>,
7
+ * listeners: Set<(name: string) => void> }`. Telescope is a separate repo and
8
+ * cannot depend on `@adonis-agora/diagnostics`, so the {@link DiagnosticsWatcher} reads
9
+ * this slot structurally to learn the current `agora:<lib>:<event>` channel names
10
+ * and to be notified of future ones, then subscribes to each via the Node builtin
11
+ * `node:diagnostics_channel` (which needs no import of the Agora package).
12
+ */
13
+ /** The registry shape `@adonis-agora/diagnostics` publishes on the global slot. */
14
+ export interface DiagnosticsRegistry {
15
+ /** Every channel name registered so far. */
16
+ channels: Set<string>;
17
+ /** Listeners notified once per newly-registered channel name. */
18
+ listeners: Set<(name: string) => void>;
19
+ }
20
+ /**
21
+ * The registry `@adonis-agora/diagnostics` published, or `undefined` when the package is
22
+ * not loaded. Returned WITHOUT creating a slot — telescope only ever reads.
23
+ */
24
+ export declare function getDiagnosticsRegistry(): DiagnosticsRegistry | undefined;
25
+ /**
26
+ * The envelope `@adonis-agora/diagnostics` publishes on each channel. Defined LOCALLY
27
+ * (mirrors `DiagnosticEvent`) so telescope validates it structurally without an
28
+ * import. `v` may be absent on legacy envelopes; `traceId` may be absent.
29
+ */
30
+ export interface DiagnosticEvent<TPayload = unknown> {
31
+ /** Envelope schema version, or absent on a legacy (pre-versioning) envelope. */
32
+ v?: number;
33
+ /** Epoch millis the producer stamped the event with. */
34
+ ts: number;
35
+ /** The emitting library, e.g. `'billing'`. */
36
+ lib: string;
37
+ /** The event within that library, e.g. `'invoice-paid'`. */
38
+ event: string;
39
+ /** The trace id the producer resolved, or absent when none. */
40
+ traceId?: string;
41
+ /** The library-defined payload. */
42
+ payload: TPayload;
43
+ }
44
+ /** Strict structural validation of a diagnostics envelope. */
45
+ export declare function isDiagnosticEvent(msg: unknown): msg is DiagnosticEvent;
46
+ //# sourceMappingURL=diagnostics_registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics_registry.d.ts","sourceRoot":"","sources":["../../src/diagnostics_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,mFAAmF;AACnF,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,iEAAiE;IACjE,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC;CACxC;AAID;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,mBAAmB,GAAG,SAAS,CAExE;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ,GAAG,OAAO;IACjD,gFAAgF;IAChF,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,eAAe,CAYtE"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Structural reader for the `@adonis-agora/diagnostics` channel registry — WITHOUT
3
+ * importing it.
4
+ *
5
+ * `@adonis-agora/diagnostics` publishes its registry on the cross-copy-stable global slot
6
+ * `Symbol.for('@agora/diagnostics:registry')`: `{ channels: Set<string>,
7
+ * listeners: Set<(name: string) => void> }`. Telescope is a separate repo and
8
+ * cannot depend on `@adonis-agora/diagnostics`, so the {@link DiagnosticsWatcher} reads
9
+ * this slot structurally to learn the current `agora:<lib>:<event>` channel names
10
+ * and to be notified of future ones, then subscribes to each via the Node builtin
11
+ * `node:diagnostics_channel` (which needs no import of the Agora package).
12
+ */
13
+ const REGISTRY_KEY = Symbol.for('@agora/diagnostics:registry');
14
+ /**
15
+ * The registry `@adonis-agora/diagnostics` published, or `undefined` when the package is
16
+ * not loaded. Returned WITHOUT creating a slot — telescope only ever reads.
17
+ */
18
+ export function getDiagnosticsRegistry() {
19
+ return globalThis[REGISTRY_KEY];
20
+ }
21
+ /** Strict structural validation of a diagnostics envelope. */
22
+ export function isDiagnosticEvent(msg) {
23
+ if (typeof msg !== 'object' || msg === null)
24
+ return false;
25
+ const m = msg;
26
+ return (typeof m.ts === 'number' &&
27
+ typeof m.lib === 'string' &&
28
+ typeof m.event === 'string' &&
29
+ 'payload' in m &&
30
+ (m.traceId === undefined || typeof m.traceId === 'string') &&
31
+ // Tolerate legacy envelopes without `v`; reject a malformed (non-number) one.
32
+ (m.v === undefined || typeof m.v === 'number'));
33
+ }
34
+ //# sourceMappingURL=diagnostics_registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics_registry.js","sourceRoot":"","sources":["../../src/diagnostics_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;AAE/D;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAQ,UAAsC,CAAC,YAAY,CAAoC,CAAC;AAClG,CAAC;AAsBD,8DAA8D;AAC9D,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,OAAO,CACL,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ;QACxB,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ;QACzB,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAC3B,SAAS,IAAI,CAAC;QACd,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC;QAC1D,8EAA8E;QAC9E,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAC/C,CAAC;AACJ,CAAC"}