@foam-ai/node 0.1.0-alpha.5 → 0.1.0-alpha.6

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.
@@ -0,0 +1,421 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SENSITIVE_QUERY_KEYS = exports.SENSITIVE_HTTP_HEADERS = exports.SENSITIVE_KEYS = void 0;
4
+ const PASSWORD_KEYS = [
5
+ "admin_password",
6
+ "basic_auth_password",
7
+ "confirm_password",
8
+ "connection_password",
9
+ "current_password",
10
+ "database_password",
11
+ "db_pass",
12
+ "db_password",
13
+ "ftp_password",
14
+ "http_password",
15
+ "keystore_password",
16
+ "master_password",
17
+ "mail_password",
18
+ "mysql_pwd",
19
+ "new_password",
20
+ "old_password",
21
+ "pass",
22
+ "passcode",
23
+ "passphrase",
24
+ "passwd",
25
+ "password",
26
+ "password_confirmation",
27
+ "postgres_password",
28
+ "pwd",
29
+ "redis_password",
30
+ "root_password",
31
+ "smtp_password",
32
+ "user_password",
33
+ ];
34
+ const TOKEN_KEYS = [
35
+ "access_token_secret",
36
+ "activation_token",
37
+ "access_token",
38
+ "api_token",
39
+ "assertion",
40
+ "auth",
41
+ "auth_token",
42
+ "authentication_token",
43
+ "authorization",
44
+ "authorization_code",
45
+ "bearer",
46
+ "bearer_token",
47
+ "bot_token",
48
+ "ci_job_token",
49
+ "client_assertion",
50
+ "client_secret",
51
+ "credential",
52
+ "credentials",
53
+ "deploy_token",
54
+ "email_verification_token",
55
+ "id_token",
56
+ "identity_token",
57
+ "invite_token",
58
+ "jwt",
59
+ "jwt_token",
60
+ "magic_link_token",
61
+ "oauth_token",
62
+ "oauth2_token",
63
+ "oauth_token_secret",
64
+ "password_reset_token",
65
+ "personal_access_token",
66
+ "registration_token",
67
+ "request_token",
68
+ "refresh_token",
69
+ "reset_token",
70
+ "saml_assertion",
71
+ "saml_response",
72
+ "secret_token",
73
+ "security_token",
74
+ "service_token",
75
+ "sso_token",
76
+ "token",
77
+ "unsubscribe_token",
78
+ "verification_token",
79
+ ];
80
+ const KEY_MATERIAL_KEYS = [
81
+ "access_key",
82
+ "access_key_id",
83
+ "api_key",
84
+ "api_secret",
85
+ "amqp_url",
86
+ "apikey",
87
+ "app_key",
88
+ "app_secret",
89
+ "application_key",
90
+ "application_secret",
91
+ "aws_access_key_id",
92
+ "aws_secret_access_key",
93
+ "consumer_key",
94
+ "consumer_secret",
95
+ "broker_url",
96
+ "connection_string",
97
+ "connection_uri",
98
+ "credential_blob",
99
+ "decryption_key",
100
+ "database_url",
101
+ "database_connection_string",
102
+ "db_url",
103
+ "dsn",
104
+ "encryption_key",
105
+ "gcp_service_account_key",
106
+ "google_application_credentials",
107
+ "key",
108
+ "key_password",
109
+ "key_store_password",
110
+ "keystore",
111
+ "license_key",
112
+ "mnemonic",
113
+ "mongodb_uri",
114
+ "kube_config",
115
+ "kubeconfig",
116
+ "pem",
117
+ "private_key",
118
+ "privatekey",
119
+ "proxy_authorization",
120
+ "redis_url",
121
+ "redis_uri",
122
+ "rabbitmq_url",
123
+ "secret",
124
+ "secret_access_key",
125
+ "secret_key",
126
+ "seed_phrase",
127
+ "service_account_json",
128
+ "service_account_key",
129
+ "shared_secret",
130
+ "signature",
131
+ "signing_key",
132
+ "signing_secret",
133
+ "ssh_private_key",
134
+ "smtp_url",
135
+ "tls_private_key",
136
+ "wallet_private_key",
137
+ "wallet_seed",
138
+ "webhook_secret",
139
+ "www_authenticate",
140
+ ];
141
+ const SESSION_KEYS = [
142
+ "_csrf",
143
+ "_csrf_token",
144
+ "_session",
145
+ "_xsrf",
146
+ "aiohttp_session",
147
+ "anti_forgery_token",
148
+ "backup_code",
149
+ "backup_codes",
150
+ "connect.sid",
151
+ "cookie",
152
+ "csrf",
153
+ "csrf_token",
154
+ "csrftoken",
155
+ "django_session",
156
+ "hotp",
157
+ "laravel_session",
158
+ "mfa",
159
+ "mfa_code",
160
+ "otp",
161
+ "phpsessid",
162
+ "pin",
163
+ "recovery_code",
164
+ "recovery_codes",
165
+ "remember_token",
166
+ "session",
167
+ "session_id",
168
+ "session_key",
169
+ "session_token",
170
+ "sessionid",
171
+ "set_cookie",
172
+ "setcookie",
173
+ "sid",
174
+ "symfony",
175
+ "totp",
176
+ "user_session",
177
+ "x_csrf_token",
178
+ "x_csrftoken",
179
+ "x_xsrf_token",
180
+ "xsrf",
181
+ "xsrf_token",
182
+ ];
183
+ const PERSONAL_AND_FINANCIAL_KEYS = [
184
+ "account_number",
185
+ "bank_account",
186
+ "card",
187
+ "card_number",
188
+ "credit_card",
189
+ "credit_card_number",
190
+ "cvc",
191
+ "cvv",
192
+ "date_of_birth",
193
+ "dob",
194
+ "driver_license",
195
+ "drivers_license",
196
+ "iban",
197
+ "ip_address",
198
+ "national_id",
199
+ "passport_number",
200
+ "remote_addr",
201
+ "routing_number",
202
+ "sort_code",
203
+ "ssn",
204
+ "tax_id",
205
+ "x_forwarded_for",
206
+ "x_real_ip",
207
+ ];
208
+ const PROVIDER_KEYS = [
209
+ "algolia_admin_api_key",
210
+ "anthropic_api_key",
211
+ "artifactory_api_key",
212
+ "airtable_api_key",
213
+ "azure_api_key",
214
+ "buildkite_agent_token",
215
+ "circle_token",
216
+ "cohere_api_key",
217
+ "cloudflare_api_token",
218
+ "consul_http_token",
219
+ "datadog_api_key",
220
+ "datadog_app_key",
221
+ "discord_bot_token",
222
+ "docker_password",
223
+ "docker_config_json",
224
+ "digitalocean_token",
225
+ "firebase_service_account",
226
+ "gemini_api_key",
227
+ "github_token",
228
+ "gitlab_token",
229
+ "google_api_key",
230
+ "groq_api_key",
231
+ "honeycomb_api_key",
232
+ "huggingface_token",
233
+ "heroku_api_key",
234
+ "jfrog_access_token",
235
+ "linear_api_key",
236
+ "mapbox_access_token",
237
+ "new_relic_license_key",
238
+ "nomad_token",
239
+ "notion_token",
240
+ "npm_token",
241
+ "openai_api_key",
242
+ "pagerduty_routing_key",
243
+ "pypi_token",
244
+ "sentry_auth_token",
245
+ "sentry_dsn",
246
+ "sendgrid_api_key",
247
+ "shopify_access_token",
248
+ "shopify_api_secret",
249
+ "slack_app_token",
250
+ "slack_bot_token",
251
+ "slack_signing_secret",
252
+ "stripe_secret_key",
253
+ "stripe_webhook_secret",
254
+ "supabase_service_role_key",
255
+ "telegram_bot_token",
256
+ "terraform_cloud_token",
257
+ "twilio_auth_token",
258
+ "vault_token",
259
+ "vercel_oidc_token",
260
+ "x_api_key",
261
+ "x_auth_token",
262
+ ];
263
+ exports.SENSITIVE_KEYS = [
264
+ ...PASSWORD_KEYS,
265
+ ...TOKEN_KEYS,
266
+ ...KEY_MATERIAL_KEYS,
267
+ ...SESSION_KEYS,
268
+ ...PERSONAL_AND_FINANCIAL_KEYS,
269
+ ...PROVIDER_KEYS,
270
+ ];
271
+ exports.SENSITIVE_HTTP_HEADERS = [
272
+ "authentication_info",
273
+ "authorization",
274
+ "cf_access_authenticated_user_email",
275
+ "cf_access_jwt_assertion",
276
+ "cookie",
277
+ "grpcgateway_authorization",
278
+ "impersonate_group",
279
+ "impersonate_user",
280
+ "jenkins_crumb",
281
+ "job_token",
282
+ "ocp_apim_subscription_key",
283
+ "private_token",
284
+ "proxy_authenticate",
285
+ "proxy_authentication_info",
286
+ "proxy_authorization",
287
+ "set_cookie",
288
+ "stripe_signature",
289
+ "www_authenticate",
290
+ "x_access_token",
291
+ "x_algolia_api_key",
292
+ "x_amz_credential",
293
+ "x_amz_security_token",
294
+ "x_amz_signature",
295
+ "x_amzn_oidc_accesstoken",
296
+ "x_amzn_oidc_data",
297
+ "x_amzn_oidc_identity",
298
+ "x_api_key",
299
+ "x_asana_request_token",
300
+ "x_aws_ec2_metadata_token",
301
+ "x_auth_request_access_token",
302
+ "x_auth_request_email",
303
+ "x_auth_request_groups",
304
+ "x_auth_request_preferred_username",
305
+ "x_auth_request_user",
306
+ "x_auth_token",
307
+ "x_box_signature_primary",
308
+ "x_box_signature_secondary",
309
+ "x_cf_access_jwt_assertion",
310
+ "x_csrf_token",
311
+ "x_circle_token",
312
+ "x_consul_token",
313
+ "x_credential_identifier",
314
+ "x_datadog_api_key",
315
+ "x_discord_signature_ed25519",
316
+ "x_docusign_signature_1",
317
+ "x_dropbox_signature",
318
+ "x_elastic_client_authentication",
319
+ "x_firebase_appcheck",
320
+ "x_forwarded_access_token",
321
+ "x_forwarded_email",
322
+ "x_forwarded_for",
323
+ "x_forwarded_user",
324
+ "x_functions_key",
325
+ "x_github_token",
326
+ "x_gitlab_token",
327
+ "x_goog_api_key",
328
+ "x_goog_firebase_installations_auth",
329
+ "x_goog_iap_jwt_assertion",
330
+ "x_hub_signature",
331
+ "x_hub_signature_256",
332
+ "x_honeycomb_api_key",
333
+ "x_honeycomb_team",
334
+ "x_intercom_hmac",
335
+ "x_jwt_assertion",
336
+ "x_linear_signature",
337
+ "x_mailgun_signature",
338
+ "x_master_key",
339
+ "x_meili_api_key",
340
+ "x_ms_client_principal",
341
+ "x_ms_token_aad_access_token",
342
+ "x_ms_token_aad_id_token",
343
+ "x_ms_token_aad_refresh_token",
344
+ "x_nf_client_connection_ip",
345
+ "x_nomad_token",
346
+ "x_npm_token",
347
+ "x_original_authorization",
348
+ "x_real_ip",
349
+ "x_remote_email",
350
+ "x_remote_groups",
351
+ "x_remote_user",
352
+ "x_pagerduty_signature",
353
+ "x_parse_rest_api_key",
354
+ "x_sendgrid_event_webhook_signature",
355
+ "x_session_token",
356
+ "x_shopify_hmac_sha256",
357
+ "x_signature",
358
+ "x_signature_ed25519",
359
+ "x_slack_signature",
360
+ "x_sonarqube_passcode",
361
+ "x_squarespace_hmacsha256_signature",
362
+ "x_twilio_signature",
363
+ "x_typesense_api_key",
364
+ "x_userinfo",
365
+ "x_vault_token",
366
+ "x_vercel_oidc_token",
367
+ "x_webhook_signature",
368
+ "x_webhook_secret",
369
+ "x_wix_webhook_signature",
370
+ "x_xsrf_token",
371
+ "x_zendesk_webhook_signature",
372
+ ];
373
+ exports.SENSITIVE_QUERY_KEYS = [
374
+ "access_token",
375
+ "api_key",
376
+ "api_secret",
377
+ "api_token",
378
+ "apikey",
379
+ "assertion",
380
+ "auth",
381
+ "auth_token",
382
+ "authorization",
383
+ "authorization_code",
384
+ "bearer_token",
385
+ "client_assertion",
386
+ "client_secret",
387
+ "code",
388
+ "code_verifier",
389
+ "credential",
390
+ "hmac",
391
+ "id_token",
392
+ "invite_token",
393
+ "jwt",
394
+ "key",
395
+ "magic_link_token",
396
+ "oauth_token_secret",
397
+ "otp",
398
+ "password_reset_token",
399
+ "password",
400
+ "policy",
401
+ "pin",
402
+ "refresh_token",
403
+ "reset_token",
404
+ "saml_response",
405
+ "secret",
406
+ "secret_key",
407
+ "session",
408
+ "session_id",
409
+ "session_token",
410
+ "sig",
411
+ "signature",
412
+ "token",
413
+ "token_secret",
414
+ "unsubscribe_token",
415
+ "verification_token",
416
+ "x_amz_credential",
417
+ "x_amz_security_token",
418
+ "x_amz_signature",
419
+ "x_goog_credential",
420
+ "x_goog_signature",
421
+ ];
@@ -0,0 +1,24 @@
1
+ export interface RedactOptions {
2
+ readonly secrets?: readonly string[];
3
+ readonly pii?: readonly string[];
4
+ }
5
+ export interface RedactionConfig {
6
+ readonly secretKeys: ReadonlySet<string>;
7
+ readonly piiKeys: ReadonlySet<string>;
8
+ }
9
+ export type KeyMatchKind = "floor" | "pii" | "secret";
10
+ export declare function setActiveRedactionConfig(config: RedactionConfig): void;
11
+ export declare function getActiveRedactionConfig(): RedactionConfig;
12
+ export declare function normalizeKey(key: string): string;
13
+ export declare function isFloorKey(key: string): boolean;
14
+ export declare function isSensitiveQueryKey(key: string): boolean;
15
+ export declare function keyMatch(key: string, config?: RedactionConfig): KeyMatchKind | undefined;
16
+ export declare function tailMask(value: unknown): string;
17
+ export declare function maskForMatch(kind: KeyMatchKind, value: unknown): string;
18
+ export declare function redactQueryPairs(query: string, config?: RedactionConfig): string;
19
+ export declare function redactUrlLike(text: string, config?: RedactionConfig): string;
20
+ export declare function redactString(text: string, config?: RedactionConfig): string;
21
+ export declare function redactDeep(value: unknown, config?: RedactionConfig): unknown;
22
+ export declare function redactAttributeValue(key: string, value: unknown, config?: RedactionConfig): unknown;
23
+ export declare function redactAttributesCopy(attributes: Readonly<Record<string, unknown>>, config?: RedactionConfig): Record<string, unknown>;
24
+ export declare function resolveRedactionConfig(redact: unknown): RedactionConfig;
@@ -0,0 +1,270 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setActiveRedactionConfig = setActiveRedactionConfig;
4
+ exports.getActiveRedactionConfig = getActiveRedactionConfig;
5
+ exports.normalizeKey = normalizeKey;
6
+ exports.isFloorKey = isFloorKey;
7
+ exports.isSensitiveQueryKey = isSensitiveQueryKey;
8
+ exports.keyMatch = keyMatch;
9
+ exports.tailMask = tailMask;
10
+ exports.maskForMatch = maskForMatch;
11
+ exports.redactQueryPairs = redactQueryPairs;
12
+ exports.redactUrlLike = redactUrlLike;
13
+ exports.redactString = redactString;
14
+ exports.redactDeep = redactDeep;
15
+ exports.redactAttributeValue = redactAttributeValue;
16
+ exports.redactAttributesCopy = redactAttributesCopy;
17
+ exports.resolveRedactionConfig = resolveRedactionConfig;
18
+ const constants_js_1 = require("./constants.js");
19
+ const redaction_keys_js_1 = require("./redaction-keys.js");
20
+ const EMPTY_CONFIG = {
21
+ secretKeys: new Set(),
22
+ piiKeys: new Set(),
23
+ };
24
+ const FLOOR_KEYS = new Set(redaction_keys_js_1.SENSITIVE_KEYS);
25
+ const HTTP_HEADERS = new Set(redaction_keys_js_1.SENSITIVE_HTTP_HEADERS);
26
+ const QUERY_KEYS = new Set(redaction_keys_js_1.SENSITIVE_QUERY_KEYS);
27
+ const HEADER_PREFIXES = ["http.request.header.", "http.response.header."];
28
+ const BARE_QUERY_KEYS = new Set(["url.query"]);
29
+ const BODY_KEYS = new Set([
30
+ "http.request.body.content",
31
+ "http.response.body.content",
32
+ ]);
33
+ const MAX_DEPTH = 10;
34
+ const QUERY_PAIR_CAP = 256;
35
+ let activeConfig = EMPTY_CONFIG;
36
+ function setActiveRedactionConfig(config) {
37
+ activeConfig = config;
38
+ }
39
+ function getActiveRedactionConfig() {
40
+ return activeConfig;
41
+ }
42
+ function normalizeKey(key) {
43
+ return key
44
+ .trim()
45
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
46
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
47
+ .replace(/-/g, "_")
48
+ .toLowerCase();
49
+ }
50
+ function isFloorKey(key) {
51
+ return FLOOR_KEYS.has(normalizeKey(key));
52
+ }
53
+ function isSensitiveHeader(key) {
54
+ return HTTP_HEADERS.has(normalizeKey(key));
55
+ }
56
+ function isSensitiveQueryKey(key) {
57
+ const normalized = normalizeKey(key);
58
+ return FLOOR_KEYS.has(normalized) || QUERY_KEYS.has(normalized);
59
+ }
60
+ function keyMatch(key, config = activeConfig) {
61
+ const normalized = normalizeKey(key);
62
+ if (FLOOR_KEYS.has(normalized))
63
+ return "floor";
64
+ if (config.piiKeys.has(normalized))
65
+ return "pii";
66
+ if (config.secretKeys.has(normalized))
67
+ return "secret";
68
+ return undefined;
69
+ }
70
+ function tailMask(value) {
71
+ if (value === constants_js_1.REDACTED_VALUE)
72
+ return constants_js_1.REDACTED_VALUE;
73
+ if (typeof value === "string" || typeof value === "number") {
74
+ const text = String(value);
75
+ if (text.length >= constants_js_1.TAIL_MASK_THRESHOLD)
76
+ return constants_js_1.FULL_MASK + text.slice(-4);
77
+ }
78
+ return constants_js_1.FULL_MASK;
79
+ }
80
+ function maskForMatch(kind, value) {
81
+ return kind === "secret" ? tailMask(value) : constants_js_1.REDACTED_VALUE;
82
+ }
83
+ function decodeKey(value) {
84
+ try {
85
+ return decodeURIComponent(value.replace(/\+/g, " "));
86
+ }
87
+ catch {
88
+ return value;
89
+ }
90
+ }
91
+ function redactPair(pair, config) {
92
+ const separator = pair.indexOf("=");
93
+ if (separator < 0)
94
+ return pair;
95
+ const key = decodeKey(pair.slice(0, separator));
96
+ if (keyMatch(key, config) || isSensitiveQueryKey(key)) {
97
+ return `${pair.slice(0, separator)}=${constants_js_1.REDACTED_VALUE}`;
98
+ }
99
+ return pair;
100
+ }
101
+ function redactQueryPairs(query, config = activeConfig) {
102
+ const result = [];
103
+ let start = 0;
104
+ let count = 0;
105
+ while (start <= query.length) {
106
+ if (count >= QUERY_PAIR_CAP) {
107
+ result.push(constants_js_1.REDACTED_VALUE);
108
+ break;
109
+ }
110
+ const next = query.indexOf("&", start);
111
+ result.push(redactPair(next < 0 ? query.slice(start) : query.slice(start, next), config));
112
+ count += 1;
113
+ if (next < 0)
114
+ break;
115
+ start = next + 1;
116
+ }
117
+ return result.join("&");
118
+ }
119
+ function redactSegment(segment, config) {
120
+ return segment.includes("=") ? redactQueryPairs(segment, config) : segment;
121
+ }
122
+ function redactUrlLike(text, config = activeConfig) {
123
+ const hash = text.indexOf("#");
124
+ const head = hash < 0 ? text : text.slice(0, hash);
125
+ const fragment = hash < 0 ? undefined : text.slice(hash + 1);
126
+ const query = head.indexOf("?");
127
+ const redactedHead = query < 0
128
+ ? redactSegment(head, config)
129
+ : `${head.slice(0, query + 1)}${redactQueryPairs(head.slice(query + 1), config)}`;
130
+ if (fragment === undefined)
131
+ return redactedHead;
132
+ const fragmentQuery = fragment.indexOf("?");
133
+ const redactedFragment = fragmentQuery < 0
134
+ ? redactSegment(fragment, config)
135
+ : `${redactSegment(fragment.slice(0, fragmentQuery), config)}?${redactQueryPairs(fragment.slice(fragmentQuery + 1), config)}`;
136
+ return `${redactedHead}#${redactedFragment}`;
137
+ }
138
+ function redactString(text, config = activeConfig) {
139
+ return text.includes("=") ? redactUrlLike(text, config) : text;
140
+ }
141
+ function redactNode(value, config, depth, ancestors) {
142
+ if (depth > MAX_DEPTH)
143
+ return constants_js_1.FULL_MASK;
144
+ if (typeof value === "string")
145
+ return redactString(value, config);
146
+ if (value === null ||
147
+ value === undefined ||
148
+ typeof value === "number" ||
149
+ typeof value === "boolean") {
150
+ return value;
151
+ }
152
+ if (typeof value !== "object")
153
+ return constants_js_1.FULL_MASK;
154
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer)
155
+ return value;
156
+ if (ancestors.has(value))
157
+ return constants_js_1.FULL_MASK;
158
+ ancestors.add(value);
159
+ try {
160
+ if (Array.isArray(value)) {
161
+ return value.map((item) => redactNode(item, config, depth + 1, ancestors));
162
+ }
163
+ const result = {};
164
+ for (const [key, item] of Object.entries(value)) {
165
+ const match = keyMatch(key, config);
166
+ result[key] = match
167
+ ? maskForMatch(match, item)
168
+ : redactNode(item, config, depth + 1, ancestors);
169
+ }
170
+ return result;
171
+ }
172
+ finally {
173
+ ancestors.delete(value);
174
+ }
175
+ }
176
+ function redactDeep(value, config = activeConfig) {
177
+ try {
178
+ return redactNode(value, config, 0, new Set());
179
+ }
180
+ catch {
181
+ return constants_js_1.FULL_MASK;
182
+ }
183
+ }
184
+ function headerSuffix(key) {
185
+ const lower = key.toLowerCase();
186
+ for (const prefix of HEADER_PREFIXES) {
187
+ if (lower.startsWith(prefix) && key.length > prefix.length) {
188
+ return key.slice(prefix.length);
189
+ }
190
+ }
191
+ return undefined;
192
+ }
193
+ function maskElements(kind, value) {
194
+ return Array.isArray(value)
195
+ ? value.map((item) => maskForMatch(kind, item))
196
+ : maskForMatch(kind, value);
197
+ }
198
+ function redactAttributeValue(key, value, config = activeConfig) {
199
+ try {
200
+ const match = keyMatch(key, config);
201
+ if (match)
202
+ return maskElements(match, value);
203
+ const header = headerSuffix(key);
204
+ if (header) {
205
+ const headerMatch = keyMatch(header, config);
206
+ if (headerMatch)
207
+ return maskElements(headerMatch, value);
208
+ if (isSensitiveHeader(header))
209
+ return maskElements("floor", value);
210
+ }
211
+ if (BARE_QUERY_KEYS.has(key.toLowerCase()) && typeof value === "string") {
212
+ return redactQueryPairs(value, config);
213
+ }
214
+ if (BODY_KEYS.has(key))
215
+ return value;
216
+ if (typeof value === "string")
217
+ return redactString(value, config);
218
+ if (Array.isArray(value) ||
219
+ (value !== null && typeof value === "object" && !ArrayBuffer.isView(value))) {
220
+ return redactDeep(value, config);
221
+ }
222
+ if (value === null ||
223
+ value === undefined ||
224
+ typeof value === "number" ||
225
+ typeof value === "boolean" ||
226
+ ArrayBuffer.isView(value)) {
227
+ return value;
228
+ }
229
+ return constants_js_1.FULL_MASK;
230
+ }
231
+ catch {
232
+ return constants_js_1.FULL_MASK;
233
+ }
234
+ }
235
+ function redactAttributesCopy(attributes, config = activeConfig) {
236
+ const result = {};
237
+ for (const [key, value] of Object.entries(attributes)) {
238
+ result[key] = redactAttributeValue(key, value, config);
239
+ }
240
+ return result;
241
+ }
242
+ const REDACT_FIELDS = ["secrets", "pii"];
243
+ function keyList(field, value) {
244
+ if (value === undefined || value === null)
245
+ return [];
246
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
247
+ throw new TypeError(`[foam] redact.${field} must be an array of strings`);
248
+ }
249
+ return value;
250
+ }
251
+ function resolveRedactionConfig(redact) {
252
+ if (redact === undefined || redact === null)
253
+ return EMPTY_CONFIG;
254
+ if (typeof redact !== "object" || Array.isArray(redact)) {
255
+ throw new TypeError("[foam] redact must be an object");
256
+ }
257
+ const record = redact;
258
+ const unknown = Object.keys(record).filter((field) => !REDACT_FIELDS.includes(field));
259
+ if (unknown.length) {
260
+ throw new TypeError(`[foam] redact contains unknown fields: ${unknown.join(", ")}`);
261
+ }
262
+ return {
263
+ secretKeys: new Set(keyList("secrets", record.secrets)
264
+ .map(normalizeKey)
265
+ .filter(Boolean)),
266
+ piiKeys: new Set(keyList("pii", record.pii)
267
+ .map(normalizeKey)
268
+ .filter(Boolean)),
269
+ };
270
+ }