chainlesschain 0.132.0 → 0.145.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/package.json +1 -1
- package/src/commands/a2a.js +230 -0
- package/src/commands/activitypub.js +191 -0
- package/src/commands/agent.js +601 -0
- package/src/commands/audit.js +206 -0
- package/src/commands/bi.js +186 -0
- package/src/commands/bm25.js +162 -0
- package/src/commands/browse.js +225 -0
- package/src/commands/ccron.js +178 -0
- package/src/commands/chat.js +207 -0
- package/src/commands/compliance.js +420 -0
- package/src/commands/compt.js +176 -0
- package/src/commands/consol.js +237 -0
- package/src/commands/cowork.js +588 -0
- package/src/commands/crosschain.js +216 -0
- package/src/commands/dao.js +216 -0
- package/src/commands/dlp.js +206 -0
- package/src/commands/economy.js +211 -0
- package/src/commands/evolution.js +209 -0
- package/src/commands/evomap.js +216 -0
- package/src/commands/fflag.js +230 -0
- package/src/commands/git.js +185 -0
- package/src/commands/hardening.js +209 -0
- package/src/commands/hmemory.js +210 -0
- package/src/commands/incentive.js +209 -0
- package/src/commands/inference.js +178 -0
- package/src/commands/itbudget.js +161 -0
- package/src/commands/kg.js +206 -0
- package/src/commands/lowcode.js +201 -0
- package/src/commands/marketplace.js +206 -0
- package/src/commands/matrix.js +214 -0
- package/src/commands/mcpscaf.js +153 -0
- package/src/commands/meminj.js +153 -0
- package/src/commands/nostr.js +213 -0
- package/src/commands/orchestrate.js +217 -0
- package/src/commands/orchgov.js +156 -0
- package/src/commands/pdfp.js +160 -0
- package/src/commands/perf.js +176 -0
- package/src/commands/perm.js +156 -0
- package/src/commands/pipeline.js +211 -0
- package/src/commands/planmode.js +154 -0
- package/src/commands/privacy.js +203 -0
- package/src/commands/promcomp.js +166 -0
- package/src/commands/recommend.js +185 -0
- package/src/commands/reputation.js +208 -0
- package/src/commands/sandbox.js +206 -0
- package/src/commands/seshhook.js +153 -0
- package/src/commands/seshsearch.js +149 -0
- package/src/commands/seshtail.js +152 -0
- package/src/commands/seshu.js +160 -0
- package/src/commands/sganal.js +172 -0
- package/src/commands/siem.js +207 -0
- package/src/commands/sla.js +212 -0
- package/src/commands/slotfill.js +154 -0
- package/src/commands/social.js +159 -0
- package/src/commands/stress.js +206 -0
- package/src/commands/svccont.js +157 -0
- package/src/commands/terraform.js +206 -0
- package/src/commands/tms.js +183 -0
- package/src/commands/topiccls.js +158 -0
- package/src/commands/uprof.js +154 -0
- package/src/commands/vcheck.js +172 -0
- package/src/commands/webfetch.js +150 -0
- package/src/commands/zkp.js +218 -0
- package/src/harness/prompt-compressor.js +331 -0
- package/src/index.js +101 -1
- package/src/lib/a2a-protocol.js +373 -0
- package/src/lib/activitypub-bridge.js +343 -0
- package/src/lib/agent-economy.js +358 -0
- package/src/lib/app-builder.js +338 -0
- package/src/lib/audit-logger.js +321 -0
- package/src/lib/autonomous-agent.js +341 -0
- package/src/lib/bi-engine.js +339 -0
- package/src/lib/bm25-search.js +333 -0
- package/src/lib/browser-automation.js +352 -0
- package/src/lib/chat-core.js +336 -0
- package/src/lib/claude-code-bridge.js +341 -0
- package/src/lib/compliance-framework-reporter.js +359 -0
- package/src/lib/compliance-manager.js +330 -0
- package/src/lib/compression-telemetry.js +333 -0
- package/src/lib/content-recommender.js +370 -0
- package/src/lib/cowork-cron.js +330 -0
- package/src/lib/cowork-learning.js +333 -0
- package/src/lib/cowork-task-runner.js +362 -0
- package/src/lib/cowork-workflow.js +327 -0
- package/src/lib/cross-chain.js +365 -0
- package/src/lib/dao-governance.js +339 -0
- package/src/lib/dlp-engine.js +343 -0
- package/src/lib/evolution-system.js +336 -0
- package/src/lib/evomap-manager.js +339 -0
- package/src/lib/execution-backend.js +351 -0
- package/src/lib/feature-flags.js +330 -0
- package/src/lib/git-integration.js +343 -0
- package/src/lib/hardening-manager.js +341 -0
- package/src/lib/hierarchical-memory.js +341 -0
- package/src/lib/inference-network.js +362 -0
- package/src/lib/iteration-budget.js +357 -0
- package/src/lib/knowledge-graph.js +333 -0
- package/src/lib/matrix-bridge.js +339 -0
- package/src/lib/mcp-scaffold.js +345 -0
- package/src/lib/memory-injection.js +320 -0
- package/src/lib/nostr-bridge.js +342 -0
- package/src/lib/orchestrator.js +350 -0
- package/src/lib/pdf-parser.js +330 -0
- package/src/lib/perf-tuning.js +364 -0
- package/src/lib/permission-engine.js +319 -0
- package/src/lib/pipeline-orchestrator.js +345 -0
- package/src/lib/plan-mode.js +328 -0
- package/src/lib/privacy-computing.js +335 -0
- package/src/lib/prompt-compressor.js +1 -10
- package/src/lib/reputation-optimizer.js +340 -0
- package/src/lib/sandbox-v2.js +327 -0
- package/src/lib/service-container.js +342 -0
- package/src/lib/session-consolidator.js +352 -0
- package/src/lib/session-hooks.js +340 -0
- package/src/lib/session-search.js +334 -0
- package/src/lib/session-tail.js +320 -0
- package/src/lib/session-usage.js +329 -0
- package/src/lib/siem-exporter.js +352 -0
- package/src/lib/skill-marketplace.js +345 -0
- package/src/lib/sla-manager.js +341 -0
- package/src/lib/slot-filler.js +333 -0
- package/src/lib/social-graph-analytics.js +327 -0
- package/src/lib/social-graph.js +304 -0
- package/src/lib/stress-tester.js +342 -0
- package/src/lib/sub-agent-registry.js +359 -0
- package/src/lib/task-model-selector.js +333 -0
- package/src/lib/terraform-manager.js +333 -0
- package/src/lib/todo-manager.js +339 -0
- package/src/lib/token-incentive.js +341 -0
- package/src/lib/topic-classifier.js +353 -0
- package/src/lib/user-profile.js +325 -0
- package/src/lib/version-checker.js +335 -0
- package/src/lib/web-fetch.js +322 -0
- package/src/lib/zkp-engine.js +342 -0
|
@@ -88,3 +88,323 @@ export function buildMemoryInjection(options = {}) {
|
|
|
88
88
|
});
|
|
89
89
|
return content ? { role: "system", content, count: memories.length } : null;
|
|
90
90
|
}
|
|
91
|
+
|
|
92
|
+
// ===== V2 Surface: Memory Injection governance overlay (CLI v0.142.0) =====
|
|
93
|
+
export const MINJ_RULE_MATURITY_V2 = Object.freeze({
|
|
94
|
+
PENDING: "pending",
|
|
95
|
+
ACTIVE: "active",
|
|
96
|
+
PAUSED: "paused",
|
|
97
|
+
ARCHIVED: "archived",
|
|
98
|
+
});
|
|
99
|
+
export const MINJ_INJECTION_LIFECYCLE_V2 = Object.freeze({
|
|
100
|
+
QUEUED: "queued",
|
|
101
|
+
INJECTING: "injecting",
|
|
102
|
+
APPLIED: "applied",
|
|
103
|
+
FAILED: "failed",
|
|
104
|
+
CANCELLED: "cancelled",
|
|
105
|
+
});
|
|
106
|
+
const _minjRTrans = new Map([
|
|
107
|
+
[
|
|
108
|
+
MINJ_RULE_MATURITY_V2.PENDING,
|
|
109
|
+
new Set([MINJ_RULE_MATURITY_V2.ACTIVE, MINJ_RULE_MATURITY_V2.ARCHIVED]),
|
|
110
|
+
],
|
|
111
|
+
[
|
|
112
|
+
MINJ_RULE_MATURITY_V2.ACTIVE,
|
|
113
|
+
new Set([MINJ_RULE_MATURITY_V2.PAUSED, MINJ_RULE_MATURITY_V2.ARCHIVED]),
|
|
114
|
+
],
|
|
115
|
+
[
|
|
116
|
+
MINJ_RULE_MATURITY_V2.PAUSED,
|
|
117
|
+
new Set([MINJ_RULE_MATURITY_V2.ACTIVE, MINJ_RULE_MATURITY_V2.ARCHIVED]),
|
|
118
|
+
],
|
|
119
|
+
[MINJ_RULE_MATURITY_V2.ARCHIVED, new Set()],
|
|
120
|
+
]);
|
|
121
|
+
const _minjRTerminal = new Set([MINJ_RULE_MATURITY_V2.ARCHIVED]);
|
|
122
|
+
const _minjITrans = new Map([
|
|
123
|
+
[
|
|
124
|
+
MINJ_INJECTION_LIFECYCLE_V2.QUEUED,
|
|
125
|
+
new Set([
|
|
126
|
+
MINJ_INJECTION_LIFECYCLE_V2.INJECTING,
|
|
127
|
+
MINJ_INJECTION_LIFECYCLE_V2.CANCELLED,
|
|
128
|
+
]),
|
|
129
|
+
],
|
|
130
|
+
[
|
|
131
|
+
MINJ_INJECTION_LIFECYCLE_V2.INJECTING,
|
|
132
|
+
new Set([
|
|
133
|
+
MINJ_INJECTION_LIFECYCLE_V2.APPLIED,
|
|
134
|
+
MINJ_INJECTION_LIFECYCLE_V2.FAILED,
|
|
135
|
+
MINJ_INJECTION_LIFECYCLE_V2.CANCELLED,
|
|
136
|
+
]),
|
|
137
|
+
],
|
|
138
|
+
[MINJ_INJECTION_LIFECYCLE_V2.APPLIED, new Set()],
|
|
139
|
+
[MINJ_INJECTION_LIFECYCLE_V2.FAILED, new Set()],
|
|
140
|
+
[MINJ_INJECTION_LIFECYCLE_V2.CANCELLED, new Set()],
|
|
141
|
+
]);
|
|
142
|
+
const _minjRsV2 = new Map();
|
|
143
|
+
const _minjIsV2 = new Map();
|
|
144
|
+
let _minjMaxActive = 10,
|
|
145
|
+
_minjMaxPending = 25,
|
|
146
|
+
_minjIdleMs = 30 * 24 * 60 * 60 * 1000,
|
|
147
|
+
_minjStuckMs = 30 * 1000;
|
|
148
|
+
function _minjPos(n, label) {
|
|
149
|
+
const v = Math.floor(Number(n));
|
|
150
|
+
if (!Number.isFinite(v) || v <= 0)
|
|
151
|
+
throw new Error(`${label} must be positive integer`);
|
|
152
|
+
return v;
|
|
153
|
+
}
|
|
154
|
+
function _minjCheckR(from, to) {
|
|
155
|
+
const a = _minjRTrans.get(from);
|
|
156
|
+
if (!a || !a.has(to))
|
|
157
|
+
throw new Error(`invalid minj rule transition ${from} → ${to}`);
|
|
158
|
+
}
|
|
159
|
+
function _minjCheckI(from, to) {
|
|
160
|
+
const a = _minjITrans.get(from);
|
|
161
|
+
if (!a || !a.has(to))
|
|
162
|
+
throw new Error(`invalid minj injection transition ${from} → ${to}`);
|
|
163
|
+
}
|
|
164
|
+
export function setMaxActiveMinjRulesPerOwnerV2(n) {
|
|
165
|
+
_minjMaxActive = _minjPos(n, "maxActiveMinjRulesPerOwner");
|
|
166
|
+
}
|
|
167
|
+
export function getMaxActiveMinjRulesPerOwnerV2() {
|
|
168
|
+
return _minjMaxActive;
|
|
169
|
+
}
|
|
170
|
+
export function setMaxPendingMinjInjectionsPerRuleV2(n) {
|
|
171
|
+
_minjMaxPending = _minjPos(n, "maxPendingMinjInjectionsPerRule");
|
|
172
|
+
}
|
|
173
|
+
export function getMaxPendingMinjInjectionsPerRuleV2() {
|
|
174
|
+
return _minjMaxPending;
|
|
175
|
+
}
|
|
176
|
+
export function setMinjRuleIdleMsV2(n) {
|
|
177
|
+
_minjIdleMs = _minjPos(n, "minjRuleIdleMs");
|
|
178
|
+
}
|
|
179
|
+
export function getMinjRuleIdleMsV2() {
|
|
180
|
+
return _minjIdleMs;
|
|
181
|
+
}
|
|
182
|
+
export function setMinjInjectionStuckMsV2(n) {
|
|
183
|
+
_minjStuckMs = _minjPos(n, "minjInjectionStuckMs");
|
|
184
|
+
}
|
|
185
|
+
export function getMinjInjectionStuckMsV2() {
|
|
186
|
+
return _minjStuckMs;
|
|
187
|
+
}
|
|
188
|
+
export function _resetStateMemoryInjectionV2() {
|
|
189
|
+
_minjRsV2.clear();
|
|
190
|
+
_minjIsV2.clear();
|
|
191
|
+
_minjMaxActive = 10;
|
|
192
|
+
_minjMaxPending = 25;
|
|
193
|
+
_minjIdleMs = 30 * 24 * 60 * 60 * 1000;
|
|
194
|
+
_minjStuckMs = 30 * 1000;
|
|
195
|
+
}
|
|
196
|
+
export function registerMinjRuleV2({ id, owner, scope, metadata } = {}) {
|
|
197
|
+
if (!id) throw new Error("minj rule id required");
|
|
198
|
+
if (!owner) throw new Error("minj rule owner required");
|
|
199
|
+
if (_minjRsV2.has(id)) throw new Error(`minj rule ${id} already registered`);
|
|
200
|
+
const now = Date.now();
|
|
201
|
+
const r = {
|
|
202
|
+
id,
|
|
203
|
+
owner,
|
|
204
|
+
scope: scope || "*",
|
|
205
|
+
status: MINJ_RULE_MATURITY_V2.PENDING,
|
|
206
|
+
createdAt: now,
|
|
207
|
+
updatedAt: now,
|
|
208
|
+
activatedAt: null,
|
|
209
|
+
archivedAt: null,
|
|
210
|
+
lastTouchedAt: now,
|
|
211
|
+
metadata: { ...(metadata || {}) },
|
|
212
|
+
};
|
|
213
|
+
_minjRsV2.set(id, r);
|
|
214
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
215
|
+
}
|
|
216
|
+
function _minjCountActive(owner) {
|
|
217
|
+
let n = 0;
|
|
218
|
+
for (const r of _minjRsV2.values())
|
|
219
|
+
if (r.owner === owner && r.status === MINJ_RULE_MATURITY_V2.ACTIVE) n++;
|
|
220
|
+
return n;
|
|
221
|
+
}
|
|
222
|
+
export function activateMinjRuleV2(id) {
|
|
223
|
+
const r = _minjRsV2.get(id);
|
|
224
|
+
if (!r) throw new Error(`minj rule ${id} not found`);
|
|
225
|
+
_minjCheckR(r.status, MINJ_RULE_MATURITY_V2.ACTIVE);
|
|
226
|
+
const recovery = r.status === MINJ_RULE_MATURITY_V2.PAUSED;
|
|
227
|
+
if (!recovery && _minjCountActive(r.owner) >= _minjMaxActive)
|
|
228
|
+
throw new Error(`max active minj rules for owner ${r.owner} reached`);
|
|
229
|
+
const now = Date.now();
|
|
230
|
+
r.status = MINJ_RULE_MATURITY_V2.ACTIVE;
|
|
231
|
+
r.updatedAt = now;
|
|
232
|
+
r.lastTouchedAt = now;
|
|
233
|
+
if (!r.activatedAt) r.activatedAt = now;
|
|
234
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
235
|
+
}
|
|
236
|
+
export function pauseMinjRuleV2(id) {
|
|
237
|
+
const r = _minjRsV2.get(id);
|
|
238
|
+
if (!r) throw new Error(`minj rule ${id} not found`);
|
|
239
|
+
_minjCheckR(r.status, MINJ_RULE_MATURITY_V2.PAUSED);
|
|
240
|
+
r.status = MINJ_RULE_MATURITY_V2.PAUSED;
|
|
241
|
+
r.updatedAt = Date.now();
|
|
242
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
243
|
+
}
|
|
244
|
+
export function archiveMinjRuleV2(id) {
|
|
245
|
+
const r = _minjRsV2.get(id);
|
|
246
|
+
if (!r) throw new Error(`minj rule ${id} not found`);
|
|
247
|
+
_minjCheckR(r.status, MINJ_RULE_MATURITY_V2.ARCHIVED);
|
|
248
|
+
const now = Date.now();
|
|
249
|
+
r.status = MINJ_RULE_MATURITY_V2.ARCHIVED;
|
|
250
|
+
r.updatedAt = now;
|
|
251
|
+
if (!r.archivedAt) r.archivedAt = now;
|
|
252
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
253
|
+
}
|
|
254
|
+
export function touchMinjRuleV2(id) {
|
|
255
|
+
const r = _minjRsV2.get(id);
|
|
256
|
+
if (!r) throw new Error(`minj rule ${id} not found`);
|
|
257
|
+
if (_minjRTerminal.has(r.status))
|
|
258
|
+
throw new Error(`cannot touch terminal minj rule ${id}`);
|
|
259
|
+
const now = Date.now();
|
|
260
|
+
r.lastTouchedAt = now;
|
|
261
|
+
r.updatedAt = now;
|
|
262
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
263
|
+
}
|
|
264
|
+
export function getMinjRuleV2(id) {
|
|
265
|
+
const r = _minjRsV2.get(id);
|
|
266
|
+
if (!r) return null;
|
|
267
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
268
|
+
}
|
|
269
|
+
export function listMinjRulesV2() {
|
|
270
|
+
return [..._minjRsV2.values()].map((r) => ({
|
|
271
|
+
...r,
|
|
272
|
+
metadata: { ...r.metadata },
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
275
|
+
function _minjCountPending(ruleId) {
|
|
276
|
+
let n = 0;
|
|
277
|
+
for (const i of _minjIsV2.values())
|
|
278
|
+
if (
|
|
279
|
+
i.ruleId === ruleId &&
|
|
280
|
+
(i.status === MINJ_INJECTION_LIFECYCLE_V2.QUEUED ||
|
|
281
|
+
i.status === MINJ_INJECTION_LIFECYCLE_V2.INJECTING)
|
|
282
|
+
)
|
|
283
|
+
n++;
|
|
284
|
+
return n;
|
|
285
|
+
}
|
|
286
|
+
export function createMinjInjectionV2({ id, ruleId, payload, metadata } = {}) {
|
|
287
|
+
if (!id) throw new Error("minj injection id required");
|
|
288
|
+
if (!ruleId) throw new Error("minj injection ruleId required");
|
|
289
|
+
if (_minjIsV2.has(id)) throw new Error(`minj injection ${id} already exists`);
|
|
290
|
+
if (!_minjRsV2.has(ruleId)) throw new Error(`minj rule ${ruleId} not found`);
|
|
291
|
+
if (_minjCountPending(ruleId) >= _minjMaxPending)
|
|
292
|
+
throw new Error(`max pending minj injections for rule ${ruleId} reached`);
|
|
293
|
+
const now = Date.now();
|
|
294
|
+
const i = {
|
|
295
|
+
id,
|
|
296
|
+
ruleId,
|
|
297
|
+
payload: payload || "",
|
|
298
|
+
status: MINJ_INJECTION_LIFECYCLE_V2.QUEUED,
|
|
299
|
+
createdAt: now,
|
|
300
|
+
updatedAt: now,
|
|
301
|
+
startedAt: null,
|
|
302
|
+
settledAt: null,
|
|
303
|
+
metadata: { ...(metadata || {}) },
|
|
304
|
+
};
|
|
305
|
+
_minjIsV2.set(id, i);
|
|
306
|
+
return { ...i, metadata: { ...i.metadata } };
|
|
307
|
+
}
|
|
308
|
+
export function injectingMinjInjectionV2(id) {
|
|
309
|
+
const i = _minjIsV2.get(id);
|
|
310
|
+
if (!i) throw new Error(`minj injection ${id} not found`);
|
|
311
|
+
_minjCheckI(i.status, MINJ_INJECTION_LIFECYCLE_V2.INJECTING);
|
|
312
|
+
const now = Date.now();
|
|
313
|
+
i.status = MINJ_INJECTION_LIFECYCLE_V2.INJECTING;
|
|
314
|
+
i.updatedAt = now;
|
|
315
|
+
if (!i.startedAt) i.startedAt = now;
|
|
316
|
+
return { ...i, metadata: { ...i.metadata } };
|
|
317
|
+
}
|
|
318
|
+
export function applyMinjInjectionV2(id) {
|
|
319
|
+
const i = _minjIsV2.get(id);
|
|
320
|
+
if (!i) throw new Error(`minj injection ${id} not found`);
|
|
321
|
+
_minjCheckI(i.status, MINJ_INJECTION_LIFECYCLE_V2.APPLIED);
|
|
322
|
+
const now = Date.now();
|
|
323
|
+
i.status = MINJ_INJECTION_LIFECYCLE_V2.APPLIED;
|
|
324
|
+
i.updatedAt = now;
|
|
325
|
+
if (!i.settledAt) i.settledAt = now;
|
|
326
|
+
return { ...i, metadata: { ...i.metadata } };
|
|
327
|
+
}
|
|
328
|
+
export function failMinjInjectionV2(id, reason) {
|
|
329
|
+
const i = _minjIsV2.get(id);
|
|
330
|
+
if (!i) throw new Error(`minj injection ${id} not found`);
|
|
331
|
+
_minjCheckI(i.status, MINJ_INJECTION_LIFECYCLE_V2.FAILED);
|
|
332
|
+
const now = Date.now();
|
|
333
|
+
i.status = MINJ_INJECTION_LIFECYCLE_V2.FAILED;
|
|
334
|
+
i.updatedAt = now;
|
|
335
|
+
if (!i.settledAt) i.settledAt = now;
|
|
336
|
+
if (reason) i.metadata.failReason = String(reason);
|
|
337
|
+
return { ...i, metadata: { ...i.metadata } };
|
|
338
|
+
}
|
|
339
|
+
export function cancelMinjInjectionV2(id, reason) {
|
|
340
|
+
const i = _minjIsV2.get(id);
|
|
341
|
+
if (!i) throw new Error(`minj injection ${id} not found`);
|
|
342
|
+
_minjCheckI(i.status, MINJ_INJECTION_LIFECYCLE_V2.CANCELLED);
|
|
343
|
+
const now = Date.now();
|
|
344
|
+
i.status = MINJ_INJECTION_LIFECYCLE_V2.CANCELLED;
|
|
345
|
+
i.updatedAt = now;
|
|
346
|
+
if (!i.settledAt) i.settledAt = now;
|
|
347
|
+
if (reason) i.metadata.cancelReason = String(reason);
|
|
348
|
+
return { ...i, metadata: { ...i.metadata } };
|
|
349
|
+
}
|
|
350
|
+
export function getMinjInjectionV2(id) {
|
|
351
|
+
const i = _minjIsV2.get(id);
|
|
352
|
+
if (!i) return null;
|
|
353
|
+
return { ...i, metadata: { ...i.metadata } };
|
|
354
|
+
}
|
|
355
|
+
export function listMinjInjectionsV2() {
|
|
356
|
+
return [..._minjIsV2.values()].map((i) => ({
|
|
357
|
+
...i,
|
|
358
|
+
metadata: { ...i.metadata },
|
|
359
|
+
}));
|
|
360
|
+
}
|
|
361
|
+
export function autoPauseIdleMinjRulesV2({ now } = {}) {
|
|
362
|
+
const t = now ?? Date.now();
|
|
363
|
+
const flipped = [];
|
|
364
|
+
for (const r of _minjRsV2.values())
|
|
365
|
+
if (
|
|
366
|
+
r.status === MINJ_RULE_MATURITY_V2.ACTIVE &&
|
|
367
|
+
t - r.lastTouchedAt >= _minjIdleMs
|
|
368
|
+
) {
|
|
369
|
+
r.status = MINJ_RULE_MATURITY_V2.PAUSED;
|
|
370
|
+
r.updatedAt = t;
|
|
371
|
+
flipped.push(r.id);
|
|
372
|
+
}
|
|
373
|
+
return { flipped, count: flipped.length };
|
|
374
|
+
}
|
|
375
|
+
export function autoFailStuckMinjInjectionsV2({ now } = {}) {
|
|
376
|
+
const t = now ?? Date.now();
|
|
377
|
+
const flipped = [];
|
|
378
|
+
for (const i of _minjIsV2.values())
|
|
379
|
+
if (
|
|
380
|
+
i.status === MINJ_INJECTION_LIFECYCLE_V2.INJECTING &&
|
|
381
|
+
i.startedAt != null &&
|
|
382
|
+
t - i.startedAt >= _minjStuckMs
|
|
383
|
+
) {
|
|
384
|
+
i.status = MINJ_INJECTION_LIFECYCLE_V2.FAILED;
|
|
385
|
+
i.updatedAt = t;
|
|
386
|
+
if (!i.settledAt) i.settledAt = t;
|
|
387
|
+
i.metadata.failReason = "auto-fail-stuck";
|
|
388
|
+
flipped.push(i.id);
|
|
389
|
+
}
|
|
390
|
+
return { flipped, count: flipped.length };
|
|
391
|
+
}
|
|
392
|
+
export function getMemoryInjectionGovStatsV2() {
|
|
393
|
+
const rulesByStatus = {};
|
|
394
|
+
for (const v of Object.values(MINJ_RULE_MATURITY_V2)) rulesByStatus[v] = 0;
|
|
395
|
+
for (const r of _minjRsV2.values()) rulesByStatus[r.status]++;
|
|
396
|
+
const injectionsByStatus = {};
|
|
397
|
+
for (const v of Object.values(MINJ_INJECTION_LIFECYCLE_V2))
|
|
398
|
+
injectionsByStatus[v] = 0;
|
|
399
|
+
for (const i of _minjIsV2.values()) injectionsByStatus[i.status]++;
|
|
400
|
+
return {
|
|
401
|
+
totalMinjRulesV2: _minjRsV2.size,
|
|
402
|
+
totalMinjInjectionsV2: _minjIsV2.size,
|
|
403
|
+
maxActiveMinjRulesPerOwner: _minjMaxActive,
|
|
404
|
+
maxPendingMinjInjectionsPerRule: _minjMaxPending,
|
|
405
|
+
minjRuleIdleMs: _minjIdleMs,
|
|
406
|
+
minjInjectionStuckMs: _minjStuckMs,
|
|
407
|
+
rulesByStatus,
|
|
408
|
+
injectionsByStatus,
|
|
409
|
+
};
|
|
410
|
+
}
|
package/src/lib/nostr-bridge.js
CHANGED
|
@@ -369,3 +369,345 @@ export function _resetState() {
|
|
|
369
369
|
_keypairs.clear();
|
|
370
370
|
_didMappings.clear();
|
|
371
371
|
}
|
|
372
|
+
|
|
373
|
+
// ===== V2 Surface: Nostr Bridge governance overlay (CLI v0.134.0) =====
|
|
374
|
+
export const NOSTR_RELAY_MATURITY_V2 = Object.freeze({
|
|
375
|
+
PENDING: "pending",
|
|
376
|
+
ACTIVE: "active",
|
|
377
|
+
OFFLINE: "offline",
|
|
378
|
+
RETIRED: "retired",
|
|
379
|
+
});
|
|
380
|
+
export const NOSTR_EVENT_LIFECYCLE_V2 = Object.freeze({
|
|
381
|
+
QUEUED: "queued",
|
|
382
|
+
PUBLISHING: "publishing",
|
|
383
|
+
PUBLISHED: "published",
|
|
384
|
+
FAILED: "failed",
|
|
385
|
+
CANCELLED: "cancelled",
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const _nsRelayTrans = new Map([
|
|
389
|
+
[
|
|
390
|
+
NOSTR_RELAY_MATURITY_V2.PENDING,
|
|
391
|
+
new Set([NOSTR_RELAY_MATURITY_V2.ACTIVE, NOSTR_RELAY_MATURITY_V2.RETIRED]),
|
|
392
|
+
],
|
|
393
|
+
[
|
|
394
|
+
NOSTR_RELAY_MATURITY_V2.ACTIVE,
|
|
395
|
+
new Set([NOSTR_RELAY_MATURITY_V2.OFFLINE, NOSTR_RELAY_MATURITY_V2.RETIRED]),
|
|
396
|
+
],
|
|
397
|
+
[
|
|
398
|
+
NOSTR_RELAY_MATURITY_V2.OFFLINE,
|
|
399
|
+
new Set([NOSTR_RELAY_MATURITY_V2.ACTIVE, NOSTR_RELAY_MATURITY_V2.RETIRED]),
|
|
400
|
+
],
|
|
401
|
+
[NOSTR_RELAY_MATURITY_V2.RETIRED, new Set()],
|
|
402
|
+
]);
|
|
403
|
+
const _nsRelayTerminal = new Set([NOSTR_RELAY_MATURITY_V2.RETIRED]);
|
|
404
|
+
const _nsEventTrans = new Map([
|
|
405
|
+
[
|
|
406
|
+
NOSTR_EVENT_LIFECYCLE_V2.QUEUED,
|
|
407
|
+
new Set([
|
|
408
|
+
NOSTR_EVENT_LIFECYCLE_V2.PUBLISHING,
|
|
409
|
+
NOSTR_EVENT_LIFECYCLE_V2.CANCELLED,
|
|
410
|
+
]),
|
|
411
|
+
],
|
|
412
|
+
[
|
|
413
|
+
NOSTR_EVENT_LIFECYCLE_V2.PUBLISHING,
|
|
414
|
+
new Set([
|
|
415
|
+
NOSTR_EVENT_LIFECYCLE_V2.PUBLISHED,
|
|
416
|
+
NOSTR_EVENT_LIFECYCLE_V2.FAILED,
|
|
417
|
+
NOSTR_EVENT_LIFECYCLE_V2.CANCELLED,
|
|
418
|
+
]),
|
|
419
|
+
],
|
|
420
|
+
[NOSTR_EVENT_LIFECYCLE_V2.PUBLISHED, new Set()],
|
|
421
|
+
[NOSTR_EVENT_LIFECYCLE_V2.FAILED, new Set()],
|
|
422
|
+
[NOSTR_EVENT_LIFECYCLE_V2.CANCELLED, new Set()],
|
|
423
|
+
]);
|
|
424
|
+
|
|
425
|
+
const _nsRelays = new Map();
|
|
426
|
+
const _nsEvents = new Map();
|
|
427
|
+
let _nsMaxActivePerOwner = 10;
|
|
428
|
+
let _nsMaxPendingPerRelay = 30;
|
|
429
|
+
let _nsRelayIdleMs = 60 * 60 * 1000;
|
|
430
|
+
let _nsEventStuckMs = 2 * 60 * 1000;
|
|
431
|
+
|
|
432
|
+
function _nsPos(n, lbl) {
|
|
433
|
+
const v = Math.floor(Number(n));
|
|
434
|
+
if (!Number.isFinite(v) || v <= 0)
|
|
435
|
+
throw new Error(`${lbl} must be positive integer`);
|
|
436
|
+
return v;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export function setMaxActiveNostrRelaysPerOwnerV2(n) {
|
|
440
|
+
_nsMaxActivePerOwner = _nsPos(n, "maxActiveNostrRelaysPerOwner");
|
|
441
|
+
}
|
|
442
|
+
export function getMaxActiveNostrRelaysPerOwnerV2() {
|
|
443
|
+
return _nsMaxActivePerOwner;
|
|
444
|
+
}
|
|
445
|
+
export function setMaxPendingNostrEventsPerRelayV2(n) {
|
|
446
|
+
_nsMaxPendingPerRelay = _nsPos(n, "maxPendingNostrEventsPerRelay");
|
|
447
|
+
}
|
|
448
|
+
export function getMaxPendingNostrEventsPerRelayV2() {
|
|
449
|
+
return _nsMaxPendingPerRelay;
|
|
450
|
+
}
|
|
451
|
+
export function setNostrRelayIdleMsV2(n) {
|
|
452
|
+
_nsRelayIdleMs = _nsPos(n, "nostrRelayIdleMs");
|
|
453
|
+
}
|
|
454
|
+
export function getNostrRelayIdleMsV2() {
|
|
455
|
+
return _nsRelayIdleMs;
|
|
456
|
+
}
|
|
457
|
+
export function setNostrEventStuckMsV2(n) {
|
|
458
|
+
_nsEventStuckMs = _nsPos(n, "nostrEventStuckMs");
|
|
459
|
+
}
|
|
460
|
+
export function getNostrEventStuckMsV2() {
|
|
461
|
+
return _nsEventStuckMs;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export function _resetStateNostrBridgeV2() {
|
|
465
|
+
_nsRelays.clear();
|
|
466
|
+
_nsEvents.clear();
|
|
467
|
+
_nsMaxActivePerOwner = 10;
|
|
468
|
+
_nsMaxPendingPerRelay = 30;
|
|
469
|
+
_nsRelayIdleMs = 60 * 60 * 1000;
|
|
470
|
+
_nsEventStuckMs = 2 * 60 * 1000;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export function registerNostrRelayV2({ id, owner, url, metadata } = {}) {
|
|
474
|
+
if (!id || typeof id !== "string") throw new Error("id is required");
|
|
475
|
+
if (!owner || typeof owner !== "string") throw new Error("owner is required");
|
|
476
|
+
if (_nsRelays.has(id))
|
|
477
|
+
throw new Error(`nostr relay ${id} already registered`);
|
|
478
|
+
const now = Date.now();
|
|
479
|
+
const r = {
|
|
480
|
+
id,
|
|
481
|
+
owner,
|
|
482
|
+
url: url || "",
|
|
483
|
+
status: NOSTR_RELAY_MATURITY_V2.PENDING,
|
|
484
|
+
createdAt: now,
|
|
485
|
+
updatedAt: now,
|
|
486
|
+
activatedAt: null,
|
|
487
|
+
retiredAt: null,
|
|
488
|
+
lastTouchedAt: now,
|
|
489
|
+
metadata: { ...(metadata || {}) },
|
|
490
|
+
};
|
|
491
|
+
_nsRelays.set(id, r);
|
|
492
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
493
|
+
}
|
|
494
|
+
function _nsCheckR(from, to) {
|
|
495
|
+
const a = _nsRelayTrans.get(from);
|
|
496
|
+
if (!a || !a.has(to))
|
|
497
|
+
throw new Error(`invalid nostr relay transition ${from} → ${to}`);
|
|
498
|
+
}
|
|
499
|
+
function _nsCountActive(owner) {
|
|
500
|
+
let n = 0;
|
|
501
|
+
for (const r of _nsRelays.values())
|
|
502
|
+
if (r.owner === owner && r.status === NOSTR_RELAY_MATURITY_V2.ACTIVE) n++;
|
|
503
|
+
return n;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export function activateNostrRelayV2(id) {
|
|
507
|
+
const r = _nsRelays.get(id);
|
|
508
|
+
if (!r) throw new Error(`nostr relay ${id} not found`);
|
|
509
|
+
_nsCheckR(r.status, NOSTR_RELAY_MATURITY_V2.ACTIVE);
|
|
510
|
+
const recovery = r.status === NOSTR_RELAY_MATURITY_V2.OFFLINE;
|
|
511
|
+
if (!recovery) {
|
|
512
|
+
const a = _nsCountActive(r.owner);
|
|
513
|
+
if (a >= _nsMaxActivePerOwner)
|
|
514
|
+
throw new Error(
|
|
515
|
+
`max active nostr relays per owner (${_nsMaxActivePerOwner}) reached for ${r.owner}`,
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
const now = Date.now();
|
|
519
|
+
r.status = NOSTR_RELAY_MATURITY_V2.ACTIVE;
|
|
520
|
+
r.updatedAt = now;
|
|
521
|
+
r.lastTouchedAt = now;
|
|
522
|
+
if (!r.activatedAt) r.activatedAt = now;
|
|
523
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
524
|
+
}
|
|
525
|
+
export function offlineNostrRelayV2(id) {
|
|
526
|
+
const r = _nsRelays.get(id);
|
|
527
|
+
if (!r) throw new Error(`nostr relay ${id} not found`);
|
|
528
|
+
_nsCheckR(r.status, NOSTR_RELAY_MATURITY_V2.OFFLINE);
|
|
529
|
+
r.status = NOSTR_RELAY_MATURITY_V2.OFFLINE;
|
|
530
|
+
r.updatedAt = Date.now();
|
|
531
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
532
|
+
}
|
|
533
|
+
export function retireNostrRelayV2(id) {
|
|
534
|
+
const r = _nsRelays.get(id);
|
|
535
|
+
if (!r) throw new Error(`nostr relay ${id} not found`);
|
|
536
|
+
_nsCheckR(r.status, NOSTR_RELAY_MATURITY_V2.RETIRED);
|
|
537
|
+
const now = Date.now();
|
|
538
|
+
r.status = NOSTR_RELAY_MATURITY_V2.RETIRED;
|
|
539
|
+
r.updatedAt = now;
|
|
540
|
+
if (!r.retiredAt) r.retiredAt = now;
|
|
541
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
542
|
+
}
|
|
543
|
+
export function touchNostrRelayV2(id) {
|
|
544
|
+
const r = _nsRelays.get(id);
|
|
545
|
+
if (!r) throw new Error(`nostr relay ${id} not found`);
|
|
546
|
+
if (_nsRelayTerminal.has(r.status))
|
|
547
|
+
throw new Error(`cannot touch terminal nostr relay ${id}`);
|
|
548
|
+
const now = Date.now();
|
|
549
|
+
r.lastTouchedAt = now;
|
|
550
|
+
r.updatedAt = now;
|
|
551
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
552
|
+
}
|
|
553
|
+
export function getNostrRelayV2(id) {
|
|
554
|
+
const r = _nsRelays.get(id);
|
|
555
|
+
if (!r) return null;
|
|
556
|
+
return { ...r, metadata: { ...r.metadata } };
|
|
557
|
+
}
|
|
558
|
+
export function listNostrRelaysV2() {
|
|
559
|
+
return [..._nsRelays.values()].map((r) => ({
|
|
560
|
+
...r,
|
|
561
|
+
metadata: { ...r.metadata },
|
|
562
|
+
}));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function _nsCountPending(rid) {
|
|
566
|
+
let n = 0;
|
|
567
|
+
for (const e of _nsEvents.values())
|
|
568
|
+
if (
|
|
569
|
+
e.relayId === rid &&
|
|
570
|
+
(e.status === NOSTR_EVENT_LIFECYCLE_V2.QUEUED ||
|
|
571
|
+
e.status === NOSTR_EVENT_LIFECYCLE_V2.PUBLISHING)
|
|
572
|
+
)
|
|
573
|
+
n++;
|
|
574
|
+
return n;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export function createNostrEventV2({ id, relayId, kind, metadata } = {}) {
|
|
578
|
+
if (!id || typeof id !== "string") throw new Error("id is required");
|
|
579
|
+
if (!relayId || typeof relayId !== "string")
|
|
580
|
+
throw new Error("relayId is required");
|
|
581
|
+
if (_nsEvents.has(id)) throw new Error(`nostr event ${id} already exists`);
|
|
582
|
+
if (!_nsRelays.has(relayId))
|
|
583
|
+
throw new Error(`nostr relay ${relayId} not found`);
|
|
584
|
+
const pending = _nsCountPending(relayId);
|
|
585
|
+
if (pending >= _nsMaxPendingPerRelay)
|
|
586
|
+
throw new Error(
|
|
587
|
+
`max pending nostr events per relay (${_nsMaxPendingPerRelay}) reached for ${relayId}`,
|
|
588
|
+
);
|
|
589
|
+
const now = Date.now();
|
|
590
|
+
const e = {
|
|
591
|
+
id,
|
|
592
|
+
relayId,
|
|
593
|
+
kind: typeof kind === "number" ? kind : 1,
|
|
594
|
+
status: NOSTR_EVENT_LIFECYCLE_V2.QUEUED,
|
|
595
|
+
createdAt: now,
|
|
596
|
+
updatedAt: now,
|
|
597
|
+
startedAt: null,
|
|
598
|
+
settledAt: null,
|
|
599
|
+
metadata: { ...(metadata || {}) },
|
|
600
|
+
};
|
|
601
|
+
_nsEvents.set(id, e);
|
|
602
|
+
return { ...e, metadata: { ...e.metadata } };
|
|
603
|
+
}
|
|
604
|
+
function _nsCheckE(from, to) {
|
|
605
|
+
const a = _nsEventTrans.get(from);
|
|
606
|
+
if (!a || !a.has(to))
|
|
607
|
+
throw new Error(`invalid nostr event transition ${from} → ${to}`);
|
|
608
|
+
}
|
|
609
|
+
export function startNostrEventV2(id) {
|
|
610
|
+
const e = _nsEvents.get(id);
|
|
611
|
+
if (!e) throw new Error(`nostr event ${id} not found`);
|
|
612
|
+
_nsCheckE(e.status, NOSTR_EVENT_LIFECYCLE_V2.PUBLISHING);
|
|
613
|
+
const now = Date.now();
|
|
614
|
+
e.status = NOSTR_EVENT_LIFECYCLE_V2.PUBLISHING;
|
|
615
|
+
e.updatedAt = now;
|
|
616
|
+
if (!e.startedAt) e.startedAt = now;
|
|
617
|
+
return { ...e, metadata: { ...e.metadata } };
|
|
618
|
+
}
|
|
619
|
+
export function publishNostrEventV2(id) {
|
|
620
|
+
const e = _nsEvents.get(id);
|
|
621
|
+
if (!e) throw new Error(`nostr event ${id} not found`);
|
|
622
|
+
_nsCheckE(e.status, NOSTR_EVENT_LIFECYCLE_V2.PUBLISHED);
|
|
623
|
+
const now = Date.now();
|
|
624
|
+
e.status = NOSTR_EVENT_LIFECYCLE_V2.PUBLISHED;
|
|
625
|
+
e.updatedAt = now;
|
|
626
|
+
if (!e.settledAt) e.settledAt = now;
|
|
627
|
+
return { ...e, metadata: { ...e.metadata } };
|
|
628
|
+
}
|
|
629
|
+
export function failNostrEventV2(id, reason) {
|
|
630
|
+
const e = _nsEvents.get(id);
|
|
631
|
+
if (!e) throw new Error(`nostr event ${id} not found`);
|
|
632
|
+
_nsCheckE(e.status, NOSTR_EVENT_LIFECYCLE_V2.FAILED);
|
|
633
|
+
const now = Date.now();
|
|
634
|
+
e.status = NOSTR_EVENT_LIFECYCLE_V2.FAILED;
|
|
635
|
+
e.updatedAt = now;
|
|
636
|
+
if (!e.settledAt) e.settledAt = now;
|
|
637
|
+
if (reason) e.metadata.failReason = String(reason);
|
|
638
|
+
return { ...e, metadata: { ...e.metadata } };
|
|
639
|
+
}
|
|
640
|
+
export function cancelNostrEventV2(id, reason) {
|
|
641
|
+
const e = _nsEvents.get(id);
|
|
642
|
+
if (!e) throw new Error(`nostr event ${id} not found`);
|
|
643
|
+
_nsCheckE(e.status, NOSTR_EVENT_LIFECYCLE_V2.CANCELLED);
|
|
644
|
+
const now = Date.now();
|
|
645
|
+
e.status = NOSTR_EVENT_LIFECYCLE_V2.CANCELLED;
|
|
646
|
+
e.updatedAt = now;
|
|
647
|
+
if (!e.settledAt) e.settledAt = now;
|
|
648
|
+
if (reason) e.metadata.cancelReason = String(reason);
|
|
649
|
+
return { ...e, metadata: { ...e.metadata } };
|
|
650
|
+
}
|
|
651
|
+
export function getNostrEventV2(id) {
|
|
652
|
+
const e = _nsEvents.get(id);
|
|
653
|
+
if (!e) return null;
|
|
654
|
+
return { ...e, metadata: { ...e.metadata } };
|
|
655
|
+
}
|
|
656
|
+
export function listNostrEventsV2() {
|
|
657
|
+
return [..._nsEvents.values()].map((e) => ({
|
|
658
|
+
...e,
|
|
659
|
+
metadata: { ...e.metadata },
|
|
660
|
+
}));
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export function autoOfflineIdleNostrRelaysV2({ now } = {}) {
|
|
664
|
+
const t = now ?? Date.now();
|
|
665
|
+
const flipped = [];
|
|
666
|
+
for (const r of _nsRelays.values())
|
|
667
|
+
if (
|
|
668
|
+
r.status === NOSTR_RELAY_MATURITY_V2.ACTIVE &&
|
|
669
|
+
t - r.lastTouchedAt >= _nsRelayIdleMs
|
|
670
|
+
) {
|
|
671
|
+
r.status = NOSTR_RELAY_MATURITY_V2.OFFLINE;
|
|
672
|
+
r.updatedAt = t;
|
|
673
|
+
flipped.push(r.id);
|
|
674
|
+
}
|
|
675
|
+
return { flipped, count: flipped.length };
|
|
676
|
+
}
|
|
677
|
+
export function autoFailStuckNostrEventsV2({ now } = {}) {
|
|
678
|
+
const t = now ?? Date.now();
|
|
679
|
+
const flipped = [];
|
|
680
|
+
for (const e of _nsEvents.values())
|
|
681
|
+
if (
|
|
682
|
+
e.status === NOSTR_EVENT_LIFECYCLE_V2.PUBLISHING &&
|
|
683
|
+
e.startedAt != null &&
|
|
684
|
+
t - e.startedAt >= _nsEventStuckMs
|
|
685
|
+
) {
|
|
686
|
+
e.status = NOSTR_EVENT_LIFECYCLE_V2.FAILED;
|
|
687
|
+
e.updatedAt = t;
|
|
688
|
+
if (!e.settledAt) e.settledAt = t;
|
|
689
|
+
e.metadata.failReason = "auto-fail-stuck";
|
|
690
|
+
flipped.push(e.id);
|
|
691
|
+
}
|
|
692
|
+
return { flipped, count: flipped.length };
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
export function getNostrBridgeStatsV2() {
|
|
696
|
+
const relaysByStatus = {};
|
|
697
|
+
for (const s of Object.values(NOSTR_RELAY_MATURITY_V2)) relaysByStatus[s] = 0;
|
|
698
|
+
for (const r of _nsRelays.values()) relaysByStatus[r.status]++;
|
|
699
|
+
const eventsByStatus = {};
|
|
700
|
+
for (const s of Object.values(NOSTR_EVENT_LIFECYCLE_V2))
|
|
701
|
+
eventsByStatus[s] = 0;
|
|
702
|
+
for (const e of _nsEvents.values()) eventsByStatus[e.status]++;
|
|
703
|
+
return {
|
|
704
|
+
totalRelaysV2: _nsRelays.size,
|
|
705
|
+
totalEventsV2: _nsEvents.size,
|
|
706
|
+
maxActiveNostrRelaysPerOwner: _nsMaxActivePerOwner,
|
|
707
|
+
maxPendingNostrEventsPerRelay: _nsMaxPendingPerRelay,
|
|
708
|
+
nostrRelayIdleMs: _nsRelayIdleMs,
|
|
709
|
+
nostrEventStuckMs: _nsEventStuckMs,
|
|
710
|
+
relaysByStatus,
|
|
711
|
+
eventsByStatus,
|
|
712
|
+
};
|
|
713
|
+
}
|