datakeen-session-react 1.1.188 → 1.1.189

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 (58) hide show
  1. package/dist/cjs/components/document-video/DocumentVideoCapture.js +2 -2
  2. package/dist/cjs/components/document-video/DocumentVideoCapture.js.map +1 -1
  3. package/dist/cjs/components/document-video/document-video-flow/DocumentVideoProcessing.js +10 -11
  4. package/dist/cjs/components/document-video/document-video-flow/DocumentVideoProcessing.js.map +1 -1
  5. package/dist/cjs/components/jdi/JDIError.js +8 -4
  6. package/dist/cjs/components/jdi/JDIError.js.map +1 -1
  7. package/dist/cjs/components/jdi/JDIProcessing.js +132 -147
  8. package/dist/cjs/components/jdi/JDIProcessing.js.map +1 -1
  9. package/dist/cjs/components/session/DocumentCheck.js +36 -11
  10. package/dist/cjs/components/session/DocumentCheck.js.map +1 -1
  11. package/dist/cjs/components/session/EndFlow.js +10 -1
  12. package/dist/cjs/components/session/EndFlow.js.map +1 -1
  13. package/dist/cjs/components/session/controleJdiPolicy.js +47 -0
  14. package/dist/cjs/components/session/controleJdiPolicy.js.map +1 -0
  15. package/dist/cjs/i18n/en.json.js +8 -3
  16. package/dist/cjs/i18n/en.json.js.map +1 -1
  17. package/dist/cjs/i18n/fr.json.js +8 -3
  18. package/dist/cjs/i18n/fr.json.js.map +1 -1
  19. package/dist/cjs/index.css.js +1 -1
  20. package/dist/cjs/services/pollingService.js.map +1 -1
  21. package/dist/cjs/services/sessionService.js +15 -0
  22. package/dist/cjs/services/sessionService.js.map +1 -1
  23. package/dist/cjs/types/session.js.map +1 -1
  24. package/dist/cjs/utils/apiAnalysis.js.map +1 -1
  25. package/dist/cjs/utils/jdiCodes.js +58 -0
  26. package/dist/cjs/utils/jdiCodes.js.map +1 -0
  27. package/dist/cjs/utils/validationUtils.js +35 -2
  28. package/dist/cjs/utils/validationUtils.js.map +1 -1
  29. package/dist/esm/components/document-video/DocumentVideoCapture.js +2 -2
  30. package/dist/esm/components/document-video/DocumentVideoCapture.js.map +1 -1
  31. package/dist/esm/components/document-video/document-video-flow/DocumentVideoProcessing.js +10 -11
  32. package/dist/esm/components/document-video/document-video-flow/DocumentVideoProcessing.js.map +1 -1
  33. package/dist/esm/components/jdi/JDIError.js +8 -4
  34. package/dist/esm/components/jdi/JDIError.js.map +1 -1
  35. package/dist/esm/components/jdi/JDIProcessing.js +132 -147
  36. package/dist/esm/components/jdi/JDIProcessing.js.map +1 -1
  37. package/dist/esm/components/session/DocumentCheck.js +37 -12
  38. package/dist/esm/components/session/DocumentCheck.js.map +1 -1
  39. package/dist/esm/components/session/EndFlow.js +10 -1
  40. package/dist/esm/components/session/EndFlow.js.map +1 -1
  41. package/dist/esm/components/session/controleJdiPolicy.js +42 -0
  42. package/dist/esm/components/session/controleJdiPolicy.js.map +1 -0
  43. package/dist/esm/i18n/en.json.js +8 -3
  44. package/dist/esm/i18n/en.json.js.map +1 -1
  45. package/dist/esm/i18n/fr.json.js +8 -3
  46. package/dist/esm/i18n/fr.json.js.map +1 -1
  47. package/dist/esm/index.css.js +1 -1
  48. package/dist/esm/services/pollingService.js.map +1 -1
  49. package/dist/esm/services/sessionService.js +15 -1
  50. package/dist/esm/services/sessionService.js.map +1 -1
  51. package/dist/esm/types/session.js.map +1 -1
  52. package/dist/esm/utils/apiAnalysis.js.map +1 -1
  53. package/dist/esm/utils/jdiCodes.js +54 -0
  54. package/dist/esm/utils/jdiCodes.js.map +1 -0
  55. package/dist/esm/utils/validationUtils.js +35 -2
  56. package/dist/esm/utils/validationUtils.js.map +1 -1
  57. package/dist/types/utils/apiAnalysis.d.ts +13 -1
  58. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"sessionService.js","sources":["../../../../src/services/sessionService.ts"],"sourcesContent":["/**\n * Session Service\n *\n * Service for interacting with the Datakeen Session API.\n * Handles fetching session data by ID.\n */\n\nimport type {\n ClientInfo,\n SessionData,\n SessionTemplate,\n SessionTemplateNode,\n} from \"../types/session\";\nimport { apiService } from \"./api\";\nimport { logStatusModified } from \"./auditTrailService\";\nimport { clearSessionMemory } from \"./sessionMemoryStore\";\n\n/**\n * Fetches session data by ID from the Datakeen backend\n *\n * @param sessionId - The unique identifier of the session\n * @returns The session data\n */\nexport const fetchSessionById = async (\n sessionId: string,\n): Promise<SessionData> => {\n try {\n const response = await apiService.get(`/session/sdk/${sessionId}`);\n return response.data;\n } catch (error) {\n console.error(\"Error fetching session data:\", error);\n throw error;\n }\n};\n\n/** Sends client information (IP, device, browser, OS) to the backend for a specific session\n *\n * @param sessionId - The unique identifier of the session\n * @param clientInfo - The client information to send\n */\nexport const sendClientInfo = async (\n sessionId: string,\n clientInfo: ClientInfo,\n): Promise<void> => {\n try {\n await apiService.post(`/session/sdk/${sessionId}/client-info`, clientInfo);\n } catch (error) {\n console.error(\"Error sending client info:\", error);\n throw error;\n }\n};\n\n/**\n * Determines if the session template has a specific type of node\n *\n * @param template - The session template\n * @param nodeType - The type of node to check for\n * @returns true if the template has a node of the specified type, false otherwise\n */\nexport const hasNodeType = (\n template: SessionTemplate,\n nodeType: string,\n): boolean => {\n return template.nodes.some((node) => node.type === nodeType);\n};\n\n/**\n * Determines if the session template has a node with a specific requiredDocumentType\n *\n * @param template - The session template\n * @param requiredDocumentType - The requiredDocumentType to check for\n * @returns true if the template has a node with the specified requiredDocumentType, false otherwise\n */\nexport const hasDocumentTypeNode = (\n template: SessionTemplate,\n requiredDocumentType: string,\n): boolean => {\n return template.nodes.some(\n (node) => node.requiredDocumentType === requiredDocumentType,\n );\n};\n\n/**\n * Gets all nodes of a specific type\n *\n * @param template - The session template\n * @param nodeType - The type of node to get\n * @returns Array of nodes matching the type\n */\nexport const getNodesByType = (\n template: SessionTemplate,\n nodeType: string,\n): SessionTemplateNode[] => {\n return template.nodes.filter((node) => node.type === nodeType);\n};\n\n/**\n * Gets all nodes with a specific requiredDocumentType\n *\n * @param template - The session template\n * @param requiredDocumentType - The requiredDocumentType to get\n * @returns Array of nodes matching the requiredDocumentType\n */\nexport const getNodesByDocumentType = (\n template: SessionTemplate,\n requiredDocumentType: string,\n): SessionTemplateNode[] => {\n return template.nodes.filter(\n (node) => node.requiredDocumentType === requiredDocumentType,\n );\n};\n\n/**\n * Get document options for a specific document type\n *\n * @param template - The session template\n * @param requiredDocumentType - The document type to get options for\n * @returns Array of document options (empty if none found)\n */\nexport const getDocumentOptions = (\n template: SessionTemplate,\n requiredDocumentType: string,\n): string[] => {\n const node = template.nodes.find(\n (node) => node.requiredDocumentType === requiredDocumentType,\n );\n return node?.selectedOptions || [];\n};\n\n/**\n * Determines if the session template has a selfie step\n *\n * @param template - The session template\n * @returns true if the template has a selfie step, false otherwise\n */\nexport const hasSelfieCaptureStep = (template: SessionTemplate): boolean => {\n return hasNodeType(template, \"selfie-capture\");\n};\n\n/**\n * Determines if the session template has an ID document step\n *\n * @param template - The session template\n * @returns true if the template has an ID document step, false otherwise\n */\nexport const hasDocumentStep = (template: SessionTemplate): boolean => {\n // Check if there's any document-selection node with requiredDocumentType \"id-card\"\n // or if none specified, just check for document-selection nodes\n const hasIDCard = hasDocumentTypeNode(template, \"id-card\");\n return hasIDCard || hasNodeType(template, \"document-selection\");\n};\n\n/**\n * Determines if the session template has a JDD (proof of address) step\n *\n * @param template - The session template\n * @returns true if the template has a JDD step, false otherwise\n */\nexport const hasJDDStep = (template: SessionTemplate): boolean => {\n return hasDocumentTypeNode(template, \"jdd\");\n};\n\n/**\n * Determines if the session template has a proof of funds step\n *\n * @param template - The session template\n * @returns true if the template has a proof of funds step, false otherwise\n */\nexport const hasProofOfFundsStep = (template: SessionTemplate): boolean => {\n return hasDocumentTypeNode(template, \"income-proof\");\n};\n\n/**\n * Determines if the session template has a document collection step\n *\n * @param template - The session template\n * @returns true if the template has a document collection step, false otherwise\n */\nexport const hasDocumentCollectionStep = (\n template: SessionTemplate,\n): boolean => {\n return hasNodeType(template, \"document-collection\");\n};\n\n/**\n * Gets all node types in the template\n *\n * @param template - The session template\n * @returns Array of node types in the template\n */\nexport const getNodeTypes = (template: SessionTemplate): string[] => {\n return Array.from(new Set(template.nodes.map((node) => node.type)));\n};\n\n/**\n * Gets all document types required in the template\n *\n * @param template - The session template\n * @returns Array of document types required in the template\n */\nexport const getRequiredDocumentTypes = (\n template: SessionTemplate,\n): string[] => {\n return Array.from(\n new Set(\n template.nodes\n .filter((node) => node.requiredDocumentType)\n .map((node) => node.requiredDocumentType!),\n ),\n );\n};\n\n/**\n * Converts template document type to internal document type\n * This helps standardize document types between the template and the application\n *\n * @param templateDocType - The document type as defined in the template\n * @returns The internal document type used by the application\n */\nexport const convertTemplateDocTypeToInternal = (\n templateDocType: string,\n): string => {\n if (!templateDocType) return \"\";\n\n // Mapping between template document types and internal document types\n const typeMap: Record<string, string> = {\n \"id-card\": \"id-card\",\n jdd: \"jdd\",\n \"income-proof\": \"income-proof\", // Using consistent naming\n };\n\n return typeMap[templateDocType] || templateDocType;\n};\n\n/**\n * Converts internal document type to template document type\n *\n * @param internalDocType - The document type used internally by the application\n * @returns The document type as expected in the template\n */\nexport const convertInternalDocTypeToTemplate = (\n internalDocType: string,\n): string => {\n if (!internalDocType) return \"\";\n\n // Mapping between internal document types and template document types\n const typeMap: Record<string, string> = {\n \"id-card\": \"id-card\",\n jdd: \"jdd\",\n funds: \"income-proof\", // Map funds to income-proof for backwards compatibility\n \"income-proof\": \"income-proof\",\n };\n\n return typeMap[internalDocType] || internalDocType;\n};\n\n/**\n * Updates session data with user input information\n *\n * @param sessionId - The unique identifier of the session\n * @param userInput - The user input data (firstName, lastName, birthDate)\n * @returns The updated session data\n */\nexport const updateSessionUserInput = async (\n sessionId: string,\n userInput: {\n firstName?: string;\n lastName?: string;\n birthDate?: string;\n [key: string]: unknown;\n },\n): Promise<SessionData> => {\n try {\n const response = await apiService.patch(`/session/sdk/${sessionId}`, {\n userInput,\n });\n return response.data;\n } catch (error) {\n console.error(\"Error updating session data:\", error);\n throw error;\n }\n};\n\n/**\n * Records the NFC fallback reason when the user declares they cannot use the\n * contactless scan, and marks the NFC scan as skipped server-side.\n *\n * @param sessionId - The unique identifier of the session\n * @param payload - The selected reason (technical key), its human-readable label,\n * and an optional free-text comment.\n */\nexport const skipNfcWithReason = async (\n sessionId: string,\n payload: { reason: string; label: string; comment?: string },\n): Promise<void> => {\n await apiService.post(`/session/sdk/${sessionId}/nfc-skip`, payload);\n};\n\nexport type SelfieFailureReason =\n | \"timeout\"\n | \"network_error\"\n | \"api_error\"\n | \"user_bypassed\";\n\nexport interface SelfieFailurePayload {\n nodeId: string;\n reason?: SelfieFailureReason;\n conformityCode?: string;\n bypassed?: boolean;\n}\n\nexport const reportSelfieFailure = async (\n sessionId: string,\n payload: SelfieFailurePayload,\n): Promise<void> => {\n await apiService.post(`/session/sdk/${sessionId}/selfie-failed`, payload);\n};\n\n/**\n * Resets a terminal NFC failure before the user starts again with another\n * document. The backend keeps completed scans immutable and treats this call\n * as a no-op when the status is not terminal.\n */\nexport const resetNfcScan = async (sessionId: string): Promise<void> => {\n await apiService.post(`/session/sdk/${sessionId}/nfc-reset`);\n};\n\n/**\n * Updates session data with contact information\n *\n * @param sessionId - The unique identifier of the session\n * @param contactInfo - The contact information data (email, phoneNumber)\n * @returns The updated session data\n */\nexport const updateSessionContactInfo = async (\n sessionId: string,\n contactInfo: {\n email: string;\n phoneNumber: string;\n [key: string]: unknown;\n },\n): Promise<SessionData> => {\n try {\n const response = await apiService.patch(`/session/sdk/${sessionId}`, {\n contactInfo,\n });\n return response.data;\n } catch (error) {\n console.error(\"Error updating contact information:\", error);\n throw error;\n }\n};\n\n/**\n * Updates session status\n *\n * @param sessionId - The unique identifier of the session\n * @param status - The new status for the session\n * @param reachedEndNodeId - Id of the end node actually reached (when status is \"ended\"),\n * so the backend can force the correct final status with multiple end nodes.\n * @returns The updated session data\n */\nexport const updateSessionStatus = async (\n sessionId: string,\n status: string,\n reachedEndNodeId?: string,\n): Promise<SessionData> => {\n try {\n const response = await apiService.patch(`/session/sdk/${sessionId}`, {\n status,\n ...(reachedEndNodeId ? { reachedEndNodeId } : {}),\n });\n\n // Log status modification in audit trail\n if (response.data && response.data.analysisId) {\n try {\n await logStatusModified(\n sessionId,\n status,\n response.data.clientInfoId || undefined,\n );\n } catch (err) {\n console.error(\"Failed to log status modification in audit trail:\", err);\n // Non-blocking error - continue session\n }\n }\n\n return response.data;\n } catch (error) {\n console.error(\"Error updating session status:\", error);\n throw error;\n }\n};\n\n/**\n * Updates the current step in the session\n *\n * @param sessionId - The unique identifier of the session\n * @param currentStep - The current step index in the workflow\n * @returns The updated session data\n */\nexport const updateSessionCurrentStep = async (\n sessionId: string,\n currentStep: number,\n): Promise<SessionData> => {\n try {\n const response = await apiService.patch(`/session/sdk/${sessionId}`, {\n currentStep,\n });\n return response.data;\n } catch (error) {\n console.error(\"Error updating session current step:\", error);\n throw error;\n }\n};\n\n/**\n * Gets the journey steps from the template in order\n *\n * @param template - The session template\n * @returns Array of ordered steps\n */\nexport const getOrderedJourneySteps = (\n template: SessionTemplate,\n): SessionTemplateNode[] => {\n // Filter out only start nodes, keep end nodes for proper journey completion, then sort by order.\n // Tiebreaker on id keeps the ordering deterministic when several nodes share the same `order`\n // (e.g. parallel branches of a condition), independently of their position in template.nodes.\n return template.nodes\n .filter((node) => node.type !== \"start\")\n .sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));\n};\n\nconst normalizeHandle = (value?: string): string => {\n return (value || \"\").trim().toLowerCase();\n};\n\n/**\n * Finds the outgoing edge to follow from a node.\n *\n * Resolution order:\n * 1. Exact handle match via sourceHandle/conditionValue.\n * 2. For condition:false loops, fallback to targetHandle=right.\n * 3. First outgoing edge as final fallback.\n */\nexport const findOutgoingEdge = (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n): SessionTemplate[\"edges\"][number] | null => {\n const outgoingEdges = (template.edges || []).filter(\n (edge) => edge.source === currentNodeId,\n );\n\n if (outgoingEdges.length === 0) {\n return null;\n }\n\n if (!handle) {\n return outgoingEdges[0];\n }\n\n const normalizedHandle = normalizeHandle(handle);\n const edgeByHandle = outgoingEdges.find((edge) => {\n return (\n normalizeHandle(edge.sourceHandle) === normalizedHandle ||\n normalizeHandle(edge.conditionValue) === normalizedHandle\n );\n });\n\n if (edgeByHandle) {\n return edgeByHandle;\n }\n\n const currentNode = template.nodes.find((node) => node.id === currentNodeId);\n if (currentNode?.type === \"condition\" && normalizedHandle === \"false\") {\n const rightHandleLoopEdge = outgoingEdges.find(\n (edge) => normalizeHandle(edge.targetHandle) === \"right\",\n );\n if (rightHandleLoopEdge) {\n return rightHandleLoopEdge;\n }\n }\n\n return outgoingEdges[0];\n};\n\n/**\n * Gets the next step index by following the graph edge from the current node\n *\n * @param currentNodeId - The ID of the current node\n * @param template - The session template\n * @returns The next step index (1-based) or null if no edge found\n */\nexport const getNextStepIndex = (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n): number | null => {\n const orderedNodes = getOrderedJourneySteps(template);\n const edge = findOutgoingEdge(currentNodeId, template, handle);\n\n if (!edge) {\n console.debug(\n `[sessionService] No outgoing edge found for node ${currentNodeId}${handle ? ` with handle ${handle}` : \"\"}`,\n );\n return null;\n }\n\n const targetId = edge.target;\n const targetIndex = orderedNodes.findIndex((n) => n.id === targetId);\n\n if (targetIndex === -1) {\n console.debug(\n `[sessionService] Target node ${targetId} not found in ordered steps`,\n );\n return null;\n }\n\n // steps are 1-indexed in the SDK (0 is StartSession)\n return 1 + targetIndex;\n};\n\n/**\n * Reconstructs the navigation history by following the graph from step 0\n * up to (and including) targetStep. Returns [0, ...stepIndices].\n * If the graph path cannot reach targetStep, falls back to [0, targetStep].\n */\nexport const reconstructHistoryToStep = (\n targetStep: number,\n template: SessionTemplate,\n): number[] => {\n if (targetStep <= 0) return [0];\n\n const orderedNodes = getOrderedJourneySteps(template);\n const history: number[] = [0];\n let currentStep = 1; // first node is step 1\n\n // Follow the default (first) edge from each node in sequence\n for (let safetyLimit = 0; safetyLimit < orderedNodes.length + 1; safetyLimit++) {\n if (currentStep === targetStep) {\n history.push(currentStep);\n break;\n }\n if (currentStep > targetStep) break;\n\n const nodeIndex = currentStep - 1;\n const currentNode = orderedNodes[nodeIndex];\n if (!currentNode) break;\n\n history.push(currentStep);\n\n const nextStep = getNextStepIndex(currentNode.id, template);\n if (nextStep === null) break;\n currentStep = nextStep;\n }\n\n // Fallback: if we couldn't reach targetStep via graph, use simple seed\n if (history[history.length - 1] !== targetStep) {\n return [0, targetStep];\n }\n\n return history;\n};\n\n/**\n * Maps a template node type to a step component type\n *\n * @param node - The session template node\n * @returns The step component type\n */\nexport const getStepComponentType = (node: SessionTemplateNode): string => {\n // Map from template node types to component types\n const typeMap: Record<string, string> = {\n \"document-selection\": \"document\",\n \"document-collection\": \"document-collection\",\n \"selfie-capture\": \"selfie\",\n \"contact-info\": \"contact-info\",\n \"user-input\": \"user-input\",\n \"otp-verification\": \"otp\",\n };\n\n // First check the node type\n if (node.type in typeMap) {\n return typeMap[node.type];\n }\n\n // Then check the requiredDocumentType\n if (node.requiredDocumentType) {\n return node.requiredDocumentType;\n }\n\n // Default fallback\n return node.type;\n};\n\n/**\n * Checks if a session has expired\n *\n * @param session - The session data to check\n * @returns true if the session has expired, false otherwise\n */\nexport const isSessionExpired = (session: SessionData): boolean => {\n if (!session.expireTime) {\n return false;\n }\n\n const currentTime = Date.now();\n return currentTime > session.expireTime;\n};\n\n/**\n * Stores document options in localStorage for a specific document type\n *\n * @param sessionId - The session ID\n * @param documentTypeId - The document type ID (e.g., 'jdd', 'income-proof')\n * @param options - The options to store\n */\nexport const storeDocumentOptions = (\n sessionId: string,\n documentTypeId: string,\n options: string[],\n): void => {\n if (!sessionId || !documentTypeId || !options || options.length === 0) {\n console.warn(\"Missing data for storeDocumentOptions:\", {\n sessionId,\n documentTypeId,\n options,\n });\n return;\n }\n\n // Create a consistent key format based on document type\n let storageKey = \"\";\n\n switch (documentTypeId) {\n case \"jdd\":\n storageKey = `jddOptions_${sessionId}`;\n break;\n case \"income-proof\":\n storageKey = `fundsOptions_${sessionId}`;\n break;\n case \"id-card\":\n storageKey = `idOptions_${sessionId}`;\n break;\n case \"document-collection\":\n storageKey = `documentCollectionOptions_${sessionId}`;\n break;\n default:\n storageKey = `${documentTypeId}Options_${sessionId}`;\n }\n\n localStorage.setItem(storageKey, JSON.stringify(options));\n};\n\n/**\n * Retrieves document options from localStorage for a specific document type\n *\n * @param sessionId - The session ID\n * @param documentTypeId - The document type ID (e.g., 'jdd', 'income-proof')\n * @returns Array of options or default options if none found\n */\nexport const retrieveDocumentOptions = (\n sessionId: string,\n documentTypeId: string,\n): string[] => {\n if (!sessionId || !documentTypeId) {\n console.warn(\"Missing data for retrieveDocumentOptions:\", {\n sessionId,\n documentTypeId,\n });\n return [];\n }\n\n // Create consistent key formats to check\n const possibleKeys = [\n `${documentTypeId}Options_${sessionId}`,\n documentTypeId === \"jdd\" ? `jddOptions_${sessionId}` : \"\",\n documentTypeId === \"income-proof\" ? `fundsOptions_${sessionId}` : \"\",\n documentTypeId === \"id-card\" ? `idOptions_${sessionId}` : \"\",\n documentTypeId === \"document-collection\"\n ? `documentCollectionOptions_${sessionId}`\n : \"\",\n ].filter(Boolean);\n\n // Try each possible key\n for (const key of possibleKeys) {\n const savedOptions = localStorage.getItem(key);\n if (savedOptions) {\n try {\n const parsedOptions = JSON.parse(savedOptions);\n\n return parsedOptions;\n } catch (e) {\n console.error(\n `Error parsing options for ${documentTypeId} with key ${key}:`,\n e,\n );\n }\n }\n }\n\n // Return default options if none found\n console.warn(`No options found for ${documentTypeId}, using defaults`);\n if (documentTypeId === \"jdd\") {\n return [\n \"Facture d'électricité (< 3 mois)\",\n \"Facture de gaz (< 3 mois)\",\n \"Facture d'eau (< 3 mois)\",\n \"Quittance de loyer (< 3 mois)\",\n \"Facture téléphone/internet (< 3 mois)\",\n \"Attestation d'assurance habitation (< 3 mois)\",\n ];\n } else if (documentTypeId === \"income-proof\") {\n return [\n \"Bulletin de salaire\",\n \"Avis d'imposition\",\n \"Relevé de compte bancaire\",\n \"Attestation de revenus\",\n \"Contrat de travail\",\n ];\n } else if (documentTypeId === \"id-card\") {\n return [\"Carte nationale d'identité\", \"Passeport\", \"Permis de conduire\"];\n } else if (documentTypeId === \"document-collection\") {\n return [\"Document administratif\", \"Justificatif\", \"Attestation\"];\n }\n\n return [];\n};\n\nconst clearStorageBySessionId = (sessionId: string): void => {\n const scopedKeys = [\n `userInput_${sessionId}`,\n `contactInfo_${sessionId}`,\n `sessionData_${sessionId}`,\n ];\n\n scopedKeys.forEach((key) => {\n localStorage.removeItem(key);\n sessionStorage.removeItem(key);\n });\n\n for (let i = localStorage.length - 1; i >= 0; i -= 1) {\n const key = localStorage.key(i);\n if (!key) {\n continue;\n }\n if (key.endsWith(`_${sessionId}`)) {\n localStorage.removeItem(key);\n }\n }\n\n for (let i = sessionStorage.length - 1; i >= 0; i -= 1) {\n const key = sessionStorage.key(i);\n if (!key) {\n continue;\n }\n if (key.endsWith(`_${sessionId}`)) {\n sessionStorage.removeItem(key);\n }\n }\n\n if (localStorage.getItem(\"sessionId\") === sessionId) {\n localStorage.removeItem(\"sessionId\");\n }\n if (sessionStorage.getItem(\"sessionId\") === sessionId) {\n sessionStorage.removeItem(\"sessionId\");\n }\n};\n\n/**\n * Clears all client-side session traces (memory + browser storage)\n * for a given session. This is intentionally aggressive for security.\n */\nexport const clearSessionSensitiveData = (sessionId?: string): void => {\n clearSessionMemory(sessionId);\n\n if (sessionId) {\n clearStorageBySessionId(sessionId);\n return;\n }\n\n localStorage.removeItem(\"sessionId\");\n sessionStorage.removeItem(\"sessionId\");\n\n for (let i = localStorage.length - 1; i >= 0; i -= 1) {\n const key = localStorage.key(i);\n if (!key) {\n continue;\n }\n if (\n key.startsWith(\"userInput_\") ||\n key.startsWith(\"contactInfo_\") ||\n key.includes(\"Options_\")\n ) {\n localStorage.removeItem(key);\n }\n }\n\n for (let i = sessionStorage.length - 1; i >= 0; i -= 1) {\n const key = sessionStorage.key(i);\n if (!key) {\n continue;\n }\n if (\n key.startsWith(\"userInput_\") ||\n key.startsWith(\"contactInfo_\") ||\n key.includes(\"Options_\")\n ) {\n sessionStorage.removeItem(key);\n }\n }\n};\n\n/**\n * Returns the pre-fill data for a given run index from a `userInput` object\n * that contains a `_list` array.\n *\n * Convention: when the integrator wants to pre-fill different data per run\n * (e.g. multiple persons in a loop), they pass `userInput: { _list: [...] }`\n * at session creation. Each element in `_list` corresponds to a run (0-indexed).\n *\n * @param userInput - The session's userInput object\n * @param runIndex - The current run index (0 = first pass, 1 = second pass, …)\n * @returns The pre-fill data for that run, or null if not defined\n */\nexport const getRunPrefillData = (\n userInput: Record<string, unknown>,\n runIndex: number,\n): Record<string, unknown> | null => {\n const list = userInput?._list;\n if (!Array.isArray(list)) return null;\n return (list[runIndex] as Record<string, unknown>) ?? null;\n};\n"],"names":["__awaiter","apiService","__assign","logStatusModified","clearSessionMemory"],"mappings":";;;;;;;AAAA;;;;;AAKG;AAYH;;;;;AAKG;AACI,IAAM,gBAAgB,GAAG,UAC9B,SAAiB,EAAA,EAAA,OAAAA,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;;;;gBAGE,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,GAAG,CAAC,uBAAgB,SAAS,CAAE,CAAC,CAAA;;AAA5D,gBAAA,QAAQ,GAAG,EAAA,CAAA,IAAA,EAAiD;gBAClE,OAAA,CAAA,CAAA,aAAO,QAAQ,CAAC,IAAI,CAAA;;;AAEpB,gBAAA,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,OAAK,CAAC;AACpD,gBAAA,MAAM,OAAK;;;;;AAIf;;;;AAIG;AACI,IAAM,cAAc,GAAG,UAC5B,SAAiB,EACjB,UAAsB,EAAA,EAAA,OAAAD,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;;;;gBAGpB,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,IAAI,CAAC,eAAA,CAAA,MAAA,CAAgB,SAAS,EAAA,cAAA,CAAc,EAAE,UAAU,CAAC,CAAA;;AAA1E,gBAAA,EAAA,CAAA,IAAA,EAA0E;;;;AAE1E,gBAAA,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,OAAK,CAAC;AAClD,gBAAA,MAAM,OAAK;;;;;AAgNf;;;;;;AAMG;AACI,IAAM,sBAAsB,GAAG,UACpC,SAAiB,EACjB,SAKC,EAAA,EAAA,OAAAD,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;;;;AAGkB,gBAAA,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,KAAK,CAAC,eAAA,CAAA,MAAA,CAAgB,SAAS,CAAE,EAAE;AACnE,wBAAA,SAAS,EAAA,SAAA;AACV,qBAAA,CAAC,CAAA;;AAFI,gBAAA,QAAQ,GAAG,EAAA,CAAA,IAAA,EAEf;gBACF,OAAA,CAAA,CAAA,aAAO,QAAQ,CAAC,IAAI,CAAA;;;AAEpB,gBAAA,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,OAAK,CAAC;AACpD,gBAAA,MAAM,OAAK;;;;;AAIf;;;;;;;AAOG;AACI,IAAM,iBAAiB,GAAG,UAC/B,SAAiB,EACjB,OAA4D,EAAA,EAAA,OAAAD,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;oBAE5D,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,IAAI,CAAC,eAAA,CAAA,MAAA,CAAgB,SAAS,EAAA,WAAA,CAAW,EAAE,OAAO,CAAC,CAAA;;AAApE,gBAAA,EAAA,CAAA,IAAA,EAAoE;;;;;AAgB/D,IAAM,mBAAmB,GAAG,UACjC,SAAiB,EACjB,OAA6B,EAAA,EAAA,OAAAD,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;oBAE7B,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,IAAI,CAAC,eAAA,CAAA,MAAA,CAAgB,SAAS,EAAA,gBAAA,CAAgB,EAAE,OAAO,CAAC,CAAA;;AAAzE,gBAAA,EAAA,CAAA,IAAA,EAAyE;;;;;AAG3E;;;;AAIG;AACI,IAAM,YAAY,GAAG,UAAO,SAAiB,EAAA,EAAA,OAAAD,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;oBAClD,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,IAAI,CAAC,uBAAgB,SAAS,EAAA,YAAA,CAAY,CAAC,CAAA;;AAA5D,gBAAA,EAAA,CAAA,IAAA,EAA4D;;;;;AAG9D;;;;;;AAMG;AACI,IAAM,wBAAwB,GAAG,UACtC,SAAiB,EACjB,WAIC,EAAA,EAAA,OAAAD,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;;;;AAGkB,gBAAA,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,KAAK,CAAC,eAAA,CAAA,MAAA,CAAgB,SAAS,CAAE,EAAE;AACnE,wBAAA,WAAW,EAAA,WAAA;AACZ,qBAAA,CAAC,CAAA;;AAFI,gBAAA,QAAQ,GAAG,EAAA,CAAA,IAAA,EAEf;gBACF,OAAA,CAAA,CAAA,aAAO,QAAQ,CAAC,IAAI,CAAA;;;AAEpB,gBAAA,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,OAAK,CAAC;AAC3D,gBAAA,MAAM,OAAK;;;;;AAIf;;;;;;;;AAQG;IACU,mBAAmB,GAAG,UACjC,SAAiB,EACjB,MAAc,EACd,gBAAyB,EAAA,EAAA,OAAAD,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;;;;gBAGN,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,KAAK,CAAC,eAAA,CAAA,MAAA,CAAgB,SAAS,CAAE,EAAAC,kBAAA,CAAA,EACjE,MAAM,EAAA,MAAA,EAAA,GACF,gBAAgB,GAAG,EAAE,gBAAgB,EAAA,gBAAA,EAAE,GAAG,EAAE,EAAC,CACjD,CAAA;;AAHI,gBAAA,QAAQ,GAAG,EAAA,CAAA,IAAA,EAGf;sBAGE,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAA,EAAzC,OAAA,CAAA,CAAA,YAAA,CAAA,CAAA;;;;AAEA,gBAAA,OAAA,CAAA,CAAA,YAAMC,mCAAiB,CACrB,SAAS,EACT,MAAM,EACN,QAAQ,CAAC,IAAI,CAAC,YAAY,IAAI,SAAS,CACxC,CAAA;;AAJD,gBAAA,EAAA,CAAA,IAAA,EAIC;;;;AAED,gBAAA,OAAO,CAAC,KAAK,CAAC,mDAAmD,EAAE,KAAG,CAAC;;oBAK3E,OAAA,CAAA,CAAA,aAAO,QAAQ,CAAC,IAAI,CAAA;;;AAEpB,gBAAA,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,OAAK,CAAC;AACtD,gBAAA,MAAM,OAAK;;;;;AAIf;;;;;;AAMG;AACI,IAAM,wBAAwB,GAAG,UACtC,SAAiB,EACjB,WAAmB,EAAA,EAAA,OAAAH,mBAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;;;;AAGA,gBAAA,OAAA,CAAA,CAAA,YAAMC,cAAU,CAAC,KAAK,CAAC,eAAA,CAAA,MAAA,CAAgB,SAAS,CAAE,EAAE;AACnE,wBAAA,WAAW,EAAA,WAAA;AACZ,qBAAA,CAAC,CAAA;;AAFI,gBAAA,QAAQ,GAAG,EAAA,CAAA,IAAA,EAEf;gBACF,OAAA,CAAA,CAAA,aAAO,QAAQ,CAAC,IAAI,CAAA;;;AAEpB,gBAAA,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,OAAK,CAAC;AAC5D,gBAAA,MAAM,OAAK;;;;;AAIf;;;;;AAKG;AACI,IAAM,sBAAsB,GAAG,UACpC,QAAyB,EAAA;;;;IAKzB,OAAO,QAAQ,CAAC;AACb,SAAA,MAAM,CAAC,UAAC,IAAI,EAAA,EAAK,OAAA,IAAI,CAAC,IAAI,KAAK,OAAO,CAAA,CAArB,CAAqB;AACtC,SAAA,IAAI,CAAC,UAAC,CAAC,EAAE,CAAC,EAAA,EAAK,OAAA,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA,CAA7C,CAA6C,CAAC;AAClE;AAEA,IAAM,eAAe,GAAG,UAAC,KAAc,EAAA;IACrC,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE;AAC3C,CAAC;AAED;;;;;;;AAOG;IACU,gBAAgB,GAAG,UAC9B,aAAqB,EACrB,QAAyB,EACzB,MAAe,EAAA;IAEf,IAAM,aAAa,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,MAAM,CACjD,UAAC,IAAI,EAAA,EAAK,OAAA,IAAI,CAAC,MAAM,KAAK,aAAa,CAAA,CAA7B,CAA6B,CACxC;AAED,IAAA,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;AAC9B,QAAA,OAAO,IAAI;IACb;IAEA,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,OAAO,aAAa,CAAC,CAAC,CAAC;IACzB;AAEA,IAAA,IAAM,gBAAgB,GAAG,eAAe,CAAC,MAAM,CAAC;AAChD,IAAA,IAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,UAAC,IAAI,EAAA;QAC3C,QACE,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,gBAAgB;YACvD,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,gBAAgB;AAE7D,IAAA,CAAC,CAAC;IAEF,IAAI,YAAY,EAAE;AAChB,QAAA,OAAO,YAAY;IACrB;IAEA,IAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,UAAC,IAAI,IAAK,OAAA,IAAI,CAAC,EAAE,KAAK,aAAa,CAAA,CAAzB,CAAyB,CAAC;AAC5E,IAAA,IAAI,CAAA,WAAW,KAAA,IAAA,IAAX,WAAW,uBAAX,WAAW,CAAE,IAAI,MAAK,WAAW,IAAI,gBAAgB,KAAK,OAAO,EAAE;QACrE,IAAM,mBAAmB,GAAG,aAAa,CAAC,IAAI,CAC5C,UAAC,IAAI,EAAA,EAAK,OAAA,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,OAAO,CAAA,CAA9C,CAA8C,CACzD;QACD,IAAI,mBAAmB,EAAE;AACvB,YAAA,OAAO,mBAAmB;QAC5B;IACF;AAEA,IAAA,OAAO,aAAa,CAAC,CAAC,CAAC;AACzB;AAEA;;;;;;AAMG;IACU,gBAAgB,GAAG,UAC9B,aAAqB,EACrB,QAAyB,EACzB,MAAe,EAAA;AAEf,IAAA,IAAM,YAAY,GAAG,sBAAsB,CAAC,QAAQ,CAAC;IACrD,IAAM,IAAI,GAAG,gBAAgB,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC;IAE9D,IAAI,CAAC,IAAI,EAAE;AACT,QAAA,OAAO,CAAC,KAAK,CACX,2DAAoD,aAAa,CAAA,CAAA,MAAA,CAAG,MAAM,GAAG,eAAA,CAAA,MAAA,CAAgB,MAAM,CAAE,GAAG,EAAE,CAAE,CAC7G;AACD,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,IAAM,QAAQ,GAAG,IAAI,CAAC,MAAM;AAC5B,IAAA,IAAM,WAAW,GAAG,YAAY,CAAC,SAAS,CAAC,UAAC,CAAC,EAAA,EAAK,OAAA,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAA,CAAjB,CAAiB,CAAC;AAEpE,IAAA,IAAI,WAAW,KAAK,EAAE,EAAE;AACtB,QAAA,OAAO,CAAC,KAAK,CACX,uCAAgC,QAAQ,EAAA,6BAAA,CAA6B,CACtE;AACD,QAAA,OAAO,IAAI;IACb;;IAGA,OAAO,CAAC,GAAG,WAAW;AACxB;AAEA;;;;AAIG;AACI,IAAM,wBAAwB,GAAG,UACtC,UAAkB,EAClB,QAAyB,EAAA;IAEzB,IAAI,UAAU,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC;AAE/B,IAAA,IAAM,YAAY,GAAG,sBAAsB,CAAC,QAAQ,CAAC;AACrD,IAAA,IAAM,OAAO,GAAa,CAAC,CAAC,CAAC;AAC7B,IAAA,IAAI,WAAW,GAAG,CAAC,CAAC;;AAGpB,IAAA,KAAK,IAAI,WAAW,GAAG,CAAC,EAAE,WAAW,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,WAAW,EAAE,EAAE;AAC9E,QAAA,IAAI,WAAW,KAAK,UAAU,EAAE;AAC9B,YAAA,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;YACzB;QACF;QACA,IAAI,WAAW,GAAG,UAAU;YAAE;AAE9B,QAAA,IAAM,SAAS,GAAG,WAAW,GAAG,CAAC;AACjC,QAAA,IAAM,WAAW,GAAG,YAAY,CAAC,SAAS,CAAC;AAC3C,QAAA,IAAI,CAAC,WAAW;YAAE;AAElB,QAAA,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;QAEzB,IAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC;QAC3D,IAAI,QAAQ,KAAK,IAAI;YAAE;QACvB,WAAW,GAAG,QAAQ;IACxB;;IAGA,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,UAAU,EAAE;AAC9C,QAAA,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC;IACxB;AAEA,IAAA,OAAO,OAAO;AAChB;AAiCA;;;;;AAKG;AACI,IAAM,gBAAgB,GAAG,UAAC,OAAoB,EAAA;AACnD,IAAA,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;AACvB,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,IAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE;AAC9B,IAAA,OAAO,WAAW,GAAG,OAAO,CAAC,UAAU;AACzC;AAEA;;;;;;AAMG;IACU,oBAAoB,GAAG,UAClC,SAAiB,EACjB,cAAsB,EACtB,OAAiB,EAAA;AAEjB,IAAA,IAAI,CAAC,SAAS,IAAI,CAAC,cAAc,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;AACrE,QAAA,OAAO,CAAC,IAAI,CAAC,wCAAwC,EAAE;AACrD,YAAA,SAAS,EAAA,SAAA;AACT,YAAA,cAAc,EAAA,cAAA;AACd,YAAA,OAAO,EAAA,OAAA;AACR,SAAA,CAAC;QACF;IACF;;IAGA,IAAI,UAAU,GAAG,EAAE;IAEnB,QAAQ,cAAc;AACpB,QAAA,KAAK,KAAK;AACR,YAAA,UAAU,GAAG,aAAA,CAAA,MAAA,CAAc,SAAS,CAAE;YACtC;AACF,QAAA,KAAK,cAAc;AACjB,YAAA,UAAU,GAAG,eAAA,CAAA,MAAA,CAAgB,SAAS,CAAE;YACxC;AACF,QAAA,KAAK,SAAS;AACZ,YAAA,UAAU,GAAG,YAAA,CAAA,MAAA,CAAa,SAAS,CAAE;YACrC;AACF,QAAA,KAAK,qBAAqB;AACxB,YAAA,UAAU,GAAG,4BAAA,CAAA,MAAA,CAA6B,SAAS,CAAE;YACrD;AACF,QAAA;AACE,YAAA,UAAU,GAAG,EAAA,CAAA,MAAA,CAAG,cAAc,EAAA,UAAA,CAAA,CAAA,MAAA,CAAW,SAAS,CAAE;;AAGxD,IAAA,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AAC3D;AA6EA,IAAM,uBAAuB,GAAG,UAAC,SAAiB,EAAA;AAChD,IAAA,IAAM,UAAU,GAAG;AACjB,QAAA,YAAA,CAAA,MAAA,CAAa,SAAS,CAAE;AACxB,QAAA,cAAA,CAAA,MAAA,CAAe,SAAS,CAAE;AAC1B,QAAA,cAAA,CAAA,MAAA,CAAe,SAAS,CAAE;KAC3B;AAED,IAAA,UAAU,CAAC,OAAO,CAAC,UAAC,GAAG,EAAA;AACrB,QAAA,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC;AAC5B,QAAA,cAAc,CAAC,UAAU,CAAC,GAAG,CAAC;AAChC,IAAA,CAAC,CAAC;AAEF,IAAA,KAAK,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;QACpD,IAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,EAAE;YACR;QACF;QACA,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAI,SAAS,CAAE,CAAC,EAAE;AACjC,YAAA,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC;QAC9B;IACF;AAEA,IAAA,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;QACtD,IAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG,EAAE;YACR;QACF;QACA,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAI,SAAS,CAAE,CAAC,EAAE;AACjC,YAAA,cAAc,CAAC,UAAU,CAAC,GAAG,CAAC;QAChC;IACF;IAEA,IAAI,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,SAAS,EAAE;AACnD,QAAA,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC;IACtC;IACA,IAAI,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,SAAS,EAAE;AACrD,QAAA,cAAc,CAAC,UAAU,CAAC,WAAW,CAAC;IACxC;AACF,CAAC;AAED;;;AAGG;AACI,IAAM,yBAAyB,GAAG,UAAC,SAAkB,EAAA;IAC1DG,qCAAkB,CAAC,SAAS,CAAC;IAE7B,IAAI,SAAS,EAAE;QACb,uBAAuB,CAAC,SAAS,CAAC;QAClC;IACF;AAEA,IAAA,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC;AACpC,IAAA,cAAc,CAAC,UAAU,CAAC,WAAW,CAAC;AAEtC,IAAA,KAAK,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;QACpD,IAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,EAAE;YACR;QACF;AACA,QAAA,IACE,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC;AAC5B,YAAA,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC;AAC9B,YAAA,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EACxB;AACA,YAAA,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC;QAC9B;IACF;AAEA,IAAA,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;QACtD,IAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG,EAAE;YACR;QACF;AACA,QAAA,IACE,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC;AAC5B,YAAA,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC;AAC9B,YAAA,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EACxB;AACA,YAAA,cAAc,CAAC,UAAU,CAAC,GAAG,CAAC;QAChC;IACF;AACF;AAEA;;;;;;;;;;;AAWG;AACI,IAAM,iBAAiB,GAAG,UAC/B,SAAkC,EAClC,QAAgB,EAAA;;IAEhB,IAAM,IAAI,GAAG,SAAS,KAAA,IAAA,IAAT,SAAS,KAAA,MAAA,GAAA,MAAA,GAAT,SAAS,CAAE,KAAK;AAC7B,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;AAAE,QAAA,OAAO,IAAI;AACrC,IAAA,OAAO,MAAC,IAAI,CAAC,QAAQ,CAA6B,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,IAAI;AAC5D;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"sessionService.js","sources":["../../../../src/services/sessionService.ts"],"sourcesContent":["/**\n * Session Service\n *\n * Service for interacting with the Datakeen Session API.\n * Handles fetching session data by ID.\n */\n\nimport type {\n ClientInfo,\n SessionData,\n SessionTemplate,\n SessionTemplateNode,\n} from \"../types/session\";\nimport { apiService } from \"./api\";\nimport { logStatusModified } from \"./auditTrailService\";\nimport { clearSessionMemory } from \"./sessionMemoryStore\";\n\n/**\n * Fetches session data by ID from the Datakeen backend\n *\n * @param sessionId - The unique identifier of the session\n * @returns The session data\n */\nexport const fetchSessionById = async (\n sessionId: string,\n): Promise<SessionData> => {\n try {\n const response = await apiService.get(`/session/sdk/${sessionId}`);\n return response.data;\n } catch (error) {\n console.error(\"Error fetching session data:\", error);\n throw error;\n }\n};\n\n/** Sends client information (IP, device, browser, OS) to the backend for a specific session\n *\n * @param sessionId - The unique identifier of the session\n * @param clientInfo - The client information to send\n */\nexport const sendClientInfo = async (\n sessionId: string,\n clientInfo: ClientInfo,\n): Promise<void> => {\n try {\n await apiService.post(`/session/sdk/${sessionId}/client-info`, clientInfo);\n } catch (error) {\n console.error(\"Error sending client info:\", error);\n throw error;\n }\n};\n\n/**\n * Determines if the session template has a specific type of node\n *\n * @param template - The session template\n * @param nodeType - The type of node to check for\n * @returns true if the template has a node of the specified type, false otherwise\n */\nexport const hasNodeType = (\n template: SessionTemplate,\n nodeType: string,\n): boolean => {\n return template.nodes.some((node) => node.type === nodeType);\n};\n\n/**\n * Determines if the session template has a node with a specific requiredDocumentType\n *\n * @param template - The session template\n * @param requiredDocumentType - The requiredDocumentType to check for\n * @returns true if the template has a node with the specified requiredDocumentType, false otherwise\n */\nexport const hasDocumentTypeNode = (\n template: SessionTemplate,\n requiredDocumentType: string,\n): boolean => {\n return template.nodes.some(\n (node) => node.requiredDocumentType === requiredDocumentType,\n );\n};\n\n/**\n * Gets all nodes of a specific type\n *\n * @param template - The session template\n * @param nodeType - The type of node to get\n * @returns Array of nodes matching the type\n */\nexport const getNodesByType = (\n template: SessionTemplate,\n nodeType: string,\n): SessionTemplateNode[] => {\n return template.nodes.filter((node) => node.type === nodeType);\n};\n\n/**\n * Gets all nodes with a specific requiredDocumentType\n *\n * @param template - The session template\n * @param requiredDocumentType - The requiredDocumentType to get\n * @returns Array of nodes matching the requiredDocumentType\n */\nexport const getNodesByDocumentType = (\n template: SessionTemplate,\n requiredDocumentType: string,\n): SessionTemplateNode[] => {\n return template.nodes.filter(\n (node) => node.requiredDocumentType === requiredDocumentType,\n );\n};\n\n/**\n * Get document options for a specific document type\n *\n * @param template - The session template\n * @param requiredDocumentType - The document type to get options for\n * @returns Array of document options (empty if none found)\n */\nexport const getDocumentOptions = (\n template: SessionTemplate,\n requiredDocumentType: string,\n): string[] => {\n const node = template.nodes.find(\n (node) => node.requiredDocumentType === requiredDocumentType,\n );\n return node?.selectedOptions || [];\n};\n\n/**\n * Determines if the session template has a selfie step\n *\n * @param template - The session template\n * @returns true if the template has a selfie step, false otherwise\n */\nexport const hasSelfieCaptureStep = (template: SessionTemplate): boolean => {\n return hasNodeType(template, \"selfie-capture\");\n};\n\n/**\n * Determines if the session template has an ID document step\n *\n * @param template - The session template\n * @returns true if the template has an ID document step, false otherwise\n */\nexport const hasDocumentStep = (template: SessionTemplate): boolean => {\n // Check if there's any document-selection node with requiredDocumentType \"id-card\"\n // or if none specified, just check for document-selection nodes\n const hasIDCard = hasDocumentTypeNode(template, \"id-card\");\n return hasIDCard || hasNodeType(template, \"document-selection\");\n};\n\n/**\n * Determines if the session template has a JDD (proof of address) step\n *\n * @param template - The session template\n * @returns true if the template has a JDD step, false otherwise\n */\nexport const hasJDDStep = (template: SessionTemplate): boolean => {\n return hasDocumentTypeNode(template, \"jdd\");\n};\n\n/**\n * Determines if the session template has a proof of funds step\n *\n * @param template - The session template\n * @returns true if the template has a proof of funds step, false otherwise\n */\nexport const hasProofOfFundsStep = (template: SessionTemplate): boolean => {\n return hasDocumentTypeNode(template, \"income-proof\");\n};\n\n/**\n * Determines if the session template has a document collection step\n *\n * @param template - The session template\n * @returns true if the template has a document collection step, false otherwise\n */\nexport const hasDocumentCollectionStep = (\n template: SessionTemplate,\n): boolean => {\n return hasNodeType(template, \"document-collection\");\n};\n\n/**\n * Gets all node types in the template\n *\n * @param template - The session template\n * @returns Array of node types in the template\n */\nexport const getNodeTypes = (template: SessionTemplate): string[] => {\n return Array.from(new Set(template.nodes.map((node) => node.type)));\n};\n\n/**\n * Gets all document types required in the template\n *\n * @param template - The session template\n * @returns Array of document types required in the template\n */\nexport const getRequiredDocumentTypes = (\n template: SessionTemplate,\n): string[] => {\n return Array.from(\n new Set(\n template.nodes\n .filter((node) => node.requiredDocumentType)\n .map((node) => node.requiredDocumentType!),\n ),\n );\n};\n\n/**\n * Converts template document type to internal document type\n * This helps standardize document types between the template and the application\n *\n * @param templateDocType - The document type as defined in the template\n * @returns The internal document type used by the application\n */\nexport const convertTemplateDocTypeToInternal = (\n templateDocType: string,\n): string => {\n if (!templateDocType) return \"\";\n\n // Mapping between template document types and internal document types\n const typeMap: Record<string, string> = {\n \"id-card\": \"id-card\",\n jdd: \"jdd\",\n \"income-proof\": \"income-proof\", // Using consistent naming\n };\n\n return typeMap[templateDocType] || templateDocType;\n};\n\n/**\n * Converts internal document type to template document type\n *\n * @param internalDocType - The document type used internally by the application\n * @returns The document type as expected in the template\n */\nexport const convertInternalDocTypeToTemplate = (\n internalDocType: string,\n): string => {\n if (!internalDocType) return \"\";\n\n // Mapping between internal document types and template document types\n const typeMap: Record<string, string> = {\n \"id-card\": \"id-card\",\n jdd: \"jdd\",\n funds: \"income-proof\", // Map funds to income-proof for backwards compatibility\n \"income-proof\": \"income-proof\",\n };\n\n return typeMap[internalDocType] || internalDocType;\n};\n\n/**\n * Updates session data with user input information\n *\n * @param sessionId - The unique identifier of the session\n * @param userInput - The user input data (firstName, lastName, birthDate)\n * @returns The updated session data\n */\nexport const updateSessionUserInput = async (\n sessionId: string,\n userInput: {\n firstName?: string;\n lastName?: string;\n birthDate?: string;\n [key: string]: unknown;\n },\n): Promise<SessionData> => {\n try {\n const response = await apiService.patch(`/session/sdk/${sessionId}`, {\n userInput,\n });\n return response.data;\n } catch (error) {\n console.error(\"Error updating session data:\", error);\n throw error;\n }\n};\n\n/**\n * Records the NFC fallback reason when the user declares they cannot use the\n * contactless scan, and marks the NFC scan as skipped server-side.\n *\n * @param sessionId - The unique identifier of the session\n * @param payload - The selected reason (technical key), its human-readable label,\n * and an optional free-text comment.\n */\nexport const skipNfcWithReason = async (\n sessionId: string,\n payload: { reason: string; label: string; comment?: string },\n): Promise<void> => {\n await apiService.post(`/session/sdk/${sessionId}/nfc-skip`, payload);\n};\n\nexport type SelfieFailureReason =\n | \"timeout\"\n | \"network_error\"\n | \"api_error\"\n | \"user_bypassed\";\n\nexport interface SelfieFailurePayload {\n nodeId: string;\n reason?: SelfieFailureReason;\n conformityCode?: string;\n bypassed?: boolean;\n}\n\nexport const reportSelfieFailure = async (\n sessionId: string,\n payload: SelfieFailurePayload,\n): Promise<void> => {\n await apiService.post(`/session/sdk/${sessionId}/selfie-failed`, payload);\n};\n\n/**\n * Resets a terminal NFC failure before the user starts again with another\n * document. The backend keeps completed scans immutable and treats this call\n * as a no-op when the status is not terminal.\n */\nexport const resetNfcScan = async (sessionId: string): Promise<void> => {\n await apiService.post(`/session/sdk/${sessionId}/nfc-reset`);\n};\n\n/**\n * Updates session data with contact information\n *\n * @param sessionId - The unique identifier of the session\n * @param contactInfo - The contact information data (email, phoneNumber)\n * @returns The updated session data\n */\nexport const updateSessionContactInfo = async (\n sessionId: string,\n contactInfo: {\n email: string;\n phoneNumber: string;\n [key: string]: unknown;\n },\n): Promise<SessionData> => {\n try {\n const response = await apiService.patch(`/session/sdk/${sessionId}`, {\n contactInfo,\n });\n return response.data;\n } catch (error) {\n console.error(\"Error updating contact information:\", error);\n throw error;\n }\n};\n\n/**\n * Updates session status\n *\n * @param sessionId - The unique identifier of the session\n * @param status - The new status for the session\n * @param reachedEndNodeId - Id of the end node actually reached (when status is \"ended\"),\n * so the backend can force the correct final status with multiple end nodes.\n * @returns The updated session data\n */\nexport const updateSessionStatus = async (\n sessionId: string,\n status: string,\n reachedEndNodeId?: string,\n): Promise<SessionData> => {\n try {\n const response = await apiService.patch(`/session/sdk/${sessionId}`, {\n status,\n ...(reachedEndNodeId ? { reachedEndNodeId } : {}),\n });\n\n // Log status modification in audit trail\n if (response.data && response.data.analysisId) {\n try {\n await logStatusModified(\n sessionId,\n status,\n response.data.clientInfoId || undefined,\n );\n } catch (err) {\n console.error(\"Failed to log status modification in audit trail:\", err);\n // Non-blocking error - continue session\n }\n }\n\n return response.data;\n } catch (error) {\n console.error(\"Error updating session status:\", error);\n throw error;\n }\n};\n\n/**\n * Updates the current step in the session\n *\n * @param sessionId - The unique identifier of the session\n * @param currentStep - The current step index in the workflow\n * @returns The updated session data\n */\nexport const updateSessionCurrentStep = async (\n sessionId: string,\n currentStep: number,\n): Promise<SessionData> => {\n try {\n const response = await apiService.patch(`/session/sdk/${sessionId}`, {\n currentStep,\n });\n return response.data;\n } catch (error) {\n console.error(\"Error updating session current step:\", error);\n throw error;\n }\n};\n\n/**\n * Gets the journey steps from the template in order\n *\n * @param template - The session template\n * @returns Array of ordered steps\n */\nexport const getOrderedJourneySteps = (\n template: SessionTemplate,\n): SessionTemplateNode[] => {\n // Filter out only start nodes, keep end nodes for proper journey completion, then sort by order.\n // Tiebreaker on id keeps the ordering deterministic when several nodes share the same `order`\n // (e.g. parallel branches of a condition), independently of their position in template.nodes.\n return template.nodes\n .filter((node) => node.type !== \"start\")\n .sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));\n};\n\nconst normalizeHandle = (value?: string): string => {\n return (value || \"\").trim().toLowerCase();\n};\n\n/**\n * Finds the outgoing edge to follow from a node.\n *\n * Resolution order:\n * 1. Exact handle match via sourceHandle/conditionValue.\n * 2. For condition:false loops, fallback to targetHandle=right.\n * 3. First outgoing edge as final fallback.\n */\nexport const findOutgoingEdge = (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n): SessionTemplate[\"edges\"][number] | null => {\n const outgoingEdges = (template.edges || []).filter(\n (edge) => edge.source === currentNodeId,\n );\n\n if (outgoingEdges.length === 0) {\n return null;\n }\n\n if (!handle) {\n return outgoingEdges[0];\n }\n\n const normalizedHandle = normalizeHandle(handle);\n const edgeByHandle = outgoingEdges.find((edge) => {\n return (\n normalizeHandle(edge.sourceHandle) === normalizedHandle ||\n normalizeHandle(edge.conditionValue) === normalizedHandle\n );\n });\n\n if (edgeByHandle) {\n return edgeByHandle;\n }\n\n const currentNode = template.nodes.find((node) => node.id === currentNodeId);\n if (currentNode?.type === \"condition\" && normalizedHandle === \"false\") {\n const rightHandleLoopEdge = outgoingEdges.find(\n (edge) => normalizeHandle(edge.targetHandle) === \"right\",\n );\n if (rightHandleLoopEdge) {\n return rightHandleLoopEdge;\n }\n }\n\n return outgoingEdges[0];\n};\n\n/**\n * Strict existence check for a named outgoing edge — unlike `findOutgoingEdge`,\n * this does NOT fall back to the first outgoing edge when no edge matches the\n * handle. Used by controle-jdi to decide whether a node is \"new-style\" (author\n * explicitly wired a \"false\" edge, enabling automatic true/false routing) or\n * \"legacy\" (single edge, preserve the existing manual continue/retry UX).\n */\nexport const hasOutgoingEdgeForHandle = (\n currentNodeId: string,\n template: SessionTemplate,\n handle: string,\n): boolean => {\n const normalizedHandle = normalizeHandle(handle);\n return (template.edges || []).some(\n (edge) =>\n edge.source === currentNodeId &&\n normalizeHandle(edge.sourceHandle) === normalizedHandle,\n );\n};\n\n/**\n * Gets the next step index by following the graph edge from the current node\n *\n * @param currentNodeId - The ID of the current node\n * @param template - The session template\n * @returns The next step index (1-based) or null if no edge found\n */\nexport const getNextStepIndex = (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n): number | null => {\n const orderedNodes = getOrderedJourneySteps(template);\n const edge = findOutgoingEdge(currentNodeId, template, handle);\n\n if (!edge) {\n console.debug(\n `[sessionService] No outgoing edge found for node ${currentNodeId}${handle ? ` with handle ${handle}` : \"\"}`,\n );\n return null;\n }\n\n const targetId = edge.target;\n const targetIndex = orderedNodes.findIndex((n) => n.id === targetId);\n\n if (targetIndex === -1) {\n console.debug(\n `[sessionService] Target node ${targetId} not found in ordered steps`,\n );\n return null;\n }\n\n // steps are 1-indexed in the SDK (0 is StartSession)\n return 1 + targetIndex;\n};\n\n/**\n * Reconstructs the navigation history by following the graph from step 0\n * up to (and including) targetStep. Returns [0, ...stepIndices].\n * If the graph path cannot reach targetStep, falls back to [0, targetStep].\n */\nexport const reconstructHistoryToStep = (\n targetStep: number,\n template: SessionTemplate,\n): number[] => {\n if (targetStep <= 0) return [0];\n\n const orderedNodes = getOrderedJourneySteps(template);\n const history: number[] = [0];\n let currentStep = 1; // first node is step 1\n\n // Follow the default (first) edge from each node in sequence\n for (let safetyLimit = 0; safetyLimit < orderedNodes.length + 1; safetyLimit++) {\n if (currentStep === targetStep) {\n history.push(currentStep);\n break;\n }\n if (currentStep > targetStep) break;\n\n const nodeIndex = currentStep - 1;\n const currentNode = orderedNodes[nodeIndex];\n if (!currentNode) break;\n\n history.push(currentStep);\n\n const nextStep = getNextStepIndex(currentNode.id, template);\n if (nextStep === null) break;\n currentStep = nextStep;\n }\n\n // Fallback: if we couldn't reach targetStep via graph, use simple seed\n if (history[history.length - 1] !== targetStep) {\n return [0, targetStep];\n }\n\n return history;\n};\n\n/**\n * Maps a template node type to a step component type\n *\n * @param node - The session template node\n * @returns The step component type\n */\nexport const getStepComponentType = (node: SessionTemplateNode): string => {\n // Map from template node types to component types\n const typeMap: Record<string, string> = {\n \"document-selection\": \"document\",\n \"document-collection\": \"document-collection\",\n \"selfie-capture\": \"selfie\",\n \"contact-info\": \"contact-info\",\n \"user-input\": \"user-input\",\n \"otp-verification\": \"otp\",\n };\n\n // First check the node type\n if (node.type in typeMap) {\n return typeMap[node.type];\n }\n\n // Then check the requiredDocumentType\n if (node.requiredDocumentType) {\n return node.requiredDocumentType;\n }\n\n // Default fallback\n return node.type;\n};\n\n/**\n * Checks if a session has expired\n *\n * @param session - The session data to check\n * @returns true if the session has expired, false otherwise\n */\nexport const isSessionExpired = (session: SessionData): boolean => {\n if (!session.expireTime) {\n return false;\n }\n\n const currentTime = Date.now();\n return currentTime > session.expireTime;\n};\n\n/**\n * Stores document options in localStorage for a specific document type\n *\n * @param sessionId - The session ID\n * @param documentTypeId - The document type ID (e.g., 'jdd', 'income-proof')\n * @param options - The options to store\n */\nexport const storeDocumentOptions = (\n sessionId: string,\n documentTypeId: string,\n options: string[],\n): void => {\n if (!sessionId || !documentTypeId || !options || options.length === 0) {\n console.warn(\"Missing data for storeDocumentOptions:\", {\n sessionId,\n documentTypeId,\n options,\n });\n return;\n }\n\n // Create a consistent key format based on document type\n let storageKey = \"\";\n\n switch (documentTypeId) {\n case \"jdd\":\n storageKey = `jddOptions_${sessionId}`;\n break;\n case \"income-proof\":\n storageKey = `fundsOptions_${sessionId}`;\n break;\n case \"id-card\":\n storageKey = `idOptions_${sessionId}`;\n break;\n case \"document-collection\":\n storageKey = `documentCollectionOptions_${sessionId}`;\n break;\n default:\n storageKey = `${documentTypeId}Options_${sessionId}`;\n }\n\n localStorage.setItem(storageKey, JSON.stringify(options));\n};\n\n/**\n * Retrieves document options from localStorage for a specific document type\n *\n * @param sessionId - The session ID\n * @param documentTypeId - The document type ID (e.g., 'jdd', 'income-proof')\n * @returns Array of options or default options if none found\n */\nexport const retrieveDocumentOptions = (\n sessionId: string,\n documentTypeId: string,\n): string[] => {\n if (!sessionId || !documentTypeId) {\n console.warn(\"Missing data for retrieveDocumentOptions:\", {\n sessionId,\n documentTypeId,\n });\n return [];\n }\n\n // Create consistent key formats to check\n const possibleKeys = [\n `${documentTypeId}Options_${sessionId}`,\n documentTypeId === \"jdd\" ? `jddOptions_${sessionId}` : \"\",\n documentTypeId === \"income-proof\" ? `fundsOptions_${sessionId}` : \"\",\n documentTypeId === \"id-card\" ? `idOptions_${sessionId}` : \"\",\n documentTypeId === \"document-collection\"\n ? `documentCollectionOptions_${sessionId}`\n : \"\",\n ].filter(Boolean);\n\n // Try each possible key\n for (const key of possibleKeys) {\n const savedOptions = localStorage.getItem(key);\n if (savedOptions) {\n try {\n const parsedOptions = JSON.parse(savedOptions);\n\n return parsedOptions;\n } catch (e) {\n console.error(\n `Error parsing options for ${documentTypeId} with key ${key}:`,\n e,\n );\n }\n }\n }\n\n // Return default options if none found\n console.warn(`No options found for ${documentTypeId}, using defaults`);\n if (documentTypeId === \"jdd\") {\n return [\n \"Facture d'électricité (< 3 mois)\",\n \"Facture de gaz (< 3 mois)\",\n \"Facture d'eau (< 3 mois)\",\n \"Quittance de loyer (< 3 mois)\",\n \"Facture téléphone/internet (< 3 mois)\",\n \"Attestation d'assurance habitation (< 3 mois)\",\n ];\n } else if (documentTypeId === \"income-proof\") {\n return [\n \"Bulletin de salaire\",\n \"Avis d'imposition\",\n \"Relevé de compte bancaire\",\n \"Attestation de revenus\",\n \"Contrat de travail\",\n ];\n } else if (documentTypeId === \"id-card\") {\n return [\"Carte nationale d'identité\", \"Passeport\", \"Permis de conduire\"];\n } else if (documentTypeId === \"document-collection\") {\n return [\"Document administratif\", \"Justificatif\", \"Attestation\"];\n }\n\n return [];\n};\n\nconst clearStorageBySessionId = (sessionId: string): void => {\n const scopedKeys = [\n `userInput_${sessionId}`,\n `contactInfo_${sessionId}`,\n `sessionData_${sessionId}`,\n ];\n\n scopedKeys.forEach((key) => {\n localStorage.removeItem(key);\n sessionStorage.removeItem(key);\n });\n\n for (let i = localStorage.length - 1; i >= 0; i -= 1) {\n const key = localStorage.key(i);\n if (!key) {\n continue;\n }\n if (key.endsWith(`_${sessionId}`)) {\n localStorage.removeItem(key);\n }\n }\n\n for (let i = sessionStorage.length - 1; i >= 0; i -= 1) {\n const key = sessionStorage.key(i);\n if (!key) {\n continue;\n }\n if (key.endsWith(`_${sessionId}`)) {\n sessionStorage.removeItem(key);\n }\n }\n\n if (localStorage.getItem(\"sessionId\") === sessionId) {\n localStorage.removeItem(\"sessionId\");\n }\n if (sessionStorage.getItem(\"sessionId\") === sessionId) {\n sessionStorage.removeItem(\"sessionId\");\n }\n};\n\n/**\n * Clears all client-side session traces (memory + browser storage)\n * for a given session. This is intentionally aggressive for security.\n */\nexport const clearSessionSensitiveData = (sessionId?: string): void => {\n clearSessionMemory(sessionId);\n\n if (sessionId) {\n clearStorageBySessionId(sessionId);\n return;\n }\n\n localStorage.removeItem(\"sessionId\");\n sessionStorage.removeItem(\"sessionId\");\n\n for (let i = localStorage.length - 1; i >= 0; i -= 1) {\n const key = localStorage.key(i);\n if (!key) {\n continue;\n }\n if (\n key.startsWith(\"userInput_\") ||\n key.startsWith(\"contactInfo_\") ||\n key.includes(\"Options_\")\n ) {\n localStorage.removeItem(key);\n }\n }\n\n for (let i = sessionStorage.length - 1; i >= 0; i -= 1) {\n const key = sessionStorage.key(i);\n if (!key) {\n continue;\n }\n if (\n key.startsWith(\"userInput_\") ||\n key.startsWith(\"contactInfo_\") ||\n key.includes(\"Options_\")\n ) {\n sessionStorage.removeItem(key);\n }\n }\n};\n\n/**\n * Returns the pre-fill data for a given run index from a `userInput` object\n * that contains a `_list` array.\n *\n * Convention: when the integrator wants to pre-fill different data per run\n * (e.g. multiple persons in a loop), they pass `userInput: { _list: [...] }`\n * at session creation. Each element in `_list` corresponds to a run (0-indexed).\n *\n * @param userInput - The session's userInput object\n * @param runIndex - The current run index (0 = first pass, 1 = second pass, …)\n * @returns The pre-fill data for that run, or null if not defined\n */\nexport const getRunPrefillData = (\n userInput: Record<string, unknown>,\n runIndex: number,\n): Record<string, unknown> | null => {\n const list = userInput?._list;\n if (!Array.isArray(list)) return null;\n return (list[runIndex] as Record<string, unknown>) ?? null;\n};\n"],"names":["__awaiter","apiService","__assign","logStatusModified","clearSessionMemory"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sources":["../../../../src/types/session.ts"],"sourcesContent":["import type React from \"react\";\n\nexport interface SessionConfig {\n selfie?: boolean;\n requireMobile?: boolean;\n}\n\nexport interface DatakeenSessionProps {\n sessionId: string;\n sessionConfig?: SessionConfig;\n apiBaseUrl?: string; // Optional API base URL for dynamic environment configuration\n}\n\nexport interface UseSessionReturn {\n SessionComponent: React.ReactElement;\n}\n\nexport type stepObject = {\n setStep: (step: number, skipHistory?: boolean) => void;\n goBack: () => void;\n /** Retour arrière vers un nœud précis (ex: \"Corriger ma saisie\") :\n * tronque l'historique jusqu'à `targetStep` au lieu de l'empiler. */\n goBackToStep: (targetStep: number) => void;\n goToNextStep: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n /** Avance via le graphe et tronque l'historique au nœud d'arrivée. */\n goToNextStepCommitted: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n step: number;\n canGoBack: boolean;\n};\n\nexport interface ProcessingStep {\n title: string;\n subtitle: string;\n hasError?: boolean;\n}\n\nexport type ConditionTokenType = \"variable\" | \"control\" | \"operator\" | \"input\";\n\nexport interface ConditionToken {\n type: ConditionTokenType;\n value: string;\n label?: string;\n sourceNodeId?: string;\n}\n\n/**\n * Type for custom field value types\n */\nexport type CustomFieldValueType =\n | \"text\"\n | \"enum\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"email\"\n | \"address\"\n | \"list\";\n\n/**\n * Display formats supported for date fields (top-level and list columns).\n */\nexport type DateDisplayFormat = \"dd/mm/yyyy\" | \"mm/dd/yyyy\" | \"yyyy-mm-dd\";\n\nexport const DEFAULT_DATE_DISPLAY_FORMAT: DateDisplayFormat = \"dd/mm/yyyy\";\n\n/**\n * Column definition for a list-type custom field\n */\nexport interface ListColumn {\n label: string;\n type: \"text\" | \"enum\" | \"date\" | \"email\";\n options?: string[]; // required when type === 'enum'\n placeholder?: string; // text/email/date — shown to the end user\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n}\n\n/**\n * Interface for custom field definition\n */\nexport interface CustomField {\n id: string;\n label: string;\n placeholder?: string;\n description?: string;\n valueType: CustomFieldValueType;\n enumOptions?: string[];\n listColumns?: ListColumn[]; // for list type: column definitions\n minRows?: number; // for list type: minimum rows expected\n required?: boolean;\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n lockedFromApi?: boolean;\n editableIfMissing?: boolean; // soft lock — éditable si la valeur API est absente\n userInputKey?: string;\n}\n\n/**\n * Interface for session template node\n */\nexport interface SessionTemplateNode {\n id: string;\n type: string;\n title: string;\n description: string;\n informationType?:\n | \"identity\"\n | \"identity-legal\"\n | \"contact\"\n | \"address\"\n | \"nationality\"\n | \"custom\";\n position: {\n x: number;\n y: number;\n };\n options: unknown[];\n selectedOptions: string[];\n requiredDocumentType?: string;\n isRequired: boolean;\n order: number;\n optionalFields?: string[];\n requiredFields?: string[];\n pageTitle?: string;\n pageDescription?: string;\n // Properties for document-collection node type\n allowedDocumentTypes?: Array<{\n id: string;\n name: string;\n /**\n * Optional side information coming from the template.\n * When provided and equals to two (\"two\", 2, \"double\", \"recto-verso\"),\n * consumers should allow uploading two sides (front/back).\n */\n side?: string | number;\n }>;\n allowedAddingMethods?: string[];\n introductionPage?: {\n title?: string;\n description?: string;\n };\n documentSelection?: {\n title?: string;\n description?: string;\n };\n // Start node specific properties\n welcomeTitle?: string;\n welcomeSubtitle?: string;\n welcomeDescription?: string;\n welcomeImage?: string;\n qrCodeTitle?: string;\n qrCodeDescription?: string;\n showLegacyCGU?: boolean; // default: true — rétrocompatibilité\n\n // Legal consent node specific properties\n consentDescription?: string;\n consentDescription2?: string;\n cguUrl?: string;\n privacyPolicyUrl?: string;\n cguLinkLabel?: string;\n privacyLinkLabel?: string;\n checkboxText?: string;\n // Identity control specific properties\n automaticPhotoCapture?: boolean;\n nfcEnabled?: boolean;\n // \"nfcAndApi\" reste accepté pour rétrocompat (parcours legacy) ; à normaliser à la lecture.\n nfcMode?: \"nfcOnly\" | \"nfcOrPhoto\" | \"nfcAndApi\";\n acceptedCountries?: AcceptedCountry[];\n // End node specific properties\n callbackURL?: string | null;\n // Résultat forcé par le nœud `end` (configuré dans le builder). Sert au SDK à\n // afficher la variante « erreur conservée » de l'écran de fin quand la branche\n // fausse d'une condition pointe directement vers un end non_compliant.\n expectedResult?: string;\n // Condition node specific properties\n conditionExpression?: string;\n conditionTokens?: ConditionToken[];\n conditionFalseErrorMessage?: string;\n conditionMaxRetries?: number;\n conditionMaxRetryAction?: \"end-journey\" | \"force-true\";\n // Undefined is treated as \"loop\" by the SDK for legacy templates.\n conditionFalseMode?: \"retry\" | \"loop\";\n\n // External verification specific properties\n targetApi?: \"INSEE\" | \"INPI_RBE\";\n /** INPI_RBE only. Opt-in: retry against the RNA (associations) when the RNE finds nothing. */\n rnaFallbackEnabled?: boolean;\n referenceNodeId?: string;\n referenceNodeType?:\n | \"information-input\"\n | \"document-collection\"\n | \"identity-control\";\n referenceField?: \"siren\" | \"siret\";\n referenceVariable?: string;\n // Custom form fields (for information-input with type 'custom')\n customFields?: CustomField[];\n\n // Electronic signature specific properties\n templateId?: string;\n external_id?: string;\n /** Écran affiché après la signature. Valeurs vides : textes standard traduits. */\n signedScreenTitle?: string;\n signedScreenDescription?: string;\n signedScreenDownloadHint?: string;\n fieldMappings?: Array<{\n sourceFieldId: string;\n label: string;\n docusealType: string;\n readonly: boolean;\n role?: string;\n sourceNodeId?: string;\n }>;\n /** If set, the generated PDF from this upstream pdf-generation node will be used as the document to sign */\n sourcePdfNodeId?: string;\n\n // PDF generation node specific properties\n // Note: htmlTemplate is intentionally NOT included — it is server-side only and never sent to the client\n pdfMode?: \"upload\" | \"html-template\";\n sourceNodeIds?: string[];\n\n // retry properties\n allowResubmission: boolean;\n maxResubmissionAttempts?: number;\n\n /**\n * Paramétrable par nœud depuis le journey builder : autorise ou non le\n * bouton \"Poursuivre quand même\" en cas d'échec. S'applique aux nœuds\n * identity-control, document-collection, biometric-capture (selfie/video)\n * et external-verification. Absent/true = comportement actuel inchangé\n * (bouton proposé), false = masqué.\n */\n allowContinueOnFailure?: boolean;\n}\n\n/**\n * Interface for accepted countries\n */\nexport interface AcceptedCountry {\n code: string;\n documents: {\n passport: string[];\n idCard: string[];\n driverLicense: string[];\n residencePermit: string[];\n pinkDriverLicense: string[];\n };\n}\n\n/**\n * Interface for session template edge\n */\nexport interface SessionTemplateEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n conditionValue?: string;\n}\n\n/**\n * Interface for platform information\n */\nexport interface PlatformInfo {\n mobile: boolean;\n desktop: boolean;\n backoffice: boolean;\n}\n\n/**\n * Interface for session template\n */\n/** Clé du catalogue d'icônes des écrans de fin (mappée vers lucide-react au rendu). */\nexport type EndScreenIcon =\n | \"thanks\"\n | \"send\"\n | \"mail\"\n | \"check\"\n | \"clock\"\n | \"shield\"\n | \"user\"\n | \"info\";\n\nexport interface EndScreenItem {\n icon: EndScreenIcon;\n text: string;\n}\n\nexport interface EndScreenCase {\n title?: string;\n items: EndScreenItem[];\n}\n\n/** Textes de fin personnalisés (config globale du journey). Vide → fallback standard. */\nexport interface EndScreenConfig {\n compliant?: EndScreenCase;\n nonCompliant?: EndScreenCase;\n}\n\nexport interface SessionTemplate {\n id: string;\n name: string;\n description: string;\n version: string;\n languages: string[];\n nodes: SessionTemplateNode[];\n edges: SessionTemplateEdge[];\n groupId: string;\n userId: string | null;\n created_at: string;\n updated_at: string;\n platforms?: PlatformInfo;\n logo?: string;\n showQRCode?: boolean;\n buttonBgColor?: string;\n buttonTextColor?: string;\n endScreenConfig?: EndScreenConfig;\n}\n\n/**\n * Interface for session data\n */\nexport interface SessionData {\n id: string;\n userId: string | null;\n token: string;\n templateId: string;\n templateKey: string;\n expireTime: number;\n status: string;\n result: Record<string, unknown>;\n landingPage: unknown;\n withSelfie: boolean | null;\n groupId: string | null;\n userInput: Record<string, unknown>;\n contactInfo?: {\n email: string;\n phoneNumber: string;\n };\n callbackURL?: string | null;\n webhookURL: string;\n analysisTemplateId: string | null;\n userAgent: unknown[];\n mobile: boolean;\n analysisId: string | null;\n currentStep?: number;\n nfcStatus?: \"pending\" | \"opened\" | \"completed\" | \"skipped\" | \"failed\";\n createdAt: string;\n updatedAt: string;\n auditTrail: unknown[];\n user: unknown | null;\n analysis: unknown[];\n documents: unknown[];\n template: SessionTemplate;\n retryCounts?: Record<string, number>; // nodeId -> retry count\n}\n\nexport interface ClientInfo {\n ip?: string;\n location?: string;\n device: string;\n browser: string;\n os: string;\n}\n"],"names":[],"mappings":";;AAuEO,IAAM,2BAA2B,GAAsB;;;;"}
1
+ {"version":3,"file":"session.js","sources":["../../../../src/types/session.ts"],"sourcesContent":["import type React from \"react\";\n\nexport interface SessionConfig {\n selfie?: boolean;\n requireMobile?: boolean;\n}\n\nexport interface DatakeenSessionProps {\n sessionId: string;\n sessionConfig?: SessionConfig;\n apiBaseUrl?: string; // Optional API base URL for dynamic environment configuration\n}\n\nexport interface UseSessionReturn {\n SessionComponent: React.ReactElement;\n}\n\nexport type stepObject = {\n setStep: (step: number, skipHistory?: boolean) => void;\n goBack: () => void;\n /** Retour arrière vers un nœud précis (ex: \"Corriger ma saisie\") :\n * tronque l'historique jusqu'à `targetStep` au lieu de l'empiler. */\n goBackToStep: (targetStep: number) => void;\n goToNextStep: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n /** Avance via le graphe et tronque l'historique au nœud d'arrivée. */\n goToNextStepCommitted: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n step: number;\n canGoBack: boolean;\n};\n\nexport interface ProcessingStep {\n title: string;\n subtitle: string;\n hasError?: boolean;\n}\n\nexport type ConditionTokenType = \"variable\" | \"control\" | \"operator\" | \"input\";\n\nexport interface ConditionToken {\n type: ConditionTokenType;\n value: string;\n label?: string;\n sourceNodeId?: string;\n}\n\n/**\n * Type for custom field value types\n */\nexport type CustomFieldValueType =\n | \"text\"\n | \"enum\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"email\"\n | \"address\"\n | \"list\";\n\n/**\n * Display formats supported for date fields (top-level and list columns).\n */\nexport type DateDisplayFormat = \"dd/mm/yyyy\" | \"mm/dd/yyyy\" | \"yyyy-mm-dd\";\n\nexport const DEFAULT_DATE_DISPLAY_FORMAT: DateDisplayFormat = \"dd/mm/yyyy\";\n\n/**\n * Column definition for a list-type custom field\n */\nexport interface ListColumn {\n label: string;\n type: \"text\" | \"enum\" | \"date\" | \"email\";\n options?: string[]; // required when type === 'enum'\n placeholder?: string; // text/email/date — shown to the end user\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n}\n\n/**\n * Interface for custom field definition\n */\nexport interface CustomField {\n id: string;\n label: string;\n placeholder?: string;\n description?: string;\n valueType: CustomFieldValueType;\n enumOptions?: string[];\n listColumns?: ListColumn[]; // for list type: column definitions\n minRows?: number; // for list type: minimum rows expected\n required?: boolean;\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n lockedFromApi?: boolean;\n editableIfMissing?: boolean; // soft lock — éditable si la valeur API est absente\n userInputKey?: string;\n}\n\n/**\n * Interface for session template node\n */\nexport interface SessionTemplateNode {\n id: string;\n type: string;\n title: string;\n description: string;\n informationType?:\n | \"identity\"\n | \"identity-legal\"\n | \"contact\"\n | \"address\"\n | \"nationality\"\n | \"custom\";\n position: {\n x: number;\n y: number;\n };\n options: unknown[];\n selectedOptions: string[];\n requiredDocumentType?: string;\n isRequired: boolean;\n order: number;\n optionalFields?: string[];\n requiredFields?: string[];\n pageTitle?: string;\n pageDescription?: string;\n // Properties for document-collection node type\n allowedDocumentTypes?: Array<{\n id: string;\n name: string;\n /**\n * Optional side information coming from the template.\n * When provided and equals to two (\"two\", 2, \"double\", \"recto-verso\"),\n * consumers should allow uploading two sides (front/back).\n */\n side?: string | number;\n }>;\n allowedAddingMethods?: string[];\n introductionPage?: {\n title?: string;\n description?: string;\n };\n documentSelection?: {\n title?: string;\n description?: string;\n };\n // Start node specific properties\n welcomeTitle?: string;\n welcomeSubtitle?: string;\n welcomeDescription?: string;\n welcomeImage?: string;\n qrCodeTitle?: string;\n qrCodeDescription?: string;\n showLegacyCGU?: boolean; // default: true — rétrocompatibilité\n\n // Legal consent node specific properties\n consentDescription?: string;\n consentDescription2?: string;\n cguUrl?: string;\n privacyPolicyUrl?: string;\n cguLinkLabel?: string;\n privacyLinkLabel?: string;\n checkboxText?: string;\n // Identity control specific properties\n automaticPhotoCapture?: boolean;\n nfcEnabled?: boolean;\n // \"nfcAndApi\" reste accepté pour rétrocompat (parcours legacy) ; à normaliser à la lecture.\n nfcMode?: \"nfcOnly\" | \"nfcOrPhoto\" | \"nfcAndApi\";\n acceptedCountries?: AcceptedCountry[];\n // End node specific properties\n callbackURL?: string | null;\n // Résultat forcé par le nœud `end` (configuré dans le builder). Sert au SDK à\n // afficher la variante « erreur conservée » de l'écran de fin quand la branche\n // fausse d'une condition pointe directement vers un end non_compliant.\n expectedResult?: string;\n // Condition node specific properties\n conditionExpression?: string;\n conditionTokens?: ConditionToken[];\n conditionFalseErrorMessage?: string;\n conditionMaxRetries?: number;\n conditionMaxRetryAction?: \"end-journey\" | \"force-true\";\n // Undefined is treated as \"loop\" by the SDK for legacy templates.\n conditionFalseMode?: \"retry\" | \"loop\";\n\n // External verification specific properties\n targetApi?: \"INSEE\" | \"INPI_RBE\";\n /** INPI_RBE only. Opt-in: retry against the RNA (associations) when the RNE finds nothing. */\n rnaFallbackEnabled?: boolean;\n referenceNodeId?: string;\n referenceNodeType?:\n | \"information-input\"\n | \"document-collection\"\n | \"identity-control\";\n referenceField?: \"siren\" | \"siret\";\n referenceVariable?: string;\n // Custom form fields (for information-input with type 'custom')\n customFields?: CustomField[];\n\n // Electronic signature specific properties\n templateId?: string;\n external_id?: string;\n /** Écran affiché après la signature. Valeurs vides : textes standard traduits. */\n signedScreenTitle?: string;\n signedScreenDescription?: string;\n signedScreenDownloadHint?: string;\n fieldMappings?: Array<{\n sourceFieldId: string;\n label: string;\n docusealType: string;\n readonly: boolean;\n role?: string;\n sourceNodeId?: string;\n }>;\n /** If set, the generated PDF from this upstream pdf-generation node will be used as the document to sign */\n sourcePdfNodeId?: string;\n\n // PDF generation node specific properties\n // Note: htmlTemplate is intentionally NOT included — it is server-side only and never sent to the client\n pdfMode?: \"upload\" | \"html-template\";\n sourceNodeIds?: string[];\n\n // retry properties\n allowResubmission: boolean;\n maxResubmissionAttempts?: number;\n\n /**\n * Paramétrable par nœud depuis le journey builder : autorise ou non le\n * bouton \"Poursuivre quand même\" en cas d'échec. S'applique aux nœuds\n * identity-control, document-collection, biometric-capture (selfie/video)\n * et external-verification. Absent/true = comportement actuel inchangé\n * (bouton proposé), false = masqué.\n *\n * Déprécié pour controle-jdi/identity-control quand une sortie \"false\" est\n * câblée : dans ce cas le routage automatique (blockingCodes +\n * maxResubmissionAction) prend le relais et ce bouton disparaît. Reste lu\n * tel quel pour les nœuds legacy sans sortie \"false\" (rétrocompat).\n */\n allowContinueOnFailure?: boolean;\n\n /**\n * Codes JDI exacts considérés comme bloquants pour ce nœud controle-jdi\n * (déclenchent la boucle de resoumission). Absent = DEFAULT_BLOCKING_CODES\n * (utils/jdiCodes.ts) — comportement legacy inchangé. Le code 8.0 est\n * toujours bloquant indépendamment de cette liste.\n */\n blockingCodes?: string[];\n\n /**\n * Action suivie quand les resoumissions sont épuisées sur un code bloquant\n * ET qu'une sortie \"false\" est câblée sur ce nœud controle-jdi (miroir de\n * conditionMaxRetryAction sur le nœud condition). Défaut \"end-journey\".\n */\n maxResubmissionAction?: \"end-journey\" | \"force-true\";\n}\n\n/**\n * Interface for accepted countries\n */\nexport interface AcceptedCountry {\n code: string;\n documents: {\n passport: string[];\n idCard: string[];\n driverLicense: string[];\n residencePermit: string[];\n pinkDriverLicense: string[];\n };\n}\n\n/**\n * Interface for session template edge\n */\nexport interface SessionTemplateEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n conditionValue?: string;\n}\n\n/**\n * Interface for platform information\n */\nexport interface PlatformInfo {\n mobile: boolean;\n desktop: boolean;\n backoffice: boolean;\n}\n\n/**\n * Interface for session template\n */\n/** Clé du catalogue d'icônes des écrans de fin (mappée vers lucide-react au rendu). */\nexport type EndScreenIcon =\n | \"thanks\"\n | \"send\"\n | \"mail\"\n | \"check\"\n | \"clock\"\n | \"shield\"\n | \"user\"\n | \"info\";\n\nexport interface EndScreenItem {\n icon: EndScreenIcon;\n text: string;\n}\n\nexport interface EndScreenCase {\n title?: string;\n items: EndScreenItem[];\n}\n\n/** Textes de fin personnalisés (config globale du journey). Vide → fallback standard. */\nexport interface EndScreenConfig {\n compliant?: EndScreenCase;\n nonCompliant?: EndScreenCase;\n}\n\nexport interface SessionTemplate {\n id: string;\n name: string;\n description: string;\n version: string;\n languages: string[];\n nodes: SessionTemplateNode[];\n edges: SessionTemplateEdge[];\n groupId: string;\n userId: string | null;\n created_at: string;\n updated_at: string;\n platforms?: PlatformInfo;\n logo?: string;\n showQRCode?: boolean;\n buttonBgColor?: string;\n buttonTextColor?: string;\n endScreenConfig?: EndScreenConfig;\n}\n\n/**\n * Interface for session data\n */\nexport interface SessionData {\n id: string;\n userId: string | null;\n token: string;\n templateId: string;\n templateKey: string;\n expireTime: number;\n status: string;\n result: Record<string, unknown>;\n landingPage: unknown;\n withSelfie: boolean | null;\n groupId: string | null;\n userInput: Record<string, unknown>;\n contactInfo?: {\n email: string;\n phoneNumber: string;\n };\n callbackURL?: string | null;\n webhookURL: string;\n analysisTemplateId: string | null;\n userAgent: unknown[];\n mobile: boolean;\n analysisId: string | null;\n currentStep?: number;\n nfcStatus?: \"pending\" | \"opened\" | \"completed\" | \"skipped\" | \"failed\";\n createdAt: string;\n updatedAt: string;\n auditTrail: unknown[];\n user: unknown | null;\n analysis: unknown[];\n documents: unknown[];\n template: SessionTemplate;\n retryCounts?: Record<string, number>; // nodeId -> retry count\n}\n\nexport interface ClientInfo {\n ip?: string;\n location?: string;\n device: string;\n browser: string;\n os: string;\n}\n"],"names":[],"mappings":";;AAuEO,IAAM,2BAA2B,GAAsB;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"apiAnalysis.js","sources":["../../../../src/utils/apiAnalysis.ts"],"sourcesContent":["export interface Prediction {\n code: string;\n codeDescription: string;\n codeName: string;\n type: string;\n userInput?: {\n birthDate?: string;\n firstName?: string;\n lastName?: string;\n };\n}\n\nexport interface AnalysisResult {\n predictions: Prediction[];\n internal_status: string;\n analysis_id: string;\n}\n\n/**\n * Extrait les root causes principales à partir des prédictions de l'API\n * Retourne les codes d'erreur (ex: \"2.2\", \"4.0\") au lieu des codeNames\n */\nexport const extractRootCauses = (predictions: Prediction[]): string[] => {\n if (!predictions || !Array.isArray(predictions)) {\n return [];\n }\n\n return predictions\n .filter(prediction => prediction.code && prediction.code !== '1.0')\n .map(prediction => prediction.code);\n};\n\n/**\n * Détermine si l'analyse a échoué basé sur les prédictions\n */\nexport const hasAnalysisFailed = (predictions: Prediction[]): boolean => {\n if (!predictions || !Array.isArray(predictions)) {\n return true;\n }\n\n // Si au moins une prédiction n'est pas '1.0' (conform), l'analyse a échoué\n return predictions.some(prediction =>\n prediction.code && prediction.code !== '1.0'\n );\n};\n\n/**\n * Obtient la root cause principale (première dans la liste)\n */\nexport const getPrimaryRootCause = (predictions: Prediction[]): string | null => {\n const rootCauses = extractRootCauses(predictions);\n return rootCauses.length > 0 ? rootCauses[0] : null;\n};\n\nexport function analyzeApiResponse(response: { status: number; data: any }) {\n // Dummy implementation for test\n return response.status === 200 ? 'success' : 'error';\n}\n"],"names":[],"mappings":";;AAkBA;;;AAGG;AACI,IAAM,iBAAiB,GAAG,UAAC,WAAyB,EAAA;IACzD,IAAI,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;AAC/C,QAAA,OAAO,EAAE;IACX;AAEA,IAAA,OAAO;AACJ,SAAA,MAAM,CAAC,UAAA,UAAU,EAAA,EAAI,OAAA,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,CAAA,CAA5C,CAA4C;SACjE,GAAG,CAAC,UAAA,UAAU,EAAA,EAAI,OAAA,UAAU,CAAC,IAAI,CAAA,CAAf,CAAe,CAAC;AACvC;AAEA;;AAEG;AACI,IAAM,iBAAiB,GAAG,UAAC,WAAyB,EAAA;IACzD,IAAI,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;AAC/C,QAAA,OAAO,IAAI;IACb;;AAGA,IAAA,OAAO,WAAW,CAAC,IAAI,CAAC,UAAA,UAAU,EAAA;QAChC,OAAA,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK;AAA5C,IAAA,CAA4C,CAC7C;AACH;AAEA;;AAEG;AACI,IAAM,mBAAmB,GAAG,UAAC,WAAyB,EAAA;AAC3D,IAAA,IAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC;AACjD,IAAA,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI;AACrD;;;;;;"}
1
+ {"version":3,"file":"apiAnalysis.js","sources":["../../../../src/utils/apiAnalysis.ts"],"sourcesContent":["/**\n * Détail d'un champ d'identité en échec pour le code 7.0 (owner mismatch) :\n * valeur saisie par l'utilisateur vs valeur lue sur le document, telles que\n * calculées côté backend (voir GET /session/sdk/:id/analysis-status).\n */\nexport interface JdiMismatchDetail {\n field: 'firstName' | 'lastName' | 'birthDate';\n entered: string;\n read: string;\n}\n\nexport interface Prediction {\n code: string;\n codeDescription: string;\n codeName: string;\n type: string;\n userInput?: {\n birthDate?: string;\n firstName?: string;\n lastName?: string;\n };\n /** Présent uniquement pour le code 7.0, quand un mismatch a été détecté. */\n mismatchDetails?: JdiMismatchDetail[];\n}\n\nexport interface AnalysisResult {\n predictions: Prediction[];\n internal_status: string;\n analysis_id: string;\n}\n\n/**\n * Extrait les root causes principales à partir des prédictions de l'API\n * Retourne les codes d'erreur (ex: \"2.2\", \"4.0\") au lieu des codeNames\n */\nexport const extractRootCauses = (predictions: Prediction[]): string[] => {\n if (!predictions || !Array.isArray(predictions)) {\n return [];\n }\n\n return predictions\n .filter(prediction => prediction.code && prediction.code !== '1.0')\n .map(prediction => prediction.code);\n};\n\n/**\n * Détermine si l'analyse a échoué basé sur les prédictions\n */\nexport const hasAnalysisFailed = (predictions: Prediction[]): boolean => {\n if (!predictions || !Array.isArray(predictions)) {\n return true;\n }\n\n // Si au moins une prédiction n'est pas '1.0' (conform), l'analyse a échoué\n return predictions.some(prediction =>\n prediction.code && prediction.code !== '1.0'\n );\n};\n\n/**\n * Obtient la root cause principale (première dans la liste)\n */\nexport const getPrimaryRootCause = (predictions: Prediction[]): string | null => {\n const rootCauses = extractRootCauses(predictions);\n return rootCauses.length > 0 ? rootCauses[0] : null;\n};\n\nexport function analyzeApiResponse(response: { status: number; data: any }) {\n // Dummy implementation for test\n return response.status === 200 ? 'success' : 'error';\n}\n"],"names":[],"mappings":";;AA+BA;;;AAGG;AACI,IAAM,iBAAiB,GAAG,UAAC,WAAyB,EAAA;IACzD,IAAI,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;AAC/C,QAAA,OAAO,EAAE;IACX;AAEA,IAAA,OAAO;AACJ,SAAA,MAAM,CAAC,UAAA,UAAU,EAAA,EAAI,OAAA,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,CAAA,CAA5C,CAA4C;SACjE,GAAG,CAAC,UAAA,UAAU,EAAA,EAAI,OAAA,UAAU,CAAC,IAAI,CAAA,CAAf,CAAe,CAAC;AACvC;AAEA;;AAEG;AACI,IAAM,iBAAiB,GAAG,UAAC,WAAyB,EAAA;IACzD,IAAI,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;AAC/C,QAAA,OAAO,IAAI;IACb;;AAGA,IAAA,OAAO,WAAW,CAAC,IAAI,CAAC,UAAA,UAAU,EAAA;QAChC,OAAA,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK;AAA5C,IAAA,CAA4C,CAC7C;AACH;AAEA;;AAEG;AACI,IAAM,mBAAmB,GAAG,UAAC,WAAyB,EAAA;AAC3D,IAAA,IAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC;AACjD,IAAA,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI;AACrD;;;;;;"}
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Codes JDI (Justificatif D'Identité) considérés comme "bloquants" pour le
5
+ * nœud controle-jdi, c'est-à-dire déclenchant la boucle de resoumission
6
+ * (écran d'erreur + éventuel réessai) plutôt qu'un passage silencieux.
7
+ *
8
+ * Historiquement cette liste était hardcodée en dur (inversée) dans
9
+ * JDIProcessing.tsx / DocumentVideoProcessing.tsx / DocumentProcessing.tsx :
10
+ * `isSuccess = ["1.", "4.", "5.", "6.", "9."].some(prefix => code.startsWith(prefix))`.
11
+ * Elle est désormais configurable par nœud via `node.blockingCodes`, avec
12
+ * cette liste comme valeur par défaut pour préserver le comportement legacy.
13
+ *
14
+ * Miroir exact du catalogue frontend (app-frontend/src/utils/jdiCodes.ts) —
15
+ * les deux listes doivent rester synchronisées.
16
+ */
17
+ var DEFAULT_BLOCKING_CODES = [
18
+ '2.0',
19
+ '2.1',
20
+ '2.2',
21
+ '2.3',
22
+ '2.4',
23
+ '2.5',
24
+ '2.6',
25
+ '3.0',
26
+ '7.0',
27
+ '7.1',
28
+ ];
29
+ /**
30
+ * Codes toujours bloquants, quelle que soit la configuration du nœud.
31
+ * 8.0 (document trouvé dans la base de spécimens frauduleux) ne doit jamais
32
+ * pouvoir être désactivé — cf. DocumentCheck.tsx `isRetryAllowed` historique
33
+ * (`errorCode?.startsWith("8")` bloque déjà totalement le retry).
34
+ */
35
+ var ALWAYS_BLOCKING_CODES = ['8.0'];
36
+ /**
37
+ * Détermine si un code JDI doit être traité comme bloquant pour un nœud
38
+ * controle-jdi donné.
39
+ *
40
+ * - `configured` absent (nœud legacy, jamais reconfiguré) → applique
41
+ * DEFAULT_BLOCKING_CODES (comportement inchangé).
42
+ * - `configured` présent (même vide) → correspondance exacte uniquement
43
+ * (pas de préfixe : "4.0" dans la liste ne bloque pas "4.1"/"4.2").
44
+ * - Les codes de ALWAYS_BLOCKING_CODES bloquent toujours, indépendamment
45
+ * de `configured`.
46
+ */
47
+ function isBlockingCode(code, configured) {
48
+ if (ALWAYS_BLOCKING_CODES.includes(code)) {
49
+ return true;
50
+ }
51
+ var list = configured !== null && configured !== void 0 ? configured : DEFAULT_BLOCKING_CODES;
52
+ return list.includes(code);
53
+ }
54
+
55
+ exports.ALWAYS_BLOCKING_CODES = ALWAYS_BLOCKING_CODES;
56
+ exports.DEFAULT_BLOCKING_CODES = DEFAULT_BLOCKING_CODES;
57
+ exports.isBlockingCode = isBlockingCode;
58
+ //# sourceMappingURL=jdiCodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jdiCodes.js","sources":["../../../../src/utils/jdiCodes.ts"],"sourcesContent":["/**\n * Codes JDI (Justificatif D'Identité) considérés comme \"bloquants\" pour le\n * nœud controle-jdi, c'est-à-dire déclenchant la boucle de resoumission\n * (écran d'erreur + éventuel réessai) plutôt qu'un passage silencieux.\n *\n * Historiquement cette liste était hardcodée en dur (inversée) dans\n * JDIProcessing.tsx / DocumentVideoProcessing.tsx / DocumentProcessing.tsx :\n * `isSuccess = [\"1.\", \"4.\", \"5.\", \"6.\", \"9.\"].some(prefix => code.startsWith(prefix))`.\n * Elle est désormais configurable par nœud via `node.blockingCodes`, avec\n * cette liste comme valeur par défaut pour préserver le comportement legacy.\n *\n * Miroir exact du catalogue frontend (app-frontend/src/utils/jdiCodes.ts) —\n * les deux listes doivent rester synchronisées.\n */\nexport const DEFAULT_BLOCKING_CODES: string[] = [\n '2.0',\n '2.1',\n '2.2',\n '2.3',\n '2.4',\n '2.5',\n '2.6',\n '3.0',\n '7.0',\n '7.1',\n];\n\n/**\n * Codes toujours bloquants, quelle que soit la configuration du nœud.\n * 8.0 (document trouvé dans la base de spécimens frauduleux) ne doit jamais\n * pouvoir être désactivé — cf. DocumentCheck.tsx `isRetryAllowed` historique\n * (`errorCode?.startsWith(\"8\")` bloque déjà totalement le retry).\n */\nexport const ALWAYS_BLOCKING_CODES: string[] = ['8.0'];\n\n/**\n * Détermine si un code JDI doit être traité comme bloquant pour un nœud\n * controle-jdi donné.\n *\n * - `configured` absent (nœud legacy, jamais reconfiguré) → applique\n * DEFAULT_BLOCKING_CODES (comportement inchangé).\n * - `configured` présent (même vide) → correspondance exacte uniquement\n * (pas de préfixe : \"4.0\" dans la liste ne bloque pas \"4.1\"/\"4.2\").\n * - Les codes de ALWAYS_BLOCKING_CODES bloquent toujours, indépendamment\n * de `configured`.\n */\nexport function isBlockingCode(code: string, configured?: string[]): boolean {\n if (ALWAYS_BLOCKING_CODES.includes(code)) {\n return true;\n }\n const list = configured ?? DEFAULT_BLOCKING_CODES;\n return list.includes(code);\n}\n"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;AAaG;AACI,IAAM,sBAAsB,GAAa;IAC9C,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;;AAGP;;;;;AAKG;AACI,IAAM,qBAAqB,GAAa,CAAC,KAAK;AAErD;;;;;;;;;;AAUG;AACG,SAAU,cAAc,CAAC,IAAY,EAAE,UAAqB,EAAA;AAChE,IAAA,IAAI,qBAAqB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACxC,QAAA,OAAO,IAAI;IACb;IACA,IAAM,IAAI,GAAG,UAAU,KAAA,IAAA,IAAV,UAAU,KAAA,MAAA,GAAV,UAAU,GAAI,sBAAsB;AACjD,IAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC5B;;;;;;"}
@@ -1,5 +1,18 @@
1
1
  'use strict';
2
2
 
3
+ var tslib_es6 = require('../node_modules/tslib/tslib.es6.js');
4
+
5
+ /**
6
+ * Clé i18n (suffixe de `validation_points.7.0.*`) pour chaque champ d'identité
7
+ * en échec. Voir docs backend NFC_JDI_ERROR_MAPPING.md pour le référentiel de
8
+ * codes — 7.0 = "owner" (le détenteur du document ne correspond pas à la
9
+ * saisie utilisateur).
10
+ */
11
+ var MISMATCH_FIELD_KEY = {
12
+ firstName: "mismatch_first_name",
13
+ lastName: "mismatch_last_name",
14
+ birthDate: "mismatch_birth_date",
15
+ };
3
16
  /**
4
17
  * Default validation points for success scenarios
5
18
  */
@@ -32,10 +45,14 @@ function getErrorCodeFromPredictions(predictions) {
32
45
  * @param predictions - Optional predictions array as fallback for error code
33
46
  * @param t - Translation function from i18n
34
47
  * @param type - Type of scenario: 'success' or 'error'
48
+ * @param mismatchDetails - Pour le code 7.0 uniquement : champs d'identité en
49
+ * échec (saisi vs lu), calculés côté backend. S'ils sont fournis et non
50
+ * vides, remplacent la bullet "document" générique par un message
51
+ * personnalisé par champ. Sinon, comportement inchangé (message générique).
35
52
  * @returns Array of validation point strings
36
53
  */
37
54
  function getValidationPoints(errorCode, predictions, t, // Using any to be compatible with i18n TFunction
38
- type) {
55
+ type, mismatchDetails) {
39
56
  // Use errorCode from props, or try to get from predictions as fallback
40
57
  var code = errorCode;
41
58
  if (!code) {
@@ -45,9 +62,25 @@ type) {
45
62
  // Try to get code-specific validation points from i18n
46
63
  var quality = t("validation_points.".concat(code, ".quality"), "");
47
64
  var readability = t("validation_points.".concat(code, ".readability"), "");
48
- var document_1 = t("validation_points.".concat(code, ".document"), "");
49
65
  // If we have at least quality and readability, use code-specific points
50
66
  if (quality && readability) {
67
+ if (code === '7.0' && mismatchDetails && mismatchDetails.length > 0) {
68
+ var mismatchBullets = mismatchDetails
69
+ .map(function (detail) {
70
+ var fieldKey = MISMATCH_FIELD_KEY[detail.field];
71
+ if (!fieldKey)
72
+ return "";
73
+ return t("validation_points.7.0.".concat(fieldKey), {
74
+ entered: detail.entered,
75
+ read: detail.read,
76
+ });
77
+ })
78
+ .filter(Boolean);
79
+ if (mismatchBullets.length > 0) {
80
+ return tslib_es6.__spreadArray([quality, readability], mismatchBullets, true).filter(Boolean);
81
+ }
82
+ }
83
+ var document_1 = t("validation_points.".concat(code, ".document"), "");
51
84
  // Filter out empty strings
52
85
  return [quality, readability, document_1].filter(Boolean);
53
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validationUtils.js","sources":["../../../../src/utils/validationUtils.ts"],"sourcesContent":["import type { Prediction } from \"./apiAnalysis\";\n\n/**\n * Default validation points for success scenarios\n */\nconst DEFAULT_SUCCESS_VALIDATION_POINTS = {\n quality: \"success.quality_excellent\",\n readability: \"success.readability_confirmed\",\n authenticity: \"success.authenticity_verified\",\n} as const;\n\n/**\n * Default validation points for error scenarios\n */\nconst DEFAULT_ERROR_VALIDATION_POINTS = {\n quality: \"errors.image_quality_insufficient\",\n readability: \"errors.readability_problematic\",\n authenticity: \"errors.authenticity_not_verified\",\n} as const;\n\n/**\n * Safely extracts error code from predictions array\n */\nexport function getErrorCodeFromPredictions(predictions?: Prediction[] | null): string | null {\n if (!predictions || !Array.isArray(predictions) || predictions.length === 0) {\n return null;\n }\n return predictions[0].code || null;\n}\n\n/**\n * Gets validation points based on error code and scenario type\n * \n * @param errorCode - The error code from API response (e.g., \"1.0\", \"2.1\")\n * @param predictions - Optional predictions array as fallback for error code\n * @param t - Translation function from i18n\n * @param type - Type of scenario: 'success' or 'error'\n * @returns Array of validation point strings\n */\nexport function getValidationPoints(\n errorCode: string | undefined | null,\n predictions: Prediction[] | undefined | null,\n t: any, // Using any to be compatible with i18n TFunction\n type: 'success' | 'error'\n): string[] {\n // Use errorCode from props, or try to get from predictions as fallback\n let code = errorCode;\n if (!code) {\n code = getErrorCodeFromPredictions(predictions);\n }\n\n if (code) {\n // Try to get code-specific validation points from i18n\n const quality = t(`validation_points.${code}.quality`, \"\");\n const readability = t(`validation_points.${code}.readability`, \"\");\n const document = t(`validation_points.${code}.document`, \"\");\n\n // If we have at least quality and readability, use code-specific points\n if (quality && readability) {\n // Filter out empty strings\n return [quality, readability, document].filter(Boolean);\n }\n }\n\n // Fallback to default validation points\n const defaults = type === 'success'\n ? DEFAULT_SUCCESS_VALIDATION_POINTS\n : DEFAULT_ERROR_VALIDATION_POINTS;\n\n return [\n t(defaults.quality, \"\"),\n t(defaults.readability, \"\"),\n t(defaults.authenticity, \"\"),\n ].filter(Boolean);\n}\n"],"names":[],"mappings":";;AAEA;;AAEG;AACH,IAAM,iCAAiC,GAAG;AACtC,IAAA,OAAO,EAAE,2BAA2B;AACpC,IAAA,WAAW,EAAE,+BAA+B;AAC5C,IAAA,YAAY,EAAE,+BAA+B;CACvC;AAEV;;AAEG;AACH,IAAM,+BAA+B,GAAG;AACpC,IAAA,OAAO,EAAE,mCAAmC;AAC5C,IAAA,WAAW,EAAE,gCAAgC;AAC7C,IAAA,YAAY,EAAE,kCAAkC;CAC1C;AAEV;;AAEG;AACG,SAAU,2BAA2B,CAAC,WAAiC,EAAA;AACzE,IAAA,IAAI,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;AACzE,QAAA,OAAO,IAAI;IACf;IACA,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI;AACtC;AAEA;;;;;;;;AAQG;AACG,SAAU,mBAAmB,CAC/B,SAAoC,EACpC,WAA4C,EAC5C,CAAM;AACN,IAAyB,EAAA;;IAGzB,IAAI,IAAI,GAAG,SAAS;IACpB,IAAI,CAAC,IAAI,EAAE;AACP,QAAA,IAAI,GAAG,2BAA2B,CAAC,WAAW,CAAC;IACnD;IAEA,IAAI,IAAI,EAAE;;QAEN,IAAM,OAAO,GAAG,CAAC,CAAC,oBAAA,CAAA,MAAA,CAAqB,IAAI,EAAA,UAAA,CAAU,EAAE,EAAE,CAAC;QAC1D,IAAM,WAAW,GAAG,CAAC,CAAC,oBAAA,CAAA,MAAA,CAAqB,IAAI,EAAA,cAAA,CAAc,EAAE,EAAE,CAAC;QAClE,IAAM,UAAQ,GAAG,CAAC,CAAC,oBAAA,CAAA,MAAA,CAAqB,IAAI,EAAA,WAAA,CAAW,EAAE,EAAE,CAAC;;AAG5D,QAAA,IAAI,OAAO,IAAI,WAAW,EAAE;;AAExB,YAAA,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,UAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QAC3D;IACJ;;AAGA,IAAA,IAAM,QAAQ,GAAG,IAAI,KAAK;AACtB,UAAE;UACA,+BAA+B;IAErC,OAAO;AACH,QAAA,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;AACvB,QAAA,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;AAC3B,QAAA,CAAC,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,CAAC;AAC/B,KAAA,CAAC,MAAM,CAAC,OAAO,CAAC;AACrB;;;;;"}
1
+ {"version":3,"file":"validationUtils.js","sources":["../../../../src/utils/validationUtils.ts"],"sourcesContent":["import type { Prediction, JdiMismatchDetail } from \"./apiAnalysis\";\n\n/**\n * Clé i18n (suffixe de `validation_points.7.0.*`) pour chaque champ d'identité\n * en échec. Voir docs backend NFC_JDI_ERROR_MAPPING.md pour le référentiel de\n * codes — 7.0 = \"owner\" (le détenteur du document ne correspond pas à la\n * saisie utilisateur).\n */\nconst MISMATCH_FIELD_KEY: Record<JdiMismatchDetail[\"field\"], string> = {\n firstName: \"mismatch_first_name\",\n lastName: \"mismatch_last_name\",\n birthDate: \"mismatch_birth_date\",\n};\n\n/**\n * Default validation points for success scenarios\n */\nconst DEFAULT_SUCCESS_VALIDATION_POINTS = {\n quality: \"success.quality_excellent\",\n readability: \"success.readability_confirmed\",\n authenticity: \"success.authenticity_verified\",\n} as const;\n\n/**\n * Default validation points for error scenarios\n */\nconst DEFAULT_ERROR_VALIDATION_POINTS = {\n quality: \"errors.image_quality_insufficient\",\n readability: \"errors.readability_problematic\",\n authenticity: \"errors.authenticity_not_verified\",\n} as const;\n\n/**\n * Safely extracts error code from predictions array\n */\nexport function getErrorCodeFromPredictions(predictions?: Prediction[] | null): string | null {\n if (!predictions || !Array.isArray(predictions) || predictions.length === 0) {\n return null;\n }\n return predictions[0].code || null;\n}\n\n/**\n * Gets validation points based on error code and scenario type\n *\n * @param errorCode - The error code from API response (e.g., \"1.0\", \"2.1\")\n * @param predictions - Optional predictions array as fallback for error code\n * @param t - Translation function from i18n\n * @param type - Type of scenario: 'success' or 'error'\n * @param mismatchDetails - Pour le code 7.0 uniquement : champs d'identité en\n * échec (saisi vs lu), calculés côté backend. S'ils sont fournis et non\n * vides, remplacent la bullet \"document\" générique par un message\n * personnalisé par champ. Sinon, comportement inchangé (message générique).\n * @returns Array of validation point strings\n */\nexport function getValidationPoints(\n errorCode: string | undefined | null,\n predictions: Prediction[] | undefined | null,\n t: any, // Using any to be compatible with i18n TFunction\n type: 'success' | 'error',\n mismatchDetails?: JdiMismatchDetail[] | null,\n): string[] {\n // Use errorCode from props, or try to get from predictions as fallback\n let code = errorCode;\n if (!code) {\n code = getErrorCodeFromPredictions(predictions);\n }\n\n if (code) {\n // Try to get code-specific validation points from i18n\n const quality = t(`validation_points.${code}.quality`, \"\");\n const readability = t(`validation_points.${code}.readability`, \"\");\n\n // If we have at least quality and readability, use code-specific points\n if (quality && readability) {\n if (code === '7.0' && mismatchDetails && mismatchDetails.length > 0) {\n const mismatchBullets = mismatchDetails\n .map((detail) => {\n const fieldKey = MISMATCH_FIELD_KEY[detail.field];\n if (!fieldKey) return \"\";\n return t(`validation_points.7.0.${fieldKey}`, {\n entered: detail.entered,\n read: detail.read,\n });\n })\n .filter(Boolean);\n\n if (mismatchBullets.length > 0) {\n return [quality, readability, ...mismatchBullets].filter(Boolean);\n }\n }\n\n const document = t(`validation_points.${code}.document`, \"\");\n // Filter out empty strings\n return [quality, readability, document].filter(Boolean);\n }\n }\n\n // Fallback to default validation points\n const defaults = type === 'success'\n ? DEFAULT_SUCCESS_VALIDATION_POINTS\n : DEFAULT_ERROR_VALIDATION_POINTS;\n\n return [\n t(defaults.quality, \"\"),\n t(defaults.readability, \"\"),\n t(defaults.authenticity, \"\"),\n ].filter(Boolean);\n}\n"],"names":["__spreadArray"],"mappings":"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"}
@@ -10,7 +10,7 @@ import DocumentVideoProcessing from './document-video-flow/DocumentVideoProcessi
10
10
  * Gère les étapes internes de capture, confirmation et traitement de la vidéo.
11
11
  */
12
12
  var DocumentVideoCapture = function (_a) {
13
- var selectedDocumentType = _a.selectedDocumentType, onComplete = _a.onComplete, onBack = _a.onBack, nodeId = _a.nodeId, sessionId = _a.sessionId, previewOverrides = _a.previewOverrides;
13
+ var selectedDocumentType = _a.selectedDocumentType, onComplete = _a.onComplete, onBack = _a.onBack, nodeId = _a.nodeId, sessionId = _a.sessionId, previewOverrides = _a.previewOverrides, blockingCodes = _a.blockingCodes;
14
14
  var _b = useState(0), internalStep = _b[0], setInternalStep = _b[1];
15
15
  var _c = useState({}), videoData = _c[0], setVideoData = _c[1];
16
16
  var _d = useState({}), thumbnail = _d[0], setThumbnail = _d[1];
@@ -71,7 +71,7 @@ var DocumentVideoCapture = function (_a) {
71
71
  (thumbnail[currentSide] || (previewOverrides === null || previewOverrides === void 0 ? void 0 : previewOverrides[currentSide])) && (jsx(DocumentVideoConfirmation, { videoData: videoData[currentSide], thumbnail: ((previewOverrides === null || previewOverrides === void 0 ? void 0 : previewOverrides[currentSide]) ||
72
72
  thumbnail[currentSide]), documentType: (selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.label) || "document", side: currentSide, onConfirm: handleConfirmVideo, onRetake: handleRetakeVideo })), internalStep === 2 &&
73
73
  videoData.recto &&
74
- (thumbnail.recto || (previewOverrides === null || previewOverrides === void 0 ? void 0 : previewOverrides.recto)) && (jsx(DocumentVideoProcessing, { onProcessingComplete: videoProcessed, videoData: videoData, thumbnail: previewOverrides !== null && previewOverrides !== void 0 ? previewOverrides : thumbnail, onRetake: onRetake, sessionId: sessionId, nodeId: nodeId, documentTemplateId: (selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.documentTemplateId) || "", documentType: (selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.id) || "document", requiresTwoSides: requiresTwoSides }))] }));
74
+ (thumbnail.recto || (previewOverrides === null || previewOverrides === void 0 ? void 0 : previewOverrides.recto)) && (jsx(DocumentVideoProcessing, { onProcessingComplete: videoProcessed, videoData: videoData, thumbnail: previewOverrides !== null && previewOverrides !== void 0 ? previewOverrides : thumbnail, onRetake: onRetake, sessionId: sessionId, nodeId: nodeId, documentTemplateId: (selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.documentTemplateId) || "", documentType: (selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.id) || "document", requiresTwoSides: requiresTwoSides, blockingCodes: blockingCodes }))] }));
75
75
  };
76
76
 
77
77
  export { DocumentVideoCapture as default };
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentVideoCapture.js","sources":["../../../../../src/components/document-video/DocumentVideoCapture.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport DocumentVideoFlow from \"./document-video-flow/DocumentVideoFlow\";\nimport DocumentVideoConfirmation from \"./DocumentVideoConfirmation\";\nimport DocumentVideoProcessing from \"./document-video-flow/DocumentVideoProcessing\";\nimport type {\n DocumentVideoCaptureBySide,\n DocumentVideoPreviewBySide,\n DocumentVideoSide,\n DocumentVideoCaptureData,\n} from \"../../types/documentVideo\";\nimport type { Prediction } from \"../../utils/apiAnalysis\";\n\ninterface DocumentVideoCaptureProps {\n selectedDocumentType: {\n id: string;\n label: string;\n hasTwoSides?: boolean;\n documentTemplateId?: string;\n } | null;\n onComplete: (\n success: boolean,\n predictions?: Prediction[],\n errorCode?: string,\n ) => void;\n onBack: () => void;\n nodeId: string;\n sessionId: string;\n previewOverrides?: DocumentVideoPreviewBySide;\n}\n\n/**\n * Composant de gestion du flux de capture vidéo de documents.\n * Gère les étapes internes de capture, confirmation et traitement de la vidéo.\n */\nconst DocumentVideoCapture = ({\n selectedDocumentType,\n onComplete,\n onBack,\n nodeId,\n sessionId,\n previewOverrides,\n}: DocumentVideoCaptureProps) => {\n const [internalStep, setInternalStep] = useState(0);\n const [videoData, setVideoData] = useState<DocumentVideoCaptureBySide>({});\n const [thumbnail, setThumbnail] = useState<DocumentVideoPreviewBySide>({});\n const [isTransitioning, setIsTransitioning] = useState(false);\n const [currentSide, setCurrentSide] = useState<DocumentVideoSide>(\"recto\");\n\n const requiresTwoSides = !!selectedDocumentType?.hasTwoSides;\n\n const handleConfirmVideo = () => {\n // Ajouter une transition visuelle avant de passer à l'étape suivante\n setIsTransitioning(true);\n\n // Attendre un peu pour l'animation avant de passer à l'étape suivante\n setTimeout(() => {\n if (requiresTwoSides && currentSide === \"recto\") {\n setCurrentSide(\"verso\");\n setInternalStep(0);\n } else {\n setInternalStep(2); // Passer à l'étape de traitement de la vidéo\n }\n setIsTransitioning(false);\n }, 500);\n };\n\n const videoProcessed = (\n processed: boolean,\n predictions?: Prediction[],\n errorCode?: string,\n ) => {\n // Callback pour indiquer que la vidéo a été traitée\n onComplete(processed, predictions, errorCode);\n };\n\n const onRetake = () => {\n setCurrentSide(\"recto\");\n setVideoData({});\n setThumbnail({});\n setInternalStep(0);\n };\n\n const handleRetakeVideo = () => {\n setVideoData((prev) => ({ ...prev, [currentSide]: undefined }));\n setThumbnail((prev) => ({ ...prev, [currentSide]: undefined }));\n setInternalStep(0);\n };\n\n return (\n <div\n className={`h-full w-full transition-opacity duration-500 ${\n isTransitioning ? \"opacity-50\" : \"opacity-100\"\n }`}\n >\n {internalStep === 0 && (\n <DocumentVideoFlow\n setVideoData={(\n side: DocumentVideoSide,\n data: DocumentVideoCaptureData,\n ) => setVideoData((prev) => ({ ...prev, [side]: data }))}\n setThumbnail={(side: DocumentVideoSide, data: string) =>\n setThumbnail((prev) => ({ ...prev, [side]: data }))\n }\n setStep={setInternalStep}\n onBack={\n currentSide === \"verso\"\n ? () => {\n setCurrentSide(\"recto\");\n setInternalStep(1);\n }\n : onBack\n }\n documentType={selectedDocumentType?.label || \"document\"}\n side={currentSide}\n />\n )}\n {internalStep === 1 &&\n videoData[currentSide] &&\n (thumbnail[currentSide] || previewOverrides?.[currentSide]) && (\n <DocumentVideoConfirmation\n videoData={videoData[currentSide] as DocumentVideoCaptureData}\n thumbnail={\n (previewOverrides?.[currentSide] ||\n thumbnail[currentSide]) as string\n }\n documentType={selectedDocumentType?.label || \"document\"}\n side={currentSide}\n onConfirm={handleConfirmVideo}\n onRetake={handleRetakeVideo}\n />\n )}\n {internalStep === 2 &&\n videoData.recto &&\n (thumbnail.recto || previewOverrides?.recto) && (\n <DocumentVideoProcessing\n onProcessingComplete={videoProcessed}\n videoData={videoData}\n thumbnail={previewOverrides ?? thumbnail}\n onRetake={onRetake}\n sessionId={sessionId}\n nodeId={nodeId}\n documentTemplateId={selectedDocumentType?.documentTemplateId || \"\"}\n documentType={selectedDocumentType?.id || \"document\"}\n requiresTwoSides={requiresTwoSides}\n />\n )}\n </div>\n );\n};\n\nexport default DocumentVideoCapture;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"DocumentVideoCapture.js","sources":["../../../../../src/components/document-video/DocumentVideoCapture.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport DocumentVideoFlow from \"./document-video-flow/DocumentVideoFlow\";\nimport DocumentVideoConfirmation from \"./DocumentVideoConfirmation\";\nimport DocumentVideoProcessing from \"./document-video-flow/DocumentVideoProcessing\";\nimport type {\n DocumentVideoCaptureBySide,\n DocumentVideoPreviewBySide,\n DocumentVideoSide,\n DocumentVideoCaptureData,\n} from \"../../types/documentVideo\";\nimport type { Prediction } from \"../../utils/apiAnalysis\";\n\ninterface DocumentVideoCaptureProps {\n selectedDocumentType: {\n id: string;\n label: string;\n hasTwoSides?: boolean;\n documentTemplateId?: string;\n } | null;\n onComplete: (\n success: boolean,\n predictions?: Prediction[],\n errorCode?: string,\n ) => void;\n onBack: () => void;\n nodeId: string;\n sessionId: string;\n previewOverrides?: DocumentVideoPreviewBySide;\n /** Codes JDI exacts considérés comme bloquants pour ce nœud (cf. node.blockingCodes). Absent = liste par défaut. */\n blockingCodes?: string[];\n}\n\n/**\n * Composant de gestion du flux de capture vidéo de documents.\n * Gère les étapes internes de capture, confirmation et traitement de la vidéo.\n */\nconst DocumentVideoCapture = ({\n selectedDocumentType,\n onComplete,\n onBack,\n nodeId,\n sessionId,\n previewOverrides,\n blockingCodes,\n}: DocumentVideoCaptureProps) => {\n const [internalStep, setInternalStep] = useState(0);\n const [videoData, setVideoData] = useState<DocumentVideoCaptureBySide>({});\n const [thumbnail, setThumbnail] = useState<DocumentVideoPreviewBySide>({});\n const [isTransitioning, setIsTransitioning] = useState(false);\n const [currentSide, setCurrentSide] = useState<DocumentVideoSide>(\"recto\");\n\n const requiresTwoSides = !!selectedDocumentType?.hasTwoSides;\n\n const handleConfirmVideo = () => {\n // Ajouter une transition visuelle avant de passer à l'étape suivante\n setIsTransitioning(true);\n\n // Attendre un peu pour l'animation avant de passer à l'étape suivante\n setTimeout(() => {\n if (requiresTwoSides && currentSide === \"recto\") {\n setCurrentSide(\"verso\");\n setInternalStep(0);\n } else {\n setInternalStep(2); // Passer à l'étape de traitement de la vidéo\n }\n setIsTransitioning(false);\n }, 500);\n };\n\n const videoProcessed = (\n processed: boolean,\n predictions?: Prediction[],\n errorCode?: string,\n ) => {\n // Callback pour indiquer que la vidéo a été traitée\n onComplete(processed, predictions, errorCode);\n };\n\n const onRetake = () => {\n setCurrentSide(\"recto\");\n setVideoData({});\n setThumbnail({});\n setInternalStep(0);\n };\n\n const handleRetakeVideo = () => {\n setVideoData((prev) => ({ ...prev, [currentSide]: undefined }));\n setThumbnail((prev) => ({ ...prev, [currentSide]: undefined }));\n setInternalStep(0);\n };\n\n return (\n <div\n className={`h-full w-full transition-opacity duration-500 ${\n isTransitioning ? \"opacity-50\" : \"opacity-100\"\n }`}\n >\n {internalStep === 0 && (\n <DocumentVideoFlow\n setVideoData={(\n side: DocumentVideoSide,\n data: DocumentVideoCaptureData,\n ) => setVideoData((prev) => ({ ...prev, [side]: data }))}\n setThumbnail={(side: DocumentVideoSide, data: string) =>\n setThumbnail((prev) => ({ ...prev, [side]: data }))\n }\n setStep={setInternalStep}\n onBack={\n currentSide === \"verso\"\n ? () => {\n setCurrentSide(\"recto\");\n setInternalStep(1);\n }\n : onBack\n }\n documentType={selectedDocumentType?.label || \"document\"}\n side={currentSide}\n />\n )}\n {internalStep === 1 &&\n videoData[currentSide] &&\n (thumbnail[currentSide] || previewOverrides?.[currentSide]) && (\n <DocumentVideoConfirmation\n videoData={videoData[currentSide] as DocumentVideoCaptureData}\n thumbnail={\n (previewOverrides?.[currentSide] ||\n thumbnail[currentSide]) as string\n }\n documentType={selectedDocumentType?.label || \"document\"}\n side={currentSide}\n onConfirm={handleConfirmVideo}\n onRetake={handleRetakeVideo}\n />\n )}\n {internalStep === 2 &&\n videoData.recto &&\n (thumbnail.recto || previewOverrides?.recto) && (\n <DocumentVideoProcessing\n onProcessingComplete={videoProcessed}\n videoData={videoData}\n thumbnail={previewOverrides ?? thumbnail}\n onRetake={onRetake}\n sessionId={sessionId}\n nodeId={nodeId}\n documentTemplateId={selectedDocumentType?.documentTemplateId || \"\"}\n documentType={selectedDocumentType?.id || \"document\"}\n requiresTwoSides={requiresTwoSides}\n blockingCodes={blockingCodes}\n />\n )}\n </div>\n );\n};\n\nexport default DocumentVideoCapture;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
@@ -5,6 +5,7 @@ import Title from '../../ui/Title.js';
5
5
  import Subtitle from '../../ui/Subtitle.js';
6
6
  import { useI18n } from '../../../hooks/useI18n.js';
7
7
  import { analyzeDocumentVideo } from '../../../services/analysis.js';
8
+ import { isBlockingCode } from '../../../utils/jdiCodes.js';
8
9
 
9
10
  var processingSteps = [
10
11
  {
@@ -21,7 +22,7 @@ var processingSteps = [
21
22
  },
22
23
  ];
23
24
  var DocumentVideoProcessing = function (_a) {
24
- var onProcessingComplete = _a.onProcessingComplete, videoData = _a.videoData, thumbnail = _a.thumbnail, onRetake = _a.onRetake, sessionId = _a.sessionId, nodeId = _a.nodeId, documentTemplateId = _a.documentTemplateId, documentType = _a.documentType, requiresTwoSides = _a.requiresTwoSides;
25
+ var onProcessingComplete = _a.onProcessingComplete, videoData = _a.videoData, thumbnail = _a.thumbnail, onRetake = _a.onRetake, sessionId = _a.sessionId, nodeId = _a.nodeId, documentTemplateId = _a.documentTemplateId, documentType = _a.documentType, requiresTwoSides = _a.requiresTwoSides, blockingCodes = _a.blockingCodes;
25
26
  var t = useI18n().t;
26
27
  var _b = useState(0), currentStep = _b[0], setCurrentStep = _b[1];
27
28
  var _c = useState(false), hasError = _c[0], setHasError = _c[1];
@@ -46,7 +47,7 @@ var DocumentVideoProcessing = function (_a) {
46
47
  }
47
48
  }, 90000);
48
49
  var processFiles = function () { return __awaiter(void 0, void 0, void 0, function () {
49
- var response, rawCode, extractedCode_1, isSuccess, predictionSource, predictions, error_1;
50
+ var response, rawCode, extractedCode, isSuccess, predictionSource, predictions, error_1;
50
51
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3;
51
52
  return __generator(this, function (_4) {
52
53
  switch (_4.label) {
@@ -72,10 +73,8 @@ var DocumentVideoProcessing = function (_a) {
72
73
  console.log("✅ Analysis response:", response);
73
74
  clearTimeout(timeoutId);
74
75
  rawCode = (_r = (_m = (_h = (_e = (_d = (_c = (_b = (_a = response === null || response === void 0 ? void 0 : response.result) === null || _a === void 0 ? void 0 : _a.job_status) === null || _b === void 0 ? void 0 : _b.predictions) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.code) !== null && _e !== void 0 ? _e : (_g = (_f = response === null || response === void 0 ? void 0 : response.result) === null || _f === void 0 ? void 0 : _f.job_status) === null || _g === void 0 ? void 0 : _g.code) !== null && _h !== void 0 ? _h : (_l = (_k = (_j = response === null || response === void 0 ? void 0 : response.result) === null || _j === void 0 ? void 0 : _j.result) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.code) !== null && _m !== void 0 ? _m : (_q = (_p = (_o = response === null || response === void 0 ? void 0 : response.job_status) === null || _o === void 0 ? void 0 : _o.predictions) === null || _p === void 0 ? void 0 : _p[0]) === null || _q === void 0 ? void 0 : _q.code) !== null && _r !== void 0 ? _r : response === null || response === void 0 ? void 0 : response.code;
75
- extractedCode_1 = rawCode ? String(rawCode) : "";
76
- isSuccess = ["1.", "4.", "5.", "6.", "9."].some(function (prefix) {
77
- return extractedCode_1.startsWith(prefix);
78
- });
76
+ extractedCode = rawCode ? String(rawCode) : "";
77
+ isSuccess = !isBlockingCode(extractedCode, blockingCodes);
79
78
  predictionSource = (_3 = (_y = (_v = (_u = (_t = (_s = response === null || response === void 0 ? void 0 : response.result) === null || _s === void 0 ? void 0 : _s.job_status) === null || _t === void 0 ? void 0 : _t.predictions) === null || _u === void 0 ? void 0 : _u[0]) !== null && _v !== void 0 ? _v : (_x = (_w = response === null || response === void 0 ? void 0 : response.job_status) === null || _w === void 0 ? void 0 : _w.predictions) === null || _x === void 0 ? void 0 : _x[0]) !== null && _y !== void 0 ? _y : (_2 = (_1 = (_0 = (_z = response === null || response === void 0 ? void 0 : response.result) === null || _z === void 0 ? void 0 : _z.result) === null || _0 === void 0 ? void 0 : _0[0]) === null || _1 === void 0 ? void 0 : _1.predictions) === null || _2 === void 0 ? void 0 : _2[0]) !== null && _3 !== void 0 ? _3 : null;
80
79
  predictions = (predictionSource === null || predictionSource === void 0 ? void 0 : predictionSource.code)
81
80
  ? [
@@ -90,10 +89,10 @@ var DocumentVideoProcessing = function (_a) {
90
89
  type: predictionSource.type || "document",
91
90
  },
92
91
  ]
93
- : extractedCode_1
92
+ : extractedCode
94
93
  ? [
95
94
  {
96
- code: extractedCode_1,
95
+ code: extractedCode,
97
96
  codeName: (response === null || response === void 0 ? void 0 : response.codeName) || "",
98
97
  codeDescription: (response === null || response === void 0 ? void 0 : response.codeDescription) || "",
99
98
  type: "document",
@@ -102,11 +101,11 @@ var DocumentVideoProcessing = function (_a) {
102
101
  : [];
103
102
  console.log("📊 Document video analysis result:", {
104
103
  isSuccess: isSuccess,
105
- code: extractedCode_1,
104
+ code: extractedCode,
106
105
  response: response,
107
106
  });
108
107
  setAnalysisPredictions(predictions);
109
- setAnalysisErrorCode(extractedCode_1);
108
+ setAnalysisErrorCode(extractedCode);
110
109
  setHasError(!isSuccess);
111
110
  setIsDone(true);
112
111
  return [3 /*break*/, 4];
@@ -127,7 +126,7 @@ var DocumentVideoProcessing = function (_a) {
127
126
  return function () {
128
127
  clearTimeout(timeoutId);
129
128
  };
130
- }, [onProcessingComplete, videoData, thumbnail, sessionId, nodeId, isDone, documentType, requiresTwoSides, documentTemplateId]);
129
+ }, [onProcessingComplete, videoData, thumbnail, sessionId, nodeId, isDone, documentType, requiresTwoSides, documentTemplateId, blockingCodes]);
131
130
  useEffect(function () {
132
131
  // While analysis is not finished, stay at step 0
133
132
  if (!isDone && !hasError) {