@realtek/core-theme 0.0.318 → 0.0.319

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.
Files changed (43) hide show
  1. package/dist-lib/Breadcrumb-C4g4beys.cjs +5 -0
  2. package/dist-lib/Breadcrumb-C4g4beys.cjs.map +1 -0
  3. package/dist-lib/{Breadcrumb-C8JV1weU.js → Breadcrumb-CUZKsniF.js} +1533 -1418
  4. package/dist-lib/Breadcrumb-CUZKsniF.js.map +1 -0
  5. package/dist-lib/addFormApi-B8wJfZdE.js +53 -0
  6. package/dist-lib/{addFormApi-CuFRO2TI.js.map → addFormApi-B8wJfZdE.js.map} +1 -1
  7. package/dist-lib/addFormApi-CFSqio1D.cjs +2 -0
  8. package/dist-lib/{addFormApi-DBFdfv0-.cjs.map → addFormApi-CFSqio1D.cjs.map} +1 -1
  9. package/dist-lib/authApi-DieKJTds.cjs +2 -0
  10. package/dist-lib/{authApi-qTqKoZ1I.cjs.map → authApi-DieKJTds.cjs.map} +1 -1
  11. package/dist-lib/{authApi-cJpMRgNq.js → authApi-KeciU9Ow.js} +103 -85
  12. package/dist-lib/{authApi-cJpMRgNq.js.map → authApi-KeciU9Ow.js.map} +1 -1
  13. package/dist-lib/{diceCandidateMapper-BKRGwz7g.js → diceCandidateMapper-CjMFuVFe.js} +50 -42
  14. package/dist-lib/{diceCandidateMapper-BKRGwz7g.js.map → diceCandidateMapper-CjMFuVFe.js.map} +1 -1
  15. package/dist-lib/diceCandidateMapper-G6mMmRda.cjs +2 -0
  16. package/dist-lib/{diceCandidateMapper-MB-yyU21.cjs.map → diceCandidateMapper-G6mMmRda.cjs.map} +1 -1
  17. package/dist-lib/formGroupsCache-Bbz-28ws.cjs +2 -0
  18. package/dist-lib/{formGroupsCache-Bw0aY136.cjs.map → formGroupsCache-Bbz-28ws.cjs.map} +1 -1
  19. package/dist-lib/formGroupsCache-JeC59oNe.js +24 -0
  20. package/dist-lib/{formGroupsCache-CdBtIpe0.js.map → formGroupsCache-JeC59oNe.js.map} +1 -1
  21. package/dist-lib/index.cjs +10 -10
  22. package/dist-lib/index.cjs.map +1 -1
  23. package/dist-lib/index.js +8505 -8431
  24. package/dist-lib/index.js.map +1 -1
  25. package/dist-lib/rolldown-runtime-Chgba0Kb.cjs +1 -0
  26. package/dist-lib/rolldown-runtime-Dy4uBu1J.js +11 -0
  27. package/dist-lib/style.css +1 -1
  28. package/package.json +5 -1
  29. package/dist-lib/Breadcrumb-C8JV1weU.js.map +0 -1
  30. package/dist-lib/Breadcrumb-CnVqsNfZ.cjs +0 -3
  31. package/dist-lib/Breadcrumb-CnVqsNfZ.cjs.map +0 -1
  32. package/dist-lib/addFormApi-CuFRO2TI.js +0 -47
  33. package/dist-lib/addFormApi-DBFdfv0-.cjs +0 -2
  34. package/dist-lib/addFormApi-DtOvWQ0Z.js +0 -2
  35. package/dist-lib/authApi-bAKRYcVy.cjs +0 -1
  36. package/dist-lib/authApi-f5UkjakT.js +0 -2
  37. package/dist-lib/authApi-qTqKoZ1I.cjs +0 -2
  38. package/dist-lib/diceCandidateMapper-CB9x_ZiS.js +0 -2
  39. package/dist-lib/diceCandidateMapper-CCsJWM_a.cjs +0 -1
  40. package/dist-lib/diceCandidateMapper-MB-yyU21.cjs +0 -2
  41. package/dist-lib/formGroupsCache-Bw0aY136.cjs +0 -2
  42. package/dist-lib/formGroupsCache-CdBtIpe0.js +0 -20
  43. package/dist-lib/formGroupsCache-DTmvHD80.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"authApi-cJpMRgNq.js","names":[],"sources":["../src/services/apiConfig.js","../src/services/authApi.js"],"sourcesContent":["// Central API base URLs.\n//\n// When CORE-THEME runs standalone (npm run dev), the values come from\n// src/services/.env (Vite VITE_* vars, baked in at build time).\n//\n// When CORE-THEME is consumed as the published @realtek/core-theme package,\n// host apps can override these values at RUNTIME by setting\n// `window.__CORE_THEME_CONFIG__` before the app renders:\n//\n// <script>\n// window.__CORE_THEME_CONFIG__ = {\n// VITE_AUTH_URL: 'http://192.168.1.66/authapi/v1',\n// VITE_SUBMISSIONS_URL: 'http://192.168.1.66/submissionsapi/v1',\n// VITE_JOBS_URL: 'http://192.168.1.66/jobsapi/v1',\n// VITE_CANDIDATES_URL: 'http://192.168.1.66/candidatesapi/v1',\n// VITE_APP_ID: 'zinnext', // sent as the `X-App-Id` header on every API call\n// VITE_ADMIN_APP_ID: 'zinnext', // optional admin override\n// };\n// </script>\n//\n// Priority: runtime window config > build-time .env fallback.\n\nconst BUILD_TIME_FALLBACK = {\n VITE_AUTH_URL: import.meta.env.VITE_AUTH_URL,\n VITE_ADMIN_API_URL: import.meta.env.VITE_ADMIN_API_URL,\n VITE_ADMIN_APP_ID: import.meta.env.VITE_ADMIN_APP_ID,\n VITE_SUBMISSIONS_URL: import.meta.env.VITE_SUBMISSIONS_URL,\n VITE_JOBS_URL: import.meta.env.VITE_JOBS_URL,\n VITE_CANDIDATES_URL: import.meta.env.VITE_CANDIDATES_URL,\n VITE_PYOPS_URL: import.meta.env.VITE_PYOPS_URL,\n VITE_APP_ID: import.meta.env.VITE_APP_ID,\n};\n\nfunction resolve(key) {\n if (\n typeof window !== 'undefined' &&\n window.__CORE_THEME_CONFIG__ &&\n window.__CORE_THEME_CONFIG__[key] != null\n ) {\n return window.__CORE_THEME_CONFIG__[key];\n }\n return BUILD_TIME_FALLBACK[key];\n}\n\nfunction runtimeValue(key, fallback = '') {\n return {\n toString: () => resolve(key) || (typeof fallback === 'function' ? fallback() : fallback),\n valueOf: () => resolve(key) || (typeof fallback === 'function' ? fallback() : fallback),\n [Symbol.toPrimitive]: () => resolve(key) || (typeof fallback === 'function' ? fallback() : fallback),\n };\n}\n\n// These are intentionally dynamic. Many service files use them inside template\n// literals (`${AUTH_URL}/path`) or pass them to helpers that later build a URL.\n// Resolving at string-conversion time prevents a published package from\n// freezing CORE-THEME's own .env values into consuming apps and Docker builds.\nexport const AUTH_URL = runtimeValue('VITE_AUTH_URL');\nexport const ADMIN_API_URL = runtimeValue(\n 'VITE_ADMIN_API_URL',\n () => resolve('VITE_AUTH_URL') || 'http://localhost:9009',\n);\nexport const ADMIN_APP_ID = runtimeValue('VITE_ADMIN_APP_ID', () => resolve('VITE_APP_ID') || 'zinnext-dev-api-v1');\nexport const SUBMISSIONS_URL = runtimeValue('VITE_SUBMISSIONS_URL');\nexport const JOBS_URL = runtimeValue('VITE_JOBS_URL');\nexport const CANDIDATES_URL = runtimeValue('VITE_CANDIDATES_URL');\nexport const PYOPS_URL = runtimeValue('VITE_PYOPS_URL', 'http://localhost:7020/v1');\n\n// App identifier sent as the `X-App-Id` header on every API request (e.g.\n// 'zinnext', 'lms'). Configured in ONE place — the host's window config (or the\n// build-time .env fallback) — and applied to all calls via the interceptor below.\nexport const APP_ID = runtimeValue('VITE_APP_ID');\n\n// Helper for code that builds headers explicitly: merges `X-App-Id` into a\n// header object without clobbering anything else. (The interceptor below already\n// covers existing calls; this is just a convenience for new code.)\nexport function withAppId(headers = {}) {\n const appId = resolve('VITE_APP_ID');\n return appId ? { 'X-App-Id': appId, ...headers } : { ...headers };\n}\n\nexport function withAdminAppId(headers = {}) {\n const appId = resolve('VITE_ADMIN_APP_ID') || resolve('VITE_APP_ID') || 'zinnext-dev-api-v1';\n return appId ? { 'X-App-Id': appId, ...headers } : { ...headers };\n}\n\n// ── X-App-Id interceptor ──────────────────────────────────────────────────────\n//\n// Rather than editing every inline `headers: {...}` across the service files\n// (and risking new calls forgetting it), we patch `fetch` ONCE so every request\n// to a configured API base URL carries `X-App-Id`. This is scoped strictly to the\n// four API origins, so third-party/asset requests are never touched, and any\n// caller that already set `X-App-Id` explicitly is left as-is.\nfunction installAppIdInterceptor() {\n if (typeof window === 'undefined' || typeof window.fetch !== 'function') return;\n // Guard against double-patching (repeated imports / Vite HMR).\n if (window.__CORE_THEME_APP_ID_PATCHED__) return;\n\n const apiBaseUrls = [AUTH_URL, ADMIN_API_URL, SUBMISSIONS_URL, JOBS_URL, CANDIDATES_URL, PYOPS_URL];\n const originalFetch = window.fetch.bind(window);\n\n const urlOf = (input) => {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.href;\n if (input && typeof input.url === 'string') return input.url; // Request object\n return '';\n };\n const isApiRequest = (url) =>\n !!url && apiBaseUrls.some((base) => {\n const value = String(base);\n return value && url.startsWith(value);\n });\n\n window.fetch = function patchedFetch(input, init) {\n try {\n const url = urlOf(input);\n const isAdminRequest = String(ADMIN_API_URL) && url.startsWith(String(ADMIN_API_URL));\n const appId = isAdminRequest\n ? (resolve('VITE_ADMIN_APP_ID') || resolve('VITE_APP_ID') || 'zinnext-dev-api-v1')\n : resolve('VITE_APP_ID');\n if (appId && isApiRequest(url)) {\n const isRequestObj = typeof Request !== 'undefined' && input instanceof Request;\n const headers = new Headers(\n (init && init.headers) || (isRequestObj ? input.headers : undefined),\n );\n if (!headers.has('X-App-Id')) headers.set('X-App-Id', appId);\n if (isRequestObj && !(init && init.headers)) {\n return originalFetch(new Request(input, { headers }), init);\n }\n return originalFetch(input, { ...(init || {}), headers });\n }\n } catch {\n // Any unexpected argument shape: fall through to the untouched request.\n }\n return originalFetch(input, init);\n };\n\n window.__CORE_THEME_APP_ID_PATCHED__ = true;\n}\n\ninstallAppIdInterceptor();\n\n// Optional JS helper (alternative to the index.html <script>). Because the\n// exports above are resolved when this module first loads, call this BEFORE the\n// first import of @realtek/core-theme — e.g. in the host's index.html, not in\n// main.jsx (which runs after imports are evaluated). The index.html <script>\n// approach is the reliable one.\nexport function configureCoreTheme(config = {}) {\n if (typeof window === 'undefined') return;\n window.__CORE_THEME_CONFIG__ = { ...(window.__CORE_THEME_CONFIG__ || {}), ...config };\n installAppIdInterceptor();\n}\n","import { AUTH_URL } from './apiConfig';\n\nconst AUTH_TOKEN_KEY = 'authToken';\nconst AUTH_USER_KEY = 'authUser';\nconst AUTH_LOGIN_SESSION_KEY = 'authLoginSession';\nconst CT_PROJECT_ID_KEY = 'ct_project_id';\nconst CT_PROJECT_NAME_KEY = 'ct_project_name';\nconst LOGIN_STORAGE_KEYS = [\n 'access_token', 'refresh_token', 'id_token', 'token_type', 'expires_in',\n 'refresh_expires_in', 'menu', 'footermenu', 'menuPermission', 'default_values',\n 'roleId', 'companyName', 'preferred_Username', 'user_Email', 'userName',\n 'userId', 'tenantId', 'businessId', 'businessUnitId', 'activeKey',\n 'ct_project_id', 'ct_project_name',\n];\n\nlet loginPromise = null;\nlet runtimeAuthToken = null;\n\nexport function setAuthTokenOverride(token) {\n runtimeAuthToken = typeof token === 'string' && token.trim() ? token.trim() : null;\n}\n\nexport function clearAuthTokenOverride() {\n runtimeAuthToken = null;\n}\n\nfunction extractToken(json) {\n return (\n json?.token ?? json?.access_token ?? json?.accessToken ?? json?.jwt ??\n json?.data?.token ?? json?.data?.access_token ?? json?.data?.accessToken ?? json?.data?.jwt\n );\n}\n\nfunction extractUser(json) {\n return json?.user ?? json?.data?.user ?? json?.data?.profile ?? null;\n}\n\nfunction decodeJwtPayload(token) {\n if (!token || typeof token !== 'string') return null;\n try {\n const payload = token.split('.')[1];\n if (!payload) return null;\n const normalized = payload.replace(/-/g, '+').replace(/_/g, '/');\n return JSON.parse(atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=')));\n } catch {\n return null;\n }\n}\n\nfunction setLocalStorageJson(key, value) {\n if (value === undefined || value === null) return;\n localStorage.setItem(key, JSON.stringify(value));\n}\n\nfunction getLoginMenus(json, data) {\n return data?.menus ?? json?.menus ?? {\n menu: data?.menu ?? json?.menu,\n footermenu: data?.footermenu ?? json?.footermenu,\n };\n}\n\nfunction persistLoginResponse(json, token, user) {\n const data = json?.data ?? json;\n const tokenPayload = decodeJwtPayload(token) ?? {};\n const menus = getLoginMenus(json, data);\n const userName = (\n user?.userName ?? user?.name ?? data?.userName ?? data?.name ??\n tokenPayload.userName ?? tokenPayload.name ?? tokenPayload.preferred_username ?? tokenPayload.email\n );\n const preferredUsername = (\n user?.preferred_Username ?? user?.preferred_username ??\n data?.preferred_Username ?? data?.preferred_username ??\n tokenPayload.preferred_Username ?? tokenPayload.preferred_username ??\n tokenPayload.email ?? userName\n );\n const userEmail = user?.email ?? data?.email ?? tokenPayload.email ?? preferredUsername;\n\n localStorage.setItem('access_token', token);\n if (data?.refresh_token) localStorage.setItem('refresh_token', data.refresh_token);\n if (data?.id_token !== undefined) localStorage.setItem('id_token', data.id_token);\n if (data?.token_type) localStorage.setItem('token_type', data.token_type);\n if (data?.expires_in !== undefined) localStorage.setItem('expires_in', String(data.expires_in));\n if (data?.refresh_expires_in !== undefined) localStorage.setItem('refresh_expires_in', String(data.refresh_expires_in));\n if (userName) localStorage.setItem('userName', userName);\n if (preferredUsername) localStorage.setItem('preferred_Username', preferredUsername);\n if (userEmail) localStorage.setItem('user_Email', userEmail);\n if (data?.roleId ?? tokenPayload.role_id) localStorage.setItem('roleId', data?.roleId ?? tokenPayload.role_id);\n if (data?.companyName) localStorage.setItem('companyName', data.companyName);\n if (tokenPayload.userId !== undefined) localStorage.setItem('userId', String(tokenPayload.userId));\n if (tokenPayload.tenantId) localStorage.setItem('tenantId', tokenPayload.tenantId);\n if (tokenPayload.businessId) localStorage.setItem('businessId', tokenPayload.businessId);\n if (tokenPayload.businessUnitId) localStorage.setItem('businessUnitId', tokenPayload.businessUnitId);\n\n setLocalStorageJson('menu', menus.menu);\n setLocalStorageJson('footermenu', menus.footermenu);\n setLocalStorageJson('menuPermission', data?.menuPermission);\n setLocalStorageJson('default_values', data?.default_values);\n}\n\n// ── Token & Session ──────────────────────────────────────────────────────────\n\nexport function getStoredToken() {\n if (runtimeAuthToken) return runtimeAuthToken;\n const token = localStorage.getItem(AUTH_TOKEN_KEY);\n const hasSession = sessionStorage.getItem(AUTH_LOGIN_SESSION_KEY) === '1';\n return token && hasSession ? token : null;\n}\n\nexport function getStoredUser() {\n try {\n const stored = localStorage.getItem(AUTH_USER_KEY);\n if (stored) return JSON.parse(stored);\n } catch {\n // Fall through to the legacy login fields below.\n }\n return {\n userId: localStorage.getItem('userId'),\n username: localStorage.getItem('userName') || localStorage.getItem('preferred_Username'),\n email: localStorage.getItem('user_Email'),\n roleId: localStorage.getItem('roleId'),\n };\n}\n\nexport function logout() {\n localStorage.removeItem(AUTH_TOKEN_KEY);\n localStorage.removeItem(AUTH_USER_KEY);\n LOGIN_STORAGE_KEYS.forEach((key) => localStorage.removeItem(key));\n sessionStorage.removeItem(AUTH_LOGIN_SESSION_KEY);\n window.dispatchEvent(new Event('auth:logout'));\n}\n\n// ── Role Helpers ─────────────────────────────────────────────────────────────\n\nexport function getCurrentRoleName() {\n const stored = String(localStorage.getItem('roleId') ?? '').trim().toLowerCase();\n if (stored) return stored;\n const payload = decodeJwtPayload(getStoredToken()) ?? {};\n return String(payload.role ?? payload.roleName ?? payload.role_name ?? payload.role_id ?? payload.roleId ?? '').trim().toLowerCase();\n}\n\nexport function getUserRoles() {\n const token = getStoredToken() ?? localStorage.getItem(AUTH_TOKEN_KEY);\n const payload = decodeJwtPayload(token);\n const roles = new Set();\n const stored = getCurrentRoleName();\n if (stored) roles.add(stored);\n if (payload) {\n (payload?.realm_access?.roles ?? []).forEach((role) => roles.add(role));\n Object.values(payload?.resource_access ?? {}).forEach((client) => {\n (client?.roles ?? []).forEach((role) => roles.add(role));\n });\n [payload?.role, payload?.roleName, payload?.role_name].forEach((role) => {\n if (role) roles.add(role);\n });\n }\n return Array.from(roles).map((role) => String(role).toLowerCase());\n}\n\nexport function isTester() {\n return getCurrentRoleName() === 'tester' || getUserRoles().includes('tester');\n}\n\n// getActingIdentity returns the numeric {roleId, userId} of the logged-in user,\n// read from the auth token (falling back to the stored roleId). Used to evaluate\n// admin-configured field autoValueRules for UX only — the gateway re-evaluates\n// the same rules from the token and has the final say, so nothing here is a\n// security boundary.\nexport function getActingIdentity() {\n const payload = decodeJwtPayload(getStoredToken() ?? localStorage.getItem(AUTH_TOKEN_KEY)) ?? {};\n const num = (value) => {\n if (value === undefined || value === null || value === '') return undefined;\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n };\n return {\n roleId: num(payload.role_id ?? payload.roleId) ?? num(localStorage.getItem('roleId')),\n userId: num(payload.userId ?? payload.user_id),\n };\n}\n\n// ── Project Context ───────────────────────────────────────────────────────────\n\nexport function setSelectedProject(project) {\n if (!project) return;\n localStorage.setItem(CT_PROJECT_ID_KEY, String(project.id));\n localStorage.setItem(CT_PROJECT_NAME_KEY, String(project.name));\n}\n\nexport function getSelectedProject() {\n const id = localStorage.getItem(CT_PROJECT_ID_KEY);\n const name = localStorage.getItem(CT_PROJECT_NAME_KEY);\n if (!id || !name) return null;\n return { id: Number(id), name };\n}\n\nexport function clearSelectedProject() {\n localStorage.removeItem(CT_PROJECT_ID_KEY);\n localStorage.removeItem(CT_PROJECT_NAME_KEY);\n}\n\n// ── Login ────────────────────────────────────────────────────────────────────\n\nexport async function login(credentials) {\n if (loginPromise) return loginPromise;\n\n loginPromise = fetch(`${AUTH_URL}/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(credentials),\n })\n .then(async (res) => {\n const json = await res.json();\n if (!res.ok) {\n const error = new Error(json?.message ?? json?.error ?? `Login failed: ${res.status}`);\n error.status = res.status;\n throw error;\n }\n const token = extractToken(json);\n if (!token) throw new Error('No token in login response');\n const user = extractUser(json);\n localStorage.setItem(AUTH_TOKEN_KEY, token);\n sessionStorage.setItem(AUTH_LOGIN_SESSION_KEY, '1');\n if (user) localStorage.setItem(AUTH_USER_KEY, JSON.stringify(user));\n persistLoginResponse(json, token, user);\n // Let any mounted AuthGuard re-check and reveal the protected content.\n window.dispatchEvent(new Event('auth:login'));\n return { token, user, response: json };\n })\n .finally(() => { loginPromise = null; });\n\n return loginPromise;\n}\n\n// ── HTTP Helpers (exported for use by other service files) ───────────────────\n\nexport async function ensureToken() {\n const token = getStoredToken();\n if (token) return token;\n const error = new Error('Authentication required');\n error.status = 401;\n throw error;\n}\n\nasync function authHeaders() {\n const token = await ensureToken();\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n };\n}\n\nexport async function fetchJsonWithAuth(baseUrl, path = '', options = {}) {\n if (path && typeof path === 'object') {\n options = path;\n path = '';\n }\n\n const headers = await authHeaders();\n const res = await fetch(`${baseUrl}${path || ''}`, {\n ...options,\n headers: { ...headers, ...options.headers },\n });\n if (res.status === 401) logout();\n const text = await res.text();\n let json = {};\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n json = { error: text };\n }\n }\n if (!res.ok) {\n const responseError = json?.error ?? json?.message;\n const detail = typeof responseError === 'string'\n ? responseError\n : responseError && Object.keys(responseError).length > 0\n ? JSON.stringify(responseError)\n : '';\n const error = new Error(detail || `API ${res.status}: ${res.statusText}`);\n error.status = res.status;\n error.response = json;\n throw error;\n }\n return json;\n}\n\nexport async function apiGetWithAuth(baseUrl, path) {\n const json = await fetchJsonWithAuth(baseUrl, path);\n return json.data ?? json;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"authApi-KeciU9Ow.js","names":[],"sources":["../src/services/apiConfig.js","../src/services/authApi.js"],"sourcesContent":["// Central API base URLs.\n//\n// When CORE-THEME runs standalone (npm run dev), the values come from\n// src/services/.env (Vite VITE_* vars, baked in at build time).\n//\n// When CORE-THEME is consumed as the published @realtek/core-theme package,\n// host apps can override these values at RUNTIME by setting\n// `window.__CORE_THEME_CONFIG__` before the app renders:\n//\n// <script>\n// window.__CORE_THEME_CONFIG__ = {\n// VITE_AUTH_URL: 'http://192.168.1.66/authapi/v1',\n// VITE_SUBMISSIONS_URL: 'http://192.168.1.66/submissionsapi/v1',\n// VITE_JOBS_URL: 'http://192.168.1.66/jobsapi/v1',\n// VITE_CANDIDATES_URL: 'http://192.168.1.66/candidatesapi/v1',\n// VITE_APP_ID: 'zinnext', // sent as the `X-App-Id` header on every API call\n// VITE_ADMIN_APP_ID: 'zinnext', // optional admin override\n// };\n// </script>\n//\n// Priority: runtime window config > build-time .env fallback.\n\nconst BUILD_TIME_FALLBACK = {\n VITE_AUTH_URL: import.meta.env.VITE_AUTH_URL,\n VITE_ADMIN_API_URL: import.meta.env.VITE_ADMIN_API_URL,\n VITE_ADMIN_APP_ID: import.meta.env.VITE_ADMIN_APP_ID,\n VITE_SUBMISSIONS_URL: import.meta.env.VITE_SUBMISSIONS_URL,\n VITE_JOBS_URL: import.meta.env.VITE_JOBS_URL,\n VITE_CANDIDATES_URL: import.meta.env.VITE_CANDIDATES_URL,\n VITE_PYOPS_URL: import.meta.env.VITE_PYOPS_URL,\n VITE_APP_ID: import.meta.env.VITE_APP_ID,\n};\n\nfunction resolve(key) {\n if (\n typeof window !== 'undefined' &&\n window.__CORE_THEME_CONFIG__ &&\n window.__CORE_THEME_CONFIG__[key] != null\n ) {\n return window.__CORE_THEME_CONFIG__[key];\n }\n return BUILD_TIME_FALLBACK[key];\n}\n\nfunction runtimeValue(key, fallback = '') {\n return {\n toString: () => resolve(key) || (typeof fallback === 'function' ? fallback() : fallback),\n valueOf: () => resolve(key) || (typeof fallback === 'function' ? fallback() : fallback),\n [Symbol.toPrimitive]: () => resolve(key) || (typeof fallback === 'function' ? fallback() : fallback),\n };\n}\n\n// These are intentionally dynamic. Many service files use them inside template\n// literals (`${AUTH_URL}/path`) or pass them to helpers that later build a URL.\n// Resolving at string-conversion time prevents a published package from\n// freezing CORE-THEME's own .env values into consuming apps and Docker builds.\nexport const AUTH_URL = runtimeValue('VITE_AUTH_URL');\nexport const ADMIN_API_URL = runtimeValue(\n 'VITE_ADMIN_API_URL',\n () => resolve('VITE_AUTH_URL') || 'http://localhost:9009',\n);\nexport const ADMIN_APP_ID = runtimeValue('VITE_ADMIN_APP_ID', () => resolve('VITE_APP_ID') || 'zinnext-dev-api-v1');\nexport const SUBMISSIONS_URL = runtimeValue('VITE_SUBMISSIONS_URL');\nexport const JOBS_URL = runtimeValue('VITE_JOBS_URL');\nexport const CANDIDATES_URL = runtimeValue('VITE_CANDIDATES_URL');\nexport const PYOPS_URL = runtimeValue('VITE_PYOPS_URL', 'http://localhost:7020/v1');\n\n// App identifier sent as the `X-App-Id` header on every API request (e.g.\n// 'zinnext', 'lms'). Configured in ONE place — the host's window config (or the\n// build-time .env fallback) — and applied to all calls via the interceptor below.\nexport const APP_ID = runtimeValue('VITE_APP_ID');\n\n// Helper for code that builds headers explicitly: merges `X-App-Id` into a\n// header object without clobbering anything else. (The interceptor below already\n// covers existing calls; this is just a convenience for new code.)\nexport function withAppId(headers = {}) {\n const appId = resolve('VITE_APP_ID');\n return appId ? { 'X-App-Id': appId, ...headers } : { ...headers };\n}\n\nexport function withAdminAppId(headers = {}) {\n const appId = resolve('VITE_ADMIN_APP_ID') || resolve('VITE_APP_ID') || 'zinnext-dev-api-v1';\n return appId ? { 'X-App-Id': appId, ...headers } : { ...headers };\n}\n\n// ── X-App-Id interceptor ──────────────────────────────────────────────────────\n//\n// Rather than editing every inline `headers: {...}` across the service files\n// (and risking new calls forgetting it), we patch `fetch` ONCE so every request\n// to a configured API base URL carries `X-App-Id`. This is scoped strictly to the\n// four API origins, so third-party/asset requests are never touched, and any\n// caller that already set `X-App-Id` explicitly is left as-is.\nfunction installAppIdInterceptor() {\n if (typeof window === 'undefined' || typeof window.fetch !== 'function') return;\n // Guard against double-patching (repeated imports / Vite HMR).\n if (window.__CORE_THEME_APP_ID_PATCHED__) return;\n\n const apiBaseUrls = [AUTH_URL, ADMIN_API_URL, SUBMISSIONS_URL, JOBS_URL, CANDIDATES_URL, PYOPS_URL];\n const originalFetch = window.fetch.bind(window);\n\n const urlOf = (input) => {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.href;\n if (input && typeof input.url === 'string') return input.url; // Request object\n return '';\n };\n const isApiRequest = (url) =>\n !!url && apiBaseUrls.some((base) => {\n const value = String(base);\n return value && url.startsWith(value);\n });\n\n window.fetch = function patchedFetch(input, init) {\n try {\n const url = urlOf(input);\n const isAdminRequest = String(ADMIN_API_URL) && url.startsWith(String(ADMIN_API_URL));\n const appId = isAdminRequest\n ? (resolve('VITE_ADMIN_APP_ID') || resolve('VITE_APP_ID') || 'zinnext-dev-api-v1')\n : resolve('VITE_APP_ID');\n if (appId && isApiRequest(url)) {\n const isRequestObj = typeof Request !== 'undefined' && input instanceof Request;\n const headers = new Headers(\n (init && init.headers) || (isRequestObj ? input.headers : undefined),\n );\n if (!headers.has('X-App-Id')) headers.set('X-App-Id', appId);\n if (isRequestObj && !(init && init.headers)) {\n return originalFetch(new Request(input, { headers }), init);\n }\n return originalFetch(input, { ...(init || {}), headers });\n }\n } catch {\n // Any unexpected argument shape: fall through to the untouched request.\n }\n return originalFetch(input, init);\n };\n\n window.__CORE_THEME_APP_ID_PATCHED__ = true;\n}\n\ninstallAppIdInterceptor();\n\n// Optional JS helper (alternative to the index.html <script>). Because the\n// exports above are resolved when this module first loads, call this BEFORE the\n// first import of @realtek/core-theme — e.g. in the host's index.html, not in\n// main.jsx (which runs after imports are evaluated). The index.html <script>\n// approach is the reliable one.\nexport function configureCoreTheme(config = {}) {\n if (typeof window === 'undefined') return;\n window.__CORE_THEME_CONFIG__ = { ...(window.__CORE_THEME_CONFIG__ || {}), ...config };\n installAppIdInterceptor();\n}\n","import { AUTH_URL } from './apiConfig';\n\nconst AUTH_TOKEN_KEY = 'authToken';\nconst AUTH_USER_KEY = 'authUser';\nconst AUTH_LOGIN_SESSION_KEY = 'authLoginSession';\nconst CT_PROJECT_ID_KEY = 'ct_project_id';\nconst CT_PROJECT_NAME_KEY = 'ct_project_name';\nconst LOGIN_STORAGE_KEYS = [\n 'access_token', 'refresh_token', 'id_token', 'token_type', 'expires_in',\n 'refresh_expires_in', 'menu', 'footermenu', 'menuPermission', 'default_values',\n 'roleId', 'companyName', 'preferred_Username', 'user_Email', 'userName',\n 'userId', 'tenantId', 'businessId', 'businessUnitId', 'activeKey',\n 'ct_project_id', 'ct_project_name',\n];\n\nlet loginPromise = null;\nlet runtimeAuthToken = null;\n\nexport function setAuthTokenOverride(token) {\n runtimeAuthToken = typeof token === 'string' && token.trim() ? token.trim() : null;\n}\n\nexport function clearAuthTokenOverride() {\n runtimeAuthToken = null;\n}\n\nfunction extractToken(json) {\n return (\n json?.token ?? json?.access_token ?? json?.accessToken ?? json?.jwt ??\n json?.data?.token ?? json?.data?.access_token ?? json?.data?.accessToken ?? json?.data?.jwt\n );\n}\n\nfunction extractUser(json) {\n return json?.user ?? json?.data?.user ?? json?.data?.profile ?? null;\n}\n\nfunction decodeJwtPayload(token) {\n if (!token || typeof token !== 'string') return null;\n try {\n const payload = token.split('.')[1];\n if (!payload) return null;\n const normalized = payload.replace(/-/g, '+').replace(/_/g, '/');\n return JSON.parse(atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=')));\n } catch {\n return null;\n }\n}\n\nfunction setLocalStorageJson(key, value) {\n if (value === undefined || value === null) return;\n localStorage.setItem(key, JSON.stringify(value));\n}\n\nfunction getLoginMenus(json, data) {\n return data?.menus ?? json?.menus ?? {\n menu: data?.menu ?? json?.menu,\n footermenu: data?.footermenu ?? json?.footermenu,\n };\n}\n\nfunction persistLoginResponse(json, token, user) {\n const data = json?.data ?? json;\n const tokenPayload = decodeJwtPayload(token) ?? {};\n const menus = getLoginMenus(json, data);\n const userName = (\n user?.userName ?? user?.name ?? data?.userName ?? data?.name ??\n tokenPayload.userName ?? tokenPayload.name ?? tokenPayload.preferred_username ?? tokenPayload.email\n );\n const preferredUsername = (\n user?.preferred_Username ?? user?.preferred_username ??\n data?.preferred_Username ?? data?.preferred_username ??\n tokenPayload.preferred_Username ?? tokenPayload.preferred_username ??\n tokenPayload.email ?? userName\n );\n const userEmail = user?.email ?? data?.email ?? tokenPayload.email ?? preferredUsername;\n\n localStorage.setItem('access_token', token);\n if (data?.refresh_token) localStorage.setItem('refresh_token', data.refresh_token);\n if (data?.id_token !== undefined) localStorage.setItem('id_token', data.id_token);\n if (data?.token_type) localStorage.setItem('token_type', data.token_type);\n if (data?.expires_in !== undefined) localStorage.setItem('expires_in', String(data.expires_in));\n if (data?.refresh_expires_in !== undefined) localStorage.setItem('refresh_expires_in', String(data.refresh_expires_in));\n if (userName) localStorage.setItem('userName', userName);\n if (preferredUsername) localStorage.setItem('preferred_Username', preferredUsername);\n if (userEmail) localStorage.setItem('user_Email', userEmail);\n if (data?.roleId ?? tokenPayload.role_id) localStorage.setItem('roleId', data?.roleId ?? tokenPayload.role_id);\n if (data?.companyName) localStorage.setItem('companyName', data.companyName);\n if (tokenPayload.userId !== undefined) localStorage.setItem('userId', String(tokenPayload.userId));\n if (tokenPayload.tenantId) localStorage.setItem('tenantId', tokenPayload.tenantId);\n if (tokenPayload.businessId) localStorage.setItem('businessId', tokenPayload.businessId);\n if (tokenPayload.businessUnitId) localStorage.setItem('businessUnitId', tokenPayload.businessUnitId);\n\n setLocalStorageJson('menu', menus.menu);\n setLocalStorageJson('footermenu', menus.footermenu);\n setLocalStorageJson('menuPermission', data?.menuPermission);\n setLocalStorageJson('default_values', data?.default_values);\n}\n\n// ── Token & Session ──────────────────────────────────────────────────────────\n\nexport function getStoredToken() {\n if (runtimeAuthToken) return runtimeAuthToken;\n const token = localStorage.getItem(AUTH_TOKEN_KEY);\n const hasSession = sessionStorage.getItem(AUTH_LOGIN_SESSION_KEY) === '1';\n return token && hasSession ? token : null;\n}\n\nexport function getStoredUser() {\n try {\n const stored = localStorage.getItem(AUTH_USER_KEY);\n if (stored) return JSON.parse(stored);\n } catch {\n // Fall through to the legacy login fields below.\n }\n return {\n userId: localStorage.getItem('userId'),\n username: localStorage.getItem('userName') || localStorage.getItem('preferred_Username'),\n email: localStorage.getItem('user_Email'),\n roleId: localStorage.getItem('roleId'),\n };\n}\n\nexport function logout() {\n localStorage.removeItem(AUTH_TOKEN_KEY);\n localStorage.removeItem(AUTH_USER_KEY);\n LOGIN_STORAGE_KEYS.forEach((key) => localStorage.removeItem(key));\n sessionStorage.removeItem(AUTH_LOGIN_SESSION_KEY);\n window.dispatchEvent(new Event('auth:logout'));\n}\n\n// ── Role Helpers ─────────────────────────────────────────────────────────────\n\nexport function getCurrentRoleName() {\n const stored = String(localStorage.getItem('roleId') ?? '').trim().toLowerCase();\n if (stored) return stored;\n const payload = decodeJwtPayload(getStoredToken()) ?? {};\n return String(payload.role ?? payload.roleName ?? payload.role_name ?? payload.role_id ?? payload.roleId ?? '').trim().toLowerCase();\n}\n\nexport function getUserRoles() {\n const token = getStoredToken() ?? localStorage.getItem(AUTH_TOKEN_KEY);\n const payload = decodeJwtPayload(token);\n const roles = new Set();\n const stored = getCurrentRoleName();\n if (stored) roles.add(stored);\n if (payload) {\n (payload?.realm_access?.roles ?? []).forEach((role) => roles.add(role));\n Object.values(payload?.resource_access ?? {}).forEach((client) => {\n (client?.roles ?? []).forEach((role) => roles.add(role));\n });\n [payload?.role, payload?.roleName, payload?.role_name].forEach((role) => {\n if (role) roles.add(role);\n });\n }\n return Array.from(roles).map((role) => String(role).toLowerCase());\n}\n\nexport function isTester() {\n return getCurrentRoleName() === 'tester' || getUserRoles().includes('tester');\n}\n\n// getActingIdentity returns the numeric {roleId, userId} of the logged-in user,\n// read from the auth token (falling back to the stored roleId). Used to evaluate\n// admin-configured field autoValueRules for UX only — the gateway re-evaluates\n// the same rules from the token and has the final say, so nothing here is a\n// security boundary.\nexport function getActingIdentity() {\n const payload = decodeJwtPayload(getStoredToken() ?? localStorage.getItem(AUTH_TOKEN_KEY)) ?? {};\n const num = (value) => {\n if (value === undefined || value === null || value === '') return undefined;\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n };\n return {\n roleId: num(payload.role_id ?? payload.roleId) ?? num(localStorage.getItem('roleId')),\n userId: num(payload.userId ?? payload.user_id),\n };\n}\n\n// ── Project Context ───────────────────────────────────────────────────────────\n\nexport function setSelectedProject(project) {\n if (!project) return;\n localStorage.setItem(CT_PROJECT_ID_KEY, String(project.id));\n localStorage.setItem(CT_PROJECT_NAME_KEY, String(project.name));\n}\n\nexport function getSelectedProject() {\n const id = localStorage.getItem(CT_PROJECT_ID_KEY);\n const name = localStorage.getItem(CT_PROJECT_NAME_KEY);\n if (!id || !name) return null;\n return { id: Number(id), name };\n}\n\nexport function clearSelectedProject() {\n localStorage.removeItem(CT_PROJECT_ID_KEY);\n localStorage.removeItem(CT_PROJECT_NAME_KEY);\n}\n\n// ── Login ────────────────────────────────────────────────────────────────────\n\nexport async function login(credentials) {\n if (loginPromise) return loginPromise;\n\n loginPromise = fetch(`${AUTH_URL}/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(credentials),\n })\n .then(async (res) => {\n const json = await res.json();\n if (!res.ok) {\n const error = new Error(json?.message ?? json?.error ?? `Login failed: ${res.status}`);\n error.status = res.status;\n throw error;\n }\n const token = extractToken(json);\n if (!token) throw new Error('No token in login response');\n const user = extractUser(json);\n localStorage.setItem(AUTH_TOKEN_KEY, token);\n sessionStorage.setItem(AUTH_LOGIN_SESSION_KEY, '1');\n if (user) localStorage.setItem(AUTH_USER_KEY, JSON.stringify(user));\n persistLoginResponse(json, token, user);\n // Let any mounted AuthGuard re-check and reveal the protected content.\n window.dispatchEvent(new Event('auth:login'));\n return { token, user, response: json };\n })\n .finally(() => { loginPromise = null; });\n\n return loginPromise;\n}\n\n// ── HTTP Helpers (exported for use by other service files) ───────────────────\n\nexport async function ensureToken() {\n const token = getStoredToken();\n if (token) return token;\n const error = new Error('Authentication required');\n error.status = 401;\n throw error;\n}\n\nasync function authHeaders() {\n const token = await ensureToken();\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n };\n}\n\nexport async function fetchJsonWithAuth(baseUrl, path = '', options = {}) {\n if (path && typeof path === 'object') {\n options = path;\n path = '';\n }\n\n const headers = await authHeaders();\n const res = await fetch(`${baseUrl}${path || ''}`, {\n ...options,\n headers: { ...headers, ...options.headers },\n });\n if (res.status === 401) logout();\n const text = await res.text();\n let json = {};\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n json = { error: text };\n }\n }\n if (!res.ok) {\n const responseError = json?.error ?? json?.message;\n const detail = typeof responseError === 'string'\n ? responseError\n : responseError && Object.keys(responseError).length > 0\n ? JSON.stringify(responseError)\n : '';\n const error = new Error(detail || `API ${res.status}: ${res.statusText}`);\n error.status = res.status;\n error.response = json;\n throw error;\n }\n return json;\n}\n\nexport async function apiGetWithAuth(baseUrl, path) {\n const json = await fetchJsonWithAuth(baseUrl, path);\n return json.data ?? json;\n}\n"],"mappings":"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"}
@@ -1,52 +1,60 @@
1
+ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
1
2
  //#region src/services/diceCandidateMapper.js
2
- function e(...e) {
3
+ var t = /* @__PURE__ */ e({
4
+ mapDiceCandidateToInternal: () => m,
5
+ mapDiceCandidatesToInternal: () => h,
6
+ normalizeDiceSkills: () => l,
7
+ resolveDiceProfileId: () => c,
8
+ transformDiceResponseToInternalFormat: () => g
9
+ });
10
+ function n(...e) {
3
11
  return e.find((e) => e != null && String(e).trim() !== "");
4
12
  }
5
- function t(e, t) {
13
+ function r(e, t) {
6
14
  if (!(!e || !t)) return Object.prototype.hasOwnProperty.call(e, t) ? e[t] : String(t).split(".").reduce((e, t) => e?.[t], e);
7
15
  }
8
- function n(e) {
16
+ function i(e) {
9
17
  return /^[a-f0-9]{24}$/i.test(String(e ?? "").trim());
10
18
  }
11
- function r(e) {
19
+ function a(e) {
12
20
  let t = String(e ?? "").trim();
13
21
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t) || /^[a-f0-9]{40,}$/i.test(t);
14
22
  }
15
- function i(t, n) {
16
- let r = String(t ?? "").trim(), i = e(n?.candidateId, n?.customFields?.diceProfileData?.candidateId);
23
+ function o(e, t) {
24
+ let r = String(e ?? "").trim(), i = n(t?.candidateId, t?.customFields?.diceProfileData?.candidateId);
17
25
  return i && r === String(i).trim() || /^[a-f0-9]{40,}-\d+$/i.test(r);
18
26
  }
19
- function a(e) {
20
- let t = /* @__PURE__ */ new Set(), n = [], i = (e, a = "") => {
27
+ function s(e) {
28
+ let t = /* @__PURE__ */ new Set(), n = [], r = (e, i = "") => {
21
29
  if (e != null) {
22
30
  if (typeof e == "string" || typeof e == "number") {
23
- let t = String(e).trim(), i = /(^|[._-])(dice|profile|source|external).*(id|guid|uuid)$|(^|[._-])(id|guid|uuid)$/i.test(a);
24
- t && i && r(t) && n.push({
25
- path: a,
31
+ let t = String(e).trim(), r = /(^|[._-])(dice|profile|source|external).*(id|guid|uuid)$|(^|[._-])(id|guid|uuid)$/i.test(i);
32
+ t && r && a(t) && n.push({
33
+ path: i,
26
34
  value: t
27
35
  });
28
36
  return;
29
37
  }
30
38
  typeof e != "object" || t.has(e) || (t.add(e), Object.entries(e).forEach(([e, t]) => {
31
- i(t, a ? `${a}.${e}` : e);
39
+ r(t, i ? `${i}.${e}` : e);
32
40
  }));
33
41
  }
34
42
  };
35
- return i(e), n.find((e) => /dice|profile|source|external/i.test(e.path))?.value ?? n[0]?.value ?? "";
43
+ return r(e), n.find((e) => /dice|profile|source|external/i.test(e.path))?.value ?? n[0]?.value ?? "";
36
44
  }
37
- function o(r) {
38
- if (!r || typeof r != "object") return "";
39
- let o = (() => {
40
- let e = r?.sourceType ?? r?.profileSource ?? r?.selectedSource;
41
- return (Array.isArray(e) ? e : [e]).some((e) => String(e ?? "").trim().toLowerCase() === "dice");
42
- })(), s = e(...(/* @__PURE__ */ "diceId,diceID,dice_id,diceProfileId,diceProfileID,diceProfileGuid,profileId,profileID,profileGuid,sourceId,sourceProfileId,externalId,externalProfileId,customFields.diceId,customFields.diceProfileId,customFields.profileId,customFields.externalProfileId,customFields.diceProfileData.diceId,customFields.diceProfileData.diceID,customFields.diceProfileData.id,customFields.diceProfileData._id,customFields.diceProfileData.profileId,customFields.diceProfileData.profileID,customFields.diceProfileData.diceProfileId,customFields.diceProfileData.diceProfileID,customFields.diceProfileData.guid,customFields.diceProfileData.uuid,customFields.diceProfileData.externalId,customFields.diceProfileData.candidateid,customFields.diceProfileData.candidateId".split(",")).map((e) => t(r, e)));
43
- if (s && !i(s, r)) return String(s);
44
- let c = a(r);
45
+ function c(e) {
46
+ if (!e || typeof e != "object") return "";
47
+ let t = (() => {
48
+ let t = e?.sourceType ?? e?.profileSource ?? e?.selectedSource;
49
+ return (Array.isArray(t) ? t : [t]).some((e) => String(e ?? "").trim().toLowerCase() === "dice");
50
+ })(), a = n(...(/* @__PURE__ */ "diceId,diceID,dice_id,diceProfileId,diceProfileID,diceProfileGuid,profileId,profileID,profileGuid,sourceId,sourceProfileId,externalId,externalProfileId,customFields.diceId,customFields.diceProfileId,customFields.profileId,customFields.externalProfileId,customFields.diceProfileData.diceId,customFields.diceProfileData.diceID,customFields.diceProfileData.id,customFields.diceProfileData._id,customFields.diceProfileData.profileId,customFields.diceProfileData.profileID,customFields.diceProfileData.diceProfileId,customFields.diceProfileData.diceProfileID,customFields.diceProfileData.guid,customFields.diceProfileData.uuid,customFields.diceProfileData.externalId,customFields.diceProfileData.candidateid,customFields.diceProfileData.candidateId".split(",")).map((t) => r(e, t)));
51
+ if (a && !o(a, e)) return String(a);
52
+ let c = s(e);
45
53
  if (c) return c;
46
- let l = e(r.id, r._id);
47
- return l && (o || !n(l)) ? String(l) : "";
54
+ let l = n(e.id, e._id);
55
+ return l && (t || !i(l)) ? String(l) : "";
48
56
  }
49
- function s(e) {
57
+ function l(e) {
50
58
  return e ? Array.isArray(e) ? e.map((e) => {
51
59
  if (e?.skill) return e.skill;
52
60
  if (typeof e == "object" && e) {
@@ -57,7 +65,7 @@ function s(e) {
57
65
  return typeof e == "string" ? e : null;
58
66
  }).filter(Boolean) : typeof e == "string" ? e.split(",").map((e) => e.trim()).filter(Boolean) : [] : [];
59
67
  }
60
- function c(e) {
68
+ function u(e) {
61
69
  if (Array.isArray(e.locations) && e.locations.length > 0) {
62
70
  let t = e.locations[0];
63
71
  if (typeof t == "string") return t;
@@ -68,14 +76,14 @@ function c(e) {
68
76
  }
69
77
  return e.currentLocation ?? e.location ?? e.city ?? e.region ?? "";
70
78
  }
71
- function l(e) {
79
+ function d(e) {
72
80
  let t = e.totalExperience ?? e.experience ?? e.yearsOfExperience ?? e.exp ?? e.totalYearsOfExperience ?? e.workExperienceYears;
73
81
  return t != null && t !== "" ? t : null;
74
82
  }
75
- function u(e) {
83
+ function f(e) {
76
84
  return e.dateLastUpdated ?? e.updatedAt ?? e.createdAt ?? e.createdDate ?? e.dateCreated ?? null;
77
85
  }
78
- function d(e) {
86
+ function p(e) {
79
87
  let t = [
80
88
  e.firstName,
81
89
  e.middleName,
@@ -83,7 +91,7 @@ function d(e) {
83
91
  ].filter(Boolean);
84
92
  return t.length > 0 ? t.join(" ") : e.fullName ?? e.name ?? e.candidateName ?? "";
85
93
  }
86
- function f(e, t = 0) {
94
+ function m(e, t = 0) {
87
95
  if (!e || typeof e != "object") return {
88
96
  id: `dice-candidate-${t}`,
89
97
  diceId: "",
@@ -102,7 +110,7 @@ function f(e, t = 0) {
102
110
  sourceType: "dice",
103
111
  profileSource: "dice"
104
112
  };
105
- let n = d(e), r = n.split(" "), i = r[0] || "", a = r.length > 1 ? r[r.length - 1] : "", f = c(e), p = l(e), m = u(e), h = o(e), g = e.candidateId ?? e.customFields?.diceProfileData?.candidateId ?? `dice-candidate-${t}`, _ = e.skills ?? e.technicalSkills ?? e.primarySkills ?? e.keySkills ?? [], v = s(_);
113
+ let n = p(e), r = n.split(" "), i = r[0] || "", a = r.length > 1 ? r[r.length - 1] : "", o = u(e), s = d(e), m = f(e), h = c(e), g = e.candidateId ?? e.customFields?.diceProfileData?.candidateId ?? `dice-candidate-${t}`, _ = e.skills ?? e.technicalSkills ?? e.primarySkills ?? e.keySkills ?? [], v = l(_);
106
114
  return process.env.NODE_ENV === "development" && (console.log("[DiceMapper] Original skills:", _), console.log("[DiceMapper] Mapped skills:", v), console.log("[DiceMapper] Dice IDs:", {
107
115
  id: h,
108
116
  diceId: h,
@@ -120,14 +128,14 @@ function f(e, t = 0) {
120
128
  designation: e.currentJobTitle ?? e.jobTitle ?? e.designation ?? e.currentDesignation ?? "-",
121
129
  currentDesignation: e.currentJobTitle ?? e.jobTitle ?? e.designation ?? e.currentDesignation ?? "",
122
130
  jobTitle: e.currentJobTitle ?? e.jobTitle ?? e.designation ?? "",
123
- currentLocation: f || "",
124
- location: f || "",
131
+ currentLocation: o || "",
132
+ location: o || "",
125
133
  city: e.city ?? e.locations?.[0]?.city ?? "",
126
134
  region: e.region ?? e.locations?.[0]?.region ?? "",
127
- totalExperience: p,
128
- experience: p,
129
- yearsOfExperience: p,
130
- exp: p != null && p !== "" ? `${p} yrs` : "",
135
+ totalExperience: s,
136
+ experience: s,
137
+ yearsOfExperience: s,
138
+ exp: s != null && s !== "" ? `${s} yrs` : "",
131
139
  skills: v,
132
140
  technicalSkills: v,
133
141
  primarySkills: v,
@@ -146,10 +154,10 @@ function f(e, t = 0) {
146
154
  isDeleted: !1
147
155
  };
148
156
  }
149
- function p(e) {
150
- return Array.isArray(e) ? e.map((e, t) => f(e, t)) : [];
157
+ function h(e) {
158
+ return Array.isArray(e) ? e.map((e, t) => m(e, t)) : [];
151
159
  }
152
- function m(e, t = {}) {
160
+ function g(e, t = {}) {
153
161
  if (!e || typeof e != "object") return {
154
162
  status: "success",
155
163
  data: {
@@ -160,7 +168,7 @@ function m(e, t = {}) {
160
168
  data: []
161
169
  }
162
170
  };
163
- let n = p(Array.isArray(e) ? e : e?.data?.data ?? e?.data?.applicant ?? e?.data?.candidates ?? e?.data?.items ?? e?.items ?? e?.candidates ?? e?.records ?? []), r = e?.data?.count?.searchCount ?? e?.data?.count?.total ?? e?.count?.searchCount ?? e?.count?.total ?? e?.total ?? e?.totalCount ?? n.length;
171
+ let n = h(Array.isArray(e) ? e : e?.data?.data ?? e?.data?.applicant ?? e?.data?.candidates ?? e?.data?.items ?? e?.items ?? e?.candidates ?? e?.records ?? []), r = e?.data?.count?.searchCount ?? e?.data?.count?.total ?? e?.count?.searchCount ?? e?.count?.total ?? e?.total ?? e?.totalCount ?? n.length;
164
172
  return {
165
173
  status: e?.status ?? "success",
166
174
  data: {
@@ -176,6 +184,6 @@ function m(e, t = {}) {
176
184
  };
177
185
  }
178
186
  //#endregion
179
- export { m as a, o as i, p as n, s as r, f as t };
187
+ export { l as n, c as r, t };
180
188
 
181
- //# sourceMappingURL=diceCandidateMapper-BKRGwz7g.js.map
189
+ //# sourceMappingURL=diceCandidateMapper-CjMFuVFe.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"diceCandidateMapper-BKRGwz7g.js","names":[],"sources":["../src/services/diceCandidateMapper.js"],"sourcesContent":["/**\n * Dice Candidate Response Mapper\n * \n * Transforms Dice API candidate responses into the existing Internal Candidate\n * List API format. This ensures the frontend receives an identical response\n * schema regardless of the data source.\n * \n * Reusable for additional external sources (Monster, CareerBuilder, LinkedIn, etc.)\n */\n\n/**\n * Normalizes skills from various Dice skill formats into a simple string array\n */\nfunction firstPresentValue(...values) {\n return values.find((value) => value !== undefined && value !== null && String(value).trim() !== '');\n}\n\nfunction getPathValue(record, path) {\n if (!record || !path) return undefined;\n if (Object.prototype.hasOwnProperty.call(record, path)) return record[path];\n return String(path)\n .split('.')\n .reduce((value, key) => value?.[key], record);\n}\n\nfunction isLikelyInternalRecordId(value) {\n return /^[a-f0-9]{24}$/i.test(String(value ?? '').trim());\n}\n\nfunction isLikelyDiceProfileId(value) {\n const text = String(value ?? '').trim();\n return (\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(text)\n || /^[a-f0-9]{40,}$/i.test(text)\n );\n}\n\nfunction isLikelyDiceCandidateId(value, candidate) {\n const text = String(value ?? '').trim();\n const knownCandidateId = firstPresentValue(\n candidate?.candidateId,\n candidate?.customFields?.diceProfileData?.candidateId,\n );\n\n return (\n (knownCandidateId && text === String(knownCandidateId).trim())\n || /^[a-f0-9]{40,}-\\d+$/i.test(text)\n );\n}\n\nfunction findLikelyDiceProfileId(record) {\n const seen = new Set();\n const candidates = [];\n\n const visit = (value, path = '') => {\n if (value === null || value === undefined) return;\n if (typeof value === 'string' || typeof value === 'number') {\n const text = String(value).trim();\n const keyLooksRelevant = /(^|[._-])(dice|profile|source|external).*(id|guid|uuid)$|(^|[._-])(id|guid|uuid)$/i.test(path);\n if (text && keyLooksRelevant && isLikelyDiceProfileId(text)) {\n candidates.push({ path, value: text });\n }\n return;\n }\n if (typeof value !== 'object' || seen.has(value)) return;\n seen.add(value);\n Object.entries(value).forEach(([key, child]) => {\n visit(child, path ? `${path}.${key}` : key);\n });\n };\n\n visit(record);\n\n return candidates.find((candidate) => /dice|profile|source|external/i.test(candidate.path))?.value\n ?? candidates[0]?.value\n ?? '';\n}\n\nexport function resolveDiceProfileId(candidate) {\n if (!candidate || typeof candidate !== 'object') return '';\n\n // Check if this is a Dice candidate\n const isDiceCandidate = (() => {\n const source = candidate?.sourceType\n ?? candidate?.profileSource\n ?? candidate?.selectedSource;\n const normalizedSources = Array.isArray(source) ? source : [source];\n return normalizedSources.some(\n (value) => String(value ?? '').trim().toLowerCase() === 'dice',\n );\n })();\n\n const explicitPaths = [\n 'diceId',\n 'diceID',\n 'dice_id',\n 'diceProfileId',\n 'diceProfileID',\n 'diceProfileGuid',\n 'profileId',\n 'profileID',\n 'profileGuid',\n 'sourceId',\n 'sourceProfileId',\n 'externalId',\n 'externalProfileId',\n 'customFields.diceId',\n 'customFields.diceProfileId',\n 'customFields.profileId',\n 'customFields.externalProfileId',\n 'customFields.diceProfileData.diceId',\n 'customFields.diceProfileData.diceID',\n 'customFields.diceProfileData.id',\n 'customFields.diceProfileData._id',\n 'customFields.diceProfileData.profileId',\n 'customFields.diceProfileData.profileID',\n 'customFields.diceProfileData.diceProfileId',\n 'customFields.diceProfileData.diceProfileID',\n 'customFields.diceProfileData.guid',\n 'customFields.diceProfileData.uuid',\n 'customFields.diceProfileData.externalId',\n 'customFields.diceProfileData.candidateid',\n 'customFields.diceProfileData.candidateId',\n ];\n\n const explicitDiceId = firstPresentValue(\n ...explicitPaths.map((path) => getPathValue(candidate, path)),\n );\n\n if (explicitDiceId && !isLikelyDiceCandidateId(explicitDiceId, candidate)) {\n return String(explicitDiceId);\n }\n\n const likelyNestedId = findLikelyDiceProfileId(candidate);\n if (likelyNestedId) return likelyNestedId;\n\n const genericId = firstPresentValue(candidate.id, candidate._id);\n \n // For Dice candidates, accept the ID even if it looks like an internal MongoDB ObjectId\n // For non-Dice candidates, reject IDs that look like internal record IDs\n if (genericId && (isDiceCandidate || !isLikelyInternalRecordId(genericId))) {\n return String(genericId);\n }\n \n return '';\n}\n\nexport function normalizeDiceSkills(skills) {\n if (!skills) return [];\n \n if (Array.isArray(skills)) {\n return skills\n .map(skill => {\n // Handle Dice format: {skill: \"courts\", lastUsed: 2026}\n if (skill?.skill) return skill.skill;\n // Handle other object formats\n if (typeof skill === 'object' && skill !== null) {\n if (skill?.name) return skill.name;\n if (skill?.skillName) return skill.skillName;\n if (skill?.value) return skill.value;\n }\n // Handle string skills\n if (typeof skill === 'string') return skill;\n return null;\n })\n .filter(Boolean);\n }\n \n if (typeof skills === 'string') {\n return skills.split(',').map(s => s.trim()).filter(Boolean);\n }\n \n return [];\n}\n\n/**\n * Normalizes location from various Dice location formats\n */\nfunction normalizeDiceLocation(candidate) {\n // Try locations array first (common in Dice)\n if (Array.isArray(candidate.locations) && candidate.locations.length > 0) {\n const loc = candidate.locations[0];\n if (typeof loc === 'string') return loc;\n if (loc?.region) return loc.region;\n if (loc?.city) return loc.city;\n if (loc?.name) return loc.name;\n if (loc?.location) return loc.location;\n }\n \n // Try direct location fields\n return (\n candidate.currentLocation ??\n candidate.location ??\n candidate.city ??\n candidate.region ??\n ''\n );\n}\n\n/**\n * Normalizes experience from various Dice experience formats\n */\nfunction normalizeDiceExperience(candidate) {\n const exp = (\n candidate.totalExperience ??\n candidate.experience ??\n candidate.yearsOfExperience ??\n candidate.exp ??\n candidate.totalYearsOfExperience ??\n candidate.workExperienceYears\n );\n \n return exp != null && exp !== '' ? exp : null;\n}\n\n/**\n * Normalizes date from various Dice date formats\n */\nfunction normalizeDiceDate(candidate) {\n return (\n candidate.dateLastUpdated ??\n candidate.updatedAt ??\n candidate.createdAt ??\n candidate.createdDate ??\n candidate.dateCreated ??\n null\n );\n}\n\n/**\n * Normalizes name from various Dice name formats\n */\nfunction normalizeDiceName(candidate) {\n const parts = [\n candidate.firstName,\n candidate.middleName,\n candidate.lastName,\n ].filter(Boolean);\n \n if (parts.length > 0) return parts.join(' ');\n \n return (\n candidate.fullName ??\n candidate.name ??\n candidate.candidateName ??\n ''\n );\n}\n\n/**\n * Maps a single Dice candidate to the Internal Candidate format\n * \n * @param {Object} diceCandidate - Raw Dice API candidate object\n * @param {number} index - Index for fallback ID generation\n * @returns {Object} Mapped candidate in Internal format\n */\nexport function mapDiceCandidateToInternal(diceCandidate, index = 0) {\n if (!diceCandidate || typeof diceCandidate !== 'object') {\n return {\n id: `dice-candidate-${index}`,\n diceId: '',\n candidateId: '',\n firstName: '',\n lastName: '',\n name: '-',\n designation: '-',\n currentLocation: '',\n location: '',\n exp: '',\n totalExperience: null,\n skills: [],\n createdAt: null,\n createdOn: '-',\n sourceType: 'dice',\n profileSource: 'dice',\n };\n }\n\n const fullName = normalizeDiceName(diceCandidate);\n const nameParts = fullName.split(' ');\n const firstName = nameParts[0] || '';\n const lastName = nameParts.length > 1 ? nameParts[nameParts.length - 1] : '';\n \n const location = normalizeDiceLocation(diceCandidate);\n const experience = normalizeDiceExperience(diceCandidate);\n const createdOn = normalizeDiceDate(diceCandidate);\n const diceProfileId = resolveDiceProfileId(diceCandidate);\n const candidateId = diceCandidate.candidateId\n ?? diceCandidate.customFields?.diceProfileData?.candidateId\n ?? `dice-candidate-${index}`;\n \n // Extract skills from various possible fields\n const rawSkills = diceCandidate.skills ?? \n diceCandidate.technicalSkills ?? \n diceCandidate.primarySkills ??\n diceCandidate.keySkills ??\n [];\n \n const skills = normalizeDiceSkills(rawSkills);\n \n // Debug logging to verify transformation\n if (process.env.NODE_ENV === 'development') {\n console.log('[DiceMapper] Original skills:', rawSkills);\n console.log('[DiceMapper] Mapped skills:', skills);\n console.log('[DiceMapper] Dice IDs:', {\n id: diceProfileId,\n diceId: diceProfileId,\n candidateId,\n });\n }\n\n return {\n // Preserve original Dice fields for reference\n ...diceCandidate,\n \n // Map to Internal candidate schema. Keep the Dice profile id as the primary id.\n id: diceProfileId,\n diceId: diceProfileId,\n candidateId,\n \n // Name fields\n firstName,\n lastName,\n middleName: diceCandidate.middleName || '',\n name: fullName || '-',\n fullName: fullName || '',\n \n // Professional info\n designation: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? diceCandidate.currentDesignation ?? '-',\n currentDesignation: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? diceCandidate.currentDesignation ?? '',\n jobTitle: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? '',\n \n // Location\n currentLocation: location || '',\n location: location || '',\n city: diceCandidate.city ?? diceCandidate.locations?.[0]?.city ?? '',\n region: diceCandidate.region ?? diceCandidate.locations?.[0]?.region ?? '',\n \n // Experience\n totalExperience: experience,\n experience: experience,\n yearsOfExperience: experience,\n exp: experience != null && experience !== '' ? `${experience} yrs` : '',\n \n // Skills\n skills,\n technicalSkills: skills,\n primarySkills: skills,\n \n // Dates\n createdAt: createdOn,\n createdOn: createdOn ? String(createdOn) : '-',\n updatedAt: createdOn,\n dateLastUpdated: createdOn,\n \n // Source identification\n sourceType: 'dice',\n profileSource: 'dice',\n selectedSource: ['dice'],\n \n // Additional fields with defaults\n email: diceCandidate.email ?? diceCandidate.emailAddress ?? '',\n phone: diceCandidate.phone ?? diceCandidate.phoneNumber ?? diceCandidate.mobile ?? '',\n summary: diceCandidate.summary ?? diceCandidate.bio ?? diceCandidate.description ?? '',\n resume: diceCandidate.resume ?? diceCandidate.resumeUrl ?? diceCandidate.cvUrl ?? '',\n \n // Status and metadata\n isActive: true,\n isDeleted: false,\n };\n}\n\n/**\n * Maps an array of Dice candidates to the Internal Candidate format\n * \n * @param {Array} diceCandidates - Array of raw Dice API candidate objects\n * @returns {Array} Array of mapped candidates in Internal format\n */\nexport function mapDiceCandidatesToInternal(diceCandidates) {\n if (!Array.isArray(diceCandidates)) {\n return [];\n }\n \n return diceCandidates.map((candidate, index) => \n mapDiceCandidateToInternal(candidate, index)\n );\n}\n\n/**\n * Transforms a Dice API response to match the existing Candidate List API response format\n * \n * @param {Object} diceResponse - Raw Dice API response\n * @param {Object} originalResponseStructure - The expected response structure from Internal API\n * @returns {Object} Transformed response matching Internal API format\n */\nexport function transformDiceResponseToInternalFormat(diceResponse, originalResponseStructure = {}) {\n if (!diceResponse || typeof diceResponse !== 'object') {\n return {\n status: 'success',\n data: {\n fields: [],\n actions: [],\n columnActions: [],\n count: 0,\n data: [],\n },\n };\n }\n\n // Extract candidates array from various possible response structures\n const diceCandidates = Array.isArray(diceResponse) \n ? diceResponse \n : diceResponse?.data?.data ?? \n diceResponse?.data?.applicant ?? \n diceResponse?.data?.candidates ?? \n diceResponse?.data?.items ?? \n diceResponse?.items ?? \n diceResponse?.candidates ?? \n diceResponse?.records ?? \n [];\n\n // Map Dice candidates to Internal format\n const mappedCandidates = mapDiceCandidatesToInternal(diceCandidates);\n\n // Extract count from various possible locations\n const count = (\n diceResponse?.data?.count?.searchCount ??\n diceResponse?.data?.count?.total ??\n diceResponse?.count?.searchCount ??\n diceResponse?.count?.total ??\n diceResponse?.total ??\n diceResponse?.totalCount ??\n mappedCandidates.length\n );\n\n // Preserve existing metadata from the original response structure\n return {\n status: diceResponse?.status ?? 'success',\n data: {\n // Preserve fields, actions, columnActions from original structure\n fields: originalResponseStructure?.fields ?? diceResponse?.data?.fields ?? diceResponse?.fields ?? [],\n actions: originalResponseStructure?.actions ?? diceResponse?.data?.actions ?? diceResponse?.actions ?? [],\n columnActions: originalResponseStructure?.columnActions ?? diceResponse?.data?.columnActions ?? diceResponse?.columnActions ?? [],\n \n // Count and mapped data\n count: Number(count) || 0,\n data: mappedCandidates,\n \n // Preserve any additional metadata\n ...(diceResponse?.data?.actionRules && { actionRules: diceResponse.data.actionRules }),\n ...(diceResponse?.data?.tabs && { tabs: diceResponse.data.tabs }),\n ...(diceResponse?.data?.tabField && { tabField: diceResponse.data.tabField }),\n },\n };\n}\n\n/**\n * Checks if a response contains Dice candidates\n * \n * @param {Array|Object} response - API response to check\n * @returns {boolean} True if response contains Dice candidates\n */\nexport function isDiceResponse(response) {\n if (!response) return false;\n \n const candidates = Array.isArray(response) \n ? response \n : response?.data?.data ?? \n response?.data?.applicant ?? \n response?.data?.candidates ?? \n response?.data?.items ?? \n response?.items ?? \n [];\n \n if (!Array.isArray(candidates) || candidates.length === 0) {\n return false;\n }\n \n // Check first few candidates for Dice source indicators\n const sampleSize = Math.min(candidates.length, 5);\n for (let i = 0; i < sampleSize; i++) {\n const candidate = candidates[i];\n const sourceType = candidate?.sourceType ?? candidate?.profileSource ?? '';\n if (String(sourceType).toLowerCase() === 'dice') {\n return true;\n }\n }\n \n return false;\n}\n\nexport default {\n mapDiceCandidateToInternal,\n mapDiceCandidatesToInternal,\n transformDiceResponseToInternalFormat,\n isDiceResponse,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"diceCandidateMapper-CjMFuVFe.js","names":[],"sources":["../src/services/diceCandidateMapper.js"],"sourcesContent":["/**\n * Dice Candidate Response Mapper\n * \n * Transforms Dice API candidate responses into the existing Internal Candidate\n * List API format. This ensures the frontend receives an identical response\n * schema regardless of the data source.\n * \n * Reusable for additional external sources (Monster, CareerBuilder, LinkedIn, etc.)\n */\n\n/**\n * Normalizes skills from various Dice skill formats into a simple string array\n */\nfunction firstPresentValue(...values) {\n return values.find((value) => value !== undefined && value !== null && String(value).trim() !== '');\n}\n\nfunction getPathValue(record, path) {\n if (!record || !path) return undefined;\n if (Object.prototype.hasOwnProperty.call(record, path)) return record[path];\n return String(path)\n .split('.')\n .reduce((value, key) => value?.[key], record);\n}\n\nfunction isLikelyInternalRecordId(value) {\n return /^[a-f0-9]{24}$/i.test(String(value ?? '').trim());\n}\n\nfunction isLikelyDiceProfileId(value) {\n const text = String(value ?? '').trim();\n return (\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(text)\n || /^[a-f0-9]{40,}$/i.test(text)\n );\n}\n\nfunction isLikelyDiceCandidateId(value, candidate) {\n const text = String(value ?? '').trim();\n const knownCandidateId = firstPresentValue(\n candidate?.candidateId,\n candidate?.customFields?.diceProfileData?.candidateId,\n );\n\n return (\n (knownCandidateId && text === String(knownCandidateId).trim())\n || /^[a-f0-9]{40,}-\\d+$/i.test(text)\n );\n}\n\nfunction findLikelyDiceProfileId(record) {\n const seen = new Set();\n const candidates = [];\n\n const visit = (value, path = '') => {\n if (value === null || value === undefined) return;\n if (typeof value === 'string' || typeof value === 'number') {\n const text = String(value).trim();\n const keyLooksRelevant = /(^|[._-])(dice|profile|source|external).*(id|guid|uuid)$|(^|[._-])(id|guid|uuid)$/i.test(path);\n if (text && keyLooksRelevant && isLikelyDiceProfileId(text)) {\n candidates.push({ path, value: text });\n }\n return;\n }\n if (typeof value !== 'object' || seen.has(value)) return;\n seen.add(value);\n Object.entries(value).forEach(([key, child]) => {\n visit(child, path ? `${path}.${key}` : key);\n });\n };\n\n visit(record);\n\n return candidates.find((candidate) => /dice|profile|source|external/i.test(candidate.path))?.value\n ?? candidates[0]?.value\n ?? '';\n}\n\nexport function resolveDiceProfileId(candidate) {\n if (!candidate || typeof candidate !== 'object') return '';\n\n // Check if this is a Dice candidate\n const isDiceCandidate = (() => {\n const source = candidate?.sourceType\n ?? candidate?.profileSource\n ?? candidate?.selectedSource;\n const normalizedSources = Array.isArray(source) ? source : [source];\n return normalizedSources.some(\n (value) => String(value ?? '').trim().toLowerCase() === 'dice',\n );\n })();\n\n const explicitPaths = [\n 'diceId',\n 'diceID',\n 'dice_id',\n 'diceProfileId',\n 'diceProfileID',\n 'diceProfileGuid',\n 'profileId',\n 'profileID',\n 'profileGuid',\n 'sourceId',\n 'sourceProfileId',\n 'externalId',\n 'externalProfileId',\n 'customFields.diceId',\n 'customFields.diceProfileId',\n 'customFields.profileId',\n 'customFields.externalProfileId',\n 'customFields.diceProfileData.diceId',\n 'customFields.diceProfileData.diceID',\n 'customFields.diceProfileData.id',\n 'customFields.diceProfileData._id',\n 'customFields.diceProfileData.profileId',\n 'customFields.diceProfileData.profileID',\n 'customFields.diceProfileData.diceProfileId',\n 'customFields.diceProfileData.diceProfileID',\n 'customFields.diceProfileData.guid',\n 'customFields.diceProfileData.uuid',\n 'customFields.diceProfileData.externalId',\n 'customFields.diceProfileData.candidateid',\n 'customFields.diceProfileData.candidateId',\n ];\n\n const explicitDiceId = firstPresentValue(\n ...explicitPaths.map((path) => getPathValue(candidate, path)),\n );\n\n if (explicitDiceId && !isLikelyDiceCandidateId(explicitDiceId, candidate)) {\n return String(explicitDiceId);\n }\n\n const likelyNestedId = findLikelyDiceProfileId(candidate);\n if (likelyNestedId) return likelyNestedId;\n\n const genericId = firstPresentValue(candidate.id, candidate._id);\n \n // For Dice candidates, accept the ID even if it looks like an internal MongoDB ObjectId\n // For non-Dice candidates, reject IDs that look like internal record IDs\n if (genericId && (isDiceCandidate || !isLikelyInternalRecordId(genericId))) {\n return String(genericId);\n }\n \n return '';\n}\n\nexport function normalizeDiceSkills(skills) {\n if (!skills) return [];\n \n if (Array.isArray(skills)) {\n return skills\n .map(skill => {\n // Handle Dice format: {skill: \"courts\", lastUsed: 2026}\n if (skill?.skill) return skill.skill;\n // Handle other object formats\n if (typeof skill === 'object' && skill !== null) {\n if (skill?.name) return skill.name;\n if (skill?.skillName) return skill.skillName;\n if (skill?.value) return skill.value;\n }\n // Handle string skills\n if (typeof skill === 'string') return skill;\n return null;\n })\n .filter(Boolean);\n }\n \n if (typeof skills === 'string') {\n return skills.split(',').map(s => s.trim()).filter(Boolean);\n }\n \n return [];\n}\n\n/**\n * Normalizes location from various Dice location formats\n */\nfunction normalizeDiceLocation(candidate) {\n // Try locations array first (common in Dice)\n if (Array.isArray(candidate.locations) && candidate.locations.length > 0) {\n const loc = candidate.locations[0];\n if (typeof loc === 'string') return loc;\n if (loc?.region) return loc.region;\n if (loc?.city) return loc.city;\n if (loc?.name) return loc.name;\n if (loc?.location) return loc.location;\n }\n \n // Try direct location fields\n return (\n candidate.currentLocation ??\n candidate.location ??\n candidate.city ??\n candidate.region ??\n ''\n );\n}\n\n/**\n * Normalizes experience from various Dice experience formats\n */\nfunction normalizeDiceExperience(candidate) {\n const exp = (\n candidate.totalExperience ??\n candidate.experience ??\n candidate.yearsOfExperience ??\n candidate.exp ??\n candidate.totalYearsOfExperience ??\n candidate.workExperienceYears\n );\n \n return exp != null && exp !== '' ? exp : null;\n}\n\n/**\n * Normalizes date from various Dice date formats\n */\nfunction normalizeDiceDate(candidate) {\n return (\n candidate.dateLastUpdated ??\n candidate.updatedAt ??\n candidate.createdAt ??\n candidate.createdDate ??\n candidate.dateCreated ??\n null\n );\n}\n\n/**\n * Normalizes name from various Dice name formats\n */\nfunction normalizeDiceName(candidate) {\n const parts = [\n candidate.firstName,\n candidate.middleName,\n candidate.lastName,\n ].filter(Boolean);\n \n if (parts.length > 0) return parts.join(' ');\n \n return (\n candidate.fullName ??\n candidate.name ??\n candidate.candidateName ??\n ''\n );\n}\n\n/**\n * Maps a single Dice candidate to the Internal Candidate format\n * \n * @param {Object} diceCandidate - Raw Dice API candidate object\n * @param {number} index - Index for fallback ID generation\n * @returns {Object} Mapped candidate in Internal format\n */\nexport function mapDiceCandidateToInternal(diceCandidate, index = 0) {\n if (!diceCandidate || typeof diceCandidate !== 'object') {\n return {\n id: `dice-candidate-${index}`,\n diceId: '',\n candidateId: '',\n firstName: '',\n lastName: '',\n name: '-',\n designation: '-',\n currentLocation: '',\n location: '',\n exp: '',\n totalExperience: null,\n skills: [],\n createdAt: null,\n createdOn: '-',\n sourceType: 'dice',\n profileSource: 'dice',\n };\n }\n\n const fullName = normalizeDiceName(diceCandidate);\n const nameParts = fullName.split(' ');\n const firstName = nameParts[0] || '';\n const lastName = nameParts.length > 1 ? nameParts[nameParts.length - 1] : '';\n \n const location = normalizeDiceLocation(diceCandidate);\n const experience = normalizeDiceExperience(diceCandidate);\n const createdOn = normalizeDiceDate(diceCandidate);\n const diceProfileId = resolveDiceProfileId(diceCandidate);\n const candidateId = diceCandidate.candidateId\n ?? diceCandidate.customFields?.diceProfileData?.candidateId\n ?? `dice-candidate-${index}`;\n \n // Extract skills from various possible fields\n const rawSkills = diceCandidate.skills ?? \n diceCandidate.technicalSkills ?? \n diceCandidate.primarySkills ??\n diceCandidate.keySkills ??\n [];\n \n const skills = normalizeDiceSkills(rawSkills);\n \n // Debug logging to verify transformation\n if (process.env.NODE_ENV === 'development') {\n console.log('[DiceMapper] Original skills:', rawSkills);\n console.log('[DiceMapper] Mapped skills:', skills);\n console.log('[DiceMapper] Dice IDs:', {\n id: diceProfileId,\n diceId: diceProfileId,\n candidateId,\n });\n }\n\n return {\n // Preserve original Dice fields for reference\n ...diceCandidate,\n \n // Map to Internal candidate schema. Keep the Dice profile id as the primary id.\n id: diceProfileId,\n diceId: diceProfileId,\n candidateId,\n \n // Name fields\n firstName,\n lastName,\n middleName: diceCandidate.middleName || '',\n name: fullName || '-',\n fullName: fullName || '',\n \n // Professional info\n designation: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? diceCandidate.currentDesignation ?? '-',\n currentDesignation: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? diceCandidate.currentDesignation ?? '',\n jobTitle: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? '',\n \n // Location\n currentLocation: location || '',\n location: location || '',\n city: diceCandidate.city ?? diceCandidate.locations?.[0]?.city ?? '',\n region: diceCandidate.region ?? diceCandidate.locations?.[0]?.region ?? '',\n \n // Experience\n totalExperience: experience,\n experience: experience,\n yearsOfExperience: experience,\n exp: experience != null && experience !== '' ? `${experience} yrs` : '',\n \n // Skills\n skills,\n technicalSkills: skills,\n primarySkills: skills,\n \n // Dates\n createdAt: createdOn,\n createdOn: createdOn ? String(createdOn) : '-',\n updatedAt: createdOn,\n dateLastUpdated: createdOn,\n \n // Source identification\n sourceType: 'dice',\n profileSource: 'dice',\n selectedSource: ['dice'],\n \n // Additional fields with defaults\n email: diceCandidate.email ?? diceCandidate.emailAddress ?? '',\n phone: diceCandidate.phone ?? diceCandidate.phoneNumber ?? diceCandidate.mobile ?? '',\n summary: diceCandidate.summary ?? diceCandidate.bio ?? diceCandidate.description ?? '',\n resume: diceCandidate.resume ?? diceCandidate.resumeUrl ?? diceCandidate.cvUrl ?? '',\n \n // Status and metadata\n isActive: true,\n isDeleted: false,\n };\n}\n\n/**\n * Maps an array of Dice candidates to the Internal Candidate format\n * \n * @param {Array} diceCandidates - Array of raw Dice API candidate objects\n * @returns {Array} Array of mapped candidates in Internal format\n */\nexport function mapDiceCandidatesToInternal(diceCandidates) {\n if (!Array.isArray(diceCandidates)) {\n return [];\n }\n \n return diceCandidates.map((candidate, index) => \n mapDiceCandidateToInternal(candidate, index)\n );\n}\n\n/**\n * Transforms a Dice API response to match the existing Candidate List API response format\n * \n * @param {Object} diceResponse - Raw Dice API response\n * @param {Object} originalResponseStructure - The expected response structure from Internal API\n * @returns {Object} Transformed response matching Internal API format\n */\nexport function transformDiceResponseToInternalFormat(diceResponse, originalResponseStructure = {}) {\n if (!diceResponse || typeof diceResponse !== 'object') {\n return {\n status: 'success',\n data: {\n fields: [],\n actions: [],\n columnActions: [],\n count: 0,\n data: [],\n },\n };\n }\n\n // Extract candidates array from various possible response structures\n const diceCandidates = Array.isArray(diceResponse) \n ? diceResponse \n : diceResponse?.data?.data ?? \n diceResponse?.data?.applicant ?? \n diceResponse?.data?.candidates ?? \n diceResponse?.data?.items ?? \n diceResponse?.items ?? \n diceResponse?.candidates ?? \n diceResponse?.records ?? \n [];\n\n // Map Dice candidates to Internal format\n const mappedCandidates = mapDiceCandidatesToInternal(diceCandidates);\n\n // Extract count from various possible locations\n const count = (\n diceResponse?.data?.count?.searchCount ??\n diceResponse?.data?.count?.total ??\n diceResponse?.count?.searchCount ??\n diceResponse?.count?.total ??\n diceResponse?.total ??\n diceResponse?.totalCount ??\n mappedCandidates.length\n );\n\n // Preserve existing metadata from the original response structure\n return {\n status: diceResponse?.status ?? 'success',\n data: {\n // Preserve fields, actions, columnActions from original structure\n fields: originalResponseStructure?.fields ?? diceResponse?.data?.fields ?? diceResponse?.fields ?? [],\n actions: originalResponseStructure?.actions ?? diceResponse?.data?.actions ?? diceResponse?.actions ?? [],\n columnActions: originalResponseStructure?.columnActions ?? diceResponse?.data?.columnActions ?? diceResponse?.columnActions ?? [],\n \n // Count and mapped data\n count: Number(count) || 0,\n data: mappedCandidates,\n \n // Preserve any additional metadata\n ...(diceResponse?.data?.actionRules && { actionRules: diceResponse.data.actionRules }),\n ...(diceResponse?.data?.tabs && { tabs: diceResponse.data.tabs }),\n ...(diceResponse?.data?.tabField && { tabField: diceResponse.data.tabField }),\n },\n };\n}\n\n/**\n * Checks if a response contains Dice candidates\n * \n * @param {Array|Object} response - API response to check\n * @returns {boolean} True if response contains Dice candidates\n */\nexport function isDiceResponse(response) {\n if (!response) return false;\n \n const candidates = Array.isArray(response) \n ? response \n : response?.data?.data ?? \n response?.data?.applicant ?? \n response?.data?.candidates ?? \n response?.data?.items ?? \n response?.items ?? \n [];\n \n if (!Array.isArray(candidates) || candidates.length === 0) {\n return false;\n }\n \n // Check first few candidates for Dice source indicators\n const sampleSize = Math.min(candidates.length, 5);\n for (let i = 0; i < sampleSize; i++) {\n const candidate = candidates[i];\n const sourceType = candidate?.sourceType ?? candidate?.profileSource ?? '';\n if (String(sourceType).toLowerCase() === 'dice') {\n return true;\n }\n }\n \n return false;\n}\n\nexport default {\n mapDiceCandidateToInternal,\n mapDiceCandidatesToInternal,\n transformDiceResponseToInternalFormat,\n isDiceResponse,\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var e=require("./rolldown-runtime-Chgba0Kb.cjs").t({mapDiceCandidateToInternal:()=>p,mapDiceCandidatesToInternal:()=>m,normalizeDiceSkills:()=>c,resolveDiceProfileId:()=>s,transformDiceResponseToInternalFormat:()=>h});function t(...e){return e.find(e=>e!=null&&String(e).trim()!==``)}function n(e,t){if(!(!e||!t))return Object.prototype.hasOwnProperty.call(e,t)?e[t]:String(t).split(`.`).reduce((e,t)=>e?.[t],e)}function r(e){return/^[a-f0-9]{24}$/i.test(String(e??``).trim())}function i(e){let t=String(e??``).trim();return/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)||/^[a-f0-9]{40,}$/i.test(t)}function a(e,n){let r=String(e??``).trim(),i=t(n?.candidateId,n?.customFields?.diceProfileData?.candidateId);return i&&r===String(i).trim()||/^[a-f0-9]{40,}-\d+$/i.test(r)}function o(e){let t=new Set,n=[],r=(e,a=``)=>{if(e!=null){if(typeof e==`string`||typeof e==`number`){let t=String(e).trim(),r=/(^|[._-])(dice|profile|source|external).*(id|guid|uuid)$|(^|[._-])(id|guid|uuid)$/i.test(a);t&&r&&i(t)&&n.push({path:a,value:t});return}typeof e!=`object`||t.has(e)||(t.add(e),Object.entries(e).forEach(([e,t])=>{r(t,a?`${a}.${e}`:e)}))}};return r(e),n.find(e=>/dice|profile|source|external/i.test(e.path))?.value??n[0]?.value??``}function s(e){if(!e||typeof e!=`object`)return``;let i=(()=>{let t=e?.sourceType??e?.profileSource??e?.selectedSource;return(Array.isArray(t)?t:[t]).some(e=>String(e??``).trim().toLowerCase()===`dice`)})(),s=t(...`diceId,diceID,dice_id,diceProfileId,diceProfileID,diceProfileGuid,profileId,profileID,profileGuid,sourceId,sourceProfileId,externalId,externalProfileId,customFields.diceId,customFields.diceProfileId,customFields.profileId,customFields.externalProfileId,customFields.diceProfileData.diceId,customFields.diceProfileData.diceID,customFields.diceProfileData.id,customFields.diceProfileData._id,customFields.diceProfileData.profileId,customFields.diceProfileData.profileID,customFields.diceProfileData.diceProfileId,customFields.diceProfileData.diceProfileID,customFields.diceProfileData.guid,customFields.diceProfileData.uuid,customFields.diceProfileData.externalId,customFields.diceProfileData.candidateid,customFields.diceProfileData.candidateId`.split(`,`).map(t=>n(e,t)));if(s&&!a(s,e))return String(s);let c=o(e);if(c)return c;let l=t(e.id,e._id);return l&&(i||!r(l))?String(l):``}function c(e){return e?Array.isArray(e)?e.map(e=>{if(e?.skill)return e.skill;if(typeof e==`object`&&e){if(e?.name)return e.name;if(e?.skillName)return e.skillName;if(e?.value)return e.value}return typeof e==`string`?e:null}).filter(Boolean):typeof e==`string`?e.split(`,`).map(e=>e.trim()).filter(Boolean):[]:[]}function l(e){if(Array.isArray(e.locations)&&e.locations.length>0){let t=e.locations[0];if(typeof t==`string`)return t;if(t?.region)return t.region;if(t?.city)return t.city;if(t?.name)return t.name;if(t?.location)return t.location}return e.currentLocation??e.location??e.city??e.region??``}function u(e){let t=e.totalExperience??e.experience??e.yearsOfExperience??e.exp??e.totalYearsOfExperience??e.workExperienceYears;return t!=null&&t!==``?t:null}function d(e){return e.dateLastUpdated??e.updatedAt??e.createdAt??e.createdDate??e.dateCreated??null}function f(e){let t=[e.firstName,e.middleName,e.lastName].filter(Boolean);return t.length>0?t.join(` `):e.fullName??e.name??e.candidateName??``}function p(e,t=0){if(!e||typeof e!=`object`)return{id:`dice-candidate-${t}`,diceId:``,candidateId:``,firstName:``,lastName:``,name:`-`,designation:`-`,currentLocation:``,location:``,exp:``,totalExperience:null,skills:[],createdAt:null,createdOn:`-`,sourceType:`dice`,profileSource:`dice`};let n=f(e),r=n.split(` `),i=r[0]||``,a=r.length>1?r[r.length-1]:``,o=l(e),p=u(e),m=d(e),h=s(e),g=e.candidateId??e.customFields?.diceProfileData?.candidateId??`dice-candidate-${t}`,_=e.skills??e.technicalSkills??e.primarySkills??e.keySkills??[],v=c(_);return process.env.NODE_ENV===`development`&&(console.log(`[DiceMapper] Original skills:`,_),console.log(`[DiceMapper] Mapped skills:`,v),console.log(`[DiceMapper] Dice IDs:`,{id:h,diceId:h,candidateId:g})),{...e,id:h,diceId:h,candidateId:g,firstName:i,lastName:a,middleName:e.middleName||``,name:n||`-`,fullName:n||``,designation:e.currentJobTitle??e.jobTitle??e.designation??e.currentDesignation??`-`,currentDesignation:e.currentJobTitle??e.jobTitle??e.designation??e.currentDesignation??``,jobTitle:e.currentJobTitle??e.jobTitle??e.designation??``,currentLocation:o||``,location:o||``,city:e.city??e.locations?.[0]?.city??``,region:e.region??e.locations?.[0]?.region??``,totalExperience:p,experience:p,yearsOfExperience:p,exp:p!=null&&p!==``?`${p} yrs`:``,skills:v,technicalSkills:v,primarySkills:v,createdAt:m,createdOn:m?String(m):`-`,updatedAt:m,dateLastUpdated:m,sourceType:`dice`,profileSource:`dice`,selectedSource:[`dice`],email:e.email??e.emailAddress??``,phone:e.phone??e.phoneNumber??e.mobile??``,summary:e.summary??e.bio??e.description??``,resume:e.resume??e.resumeUrl??e.cvUrl??``,isActive:!0,isDeleted:!1}}function m(e){return Array.isArray(e)?e.map((e,t)=>p(e,t)):[]}function h(e,t={}){if(!e||typeof e!=`object`)return{status:`success`,data:{fields:[],actions:[],columnActions:[],count:0,data:[]}};let n=m(Array.isArray(e)?e:e?.data?.data??e?.data?.applicant??e?.data?.candidates??e?.data?.items??e?.items??e?.candidates??e?.records??[]),r=e?.data?.count?.searchCount??e?.data?.count?.total??e?.count?.searchCount??e?.count?.total??e?.total??e?.totalCount??n.length;return{status:e?.status??`success`,data:{fields:t?.fields??e?.data?.fields??e?.fields??[],actions:t?.actions??e?.data?.actions??e?.actions??[],columnActions:t?.columnActions??e?.data?.columnActions??e?.columnActions??[],count:Number(r)||0,data:n,...e?.data?.actionRules&&{actionRules:e.data.actionRules},...e?.data?.tabs&&{tabs:e.data.tabs},...e?.data?.tabField&&{tabField:e.data.tabField}}}}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return e}});
2
+ //# sourceMappingURL=diceCandidateMapper-G6mMmRda.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"diceCandidateMapper-MB-yyU21.cjs","names":[],"sources":["../src/services/diceCandidateMapper.js"],"sourcesContent":["/**\n * Dice Candidate Response Mapper\n * \n * Transforms Dice API candidate responses into the existing Internal Candidate\n * List API format. This ensures the frontend receives an identical response\n * schema regardless of the data source.\n * \n * Reusable for additional external sources (Monster, CareerBuilder, LinkedIn, etc.)\n */\n\n/**\n * Normalizes skills from various Dice skill formats into a simple string array\n */\nfunction firstPresentValue(...values) {\n return values.find((value) => value !== undefined && value !== null && String(value).trim() !== '');\n}\n\nfunction getPathValue(record, path) {\n if (!record || !path) return undefined;\n if (Object.prototype.hasOwnProperty.call(record, path)) return record[path];\n return String(path)\n .split('.')\n .reduce((value, key) => value?.[key], record);\n}\n\nfunction isLikelyInternalRecordId(value) {\n return /^[a-f0-9]{24}$/i.test(String(value ?? '').trim());\n}\n\nfunction isLikelyDiceProfileId(value) {\n const text = String(value ?? '').trim();\n return (\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(text)\n || /^[a-f0-9]{40,}$/i.test(text)\n );\n}\n\nfunction isLikelyDiceCandidateId(value, candidate) {\n const text = String(value ?? '').trim();\n const knownCandidateId = firstPresentValue(\n candidate?.candidateId,\n candidate?.customFields?.diceProfileData?.candidateId,\n );\n\n return (\n (knownCandidateId && text === String(knownCandidateId).trim())\n || /^[a-f0-9]{40,}-\\d+$/i.test(text)\n );\n}\n\nfunction findLikelyDiceProfileId(record) {\n const seen = new Set();\n const candidates = [];\n\n const visit = (value, path = '') => {\n if (value === null || value === undefined) return;\n if (typeof value === 'string' || typeof value === 'number') {\n const text = String(value).trim();\n const keyLooksRelevant = /(^|[._-])(dice|profile|source|external).*(id|guid|uuid)$|(^|[._-])(id|guid|uuid)$/i.test(path);\n if (text && keyLooksRelevant && isLikelyDiceProfileId(text)) {\n candidates.push({ path, value: text });\n }\n return;\n }\n if (typeof value !== 'object' || seen.has(value)) return;\n seen.add(value);\n Object.entries(value).forEach(([key, child]) => {\n visit(child, path ? `${path}.${key}` : key);\n });\n };\n\n visit(record);\n\n return candidates.find((candidate) => /dice|profile|source|external/i.test(candidate.path))?.value\n ?? candidates[0]?.value\n ?? '';\n}\n\nexport function resolveDiceProfileId(candidate) {\n if (!candidate || typeof candidate !== 'object') return '';\n\n // Check if this is a Dice candidate\n const isDiceCandidate = (() => {\n const source = candidate?.sourceType\n ?? candidate?.profileSource\n ?? candidate?.selectedSource;\n const normalizedSources = Array.isArray(source) ? source : [source];\n return normalizedSources.some(\n (value) => String(value ?? '').trim().toLowerCase() === 'dice',\n );\n })();\n\n const explicitPaths = [\n 'diceId',\n 'diceID',\n 'dice_id',\n 'diceProfileId',\n 'diceProfileID',\n 'diceProfileGuid',\n 'profileId',\n 'profileID',\n 'profileGuid',\n 'sourceId',\n 'sourceProfileId',\n 'externalId',\n 'externalProfileId',\n 'customFields.diceId',\n 'customFields.diceProfileId',\n 'customFields.profileId',\n 'customFields.externalProfileId',\n 'customFields.diceProfileData.diceId',\n 'customFields.diceProfileData.diceID',\n 'customFields.diceProfileData.id',\n 'customFields.diceProfileData._id',\n 'customFields.diceProfileData.profileId',\n 'customFields.diceProfileData.profileID',\n 'customFields.diceProfileData.diceProfileId',\n 'customFields.diceProfileData.diceProfileID',\n 'customFields.diceProfileData.guid',\n 'customFields.diceProfileData.uuid',\n 'customFields.diceProfileData.externalId',\n 'customFields.diceProfileData.candidateid',\n 'customFields.diceProfileData.candidateId',\n ];\n\n const explicitDiceId = firstPresentValue(\n ...explicitPaths.map((path) => getPathValue(candidate, path)),\n );\n\n if (explicitDiceId && !isLikelyDiceCandidateId(explicitDiceId, candidate)) {\n return String(explicitDiceId);\n }\n\n const likelyNestedId = findLikelyDiceProfileId(candidate);\n if (likelyNestedId) return likelyNestedId;\n\n const genericId = firstPresentValue(candidate.id, candidate._id);\n \n // For Dice candidates, accept the ID even if it looks like an internal MongoDB ObjectId\n // For non-Dice candidates, reject IDs that look like internal record IDs\n if (genericId && (isDiceCandidate || !isLikelyInternalRecordId(genericId))) {\n return String(genericId);\n }\n \n return '';\n}\n\nexport function normalizeDiceSkills(skills) {\n if (!skills) return [];\n \n if (Array.isArray(skills)) {\n return skills\n .map(skill => {\n // Handle Dice format: {skill: \"courts\", lastUsed: 2026}\n if (skill?.skill) return skill.skill;\n // Handle other object formats\n if (typeof skill === 'object' && skill !== null) {\n if (skill?.name) return skill.name;\n if (skill?.skillName) return skill.skillName;\n if (skill?.value) return skill.value;\n }\n // Handle string skills\n if (typeof skill === 'string') return skill;\n return null;\n })\n .filter(Boolean);\n }\n \n if (typeof skills === 'string') {\n return skills.split(',').map(s => s.trim()).filter(Boolean);\n }\n \n return [];\n}\n\n/**\n * Normalizes location from various Dice location formats\n */\nfunction normalizeDiceLocation(candidate) {\n // Try locations array first (common in Dice)\n if (Array.isArray(candidate.locations) && candidate.locations.length > 0) {\n const loc = candidate.locations[0];\n if (typeof loc === 'string') return loc;\n if (loc?.region) return loc.region;\n if (loc?.city) return loc.city;\n if (loc?.name) return loc.name;\n if (loc?.location) return loc.location;\n }\n \n // Try direct location fields\n return (\n candidate.currentLocation ??\n candidate.location ??\n candidate.city ??\n candidate.region ??\n ''\n );\n}\n\n/**\n * Normalizes experience from various Dice experience formats\n */\nfunction normalizeDiceExperience(candidate) {\n const exp = (\n candidate.totalExperience ??\n candidate.experience ??\n candidate.yearsOfExperience ??\n candidate.exp ??\n candidate.totalYearsOfExperience ??\n candidate.workExperienceYears\n );\n \n return exp != null && exp !== '' ? exp : null;\n}\n\n/**\n * Normalizes date from various Dice date formats\n */\nfunction normalizeDiceDate(candidate) {\n return (\n candidate.dateLastUpdated ??\n candidate.updatedAt ??\n candidate.createdAt ??\n candidate.createdDate ??\n candidate.dateCreated ??\n null\n );\n}\n\n/**\n * Normalizes name from various Dice name formats\n */\nfunction normalizeDiceName(candidate) {\n const parts = [\n candidate.firstName,\n candidate.middleName,\n candidate.lastName,\n ].filter(Boolean);\n \n if (parts.length > 0) return parts.join(' ');\n \n return (\n candidate.fullName ??\n candidate.name ??\n candidate.candidateName ??\n ''\n );\n}\n\n/**\n * Maps a single Dice candidate to the Internal Candidate format\n * \n * @param {Object} diceCandidate - Raw Dice API candidate object\n * @param {number} index - Index for fallback ID generation\n * @returns {Object} Mapped candidate in Internal format\n */\nexport function mapDiceCandidateToInternal(diceCandidate, index = 0) {\n if (!diceCandidate || typeof diceCandidate !== 'object') {\n return {\n id: `dice-candidate-${index}`,\n diceId: '',\n candidateId: '',\n firstName: '',\n lastName: '',\n name: '-',\n designation: '-',\n currentLocation: '',\n location: '',\n exp: '',\n totalExperience: null,\n skills: [],\n createdAt: null,\n createdOn: '-',\n sourceType: 'dice',\n profileSource: 'dice',\n };\n }\n\n const fullName = normalizeDiceName(diceCandidate);\n const nameParts = fullName.split(' ');\n const firstName = nameParts[0] || '';\n const lastName = nameParts.length > 1 ? nameParts[nameParts.length - 1] : '';\n \n const location = normalizeDiceLocation(diceCandidate);\n const experience = normalizeDiceExperience(diceCandidate);\n const createdOn = normalizeDiceDate(diceCandidate);\n const diceProfileId = resolveDiceProfileId(diceCandidate);\n const candidateId = diceCandidate.candidateId\n ?? diceCandidate.customFields?.diceProfileData?.candidateId\n ?? `dice-candidate-${index}`;\n \n // Extract skills from various possible fields\n const rawSkills = diceCandidate.skills ?? \n diceCandidate.technicalSkills ?? \n diceCandidate.primarySkills ??\n diceCandidate.keySkills ??\n [];\n \n const skills = normalizeDiceSkills(rawSkills);\n \n // Debug logging to verify transformation\n if (process.env.NODE_ENV === 'development') {\n console.log('[DiceMapper] Original skills:', rawSkills);\n console.log('[DiceMapper] Mapped skills:', skills);\n console.log('[DiceMapper] Dice IDs:', {\n id: diceProfileId,\n diceId: diceProfileId,\n candidateId,\n });\n }\n\n return {\n // Preserve original Dice fields for reference\n ...diceCandidate,\n \n // Map to Internal candidate schema. Keep the Dice profile id as the primary id.\n id: diceProfileId,\n diceId: diceProfileId,\n candidateId,\n \n // Name fields\n firstName,\n lastName,\n middleName: diceCandidate.middleName || '',\n name: fullName || '-',\n fullName: fullName || '',\n \n // Professional info\n designation: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? diceCandidate.currentDesignation ?? '-',\n currentDesignation: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? diceCandidate.currentDesignation ?? '',\n jobTitle: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? '',\n \n // Location\n currentLocation: location || '',\n location: location || '',\n city: diceCandidate.city ?? diceCandidate.locations?.[0]?.city ?? '',\n region: diceCandidate.region ?? diceCandidate.locations?.[0]?.region ?? '',\n \n // Experience\n totalExperience: experience,\n experience: experience,\n yearsOfExperience: experience,\n exp: experience != null && experience !== '' ? `${experience} yrs` : '',\n \n // Skills\n skills,\n technicalSkills: skills,\n primarySkills: skills,\n \n // Dates\n createdAt: createdOn,\n createdOn: createdOn ? String(createdOn) : '-',\n updatedAt: createdOn,\n dateLastUpdated: createdOn,\n \n // Source identification\n sourceType: 'dice',\n profileSource: 'dice',\n selectedSource: ['dice'],\n \n // Additional fields with defaults\n email: diceCandidate.email ?? diceCandidate.emailAddress ?? '',\n phone: diceCandidate.phone ?? diceCandidate.phoneNumber ?? diceCandidate.mobile ?? '',\n summary: diceCandidate.summary ?? diceCandidate.bio ?? diceCandidate.description ?? '',\n resume: diceCandidate.resume ?? diceCandidate.resumeUrl ?? diceCandidate.cvUrl ?? '',\n \n // Status and metadata\n isActive: true,\n isDeleted: false,\n };\n}\n\n/**\n * Maps an array of Dice candidates to the Internal Candidate format\n * \n * @param {Array} diceCandidates - Array of raw Dice API candidate objects\n * @returns {Array} Array of mapped candidates in Internal format\n */\nexport function mapDiceCandidatesToInternal(diceCandidates) {\n if (!Array.isArray(diceCandidates)) {\n return [];\n }\n \n return diceCandidates.map((candidate, index) => \n mapDiceCandidateToInternal(candidate, index)\n );\n}\n\n/**\n * Transforms a Dice API response to match the existing Candidate List API response format\n * \n * @param {Object} diceResponse - Raw Dice API response\n * @param {Object} originalResponseStructure - The expected response structure from Internal API\n * @returns {Object} Transformed response matching Internal API format\n */\nexport function transformDiceResponseToInternalFormat(diceResponse, originalResponseStructure = {}) {\n if (!diceResponse || typeof diceResponse !== 'object') {\n return {\n status: 'success',\n data: {\n fields: [],\n actions: [],\n columnActions: [],\n count: 0,\n data: [],\n },\n };\n }\n\n // Extract candidates array from various possible response structures\n const diceCandidates = Array.isArray(diceResponse) \n ? diceResponse \n : diceResponse?.data?.data ?? \n diceResponse?.data?.applicant ?? \n diceResponse?.data?.candidates ?? \n diceResponse?.data?.items ?? \n diceResponse?.items ?? \n diceResponse?.candidates ?? \n diceResponse?.records ?? \n [];\n\n // Map Dice candidates to Internal format\n const mappedCandidates = mapDiceCandidatesToInternal(diceCandidates);\n\n // Extract count from various possible locations\n const count = (\n diceResponse?.data?.count?.searchCount ??\n diceResponse?.data?.count?.total ??\n diceResponse?.count?.searchCount ??\n diceResponse?.count?.total ??\n diceResponse?.total ??\n diceResponse?.totalCount ??\n mappedCandidates.length\n );\n\n // Preserve existing metadata from the original response structure\n return {\n status: diceResponse?.status ?? 'success',\n data: {\n // Preserve fields, actions, columnActions from original structure\n fields: originalResponseStructure?.fields ?? diceResponse?.data?.fields ?? diceResponse?.fields ?? [],\n actions: originalResponseStructure?.actions ?? diceResponse?.data?.actions ?? diceResponse?.actions ?? [],\n columnActions: originalResponseStructure?.columnActions ?? diceResponse?.data?.columnActions ?? diceResponse?.columnActions ?? [],\n \n // Count and mapped data\n count: Number(count) || 0,\n data: mappedCandidates,\n \n // Preserve any additional metadata\n ...(diceResponse?.data?.actionRules && { actionRules: diceResponse.data.actionRules }),\n ...(diceResponse?.data?.tabs && { tabs: diceResponse.data.tabs }),\n ...(diceResponse?.data?.tabField && { tabField: diceResponse.data.tabField }),\n },\n };\n}\n\n/**\n * Checks if a response contains Dice candidates\n * \n * @param {Array|Object} response - API response to check\n * @returns {boolean} True if response contains Dice candidates\n */\nexport function isDiceResponse(response) {\n if (!response) return false;\n \n const candidates = Array.isArray(response) \n ? response \n : response?.data?.data ?? \n response?.data?.applicant ?? \n response?.data?.candidates ?? \n response?.data?.items ?? \n response?.items ?? \n [];\n \n if (!Array.isArray(candidates) || candidates.length === 0) {\n return false;\n }\n \n // Check first few candidates for Dice source indicators\n const sampleSize = Math.min(candidates.length, 5);\n for (let i = 0; i < sampleSize; i++) {\n const candidate = candidates[i];\n const sourceType = candidate?.sourceType ?? candidate?.profileSource ?? '';\n if (String(sourceType).toLowerCase() === 'dice') {\n return true;\n }\n }\n \n return false;\n}\n\nexport default {\n mapDiceCandidateToInternal,\n mapDiceCandidatesToInternal,\n transformDiceResponseToInternalFormat,\n isDiceResponse,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"diceCandidateMapper-G6mMmRda.cjs","names":[],"sources":["../src/services/diceCandidateMapper.js"],"sourcesContent":["/**\n * Dice Candidate Response Mapper\n * \n * Transforms Dice API candidate responses into the existing Internal Candidate\n * List API format. This ensures the frontend receives an identical response\n * schema regardless of the data source.\n * \n * Reusable for additional external sources (Monster, CareerBuilder, LinkedIn, etc.)\n */\n\n/**\n * Normalizes skills from various Dice skill formats into a simple string array\n */\nfunction firstPresentValue(...values) {\n return values.find((value) => value !== undefined && value !== null && String(value).trim() !== '');\n}\n\nfunction getPathValue(record, path) {\n if (!record || !path) return undefined;\n if (Object.prototype.hasOwnProperty.call(record, path)) return record[path];\n return String(path)\n .split('.')\n .reduce((value, key) => value?.[key], record);\n}\n\nfunction isLikelyInternalRecordId(value) {\n return /^[a-f0-9]{24}$/i.test(String(value ?? '').trim());\n}\n\nfunction isLikelyDiceProfileId(value) {\n const text = String(value ?? '').trim();\n return (\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(text)\n || /^[a-f0-9]{40,}$/i.test(text)\n );\n}\n\nfunction isLikelyDiceCandidateId(value, candidate) {\n const text = String(value ?? '').trim();\n const knownCandidateId = firstPresentValue(\n candidate?.candidateId,\n candidate?.customFields?.diceProfileData?.candidateId,\n );\n\n return (\n (knownCandidateId && text === String(knownCandidateId).trim())\n || /^[a-f0-9]{40,}-\\d+$/i.test(text)\n );\n}\n\nfunction findLikelyDiceProfileId(record) {\n const seen = new Set();\n const candidates = [];\n\n const visit = (value, path = '') => {\n if (value === null || value === undefined) return;\n if (typeof value === 'string' || typeof value === 'number') {\n const text = String(value).trim();\n const keyLooksRelevant = /(^|[._-])(dice|profile|source|external).*(id|guid|uuid)$|(^|[._-])(id|guid|uuid)$/i.test(path);\n if (text && keyLooksRelevant && isLikelyDiceProfileId(text)) {\n candidates.push({ path, value: text });\n }\n return;\n }\n if (typeof value !== 'object' || seen.has(value)) return;\n seen.add(value);\n Object.entries(value).forEach(([key, child]) => {\n visit(child, path ? `${path}.${key}` : key);\n });\n };\n\n visit(record);\n\n return candidates.find((candidate) => /dice|profile|source|external/i.test(candidate.path))?.value\n ?? candidates[0]?.value\n ?? '';\n}\n\nexport function resolveDiceProfileId(candidate) {\n if (!candidate || typeof candidate !== 'object') return '';\n\n // Check if this is a Dice candidate\n const isDiceCandidate = (() => {\n const source = candidate?.sourceType\n ?? candidate?.profileSource\n ?? candidate?.selectedSource;\n const normalizedSources = Array.isArray(source) ? source : [source];\n return normalizedSources.some(\n (value) => String(value ?? '').trim().toLowerCase() === 'dice',\n );\n })();\n\n const explicitPaths = [\n 'diceId',\n 'diceID',\n 'dice_id',\n 'diceProfileId',\n 'diceProfileID',\n 'diceProfileGuid',\n 'profileId',\n 'profileID',\n 'profileGuid',\n 'sourceId',\n 'sourceProfileId',\n 'externalId',\n 'externalProfileId',\n 'customFields.diceId',\n 'customFields.diceProfileId',\n 'customFields.profileId',\n 'customFields.externalProfileId',\n 'customFields.diceProfileData.diceId',\n 'customFields.diceProfileData.diceID',\n 'customFields.diceProfileData.id',\n 'customFields.diceProfileData._id',\n 'customFields.diceProfileData.profileId',\n 'customFields.diceProfileData.profileID',\n 'customFields.diceProfileData.diceProfileId',\n 'customFields.diceProfileData.diceProfileID',\n 'customFields.diceProfileData.guid',\n 'customFields.diceProfileData.uuid',\n 'customFields.diceProfileData.externalId',\n 'customFields.diceProfileData.candidateid',\n 'customFields.diceProfileData.candidateId',\n ];\n\n const explicitDiceId = firstPresentValue(\n ...explicitPaths.map((path) => getPathValue(candidate, path)),\n );\n\n if (explicitDiceId && !isLikelyDiceCandidateId(explicitDiceId, candidate)) {\n return String(explicitDiceId);\n }\n\n const likelyNestedId = findLikelyDiceProfileId(candidate);\n if (likelyNestedId) return likelyNestedId;\n\n const genericId = firstPresentValue(candidate.id, candidate._id);\n \n // For Dice candidates, accept the ID even if it looks like an internal MongoDB ObjectId\n // For non-Dice candidates, reject IDs that look like internal record IDs\n if (genericId && (isDiceCandidate || !isLikelyInternalRecordId(genericId))) {\n return String(genericId);\n }\n \n return '';\n}\n\nexport function normalizeDiceSkills(skills) {\n if (!skills) return [];\n \n if (Array.isArray(skills)) {\n return skills\n .map(skill => {\n // Handle Dice format: {skill: \"courts\", lastUsed: 2026}\n if (skill?.skill) return skill.skill;\n // Handle other object formats\n if (typeof skill === 'object' && skill !== null) {\n if (skill?.name) return skill.name;\n if (skill?.skillName) return skill.skillName;\n if (skill?.value) return skill.value;\n }\n // Handle string skills\n if (typeof skill === 'string') return skill;\n return null;\n })\n .filter(Boolean);\n }\n \n if (typeof skills === 'string') {\n return skills.split(',').map(s => s.trim()).filter(Boolean);\n }\n \n return [];\n}\n\n/**\n * Normalizes location from various Dice location formats\n */\nfunction normalizeDiceLocation(candidate) {\n // Try locations array first (common in Dice)\n if (Array.isArray(candidate.locations) && candidate.locations.length > 0) {\n const loc = candidate.locations[0];\n if (typeof loc === 'string') return loc;\n if (loc?.region) return loc.region;\n if (loc?.city) return loc.city;\n if (loc?.name) return loc.name;\n if (loc?.location) return loc.location;\n }\n \n // Try direct location fields\n return (\n candidate.currentLocation ??\n candidate.location ??\n candidate.city ??\n candidate.region ??\n ''\n );\n}\n\n/**\n * Normalizes experience from various Dice experience formats\n */\nfunction normalizeDiceExperience(candidate) {\n const exp = (\n candidate.totalExperience ??\n candidate.experience ??\n candidate.yearsOfExperience ??\n candidate.exp ??\n candidate.totalYearsOfExperience ??\n candidate.workExperienceYears\n );\n \n return exp != null && exp !== '' ? exp : null;\n}\n\n/**\n * Normalizes date from various Dice date formats\n */\nfunction normalizeDiceDate(candidate) {\n return (\n candidate.dateLastUpdated ??\n candidate.updatedAt ??\n candidate.createdAt ??\n candidate.createdDate ??\n candidate.dateCreated ??\n null\n );\n}\n\n/**\n * Normalizes name from various Dice name formats\n */\nfunction normalizeDiceName(candidate) {\n const parts = [\n candidate.firstName,\n candidate.middleName,\n candidate.lastName,\n ].filter(Boolean);\n \n if (parts.length > 0) return parts.join(' ');\n \n return (\n candidate.fullName ??\n candidate.name ??\n candidate.candidateName ??\n ''\n );\n}\n\n/**\n * Maps a single Dice candidate to the Internal Candidate format\n * \n * @param {Object} diceCandidate - Raw Dice API candidate object\n * @param {number} index - Index for fallback ID generation\n * @returns {Object} Mapped candidate in Internal format\n */\nexport function mapDiceCandidateToInternal(diceCandidate, index = 0) {\n if (!diceCandidate || typeof diceCandidate !== 'object') {\n return {\n id: `dice-candidate-${index}`,\n diceId: '',\n candidateId: '',\n firstName: '',\n lastName: '',\n name: '-',\n designation: '-',\n currentLocation: '',\n location: '',\n exp: '',\n totalExperience: null,\n skills: [],\n createdAt: null,\n createdOn: '-',\n sourceType: 'dice',\n profileSource: 'dice',\n };\n }\n\n const fullName = normalizeDiceName(diceCandidate);\n const nameParts = fullName.split(' ');\n const firstName = nameParts[0] || '';\n const lastName = nameParts.length > 1 ? nameParts[nameParts.length - 1] : '';\n \n const location = normalizeDiceLocation(diceCandidate);\n const experience = normalizeDiceExperience(diceCandidate);\n const createdOn = normalizeDiceDate(diceCandidate);\n const diceProfileId = resolveDiceProfileId(diceCandidate);\n const candidateId = diceCandidate.candidateId\n ?? diceCandidate.customFields?.diceProfileData?.candidateId\n ?? `dice-candidate-${index}`;\n \n // Extract skills from various possible fields\n const rawSkills = diceCandidate.skills ?? \n diceCandidate.technicalSkills ?? \n diceCandidate.primarySkills ??\n diceCandidate.keySkills ??\n [];\n \n const skills = normalizeDiceSkills(rawSkills);\n \n // Debug logging to verify transformation\n if (process.env.NODE_ENV === 'development') {\n console.log('[DiceMapper] Original skills:', rawSkills);\n console.log('[DiceMapper] Mapped skills:', skills);\n console.log('[DiceMapper] Dice IDs:', {\n id: diceProfileId,\n diceId: diceProfileId,\n candidateId,\n });\n }\n\n return {\n // Preserve original Dice fields for reference\n ...diceCandidate,\n \n // Map to Internal candidate schema. Keep the Dice profile id as the primary id.\n id: diceProfileId,\n diceId: diceProfileId,\n candidateId,\n \n // Name fields\n firstName,\n lastName,\n middleName: diceCandidate.middleName || '',\n name: fullName || '-',\n fullName: fullName || '',\n \n // Professional info\n designation: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? diceCandidate.currentDesignation ?? '-',\n currentDesignation: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? diceCandidate.currentDesignation ?? '',\n jobTitle: diceCandidate.currentJobTitle ?? diceCandidate.jobTitle ?? diceCandidate.designation ?? '',\n \n // Location\n currentLocation: location || '',\n location: location || '',\n city: diceCandidate.city ?? diceCandidate.locations?.[0]?.city ?? '',\n region: diceCandidate.region ?? diceCandidate.locations?.[0]?.region ?? '',\n \n // Experience\n totalExperience: experience,\n experience: experience,\n yearsOfExperience: experience,\n exp: experience != null && experience !== '' ? `${experience} yrs` : '',\n \n // Skills\n skills,\n technicalSkills: skills,\n primarySkills: skills,\n \n // Dates\n createdAt: createdOn,\n createdOn: createdOn ? String(createdOn) : '-',\n updatedAt: createdOn,\n dateLastUpdated: createdOn,\n \n // Source identification\n sourceType: 'dice',\n profileSource: 'dice',\n selectedSource: ['dice'],\n \n // Additional fields with defaults\n email: diceCandidate.email ?? diceCandidate.emailAddress ?? '',\n phone: diceCandidate.phone ?? diceCandidate.phoneNumber ?? diceCandidate.mobile ?? '',\n summary: diceCandidate.summary ?? diceCandidate.bio ?? diceCandidate.description ?? '',\n resume: diceCandidate.resume ?? diceCandidate.resumeUrl ?? diceCandidate.cvUrl ?? '',\n \n // Status and metadata\n isActive: true,\n isDeleted: false,\n };\n}\n\n/**\n * Maps an array of Dice candidates to the Internal Candidate format\n * \n * @param {Array} diceCandidates - Array of raw Dice API candidate objects\n * @returns {Array} Array of mapped candidates in Internal format\n */\nexport function mapDiceCandidatesToInternal(diceCandidates) {\n if (!Array.isArray(diceCandidates)) {\n return [];\n }\n \n return diceCandidates.map((candidate, index) => \n mapDiceCandidateToInternal(candidate, index)\n );\n}\n\n/**\n * Transforms a Dice API response to match the existing Candidate List API response format\n * \n * @param {Object} diceResponse - Raw Dice API response\n * @param {Object} originalResponseStructure - The expected response structure from Internal API\n * @returns {Object} Transformed response matching Internal API format\n */\nexport function transformDiceResponseToInternalFormat(diceResponse, originalResponseStructure = {}) {\n if (!diceResponse || typeof diceResponse !== 'object') {\n return {\n status: 'success',\n data: {\n fields: [],\n actions: [],\n columnActions: [],\n count: 0,\n data: [],\n },\n };\n }\n\n // Extract candidates array from various possible response structures\n const diceCandidates = Array.isArray(diceResponse) \n ? diceResponse \n : diceResponse?.data?.data ?? \n diceResponse?.data?.applicant ?? \n diceResponse?.data?.candidates ?? \n diceResponse?.data?.items ?? \n diceResponse?.items ?? \n diceResponse?.candidates ?? \n diceResponse?.records ?? \n [];\n\n // Map Dice candidates to Internal format\n const mappedCandidates = mapDiceCandidatesToInternal(diceCandidates);\n\n // Extract count from various possible locations\n const count = (\n diceResponse?.data?.count?.searchCount ??\n diceResponse?.data?.count?.total ??\n diceResponse?.count?.searchCount ??\n diceResponse?.count?.total ??\n diceResponse?.total ??\n diceResponse?.totalCount ??\n mappedCandidates.length\n );\n\n // Preserve existing metadata from the original response structure\n return {\n status: diceResponse?.status ?? 'success',\n data: {\n // Preserve fields, actions, columnActions from original structure\n fields: originalResponseStructure?.fields ?? diceResponse?.data?.fields ?? diceResponse?.fields ?? [],\n actions: originalResponseStructure?.actions ?? diceResponse?.data?.actions ?? diceResponse?.actions ?? [],\n columnActions: originalResponseStructure?.columnActions ?? diceResponse?.data?.columnActions ?? diceResponse?.columnActions ?? [],\n \n // Count and mapped data\n count: Number(count) || 0,\n data: mappedCandidates,\n \n // Preserve any additional metadata\n ...(diceResponse?.data?.actionRules && { actionRules: diceResponse.data.actionRules }),\n ...(diceResponse?.data?.tabs && { tabs: diceResponse.data.tabs }),\n ...(diceResponse?.data?.tabField && { tabField: diceResponse.data.tabField }),\n },\n };\n}\n\n/**\n * Checks if a response contains Dice candidates\n * \n * @param {Array|Object} response - API response to check\n * @returns {boolean} True if response contains Dice candidates\n */\nexport function isDiceResponse(response) {\n if (!response) return false;\n \n const candidates = Array.isArray(response) \n ? response \n : response?.data?.data ?? \n response?.data?.applicant ?? \n response?.data?.candidates ?? \n response?.data?.items ?? \n response?.items ?? \n [];\n \n if (!Array.isArray(candidates) || candidates.length === 0) {\n return false;\n }\n \n // Check first few candidates for Dice source indicators\n const sampleSize = Math.min(candidates.length, 5);\n for (let i = 0; i < sampleSize; i++) {\n const candidate = candidates[i];\n const sourceType = candidate?.sourceType ?? candidate?.profileSource ?? '';\n if (String(sourceType).toLowerCase() === 'dice') {\n return true;\n }\n }\n \n return false;\n}\n\nexport default {\n mapDiceCandidateToInternal,\n mapDiceCandidatesToInternal,\n transformDiceResponseToInternalFormat,\n isDiceResponse,\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var e=require("./rolldown-runtime-Chgba0Kb.cjs").t({fetchFormGroupsCached:()=>a,invalidateFormGroupsCache:()=>i}),t=4e3,n=new Map,r=t;function i(){n.clear()}function a(e,t){let i=Date.now(),a=n.get(e);if(a&&(a.pending||i-a.at<r))return a.promise;let o={at:i,pending:!0};return o.promise=Promise.resolve().then(t).then(e=>(o.pending=!1,o.at=Date.now(),e)).catch(t=>{throw n.get(e)===o&&n.delete(e),t}),n.set(e,o),o.promise}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return a}});
2
+ //# sourceMappingURL=formGroupsCache-Bbz-28ws.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"formGroupsCache-Bw0aY136.cjs","names":[],"sources":["../src/services/formGroupsCache.js"],"sourcesContent":["// formGroupsCache — one network request per distinct form-groups query.\n//\n// WHY\n// A single page routinely asks for the SAME form-groups payload several times\n// over, because the parts that need it are independent of each other and none\n// of them can know the others exist: on Quick Submit the job header card, the\n// form's cross-module prefill and a job-source lookup each fetch the same job,\n// and the submission config is fetched once unscoped and again client-scoped.\n// Those payloads are large (60 kB for a submission config), so the duplicates\n// are the expensive kind — a measured 245-request, ~4.8 s load with several\n// identical 60 kB and 15 kB responses in it.\n//\n// The honest fix is not to make each caller aware of the others — that couples\n// components that have no business knowing about each other, and breaks the\n// moment a new one is added. It is to make the REQUEST idempotent: identical\n// queries fired close together share one response.\n//\n// TWO MECHANISMS, deliberately:\n//\n// • in-flight coalescing — a query that is already running is joined rather\n// than reissued. Always safe: the answer cannot be staler than the request\n// that is still in the air.\n// • a SHORT time-to-live — covers the common case where the duplicates are\n// sequential rather than overlapping (a child mounts after its parent's\n// fetch has already resolved). This is the part that can serve stale data,\n// so it is kept to a few seconds and any write invalidates the whole cache.\n//\n// Errors are never cached: a failed fetch removes its entry so the next caller\n// retries for real instead of inheriting the failure.\n//\n// Nothing here knows a module or a field. The cache key is the request URL, so\n// scopes that differ in any way (id, clientId, view, group, action) are\n// different entries and can never be served each other's data.\n\n// Long enough to cover one page's mount burst, short enough that no realistic\n// user action fits inside it. Writes invalidate regardless — see below.\nconst DEFAULT_TTL_MS = 4000;\n\nconst entries = new Map(); // url -> { at, promise }\n\nlet ttlMs = DEFAULT_TTL_MS;\n\n/** Test/host hook: change the window, or set 0 to keep only in-flight coalescing. */\nexport function setFormGroupsCacheTtl(ms) {\n ttlMs = Math.max(0, Number(ms) || 0);\n}\n\n/**\n * Drop everything. Called after any module write: a save is exactly the moment\n * a cached payload stops describing the record, and a stale read here would\n * show the user their own change missing.\n */\nexport function invalidateFormGroupsCache() {\n entries.clear();\n}\n\n/**\n * fetchFormGroupsCached — run `loader()` for `url`, or join/replay a recent\n * identical run.\n *\n * `loader` returns the RAW payload, so every caller shares one request no\n * matter which shape it goes on to read out of it (the groups array, or the\n * whole envelope with recordMeta).\n */\nexport function fetchFormGroupsCached(url, loader) {\n const now = Date.now();\n const hit = entries.get(url);\n // A pending entry is always joinable; a settled one only within the window.\n if (hit && (hit.pending || now - hit.at < ttlMs)) return hit.promise;\n\n const entry = { at: now, pending: true };\n entry.promise = Promise.resolve()\n .then(loader)\n .then((value) => {\n entry.pending = false;\n // Stamp on COMPLETION, not on start: a slow request must not begin life\n // already half-expired, or a burst behind it would reissue immediately.\n entry.at = Date.now();\n return value;\n })\n .catch((err) => {\n // Never cache a failure — the next caller must get a real attempt.\n if (entries.get(url) === entry) entries.delete(url);\n throw err;\n });\n entries.set(url, entry);\n return entry.promise;\n}\n\nexport default { fetchFormGroupsCached, invalidateFormGroupsCache, setFormGroupsCacheTtl };\n"],"mappings":"6GAoCM,EAAiB,IAEjB,EAAU,IAAI,IAEhB,EAAQ,EAYZ,SAAgB,GAA4B,CAC1C,EAAQ,MAAM,CAChB,CAUA,SAAgB,EAAsB,EAAK,EAAQ,CACjD,IAAM,EAAM,KAAK,IAAI,EACf,EAAM,EAAQ,IAAI,CAAG,EAE3B,GAAI,IAAQ,EAAI,SAAW,EAAM,EAAI,GAAK,GAAQ,OAAO,EAAI,QAE7D,IAAM,EAAQ,CAAE,GAAI,EAAK,QAAS,EAAK,EAgBvC,MAfA,GAAM,QAAU,QAAQ,QAAQ,EAC7B,KAAK,CAAM,EACX,KAAM,IACL,EAAM,QAAU,GAGhB,EAAM,GAAK,KAAK,IAAI,EACb,EACR,EACA,MAAO,GAAQ,CAGd,MADI,EAAQ,IAAI,CAAG,IAAM,GAAO,EAAQ,OAAO,CAAG,EAC5C,CACR,CAAC,EACH,EAAQ,IAAI,EAAK,CAAK,EACf,EAAM,OACf"}
1
+ {"version":3,"file":"formGroupsCache-Bbz-28ws.cjs","names":[],"sources":["../src/services/formGroupsCache.js"],"sourcesContent":["// formGroupsCache — one network request per distinct form-groups query.\n//\n// WHY\n// A single page routinely asks for the SAME form-groups payload several times\n// over, because the parts that need it are independent of each other and none\n// of them can know the others exist: on Quick Submit the job header card, the\n// form's cross-module prefill and a job-source lookup each fetch the same job,\n// and the submission config is fetched once unscoped and again client-scoped.\n// Those payloads are large (60 kB for a submission config), so the duplicates\n// are the expensive kind — a measured 245-request, ~4.8 s load with several\n// identical 60 kB and 15 kB responses in it.\n//\n// The honest fix is not to make each caller aware of the others — that couples\n// components that have no business knowing about each other, and breaks the\n// moment a new one is added. It is to make the REQUEST idempotent: identical\n// queries fired close together share one response.\n//\n// TWO MECHANISMS, deliberately:\n//\n// • in-flight coalescing — a query that is already running is joined rather\n// than reissued. Always safe: the answer cannot be staler than the request\n// that is still in the air.\n// • a SHORT time-to-live — covers the common case where the duplicates are\n// sequential rather than overlapping (a child mounts after its parent's\n// fetch has already resolved). This is the part that can serve stale data,\n// so it is kept to a few seconds and any write invalidates the whole cache.\n//\n// Errors are never cached: a failed fetch removes its entry so the next caller\n// retries for real instead of inheriting the failure.\n//\n// Nothing here knows a module or a field. The cache key is the request URL, so\n// scopes that differ in any way (id, clientId, view, group, action) are\n// different entries and can never be served each other's data.\n\n// Long enough to cover one page's mount burst, short enough that no realistic\n// user action fits inside it. Writes invalidate regardless — see below.\nconst DEFAULT_TTL_MS = 4000;\n\nconst entries = new Map(); // url -> { at, promise }\n\nlet ttlMs = DEFAULT_TTL_MS;\n\n/** Test/host hook: change the window, or set 0 to keep only in-flight coalescing. */\nexport function setFormGroupsCacheTtl(ms) {\n ttlMs = Math.max(0, Number(ms) || 0);\n}\n\n/**\n * Drop everything. Called after any module write: a save is exactly the moment\n * a cached payload stops describing the record, and a stale read here would\n * show the user their own change missing.\n */\nexport function invalidateFormGroupsCache() {\n entries.clear();\n}\n\n/**\n * fetchFormGroupsCached — run `loader()` for `url`, or join/replay a recent\n * identical run.\n *\n * `loader` returns the RAW payload, so every caller shares one request no\n * matter which shape it goes on to read out of it (the groups array, or the\n * whole envelope with recordMeta).\n */\nexport function fetchFormGroupsCached(url, loader) {\n const now = Date.now();\n const hit = entries.get(url);\n // A pending entry is always joinable; a settled one only within the window.\n if (hit && (hit.pending || now - hit.at < ttlMs)) return hit.promise;\n\n const entry = { at: now, pending: true };\n entry.promise = Promise.resolve()\n .then(loader)\n .then((value) => {\n entry.pending = false;\n // Stamp on COMPLETION, not on start: a slow request must not begin life\n // already half-expired, or a burst behind it would reissue immediately.\n entry.at = Date.now();\n return value;\n })\n .catch((err) => {\n // Never cache a failure — the next caller must get a real attempt.\n if (entries.get(url) === entry) entries.delete(url);\n throw err;\n });\n entries.set(url, entry);\n return entry.promise;\n}\n\nexport default { fetchFormGroupsCached, invalidateFormGroupsCache, setFormGroupsCacheTtl };\n"],"mappings":"kHAoCM,EAAiB,IAEjB,EAAU,IAAI,IAEhB,EAAQ,EAYZ,SAAgB,GAA4B,CAC1C,EAAQ,MAAM,CAChB,CAUA,SAAgB,EAAsB,EAAK,EAAQ,CACjD,IAAM,EAAM,KAAK,IAAI,EACf,EAAM,EAAQ,IAAI,CAAG,EAE3B,GAAI,IAAQ,EAAI,SAAW,EAAM,EAAI,GAAK,GAAQ,OAAO,EAAI,QAE7D,IAAM,EAAQ,CAAE,GAAI,EAAK,QAAS,EAAK,EAgBvC,MAfA,GAAM,QAAU,QAAQ,QAAQ,CAAC,CAC9B,KAAK,CAAM,CAAC,CACZ,KAAM,IACL,EAAM,QAAU,GAGhB,EAAM,GAAK,KAAK,IAAI,EACb,EACR,CAAC,CACD,MAAO,GAAQ,CAGd,MADI,EAAQ,IAAI,CAAG,IAAM,GAAO,EAAQ,OAAO,CAAG,EAC5C,CACR,CAAC,EACH,EAAQ,IAAI,EAAK,CAAK,EACf,EAAM,OACf"}