@singhak/nodeui-core 0.3.0 → 0.3.1

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.d.mts CHANGED
@@ -155,9 +155,37 @@ interface RequestEntry {
155
155
  timestampMs: number;
156
156
  ip: string;
157
157
  }
158
+ interface RouteStat {
159
+ method: string;
160
+ path: string;
161
+ count: number;
162
+ avgMs: number;
163
+ p95Ms: number;
164
+ errors: number;
165
+ }
166
+ interface RequestsSummary {
167
+ /** Requests currently held in the ring buffer. */
168
+ count: number;
169
+ errors: number;
170
+ /** `errors / count` in 0..1 (5xx only). */
171
+ errorRate: number;
172
+ avgMs: number;
173
+ p50Ms: number;
174
+ p95Ms: number;
175
+ p99Ms: number;
176
+ byStatus: {
177
+ '2xx': number;
178
+ '3xx': number;
179
+ '4xx': number;
180
+ '5xx': number;
181
+ };
182
+ /** Busiest/slowest routes, slowest p95 first (at most 8). */
183
+ routes: RouteStat[];
184
+ }
158
185
  interface RequestsData {
159
186
  total: number;
160
187
  entries: RequestEntry[];
188
+ summary: RequestsSummary;
161
189
  }
162
190
  interface EnvEntry {
163
191
  key: string;
@@ -236,7 +264,7 @@ interface ConfigData {
236
264
  enabled: boolean;
237
265
  pattern: string;
238
266
  };
239
- authRequired: boolean;
267
+ locked: boolean;
240
268
  /** Plugin panel ids and titles, in registration order. */
241
269
  plugins: Array<{
242
270
  id: PanelId;
@@ -534,6 +562,7 @@ declare class HeapSnapshotProvider implements NodeUIProvider<HeapSnapshotPanelDa
534
562
  takeSnapshot(ctx: ProviderContext): Promise<ProviderResult<HeapSnapshotData>>;
535
563
  }
536
564
 
565
+ declare function summarizeRequests(entries: readonly RequestEntry[]): RequestsSummary;
537
566
  /** Fixed-size ring buffer of recent HTTP requests, recorded via middleware hook. */
538
567
  declare class RequestsProvider implements NodeUIProvider<RequestsData> {
539
568
  readonly id: "requests";
@@ -737,4 +766,4 @@ type NodeUIMiddleware = (req: IncomingMessage, res: ServerResponse, next: () =>
737
766
  declare function serializeEnvelope<T>(envelope: ApiEnvelope<T>, mask?: boolean): string;
738
767
  declare function createNodeUI(options?: NodeUIOptions): NodeUIServer;
739
768
 
740
- export { AUTH_COOKIE, type ActivationDecision, type ApiEnvelope, type BuiltInPanelId, type ConfigData, type ConfirmIssued, ConfirmationStore, type CpuClock, type CpuData, CpuProvider, type CpuUsageSnapshot, DEFAULT_LOG_SIZE, type EnvData, type EnvEntry, EnvProvider, type EventLoopClock, EventLoopLagProvider, type EventLoopSample, type GuardOptions, type GuardResult, type HealthCheck, type HealthCheckResult, type HealthData, HealthProvider, type HeapSnapshotData, type HeapSnapshotPanelData, HeapSnapshotProvider, type LogEntry, type LogLevel, type LogsData, LogsProvider, type MemoryData, MemoryProvider, type MetricsBucket, type MetricsData, MetricsProvider, type NodeUIConfig, type NodeUIMiddleware, type NodeUIOptions, type NodeUIProvider, type NodeUIServer, type OutgoingData, OutgoingProvider, type OutgoingRequestEntry, type PanelId, type ProviderContext, type ProviderError, ProviderRegistry, type ProviderResult, type RequestEntry, type RequestsData, RequestsProvider, RingBuffer, type RouteEntry, type RoutesData, RoutesProvider, SECRET_KEY_PATTERN, SECRET_MASKED, Sampler, type SamplerOptions, type SseStream, type StartupData, type StartupMark, StartupTracker, type StaticAsset, createGuard, createNodeUI, extractRoutes, hostnameFromHostHeader, interceptConsole, interceptOutgoing, isLoopbackAddress, isLoopbackHostname, maskSecretText, maskSecrets, matchesAddress, resolveActivation, resolveStaticAsset, serializeEnvelope, startSse };
769
+ export { AUTH_COOKIE, type ActivationDecision, type ApiEnvelope, type BuiltInPanelId, type ConfigData, type ConfirmIssued, ConfirmationStore, type CpuClock, type CpuData, CpuProvider, type CpuUsageSnapshot, DEFAULT_LOG_SIZE, type EnvData, type EnvEntry, EnvProvider, type EventLoopClock, EventLoopLagProvider, type EventLoopSample, type GuardOptions, type GuardResult, type HealthCheck, type HealthCheckResult, type HealthData, HealthProvider, type HeapSnapshotData, type HeapSnapshotPanelData, HeapSnapshotProvider, type LogEntry, type LogLevel, type LogsData, LogsProvider, type MemoryData, MemoryProvider, type MetricsBucket, type MetricsData, MetricsProvider, type NodeUIConfig, type NodeUIMiddleware, type NodeUIOptions, type NodeUIProvider, type NodeUIServer, type OutgoingData, OutgoingProvider, type OutgoingRequestEntry, type PanelId, type ProviderContext, type ProviderError, ProviderRegistry, type ProviderResult, type RequestEntry, type RequestsData, RequestsProvider, type RequestsSummary, RingBuffer, type RouteEntry, type RouteStat, type RoutesData, RoutesProvider, SECRET_KEY_PATTERN, SECRET_MASKED, Sampler, type SamplerOptions, type SseStream, type StartupData, type StartupMark, StartupTracker, type StaticAsset, createGuard, createNodeUI, extractRoutes, hostnameFromHostHeader, interceptConsole, interceptOutgoing, isLoopbackAddress, isLoopbackHostname, maskSecretText, maskSecrets, matchesAddress, resolveActivation, resolveStaticAsset, serializeEnvelope, startSse, summarizeRequests };
package/dist/index.d.ts CHANGED
@@ -155,9 +155,37 @@ interface RequestEntry {
155
155
  timestampMs: number;
156
156
  ip: string;
157
157
  }
158
+ interface RouteStat {
159
+ method: string;
160
+ path: string;
161
+ count: number;
162
+ avgMs: number;
163
+ p95Ms: number;
164
+ errors: number;
165
+ }
166
+ interface RequestsSummary {
167
+ /** Requests currently held in the ring buffer. */
168
+ count: number;
169
+ errors: number;
170
+ /** `errors / count` in 0..1 (5xx only). */
171
+ errorRate: number;
172
+ avgMs: number;
173
+ p50Ms: number;
174
+ p95Ms: number;
175
+ p99Ms: number;
176
+ byStatus: {
177
+ '2xx': number;
178
+ '3xx': number;
179
+ '4xx': number;
180
+ '5xx': number;
181
+ };
182
+ /** Busiest/slowest routes, slowest p95 first (at most 8). */
183
+ routes: RouteStat[];
184
+ }
158
185
  interface RequestsData {
159
186
  total: number;
160
187
  entries: RequestEntry[];
188
+ summary: RequestsSummary;
161
189
  }
162
190
  interface EnvEntry {
163
191
  key: string;
@@ -236,7 +264,7 @@ interface ConfigData {
236
264
  enabled: boolean;
237
265
  pattern: string;
238
266
  };
239
- authRequired: boolean;
267
+ locked: boolean;
240
268
  /** Plugin panel ids and titles, in registration order. */
241
269
  plugins: Array<{
242
270
  id: PanelId;
@@ -534,6 +562,7 @@ declare class HeapSnapshotProvider implements NodeUIProvider<HeapSnapshotPanelDa
534
562
  takeSnapshot(ctx: ProviderContext): Promise<ProviderResult<HeapSnapshotData>>;
535
563
  }
536
564
 
565
+ declare function summarizeRequests(entries: readonly RequestEntry[]): RequestsSummary;
537
566
  /** Fixed-size ring buffer of recent HTTP requests, recorded via middleware hook. */
538
567
  declare class RequestsProvider implements NodeUIProvider<RequestsData> {
539
568
  readonly id: "requests";
@@ -737,4 +766,4 @@ type NodeUIMiddleware = (req: IncomingMessage, res: ServerResponse, next: () =>
737
766
  declare function serializeEnvelope<T>(envelope: ApiEnvelope<T>, mask?: boolean): string;
738
767
  declare function createNodeUI(options?: NodeUIOptions): NodeUIServer;
739
768
 
740
- export { AUTH_COOKIE, type ActivationDecision, type ApiEnvelope, type BuiltInPanelId, type ConfigData, type ConfirmIssued, ConfirmationStore, type CpuClock, type CpuData, CpuProvider, type CpuUsageSnapshot, DEFAULT_LOG_SIZE, type EnvData, type EnvEntry, EnvProvider, type EventLoopClock, EventLoopLagProvider, type EventLoopSample, type GuardOptions, type GuardResult, type HealthCheck, type HealthCheckResult, type HealthData, HealthProvider, type HeapSnapshotData, type HeapSnapshotPanelData, HeapSnapshotProvider, type LogEntry, type LogLevel, type LogsData, LogsProvider, type MemoryData, MemoryProvider, type MetricsBucket, type MetricsData, MetricsProvider, type NodeUIConfig, type NodeUIMiddleware, type NodeUIOptions, type NodeUIProvider, type NodeUIServer, type OutgoingData, OutgoingProvider, type OutgoingRequestEntry, type PanelId, type ProviderContext, type ProviderError, ProviderRegistry, type ProviderResult, type RequestEntry, type RequestsData, RequestsProvider, RingBuffer, type RouteEntry, type RoutesData, RoutesProvider, SECRET_KEY_PATTERN, SECRET_MASKED, Sampler, type SamplerOptions, type SseStream, type StartupData, type StartupMark, StartupTracker, type StaticAsset, createGuard, createNodeUI, extractRoutes, hostnameFromHostHeader, interceptConsole, interceptOutgoing, isLoopbackAddress, isLoopbackHostname, maskSecretText, maskSecrets, matchesAddress, resolveActivation, resolveStaticAsset, serializeEnvelope, startSse };
769
+ export { AUTH_COOKIE, type ActivationDecision, type ApiEnvelope, type BuiltInPanelId, type ConfigData, type ConfirmIssued, ConfirmationStore, type CpuClock, type CpuData, CpuProvider, type CpuUsageSnapshot, DEFAULT_LOG_SIZE, type EnvData, type EnvEntry, EnvProvider, type EventLoopClock, EventLoopLagProvider, type EventLoopSample, type GuardOptions, type GuardResult, type HealthCheck, type HealthCheckResult, type HealthData, HealthProvider, type HeapSnapshotData, type HeapSnapshotPanelData, HeapSnapshotProvider, type LogEntry, type LogLevel, type LogsData, LogsProvider, type MemoryData, MemoryProvider, type MetricsBucket, type MetricsData, MetricsProvider, type NodeUIConfig, type NodeUIMiddleware, type NodeUIOptions, type NodeUIProvider, type NodeUIServer, type OutgoingData, OutgoingProvider, type OutgoingRequestEntry, type PanelId, type ProviderContext, type ProviderError, ProviderRegistry, type ProviderResult, type RequestEntry, type RequestsData, RequestsProvider, type RequestsSummary, RingBuffer, type RouteEntry, type RouteStat, type RoutesData, RoutesProvider, SECRET_KEY_PATTERN, SECRET_MASKED, Sampler, type SamplerOptions, type SseStream, type StartupData, type StartupMark, StartupTracker, type StaticAsset, createGuard, createNodeUI, extractRoutes, hostnameFromHostHeader, interceptConsole, interceptOutgoing, isLoopbackAddress, isLoopbackHostname, maskSecretText, maskSecrets, matchesAddress, resolveActivation, resolveStaticAsset, serializeEnvelope, startSse, summarizeRequests };
package/dist/index.mjs CHANGED
@@ -915,6 +915,54 @@ var HeapSnapshotProvider = class {
915
915
 
916
916
  // src/providers/requests.ts
917
917
  var RESPONSE_PAGE_SIZE2 = 100;
918
+ var MAX_ROUTE_STATS = 8;
919
+ function percentile(sorted, p) {
920
+ if (sorted.length === 0) return 0;
921
+ const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil(p * sorted.length) - 1));
922
+ return sorted[index] ?? 0;
923
+ }
924
+ function routeKey(path2) {
925
+ return path2.split("/").map(
926
+ (seg) => /^\d+$/.test(seg) || /^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(seg) || /^[0-9a-f]{24}$/i.test(seg) ? ":id" : seg
927
+ ).join("/");
928
+ }
929
+ function summarizeRequests(entries) {
930
+ const durations = entries.map((e) => e.durationMs).sort((a, b) => a - b);
931
+ const byStatus = { "2xx": 0, "3xx": 0, "4xx": 0, "5xx": 0 };
932
+ const groups = /* @__PURE__ */ new Map();
933
+ for (const e of entries) {
934
+ const bucket = `${Math.floor(e.status / 100)}xx`;
935
+ if (bucket in byStatus) byStatus[bucket] += 1;
936
+ const path2 = routeKey(e.path);
937
+ const key = `${e.method} ${path2}`;
938
+ const group = groups.get(key) ?? { method: e.method, path: path2, ms: [], errors: 0 };
939
+ group.ms.push(e.durationMs);
940
+ if (e.status >= 500) group.errors += 1;
941
+ groups.set(key, group);
942
+ }
943
+ const routes = [...groups.values()].map((g) => {
944
+ const sorted = [...g.ms].sort((a, b) => a - b);
945
+ return {
946
+ method: g.method,
947
+ path: g.path,
948
+ count: g.ms.length,
949
+ avgMs: g.ms.reduce((a, b) => a + b, 0) / g.ms.length,
950
+ p95Ms: percentile(sorted, 0.95),
951
+ errors: g.errors
952
+ };
953
+ }).sort((a, b) => b.p95Ms - a.p95Ms).slice(0, MAX_ROUTE_STATS);
954
+ return {
955
+ count: entries.length,
956
+ errors: byStatus["5xx"],
957
+ errorRate: entries.length === 0 ? 0 : byStatus["5xx"] / entries.length,
958
+ avgMs: durations.length === 0 ? 0 : durations.reduce((a, b) => a + b, 0) / durations.length,
959
+ p50Ms: percentile(durations, 0.5),
960
+ p95Ms: percentile(durations, 0.95),
961
+ p99Ms: percentile(durations, 0.99),
962
+ byStatus,
963
+ routes
964
+ };
965
+ }
918
966
  var RequestsProvider = class {
919
967
  id = "requests";
920
968
  buffer;
@@ -931,7 +979,8 @@ var RequestsProvider = class {
931
979
  }
932
980
  get() {
933
981
  const entries = this.buffer.slice(Math.max(0, this.buffer.length - RESPONSE_PAGE_SIZE2));
934
- return { ok: true, data: { total: this.buffer.length, entries } };
982
+ const summary = summarizeRequests(this.buffer.toArray());
983
+ return { ok: true, data: { total: this.buffer.length, entries, summary } };
935
984
  }
936
985
  };
937
986
 
@@ -1453,7 +1502,7 @@ function createNodeUI(options = {}) {
1453
1502
  pollIntervalMs: config.pollIntervalMs,
1454
1503
  panels: registry.ids(),
1455
1504
  masking: { enabled: config.maskSecrets, pattern: SECRET_KEY_PATTERN.source },
1456
- authRequired: config.authRequired,
1505
+ locked: config.authRequired,
1457
1506
  plugins: pluginMeta
1458
1507
  };
1459
1508
  }
@@ -1722,6 +1771,7 @@ export {
1722
1771
  resolveActivation,
1723
1772
  resolveStaticAsset,
1724
1773
  serializeEnvelope,
1725
- startSse
1774
+ startSse,
1775
+ summarizeRequests
1726
1776
  };
1727
1777
  //# sourceMappingURL=index.mjs.map