@a-company/sentinel 0.2.0 → 3.6.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/adapters/express.d.ts +3 -1
- package/dist/adapters/fastify.d.ts +3 -1
- package/dist/adapters/hono.d.ts +3 -1
- package/dist/chunk-NTX74ZPM.js +2624 -0
- package/dist/chunk-VQ3SIN7S.js +422 -0
- package/dist/cli.js +6 -6
- package/dist/{commands-KIMGFR2I.js → commands-E7ACLOE7.js} +2367 -258
- package/dist/{dist-2F7NO4H4.js → dist-AG5JNIZU.js} +27 -2
- package/dist/{dist-BPWLYV4U.js → dist-TYG2XME3.js} +27 -2
- package/dist/index.d.ts +57 -5
- package/dist/index.js +288 -186
- package/dist/mcp.js +1538 -124
- package/dist/sdk-CzFDYYST.d.ts +180 -0
- package/dist/server/index.d.ts +20 -3
- package/dist/server/index.js +805 -9
- package/dist/storage-BKyt7aPJ.d.ts +319 -0
- package/dist/transport-DqamniUy.d.ts +185 -0
- package/dist/transport.d.ts +2 -0
- package/dist/transport.js +10 -0
- package/dist/{sdk-B27_vK1g.d.ts → types-BmVoO1iF.d.ts} +196 -259
- package/package.json +15 -1
- package/ui/dist/assets/index-BuK-X6af.js +62 -0
- package/ui/dist/assets/index-BuK-X6af.js.map +1 -0
- package/ui/dist/assets/{index-DPxatSdT.css → index-DCtwmE2_.css} +1 -1
- package/ui/dist/index.html +2 -2
- package/dist/chunk-KPMG4XED.js +0 -1249
- package/ui/dist/assets/index-BNgsn_C8.js +0 -62
- package/ui/dist/assets/index-BNgsn_C8.js.map +0 -1
|
@@ -74,7 +74,7 @@ type CreateIncidentInput = Omit<SymbolicIncidentRecord, 'id' | 'notes' | 'relate
|
|
|
74
74
|
status?: IncidentStatus;
|
|
75
75
|
};
|
|
76
76
|
type PatternSource = 'manual' | 'suggested' | 'imported' | 'community';
|
|
77
|
-
type ResolutionStrategy = 'retry' | 'fallback' | 'fix-data' | 'fix-code' | 'ignore' | 'escalate';
|
|
77
|
+
type ResolutionStrategy = 'retry' | 'fallback' | 'fix-data' | 'fix-code' | 'rollback' | 'config-change' | 'scale-up' | 'investigate' | 'ignore' | 'escalate';
|
|
78
78
|
type PatternPriority = 'low' | 'medium' | 'high' | 'critical';
|
|
79
79
|
/**
|
|
80
80
|
* Symbol criteria for pattern matching
|
|
@@ -378,267 +378,204 @@ interface PracticeEventQuery {
|
|
|
378
378
|
limit?: number;
|
|
379
379
|
offset?: number;
|
|
380
380
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
381
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
382
|
+
type LogSymbolType = 'component' | 'gate' | 'signal' | 'flow' | 'aspect' | 'raw';
|
|
383
|
+
interface LogEntry {
|
|
384
|
+
id: string;
|
|
385
|
+
timestamp: string;
|
|
386
|
+
level: LogLevel;
|
|
387
|
+
symbol: string;
|
|
388
|
+
symbolType: LogSymbolType;
|
|
389
|
+
message: string;
|
|
390
|
+
data?: Record<string, unknown>;
|
|
391
|
+
service: string;
|
|
392
|
+
sessionId?: string;
|
|
393
|
+
correlationId?: string;
|
|
394
|
+
durationMs?: number;
|
|
395
|
+
environment?: string;
|
|
396
|
+
}
|
|
397
|
+
interface LogEntryInput {
|
|
398
|
+
id?: string;
|
|
399
|
+
timestamp?: string;
|
|
400
|
+
level: LogLevel;
|
|
401
|
+
symbol: string;
|
|
402
|
+
symbolType?: LogSymbolType;
|
|
403
|
+
message: string;
|
|
404
|
+
data?: Record<string, unknown>;
|
|
405
|
+
service: string;
|
|
406
|
+
sessionId?: string;
|
|
407
|
+
correlationId?: string;
|
|
408
|
+
durationMs?: number;
|
|
409
|
+
environment?: string;
|
|
410
|
+
}
|
|
411
|
+
interface LogQueryOptions {
|
|
412
|
+
level?: LogLevel;
|
|
413
|
+
symbol?: string;
|
|
414
|
+
service?: string;
|
|
415
|
+
sessionId?: string;
|
|
416
|
+
correlationId?: string;
|
|
417
|
+
search?: string;
|
|
418
|
+
since?: string;
|
|
419
|
+
until?: string;
|
|
420
|
+
limit?: number;
|
|
421
|
+
offset?: number;
|
|
422
|
+
}
|
|
423
|
+
interface ServiceInfo {
|
|
424
|
+
name: string;
|
|
425
|
+
version?: string;
|
|
426
|
+
pid?: number;
|
|
427
|
+
startedAt: string;
|
|
428
|
+
lastSeenAt: string;
|
|
429
|
+
environment?: string;
|
|
430
|
+
metadata?: Record<string, unknown>;
|
|
431
|
+
}
|
|
432
|
+
interface ServiceRegistration {
|
|
433
|
+
name: string;
|
|
434
|
+
version?: string;
|
|
435
|
+
pid?: number;
|
|
436
|
+
environment?: string;
|
|
437
|
+
metadata?: Record<string, unknown>;
|
|
438
|
+
}
|
|
439
|
+
interface AppState {
|
|
440
|
+
service: string;
|
|
441
|
+
sessionId: string;
|
|
442
|
+
timestamp: string;
|
|
443
|
+
state: Record<string, unknown>;
|
|
444
|
+
activeFlows?: string[];
|
|
445
|
+
activeGates?: string[];
|
|
446
|
+
}
|
|
447
|
+
interface SymbolValidationResult {
|
|
448
|
+
symbol: string;
|
|
449
|
+
known: boolean;
|
|
450
|
+
type?: string;
|
|
451
|
+
definedIn?: string;
|
|
452
|
+
suggestion?: string;
|
|
453
|
+
}
|
|
454
|
+
interface CorsConfig {
|
|
455
|
+
origin?: string | string[];
|
|
456
|
+
credentials?: boolean;
|
|
457
|
+
}
|
|
458
|
+
interface SentinelServerConfig {
|
|
459
|
+
port: number;
|
|
460
|
+
maxLogs: number;
|
|
461
|
+
maxBatchSize: number;
|
|
462
|
+
wsMaxSubscribers: number;
|
|
463
|
+
pruneIntervalInserts: number;
|
|
464
|
+
logRetentionDays: number;
|
|
465
|
+
auth: AuthConfig;
|
|
466
|
+
rateLimit: RateLimitConfig;
|
|
467
|
+
cors?: CorsConfig;
|
|
468
|
+
tls?: {
|
|
469
|
+
cert: string;
|
|
470
|
+
key: string;
|
|
463
471
|
};
|
|
464
|
-
private rowToPracticeEvent;
|
|
465
|
-
close(): void;
|
|
466
472
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
*
|
|
471
|
-
* Matches incidents against failure patterns using symbolic context,
|
|
472
|
-
* error text, and missing signals.
|
|
473
|
-
*/
|
|
474
|
-
|
|
475
|
-
declare class PatternMatcher {
|
|
476
|
-
private storage;
|
|
477
|
-
constructor(storage: SentinelStorage);
|
|
478
|
-
/**
|
|
479
|
-
* Match an incident against all patterns and return ranked results
|
|
480
|
-
*/
|
|
481
|
-
match(incident: SymbolicIncidentRecord, config?: Partial<MatcherConfig>): PatternMatch[];
|
|
482
|
-
/**
|
|
483
|
-
* Test a pattern against historical incidents
|
|
484
|
-
*/
|
|
485
|
-
testPattern(pattern: FailurePattern, limit?: number): PatternTestResult;
|
|
486
|
-
/**
|
|
487
|
-
* Score how well a pattern matches an incident
|
|
488
|
-
*/
|
|
489
|
-
private scoreMatch;
|
|
490
|
-
/**
|
|
491
|
-
* Match symbols between pattern and incident
|
|
492
|
-
*/
|
|
493
|
-
private matchSymbols;
|
|
494
|
-
/**
|
|
495
|
-
* Match a single symbol value (supports wildcards)
|
|
496
|
-
*/
|
|
497
|
-
private matchSingleSymbol;
|
|
498
|
-
/**
|
|
499
|
-
* Match error text keywords and regex
|
|
500
|
-
*/
|
|
501
|
-
private matchErrorText;
|
|
502
|
-
/**
|
|
503
|
-
* Match missing signals from flow position
|
|
504
|
-
*/
|
|
505
|
-
private matchMissingSignals;
|
|
506
|
-
/**
|
|
507
|
-
* Check if pattern's environment filter matches incident
|
|
508
|
-
*/
|
|
509
|
-
private matchEnvironment;
|
|
473
|
+
interface AuthConfig {
|
|
474
|
+
enabled: boolean;
|
|
475
|
+
tokens: AuthToken[];
|
|
510
476
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
* Usage:
|
|
519
|
-
* import { Sentinel } from '@a-company/sentinel';
|
|
520
|
-
* const sentinel = new Sentinel({ project: 'my-app' });
|
|
521
|
-
* sentinel.capture(new Error('Payment failed'), { component: '#checkout' });
|
|
522
|
-
*/
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Flow tracker for monitoring multi-step flows.
|
|
526
|
-
*
|
|
527
|
-
* Usage:
|
|
528
|
-
* const flow = sentinel.flow('$checkout-flow');
|
|
529
|
-
* flow.expect('!payment-authorized', '!order-created');
|
|
530
|
-
* flow.gate('^authenticated', true);
|
|
531
|
-
* flow.signal('!payment-authorized');
|
|
532
|
-
* flow.complete();
|
|
533
|
-
*/
|
|
534
|
-
declare class FlowTracker {
|
|
535
|
-
private flowId;
|
|
536
|
-
private sentinel;
|
|
537
|
-
private actual;
|
|
538
|
-
private expected;
|
|
539
|
-
private completed;
|
|
540
|
-
constructor(flowId: string, sentinel: Sentinel);
|
|
541
|
-
/** Declare which signals/gates are expected in this flow */
|
|
542
|
-
expect(...symbols: string[]): this;
|
|
543
|
-
/** Record a generic step in the flow */
|
|
544
|
-
step(symbol: string): this;
|
|
545
|
-
/** Record a gate check result */
|
|
546
|
-
gate(id: string, passed: boolean): this;
|
|
547
|
-
/** Record a signal emission */
|
|
548
|
-
signal(id: string, _data?: object): this;
|
|
549
|
-
/** Mark the flow as successfully completed */
|
|
550
|
-
complete(): void;
|
|
551
|
-
/** Capture an error with full flow position context */
|
|
552
|
-
fail(error: Error): void;
|
|
477
|
+
interface AuthToken {
|
|
478
|
+
id: string;
|
|
479
|
+
name: string;
|
|
480
|
+
token: string;
|
|
481
|
+
permissions: AuthPermission[];
|
|
482
|
+
createdAt: string;
|
|
483
|
+
expiresAt?: string;
|
|
553
484
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
485
|
+
type AuthPermission = 'read' | 'write' | 'admin';
|
|
486
|
+
declare const DEFAULT_AUTH_CONFIG: AuthConfig;
|
|
487
|
+
type MetricType = 'counter' | 'gauge' | 'histogram';
|
|
488
|
+
interface MetricEntry {
|
|
489
|
+
id: string;
|
|
490
|
+
timestamp: string;
|
|
491
|
+
name: string;
|
|
492
|
+
type: MetricType;
|
|
493
|
+
value: number;
|
|
494
|
+
tags: Record<string, string>;
|
|
495
|
+
service: string;
|
|
496
|
+
environment?: string;
|
|
497
|
+
}
|
|
498
|
+
interface MetricInput {
|
|
499
|
+
name: string;
|
|
500
|
+
type: MetricType;
|
|
501
|
+
value: number;
|
|
502
|
+
tags?: Record<string, string>;
|
|
503
|
+
service: string;
|
|
504
|
+
timestamp?: string;
|
|
505
|
+
environment?: string;
|
|
506
|
+
}
|
|
507
|
+
interface MetricQueryOptions {
|
|
508
|
+
name?: string;
|
|
509
|
+
type?: MetricType;
|
|
510
|
+
service?: string;
|
|
511
|
+
tag?: string;
|
|
512
|
+
since?: string;
|
|
513
|
+
until?: string;
|
|
514
|
+
limit?: number;
|
|
515
|
+
offset?: number;
|
|
516
|
+
}
|
|
517
|
+
interface MetricAggregation {
|
|
518
|
+
name: string;
|
|
519
|
+
count: number;
|
|
520
|
+
sum: number;
|
|
521
|
+
min: number;
|
|
522
|
+
max: number;
|
|
523
|
+
avg: number;
|
|
524
|
+
p50?: number;
|
|
525
|
+
p95?: number;
|
|
526
|
+
p99?: number;
|
|
527
|
+
}
|
|
528
|
+
interface HistogramBucket {
|
|
529
|
+
le: number;
|
|
530
|
+
count: number;
|
|
531
|
+
}
|
|
532
|
+
interface RateLimitConfig {
|
|
533
|
+
enabled: boolean;
|
|
534
|
+
global: RateLimitRule;
|
|
535
|
+
perService: Record<string, RateLimitRule>;
|
|
536
|
+
}
|
|
537
|
+
interface RateLimitRule {
|
|
538
|
+
maxRequestsPerMinute: number;
|
|
539
|
+
maxEntriesPerBatch: number;
|
|
540
|
+
samplingRate: number;
|
|
541
|
+
}
|
|
542
|
+
declare const DEFAULT_RATE_LIMIT_CONFIG: RateLimitConfig;
|
|
543
|
+
declare const DEFAULT_SERVER_CONFIG: SentinelServerConfig;
|
|
544
|
+
interface TraceSpan {
|
|
545
|
+
traceId: string;
|
|
546
|
+
spanId: string;
|
|
547
|
+
parentSpanId?: string;
|
|
548
|
+
service: string;
|
|
549
|
+
symbol: string;
|
|
550
|
+
operation: string;
|
|
551
|
+
startTime: string;
|
|
552
|
+
endTime?: string;
|
|
553
|
+
durationMs?: number;
|
|
554
|
+
status: 'ok' | 'error';
|
|
555
|
+
tags: Record<string, string>;
|
|
556
|
+
logs: string[];
|
|
557
|
+
}
|
|
558
|
+
interface TraceSpanInput {
|
|
559
|
+
traceId: string;
|
|
560
|
+
spanId?: string;
|
|
561
|
+
parentSpanId?: string;
|
|
562
|
+
service: string;
|
|
563
|
+
symbol: string;
|
|
564
|
+
operation: string;
|
|
565
|
+
startTime?: string;
|
|
566
|
+
endTime?: string;
|
|
567
|
+
durationMs?: number;
|
|
568
|
+
status?: 'ok' | 'error';
|
|
569
|
+
tags?: Record<string, string>;
|
|
570
|
+
logIds?: string[];
|
|
571
|
+
}
|
|
572
|
+
interface TraceView {
|
|
573
|
+
traceId: string;
|
|
574
|
+
spans: TraceSpan[];
|
|
575
|
+
services: string[];
|
|
576
|
+
totalDurationMs: number;
|
|
577
|
+
startTime: string;
|
|
578
|
+
endTime: string;
|
|
642
579
|
}
|
|
643
580
|
|
|
644
|
-
export { type
|
|
581
|
+
export { type PatternResolution as $, type AppState as A, type BackupExport as B, type ComponentContext as C, DEFAULT_AUTH_CONFIG as D, type EnrichedIncident as E, type FlowTimeline as F, type LogQueryOptions as G, type HistogramBucket as H, type IncidentGroup as I, type LogSymbolType as J, type MatcherConfig as K, type LogEntry as L, type MatchedCriteria as M, type MetricAggregation as N, type MetricEntry as O, type PatternCandidate as P, type MetricInput as Q, type MetricQueryOptions as R, type SentinelServerConfig as S, type MetricType as T, type PatternConfidence as U, type PatternCriteria as V, type PatternEffectiveness as W, type PatternMatch as X, type PatternPriority as Y, type PatternQueryOptions as Z, type PatternRecurrence as _, type SymbolicIncidentRecord as a, type PatternSource as a0, type PatternSymbolCriteria as a1, type PatternTestResult as a2, type PracticeCategory as a3, type PracticeEvent as a4, type PracticeEventInput as a5, type PracticeEventQuery as a6, type PracticeResult as a7, type RateLimitConfig as a8, type RateLimitRule as a9, type Resolution as aa, type ResolutionQueryOptions as ab, type ResolutionRecord as ac, type ResolutionStrategy as ad, type SentinelConfig as ae, type ServiceInfo as af, type ServiceRegistration as ag, type SymbolHotspot as ah, type SymbolIncidentCount as ai, type SymbolResolutionTime as aj, type SymbolValidationResult as ak, type SymbolicContext as al, type TraceSpan as am, type TraceSpanInput as an, type TraceView as ao, type SentinelStats as b, type SymbolHealth as c, type SymbolEnrichment as d, type FailurePattern as e, type PatternExport as f, type AuthConfig as g, type AuthPermission as h, type AuthToken as i, type CorsConfig as j, type CreateGroupInput as k, type CreateIncidentInput as l, type CreatePatternInput as m, DEFAULT_RATE_LIMIT_CONFIG as n, DEFAULT_SERVER_CONFIG as o, type DayCount as p, type Environment as q, type ErrorDetails as r, type FlowEvent as s, type FlowEventType as t, type FlowPosition as u, type IncidentNote as v, type IncidentQueryOptions as w, type IncidentStatus as x, type LogEntryInput as y, type LogLevel as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a-company/sentinel",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Semantic error monitoring — errors that speak your language",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,6 +29,18 @@
|
|
|
29
29
|
"./hono": {
|
|
30
30
|
"types": "./dist/adapters/hono.d.ts",
|
|
31
31
|
"import": "./dist/adapters/hono.js"
|
|
32
|
+
},
|
|
33
|
+
"./transport": {
|
|
34
|
+
"types": "./dist/transport.d.ts",
|
|
35
|
+
"import": "./dist/transport.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@a-company/paradigm-logger": ">=1.1.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependenciesMeta": {
|
|
42
|
+
"@a-company/paradigm-logger": {
|
|
43
|
+
"optional": true
|
|
32
44
|
}
|
|
33
45
|
},
|
|
34
46
|
"files": [
|
|
@@ -53,6 +65,7 @@
|
|
|
53
65
|
"simple-git": "^3.22.0",
|
|
54
66
|
"sql.js": "^1.10.3",
|
|
55
67
|
"uuid": "^9.0.0",
|
|
68
|
+
"ws": "^8.19.0",
|
|
56
69
|
"zod": "^3.23.0"
|
|
57
70
|
},
|
|
58
71
|
"devDependencies": {
|
|
@@ -61,6 +74,7 @@
|
|
|
61
74
|
"@types/react": "^18.2.45",
|
|
62
75
|
"@types/react-dom": "^18.2.18",
|
|
63
76
|
"@types/uuid": "^9.0.7",
|
|
77
|
+
"@types/ws": "^8.18.1",
|
|
64
78
|
"@vitejs/plugin-react": "^4.2.1",
|
|
65
79
|
"react": "^18.2.0",
|
|
66
80
|
"react-dom": "^18.2.0",
|