@capxul/observability 4.2.0 → 4.20.0-beta.2
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/README.md +14 -0
- package/dist/engineering.d.mts +12 -3
- package/dist/engineering.mjs +388 -55
- package/dist/index.d.mts +579 -5
- package/dist/index.mjs +404 -460
- package/dist/operations-sJPrehYY.mjs +748 -0
- package/package.json +2 -2
- package/dist/src-CWfRYsBI.mjs +0 -302
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capxul/observability",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.20.0-beta.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"effect": "4.0.0-
|
|
30
|
+
"effect": "4.0.0-rc.112"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@typescript/native": "npm:typescript@7.0.2",
|
package/dist/src-CWfRYsBI.mjs
DELETED
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
//#region ../errors/src/secret-material.ts
|
|
2
|
-
const CREDENTIAL_FIELDS = /* @__PURE__ */ new Set([
|
|
3
|
-
"password",
|
|
4
|
-
"passwd",
|
|
5
|
-
"pwd",
|
|
6
|
-
"pass",
|
|
7
|
-
"passphrase",
|
|
8
|
-
"currentpassword",
|
|
9
|
-
"newpassword",
|
|
10
|
-
"confirmpassword",
|
|
11
|
-
"passwordconfirmation",
|
|
12
|
-
"passwordhash",
|
|
13
|
-
"hashedpassword",
|
|
14
|
-
"pin",
|
|
15
|
-
"privatekey",
|
|
16
|
-
"walletprivatekey",
|
|
17
|
-
"secretkey",
|
|
18
|
-
"signingkey",
|
|
19
|
-
"signingsecret",
|
|
20
|
-
"seed",
|
|
21
|
-
"seedphrase",
|
|
22
|
-
"mnemonic",
|
|
23
|
-
"recoveryphrase",
|
|
24
|
-
"recovery",
|
|
25
|
-
"recoverycode",
|
|
26
|
-
"recoverycodes",
|
|
27
|
-
"keyshare",
|
|
28
|
-
"signingmaterial",
|
|
29
|
-
"recoverymaterial",
|
|
30
|
-
"privatekeybytes",
|
|
31
|
-
"signingprivatekey",
|
|
32
|
-
"encryptionkey",
|
|
33
|
-
"decryptionkey",
|
|
34
|
-
"authtoken",
|
|
35
|
-
"apitoken",
|
|
36
|
-
"bearertoken",
|
|
37
|
-
"oauthtoken",
|
|
38
|
-
"csrftoken",
|
|
39
|
-
"clientassertion",
|
|
40
|
-
"token",
|
|
41
|
-
"accesstoken",
|
|
42
|
-
"refreshtoken",
|
|
43
|
-
"idtoken",
|
|
44
|
-
"sessiontoken",
|
|
45
|
-
"session",
|
|
46
|
-
"sessionkey",
|
|
47
|
-
"sessionsecret",
|
|
48
|
-
"authsessionid",
|
|
49
|
-
"sessioncredential",
|
|
50
|
-
"sessioncredentials",
|
|
51
|
-
"sessioncookie",
|
|
52
|
-
"auth",
|
|
53
|
-
"authentication",
|
|
54
|
-
"authorization",
|
|
55
|
-
"proxyauthorization",
|
|
56
|
-
"cookie",
|
|
57
|
-
"cookies",
|
|
58
|
-
"setcookie",
|
|
59
|
-
"apikey",
|
|
60
|
-
"xapikey",
|
|
61
|
-
"xauthtoken",
|
|
62
|
-
"clientsecret",
|
|
63
|
-
"secret",
|
|
64
|
-
"secrets",
|
|
65
|
-
"credential",
|
|
66
|
-
"credentials",
|
|
67
|
-
"signature",
|
|
68
|
-
"otp",
|
|
69
|
-
"otpcode",
|
|
70
|
-
"totpsecret",
|
|
71
|
-
"onetimecode",
|
|
72
|
-
"onetimepassword",
|
|
73
|
-
"verificationcode",
|
|
74
|
-
"authcode",
|
|
75
|
-
"authorizationcode",
|
|
76
|
-
"oauthcode",
|
|
77
|
-
"codeverifier"
|
|
78
|
-
]);
|
|
79
|
-
/** Match credential fields by meaning, without hiding token addresses or replay IDs. */
|
|
80
|
-
function isCredentialField(name, context) {
|
|
81
|
-
const normalized = name.toLowerCase().replace(/[^a-z0-9]/gu, "");
|
|
82
|
-
return CREDENTIAL_FIELDS.has(normalized) || /(?:password(?:hash)?|passwd|passphrase|privatekey|signingkey|apikey|clientsecret|accesstoken|refreshtoken|sessiontoken)$/u.test(normalized) || context === "authentication" && (normalized === "code" || normalized === "sessionid") || context === "header" && /(?:token|secret|apikey|privatekey|signingkey|password|authorization|cookie|session)$/u.test(normalized);
|
|
83
|
-
}
|
|
84
|
-
function decodeUrlComponent(text) {
|
|
85
|
-
try {
|
|
86
|
-
return decodeURIComponent(text);
|
|
87
|
-
} catch {
|
|
88
|
-
return text;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
/** Preserve URL diagnostics while removing credentials from their declared components. */
|
|
92
|
-
function redactUrlSecrets(value, source) {
|
|
93
|
-
try {
|
|
94
|
-
const absolute = /^[a-z][a-z0-9+.-]*:/iu.test(value);
|
|
95
|
-
const protocolRelative = value.startsWith("//");
|
|
96
|
-
const url = new URL(value, "https://redaction.invalid");
|
|
97
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") return maskText(value);
|
|
98
|
-
let changed = url.username.length > 0 || url.password.length > 0;
|
|
99
|
-
const maskParams = (params) => new URLSearchParams(Array.from(params, ([name, entry]) => {
|
|
100
|
-
const safeName = maskText(name);
|
|
101
|
-
const safeEntry = isCredentialField(name) || /^(?:code|draft|__posthog)$/iu.test(name) ? "[REDACTED]" : maskText(entry);
|
|
102
|
-
changed ||= safeName !== name || safeEntry !== entry;
|
|
103
|
-
return [safeName, safeEntry];
|
|
104
|
-
})).toString();
|
|
105
|
-
const provider = source !== void 0 || /(?:^|\.)(?:alchemy\.com|alchemyapi\.io|infura\.io)$/iu.test(url.hostname);
|
|
106
|
-
const segments = (absolute || protocolRelative ? url.pathname : value.split(/[?#]/u)[0] ?? "").split("/");
|
|
107
|
-
const path = segments.map((segment, index) => {
|
|
108
|
-
const decoded = decodeUrlComponent(segment);
|
|
109
|
-
const masked = provider && /^v[23]$/u.test(decodeUrlComponent(segments[index - 1] ?? "")) && decoded.length > 0 ? "[REDACTED]" : maskText(decoded);
|
|
110
|
-
changed ||= masked !== decoded;
|
|
111
|
-
return masked === decoded ? segment : encodeURIComponent(masked);
|
|
112
|
-
}).join("/");
|
|
113
|
-
const query = maskParams(url.searchParams);
|
|
114
|
-
const fragment = url.hash.slice(1);
|
|
115
|
-
const decodedFragment = decodeUrlComponent(fragment);
|
|
116
|
-
const maskedFragment = maskText(decodedFragment);
|
|
117
|
-
changed ||= maskedFragment !== decodedFragment;
|
|
118
|
-
const fragmentQuery = fragment.indexOf("?");
|
|
119
|
-
const fragmentPath = fragment.slice(0, fragmentQuery);
|
|
120
|
-
const maskedFragmentPath = maskText(decodeUrlComponent(fragmentPath));
|
|
121
|
-
changed ||= maskedFragmentPath !== decodeUrlComponent(fragmentPath);
|
|
122
|
-
const hash = fragmentQuery >= 0 ? `${maskedFragmentPath === decodeUrlComponent(fragmentPath) ? fragmentPath : encodeURIComponent(maskedFragmentPath)}?${maskParams(new URLSearchParams(fragment.slice(fragmentQuery + 1)))}` : fragment.includes("=") ? maskParams(new URLSearchParams(fragment)) : maskedFragment === decodedFragment ? fragment : encodeURIComponent(maskedFragment);
|
|
123
|
-
const origin = absolute ? url.origin : protocolRelative ? `//${url.host}` : "";
|
|
124
|
-
if (!changed) return value;
|
|
125
|
-
return `${origin}${path}${query ? `?${query}` : ""}${hash ? `#${hash}` : ""}`;
|
|
126
|
-
} catch {
|
|
127
|
-
return maskText(value.replace(/(https?:\/\/)[^/\s@]+@/giu, "$1[REDACTED]@").replace(/([?&#])([^=&#]+)=([^&#]*)/gu, (whole, separator, name) => isCredentialField(decodeUrlComponent(name)) || /^(?:code|draft|__posthog)$/iu.test(decodeUrlComponent(name)) ? `${separator}${name}=[REDACTED]` : whole));
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
const JSON_FIELD = /("(?:[^"\\]|\\.)*")(\s*:\s*)("(?:[^"\\]|\\.)*"|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/gu;
|
|
131
|
-
const PROSE_FIELD = /(?=(\b([A-Za-z][A-Za-z0-9_-]*(?:[ \t]+[A-Za-z][A-Za-z0-9_-]*){0,3})\s*[:=]\s*((?:Bearer|Basic)[ \t]+[^\s,;"']+|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[^\s,;&"']+)))/gu;
|
|
132
|
-
const EMBEDDED_URL = /(https?:\/\/[^\s"<>]*)/giu;
|
|
133
|
-
function isSecretLabel(name) {
|
|
134
|
-
return isCredentialField(name) || /^request[ _-]?body$/iu.test(name);
|
|
135
|
-
}
|
|
136
|
-
const JSON_ENCODING_MAX = 8;
|
|
137
|
-
const JSON_NESTING_MAX = 64;
|
|
138
|
-
const JSON_KEY = /("(?:[^"\\]|\\.)*")\s*:/gu;
|
|
139
|
-
const JSON_CONTAINER_START = /(?:\{\s*["}]|\[\s*[[\]{}"0-9tfn-])/uy;
|
|
140
|
-
function hasSecretJsonKey(value) {
|
|
141
|
-
for (const match of value.matchAll(JSON_KEY)) try {
|
|
142
|
-
if (match[1] !== void 0 && isSecretLabel(JSON.parse(match[1]))) return true;
|
|
143
|
-
} catch {}
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
/** Project a complete fragment once. Never retry all of its nested substrings. */
|
|
147
|
-
function projectJsonFragment(value, encodingDepth, overDepth) {
|
|
148
|
-
if (overDepth || encodingDepth >= JSON_ENCODING_MAX) return "[REDACTED]";
|
|
149
|
-
let parsed;
|
|
150
|
-
try {
|
|
151
|
-
parsed = JSON.parse(value);
|
|
152
|
-
} catch {
|
|
153
|
-
return hasSecretJsonKey(value) ? "[REDACTED]" : value;
|
|
154
|
-
}
|
|
155
|
-
try {
|
|
156
|
-
let changed = false;
|
|
157
|
-
const masked = JSON.stringify(parsed, (name, nested) => {
|
|
158
|
-
if (isSecretLabel(name)) {
|
|
159
|
-
changed ||= nested !== "[REDACTED]";
|
|
160
|
-
return "[REDACTED]";
|
|
161
|
-
}
|
|
162
|
-
if (typeof nested === "string") {
|
|
163
|
-
const projected = maskJsonFragments(nested, encodingDepth + 1);
|
|
164
|
-
changed ||= projected !== nested;
|
|
165
|
-
return projected;
|
|
166
|
-
}
|
|
167
|
-
return nested;
|
|
168
|
-
});
|
|
169
|
-
return changed ? masked : value;
|
|
170
|
-
} catch {
|
|
171
|
-
return "[REDACTED]";
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
/** Scan balanced object/array fragments once, respecting JSON quotes and escapes. */
|
|
175
|
-
function maskJsonFragments(value, encodingDepth = 0) {
|
|
176
|
-
if (value.trimStart().startsWith("\"")) try {
|
|
177
|
-
const decoded = JSON.parse(value);
|
|
178
|
-
if (typeof decoded === "string") {
|
|
179
|
-
if (encodingDepth >= JSON_ENCODING_MAX) return "\"[REDACTED]\"";
|
|
180
|
-
const masked = maskJsonFragments(decoded, encodingDepth + 1);
|
|
181
|
-
return masked === decoded ? value : JSON.stringify(masked);
|
|
182
|
-
}
|
|
183
|
-
} catch {}
|
|
184
|
-
let output = "";
|
|
185
|
-
let cursor = 0;
|
|
186
|
-
let start = -1;
|
|
187
|
-
let depth = 0;
|
|
188
|
-
let overDepth = false;
|
|
189
|
-
let quoted = false;
|
|
190
|
-
let escaped = false;
|
|
191
|
-
for (let index = 0; index < value.length; index++) {
|
|
192
|
-
const character = value[index];
|
|
193
|
-
if (start < 0) {
|
|
194
|
-
JSON_CONTAINER_START.lastIndex = index;
|
|
195
|
-
if (!JSON_CONTAINER_START.test(value)) continue;
|
|
196
|
-
start = index;
|
|
197
|
-
depth = 1;
|
|
198
|
-
overDepth = false;
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if (quoted) {
|
|
202
|
-
if (escaped) escaped = false;
|
|
203
|
-
else if (character === "\\") escaped = true;
|
|
204
|
-
else if (character === "\"") quoted = false;
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
if (character === "\"") quoted = true;
|
|
208
|
-
else if (character === "{" || character === "[") {
|
|
209
|
-
depth++;
|
|
210
|
-
overDepth ||= depth > JSON_NESTING_MAX;
|
|
211
|
-
} else if (character === "}" || character === "]") {
|
|
212
|
-
depth--;
|
|
213
|
-
if (depth !== 0) continue;
|
|
214
|
-
output += value.slice(cursor, start) + projectJsonFragment(value.slice(start, index + 1), encodingDepth, overDepth);
|
|
215
|
-
cursor = index + 1;
|
|
216
|
-
start = -1;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
if (start >= 0) {
|
|
220
|
-
const fragment = value.slice(start);
|
|
221
|
-
output += value.slice(cursor, start) + (overDepth || hasSecretJsonKey(fragment) ? "[REDACTED]" : fragment);
|
|
222
|
-
cursor = value.length;
|
|
223
|
-
}
|
|
224
|
-
return output + value.slice(cursor);
|
|
225
|
-
}
|
|
226
|
-
function maskLabelledText(value) {
|
|
227
|
-
const jsonMasked = maskJsonFragments(value).replace(JSON_FIELD, (whole, quotedName, separator) => {
|
|
228
|
-
try {
|
|
229
|
-
return isSecretLabel(JSON.parse(quotedName)) ? `${quotedName}${separator}"[REDACTED]"` : whole;
|
|
230
|
-
} catch {
|
|
231
|
-
return whole;
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
let output = "";
|
|
235
|
-
let cursor = 0;
|
|
236
|
-
for (const match of jsonMasked.matchAll(PROSE_FIELD)) {
|
|
237
|
-
const [, whole, label, entry] = match;
|
|
238
|
-
if (whole === void 0 || label === void 0 || entry === void 0 || match.index < cursor || /^Bearer[ \t]+/iu.test(entry)) continue;
|
|
239
|
-
const words = label.split(/[ \t]+/u);
|
|
240
|
-
for (let index = 0; index < words.length; index++) {
|
|
241
|
-
const name = words.slice(index).join(" ");
|
|
242
|
-
if (isSecretLabel(name)) {
|
|
243
|
-
const prefix = words.slice(0, index).join(" ");
|
|
244
|
-
output += jsonMasked.slice(cursor, match.index) + `${prefix ? `${prefix} ` : ""}${name}=[REDACTED]`;
|
|
245
|
-
cursor = match.index + whole.length;
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return output + jsonMasked.slice(cursor);
|
|
251
|
-
}
|
|
252
|
-
const TOKEN_MASKS = [
|
|
253
|
-
[/\bBearer\s+(?!(?:realm|error|error_description|scope|authorization_uri|resource|claims)\s*=)[^\s,;"']+/giu, "Bearer [REDACTED]"],
|
|
254
|
-
[/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[REDACTED]"],
|
|
255
|
-
[/(^|[^a-fA-F0-9])(?<!0[xX])[a-fA-F0-9]{64}(?=$|[^a-fA-F0-9])/gu, "$1[REDACTED]"],
|
|
256
|
-
[/(?:(?:sk|pk|rk)_(?:live|test)|(?:phc|phx|ghp|gho|ghu|ghs|ghr|whsec)_|github_pat_|xox[baprs]-|AKIA[0-9A-Z]{16}|AIza)[A-Za-z0-9_-]*/giu, "[REDACTED]"]
|
|
257
|
-
];
|
|
258
|
-
/** URL components and malformed URLs use this non-recursive masking layer. */
|
|
259
|
-
function maskText(value) {
|
|
260
|
-
let text = maskLabelledText(value);
|
|
261
|
-
for (const [pattern, replacement] of TOKEN_MASKS) text = text.replace(pattern, replacement);
|
|
262
|
-
return text;
|
|
263
|
-
}
|
|
264
|
-
/** Mask credential fields and embedded URLs while preserving surrounding evidence. */
|
|
265
|
-
function redactSecrets(value, source) {
|
|
266
|
-
return maskLabelledText(value).split(EMBEDDED_URL).map((part, index) => index % 2 === 1 ? redactUrlSecrets(part, source).replaceAll("%5BREDACTED%5D", "[REDACTED]") : maskText(part)).join("");
|
|
267
|
-
}
|
|
268
|
-
//#endregion
|
|
269
|
-
//#region ../errors/src/errors.ts
|
|
270
|
-
const CAPXUL_ERROR_CODES = [
|
|
271
|
-
"NOT_AUTHENTICATED",
|
|
272
|
-
"EMAIL_DELIVERY_FAILED",
|
|
273
|
-
"PROFILE_NOT_FOUND",
|
|
274
|
-
"SMART_ACCOUNT_MISSING",
|
|
275
|
-
"PLAYER_NOT_FOUND",
|
|
276
|
-
"ACCOUNT_NOT_FOUND",
|
|
277
|
-
"ACCOUNT_CLAIMED_BY_OTHER_SIGNER",
|
|
278
|
-
"PROVIDER_ERROR",
|
|
279
|
-
"CAPABILITY_UNAVAILABLE",
|
|
280
|
-
"INVALID_INPUT",
|
|
281
|
-
"ENV_MISSING",
|
|
282
|
-
"NOT_IMPLEMENTED",
|
|
283
|
-
"VERIFICATION_REQUIRED",
|
|
284
|
-
"INSUFFICIENT_BALANCE",
|
|
285
|
-
"INVALID_RECIPIENT",
|
|
286
|
-
"ROLE_PERMISSION_DENIED",
|
|
287
|
-
"TRANSACTION_FAILED",
|
|
288
|
-
"RATE_LIMITED",
|
|
289
|
-
"NETWORK_ERROR",
|
|
290
|
-
"UNKNOWN",
|
|
291
|
-
"OTP_EXPIRED",
|
|
292
|
-
"SIGNER_REJECTED",
|
|
293
|
-
"CANCELLED",
|
|
294
|
-
"WRONG_STATE",
|
|
295
|
-
"STALE_EPOCH",
|
|
296
|
-
"SUPERSEDED",
|
|
297
|
-
"WORK_DIED",
|
|
298
|
-
"ACTOR_STOPPED"
|
|
299
|
-
];
|
|
300
|
-
new Set(CAPXUL_ERROR_CODES);
|
|
301
|
-
//#endregion
|
|
302
|
-
export { redactUrlSecrets as i, isCredentialField as n, redactSecrets as r, CAPXUL_ERROR_CODES as t };
|