@junando/core 0.12.3 → 0.14.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.
- package/dist/index.d.ts +38 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +204 -90
- package/dist/index.js.map +1 -1
- package/dist/shared/metrics/index.d.ts +3 -3
- package/dist/shared/metrics/index.d.ts.map +1 -1
- package/dist/shared/metrics/index.js +6 -6
- package/dist/shared/metrics/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -556,6 +556,13 @@ interface IAlertQueue {
|
|
|
556
556
|
interface ITraceRepository {
|
|
557
557
|
findByTraceId(traceId: string): Promise<Record<string, unknown>[]>;
|
|
558
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* Reason a parse attempt could not produce a diagnosis.
|
|
561
|
+
* `unparseable_response` — non-empty raw text that neither JSON nor regex
|
|
562
|
+
* stage could extract a usable analysis from.
|
|
563
|
+
* `empty_response` — the provider returned an empty (or whitespace-only) string.
|
|
564
|
+
*/
|
|
565
|
+
type LlmDegradedReason = 'unparseable_response' | 'empty_response';
|
|
559
566
|
/**
|
|
560
567
|
* Structured result of an LLM analysis call.
|
|
561
568
|
* Carries the diagnosis plus the observability metadata that feeds the
|
|
@@ -563,7 +570,8 @@ interface ITraceRepository {
|
|
|
563
570
|
* total tokens = promptTokens + completionTokens).
|
|
564
571
|
*/
|
|
565
572
|
interface LLMResult {
|
|
566
|
-
analysis: LLMAnalysis;
|
|
573
|
+
analysis: LLMAnalysis | null;
|
|
574
|
+
degradedReason?: LlmDegradedReason;
|
|
567
575
|
provider: string;
|
|
568
576
|
model: string;
|
|
569
577
|
latencyMs: number;
|
|
@@ -776,7 +784,10 @@ interface LlmSection {
|
|
|
776
784
|
provider: string;
|
|
777
785
|
model: string;
|
|
778
786
|
latencyMs: number;
|
|
779
|
-
|
|
787
|
+
/** Present only when parseAnalysis produced a diagnosis. */
|
|
788
|
+
urgency?: string;
|
|
789
|
+
/** Present only when analysis is null — why no diagnosis was produced. */
|
|
790
|
+
degradedReason?: string;
|
|
780
791
|
tokens: number;
|
|
781
792
|
}
|
|
782
793
|
interface NotifySection {
|
|
@@ -868,6 +879,13 @@ export declare class ProcessIncidentUseCase {
|
|
|
868
879
|
private readonly wideEventsEnabled;
|
|
869
880
|
constructor(deps: Dependencies);
|
|
870
881
|
execute(alerts: NormalizedAlert[], correlationId: string): Promise<void>;
|
|
882
|
+
/**
|
|
883
|
+
* Releases the dedup claim so an SQS retry is not discarded as a duplicate.
|
|
884
|
+
* Concurrency: safe without a lock — sqs.adapter.ts sets messageGroupId to
|
|
885
|
+
* the fingerprint, so SQS FIFO serialises delivery per fingerprint and two
|
|
886
|
+
* runs for the same fingerprint are never in flight simultaneously.
|
|
887
|
+
*/
|
|
888
|
+
private releaseDedupClaim;
|
|
871
889
|
/**
|
|
872
890
|
* Flushes the builder into a final event, applies tail sampling, redacts
|
|
873
891
|
* PII, and emits the single canonical log line for the cluster.
|
|
@@ -890,6 +908,17 @@ export declare class InMemoryDeduplicationStore implements IDeduplicationStore {
|
|
|
890
908
|
clear(): void;
|
|
891
909
|
}
|
|
892
910
|
//#endregion
|
|
911
|
+
//#region src/infrastructure/dedup/dynamodb-dedup.adapter.d.ts
|
|
912
|
+
export declare class DynamoDBDeduplicationStore implements IDeduplicationStore {
|
|
913
|
+
private readonly tableName;
|
|
914
|
+
private readonly region?;
|
|
915
|
+
private client;
|
|
916
|
+
constructor(tableName: string, region?: string | undefined);
|
|
917
|
+
private getClient;
|
|
918
|
+
isNew(fingerprint: string, ttlSeconds: number): Promise<DedupResult>;
|
|
919
|
+
reset(fingerprint: string): Promise<void>;
|
|
920
|
+
}
|
|
921
|
+
//#endregion
|
|
893
922
|
//#region src/infrastructure/indexer/opensearch.adapter.d.ts
|
|
894
923
|
interface SignedHttpRequest {
|
|
895
924
|
method: string;
|
|
@@ -992,7 +1021,12 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
992
1021
|
rollbackActionAllowedSlackUserIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
993
1022
|
teamsWebhookUrl: z.ZodOptional<z.ZodString>;
|
|
994
1023
|
lokiUrl: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<string | undefined, string | undefined>>;
|
|
995
|
-
|
|
1024
|
+
dedupStore: z.ZodDefault<z.ZodEnum<{
|
|
1025
|
+
dynamodb: "dynamodb";
|
|
1026
|
+
redis: "redis";
|
|
1027
|
+
}>>;
|
|
1028
|
+
dedupTableName: z.ZodOptional<z.ZodString>;
|
|
1029
|
+
redisUrl: z.ZodOptional<z.ZodString>;
|
|
996
1030
|
sqsQueueUrl: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
|
|
997
1031
|
dedupTtlSeconds: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
998
1032
|
clusterWindowMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -1258,5 +1292,5 @@ export declare class FactoryRegistry<T> {
|
|
|
1258
1292
|
*/
|
|
1259
1293
|
export declare function flushLoki(): Promise<void>;
|
|
1260
1294
|
//#endregion
|
|
1261
|
-
export { type Config, type DedupResult, type IAlertQueue, type IDeduplicationStore, type IIndexer, type ILLMProvider, type INotifier, type IRollbackActionHandler, type IRuleEngine, type ITraceRepository, type LLMResult, type Logger, type LoggerOptions, type NotifyResult, type OpenSearchHttpFetcher, type OpenSearchHttpResponse, type OpenSearchIndexerDeps, type RollbackActionRequest, type RollbackActionResult, type RuleActionResult, type SignedHttpRequest, type TraceabilityDocument, index_d_exports as metrics };
|
|
1295
|
+
export { type Config, type DedupResult, type IAlertQueue, type IDeduplicationStore, type IIndexer, type ILLMProvider, type INotifier, type IRollbackActionHandler, type IRuleEngine, type ITraceRepository, type LLMResult, type LlmDegradedReason, type Logger, type LoggerOptions, type NotifyResult, type OpenSearchHttpFetcher, type OpenSearchHttpResponse, type OpenSearchIndexerDeps, type RollbackActionRequest, type RollbackActionResult, type RuleActionResult, type SignedHttpRequest, type TraceabilityDocument, index_d_exports as metrics };
|
|
1262
1296
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/shared/constants.ts","../src/domain/entities/alert.ts","../src/domain/entities/cluster.ts","../src/domain/entities/incident.ts","../src/domain/entities/rule.ts","../src/domain/entities/traceability.ts","../src/domain/value-objects/fingerprint.ts","../src/domain/ports/index.ts","../src/domain/services/clustering.service.ts","../src/application/dtos/normalize-payload.ts","../src/shared/logger/enums.ts","../src/shared/logger/wide-event-builder.ts","../src/shared/logger/index.ts","../src/application/use-cases/process-incident.use-case.ts","../src/infrastructure/dedup/redis-dedup.adapter.ts","../src/infrastructure/indexer/opensearch.adapter.ts","../src/infrastructure/llm/llm.adapter.ts","../src/shared/config/index.ts","../src/infrastructure/rules/channel-registry.ts","../src/infrastructure/notifier/factory.ts","../src/infrastructure/rollback/factory.ts","../src/infrastructure/rollback/noop-rollback-action.handler.ts","../src/infrastructure/notifier/slack.adapter.ts","../src/infrastructure/notifier/teams.adapter.ts","../src/infrastructure/notifier/routing-notifier.ts","../src/infrastructure/queue/sqs.adapter.ts","../src/infrastructure/queue/sqs-lag-poller.ts","../src/infrastructure/traces/loki-trace.adapter.ts","../src/infrastructure/rules/yaml-rule-loader.ts","../src/infrastructure/rules/condition-evaluator.ts","../src/infrastructure/rules/action-dispatcher.ts","../src/infrastructure/rules/rule-engine.ts","../src/shared/factory-registry.ts","../src/shared/logger/loki-transport.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/shared/constants.ts","../src/domain/entities/alert.ts","../src/domain/entities/cluster.ts","../src/domain/entities/incident.ts","../src/domain/entities/rule.ts","../src/domain/entities/traceability.ts","../src/domain/value-objects/fingerprint.ts","../src/domain/ports/index.ts","../src/domain/services/clustering.service.ts","../src/application/dtos/normalize-payload.ts","../src/shared/logger/enums.ts","../src/shared/logger/wide-event-builder.ts","../src/shared/logger/index.ts","../src/application/use-cases/process-incident.use-case.ts","../src/infrastructure/dedup/redis-dedup.adapter.ts","../src/infrastructure/dedup/dynamodb-dedup.adapter.ts","../src/infrastructure/indexer/opensearch.adapter.ts","../src/infrastructure/llm/llm.adapter.ts","../src/shared/config/index.ts","../src/infrastructure/rules/channel-registry.ts","../src/infrastructure/notifier/factory.ts","../src/infrastructure/rollback/factory.ts","../src/infrastructure/rollback/noop-rollback-action.handler.ts","../src/infrastructure/notifier/slack.adapter.ts","../src/infrastructure/notifier/teams.adapter.ts","../src/infrastructure/notifier/routing-notifier.ts","../src/infrastructure/queue/sqs.adapter.ts","../src/infrastructure/queue/sqs-lag-poller.ts","../src/infrastructure/traces/loki-trace.adapter.ts","../src/infrastructure/rules/yaml-rule-loader.ts","../src/infrastructure/rules/condition-evaluator.ts","../src/infrastructure/rules/action-dispatcher.ts","../src/infrastructure/rules/rule-engine.ts","../src/shared/factory-registry.ts","../src/shared/logger/loki-transport.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./rolldown-runtime-BMI-E3GI.js";
|
|
2
|
-
import { dedupDuplicate,
|
|
2
|
+
import { dedupDuplicate, dedupFailoverTotal, dedupNew, llmInferenceDuration, llmInferenceTotal, notificationsTotal, sqsQueueLag, suppressedClusters, t as metrics_exports } from "./shared/metrics/index.js";
|
|
3
3
|
import { $ as booleanSelector, $t as ServiceException, A as BinaryDecisionDiagram, An as isValidHostLabel, B as NODE_REGION_CONFIG_FILE_OPTIONS, C as isIpAddress, Ct as dateToUtcString, Dt as parseRfc7231DateTime, E as EndpointError, En as normalizeProvider$1, Et as parseRfc3339DateTimeWithOffset, F as init_config$1, Fn as hasOwn, G as NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, H as REGION_ENV_NAME, Ht as NoOpLogger, It as fromBase64, Jt as resolveDefaultRuntimeConfig, Kt as getDefaultExtensionConfiguration, L as resolveDefaultsModeConfig, Ln as getSmithyContext, N as resolveParams, Nn as HttpRequest, Nt as toBase64, O as EndpointCache, On as isValidHostname, Ot as expectUnion, P as config_exports, Pt as fromUtf8, Qt as loadConfigsForDefaultMode, Rt as client_exports$1, Sn as parseUrl, Tt as parseEpochTimestamp, U as REGION_INI_NAME, V as NODE_REGION_CONFIG_OPTIONS, Vt as makeBuilder, Wt as getValueFromTextNode, X as loadConfig$1, Yt as emitWarningIfUnsupportedVersion$1, Z as SelectorType, _ as resolveEndpointConfig, _t as _parseRfc7231DateTime, b as decideEndpoint, bn as init_transport, bt as quoteHeader, c as generateIdempotencyToken, cn as TypeRegistry, ct as NumericValue, d as v4, en as decorateServiceException, ft as splitHeader, g as init_endpoints, gn as deref, gt as _parseRfc3339DateTimeWithOffset, h as getEndpointPlugin, ht as _parseEpochTimestamp, in as Command, jn as HttpResponse, jt as toUtf8, l as init_serde, m as endpoints_exports, mn as getSchemaSerdePlugin, mt as splitEvery, n as init_checksum, nn as createAggregatedClient, on as init_schema, p as sdkStreamMixin, pn as translateTraits, q as NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, r as Sha256Node, rt as calculateBodyLength, s as Uint8ArrayBlobAdapter, sn as schema_exports, t as checksum_exports, tt as ProviderError, u as serde_exports, un as NormalizedSchema, ut as nv, vn as Client, w as customEndpointFunctions, wn as parseQueryString, xt as LazyJsonString, y as resolveEndpoint, z as resolveRegionConfig, zn as require_dist_cjs$17, zt as init_client$1 } from "./checksum-Bbvsykod.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
6
|
import pino from "pino";
|
|
7
7
|
import { Readable, Writable } from "node:stream";
|
|
8
|
+
import { DeleteItemCommand, DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
|
|
8
9
|
import * as Breaker from "opossum";
|
|
9
10
|
import { readFileSync } from "node:fs";
|
|
10
11
|
import { YAMLParseError, parse } from "yaml";
|
|
@@ -487,6 +488,58 @@ var WideEventBuilder = class {
|
|
|
487
488
|
};
|
|
488
489
|
}
|
|
489
490
|
};
|
|
491
|
+
//#endregion
|
|
492
|
+
//#region src/shared/logger/enums.ts
|
|
493
|
+
/**
|
|
494
|
+
* Pipeline component taxonomy.
|
|
495
|
+
*
|
|
496
|
+
* `component` (not `service`) distinguishes pipeline stages in wide events.
|
|
497
|
+
* `service` stays constant ("junando"); `component` tells you WHERE the event
|
|
498
|
+
* was emitted from.
|
|
499
|
+
*/
|
|
500
|
+
const Component = {
|
|
501
|
+
Webhook: "webhook",
|
|
502
|
+
Worker: "worker",
|
|
503
|
+
UseCase: "useCase",
|
|
504
|
+
Llm: "llm",
|
|
505
|
+
Notifier: "notifier",
|
|
506
|
+
Dedup: "dedup",
|
|
507
|
+
Traces: "traces",
|
|
508
|
+
Ingest: "ingest",
|
|
509
|
+
Rollback: "rollback"
|
|
510
|
+
};
|
|
511
|
+
/**
|
|
512
|
+
* Pipeline stages that write their results into the WideEventBuilder.
|
|
513
|
+
*/
|
|
514
|
+
const Stage = {
|
|
515
|
+
Dedup: "dedup",
|
|
516
|
+
RulesPre: "rulesPre",
|
|
517
|
+
Traces: "traces",
|
|
518
|
+
Llm: "llm",
|
|
519
|
+
RulesPost: "rulesPost",
|
|
520
|
+
Notify: "notify"
|
|
521
|
+
};
|
|
522
|
+
/**
|
|
523
|
+
* Terminal outcomes for a wide event across all entry points.
|
|
524
|
+
*/
|
|
525
|
+
const Outcome = {
|
|
526
|
+
Success: "success",
|
|
527
|
+
Suppressed: "suppressed",
|
|
528
|
+
Degraded: "degraded",
|
|
529
|
+
Error: "error",
|
|
530
|
+
Accepted: "accepted",
|
|
531
|
+
Empty: "empty",
|
|
532
|
+
ParseError: "parse_error"
|
|
533
|
+
};
|
|
534
|
+
/**
|
|
535
|
+
* Reason recorded for a tail-sampling decision.
|
|
536
|
+
*/
|
|
537
|
+
const SamplingDecision = {
|
|
538
|
+
Error: "error",
|
|
539
|
+
Slow: "slow",
|
|
540
|
+
Random: "random",
|
|
541
|
+
Skipped: "skipped"
|
|
542
|
+
};
|
|
490
543
|
/** Probability of sampling a normal (non-error, non-slow) event. */
|
|
491
544
|
const NORMAL_SAMPLE_RATE = .05;
|
|
492
545
|
/**
|
|
@@ -498,6 +551,7 @@ const NORMAL_SAMPLE_RATE = .05;
|
|
|
498
551
|
function shouldSample(event) {
|
|
499
552
|
if (event.error != null) return true;
|
|
500
553
|
if (event.durationMs !== void 0 && event.durationMs > 1e4) return true;
|
|
554
|
+
if (event.outcome === Outcome.Degraded) return true;
|
|
501
555
|
return Math.random() < NORMAL_SAMPLE_RATE;
|
|
502
556
|
}
|
|
503
557
|
//#endregion
|
|
@@ -568,58 +622,6 @@ function redact(obj) {
|
|
|
568
622
|
}));
|
|
569
623
|
}
|
|
570
624
|
//#endregion
|
|
571
|
-
//#region src/shared/logger/enums.ts
|
|
572
|
-
/**
|
|
573
|
-
* Pipeline component taxonomy.
|
|
574
|
-
*
|
|
575
|
-
* `component` (not `service`) distinguishes pipeline stages in wide events.
|
|
576
|
-
* `service` stays constant ("junando"); `component` tells you WHERE the event
|
|
577
|
-
* was emitted from.
|
|
578
|
-
*/
|
|
579
|
-
const Component = {
|
|
580
|
-
Webhook: "webhook",
|
|
581
|
-
Worker: "worker",
|
|
582
|
-
UseCase: "useCase",
|
|
583
|
-
Llm: "llm",
|
|
584
|
-
Notifier: "notifier",
|
|
585
|
-
Dedup: "dedup",
|
|
586
|
-
Traces: "traces",
|
|
587
|
-
Ingest: "ingest",
|
|
588
|
-
Rollback: "rollback"
|
|
589
|
-
};
|
|
590
|
-
/**
|
|
591
|
-
* Pipeline stages that write their results into the WideEventBuilder.
|
|
592
|
-
*/
|
|
593
|
-
const Stage = {
|
|
594
|
-
Dedup: "dedup",
|
|
595
|
-
RulesPre: "rulesPre",
|
|
596
|
-
Traces: "traces",
|
|
597
|
-
Llm: "llm",
|
|
598
|
-
RulesPost: "rulesPost",
|
|
599
|
-
Notify: "notify"
|
|
600
|
-
};
|
|
601
|
-
/**
|
|
602
|
-
* Terminal outcomes for a wide event across all entry points.
|
|
603
|
-
*/
|
|
604
|
-
const Outcome = {
|
|
605
|
-
Success: "success",
|
|
606
|
-
Suppressed: "suppressed",
|
|
607
|
-
Degraded: "degraded",
|
|
608
|
-
Error: "error",
|
|
609
|
-
Accepted: "accepted",
|
|
610
|
-
Empty: "empty",
|
|
611
|
-
ParseError: "parse_error"
|
|
612
|
-
};
|
|
613
|
-
/**
|
|
614
|
-
* Reason recorded for a tail-sampling decision.
|
|
615
|
-
*/
|
|
616
|
-
const SamplingDecision = {
|
|
617
|
-
Error: "error",
|
|
618
|
-
Slow: "slow",
|
|
619
|
-
Random: "random",
|
|
620
|
-
Skipped: "skipped"
|
|
621
|
-
};
|
|
622
|
-
//#endregion
|
|
623
625
|
//#region src/shared/logger/index.ts
|
|
624
626
|
let _root = buildLogger({});
|
|
625
627
|
function buildLogger(opts) {
|
|
@@ -689,12 +691,14 @@ function toErrorSection(err) {
|
|
|
689
691
|
}
|
|
690
692
|
/**
|
|
691
693
|
* Terminal outcome for a processed cluster. Early returns — no switch/case.
|
|
692
|
-
* Notify failure is fatal (the batch is retried via SQS); LLM
|
|
693
|
-
* degraded
|
|
694
|
+
* Notify failure is fatal (the batch is retried via SQS); LLM transport
|
|
695
|
+
* failure and a parse-degraded diagnosis both leave the cluster degraded
|
|
696
|
+
* (notification still went out, with or without a diagnosis).
|
|
694
697
|
*/
|
|
695
|
-
function resolveOutcome({ llmError, notifyError }) {
|
|
698
|
+
function resolveOutcome({ llmError, notifyError, llmDegradedReason }) {
|
|
696
699
|
if (notifyError != null) return Outcome.Error;
|
|
697
700
|
if (llmError != null) return Outcome.Degraded;
|
|
701
|
+
if (llmDegradedReason != null) return Outcome.Degraded;
|
|
698
702
|
return Outcome.Success;
|
|
699
703
|
}
|
|
700
704
|
var ProcessIncidentUseCase = class {
|
|
@@ -762,14 +766,17 @@ var ProcessIncidentUseCase = class {
|
|
|
762
766
|
});
|
|
763
767
|
let analysis = null;
|
|
764
768
|
let llmError = null;
|
|
769
|
+
let llmDegradedReason = null;
|
|
765
770
|
try {
|
|
766
771
|
const llmResult = await llm.analyze(cluster, allSpans);
|
|
767
772
|
analysis = llmResult.analysis;
|
|
773
|
+
llmDegradedReason = llmResult.degradedReason ?? null;
|
|
768
774
|
builder.set("llm", {
|
|
769
775
|
provider: llmResult.provider,
|
|
770
776
|
model: llmResult.model,
|
|
771
777
|
latencyMs: llmResult.latencyMs,
|
|
772
|
-
urgency: llmResult.analysis.urgency_level,
|
|
778
|
+
...llmResult.analysis && { urgency: llmResult.analysis.urgency_level },
|
|
779
|
+
...llmResult.degradedReason && { degradedReason: llmResult.degradedReason },
|
|
773
780
|
tokens: llmResult.promptTokens + llmResult.completionTokens
|
|
774
781
|
});
|
|
775
782
|
} catch (err) {
|
|
@@ -802,17 +809,35 @@ var ProcessIncidentUseCase = class {
|
|
|
802
809
|
latencyMs: Date.now() - notifyStartMs
|
|
803
810
|
});
|
|
804
811
|
builder.set("error", toErrorSection(err));
|
|
812
|
+
await this.releaseDedupClaim(cluster.fingerprint);
|
|
805
813
|
this.emit(builder, Outcome.Error, clusterStartMs);
|
|
806
814
|
throw err;
|
|
807
815
|
}
|
|
808
816
|
if (llmError != null) builder.set("error", toErrorSection(llmError));
|
|
809
817
|
this.emit(builder, resolveOutcome({
|
|
810
818
|
llmError,
|
|
811
|
-
notifyError: null
|
|
819
|
+
notifyError: null,
|
|
820
|
+
llmDegradedReason
|
|
812
821
|
}), clusterStartMs);
|
|
813
822
|
}
|
|
814
823
|
}
|
|
815
824
|
/**
|
|
825
|
+
* Releases the dedup claim so an SQS retry is not discarded as a duplicate.
|
|
826
|
+
* Concurrency: safe without a lock — sqs.adapter.ts sets messageGroupId to
|
|
827
|
+
* the fingerprint, so SQS FIFO serialises delivery per fingerprint and two
|
|
828
|
+
* runs for the same fingerprint are never in flight simultaneously.
|
|
829
|
+
*/
|
|
830
|
+
async releaseDedupClaim(fingerprint) {
|
|
831
|
+
try {
|
|
832
|
+
await this.deps.dedup.reset(fingerprint);
|
|
833
|
+
} catch (err) {
|
|
834
|
+
this.deps.logger.warn({
|
|
835
|
+
err,
|
|
836
|
+
fingerprint
|
|
837
|
+
}, "Failed to release dedup claim; retry may be suppressed");
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
816
841
|
* Flushes the builder into a final event, applies tail sampling, redacts
|
|
817
842
|
* PII, and emits the single canonical log line for the cluster.
|
|
818
843
|
*/
|
|
@@ -825,7 +850,7 @@ var ProcessIncidentUseCase = class {
|
|
|
825
850
|
};
|
|
826
851
|
//#endregion
|
|
827
852
|
//#region src/infrastructure/dedup/redis-dedup.adapter.ts
|
|
828
|
-
const logger$
|
|
853
|
+
const logger$7 = createLogger();
|
|
829
854
|
var RedisDeduplicationStore = class {
|
|
830
855
|
redis;
|
|
831
856
|
keyPrefix = "junando:dedup:";
|
|
@@ -840,11 +865,11 @@ var RedisDeduplicationStore = class {
|
|
|
840
865
|
};
|
|
841
866
|
} catch (err) {
|
|
842
867
|
const message = err instanceof Error ? err.message : String(err);
|
|
843
|
-
logger$
|
|
868
|
+
logger$7.warn({
|
|
844
869
|
err,
|
|
845
870
|
fingerprint
|
|
846
871
|
}, "Redis dedup check failed, failing open");
|
|
847
|
-
|
|
872
|
+
dedupFailoverTotal.inc();
|
|
848
873
|
return {
|
|
849
874
|
isNew: true,
|
|
850
875
|
ttlSeconds,
|
|
@@ -879,6 +904,63 @@ var InMemoryDeduplicationStore = class {
|
|
|
879
904
|
}
|
|
880
905
|
};
|
|
881
906
|
//#endregion
|
|
907
|
+
//#region src/infrastructure/dedup/dynamodb-dedup.adapter.ts
|
|
908
|
+
const logger$6 = createLogger();
|
|
909
|
+
const CONDITION_EXPRESSION = "attribute_not_exists(fingerprint) OR expiresAt < :now";
|
|
910
|
+
var DynamoDBDeduplicationStore = class {
|
|
911
|
+
tableName;
|
|
912
|
+
region;
|
|
913
|
+
client = null;
|
|
914
|
+
constructor(tableName, region) {
|
|
915
|
+
this.tableName = tableName;
|
|
916
|
+
this.region = region;
|
|
917
|
+
}
|
|
918
|
+
getClient() {
|
|
919
|
+
if (!this.client) this.client = new DynamoDBClient(this.region ? { region: this.region } : {});
|
|
920
|
+
return this.client;
|
|
921
|
+
}
|
|
922
|
+
async isNew(fingerprint, ttlSeconds) {
|
|
923
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
924
|
+
try {
|
|
925
|
+
await this.getClient().send(new PutItemCommand({
|
|
926
|
+
TableName: this.tableName,
|
|
927
|
+
Item: {
|
|
928
|
+
fingerprint: { S: fingerprint },
|
|
929
|
+
expiresAt: { N: String(nowSec + ttlSeconds) }
|
|
930
|
+
},
|
|
931
|
+
ConditionExpression: CONDITION_EXPRESSION,
|
|
932
|
+
ExpressionAttributeValues: { ":now": { N: String(nowSec) } }
|
|
933
|
+
}));
|
|
934
|
+
return {
|
|
935
|
+
isNew: true,
|
|
936
|
+
ttlSeconds
|
|
937
|
+
};
|
|
938
|
+
} catch (err) {
|
|
939
|
+
if (err instanceof Error && err.name === "ConditionalCheckFailedException") return {
|
|
940
|
+
isNew: false,
|
|
941
|
+
ttlSeconds
|
|
942
|
+
};
|
|
943
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
944
|
+
logger$6.warn({
|
|
945
|
+
err,
|
|
946
|
+
fingerprint
|
|
947
|
+
}, "DynamoDB dedup check failed, failing open");
|
|
948
|
+
dedupFailoverTotal.inc();
|
|
949
|
+
return {
|
|
950
|
+
isNew: true,
|
|
951
|
+
ttlSeconds,
|
|
952
|
+
error: message
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
async reset(fingerprint) {
|
|
957
|
+
await this.getClient().send(new DeleteItemCommand({
|
|
958
|
+
TableName: this.tableName,
|
|
959
|
+
Key: { fingerprint: { S: fingerprint } }
|
|
960
|
+
}));
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
//#endregion
|
|
882
964
|
//#region src/infrastructure/indexer/opensearch.adapter.ts
|
|
883
965
|
var OpenSearchIndexer = class {
|
|
884
966
|
endpoint;
|
|
@@ -961,20 +1043,22 @@ function buildUserPrompt(cluster, traces) {
|
|
|
961
1043
|
}
|
|
962
1044
|
/**
|
|
963
1045
|
* Extracts LLMAnalysis from raw LLM response text.
|
|
964
|
-
*
|
|
965
|
-
*
|
|
1046
|
+
* Two-stage parsing: JSON → regex fallback. Never fabricates a diagnosis —
|
|
1047
|
+
* returns null when neither stage produces a usable analysis.
|
|
966
1048
|
*/
|
|
967
1049
|
function parseAnalysis(raw, correlationId) {
|
|
968
1050
|
const startIdx = raw.indexOf("{");
|
|
969
1051
|
const endIdx = raw.lastIndexOf("}");
|
|
1052
|
+
let stage1Succeeded = false;
|
|
970
1053
|
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) try {
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1054
|
+
const analysis = LLMAnalysisSchema.parse(JSON.parse(raw.slice(startIdx, endIdx + 1)));
|
|
1055
|
+
stage1Succeeded = true;
|
|
1056
|
+
return analysis;
|
|
1057
|
+
} catch {}
|
|
1058
|
+
if (!stage1Succeeded) logger$5.warn({
|
|
1059
|
+
rawResponse: raw.slice(0, 500),
|
|
1060
|
+
correlationId
|
|
1061
|
+
}, "llm:parse:failed");
|
|
978
1062
|
const probableCauseMatch = RE_PROBABLE_CAUSE.exec(raw);
|
|
979
1063
|
const urgencyMatch = RE_URGENCY_LEVEL.exec(raw);
|
|
980
1064
|
const rollbackMatch = RE_REQUIRES_ROLLBACK.exec(raw);
|
|
@@ -991,20 +1075,34 @@ function parseAnalysis(raw, correlationId) {
|
|
|
991
1075
|
urgency_level: urgency,
|
|
992
1076
|
requires_rollback: rollbackMatch?.[1] === "true"
|
|
993
1077
|
};
|
|
994
|
-
|
|
1078
|
+
const parsed = LLMAnalysisSchema.parse(analysis);
|
|
1079
|
+
logger$5.warn({
|
|
1080
|
+
matchedFields: ["probable_cause", "urgency_level"],
|
|
1081
|
+
correlationId
|
|
1082
|
+
}, "llm:parse:partial");
|
|
1083
|
+
return parsed;
|
|
1084
|
+
}
|
|
1085
|
+
logger$5.warn({ correlationId }, "llm:parse:unusable");
|
|
1086
|
+
return null;
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Shared entry point for turning provider text into a diagnosis (or a
|
|
1090
|
+
* degradedReason explaining why not). Detects empty responses once, here,
|
|
1091
|
+
* before delegating to parseAnalysis.
|
|
1092
|
+
*/
|
|
1093
|
+
function parseLlmText(raw, correlationId) {
|
|
1094
|
+
if (raw.trim() === "") {
|
|
1095
|
+
logger$5.warn({ correlationId }, "llm:parse:empty");
|
|
1096
|
+
return {
|
|
1097
|
+
analysis: null,
|
|
1098
|
+
degradedReason: "empty_response"
|
|
1099
|
+
};
|
|
995
1100
|
}
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
return LLMAnalysisSchema.parse({
|
|
1002
|
-
probable_cause: "Analysis in progress - check logs for details",
|
|
1003
|
-
impacted_services: ["unknown-service"],
|
|
1004
|
-
recommended_steps: ["Review incident details in logs"],
|
|
1005
|
-
urgency_level: urgencyLevel,
|
|
1006
|
-
requires_rollback: lowerRaw.includes("rollback") || lowerRaw.includes("revert")
|
|
1007
|
-
});
|
|
1101
|
+
const analysis = parseAnalysis(raw, correlationId);
|
|
1102
|
+
return analysis ? { analysis } : {
|
|
1103
|
+
analysis: null,
|
|
1104
|
+
degradedReason: "unparseable_response"
|
|
1105
|
+
};
|
|
1008
1106
|
}
|
|
1009
1107
|
/**
|
|
1010
1108
|
* Gemini LLM provider using Google Generative AI SDK.
|
|
@@ -1043,7 +1141,7 @@ var GeminiProvider = class {
|
|
|
1043
1141
|
}).generateContent(buildUserPrompt(cluster, traces));
|
|
1044
1142
|
const usage = result.response.usageMetadata;
|
|
1045
1143
|
return {
|
|
1046
|
-
|
|
1144
|
+
...parseLlmText(result.response.text()),
|
|
1047
1145
|
promptTokens: usage?.promptTokenCount ?? 0,
|
|
1048
1146
|
completionTokens: usage?.candidatesTokenCount ?? 0
|
|
1049
1147
|
};
|
|
@@ -1073,7 +1171,7 @@ var ClaudeProvider = class {
|
|
|
1073
1171
|
}]
|
|
1074
1172
|
});
|
|
1075
1173
|
return {
|
|
1076
|
-
|
|
1174
|
+
...parseLlmText(message.content.find((b) => b.type === "text")?.text ?? ""),
|
|
1077
1175
|
provider: "claude",
|
|
1078
1176
|
model: this.model,
|
|
1079
1177
|
latencyMs: Date.now() - startMs,
|
|
@@ -1190,7 +1288,7 @@ var OpenRouterProvider = class {
|
|
|
1190
1288
|
errors: parsed.error.format(),
|
|
1191
1289
|
correlationId
|
|
1192
1290
|
}, "llm:validation:failed");
|
|
1193
|
-
const
|
|
1291
|
+
const parsedAnalysis = parseLlmText(parsed.success ? parsed.data.choices?.[0]?.message?.content ?? "" : "", correlationId);
|
|
1194
1292
|
const usage = parsed.success ? parsed.data.usage : void 0;
|
|
1195
1293
|
if (usage) {
|
|
1196
1294
|
const { prompt_tokens, completion_tokens, total_tokens } = usage;
|
|
@@ -1208,7 +1306,7 @@ var OpenRouterProvider = class {
|
|
|
1208
1306
|
llmInferenceTotal.inc({ status: "success" });
|
|
1209
1307
|
llmInferenceDuration.observe({ model: this.model }, latencyMs / 1e3);
|
|
1210
1308
|
return {
|
|
1211
|
-
|
|
1309
|
+
...parsedAnalysis,
|
|
1212
1310
|
provider: this.providerName,
|
|
1213
1311
|
model: this.model,
|
|
1214
1312
|
latencyMs,
|
|
@@ -1258,7 +1356,7 @@ var OpenRouterProvider = class {
|
|
|
1258
1356
|
const text = parsed.success ? parsed.data.choices?.[0]?.message?.content ?? "" : "";
|
|
1259
1357
|
const usage = parsed.success ? parsed.data.usage : void 0;
|
|
1260
1358
|
return {
|
|
1261
|
-
|
|
1359
|
+
...parseLlmText(text, correlationId),
|
|
1262
1360
|
provider: this.providerName,
|
|
1263
1361
|
model: toModel,
|
|
1264
1362
|
latencyMs: Date.now() - startMs,
|
|
@@ -35636,6 +35734,8 @@ async function loadSecretsFromSSM() {
|
|
|
35636
35734
|
const key = param.Name.replace(`${prefix}/`, "").replaceAll("-", "_").toUpperCase();
|
|
35637
35735
|
process.env[key] = param.Value;
|
|
35638
35736
|
}
|
|
35737
|
+
const missing = result.InvalidParameters ?? [];
|
|
35738
|
+
if (missing.length > 0) createLogger().warn({ missingParameters: missing }, "SSM parameters not found");
|
|
35639
35739
|
} catch (err) {
|
|
35640
35740
|
createLogger().error({ err }, "Failed to load SSM parameters");
|
|
35641
35741
|
}
|
|
@@ -35657,7 +35757,9 @@ const ConfigSchema = z.object({
|
|
|
35657
35757
|
rollbackActionAllowedSlackUserIds: z.array(z.string()).optional(),
|
|
35658
35758
|
teamsWebhookUrl: z.string().url().optional(),
|
|
35659
35759
|
lokiUrl: z.string().optional().transform((v) => v === "" ? void 0 : v),
|
|
35660
|
-
|
|
35760
|
+
dedupStore: z.enum(["dynamodb", "redis"]).default("dynamodb"),
|
|
35761
|
+
dedupTableName: z.string().min(1).optional(),
|
|
35762
|
+
redisUrl: z.string().url().optional(),
|
|
35661
35763
|
sqsQueueUrl: z.string().url().optional().or(z.literal("")),
|
|
35662
35764
|
dedupTtlSeconds: z.coerce.number().int().positive().default(300),
|
|
35663
35765
|
clusterWindowMs: z.coerce.number().int().positive().default(12e4),
|
|
@@ -35718,6 +35820,16 @@ const ConfigSchema = z.object({
|
|
|
35718
35820
|
});
|
|
35719
35821
|
}
|
|
35720
35822
|
}
|
|
35823
|
+
if (data.dedupStore === "dynamodb" && !data.dedupTableName) ctx.addIssue({
|
|
35824
|
+
code: z.ZodIssueCode.custom,
|
|
35825
|
+
path: ["dedupTableName"],
|
|
35826
|
+
message: "[dedupStore: dynamodb] DEDUP_TABLE_NAME is required"
|
|
35827
|
+
});
|
|
35828
|
+
if (data.dedupStore === "redis" && !data.redisUrl) ctx.addIssue({
|
|
35829
|
+
code: z.ZodIssueCode.custom,
|
|
35830
|
+
path: ["redisUrl"],
|
|
35831
|
+
message: "[dedupStore: redis] REDIS_URL is required"
|
|
35832
|
+
});
|
|
35721
35833
|
});
|
|
35722
35834
|
async function loadConfig() {
|
|
35723
35835
|
await loadSecretsFromSSM();
|
|
@@ -35732,6 +35844,8 @@ async function loadConfig() {
|
|
|
35732
35844
|
teamsWebhookUrl: process.env["TEAMS_WEBHOOK_URL"],
|
|
35733
35845
|
lokiUrl: process.env["LOKI_URL"],
|
|
35734
35846
|
redisUrl: process.env["REDIS_URL"],
|
|
35847
|
+
dedupStore: process.env["DEDUP_STORE"],
|
|
35848
|
+
dedupTableName: process.env["DEDUP_TABLE_NAME"],
|
|
35735
35849
|
sqsQueueUrl: process.env["SQS_QUEUE_URL"],
|
|
35736
35850
|
dedupTtlSeconds: process.env["DEDUP_TTL_SECONDS"],
|
|
35737
35851
|
clusterWindowMs: process.env["CLUSTER_WINDOW_MS"],
|
|
@@ -35750,6 +35864,6 @@ async function loadConfig() {
|
|
|
35750
35864
|
return result.data;
|
|
35751
35865
|
}
|
|
35752
35866
|
//#endregion
|
|
35753
|
-
export { ALERT_TYPE_LABELS, AlertClusterSchema, AlertStatusSchema, AlertType, AlertmanagerPayloadSchema, CIRCUIT_BREAKER, ChannelRegistry, ClaudeProvider, ClusteringService, Component, ConsoleNotifier, DEDUP_TTL_MS_MULTIPLIER, DEV_SERVER_PORT, FactoryRegistry, Fingerprint, GeminiProvider, HOUR_MS, HTTP_TIMEOUT_MS, InMemoryAlertQueue, InMemoryDeduplicationStore, InMemoryIndexer, IncidentSchema, LLMAnalysisSchema, LLMProviderType, LLM_FALLBACK_DEFAULTS, LLM_MAX_TOKENS, LLM_MODELS, LokiTraceRepository, MockLLMProvider, MockTraceRepository, NoopRollbackActionHandler, NormalizedAlertSchema, NotifyOutcome, OpenSearchIndexer, Outcome, PAYLOAD_DEFAULTS, ProcessIncidentUseCase, RATE_LIMITER, REDIS_KEY_PREFIX, ROLLBACK_ACTION_ID, RedisDeduplicationStore, RoutingNotifier, RuleActionSchema, RuleActionType, RuleConditionSchema, RuleConfigurationSchema, RuleEngine, RuleEvaluationPhase, RuleSchema, RuleSectionSchema, SLACK_API_URL, SQSAlertQueue, SamplingDecision, SeverityLevel, SlackNotifier, Stage, TEAMS_WEBHOOK_TIMEOUT_MS, TeamsNotifier, TeamsNotifierError, URGENCY_EMOJI, UrgencyLevelSchema, WEBHOOK_DEFAULTS, WideEventBuilder, compileCondition, createLLMProvider, createLogger, createNotifier, createRollbackActionHandler, dispatchActions, flushLoki, loadConfig, metrics_exports as metrics, normalizePayload, parseRuleConfig, reinitLogger, startSqsLagPoller };
|
|
35867
|
+
export { ALERT_TYPE_LABELS, AlertClusterSchema, AlertStatusSchema, AlertType, AlertmanagerPayloadSchema, CIRCUIT_BREAKER, ChannelRegistry, ClaudeProvider, ClusteringService, Component, ConsoleNotifier, DEDUP_TTL_MS_MULTIPLIER, DEV_SERVER_PORT, DynamoDBDeduplicationStore, FactoryRegistry, Fingerprint, GeminiProvider, HOUR_MS, HTTP_TIMEOUT_MS, InMemoryAlertQueue, InMemoryDeduplicationStore, InMemoryIndexer, IncidentSchema, LLMAnalysisSchema, LLMProviderType, LLM_FALLBACK_DEFAULTS, LLM_MAX_TOKENS, LLM_MODELS, LokiTraceRepository, MockLLMProvider, MockTraceRepository, NoopRollbackActionHandler, NormalizedAlertSchema, NotifyOutcome, OpenSearchIndexer, Outcome, PAYLOAD_DEFAULTS, ProcessIncidentUseCase, RATE_LIMITER, REDIS_KEY_PREFIX, ROLLBACK_ACTION_ID, RedisDeduplicationStore, RoutingNotifier, RuleActionSchema, RuleActionType, RuleConditionSchema, RuleConfigurationSchema, RuleEngine, RuleEvaluationPhase, RuleSchema, RuleSectionSchema, SLACK_API_URL, SQSAlertQueue, SamplingDecision, SeverityLevel, SlackNotifier, Stage, TEAMS_WEBHOOK_TIMEOUT_MS, TeamsNotifier, TeamsNotifierError, URGENCY_EMOJI, UrgencyLevelSchema, WEBHOOK_DEFAULTS, WideEventBuilder, compileCondition, createLLMProvider, createLogger, createNotifier, createRollbackActionHandler, dispatchActions, flushLoki, loadConfig, metrics_exports as metrics, normalizePayload, parseRuleConfig, reinitLogger, startSqsLagPoller };
|
|
35754
35868
|
|
|
35755
35869
|
//# sourceMappingURL=index.js.map
|