@waiaas/daemon 2.9.1-rc → 2.10.0-rc
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/api/middleware/master-auth.d.ts +3 -0
- package/dist/api/middleware/master-auth.d.ts.map +1 -1
- package/dist/api/middleware/master-auth.js +14 -0
- package/dist/api/middleware/master-auth.js.map +1 -1
- package/dist/api/routes/admin.d.ts +4 -0
- package/dist/api/routes/admin.d.ts.map +1 -1
- package/dist/api/routes/admin.js +186 -1
- package/dist/api/routes/admin.js.map +1 -1
- package/dist/api/routes/audit-logs.d.ts +15 -0
- package/dist/api/routes/audit-logs.d.ts.map +1 -0
- package/dist/api/routes/audit-logs.js +119 -0
- package/dist/api/routes/audit-logs.js.map +1 -0
- package/dist/api/routes/index.d.ts +2 -1
- package/dist/api/routes/index.d.ts.map +1 -1
- package/dist/api/routes/index.js +2 -1
- package/dist/api/routes/index.js.map +1 -1
- package/dist/api/routes/openapi-schemas.d.ts +324 -6
- package/dist/api/routes/openapi-schemas.d.ts.map +1 -1
- package/dist/api/routes/openapi-schemas.js +76 -0
- package/dist/api/routes/openapi-schemas.js.map +1 -1
- package/dist/api/routes/sessions.d.ts +2 -0
- package/dist/api/routes/sessions.d.ts.map +1 -1
- package/dist/api/routes/sessions.js +21 -0
- package/dist/api/routes/sessions.js.map +1 -1
- package/dist/api/routes/transactions.d.ts +2 -1
- package/dist/api/routes/transactions.d.ts.map +1 -1
- package/dist/api/routes/transactions.js +72 -1
- package/dist/api/routes/transactions.js.map +1 -1
- package/dist/api/routes/wallets.d.ts.map +1 -1
- package/dist/api/routes/wallets.js +25 -0
- package/dist/api/routes/wallets.js.map +1 -1
- package/dist/api/routes/webhooks.d.ts +17 -0
- package/dist/api/routes/webhooks.d.ts.map +1 -0
- package/dist/api/routes/webhooks.js +218 -0
- package/dist/api/routes/webhooks.js.map +1 -0
- package/dist/api/server.d.ts +27 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +31 -5
- package/dist/api/server.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/backup/backup-format.d.ts +107 -0
- package/dist/infrastructure/backup/backup-format.d.ts.map +1 -0
- package/dist/infrastructure/backup/backup-format.js +134 -0
- package/dist/infrastructure/backup/backup-format.js.map +1 -0
- package/dist/infrastructure/backup/encrypted-backup-service.d.ts +56 -0
- package/dist/infrastructure/backup/encrypted-backup-service.d.ts.map +1 -0
- package/dist/infrastructure/backup/encrypted-backup-service.js +269 -0
- package/dist/infrastructure/backup/encrypted-backup-service.js.map +1 -0
- package/dist/infrastructure/backup/index.d.ts +3 -0
- package/dist/infrastructure/backup/index.d.ts.map +1 -1
- package/dist/infrastructure/backup/index.js +2 -0
- package/dist/infrastructure/backup/index.js.map +1 -1
- package/dist/infrastructure/config/loader.d.ts +23 -0
- package/dist/infrastructure/config/loader.d.ts.map +1 -1
- package/dist/infrastructure/config/loader.js +8 -0
- package/dist/infrastructure/config/loader.js.map +1 -1
- package/dist/infrastructure/database/audit-helper.d.ts +29 -0
- package/dist/infrastructure/database/audit-helper.d.ts.map +1 -0
- package/dist/infrastructure/database/audit-helper.js +30 -0
- package/dist/infrastructure/database/audit-helper.js.map +1 -0
- package/dist/infrastructure/database/index.d.ts +2 -0
- package/dist/infrastructure/database/index.d.ts.map +1 -1
- package/dist/infrastructure/database/index.js +1 -0
- package/dist/infrastructure/database/index.js.map +1 -1
- package/dist/infrastructure/database/migrate.d.ts +1 -1
- package/dist/infrastructure/database/migrate.d.ts.map +1 -1
- package/dist/infrastructure/database/migrate.js +83 -2
- package/dist/infrastructure/database/migrate.js.map +1 -1
- package/dist/infrastructure/database/schema.d.ts +343 -1
- package/dist/infrastructure/database/schema.d.ts.map +1 -1
- package/dist/infrastructure/database/schema.js +41 -1
- package/dist/infrastructure/database/schema.js.map +1 -1
- package/dist/infrastructure/metrics/in-memory-counter.d.ts +34 -0
- package/dist/infrastructure/metrics/in-memory-counter.d.ts.map +1 -0
- package/dist/infrastructure/metrics/in-memory-counter.js +88 -0
- package/dist/infrastructure/metrics/in-memory-counter.js.map +1 -0
- package/dist/infrastructure/settings/hot-reload.d.ts +1 -0
- package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -1
- package/dist/infrastructure/settings/hot-reload.js +23 -2
- package/dist/infrastructure/settings/hot-reload.js.map +1 -1
- package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -1
- package/dist/infrastructure/settings/setting-keys.js +4 -0
- package/dist/infrastructure/settings/setting-keys.js.map +1 -1
- package/dist/infrastructure/telegram/telegram-bot-service.d.ts.map +1 -1
- package/dist/infrastructure/telegram/telegram-bot-service.js +32 -19
- package/dist/infrastructure/telegram/telegram-bot-service.js.map +1 -1
- package/dist/lifecycle/daemon.d.ts +8 -1
- package/dist/lifecycle/daemon.d.ts.map +1 -1
- package/dist/lifecycle/daemon.js +103 -1
- package/dist/lifecycle/daemon.js.map +1 -1
- package/dist/pipeline/dry-run.d.ts +68 -0
- package/dist/pipeline/dry-run.d.ts.map +1 -0
- package/dist/pipeline/dry-run.js +426 -0
- package/dist/pipeline/dry-run.js.map +1 -0
- package/dist/pipeline/index.d.ts +1 -0
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +2 -0
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/pipeline.d.ts +18 -1
- package/dist/pipeline/pipeline.d.ts.map +1 -1
- package/dist/pipeline/pipeline.js +38 -0
- package/dist/pipeline/pipeline.js.map +1 -1
- package/dist/pipeline/stages.d.ts +31 -1
- package/dist/pipeline/stages.d.ts.map +1 -1
- package/dist/pipeline/stages.js +120 -22
- package/dist/pipeline/stages.js.map +1 -1
- package/dist/services/admin-stats-service.d.ts +48 -0
- package/dist/services/admin-stats-service.d.ts.map +1 -0
- package/dist/services/admin-stats-service.js +182 -0
- package/dist/services/admin-stats-service.js.map +1 -0
- package/dist/services/autostop/autostop-service.d.ts +83 -0
- package/dist/services/autostop/autostop-service.d.ts.map +1 -0
- package/dist/services/autostop/autostop-service.js +252 -0
- package/dist/services/autostop/autostop-service.js.map +1 -0
- package/dist/services/autostop/index.d.ts +15 -0
- package/dist/services/autostop/index.d.ts.map +1 -0
- package/dist/services/autostop/index.js +11 -0
- package/dist/services/autostop/index.js.map +1 -0
- package/dist/services/autostop/rule-registry.d.ts +42 -0
- package/dist/services/autostop/rule-registry.d.ts.map +1 -0
- package/dist/services/autostop/rule-registry.js +54 -0
- package/dist/services/autostop/rule-registry.js.map +1 -0
- package/dist/services/autostop/rules/consecutive-failures.rule.d.ts +38 -0
- package/dist/services/autostop/rules/consecutive-failures.rule.d.ts.map +1 -0
- package/dist/services/autostop/rules/consecutive-failures.rule.js +75 -0
- package/dist/services/autostop/rules/consecutive-failures.rule.js.map +1 -0
- package/dist/services/autostop/rules/idle-timeout.rule.d.ts +43 -0
- package/dist/services/autostop/rules/idle-timeout.rule.d.ts.map +1 -0
- package/dist/services/autostop/rules/idle-timeout.rule.js +128 -0
- package/dist/services/autostop/rules/idle-timeout.rule.js.map +1 -0
- package/dist/services/autostop/rules/unusual-activity.rule.d.ts +33 -0
- package/dist/services/autostop/rules/unusual-activity.rule.d.ts.map +1 -0
- package/dist/services/autostop/rules/unusual-activity.rule.js +73 -0
- package/dist/services/autostop/rules/unusual-activity.rule.js.map +1 -0
- package/dist/services/autostop/types.d.ts +49 -0
- package/dist/services/autostop/types.d.ts.map +1 -0
- package/dist/services/autostop/types.js +10 -0
- package/dist/services/autostop/types.js.map +1 -0
- package/dist/services/autostop-rules.d.ts +11 -74
- package/dist/services/autostop-rules.d.ts.map +1 -1
- package/dist/services/autostop-rules.js +9 -169
- package/dist/services/autostop-rules.js.map +1 -1
- package/dist/services/autostop-service.d.ts +6 -77
- package/dist/services/autostop-service.d.ts.map +1 -1
- package/dist/services/autostop-service.js +5 -212
- package/dist/services/autostop-service.js.map +1 -1
- package/dist/services/kill-switch-service.d.ts.map +1 -1
- package/dist/services/kill-switch-service.js +36 -21
- package/dist/services/kill-switch-service.js.map +1 -1
- package/dist/services/webhook-delivery-queue.d.ts +53 -0
- package/dist/services/webhook-delivery-queue.d.ts.map +1 -0
- package/dist/services/webhook-delivery-queue.js +118 -0
- package/dist/services/webhook-delivery-queue.js.map +1 -0
- package/dist/services/webhook-service.d.ts +46 -0
- package/dist/services/webhook-service.d.ts.map +1 -0
- package/dist/services/webhook-service.js +160 -0
- package/dist/services/webhook-service.js.map +1 -0
- package/package.json +5 -5
- package/public/admin/assets/{index-CBU6NfOH.js → index-RagPnRU1.js} +2 -2
- package/public/admin/index.html +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autostop-rules.d.ts","sourceRoot":"","sources":["../../src/services/autostop-rules.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"autostop-rules.d.ts","sourceRoot":"","sources":["../../src/services/autostop-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,YAAY,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACzE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -1,174 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Backward-compatible re-export barrel for autostop rule classes.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The actual implementations have been moved to:
|
|
5
|
+
* - services/autostop/rules/consecutive-failures.rule.ts
|
|
6
|
+
* - services/autostop/rules/unusual-activity.rule.ts
|
|
7
|
+
* - services/autostop/rules/idle-timeout.rule.ts
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
* Triggers when activity count within a time window exceeds threshold.
|
|
10
|
-
*
|
|
11
|
-
* 3. IdleTimeoutRule -- Track session last-activity timestamps per wallet.
|
|
12
|
-
* Returns idle sessions whose inactivity exceeds the configured timeout.
|
|
13
|
-
*
|
|
14
|
-
* All rules are stateless with respect to external dependencies (no DB, no network).
|
|
15
|
-
* State is held in in-memory Maps and is lost on restart (acceptable for reactive rules).
|
|
16
|
-
*
|
|
17
|
-
* MANUAL_TRIGGER is handled directly by AutoStopService (no separate rule class).
|
|
18
|
-
*
|
|
19
|
-
* @see AUTO-01, AUTO-02, AUTO-03 requirements
|
|
9
|
+
* @deprecated Import from './autostop/rules/*.rule.js' directly.
|
|
20
10
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export class ConsecutiveFailuresRule {
|
|
25
|
-
failureCounts = new Map();
|
|
26
|
-
_threshold;
|
|
27
|
-
constructor(threshold = 5) {
|
|
28
|
-
this._threshold = threshold;
|
|
29
|
-
}
|
|
30
|
-
get threshold() {
|
|
31
|
-
return this._threshold;
|
|
32
|
-
}
|
|
33
|
-
/** Record a transaction failure for a wallet. Returns triggered=true if threshold reached. */
|
|
34
|
-
onTransactionFailed(walletId) {
|
|
35
|
-
const count = (this.failureCounts.get(walletId) ?? 0) + 1;
|
|
36
|
-
this.failureCounts.set(walletId, count);
|
|
37
|
-
return {
|
|
38
|
-
triggered: count >= this._threshold,
|
|
39
|
-
walletId,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
/** Reset failure counter on successful transaction. */
|
|
43
|
-
onTransactionCompleted(walletId) {
|
|
44
|
-
this.failureCounts.set(walletId, 0);
|
|
45
|
-
}
|
|
46
|
-
/** Reset counter after trigger (prevents repeated triggers without new failures). */
|
|
47
|
-
resetWallet(walletId) {
|
|
48
|
-
this.failureCounts.delete(walletId);
|
|
49
|
-
}
|
|
50
|
-
/** Update threshold at runtime. */
|
|
51
|
-
updateThreshold(threshold) {
|
|
52
|
-
this._threshold = threshold;
|
|
53
|
-
}
|
|
54
|
-
/** Current state for monitoring. */
|
|
55
|
-
getTrackedCount() {
|
|
56
|
-
return this.failureCounts.size;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
// ---------------------------------------------------------------------------
|
|
60
|
-
// Rule 2: UnusualActivityRule (AUTO-02)
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
export class UnusualActivityRule {
|
|
63
|
-
activityTimestamps = new Map();
|
|
64
|
-
_threshold;
|
|
65
|
-
_windowSec;
|
|
66
|
-
constructor(threshold = 20, windowSec = 300) {
|
|
67
|
-
this._threshold = threshold;
|
|
68
|
-
this._windowSec = windowSec;
|
|
69
|
-
}
|
|
70
|
-
get threshold() {
|
|
71
|
-
return this._threshold;
|
|
72
|
-
}
|
|
73
|
-
get windowSec() {
|
|
74
|
-
return this._windowSec;
|
|
75
|
-
}
|
|
76
|
-
/** Record wallet activity. Returns triggered=true if frequency exceeds threshold. */
|
|
77
|
-
onWalletActivity(walletId, timestamp) {
|
|
78
|
-
const cutoff = timestamp - this._windowSec;
|
|
79
|
-
let timestamps = this.activityTimestamps.get(walletId) ?? [];
|
|
80
|
-
// Prune timestamps outside the sliding window
|
|
81
|
-
timestamps = timestamps.filter((t) => t > cutoff);
|
|
82
|
-
timestamps.push(timestamp);
|
|
83
|
-
this.activityTimestamps.set(walletId, timestamps);
|
|
84
|
-
return {
|
|
85
|
-
triggered: timestamps.length >= this._threshold,
|
|
86
|
-
walletId,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/** Update threshold at runtime. */
|
|
90
|
-
updateThreshold(threshold) {
|
|
91
|
-
this._threshold = threshold;
|
|
92
|
-
}
|
|
93
|
-
/** Update window at runtime. */
|
|
94
|
-
updateWindow(windowSec) {
|
|
95
|
-
this._windowSec = windowSec;
|
|
96
|
-
}
|
|
97
|
-
/** Current state for monitoring. */
|
|
98
|
-
getTrackedCount() {
|
|
99
|
-
return this.activityTimestamps.size;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
// ---------------------------------------------------------------------------
|
|
103
|
-
// Rule 3: IdleTimeoutRule (AUTO-03)
|
|
104
|
-
// ---------------------------------------------------------------------------
|
|
105
|
-
export class IdleTimeoutRule {
|
|
106
|
-
// Map<walletId, Map<sessionId, lastActivityTimestampSec>>
|
|
107
|
-
lastActivity = new Map();
|
|
108
|
-
_idleTimeoutSec;
|
|
109
|
-
constructor(idleTimeoutSec = 3600) {
|
|
110
|
-
this._idleTimeoutSec = idleTimeoutSec;
|
|
111
|
-
}
|
|
112
|
-
get idleTimeoutSec() {
|
|
113
|
-
return this._idleTimeoutSec;
|
|
114
|
-
}
|
|
115
|
-
/** Register a new session with current timestamp. */
|
|
116
|
-
registerSession(walletId, sessionId, nowSec) {
|
|
117
|
-
let walletSessions = this.lastActivity.get(walletId);
|
|
118
|
-
if (!walletSessions) {
|
|
119
|
-
walletSessions = new Map();
|
|
120
|
-
this.lastActivity.set(walletId, walletSessions);
|
|
121
|
-
}
|
|
122
|
-
walletSessions.set(sessionId, nowSec);
|
|
123
|
-
}
|
|
124
|
-
/** Update last activity time for a session (or all sessions of a wallet). */
|
|
125
|
-
onWalletActivity(walletId, nowSec, sessionId) {
|
|
126
|
-
const walletSessions = this.lastActivity.get(walletId);
|
|
127
|
-
if (!walletSessions)
|
|
128
|
-
return;
|
|
129
|
-
if (sessionId && walletSessions.has(sessionId)) {
|
|
130
|
-
walletSessions.set(sessionId, nowSec);
|
|
131
|
-
}
|
|
132
|
-
else if (!sessionId) {
|
|
133
|
-
// Update all sessions for this wallet
|
|
134
|
-
for (const sid of walletSessions.keys()) {
|
|
135
|
-
walletSessions.set(sid, nowSec);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
/** Check all tracked sessions and return those that have been idle beyond the timeout. */
|
|
140
|
-
checkIdle(nowSec) {
|
|
141
|
-
const idle = [];
|
|
142
|
-
for (const [walletId, sessions] of this.lastActivity) {
|
|
143
|
-
for (const [sessionId, lastTime] of sessions) {
|
|
144
|
-
if (nowSec - lastTime > this._idleTimeoutSec) {
|
|
145
|
-
idle.push({ walletId, sessionId });
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return idle;
|
|
150
|
-
}
|
|
151
|
-
/** Remove a session from tracking (after revocation). */
|
|
152
|
-
removeSession(walletId, sessionId) {
|
|
153
|
-
const walletSessions = this.lastActivity.get(walletId);
|
|
154
|
-
if (walletSessions) {
|
|
155
|
-
walletSessions.delete(sessionId);
|
|
156
|
-
if (walletSessions.size === 0) {
|
|
157
|
-
this.lastActivity.delete(walletId);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
/** Update timeout at runtime. */
|
|
162
|
-
updateTimeout(idleTimeoutSec) {
|
|
163
|
-
this._idleTimeoutSec = idleTimeoutSec;
|
|
164
|
-
}
|
|
165
|
-
/** Current state for monitoring. */
|
|
166
|
-
getTrackedSessionCount() {
|
|
167
|
-
let count = 0;
|
|
168
|
-
for (const sessions of this.lastActivity.values()) {
|
|
169
|
-
count += sessions.size;
|
|
170
|
-
}
|
|
171
|
-
return count;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
11
|
+
export { ConsecutiveFailuresRule } from './autostop/rules/consecutive-failures.rule.js';
|
|
12
|
+
export { UnusualActivityRule } from './autostop/rules/unusual-activity.rule.js';
|
|
13
|
+
export { IdleTimeoutRule } from './autostop/rules/idle-timeout.rule.js';
|
|
174
14
|
//# sourceMappingURL=autostop-rules.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autostop-rules.js","sourceRoot":"","sources":["../../src/services/autostop-rules.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"autostop-rules.js","sourceRoot":"","sources":["../../src/services/autostop-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC"}
|
|
@@ -1,82 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Backward-compatible re-export barrel for AutoStopService.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* AUTO-02 UNUSUAL_ACTIVITY -- High-frequency activity -> wallet SUSPENDED
|
|
7
|
-
* AUTO-03 IDLE_TIMEOUT -- Idle session -> auto-revoke
|
|
8
|
-
* AUTO-04 MANUAL_TRIGGER -- Manual trigger -> KillSwitch cascade
|
|
4
|
+
* The actual implementation has been moved to:
|
|
5
|
+
* - services/autostop/autostop-service.ts
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
* - transaction:failed -> ConsecutiveFailuresRule
|
|
12
|
-
* - transaction:completed -> ConsecutiveFailuresRule (reset on success)
|
|
13
|
-
* - wallet:activity -> UnusualActivityRule + IdleTimeoutRule
|
|
14
|
-
*
|
|
15
|
-
* Idle session check runs on a periodic interval (setInterval).
|
|
16
|
-
*
|
|
17
|
-
* DB writes use better-sqlite3 directly (same pattern as KillSwitchService).
|
|
18
|
-
*
|
|
19
|
-
* @see AUTO-01, AUTO-02, AUTO-03, AUTO-04, AUTO-06 requirements
|
|
7
|
+
* @deprecated Import from './autostop/autostop-service.js' directly.
|
|
20
8
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import type { KillSwitchService } from './kill-switch-service.js';
|
|
24
|
-
import type { NotificationService } from '../notifications/notification-service.js';
|
|
25
|
-
export interface AutoStopConfig {
|
|
26
|
-
consecutiveFailuresThreshold: number;
|
|
27
|
-
unusualActivityThreshold: number;
|
|
28
|
-
unusualActivityWindowSec: number;
|
|
29
|
-
idleTimeoutSec: number;
|
|
30
|
-
idleCheckIntervalSec: number;
|
|
31
|
-
enabled: boolean;
|
|
32
|
-
}
|
|
33
|
-
export declare const DEFAULT_AUTOSTOP_CONFIG: AutoStopConfig;
|
|
34
|
-
export declare class AutoStopService {
|
|
35
|
-
private sqlite;
|
|
36
|
-
private eventBus;
|
|
37
|
-
private killSwitchService;
|
|
38
|
-
private notificationService?;
|
|
39
|
-
private config;
|
|
40
|
-
private consecutiveFailuresRule;
|
|
41
|
-
private unusualActivityRule;
|
|
42
|
-
private idleTimeoutRule;
|
|
43
|
-
private idleCheckTimer;
|
|
44
|
-
constructor(opts: {
|
|
45
|
-
sqlite: Database;
|
|
46
|
-
eventBus: EventBus;
|
|
47
|
-
killSwitchService: KillSwitchService;
|
|
48
|
-
notificationService?: NotificationService;
|
|
49
|
-
config?: Partial<AutoStopConfig>;
|
|
50
|
-
});
|
|
51
|
-
/** Register EventBus listeners and start idle check timer. */
|
|
52
|
-
start(): void;
|
|
53
|
-
/** Stop idle check timer. Does NOT remove EventBus listeners (shared resource). */
|
|
54
|
-
stop(): void;
|
|
55
|
-
/** Manually trigger Kill Switch cascade. */
|
|
56
|
-
manualTrigger(triggeredBy: string): void;
|
|
57
|
-
/** Suspend a wallet and log the action. Only affects ACTIVE wallets. */
|
|
58
|
-
private suspendWallet;
|
|
59
|
-
/** Check idle sessions and send SESSION_IDLE notification instead of revoking. */
|
|
60
|
-
private checkIdleSessions;
|
|
61
|
-
/** Send SESSION_IDLE notification and remove from tracking to prevent duplicates (#204). */
|
|
62
|
-
private notifyIdleSession;
|
|
63
|
-
/** Update configuration at runtime (e.g., from Admin Settings). */
|
|
64
|
-
updateConfig(config: Partial<AutoStopConfig>): void;
|
|
65
|
-
/** Get current rule engine status for debugging/monitoring. */
|
|
66
|
-
getStatus(): {
|
|
67
|
-
enabled: boolean;
|
|
68
|
-
config: AutoStopConfig;
|
|
69
|
-
rules: {
|
|
70
|
-
consecutiveFailures: {
|
|
71
|
-
trackedWallets: number;
|
|
72
|
-
};
|
|
73
|
-
unusualActivity: {
|
|
74
|
-
trackedWallets: number;
|
|
75
|
-
};
|
|
76
|
-
idleTimeout: {
|
|
77
|
-
trackedSessions: number;
|
|
78
|
-
};
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
}
|
|
9
|
+
export { AutoStopService, DEFAULT_AUTOSTOP_CONFIG } from './autostop/autostop-service.js';
|
|
10
|
+
export type { AutoStopConfig } from './autostop/autostop-service.js';
|
|
82
11
|
//# sourceMappingURL=autostop-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autostop-service.d.ts","sourceRoot":"","sources":["../../src/services/autostop-service.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"autostop-service.d.ts","sourceRoot":"","sources":["../../src/services/autostop-service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC"}
|
|
@@ -1,217 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Backward-compatible re-export barrel for AutoStopService.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* AUTO-02 UNUSUAL_ACTIVITY -- High-frequency activity -> wallet SUSPENDED
|
|
7
|
-
* AUTO-03 IDLE_TIMEOUT -- Idle session -> auto-revoke
|
|
8
|
-
* AUTO-04 MANUAL_TRIGGER -- Manual trigger -> KillSwitch cascade
|
|
4
|
+
* The actual implementation has been moved to:
|
|
5
|
+
* - services/autostop/autostop-service.ts
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
* - transaction:failed -> ConsecutiveFailuresRule
|
|
12
|
-
* - transaction:completed -> ConsecutiveFailuresRule (reset on success)
|
|
13
|
-
* - wallet:activity -> UnusualActivityRule + IdleTimeoutRule
|
|
14
|
-
*
|
|
15
|
-
* Idle session check runs on a periodic interval (setInterval).
|
|
16
|
-
*
|
|
17
|
-
* DB writes use better-sqlite3 directly (same pattern as KillSwitchService).
|
|
18
|
-
*
|
|
19
|
-
* @see AUTO-01, AUTO-02, AUTO-03, AUTO-04, AUTO-06 requirements
|
|
7
|
+
* @deprecated Import from './autostop/autostop-service.js' directly.
|
|
20
8
|
*/
|
|
21
|
-
|
|
22
|
-
export const DEFAULT_AUTOSTOP_CONFIG = {
|
|
23
|
-
consecutiveFailuresThreshold: 5,
|
|
24
|
-
unusualActivityThreshold: 20,
|
|
25
|
-
unusualActivityWindowSec: 300,
|
|
26
|
-
idleTimeoutSec: 3600,
|
|
27
|
-
idleCheckIntervalSec: 60,
|
|
28
|
-
enabled: true,
|
|
29
|
-
};
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
// AutoStopService
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
export class AutoStopService {
|
|
34
|
-
sqlite;
|
|
35
|
-
eventBus;
|
|
36
|
-
killSwitchService;
|
|
37
|
-
notificationService;
|
|
38
|
-
config;
|
|
39
|
-
// Rule instances
|
|
40
|
-
consecutiveFailuresRule;
|
|
41
|
-
unusualActivityRule;
|
|
42
|
-
idleTimeoutRule;
|
|
43
|
-
// Idle check timer
|
|
44
|
-
idleCheckTimer = null;
|
|
45
|
-
constructor(opts) {
|
|
46
|
-
this.sqlite = opts.sqlite;
|
|
47
|
-
this.eventBus = opts.eventBus;
|
|
48
|
-
this.killSwitchService = opts.killSwitchService;
|
|
49
|
-
this.notificationService = opts.notificationService;
|
|
50
|
-
this.config = { ...DEFAULT_AUTOSTOP_CONFIG, ...opts.config };
|
|
51
|
-
// Initialize rules with configured thresholds
|
|
52
|
-
this.consecutiveFailuresRule = new ConsecutiveFailuresRule(this.config.consecutiveFailuresThreshold);
|
|
53
|
-
this.unusualActivityRule = new UnusualActivityRule(this.config.unusualActivityThreshold, this.config.unusualActivityWindowSec);
|
|
54
|
-
this.idleTimeoutRule = new IdleTimeoutRule(this.config.idleTimeoutSec);
|
|
55
|
-
}
|
|
56
|
-
// -----------------------------------------------------------------------
|
|
57
|
-
// Lifecycle
|
|
58
|
-
// -----------------------------------------------------------------------
|
|
59
|
-
/** Register EventBus listeners and start idle check timer. */
|
|
60
|
-
start() {
|
|
61
|
-
if (!this.config.enabled)
|
|
62
|
-
return;
|
|
63
|
-
// AUTO-01: CONSECUTIVE_FAILURES
|
|
64
|
-
this.eventBus.on('transaction:failed', (data) => {
|
|
65
|
-
const result = this.consecutiveFailuresRule.onTransactionFailed(data.walletId);
|
|
66
|
-
if (result.triggered) {
|
|
67
|
-
this.suspendWallet(result.walletId, 'CONSECUTIVE_FAILURES');
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
// Reset failure counter on successful transaction
|
|
71
|
-
this.eventBus.on('transaction:completed', (data) => {
|
|
72
|
-
this.consecutiveFailuresRule.onTransactionCompleted(data.walletId);
|
|
73
|
-
});
|
|
74
|
-
// AUTO-02: UNUSUAL_ACTIVITY + AUTO-03: IdleTimeout session tracking
|
|
75
|
-
this.eventBus.on('wallet:activity', (data) => {
|
|
76
|
-
// UnusualActivityRule
|
|
77
|
-
const result = this.unusualActivityRule.onWalletActivity(data.walletId, data.timestamp);
|
|
78
|
-
if (result.triggered) {
|
|
79
|
-
this.suspendWallet(result.walletId, 'UNUSUAL_ACTIVITY');
|
|
80
|
-
}
|
|
81
|
-
// IdleTimeoutRule: register new sessions or update activity
|
|
82
|
-
if (data.activity === 'SESSION_CREATED' && data.details?.sessionId) {
|
|
83
|
-
this.idleTimeoutRule.registerSession(data.walletId, data.details.sessionId, data.timestamp);
|
|
84
|
-
}
|
|
85
|
-
else if (data.details?.sessionId) {
|
|
86
|
-
this.idleTimeoutRule.onWalletActivity(data.walletId, data.timestamp, data.details.sessionId);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
this.idleTimeoutRule.onWalletActivity(data.walletId, data.timestamp);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
// AUTO-03: Periodic idle session check
|
|
93
|
-
this.idleCheckTimer = setInterval(() => {
|
|
94
|
-
this.checkIdleSessions();
|
|
95
|
-
}, this.config.idleCheckIntervalSec * 1000);
|
|
96
|
-
}
|
|
97
|
-
/** Stop idle check timer. Does NOT remove EventBus listeners (shared resource). */
|
|
98
|
-
stop() {
|
|
99
|
-
if (this.idleCheckTimer) {
|
|
100
|
-
clearInterval(this.idleCheckTimer);
|
|
101
|
-
this.idleCheckTimer = null;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// -----------------------------------------------------------------------
|
|
105
|
-
// AUTO-04: Manual Trigger
|
|
106
|
-
// -----------------------------------------------------------------------
|
|
107
|
-
/** Manually trigger Kill Switch cascade. */
|
|
108
|
-
manualTrigger(triggeredBy) {
|
|
109
|
-
this.killSwitchService.activateWithCascade(triggeredBy);
|
|
110
|
-
// Fire-and-forget notification (AUTO-06)
|
|
111
|
-
void this.notificationService?.notify('AUTO_STOP_TRIGGERED', 'system', { walletId: 'system', reason: 'Manual trigger by ' + triggeredBy, rule: 'MANUAL_TRIGGER' });
|
|
112
|
-
}
|
|
113
|
-
// -----------------------------------------------------------------------
|
|
114
|
-
// Wallet suspension (AUTO-01, AUTO-02)
|
|
115
|
-
// -----------------------------------------------------------------------
|
|
116
|
-
/** Suspend a wallet and log the action. Only affects ACTIVE wallets. */
|
|
117
|
-
suspendWallet(walletId, reason) {
|
|
118
|
-
const now = Math.floor(Date.now() / 1000);
|
|
119
|
-
const result = this.sqlite
|
|
120
|
-
.prepare("UPDATE wallets SET status = 'SUSPENDED', suspended_at = ?, suspension_reason = ? WHERE id = ? AND status = 'ACTIVE'")
|
|
121
|
-
.run(now, reason, walletId);
|
|
122
|
-
if (result.changes === 0) {
|
|
123
|
-
// Wallet already suspended or not found -- skip notification/audit
|
|
124
|
-
// Still reset counter to prevent re-checking
|
|
125
|
-
this.consecutiveFailuresRule.resetWallet(walletId);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
// Reset failure counter after trigger (must accumulate N new failures to re-trigger)
|
|
129
|
-
this.consecutiveFailuresRule.resetWallet(walletId);
|
|
130
|
-
// Audit log
|
|
131
|
-
try {
|
|
132
|
-
this.sqlite
|
|
133
|
-
.prepare('INSERT INTO audit_log (timestamp, event_type, actor, details, severity) VALUES (?, ?, ?, ?, ?)')
|
|
134
|
-
.run(now, 'AUTO_STOP_TRIGGERED', 'autostop', JSON.stringify({ action: 'wallet_suspended', reason, walletId }), 'warning');
|
|
135
|
-
}
|
|
136
|
-
catch {
|
|
137
|
-
// Best-effort audit logging
|
|
138
|
-
}
|
|
139
|
-
// Fire-and-forget notification (AUTO-06)
|
|
140
|
-
void this.notificationService?.notify('AUTO_STOP_TRIGGERED', walletId, { walletId, reason, rule: reason });
|
|
141
|
-
}
|
|
142
|
-
// -----------------------------------------------------------------------
|
|
143
|
-
// Session idle detection (AUTO-03) — notify only, no revoke (#204)
|
|
144
|
-
// -----------------------------------------------------------------------
|
|
145
|
-
/** Check idle sessions and send SESSION_IDLE notification instead of revoking. */
|
|
146
|
-
checkIdleSessions() {
|
|
147
|
-
const now = Math.floor(Date.now() / 1000);
|
|
148
|
-
const idleSessions = this.idleTimeoutRule.checkIdle(now);
|
|
149
|
-
for (const { walletId, sessionId } of idleSessions) {
|
|
150
|
-
this.notifyIdleSession(walletId, sessionId);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
/** Send SESSION_IDLE notification and remove from tracking to prevent duplicates (#204). */
|
|
154
|
-
notifyIdleSession(walletId, sessionId) {
|
|
155
|
-
// Remove from tracking to prevent duplicate notifications
|
|
156
|
-
this.idleTimeoutRule.removeSession(walletId, sessionId);
|
|
157
|
-
// Fire-and-forget notification
|
|
158
|
-
void this.notificationService?.notify('SESSION_IDLE', walletId, { walletId, sessionId, reason: 'Idle session detected' });
|
|
159
|
-
}
|
|
160
|
-
// -----------------------------------------------------------------------
|
|
161
|
-
// Runtime configuration update (AUTO-05)
|
|
162
|
-
// -----------------------------------------------------------------------
|
|
163
|
-
/** Update configuration at runtime (e.g., from Admin Settings). */
|
|
164
|
-
updateConfig(config) {
|
|
165
|
-
if (config.consecutiveFailuresThreshold !== undefined) {
|
|
166
|
-
this.config.consecutiveFailuresThreshold = config.consecutiveFailuresThreshold;
|
|
167
|
-
this.consecutiveFailuresRule.updateThreshold(config.consecutiveFailuresThreshold);
|
|
168
|
-
}
|
|
169
|
-
if (config.unusualActivityThreshold !== undefined) {
|
|
170
|
-
this.config.unusualActivityThreshold = config.unusualActivityThreshold;
|
|
171
|
-
this.unusualActivityRule.updateThreshold(config.unusualActivityThreshold);
|
|
172
|
-
}
|
|
173
|
-
if (config.unusualActivityWindowSec !== undefined) {
|
|
174
|
-
this.config.unusualActivityWindowSec = config.unusualActivityWindowSec;
|
|
175
|
-
this.unusualActivityRule.updateWindow(config.unusualActivityWindowSec);
|
|
176
|
-
}
|
|
177
|
-
if (config.idleTimeoutSec !== undefined) {
|
|
178
|
-
this.config.idleTimeoutSec = config.idleTimeoutSec;
|
|
179
|
-
this.idleTimeoutRule.updateTimeout(config.idleTimeoutSec);
|
|
180
|
-
}
|
|
181
|
-
if (config.idleCheckIntervalSec !== undefined) {
|
|
182
|
-
this.config.idleCheckIntervalSec = config.idleCheckIntervalSec;
|
|
183
|
-
// Restart timer with new interval
|
|
184
|
-
if (this.idleCheckTimer) {
|
|
185
|
-
clearInterval(this.idleCheckTimer);
|
|
186
|
-
this.idleCheckTimer = setInterval(() => {
|
|
187
|
-
this.checkIdleSessions();
|
|
188
|
-
}, config.idleCheckIntervalSec * 1000);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
if (config.enabled !== undefined) {
|
|
192
|
-
this.config.enabled = config.enabled;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// -----------------------------------------------------------------------
|
|
196
|
-
// Monitoring / status
|
|
197
|
-
// -----------------------------------------------------------------------
|
|
198
|
-
/** Get current rule engine status for debugging/monitoring. */
|
|
199
|
-
getStatus() {
|
|
200
|
-
return {
|
|
201
|
-
enabled: this.config.enabled,
|
|
202
|
-
config: { ...this.config },
|
|
203
|
-
rules: {
|
|
204
|
-
consecutiveFailures: {
|
|
205
|
-
trackedWallets: this.consecutiveFailuresRule.getTrackedCount(),
|
|
206
|
-
},
|
|
207
|
-
unusualActivity: {
|
|
208
|
-
trackedWallets: this.unusualActivityRule.getTrackedCount(),
|
|
209
|
-
},
|
|
210
|
-
idleTimeout: {
|
|
211
|
-
trackedSessions: this.idleTimeoutRule.getTrackedSessionCount(),
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
}
|
|
9
|
+
export { AutoStopService, DEFAULT_AUTOSTOP_CONFIG } from './autostop/autostop-service.js';
|
|
217
10
|
//# sourceMappingURL=autostop-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autostop-service.js","sourceRoot":"","sources":["../../src/services/autostop-service.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"autostop-service.js","sourceRoot":"","sources":["../../src/services/autostop-service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kill-switch-service.d.ts","sourceRoot":"","sources":["../../src/services/kill-switch-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"kill-switch-service.d.ts","sourceRoot":"","sources":["../../src/services/kill-switch-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAO7C,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,mBAAmB,CAAC,CAAsB;IAClD,OAAO,CAAC,QAAQ,CAAC,CAAW;gBAEhB,IAAI,EAAE;QAChB,MAAM,EAAE,QAAQ,CAAC;QACjB,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;QAC1C,QAAQ,CAAC,EAAE,QAAQ,CAAC;KACrB;IAMD,0DAA0D;IAC1D,QAAQ,IAAI,mBAAmB;IAoB/B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAItC;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAItC;;;OAGG;IACH,oBAAoB,IAAI,OAAO;IAa/B;;;OAGG;IACH,iBAAiB,IAAI,OAAO;IAa5B;;;OAGG;IACH,iBAAiB,IAAI,IAAI;IAazB;;;OAGG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa;IAgBvD;;;OAGG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa;IAqCvD;;;;;;;;;;OAUG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmExD;;;OAGG;IACH,OAAO,CAAC,aAAa;IA+CrB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;CAoC/B"}
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
*
|
|
35
35
|
* @see docs/36-killswitch-evm-freeze.md
|
|
36
36
|
*/
|
|
37
|
+
import { insertAuditLog } from '../infrastructure/database/audit-helper.js';
|
|
37
38
|
const KV_KEY_STATE = 'kill_switch_state';
|
|
38
39
|
const KV_KEY_ACTIVATED_AT = 'kill_switch_activated_at';
|
|
39
40
|
const KV_KEY_ACTIVATED_BY = 'kill_switch_activated_by';
|
|
@@ -82,14 +83,32 @@ export class KillSwitchService {
|
|
|
82
83
|
* Returns true on success, false on CAS failure (state was not SUSPENDED).
|
|
83
84
|
*/
|
|
84
85
|
recoverFromSuspended() {
|
|
85
|
-
|
|
86
|
+
const success = this.casTransitionWithClear('SUSPENDED', 'ACTIVE');
|
|
87
|
+
if (success) {
|
|
88
|
+
insertAuditLog(this.sqlite, {
|
|
89
|
+
eventType: 'KILL_SWITCH_RECOVERED',
|
|
90
|
+
actor: 'master',
|
|
91
|
+
details: { previousState: 'SUSPENDED', recoveredBy: 'master' },
|
|
92
|
+
severity: 'warning',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return success;
|
|
86
96
|
}
|
|
87
97
|
/**
|
|
88
98
|
* LOCKED -> ACTIVE transition (recovery from locked).
|
|
89
99
|
* Returns true on success, false on CAS failure (state was not LOCKED).
|
|
90
100
|
*/
|
|
91
101
|
recoverFromLocked() {
|
|
92
|
-
|
|
102
|
+
const success = this.casTransitionWithClear('LOCKED', 'ACTIVE');
|
|
103
|
+
if (success) {
|
|
104
|
+
insertAuditLog(this.sqlite, {
|
|
105
|
+
eventType: 'KILL_SWITCH_RECOVERED',
|
|
106
|
+
actor: 'master',
|
|
107
|
+
details: { previousState: 'LOCKED', recoveredBy: 'master' },
|
|
108
|
+
severity: 'warning',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return success;
|
|
93
112
|
}
|
|
94
113
|
/**
|
|
95
114
|
* Ensure kill_switch_state key exists in key_value_store.
|
|
@@ -136,17 +155,15 @@ export class KillSwitchService {
|
|
|
136
155
|
}
|
|
137
156
|
// Step: Send escalation notification
|
|
138
157
|
void this.notificationService?.notify('KILL_SWITCH_ESCALATED', 'system', { escalatedBy });
|
|
139
|
-
// Step: Audit log
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
// Best-effort audit logging
|
|
148
|
-
}
|
|
158
|
+
// Step: Audit log (best-effort via helper)
|
|
159
|
+
insertAuditLog(this.sqlite, {
|
|
160
|
+
eventType: 'KILL_SWITCH_ESCALATED',
|
|
161
|
+
actor: escalatedBy,
|
|
162
|
+
details: { action: 'kill_switch_escalated', escalatedBy },
|
|
163
|
+
severity: 'critical',
|
|
164
|
+
});
|
|
149
165
|
// EventBus emit
|
|
166
|
+
const now = Math.floor(Date.now() / 1000);
|
|
150
167
|
this.eventBus?.emit('kill-switch:state-changed', {
|
|
151
168
|
state: 'LOCKED',
|
|
152
169
|
previousState: 'SUSPENDED',
|
|
@@ -199,15 +216,13 @@ export class KillSwitchService {
|
|
|
199
216
|
// (KillSwitchService state is SUSPENDED/LOCKED -> middleware blocks)
|
|
200
217
|
// Step 5: Send notification
|
|
201
218
|
void this.notificationService?.notify('KILL_SWITCH_ACTIVATED', 'system', { activatedBy });
|
|
202
|
-
// Step 6: Audit log
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// Best-effort audit logging
|
|
210
|
-
}
|
|
219
|
+
// Step 6: Audit log (best-effort via helper)
|
|
220
|
+
insertAuditLog(this.sqlite, {
|
|
221
|
+
eventType: 'KILL_SWITCH_ACTIVATED',
|
|
222
|
+
actor: activatedBy,
|
|
223
|
+
details: { action: 'kill_switch_activated', activatedBy },
|
|
224
|
+
severity: 'critical',
|
|
225
|
+
});
|
|
211
226
|
// EventBus emit
|
|
212
227
|
this.eventBus?.emit('kill-switch:state-changed', {
|
|
213
228
|
state: 'SUSPENDED',
|