UNPKG

autotel

Version:
744 lines (738 loc) 27 kB
import { TLSAttributes, CodeAttributes, OTelAttributes, GraphQLAttributes, RPCAttributes, GenAIAttributes, MessagingAttributes, FeatureFlagAttributes, FaaSAttributes, CloudAttributes, K8sAttributes, ContainerAttributes, ThreadAttributes, ProcessAttributes, ExceptionAttributes, ErrorAttributes, URLAttributes, ServerAddressAttributes, NetworkAttributes, ServiceAttributes, DBAttributes, HTTPAttributes, DeviceAttributes, SessionAttributes, UserAttributes } from './chunk-4A53YIAX.js'; import { REDACTOR_PATTERNS } from './chunk-TDNKIHKT.js'; import { resourceFromAttributes } from '@opentelemetry/resources'; // src/attributes/builders.ts var attrs = { user: { id: (value) => ({ [UserAttributes.id]: value }), email: (value) => ({ [UserAttributes.email]: value }), name: (value) => ({ [UserAttributes.name]: value }), fullName: (value) => ({ [UserAttributes.fullName]: value }), hash: (value) => ({ [UserAttributes.hash]: value }), roles: (value) => ({ [UserAttributes.roles]: value }), data: (data) => { const result = {}; if (data.id !== void 0) result[UserAttributes.id] = data.id; if (data.email !== void 0) result[UserAttributes.email] = data.email; if (data.name !== void 0) result[UserAttributes.name] = data.name; if (data.fullName !== void 0) result[UserAttributes.fullName] = data.fullName; if (data.hash !== void 0) result[UserAttributes.hash] = data.hash; if (data.roles !== void 0) result[UserAttributes.roles] = data.roles; return result; } }, session: { id: (value) => ({ [SessionAttributes.id]: value }), previousId: (value) => ({ [SessionAttributes.previousId]: value }), data: (data) => { const result = {}; if (data.id !== void 0) result[SessionAttributes.id] = data.id; if (data.previousId !== void 0) result[SessionAttributes.previousId] = data.previousId; return result; } }, device: { id: (value) => ({ [DeviceAttributes.id]: value }), manufacturer: (value) => ({ [DeviceAttributes.manufacturer]: value }), modelIdentifier: (value) => ({ [DeviceAttributes.modelIdentifier]: value }), modelName: (value) => ({ [DeviceAttributes.modelName]: value }), data: (data) => { const result = {}; if (data.id !== void 0) result[DeviceAttributes.id] = data.id; if (data.manufacturer !== void 0) result[DeviceAttributes.manufacturer] = data.manufacturer; if (data.modelIdentifier !== void 0) result[DeviceAttributes.modelIdentifier] = data.modelIdentifier; if (data.modelName !== void 0) result[DeviceAttributes.modelName] = data.modelName; return result; } }, http: { request: { method: (value) => ({ [HTTPAttributes.requestMethod]: value }), methodOriginal: (value) => ({ [HTTPAttributes.requestMethodOriginal]: value }), resendCount: (value) => ({ [HTTPAttributes.requestResendCount]: value }), size: (value) => ({ [HTTPAttributes.requestSize]: value }), bodySize: (value) => ({ [HTTPAttributes.requestBodySize]: value }) }, response: { statusCode: (value) => ({ [HTTPAttributes.responseStatusCode]: value }), size: (value) => ({ [HTTPAttributes.responseSize]: value }), bodySize: (value) => ({ [HTTPAttributes.responseBodySize]: value }) }, route: (value) => ({ [HTTPAttributes.route]: value }), connectionState: (value) => ({ [HTTPAttributes.connectionState]: value }), server: (data) => { const result = {}; if (data.method !== void 0) result[HTTPAttributes.requestMethod] = data.method; if (data.route !== void 0) result[HTTPAttributes.route] = data.route; if (data.statusCode !== void 0) result[HTTPAttributes.responseStatusCode] = data.statusCode; if (data.bodySize !== void 0) result[HTTPAttributes.requestBodySize] = data.bodySize; if (data.requestSize !== void 0) result[HTTPAttributes.requestSize] = data.requestSize; if (data.responseSize !== void 0) result[HTTPAttributes.responseSize] = data.responseSize; if (data.resendCount !== void 0) result[HTTPAttributes.requestResendCount] = data.resendCount; return result; }, client: (data) => { const result = {}; if (data.method !== void 0) result[HTTPAttributes.requestMethod] = data.method; if (data.url !== void 0) result[HTTPAttributes.route] = data.url; if (data.statusCode !== void 0) result[HTTPAttributes.responseStatusCode] = data.statusCode; return result; } }, db: { client: { system: (value) => ({ [DBAttributes.systemName]: value }), operation: (value) => ({ [DBAttributes.operationName]: value }), collectionName: (value) => ({ [DBAttributes.collectionName]: value }), namespace: (value) => ({ [DBAttributes.namespace]: value }), statement: (value) => ({ [DBAttributes.statement]: value }), querySummary: (value) => ({ [DBAttributes.querySummary]: value }), queryText: (value) => ({ [DBAttributes.queryText]: value }), responseStatus: (value) => ({ [DBAttributes.responseStatusCode]: value }), rowsReturned: (value) => ({ [DBAttributes.responseReturnedRows]: value }), data: (data) => { const result = {}; if (data.system !== void 0) result[DBAttributes.systemName] = data.system; if (data.operation !== void 0) result[DBAttributes.operationName] = data.operation; if (data.collectionName !== void 0) result[DBAttributes.collectionName] = data.collectionName; if (data.name !== void 0) result[DBAttributes.namespace] = data.name; if (data.namespace !== void 0) result[DBAttributes.namespace] = data.namespace; if (data.statement !== void 0) result[DBAttributes.statement] = data.statement; if (data.querySummary !== void 0) result[DBAttributes.querySummary] = data.querySummary; if (data.queryText !== void 0) result[DBAttributes.queryText] = data.queryText; if (data.responseStatus !== void 0) result[DBAttributes.responseStatusCode] = data.responseStatus; if (data.rowsReturned !== void 0) result[DBAttributes.responseReturnedRows] = data.rowsReturned; return result; } } }, service: { name: (value) => ({ [ServiceAttributes.name]: value }), instance: (value) => ({ [ServiceAttributes.instance]: value }), version: (value) => ({ [ServiceAttributes.version]: value }), data: (data) => { const result = {}; if (data.name !== void 0) result[ServiceAttributes.name] = data.name; if (data.instance !== void 0) result[ServiceAttributes.instance] = data.instance; if (data.version !== void 0) result[ServiceAttributes.version] = data.version; return result; } }, network: { peerAddress: (value) => ({ [NetworkAttributes.peerAddress]: value }), peerPort: (value) => ({ [NetworkAttributes.peerPort]: value }), transport: (value) => ({ [NetworkAttributes.transport]: value }), protocolName: (value) => ({ [NetworkAttributes.protocolName]: value }), protocolVersion: (value) => ({ [NetworkAttributes.protocolVersion]: value }), data: (data) => { const result = {}; if (data.peerAddress !== void 0) result[NetworkAttributes.peerAddress] = data.peerAddress; if (data.peerPort !== void 0) result[NetworkAttributes.peerPort] = data.peerPort; if (data.transport !== void 0) result[NetworkAttributes.transport] = data.transport; if (data.protocolName !== void 0) result[NetworkAttributes.protocolName] = data.protocolName; if (data.protocolVersion !== void 0) result[NetworkAttributes.protocolVersion] = data.protocolVersion; return result; } }, server: { address: (value) => ({ [ServerAddressAttributes.address]: value }), port: (value) => ({ [ServerAddressAttributes.port]: value }), socketAddress: (value) => ({ [ServerAddressAttributes.socketAddress]: value }), data: (data) => { const result = {}; if (data.address !== void 0) result[ServerAddressAttributes.address] = data.address; if (data.port !== void 0) result[ServerAddressAttributes.port] = data.port; if (data.socketAddress !== void 0) result[ServerAddressAttributes.socketAddress] = data.socketAddress; return result; } }, url: { scheme: (value) => ({ [URLAttributes.scheme]: value }), full: (value) => ({ [URLAttributes.full]: value }), path: (value) => ({ [URLAttributes.path]: value }), query: (value) => ({ [URLAttributes.query]: value }), fragment: (value) => ({ [URLAttributes.fragment]: value }), data: (data) => { const result = {}; if (data.scheme !== void 0) result[URLAttributes.scheme] = data.scheme; if (data.full !== void 0) result[URLAttributes.full] = data.full; if (data.path !== void 0) result[URLAttributes.path] = data.path; if (data.query !== void 0) result[URLAttributes.query] = data.query; if (data.fragment !== void 0) result[URLAttributes.fragment] = data.fragment; return result; } }, error: { type: (value) => ({ [ErrorAttributes.type]: value }), message: (value) => ({ [ErrorAttributes.message]: value }), stackTrace: (value) => ({ [ErrorAttributes.stackTrace]: value }), code: (value) => ({ [ErrorAttributes.code]: value }), data: (data) => { const result = {}; if (data.type !== void 0) result[ErrorAttributes.type] = data.type; if (data.message !== void 0) result[ErrorAttributes.message] = data.message; if (data.stackTrace !== void 0) result[ErrorAttributes.stackTrace] = data.stackTrace; if (data.code !== void 0) result[ErrorAttributes.code] = data.code; return result; } }, exception: { escaped: (value) => ({ [ExceptionAttributes.escaped]: value }), message: (value) => ({ [ExceptionAttributes.message]: value }), stackTrace: (value) => ({ [ExceptionAttributes.stackTrace]: value }), type: (value) => ({ [ExceptionAttributes.type]: value }), moduleName: (value) => ({ [ExceptionAttributes.moduleName]: value }), data: (data) => { const result = {}; if (data.escaped !== void 0) result[ExceptionAttributes.escaped] = data.escaped; if (data.message !== void 0) result[ExceptionAttributes.message] = data.message; if (data.stackTrace !== void 0) result[ExceptionAttributes.stackTrace] = data.stackTrace; if (data.type !== void 0) result[ExceptionAttributes.type] = data.type; if (data.moduleName !== void 0) result[ExceptionAttributes.moduleName] = data.moduleName; return result; } }, process: { pid: (value) => ({ [ProcessAttributes.pid]: value }), executablePath: (value) => ({ [ProcessAttributes.executablePath]: value }), command: (value) => ({ [ProcessAttributes.command]: value }), owner: (value) => ({ [ProcessAttributes.owner]: value }), data: (data) => { const result = {}; if (data.pid !== void 0) result[ProcessAttributes.pid] = data.pid; if (data.executablePath !== void 0) result[ProcessAttributes.executablePath] = data.executablePath; if (data.command !== void 0) result[ProcessAttributes.command] = data.command; if (data.owner !== void 0) result[ProcessAttributes.owner] = data.owner; return result; } }, thread: { id: (value) => ({ [ThreadAttributes.id]: value }), name: (value) => ({ [ThreadAttributes.name]: value }) }, container: { id: (value) => ({ [ContainerAttributes.id]: value }), name: (value) => ({ [ContainerAttributes.name]: value }), image: (value) => ({ [ContainerAttributes.image]: value }), tag: (value) => ({ [ContainerAttributes.tag]: value }), data: (data) => { const result = {}; if (data.id !== void 0) result[ContainerAttributes.id] = data.id; if (data.name !== void 0) result[ContainerAttributes.name] = data.name; if (data.image !== void 0) result[ContainerAttributes.image] = data.image; if (data.tag !== void 0) result[ContainerAttributes.tag] = data.tag; return result; } }, k8s: { podName: (value) => ({ [K8sAttributes.podName]: value }), namespaceName: (value) => ({ [K8sAttributes.namespaceName]: value }), deploymentName: (value) => ({ [K8sAttributes.deploymentName]: value }), state: (value) => ({ [K8sAttributes.state]: value }) }, cloud: { provider: (value) => ({ [CloudAttributes.provider]: value }), accountId: (value) => ({ [CloudAttributes.accountId]: value }), region: (value) => ({ [CloudAttributes.region]: value }), availabilityZone: (value) => ({ [CloudAttributes.availabilityZone]: value }), platform: (value) => ({ [CloudAttributes.platform]: value }), data: (data) => { const result = {}; if (data.provider !== void 0) result[CloudAttributes.provider] = data.provider; if (data.accountId !== void 0) result[CloudAttributes.accountId] = data.accountId; if (data.region !== void 0) result[CloudAttributes.region] = data.region; if (data.availabilityZone !== void 0) result[CloudAttributes.availabilityZone] = data.availabilityZone; if (data.platform !== void 0) result[CloudAttributes.platform] = data.platform; return result; } }, faas: { name: (value) => ({ [FaaSAttributes.name]: value }), version: (value) => ({ [FaaSAttributes.version]: value }), instance: (value) => ({ [FaaSAttributes.instance]: value }), execution: (value) => ({ [FaaSAttributes.execution]: value }), coldstart: (value) => ({ [FaaSAttributes.coldstart]: value }) }, featureFlag: { key: (value) => ({ [FeatureFlagAttributes.key]: value }), provider: (value) => ({ [FeatureFlagAttributes.provider]: value }), variant: (value) => ({ [FeatureFlagAttributes.variant]: value }) }, messaging: { system: (value) => ({ [MessagingAttributes.system]: value }), destination: (value) => ({ [MessagingAttributes.destination]: value }), operation: (value) => ({ [MessagingAttributes.operation]: value }), messageId: (value) => ({ [MessagingAttributes.messageId]: value }), conversationId: (value) => ({ [MessagingAttributes.conversationId]: value }), data: (data) => { const result = {}; if (data.system !== void 0) result[MessagingAttributes.system] = data.system; if (data.destination !== void 0) result[MessagingAttributes.destination] = data.destination; if (data.operation !== void 0) result[MessagingAttributes.operation] = data.operation; if (data.messageId !== void 0) result[MessagingAttributes.messageId] = data.messageId; if (data.conversationId !== void 0) result[MessagingAttributes.conversationId] = data.conversationId; return result; } }, genAI: { system: (value) => ({ [GenAIAttributes.system]: value }), requestModel: (value) => ({ [GenAIAttributes.requestModel]: value }), responseModel: (value) => ({ [GenAIAttributes.responseModel]: value }), operationName: (value) => ({ [GenAIAttributes.operationName]: value }), usagePromptTokens: (value) => ({ [GenAIAttributes.usagePromptTokens]: value }), usageCompletionTokens: (value) => ({ [GenAIAttributes.usageCompletionTokens]: value }), provider: (value) => ({ [GenAIAttributes.provider]: value }) }, rpc: { system: (value) => ({ [RPCAttributes.system]: value }), service: (value) => ({ [RPCAttributes.service]: value }), method: (value) => ({ [RPCAttributes.method]: value }), grpcStatusCode: (value) => ({ [RPCAttributes.grpcStatusCode]: value }) }, graphql: { document: (value) => ({ [GraphQLAttributes.document]: value }), operationName: (value) => ({ [GraphQLAttributes.operationName]: value }), operationType: (value) => ({ [GraphQLAttributes.operationType]: value }) }, otel: { libraryName: (value) => ({ [OTelAttributes.libraryName]: value }), libraryVersion: (value) => ({ [OTelAttributes.libraryVersion]: value }), statusCode: (value) => ({ [OTelAttributes.statusCode]: value }) }, code: { namespace: (value) => ({ [CodeAttributes.namespace]: value }), filepath: (value) => ({ [CodeAttributes.filepath]: value }), function: (value) => ({ [CodeAttributes.function]: value }), class: (value) => ({ [CodeAttributes.class]: value }), method: (value) => ({ [CodeAttributes.method]: value }), column: (value) => ({ [CodeAttributes.column]: value }), lineNumber: (value) => ({ [CodeAttributes.lineNumber]: value }), repository: (value) => ({ [CodeAttributes.repository]: value }), revision: (value) => ({ [CodeAttributes.revision]: value }) }, tls: { protocolVersion: (value) => ({ [TLSAttributes.protocolVersion]: value }), cipher: (value) => ({ [TLSAttributes.cipher]: value }), curveName: (value) => ({ [TLSAttributes.curveName]: value }), resumed: (value) => ({ [TLSAttributes.resumed]: value }) } }; // src/attributes/validators.ts var DEPRECATED_ATTRIBUTES = { "enduser.id": "user.id", "enduser.role": "user.roles", "enduser.scope": void 0, "http.method": "http.request.method", "http.host": "server.address", "http.status_code": "http.response.status_code", "http.target": "url.path", "http.url": "url.full", "http.user_agent": "user_agent.original", "http.flavor": "network.protocol.name", "http.scheme": "url.scheme", "http.server_name": "server.address", "db.name": "db.namespace", "db.operation": "db.operation.name", "db.statement": "db.query.text", "db.system": "db.system.name", "db.collection": "db.collection.name", "db.instance.id": void 0, "db.jdbc.driver_classname": void 0, "db.mssql.instance_name": "mssql.instance.name", "db.sql.table": "db.collection.name", "http.client_ip": "client.address", "user_agent.original": "user_agent.original" }; var HTTP_METHODS = /* @__PURE__ */ new Set([ "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE", "QUERY", "_OTHER" ]); function validateAttribute(key, value, policy = {}) { const { guardrails = {} } = policy; if (value === void 0 || value === null) { return void 0; } if (typeof value !== "string") { return value; } const stringValue = value; if (guardrails.pii) { const piiResult = applyPIIPolicy(key, stringValue, guardrails.pii); if (piiResult !== stringValue) { return piiResult; } } if (guardrails.maxLength && stringValue.length > guardrails.maxLength) { return truncateValue(key, stringValue, guardrails.maxLength); } if (guardrails.validateEnum && HTTP_METHODS.has(stringValue)) { const normalizedMethod = normalizeHTTPMethod(stringValue); if (normalizedMethod !== stringValue) { return normalizedMethod; } } return stringValue; } function applyPIIPolicy(key, value, pii) { if (pii === "allow") { return value; } if (pii === "redact") { return redactIfPII(key, value); } if (pii === "hash") { return hashIfPII(key, value); } if (pii === "block" && isPIIKey(key)) { throw new Error( `PII attribute "${key}" is blocked by guardrails. Use pii: "allow" to enable it.` ); } return value; } function isPIIKey(key) { const piiKeyPatterns = [ "email", "phone", "ssn", "credit_card", "password", "secret", "token", "api_key", "authorization" ]; const lowerKey = key.toLowerCase(); return piiKeyPatterns.some((pattern) => lowerKey.includes(pattern)); } function redactIfPII(key, value) { if (isPIIKey(key)) { for (const [, pattern] of Object.entries(REDACTOR_PATTERNS)) { if (pattern instanceof RegExp && pattern.test(value)) { return "[REDACTED]"; } } return "[REDACTED]"; } return value; } function hashIfPII(key, value) { if (!isPIIKey(key)) { return value; } const FNV_PRIME = 16777619; const FNV_OFFSET = 2166136261; const hashes = []; for (let round = 0; round < 4; round++) { let hash = FNV_OFFSET; for (let i = 0; i < value.length; i++) { hash ^= (value.codePointAt(i) ?? 0) + round; hash = Math.imul(hash, FNV_PRIME); } hashes.push(hash >>> 0); } return `hash_${hashes.map((h) => h.toString(16).padStart(8, "0")).join("")}`; } function truncateValue(key, value, maxLength) { if (value.length <= maxLength) { return value; } return value.slice(0, maxLength - 3) + "..."; } function normalizeHTTPMethod(method) { const upper = method.toUpperCase(); if (HTTP_METHODS.has(upper)) { return upper; } return upper; } function checkDeprecatedAttribute(key, policy = {}) { const { guardrails = {}, deprecatedWarnings = {} } = policy; const { warnDeprecated = true } = guardrails; if (!warnDeprecated) { return null; } const isDeprecated = key in DEPRECATED_ATTRIBUTES; if (isDeprecated) { const replacement2 = DEPRECATED_ATTRIBUTES[key]; if (replacement2 === void 0) { console.warn( `[autotel/attributes] Attribute "${key}" is deprecated and has no replacement. Remove or find a replacement in OpenTelemetry semantic conventions.` ); } else { console.warn( `[autotel/attributes] Attribute "${key}" is deprecated. Use "${replacement2}" instead.` ); } } if (deprecatedWarnings[key]) { console.warn(`[autotel/attributes] ${deprecatedWarnings[key]}`); } const replacement = DEPRECATED_ATTRIBUTES[key]; return replacement ?? null; } function autoRedactPII(attributes, policy = {}) { const { guardrails = { pii: "redact" } } = policy; const redacted = {}; for (const [key, value] of Object.entries(attributes)) { redacted[key] = validateAttribute(key, value, { guardrails }); } return redacted; } function defaultGuardrails() { return { pii: "redact", maxLength: 255, validateEnum: true, warnDeprecated: true }; } // src/attributes/utils.ts function mergeAttrs(...attrSets) { const result = {}; for (const attrSet of attrSets) { if (attrSet) { Object.assign(result, attrSet); } } return result; } function safeSetAttributes(span, attrs2, policy) { const mergedGuardrails = { ...defaultGuardrails(), ...policy?.guardrails }; const effectivePolicy = { ...policy, guardrails: mergedGuardrails }; const validated = autoRedactPII(attrs2, effectivePolicy); const sanitizedAttrs = {}; for (const [key, value] of Object.entries(validated)) { if (value !== void 0) { checkDeprecatedAttribute(key, effectivePolicy); const validatedValue = validateAttribute(key, value, effectivePolicy); if (validatedValue !== void 0) { sanitizedAttrs[key] = validatedValue; } } } span.setAttributes(sanitizedAttrs); } // src/attributes/attachers.ts function setUser(spanOrContext, data, guardrails) { const attributes = attrs.user.data(data); safeSetAttributes(spanOrContext, attributes, guardrails); } function setSession(spanOrContext, data, guardrails) { const attributes = attrs.session.data(data); safeSetAttributes(spanOrContext, attributes, guardrails); } function setDevice(spanOrContext, data, guardrails) { const attributes = attrs.device.data(data); safeSetAttributes(spanOrContext, attributes, guardrails); } function httpServer(spanOrContext, data, guardrails) { const attributes = attrs.http.server(data); if ("updateName" in spanOrContext && data.method && data.route) { const span = spanOrContext; span.updateName(`HTTP ${data.method} ${data.route}`); } safeSetAttributes(spanOrContext, attributes, guardrails); } function httpClient(spanOrContext, data, guardrails) { const attributes = attrs.http.client(data); safeSetAttributes(spanOrContext, attributes, guardrails); } function dbClient(spanOrContext, data, guardrails) { const attributes = attrs.db.client.data(data); safeSetAttributes(spanOrContext, attributes, guardrails); } function mergeServiceResource(resource, data) { const attributes = attrs.service.data(data); return resource.merge(resourceFromAttributes(attributes)); } function identify(spanOrContext, data, guardrails) { const allAttrs = []; if (data.user) { allAttrs.push(attrs.user.data(data.user)); } if (data.session) { allAttrs.push(attrs.session.data(data.session)); } if (data.device) { allAttrs.push(attrs.device.data(data.device)); } const merged = {}; for (const attrSet of allAttrs) { Object.assign(merged, attrSet); } safeSetAttributes(spanOrContext, merged, guardrails); } function request(spanOrContext, data, guardrails) { const httpAttrs = attrs.http.server(data); const networkAttrs = attrs.network.peerAddress(data.clientIp || ""); const merged = { ...httpAttrs, ...networkAttrs }; safeSetAttributes(spanOrContext, merged, guardrails); } function setError(spanOrContext, data, guardrails) { const attributes = attrs.error.data(data); safeSetAttributes(spanOrContext, attributes, guardrails); } function setException(spanOrContext, data, guardrails) { const attributes = attrs.exception.data(data); safeSetAttributes(spanOrContext, attributes, guardrails); } // src/attributes/domains.ts function transaction(spanOrContext, config, guardrails) { const userAttrs = attrs.user.data(config.user || {}); const sessionAttrs = attrs.session.data(config.session || {}); const httpAttrs = attrs.http.server({ method: config.method, route: config.route, statusCode: config.statusCode }); const networkAttrs = attrs.network.peerAddress(config.clientIp || ""); const merged = { ...userAttrs, ...sessionAttrs, ...httpAttrs, ...networkAttrs }; if (config.method && config.route && "updateName" in spanOrContext) { spanOrContext.updateName(`HTTP ${config.method} ${config.route}`); } safeSetAttributes(spanOrContext, merged, guardrails); } export { attrs, autoRedactPII, checkDeprecatedAttribute, dbClient, defaultGuardrails, httpClient, httpServer, identify, mergeAttrs, mergeServiceResource, request, safeSetAttributes, setDevice, setError, setException, setSession, setUser, transaction, validateAttribute }; //# sourceMappingURL=chunk-ER43K7ES.js.map //# sourceMappingURL=chunk-ER43K7ES.js.map