@senpi/runtime 1.1.0-dev.runtime-phase-2.20260527113015 → 1.1.1-dev.runtime-phase-2.20260604073249
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/actions/close-position/close-position.action.d.ts.map +1 -1
- package/dist/actions/close-position/close-position.action.js +19 -1
- package/dist/actions/close-position/close-position.action.js.map +1 -1
- package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
- package/dist/actions/open-position/open-position.action.js +19 -0
- package/dist/actions/open-position/open-position.action.js.map +1 -1
- package/dist/actions/position-tracker/position-tracker.action.d.ts +6 -0
- package/dist/actions/position-tracker/position-tracker.action.d.ts.map +1 -1
- package/dist/actions/position-tracker/position-tracker.action.js +35 -0
- package/dist/actions/position-tracker/position-tracker.action.js.map +1 -1
- package/dist/cli/guide-commands.d.ts.map +1 -1
- package/dist/cli/guide-commands.js +8 -4
- package/dist/cli/guide-commands.js.map +1 -1
- package/dist/dsl/engine-client/config-mapping.d.ts +5 -0
- package/dist/dsl/engine-client/config-mapping.d.ts.map +1 -1
- package/dist/dsl/engine-client/config-mapping.js +14 -2
- package/dist/dsl/engine-client/config-mapping.js.map +1 -1
- package/dist/dsl/engine-client/event-mapping.d.ts +2 -0
- package/dist/dsl/engine-client/event-mapping.d.ts.map +1 -1
- package/dist/dsl/engine-client/event-mapping.js +3 -0
- package/dist/dsl/engine-client/event-mapping.js.map +1 -1
- package/dist/dsl/events/build-closed-event.d.ts.map +1 -1
- package/dist/dsl/events/build-closed-event.js +1 -0
- package/dist/dsl/events/build-closed-event.js.map +1 -1
- package/dist/dsl/events/guards.d.ts.map +1 -1
- package/dist/dsl/events/guards.js +13 -0
- package/dist/dsl/events/guards.js.map +1 -1
- package/dist/dsl/events/handlers.d.ts.map +1 -1
- package/dist/dsl/events/handlers.js +4 -0
- package/dist/dsl/events/handlers.js.map +1 -1
- package/dist/dsl/events/initial-state.d.ts.map +1 -1
- package/dist/dsl/events/initial-state.js +4 -1
- package/dist/dsl/events/initial-state.js.map +1 -1
- package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
- package/dist/dsl/monitor/process-one-position.js +31 -1
- package/dist/dsl/monitor/process-one-position.js.map +1 -1
- package/dist/runtime/create-runtime-context.d.ts +2 -0
- package/dist/runtime/create-runtime-context.d.ts.map +1 -1
- package/dist/runtime/create-runtime-context.js +1 -0
- package/dist/runtime/create-runtime-context.js.map +1 -1
- package/dist/runtime/runtime.d.ts +7 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +29 -1
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/senpi/client.js +1 -0
- package/dist/senpi/client.js.map +1 -1
- package/dist/senpi/types.d.ts +5 -1
- package/dist/senpi/types.d.ts.map +1 -1
- package/dist/state/state-manager.d.ts.map +1 -1
- package/dist/state/state-manager.js +5 -0
- package/dist/state/state-manager.js.map +1 -1
- package/dist/tracking/build-rehydrate-items.d.ts +14 -0
- package/dist/tracking/build-rehydrate-items.d.ts.map +1 -0
- package/dist/tracking/build-rehydrate-items.js +30 -0
- package/dist/tracking/build-rehydrate-items.js.map +1 -0
- package/dist/tracking/index.d.ts +4 -0
- package/dist/tracking/index.d.ts.map +1 -1
- package/dist/tracking/index.js +3 -0
- package/dist/tracking/index.js.map +1 -1
- package/dist/tracking/pending-open-store.d.ts +19 -0
- package/dist/tracking/pending-open-store.d.ts.map +1 -0
- package/dist/tracking/pending-open-store.js +27 -0
- package/dist/tracking/pending-open-store.js.map +1 -0
- package/dist/tracking/position-id-registry.d.ts +91 -0
- package/dist/tracking/position-id-registry.d.ts.map +1 -0
- package/dist/tracking/position-id-registry.js +149 -0
- package/dist/tracking/position-id-registry.js.map +1 -0
- package/dist/tracking/spans/plugin-span-tracker.d.ts.map +1 -1
- package/dist/tracking/spans/plugin-span-tracker.js +18 -0
- package/dist/tracking/spans/plugin-span-tracker.js.map +1 -1
- package/dist/tracking/spans/redact-pii.d.ts +115 -0
- package/dist/tracking/spans/redact-pii.d.ts.map +1 -0
- package/dist/tracking/spans/redact-pii.js +464 -0
- package/dist/tracking/spans/redact-pii.js.map +1 -0
- package/dist/tracking/spans/span-transport.d.ts +19 -0
- package/dist/tracking/spans/span-transport.d.ts.map +1 -1
- package/dist/tracking/spans/span-transport.js +28 -2
- package/dist/tracking/spans/span-transport.js.map +1 -1
- package/dist/tracking/tracker.d.ts +5 -0
- package/dist/tracking/tracker.d.ts.map +1 -1
- package/dist/tracking/tracker.js +4 -0
- package/dist/tracking/tracker.js.map +1 -1
- package/dist/tracking/tracking-handler.d.ts.map +1 -1
- package/dist/tracking/tracking-handler.js +47 -0
- package/dist/tracking/tracking-handler.js.map +1 -1
- package/dist/tracking/types.d.ts +12 -0
- package/dist/tracking/types.d.ts.map +1 -1
- package/dist/types/dsl/index.d.ts +44 -0
- package/dist/types/dsl/index.d.ts.map +1 -1
- package/dist/types/runtime.d.ts +6 -0
- package/dist/types/runtime.d.ts.map +1 -1
- package/openclaw.plugin.json +18 -5
- package/package.json +3 -1
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII + secret redaction for span payloads.
|
|
3
|
+
*
|
|
4
|
+
* Walks the `data` field of each span and replaces matches in string values
|
|
5
|
+
* before the batch hits the wire. Runs at flush time (async) — the underlying
|
|
6
|
+
* redactor is async, and the producer is fire-and-forget, so we pay the
|
|
7
|
+
* latency on the network-bound path rather than on the caller's enqueue call.
|
|
8
|
+
*
|
|
9
|
+
* Scope (see createOpenRedactionAdapter): emails, phones (US, international,
|
|
10
|
+
* India, China, South Korea, Japan, UK mobile, Brazil), ~28 vendor API keys
|
|
11
|
+
* / tokens (AWS, GitHub, Stripe, OpenAI, etc.), EVM private keys, Anthropic
|
|
12
|
+
* `sk-ant-*` keys, generic `sk-*` keys, and BIP39 mnemonic phrases.
|
|
13
|
+
*
|
|
14
|
+
* Integration point: BatchingSpanTransport.flush() applies this to every
|
|
15
|
+
* span in the batch before JSON.stringify. Only `span.data` is walked;
|
|
16
|
+
* top-level columns (`address`, `correlationId`, etc.) are non-PII identifiers
|
|
17
|
+
* and stay as-is.
|
|
18
|
+
*
|
|
19
|
+
* Always on — the plugin initializes a default redactor at startup.
|
|
20
|
+
*/
|
|
21
|
+
import { createLogger } from "../../utils/logger.js";
|
|
22
|
+
const logger = createLogger("[senpi-core][redact-pii]");
|
|
23
|
+
function isPlainObject(value) {
|
|
24
|
+
if (value === null || typeof value !== "object")
|
|
25
|
+
return false;
|
|
26
|
+
const proto = Object.getPrototypeOf(value);
|
|
27
|
+
return proto === Object.prototype || proto === null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Walks a JSON-shaped value. Strings are run through the redactor; arrays
|
|
31
|
+
* and plain objects are recursed; everything else (number, boolean, null,
|
|
32
|
+
* non-plain objects) is returned unchanged. Preserves reference identity
|
|
33
|
+
* when nothing changes — useful for short-circuit downstream comparisons.
|
|
34
|
+
*/
|
|
35
|
+
export async function redactStringsDeep(value, redactor) {
|
|
36
|
+
if (typeof value === "string") {
|
|
37
|
+
if (value.length === 0)
|
|
38
|
+
return value;
|
|
39
|
+
try {
|
|
40
|
+
return await redactor.redact(value);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
logger.warn("redactor.redact threw; passing through original", {
|
|
44
|
+
err: err instanceof Error ? err.message : String(err),
|
|
45
|
+
preview: value.slice(0, 64),
|
|
46
|
+
});
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(value)) {
|
|
51
|
+
const next = await Promise.all(value.map((item) => redactStringsDeep(item, redactor)));
|
|
52
|
+
return next.some((v, i) => v !== value[i]) ? next : value;
|
|
53
|
+
}
|
|
54
|
+
if (isPlainObject(value)) {
|
|
55
|
+
const entries = await Promise.all(Object.entries(value).map(async ([k, v]) => [k, await redactStringsDeep(v, redactor)]));
|
|
56
|
+
let changed = false;
|
|
57
|
+
const out = {};
|
|
58
|
+
for (const [k, v] of entries) {
|
|
59
|
+
out[k] = v;
|
|
60
|
+
if (v !== value[k])
|
|
61
|
+
changed = true;
|
|
62
|
+
}
|
|
63
|
+
return changed ? out : value;
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Redact PII inside `span.data` only. Top-level structural fields (address,
|
|
69
|
+
* correlationId, runId, etc.) are non-PII identifiers and skipped.
|
|
70
|
+
*
|
|
71
|
+
* Returns the same span if nothing changed (avoids object allocation when no
|
|
72
|
+
* PII was found).
|
|
73
|
+
*/
|
|
74
|
+
export async function redactSpanData(span, redactor) {
|
|
75
|
+
if (!span.data || typeof span.data !== "object")
|
|
76
|
+
return span;
|
|
77
|
+
const next = await redactStringsDeep(span.data, redactor);
|
|
78
|
+
if (next === span.data)
|
|
79
|
+
return span;
|
|
80
|
+
return { ...span, data: next };
|
|
81
|
+
}
|
|
82
|
+
// ─── Default redactor lifecycle ────────────────────────────────────────────
|
|
83
|
+
//
|
|
84
|
+
// The runtime registers a default redactor at startup when the feature flag is
|
|
85
|
+
// on; transports look it up via getDefaultPiiRedactor(). Tests can override.
|
|
86
|
+
let defaultRedactor = null;
|
|
87
|
+
export function setDefaultPiiRedactor(r) {
|
|
88
|
+
defaultRedactor = r;
|
|
89
|
+
}
|
|
90
|
+
export function getDefaultPiiRedactor() {
|
|
91
|
+
return defaultRedactor;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Built-in OpenRedaction pattern types we allowlist for span redaction.
|
|
95
|
+
*
|
|
96
|
+
* Scoped via the `patterns` whitelist (not categories) because category
|
|
97
|
+
* activation sweeps in patterns that false-positive on our domain content:
|
|
98
|
+
*
|
|
99
|
+
* - `categories: ['personal']` activates NAME patterns that redact
|
|
100
|
+
* strategy/asset names ("Setup Bison strategy" → "[NAME_xxx] strategy",
|
|
101
|
+
* "long position on ETH" → "long position on [NAME_xxx]").
|
|
102
|
+
* - `categories: ['financial']` activates ETH_ADDR which redacts wallet
|
|
103
|
+
* addresses inside `data.input.strategyWalletAddress`, breaking joins.
|
|
104
|
+
*
|
|
105
|
+
* Phone patterns from upstream are NOT used — we ship our own custom
|
|
106
|
+
* patterns instead. Specifically:
|
|
107
|
+
* - `PHONE_UK` — over-permissive: regex matches any 11-12 digit run with
|
|
108
|
+
* no separators, so the trailing 12-digit segment of a UUID (e.g.,
|
|
109
|
+
* `...446655440000`) is misclassified as a UK phone.
|
|
110
|
+
* - `PHONE_US` (upstream) — matches bare 10-digit numbers, which collides
|
|
111
|
+
* with 10-digit Unix timestamps (`1716855600`).
|
|
112
|
+
* - `PHONE_INTERNATIONAL` (upstream) — fine in isolation, but with
|
|
113
|
+
* `enableContextAnalysis: false` the library still suppresses matches
|
|
114
|
+
* in some contexts via undocumented filters; replacing it with our own
|
|
115
|
+
* custom version gives us deterministic behavior.
|
|
116
|
+
* - `TURKEY_ID` — personal national ID, not a credential.
|
|
117
|
+
*/
|
|
118
|
+
const ALLOWLISTED_PATTERN_TYPES = [
|
|
119
|
+
// Contact PII (phones come from custom patterns below)
|
|
120
|
+
"EMAIL",
|
|
121
|
+
// Cloud / vendor API keys + tokens
|
|
122
|
+
"AWS_ACCESS_KEY",
|
|
123
|
+
"AWS_SECRET_KEY",
|
|
124
|
+
"AZURE_STORAGE_KEY",
|
|
125
|
+
"BEARER_TOKEN",
|
|
126
|
+
"CARD_AUTH_CODE",
|
|
127
|
+
"DOCKER_AUTH",
|
|
128
|
+
"FIREBASE_API_KEY",
|
|
129
|
+
"GENERIC_API_KEY",
|
|
130
|
+
"GENERIC_SECRET",
|
|
131
|
+
"GITHUB_TOKEN",
|
|
132
|
+
"GOOGLE_API_KEY",
|
|
133
|
+
"HEROKU_API_KEY",
|
|
134
|
+
"JWT_TOKEN",
|
|
135
|
+
"KUBERNETES_SECRET",
|
|
136
|
+
"MAILGUN_API_KEY",
|
|
137
|
+
"NPM_TOKEN",
|
|
138
|
+
"OAUTH_CLIENT_SECRET",
|
|
139
|
+
"OAUTH_TOKEN",
|
|
140
|
+
"OPENAI_API_KEY",
|
|
141
|
+
"PRIVATE_KEY",
|
|
142
|
+
"PYPI_TOKEN",
|
|
143
|
+
"SENDGRID_API_KEY",
|
|
144
|
+
"SLACK_TOKEN",
|
|
145
|
+
"SSH_PRIVATE_KEY",
|
|
146
|
+
"STRIPE_API_KEY",
|
|
147
|
+
"TWILIO_API_KEY",
|
|
148
|
+
"URL_WITH_AUTH",
|
|
149
|
+
];
|
|
150
|
+
/**
|
|
151
|
+
* Phone patterns are entirely custom because upstream is unreliable: PHONE_UK
|
|
152
|
+
* matches bare 11–12 digit runs (UUID trailing segments), upstream PHONE_US
|
|
153
|
+
* matches bare 10-digit runs (Unix-seconds timestamps), and the library
|
|
154
|
+
* doesn't ship India / China / Korea / Japan / Brazil patterns at all.
|
|
155
|
+
*
|
|
156
|
+
* Design rule: every pattern requires either an explicit country code OR a
|
|
157
|
+
* country-specific mobile prefix AND/OR separators between groups. Pure
|
|
158
|
+
* numeric IDs (timestamps, span IDs, counters, UUID segments) don't satisfy
|
|
159
|
+
* any of those constraints, so they survive untouched.
|
|
160
|
+
*/
|
|
161
|
+
const PHONE_PATTERNS = [
|
|
162
|
+
{
|
|
163
|
+
type: "PHONE_INTL",
|
|
164
|
+
regex: /\+\d[\d\s.\-()]{8,20}\d/g,
|
|
165
|
+
priority: 90,
|
|
166
|
+
placeholder: "[PHONE_INTL_{n}]",
|
|
167
|
+
severity: "high",
|
|
168
|
+
description: "International phone with explicit + country-code prefix.",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
type: "PHONE_US",
|
|
172
|
+
// `(?<!\d)` / `(?!\d)` instead of `\b` so `(415) 555-1234` matches at
|
|
173
|
+
// "space-paren" (where \b fails) and bare 10-digit timestamps don't.
|
|
174
|
+
regex: /(?<!\d)(?:\+1[\s.-])?(?:\(\d{3}\)[\s.-]?|\d{3}[\s.-])\d{3}[\s.-]\d{4}(?!\d)/g,
|
|
175
|
+
priority: 88,
|
|
176
|
+
placeholder: "[PHONE_US_{n}]",
|
|
177
|
+
severity: "high",
|
|
178
|
+
description: "US phone with at least one separator (rejects bare 10-digit timestamps).",
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
type: "PHONE_IN",
|
|
182
|
+
regex: /\b(?:\+?91[\s.-]?)?[6-9]\d{4}[\s.-]?\d{5}\b/g,
|
|
183
|
+
priority: 85,
|
|
184
|
+
placeholder: "[PHONE_IN_{n}]",
|
|
185
|
+
severity: "high",
|
|
186
|
+
description: "Indian mobile (10 digits starting 6-9; optional +91/91 prefix).",
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
type: "PHONE_CN",
|
|
190
|
+
regex: /\b(?:\+?86[\s.-]?)?1[3-9]\d[\s.-]?\d{4}[\s.-]?\d{4}\b/g,
|
|
191
|
+
priority: 85,
|
|
192
|
+
placeholder: "[PHONE_CN_{n}]",
|
|
193
|
+
severity: "high",
|
|
194
|
+
description: "Chinese mobile (11 digits starting 1[3-9]; optional +86/86 prefix).",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
type: "PHONE_KR",
|
|
198
|
+
regex: /\b(?:\+?82[\s.-]?)?0?1[01679][\s.-]\d{3,4}[\s.-]\d{4}\b/g,
|
|
199
|
+
priority: 85,
|
|
200
|
+
placeholder: "[PHONE_KR_{n}]",
|
|
201
|
+
severity: "high",
|
|
202
|
+
description: "Korean mobile (010/011/016-019 + separators; optional +82 prefix).",
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: "PHONE_JP",
|
|
206
|
+
regex: /\b(?:\+?81[\s.-]?)?0?[789]0[\s.-]\d{4}[\s.-]\d{4}\b/g,
|
|
207
|
+
priority: 85,
|
|
208
|
+
placeholder: "[PHONE_JP_{n}]",
|
|
209
|
+
severity: "high",
|
|
210
|
+
description: "Japanese mobile (070/080/090 + separators; optional +81 prefix).",
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
type: "PHONE_UK_MOBILE",
|
|
214
|
+
regex: /\b(?:\+?44[\s.-]?|0)7\d{3}[\s.-]?\d{3}[\s.-]?\d{3}\b/g,
|
|
215
|
+
priority: 85,
|
|
216
|
+
placeholder: "[PHONE_UK_{n}]",
|
|
217
|
+
severity: "high",
|
|
218
|
+
description: "UK mobile (07xxx; optional +44 prefix).",
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
type: "PHONE_BR",
|
|
222
|
+
regex: /\b\+?55[\s.-]?\(?\d{2}\)?[\s.-]?9\d{4}[\s.-]?\d{4}\b/g,
|
|
223
|
+
priority: 85,
|
|
224
|
+
placeholder: "[PHONE_BR_{n}]",
|
|
225
|
+
severity: "high",
|
|
226
|
+
description: "Brazilian mobile (+55 required + DDD + 9-digit number).",
|
|
227
|
+
},
|
|
228
|
+
];
|
|
229
|
+
/**
|
|
230
|
+
* Lazy-load the BIP39 English wordlist into a Set for O(1) lookup during
|
|
231
|
+
* mnemonic validation. Cached after first call; the `bip39` package is only
|
|
232
|
+
* pulled in when PII redaction is enabled, keeping cold-start cost off the
|
|
233
|
+
* non-redacting build.
|
|
234
|
+
*/
|
|
235
|
+
let bip39WordSet = null;
|
|
236
|
+
async function getBip39WordSet() {
|
|
237
|
+
if (bip39WordSet)
|
|
238
|
+
return bip39WordSet;
|
|
239
|
+
const mod = (await import("bip39"));
|
|
240
|
+
const wordlists = mod.wordlists ?? mod.default?.wordlists;
|
|
241
|
+
if (!wordlists?.english) {
|
|
242
|
+
throw new Error("bip39: english wordlist not available");
|
|
243
|
+
}
|
|
244
|
+
bip39WordSet = new Set(wordlists.english);
|
|
245
|
+
return bip39WordSet;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Build the custom-pattern set we layer on top of OpenRedaction's built-ins.
|
|
249
|
+
* These cover credentials common in our agent traffic that the upstream
|
|
250
|
+
* library either misses entirely or whose built-in pattern doesn't fire
|
|
251
|
+
* without context:
|
|
252
|
+
*
|
|
253
|
+
* - CRYPTO_PRIVKEY_HEX: `0x` + 64 hex = EVM private key. Also matches
|
|
254
|
+
* SHA-256 hashes; over-redaction is acceptable since hashes inside
|
|
255
|
+
* `data` are rare and not load-bearing.
|
|
256
|
+
* - ANTHROPIC_API_KEY: `sk-ant-(api|admin)NN-...`; upstream has no
|
|
257
|
+
* specific Anthropic pattern.
|
|
258
|
+
* - SK_API_KEY: catch-all for OpenAI / OpenRouter / similar `sk-` prefixed
|
|
259
|
+
* keys; upstream OPENAI_API_KEY didn't fire on real `sk-proj-*` and
|
|
260
|
+
* `sk-svcacct-*` formats in smoke tests.
|
|
261
|
+
*
|
|
262
|
+
* NOTE: Mnemonic detection is NOT in this list. The earlier regex-with-
|
|
263
|
+
* validator approach was greedy and silently missed mnemonics surrounded by
|
|
264
|
+
* other lowercase words (e.g. "my secret is <12 BIP39 words> so keep safe"
|
|
265
|
+
* → regex captures the full 17-word run, validator rejects on count/words,
|
|
266
|
+
* library moves on without retrying a shorter window). Mnemonics are now
|
|
267
|
+
* handled by `redactMnemonicsPreRedaction` ahead of the OpenRedaction pass.
|
|
268
|
+
*/
|
|
269
|
+
async function buildCustomPatterns() {
|
|
270
|
+
return [
|
|
271
|
+
...PHONE_PATTERNS,
|
|
272
|
+
{
|
|
273
|
+
type: "CRYPTO_PRIVKEY_HEX",
|
|
274
|
+
regex: /\b0x[0-9a-fA-F]{64}\b/g,
|
|
275
|
+
priority: 110,
|
|
276
|
+
placeholder: "[CRYPTO_PRIVKEY_{n}]",
|
|
277
|
+
severity: "critical",
|
|
278
|
+
description: "EVM private key (0x + 32-byte hex). Matches SHA-256 hashes too — accepted as collateral.",
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
type: "ANTHROPIC_API_KEY",
|
|
282
|
+
regex: /\bsk-ant-(?:api|admin)\d+-[A-Za-z0-9_\-]{40,}\b/g,
|
|
283
|
+
priority: 110,
|
|
284
|
+
placeholder: "[ANTHROPIC_KEY_{n}]",
|
|
285
|
+
severity: "critical",
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
type: "SK_API_KEY",
|
|
289
|
+
regex: /\bsk-(?:proj|live|test|or|svcacct)?[-_]?[A-Za-z0-9_\-]{32,}\b/g,
|
|
290
|
+
priority: 100,
|
|
291
|
+
placeholder: "[SK_KEY_{n}]",
|
|
292
|
+
severity: "critical",
|
|
293
|
+
description: "Catch-all for sk-* API keys (OpenAI, OpenRouter, etc.).",
|
|
294
|
+
},
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Find BIP39-mnemonic spans in `text` using a true sliding window — not
|
|
299
|
+
* a greedy regex with a post-hoc validator.
|
|
300
|
+
*
|
|
301
|
+
* Why this and not a regex+validator:
|
|
302
|
+
* - OpenRedaction calls the validator on whatever the regex captured. JS
|
|
303
|
+
* regex matching is left-to-right with no backtracking across `lastIndex`
|
|
304
|
+
* advances; once a (greedy) match is rejected, the engine moves past it
|
|
305
|
+
* entirely. So a 17-word lowercase run like "my secret is <12 BIP39>
|
|
306
|
+
* so keep safe" gets captured whole, fails validation on word count,
|
|
307
|
+
* and the engine doesn't retry the 12-word window starting 3 tokens in.
|
|
308
|
+
*
|
|
309
|
+
* Algorithm:
|
|
310
|
+
* 1. Tokenize lowercase-only words and their offsets (skips capitalized
|
|
311
|
+
* words and punctuation — real mnemonics from wallet exports are
|
|
312
|
+
* always all-lowercase space-separated).
|
|
313
|
+
* 2. Walk left to right. At each token position, try valid mnemonic
|
|
314
|
+
* counts largest-first (24, 21, 18, 15, 12) so a 24-word phrase
|
|
315
|
+
* inside a longer prose run isn't missed by a premature 12-match.
|
|
316
|
+
* 3. A window is valid only when every word is BIP39 AND the gap between
|
|
317
|
+
* consecutive tokens in the source is whitespace-only (rejects forms
|
|
318
|
+
* with commas or other punctuation between words, which real wallet
|
|
319
|
+
* exports don't use).
|
|
320
|
+
* 4. On match, record the source span and advance past it; otherwise step
|
|
321
|
+
* forward one token.
|
|
322
|
+
*/
|
|
323
|
+
export function findMnemonicSpans(text, bip39) {
|
|
324
|
+
const tokens = [];
|
|
325
|
+
const wordRe = /[a-z]+/g;
|
|
326
|
+
let m;
|
|
327
|
+
while ((m = wordRe.exec(text)) !== null) {
|
|
328
|
+
tokens.push({ word: m[0], start: m.index, end: m.index + m[0].length });
|
|
329
|
+
}
|
|
330
|
+
const validCounts = [24, 21, 18, 15, 12];
|
|
331
|
+
const spans = [];
|
|
332
|
+
let i = 0;
|
|
333
|
+
while (i < tokens.length) {
|
|
334
|
+
let matched = false;
|
|
335
|
+
for (const count of validCounts) {
|
|
336
|
+
if (i + count > tokens.length)
|
|
337
|
+
continue;
|
|
338
|
+
let valid = true;
|
|
339
|
+
for (let j = 0; j < count; j++) {
|
|
340
|
+
if (!bip39.has(tokens[i + j].word)) {
|
|
341
|
+
valid = false;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
if (j > 0) {
|
|
345
|
+
const gap = text.slice(tokens[i + j - 1].end, tokens[i + j].start);
|
|
346
|
+
if (!/^\s+$/.test(gap)) {
|
|
347
|
+
valid = false;
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (valid) {
|
|
353
|
+
spans.push({
|
|
354
|
+
start: tokens[i].start,
|
|
355
|
+
end: tokens[i + count - 1].end,
|
|
356
|
+
});
|
|
357
|
+
i += count;
|
|
358
|
+
matched = true;
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (!matched)
|
|
363
|
+
i++;
|
|
364
|
+
}
|
|
365
|
+
return spans;
|
|
366
|
+
}
|
|
367
|
+
let mnemonicCounter = 0;
|
|
368
|
+
function redactMnemonicSpans(text, spans) {
|
|
369
|
+
if (spans.length === 0)
|
|
370
|
+
return text;
|
|
371
|
+
let out = "";
|
|
372
|
+
let cursor = 0;
|
|
373
|
+
for (const span of spans) {
|
|
374
|
+
out += text.slice(cursor, span.start);
|
|
375
|
+
// Bracketed uppercase placeholder ensures the result won't re-tokenize
|
|
376
|
+
// back into lowercase BIP39-shaped words on a second pass.
|
|
377
|
+
const suffix = String(mnemonicCounter++ % 10000).padStart(4, "0");
|
|
378
|
+
out += `[MNEMONIC_${suffix}]`;
|
|
379
|
+
cursor = span.end;
|
|
380
|
+
}
|
|
381
|
+
out += text.slice(cursor);
|
|
382
|
+
return out;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Pre-redact BIP39 mnemonics in `text` before handing the result to
|
|
386
|
+
* OpenRedaction. Returns the original string when no mnemonics are present
|
|
387
|
+
* (cheap path — only the tokenizer runs and finds nothing).
|
|
388
|
+
*/
|
|
389
|
+
export async function redactMnemonicsPreRedaction(text) {
|
|
390
|
+
const bip39 = await getBip39WordSet();
|
|
391
|
+
const spans = findMnemonicSpans(text, bip39);
|
|
392
|
+
return redactMnemonicSpans(text, spans);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Build an OpenRedaction-backed PiiRedactor.
|
|
396
|
+
*
|
|
397
|
+
* Detects:
|
|
398
|
+
* - Contact PII: emails.
|
|
399
|
+
* - Phones (all custom — upstream phone patterns are unreliable, see
|
|
400
|
+
* ALLOWLISTED_PATTERN_TYPES docstring): US, international (`+` prefix),
|
|
401
|
+
* India, China, South Korea, Japan, UK mobile, Brazil. Each requires
|
|
402
|
+
* either an explicit country code OR a country-specific mobile prefix
|
|
403
|
+
* plus separators, so bare numeric IDs (timestamps, span IDs, UUIDs)
|
|
404
|
+
* survive untouched.
|
|
405
|
+
* - Credentials (upstream): cloud / vendor API keys + tokens (AWS, Azure,
|
|
406
|
+
* GCP, GitHub, Slack, Stripe, OpenAI, Twilio, …), bearer + JWT tokens,
|
|
407
|
+
* OAuth secrets, generic API keys, SSH/PEM private keys, URLs with
|
|
408
|
+
* embedded auth.
|
|
409
|
+
* - Crypto secrets (custom patterns): EVM private keys (0x + 64 hex),
|
|
410
|
+
* Anthropic `sk-ant-*` keys, generic `sk-*` keys (OpenAI/OpenRouter).
|
|
411
|
+
* - BIP39 mnemonic phrases (out-of-band sliding-window pre-pass — see
|
|
412
|
+
* `redactMnemonicsPreRedaction`): 12/15/18/21/24 BIP39 words, found and
|
|
413
|
+
* redacted before the OpenRedaction pass so embedded phrases like
|
|
414
|
+
* "my key is <12 words> keep safe" are caught.
|
|
415
|
+
*
|
|
416
|
+
* Tuning:
|
|
417
|
+
* - `enableFalsePositiveFilter: false` — explicit; the library defaults
|
|
418
|
+
* this to truthy in practice and suppresses valid international-phone
|
|
419
|
+
* matches in some contexts.
|
|
420
|
+
* - `enableContextAnalysis: false` — saves CPU; context rules add
|
|
421
|
+
* latency and aren't load-bearing for the patterns we keep.
|
|
422
|
+
* - `enableCache: true` — chat history repeats; cache skips re-scan.
|
|
423
|
+
* - `confidenceThreshold: 0.5` — kept conservative; custom patterns score
|
|
424
|
+
* 1.0 so this only affects built-ins.
|
|
425
|
+
*
|
|
426
|
+
* Lazy-imports `openredaction` and `bip39` — both deps stay cold for builds
|
|
427
|
+
* / tests that don't enable redaction.
|
|
428
|
+
*/
|
|
429
|
+
export async function createOpenRedactionAdapter() {
|
|
430
|
+
const { OpenRedaction } = await import("openredaction");
|
|
431
|
+
const customPatterns = await buildCustomPatterns();
|
|
432
|
+
// Our local custom-pattern descriptor type is structurally compatible with
|
|
433
|
+
// the upstream PIIPattern. Cast at the options-object boundary so callers
|
|
434
|
+
// don't need a build-time dependency on the openredaction type.
|
|
435
|
+
const options = {
|
|
436
|
+
patterns: [...ALLOWLISTED_PATTERN_TYPES],
|
|
437
|
+
customPatterns,
|
|
438
|
+
enableContextAnalysis: false,
|
|
439
|
+
enableMultiPass: false,
|
|
440
|
+
enableCache: true,
|
|
441
|
+
cacheSize: 200,
|
|
442
|
+
// Despite the docs saying default is `false`, leaving this unset
|
|
443
|
+
// causes the library to suppress otherwise-valid phone matches in some
|
|
444
|
+
// contexts (e.g., `+44 20 7946 0958` after "ring me on"). Force off so
|
|
445
|
+
// our strict custom regex is the only thing deciding what gets redacted.
|
|
446
|
+
enableFalsePositiveFilter: false,
|
|
447
|
+
confidenceThreshold: 0.5,
|
|
448
|
+
};
|
|
449
|
+
const instance = new OpenRedaction(options);
|
|
450
|
+
// Warm the BIP39 word set so the first user-facing call doesn't pay the
|
|
451
|
+
// dynamic-import latency.
|
|
452
|
+
await getBip39WordSet();
|
|
453
|
+
return {
|
|
454
|
+
async redact(text) {
|
|
455
|
+
// Mnemonic pre-pass runs FIRST — its sliding-window detector can find
|
|
456
|
+
// mnemonics that OpenRedaction's regex-with-validator misses when the
|
|
457
|
+
// phrase is embedded in surrounding lowercase prose.
|
|
458
|
+
const preRedacted = await redactMnemonicsPreRedaction(text);
|
|
459
|
+
const result = await instance.detect(preRedacted);
|
|
460
|
+
return result.redacted;
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
//# sourceMappingURL=redact-pii.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact-pii.js","sourceRoot":"","sources":["../../../src/tracking/spans/redact-pii.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Mirrors src/tracking/transport.ts. Never throws — all errors caught and logged.
|
|
5
5
|
*/
|
|
6
6
|
import type { TrackingSpan, SpanTransport } from "./types.js";
|
|
7
|
+
import { type PiiRedactor } from "./redact-pii.js";
|
|
7
8
|
export interface BatchingSpanTransportOptions {
|
|
8
9
|
baseUrl: string;
|
|
9
10
|
apiKey: string;
|
|
@@ -12,6 +13,13 @@ export interface BatchingSpanTransportOptions {
|
|
|
12
13
|
maxBufferSize?: number;
|
|
13
14
|
/** Max serialized JSON bytes per batch (excluding HTTP envelope). */
|
|
14
15
|
maxBatchBytes?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Optional PII redactor. When set, every span's `data` is walked at flush
|
|
18
|
+
* time and string values are replaced with their redacted form before the
|
|
19
|
+
* batch is serialized. Pass `null`/omit to disable redaction at this
|
|
20
|
+
* transport (default lookup via `getDefaultPiiRedactor()`).
|
|
21
|
+
*/
|
|
22
|
+
piiRedactor?: PiiRedactor | null;
|
|
15
23
|
}
|
|
16
24
|
export declare class BatchingSpanTransport implements SpanTransport {
|
|
17
25
|
private buffer;
|
|
@@ -23,6 +31,17 @@ export declare class BatchingSpanTransport implements SpanTransport {
|
|
|
23
31
|
private readonly flushThreshold;
|
|
24
32
|
private readonly maxBufferSize;
|
|
25
33
|
private readonly maxBatchBytes;
|
|
34
|
+
/**
|
|
35
|
+
* Optional PII redactor override. When provided at construction, takes
|
|
36
|
+
* precedence over the process-wide default. When `undefined`, flush() falls
|
|
37
|
+
* back to `getDefaultPiiRedactor()` at flush time — handles the case where
|
|
38
|
+
* the default redactor is initialized asynchronously (dynamic import) and
|
|
39
|
+
* may not be ready when the transport is built.
|
|
40
|
+
*
|
|
41
|
+
* Pass `null` explicitly to disable redaction at this transport even if a
|
|
42
|
+
* default is registered (e.g., for tests or local dev).
|
|
43
|
+
*/
|
|
44
|
+
private readonly piiRedactorOverride;
|
|
26
45
|
constructor(options: BatchingSpanTransportOptions);
|
|
27
46
|
enqueue(span: TrackingSpan): void;
|
|
28
47
|
flush(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"span-transport.d.ts","sourceRoot":"","sources":["../../../src/tracking/spans/span-transport.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"span-transport.d.ts","sourceRoot":"","sources":["../../../src/tracking/spans/span-transport.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAW9D,OAAO,EACL,KAAK,WAAW,EAGjB,MAAM,iBAAiB,CAAC;AAkDzB,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAClC;AAED,qBAAa,qBAAsB,YAAW,aAAa;IACzD,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAiC;gBAEzD,OAAO,EAAE,4BAA4B;IAiBjD,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAW3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmEtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB/B,OAAO,CAAC,QAAQ;IAQhB;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;CAkBlB;AAcD,qBAAa,iBAAkB,YAAW,aAAa;IACrD,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IACtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAChC"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { SPANS_API_PATH, FLUSH_INTERVAL_MS, FLUSH_THRESHOLD, MAX_BUFFER_SIZE, MAX_BATCH_BYTES, MAX_SPAN_FIELD_BYTES, TRUNCATED_PREVIEW_BYTES, } from "./constants.js";
|
|
7
7
|
import { createLogger } from "../../utils/logger.js";
|
|
8
|
+
import { getDefaultPiiRedactor, redactSpanData, } from "./redact-pii.js";
|
|
8
9
|
const logger = createLogger("[senpi-core][span-transport]");
|
|
9
10
|
/**
|
|
10
11
|
* Replace any top-level `data` field whose serialized size exceeds
|
|
@@ -65,6 +66,17 @@ export class BatchingSpanTransport {
|
|
|
65
66
|
flushThreshold;
|
|
66
67
|
maxBufferSize;
|
|
67
68
|
maxBatchBytes;
|
|
69
|
+
/**
|
|
70
|
+
* Optional PII redactor override. When provided at construction, takes
|
|
71
|
+
* precedence over the process-wide default. When `undefined`, flush() falls
|
|
72
|
+
* back to `getDefaultPiiRedactor()` at flush time — handles the case where
|
|
73
|
+
* the default redactor is initialized asynchronously (dynamic import) and
|
|
74
|
+
* may not be ready when the transport is built.
|
|
75
|
+
*
|
|
76
|
+
* Pass `null` explicitly to disable redaction at this transport even if a
|
|
77
|
+
* default is registered (e.g., for tests or local dev).
|
|
78
|
+
*/
|
|
79
|
+
piiRedactorOverride;
|
|
68
80
|
constructor(options) {
|
|
69
81
|
this.url = `${options.baseUrl.replace(/\/+$/, "")}${SPANS_API_PATH}`;
|
|
70
82
|
this.apiKey = options.apiKey;
|
|
@@ -72,6 +84,7 @@ export class BatchingSpanTransport {
|
|
|
72
84
|
this.flushThreshold = options.flushThreshold ?? FLUSH_THRESHOLD;
|
|
73
85
|
this.maxBufferSize = options.maxBufferSize ?? MAX_BUFFER_SIZE;
|
|
74
86
|
this.maxBatchBytes = options.maxBatchBytes ?? MAX_BATCH_BYTES;
|
|
87
|
+
this.piiRedactorOverride = options.piiRedactor;
|
|
75
88
|
this.timer = setInterval(() => {
|
|
76
89
|
void this.flush();
|
|
77
90
|
}, this.flushIntervalMs);
|
|
@@ -94,13 +107,23 @@ export class BatchingSpanTransport {
|
|
|
94
107
|
this.flushing = true;
|
|
95
108
|
const batch = this.takeBatch();
|
|
96
109
|
try {
|
|
110
|
+
// PII redaction is applied right before serialization so it covers
|
|
111
|
+
// every emission path (hook + direct) at one chokepoint. Walks each
|
|
112
|
+
// span's `data` only; structural fields stay as-is. Override beats
|
|
113
|
+
// default; if both null/undefined, this is a no-op pass-through.
|
|
114
|
+
const redactor = this.piiRedactorOverride === undefined
|
|
115
|
+
? getDefaultPiiRedactor()
|
|
116
|
+
: this.piiRedactorOverride;
|
|
117
|
+
const wireBatch = redactor
|
|
118
|
+
? await Promise.all(batch.map((s) => redactSpanData(s, redactor)))
|
|
119
|
+
: batch;
|
|
97
120
|
const response = await fetch(this.url, {
|
|
98
121
|
method: "POST",
|
|
99
122
|
headers: {
|
|
100
123
|
"Content-Type": "application/json",
|
|
101
124
|
Authorization: `Bearer ${this.apiKey}`,
|
|
102
125
|
},
|
|
103
|
-
body: JSON.stringify({ spans:
|
|
126
|
+
body: JSON.stringify({ spans: wireBatch }),
|
|
104
127
|
signal: AbortSignal.timeout(15_000),
|
|
105
128
|
});
|
|
106
129
|
if (!response.ok) {
|
|
@@ -121,7 +144,10 @@ export class BatchingSpanTransport {
|
|
|
121
144
|
spanCount: batch.length,
|
|
122
145
|
body: body.slice(0, 500),
|
|
123
146
|
validationErrors,
|
|
124
|
-
|
|
147
|
+
// Log the redacted form — what we'd put on the wire — not the raw
|
|
148
|
+
// pre-redacted span, so warn logs don't leak PII that the
|
|
149
|
+
// redaction pass just removed from the payload.
|
|
150
|
+
sample: wireBatch[0],
|
|
125
151
|
});
|
|
126
152
|
// 413 (payload too large) and 400 (validation) are non-retryable —
|
|
127
153
|
// re-sending the same batch will fail the same way. Drop it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"span-transport.js","sourceRoot":"","sources":["../../../src/tracking/spans/span-transport.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"span-transport.js","sourceRoot":"","sources":["../../../src/tracking/spans/span-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* those are replaced here so batches are not rejected with HTTP 400.
|
|
9
9
|
*/
|
|
10
10
|
import type { TrackingTransport } from "./types.js";
|
|
11
|
+
import type { Cloids } from "./position-id-registry.js";
|
|
11
12
|
export interface CaptureOptions {
|
|
12
13
|
eventType: string;
|
|
13
14
|
category: string;
|
|
@@ -16,6 +17,10 @@ export interface CaptureOptions {
|
|
|
16
17
|
* From the bus (`__correlationId`); v4 values are sent as-is, otherwise a new v4 is used.
|
|
17
18
|
*/
|
|
18
19
|
correlationId?: string | null;
|
|
20
|
+
/** Cross-flow position.id from the bus (`__positionId`/`positionId`); empty when absent. */
|
|
21
|
+
positionId?: string | null;
|
|
22
|
+
/** Exchange-side client order ids from the bus (`__cloids`); empty object when absent. */
|
|
23
|
+
cloids?: Cloids | null;
|
|
19
24
|
data: Record<string, unknown>;
|
|
20
25
|
}
|
|
21
26
|
export declare class EventTracker {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/tracking/tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAiB,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/tracking/tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAiB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAsBxD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,4FAA4F;IAC5F,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAHd,SAAS,EAAE,iBAAiB,EAC5B,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM;IAGzC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IA8BhC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGhC"}
|