UNPKG

@sentry/remix

Version:
155 lines (130 loc) 4.67 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const core = require('@sentry/core'); const debugBuild = require('./debug-build.js'); const response = require('./vendor/response.js'); /** * Store configured FormData keys as span attributes for Remix actions. */ async function storeFormDataKeys( args, span, formDataKeys, ) { try { // We clone the request for Remix be able to read the FormData later. const clonedRequest = args.request.clone(); // This only will return the last name of multiple file uploads in a single FormData entry. // We can switch to `unstable_parseMultipartFormData` when it's stable. // https://remix.run/docs/en/main/utils/parse-multipart-form-data#unstable_parsemultipartformdata const formData = await clonedRequest.formData(); formData.forEach((value, key) => { let attrKey = key; if (formDataKeys?.[key]) { if (typeof formDataKeys[key] === 'string') { attrKey = formDataKeys[key]; } span.setAttribute( `remix.action_form_data.${attrKey}`, typeof value === 'string' ? value : '[non-string value]', ); } }); } catch (e) { debugBuild.DEBUG_BUILD && core.debug.warn('Failed to read FormData from request', e); } } /** * Converts Remix route IDs to parameterized paths at runtime. * (e.g., "routes/users.$id" -> "/users/:id") * * @param routeId - The Remix route ID * @returns The parameterized path * @internal */ function convertRemixRouteIdToPath(routeId) { // Remove the "routes/" prefix if present const path = routeId.replace(/^routes\//, ''); // Handle root index route if (path === 'index' || path === '_index') { return '/'; } // Split by dots to get segments const segments = path.split('.'); const pathSegments = []; for (let i = 0; i < segments.length; i++) { const segment = segments[i]; if (!segment) { continue; } // Skip layout route segments (prefixed with _) if (segment.startsWith('_') && segment !== '_index') { continue; } // Handle '_index' segments at the end (always skip - indicates an index route) if (segment === '_index' && i === segments.length - 1) { continue; } // Handle 'index' segments at the end (skip only if there are path segments, // otherwise root index is handled by the early return above) if (segment === 'index' && i === segments.length - 1 && pathSegments.length > 0) { continue; } // Handle splat routes (catch-all) // Remix accesses splat params via params["*"] at runtime if (segment === '$') { pathSegments.push(':*'); continue; } // Handle dynamic segments (prefixed with $) if (segment.startsWith('$')) { const paramName = segment.substring(1); pathSegments.push(`:${paramName}`); } else if (segment !== 'index') { // Static segment (skip remaining 'index' segments) pathSegments.push(segment); } } // Return with leading slash for consistency with client-side URL paths const routePath = pathSegments.length > 0 ? `/${pathSegments.join('/')}` : '/'; return routePath; } /** Check if running in Cloudflare Workers environment. */ function isCloudflareEnv() { // eslint-disable-next-line no-restricted-globals return typeof navigator !== 'undefined' && navigator?.userAgent?.includes('Cloudflare'); } /** * Get transaction name from routes and url */ function getTransactionName(routes, url) { const matches = response.matchServerRoutes(routes, url.pathname); const match = matches && response.getRequestMatch(url, matches); if (match === null) { return [url.pathname, 'url']; } const routeId = match.route.id || 'no-route-id'; // Convert route ID to parameterized path (e.g., "routes/users.$id" -> "/users/:id") // This is a pure string transformation that works without the Vite plugin manifest const parameterizedPath = convertRemixRouteIdToPath(routeId); return [parameterizedPath, 'route']; } /** * Creates routes from the server route manifest * * @param manifest * @param parentId */ function createRoutes(manifest, parentId) { return Object.entries(manifest) .filter(([, route]) => route.parentId === parentId) .map(([id, route]) => ({ ...route, children: createRoutes(manifest, id), })) ; } exports.convertRemixRouteIdToPath = convertRemixRouteIdToPath; exports.createRoutes = createRoutes; exports.getTransactionName = getTransactionName; exports.isCloudflareEnv = isCloudflareEnv; exports.storeFormDataKeys = storeFormDataKeys; //# sourceMappingURL=utils.js.map