@trustchex/react-native-sdk 1.493.2 → 1.495.0

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.
@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
8
8
  import i18n from "../../Translation/index.js";
9
9
  import StyledButton from "./StyledButton.js";
10
10
  import { analyticsService } from "../Services/AnalyticsService.js";
11
+ import { diagnostics } from "../Libs/diagnostics.js";
11
12
 
12
13
  // Navigation lock - use a ref-like pattern so unmounting resets state.
13
14
  // The module-level object is shared across all instances but the
@@ -56,11 +57,22 @@ const NavigationManager = /*#__PURE__*/forwardRef(({
56
57
  }
57
58
  const currentStepIndex = workflowSteps?.findIndex(step => step.id ? step.id === currentWorkFlowStep?.id : step.type === currentWorkFlowStep?.type) ?? -1;
58
59
  const nextStep = workflowSteps && currentStepIndex < workflowSteps.length ? workflowSteps[currentStepIndex + 1] : null;
60
+
61
+ // Diagnostics: advancing past the current step means it completed. Record
62
+ // its outcome (success — the user moved on) and start-time the next step,
63
+ // so the report captures the WHOLE flow, not just the NFC read.
64
+ const now = Date.now();
65
+ if (currentWorkFlowStep?.type) {
66
+ diagnostics.stepEnded(currentWorkFlowStep.type, 'success', now);
67
+ }
59
68
  if (!nextStep) {
60
69
  appContext.currentWorkflowStep = undefined;
61
70
  return routes.RESULT;
62
71
  }
63
72
  appContext.currentWorkflowStep = nextStep;
73
+ if (nextStep.type) {
74
+ diagnostics.stepStarted(nextStep.type, now);
75
+ }
64
76
  if (nextStep.type === 'CONTRACT_ACCEPTANCE') {
65
77
  return routes.DYNAMIC_ROUTES.CONTRACT_ACCEPTANCE;
66
78
  }
@@ -114,6 +114,9 @@ export const buildDiagnosticReport = params => {
114
114
  buildNumber: device.buildNumber
115
115
  },
116
116
  device,
117
+ // Whole-flow, per-step record (contract → document → eID → liveness →
118
+ // consent → video). Diagnostics are NOT just the NFC read.
119
+ steps: diag.steps,
117
120
  scan: {
118
121
  documentType: scan.documentType ?? diag.documentType ?? null,
119
122
  dataSource: scan.dataSource ?? diag.dataSource ?? null,
@@ -145,7 +148,11 @@ export const buildDiagnosticReport = params => {
145
148
  const nfcCode = nfcErrorCode(nfc.errorCategory, failingSw);
146
149
  const nfcLine = nfc.attempted ? `${nfc.authProtocol}${nfc.paceFellBackToBac ? '→BAC' : ''} · ${nfc.succeeded ? 'success' : `failed at ${nfc.failureStep ?? '?'} (${nfc.errorCategory ?? 'error'}) [${nfcCode}]`}` : 'not attempted';
147
150
  const checksLine = checkDigits ? Object.entries(checkDigits).map(([k, v]) => `${k}:${v}`).join(' ') : 'n/a';
148
- const body = ['TRUSTCHEX SCAN REPORT', `Device: ${device.brand} ${device.model} · ${device.systemName} ${device.systemVersion}${device.apiLevel ? ` (API ${device.apiLevel})` : ''}`, `SDK: ${sdkVersion} (build ${device.buildNumber}) · ${device.manufacturer} · ${device.deviceId}`, `Document: ${scanDataObj.documentType ?? 'unknown'} · source: ${scanDataObj.dataSource ?? 'unknown'}`, `MRZ: ${diag.mrz.reachedStable ? 'stable' : 'NOT stable'} after ${diag.mrz.framesProcessed} frames · checks: ${checksLine}`, `Camera: ${diag.camera.frames} frames · brightness ${diag.camera.avgBrightness} (low:${yesNo(diag.camera.hadLowBrightness)} blur:${yesNo(diag.camera.hadBlurryFrames)})`, `NFC: ${nfcLine}`, sessionId ? `Session: ${sessionId}` : '', '', 'Describe the issue here:', '', '', '— Full diagnostics and document images are attached. Please review before sending; do not edit the attachments. —'].filter(Boolean).join('\n');
151
+
152
+ // Compact per-step line, e.g. "Steps: CONTRACT_ACCEPTANCE:success
153
+ // IDENTITY_DOCUMENT_SCAN:success LIVENESS_CHECK:failed".
154
+ const stepsLine = diag.steps.length ? diag.steps.map(s => `${s.step}:${s.outcome}`).join(' ') : 'none recorded';
155
+ const body = ['TRUSTCHEX SCAN REPORT', `Device: ${device.brand} ${device.model} · ${device.systemName} ${device.systemVersion}${device.apiLevel ? ` (API ${device.apiLevel})` : ''}`, `SDK: ${sdkVersion} (build ${device.buildNumber}) · ${device.manufacturer} · ${device.deviceId}`, `Document: ${scanDataObj.documentType ?? 'unknown'} · source: ${scanDataObj.dataSource ?? 'unknown'}`, `Steps: ${stepsLine}`, `MRZ: ${diag.mrz.reachedStable ? 'stable' : 'NOT stable'} after ${diag.mrz.framesProcessed} frames · checks: ${checksLine}`, `Camera: ${diag.camera.frames} frames · brightness ${diag.camera.avgBrightness} (low:${yesNo(diag.camera.hadLowBrightness)} blur:${yesNo(diag.camera.hadBlurryFrames)})`, `NFC: ${nfcLine}`, sessionId ? `Session: ${sessionId}` : '', '', 'Describe the issue here:', '', '', '— Full diagnostics and document images are attached. Please review before sending; do not edit the attachments. —'].filter(Boolean).join('\n');
149
156
  const subject = `Trustchex scan report — ${scanDataObj.documentType ?? 'doc'} — ${device.brand} ${device.model} — v${sdkVersion}${sessionId ? ` — ${sessionId}` : ''}`;
150
157
  return {
151
158
  diagnosticsJson: JSON.stringify(diagnosticsObj, null, 2),
@@ -21,6 +21,14 @@
21
21
 
22
22
  /** A single step of the NFC/eID read, with its outcome and timing. */
23
23
 
24
+ /**
25
+ * A single workflow step's outcome. Diagnostics are NOT just about NFC — every
26
+ * step of the verification flow (contract, document scan, eID, liveness, verbal
27
+ * consent, video call) records one of these so a support/AI reader sees the
28
+ * whole journey: what ran, how long it took, whether it succeeded, and a small
29
+ * non-PII `details` bag specific to the step.
30
+ */
31
+
24
32
  const emptyCamera = () => ({
25
33
  frames: 0,
26
34
  frameW: 0,
@@ -58,9 +66,28 @@ export class DiagnosticsCollector {
58
66
  mrz = emptyMrz();
59
67
  nfc = emptyNfc();
60
68
  errors = [];
69
+ steps = [];
70
+ // Open steps keyed by step name → start time, for duration on stepEnded.
71
+ openSteps = new Map();
61
72
 
62
- /** Begin a fresh session — call when a scan flow starts. */
73
+ /**
74
+ * Reset the per-SCAN signals (camera/MRZ/NFC) — called when a scan flow
75
+ * starts. Deliberately PRESERVES the workflow `steps` log and accumulated
76
+ * errors: those span the whole verification journey (contract → … → result),
77
+ * and a scan starting mid-flow must not erase steps already completed. Use
78
+ * `resetSession` to clear everything for a brand-new session.
79
+ */
63
80
  reset(nowMs) {
81
+ if (!this.startedAtMs) this.startedAtMs = nowMs;
82
+ this.documentType = undefined;
83
+ this.dataSource = undefined;
84
+ this.camera = emptyCamera();
85
+ this.mrz = emptyMrz();
86
+ this.nfc = emptyNfc();
87
+ }
88
+
89
+ /** Clear the ENTIRE session (steps, errors, timings) — new verification. */
90
+ resetSession(nowMs) {
64
91
  this.startedAtMs = nowMs;
65
92
  this.documentType = undefined;
66
93
  this.dataSource = undefined;
@@ -68,12 +95,38 @@ export class DiagnosticsCollector {
68
95
  this.mrz = emptyMrz();
69
96
  this.nfc = emptyNfc();
70
97
  this.errors = [];
98
+ this.steps = [];
99
+ this.openSteps.clear();
71
100
  }
72
101
  setDocument(documentType, dataSource) {
73
102
  if (documentType) this.documentType = documentType;
74
103
  if (dataSource) this.dataSource = dataSource;
75
104
  }
76
105
 
106
+ // ---- Workflow steps (whole-flow, not just NFC) ----
107
+
108
+ /** Mark a workflow step as started (records start time for duration). */
109
+ stepStarted(step, nowMs) {
110
+ this.openSteps.set(step, nowMs);
111
+ }
112
+
113
+ /**
114
+ * Record a step's outcome. Pairs with `stepStarted` for duration; if the step
115
+ * was never started, durationMs is 0. `details` is a small non-PII bag of
116
+ * step-specific signals (counts, flags, retries).
117
+ */
118
+ stepEnded(step, outcome, nowMs, details) {
119
+ const startedAt = this.openSteps.get(step);
120
+ this.openSteps.delete(step);
121
+ this.steps.push({
122
+ step,
123
+ outcome,
124
+ // `startedAt` can legitimately be 0 (session t0), so check for undefined.
125
+ durationMs: startedAt !== undefined ? Math.max(0, nowMs - startedAt) : 0,
126
+ details: details && Object.keys(details).length ? details : undefined
127
+ });
128
+ }
129
+
77
130
  /** Merge a camera snapshot (called periodically as frames arrive). */
78
131
  setCamera(c) {
79
132
  this.camera = {
@@ -165,11 +218,17 @@ export class DiagnosticsCollector {
165
218
  /** Build the serialisable snapshot. */
166
219
  snapshot(nowMs, isoNow) {
167
220
  return {
168
- schemaVersion: 1,
221
+ schemaVersion: 2,
169
222
  generatedAt: isoNow,
170
223
  documentType: this.documentType,
171
224
  dataSource: this.dataSource,
172
225
  totalDurationMs: this.startedAtMs ? Math.max(0, nowMs - this.startedAtMs) : 0,
226
+ steps: this.steps.map(s => ({
227
+ ...s,
228
+ details: s.details ? {
229
+ ...s.details
230
+ } : undefined
231
+ })),
173
232
  camera: {
174
233
  ...this.camera
175
234
  },
@@ -2,4 +2,4 @@
2
2
 
3
3
  // This file is auto-generated. Do not edit manually.
4
4
  // Version is synced from package.json during build.
5
- export const SDK_VERSION = '1.493.2';
5
+ export const SDK_VERSION = '1.495.0';
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationManager.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/NavigationManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAKN,MAAM,OAAO,CAAC;AAmBf,MAAM,MAAM,oBAAoB,GAAG;IACjC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,QAAA,MAAM,iBAAiB,wFAyPtB,CAAC;AAaF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"NavigationManager.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/NavigationManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAKN,MAAM,OAAO,CAAC;AAoBf,MAAM,MAAM,oBAAoB,GAAG;IACjC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,QAAA,MAAM,iBAAiB,wFAoQtB,CAAC;AAaF,eAAe,iBAAiB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"diagnosticReport.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/diagnosticReport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AA2CpD,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6EAA6E;IAC7E,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAyDD,MAAM,WAAW,sBAAsB;IACrC,uCAAuC;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,GAAI,QAAQ;IAC5C,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,KAAG,sBAuFH,CAAC"}
1
+ {"version":3,"file":"diagnosticReport.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/diagnosticReport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AA2CpD,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6EAA6E;IAC7E,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAyDD,MAAM,WAAW,sBAAsB;IACrC,uCAAuC;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,GAAI,QAAQ;IAC5C,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,KAAG,sBAyGH,CAAC"}
@@ -90,12 +90,32 @@ export interface MrzDiagnostics {
90
90
  * to accept the document number (set at report-build time from the final MRZ). */
91
91
  turkishLetterPrefixApplied: boolean;
92
92
  }
93
+ /**
94
+ * A single workflow step's outcome. Diagnostics are NOT just about NFC — every
95
+ * step of the verification flow (contract, document scan, eID, liveness, verbal
96
+ * consent, video call) records one of these so a support/AI reader sees the
97
+ * whole journey: what ran, how long it took, whether it succeeded, and a small
98
+ * non-PII `details` bag specific to the step.
99
+ */
100
+ export interface WorkflowStepRecord {
101
+ /** Step type, e.g. 'CONTRACT_ACCEPTANCE' | 'IDENTITY_DOCUMENT_SCAN' |
102
+ * 'IDENTITY_DOCUMENT_EID_SCAN' | 'LIVENESS_CHECK' | 'VERBAL_CONSENT' |
103
+ * 'VIDEO_CALL'. */
104
+ step: string;
105
+ /** 'success' | 'failed' | 'skipped' | 'cancelled' | 'started' (still running). */
106
+ outcome: 'success' | 'failed' | 'skipped' | 'cancelled' | 'started';
107
+ durationMs: number;
108
+ /** Coarse, non-PII per-step signals (counts, flags, retries — never PII). */
109
+ details?: Record<string, string | number | boolean | null>;
110
+ }
93
111
  export interface DiagnosticsSnapshot {
94
112
  schemaVersion: number;
95
113
  generatedAt: string;
96
114
  documentType?: string;
97
115
  dataSource?: string;
98
116
  totalDurationMs: number;
117
+ /** Per-step record of the WHOLE flow, in the order steps started. */
118
+ steps: WorkflowStepRecord[];
99
119
  camera: CameraDiagnostics;
100
120
  mrz: MrzDiagnostics;
101
121
  nfc: NfcDiagnostics;
@@ -118,9 +138,27 @@ export declare class DiagnosticsCollector {
118
138
  private mrz;
119
139
  private nfc;
120
140
  private errors;
121
- /** Begin a fresh session — call when a scan flow starts. */
141
+ private steps;
142
+ private openSteps;
143
+ /**
144
+ * Reset the per-SCAN signals (camera/MRZ/NFC) — called when a scan flow
145
+ * starts. Deliberately PRESERVES the workflow `steps` log and accumulated
146
+ * errors: those span the whole verification journey (contract → … → result),
147
+ * and a scan starting mid-flow must not erase steps already completed. Use
148
+ * `resetSession` to clear everything for a brand-new session.
149
+ */
122
150
  reset(nowMs: number): void;
151
+ /** Clear the ENTIRE session (steps, errors, timings) — new verification. */
152
+ resetSession(nowMs: number): void;
123
153
  setDocument(documentType?: string, dataSource?: string): void;
154
+ /** Mark a workflow step as started (records start time for duration). */
155
+ stepStarted(step: string, nowMs: number): void;
156
+ /**
157
+ * Record a step's outcome. Pairs with `stepStarted` for duration; if the step
158
+ * was never started, durationMs is 0. `details` is a small non-PII bag of
159
+ * step-specific signals (counts, flags, retries).
160
+ */
161
+ stepEnded(step: string, outcome: WorkflowStepRecord['outcome'], nowMs: number, details?: WorkflowStepRecord['details']): void;
124
162
  /** Merge a camera snapshot (called periodically as frames arrive). */
125
163
  setCamera(c: Partial<CameraDiagnostics>): void;
126
164
  /** Merge MRZ consensus metrics. `reachedStable` is STICKY (once true, stays
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/diagnostics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Libs/diagnostics.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const SDK_VERSION = "1.493.2";
1
+ export declare const SDK_VERSION = "1.495.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trustchex/react-native-sdk",
3
- "version": "1.493.2",
3
+ "version": "1.495.0",
4
4
  "description": "Trustchex mobile app react native SDK for android or ios devices",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -16,6 +16,7 @@ import { useTranslation } from 'react-i18next';
16
16
  import i18n from '../../Translation';
17
17
  import StyledButton from './StyledButton';
18
18
  import { analyticsService } from '../Services/AnalyticsService';
19
+ import { diagnostics } from '../Libs/diagnostics';
19
20
 
20
21
  // Navigation lock - use a ref-like pattern so unmounting resets state.
21
22
  // The module-level object is shared across all instances but the
@@ -87,12 +88,23 @@ const NavigationManager = forwardRef(
87
88
  ? workflowSteps[currentStepIndex + 1]
88
89
  : null;
89
90
 
91
+ // Diagnostics: advancing past the current step means it completed. Record
92
+ // its outcome (success — the user moved on) and start-time the next step,
93
+ // so the report captures the WHOLE flow, not just the NFC read.
94
+ const now = Date.now();
95
+ if (currentWorkFlowStep?.type) {
96
+ diagnostics.stepEnded(currentWorkFlowStep.type, 'success', now);
97
+ }
98
+
90
99
  if (!nextStep) {
91
100
  appContext.currentWorkflowStep = undefined;
92
101
  return routes.RESULT;
93
102
  }
94
103
 
95
104
  appContext.currentWorkflowStep = nextStep;
105
+ if (nextStep.type) {
106
+ diagnostics.stepStarted(nextStep.type, now);
107
+ }
96
108
 
97
109
  if (nextStep.type === 'CONTRACT_ACCEPTANCE') {
98
110
  return routes.DYNAMIC_ROUTES.CONTRACT_ACCEPTANCE;
@@ -155,15 +155,23 @@ export const buildDiagnosticReport = (params: {
155
155
  // Set the Turkish-letter-prefix flag from the final accepted MRZ (the collector
156
156
  // can't know it during scanning; the report does, from the MRZ text).
157
157
  const turkishLetterPrefixApplied =
158
- diag.mrz.turkishLetterPrefixApplied || computed?.turkishLetterPrefix === true;
158
+ diag.mrz.turkishLetterPrefixApplied ||
159
+ computed?.turkishLetterPrefix === true;
159
160
 
160
161
  // --- diagnostics.json (technical, low-PII) ---
161
162
  const diagnosticsObj = {
162
163
  schemaVersion: diag.schemaVersion,
163
164
  generatedAt: diag.generatedAt,
164
165
  sessionId: sessionId ?? null,
165
- sdk: { platform: device.platform, sdkVersion, buildNumber: device.buildNumber },
166
+ sdk: {
167
+ platform: device.platform,
168
+ sdkVersion,
169
+ buildNumber: device.buildNumber,
170
+ },
166
171
  device,
172
+ // Whole-flow, per-step record (contract → document → eID → liveness →
173
+ // consent → video). Diagnostics are NOT just the NFC read.
174
+ steps: diag.steps,
167
175
  scan: {
168
176
  documentType: scan.documentType ?? diag.documentType ?? null,
169
177
  dataSource: scan.dataSource ?? diag.dataSource ?? null,
@@ -208,11 +216,18 @@ export const buildDiagnosticReport = (params: {
208
216
  .join(' ')
209
217
  : 'n/a';
210
218
 
219
+ // Compact per-step line, e.g. "Steps: CONTRACT_ACCEPTANCE:success
220
+ // IDENTITY_DOCUMENT_SCAN:success LIVENESS_CHECK:failed".
221
+ const stepsLine = diag.steps.length
222
+ ? diag.steps.map((s) => `${s.step}:${s.outcome}`).join(' ')
223
+ : 'none recorded';
224
+
211
225
  const body = [
212
226
  'TRUSTCHEX SCAN REPORT',
213
227
  `Device: ${device.brand} ${device.model} · ${device.systemName} ${device.systemVersion}${device.apiLevel ? ` (API ${device.apiLevel})` : ''}`,
214
228
  `SDK: ${sdkVersion} (build ${device.buildNumber}) · ${device.manufacturer} · ${device.deviceId}`,
215
229
  `Document: ${scanDataObj.documentType ?? 'unknown'} · source: ${scanDataObj.dataSource ?? 'unknown'}`,
230
+ `Steps: ${stepsLine}`,
216
231
  `MRZ: ${diag.mrz.reachedStable ? 'stable' : 'NOT stable'} after ${diag.mrz.framesProcessed} frames · checks: ${checksLine}`,
217
232
  `Camera: ${diag.camera.frames} frames · brightness ${diag.camera.avgBrightness} (low:${yesNo(diag.camera.hadLowBrightness)} blur:${yesNo(diag.camera.hadBlurryFrames)})`,
218
233
  `NFC: ${nfcLine}`,
@@ -231,7 +246,10 @@ export const buildDiagnosticReport = (params: {
231
246
  return {
232
247
  diagnosticsJson: JSON.stringify(diagnosticsObj, null, 2),
233
248
  scanDataJson: JSON.stringify(scanDataObj, null, 2),
234
- body: body.length > MAX_BODY_BYTES ? body.slice(0, MAX_BODY_BYTES - 1) + '…' : body,
249
+ body:
250
+ body.length > MAX_BODY_BYTES
251
+ ? body.slice(0, MAX_BODY_BYTES - 1) + '…'
252
+ : body,
235
253
  subject,
236
254
  };
237
255
  };
@@ -95,12 +95,33 @@ export interface MrzDiagnostics {
95
95
  turkishLetterPrefixApplied: boolean;
96
96
  }
97
97
 
98
+ /**
99
+ * A single workflow step's outcome. Diagnostics are NOT just about NFC — every
100
+ * step of the verification flow (contract, document scan, eID, liveness, verbal
101
+ * consent, video call) records one of these so a support/AI reader sees the
102
+ * whole journey: what ran, how long it took, whether it succeeded, and a small
103
+ * non-PII `details` bag specific to the step.
104
+ */
105
+ export interface WorkflowStepRecord {
106
+ /** Step type, e.g. 'CONTRACT_ACCEPTANCE' | 'IDENTITY_DOCUMENT_SCAN' |
107
+ * 'IDENTITY_DOCUMENT_EID_SCAN' | 'LIVENESS_CHECK' | 'VERBAL_CONSENT' |
108
+ * 'VIDEO_CALL'. */
109
+ step: string;
110
+ /** 'success' | 'failed' | 'skipped' | 'cancelled' | 'started' (still running). */
111
+ outcome: 'success' | 'failed' | 'skipped' | 'cancelled' | 'started';
112
+ durationMs: number;
113
+ /** Coarse, non-PII per-step signals (counts, flags, retries — never PII). */
114
+ details?: Record<string, string | number | boolean | null>;
115
+ }
116
+
98
117
  export interface DiagnosticsSnapshot {
99
118
  schemaVersion: number;
100
119
  generatedAt: string;
101
120
  documentType?: string;
102
121
  dataSource?: string;
103
122
  totalDurationMs: number;
123
+ /** Per-step record of the WHOLE flow, in the order steps started. */
124
+ steps: WorkflowStepRecord[];
104
125
  camera: CameraDiagnostics;
105
126
  mrz: MrzDiagnostics;
106
127
  nfc: NfcDiagnostics;
@@ -149,9 +170,28 @@ export class DiagnosticsCollector {
149
170
  private mrz = emptyMrz();
150
171
  private nfc = emptyNfc();
151
172
  private errors: DiagnosticsSnapshot['errors'] = [];
173
+ private steps: WorkflowStepRecord[] = [];
174
+ // Open steps keyed by step name → start time, for duration on stepEnded.
175
+ private openSteps = new Map<string, number>();
152
176
 
153
- /** Begin a fresh session — call when a scan flow starts. */
177
+ /**
178
+ * Reset the per-SCAN signals (camera/MRZ/NFC) — called when a scan flow
179
+ * starts. Deliberately PRESERVES the workflow `steps` log and accumulated
180
+ * errors: those span the whole verification journey (contract → … → result),
181
+ * and a scan starting mid-flow must not erase steps already completed. Use
182
+ * `resetSession` to clear everything for a brand-new session.
183
+ */
154
184
  reset(nowMs: number): void {
185
+ if (!this.startedAtMs) this.startedAtMs = nowMs;
186
+ this.documentType = undefined;
187
+ this.dataSource = undefined;
188
+ this.camera = emptyCamera();
189
+ this.mrz = emptyMrz();
190
+ this.nfc = emptyNfc();
191
+ }
192
+
193
+ /** Clear the ENTIRE session (steps, errors, timings) — new verification. */
194
+ resetSession(nowMs: number): void {
155
195
  this.startedAtMs = nowMs;
156
196
  this.documentType = undefined;
157
197
  this.dataSource = undefined;
@@ -159,6 +199,8 @@ export class DiagnosticsCollector {
159
199
  this.mrz = emptyMrz();
160
200
  this.nfc = emptyNfc();
161
201
  this.errors = [];
202
+ this.steps = [];
203
+ this.openSteps.clear();
162
204
  }
163
205
 
164
206
  setDocument(documentType?: string, dataSource?: string): void {
@@ -166,6 +208,35 @@ export class DiagnosticsCollector {
166
208
  if (dataSource) this.dataSource = dataSource;
167
209
  }
168
210
 
211
+ // ---- Workflow steps (whole-flow, not just NFC) ----
212
+
213
+ /** Mark a workflow step as started (records start time for duration). */
214
+ stepStarted(step: string, nowMs: number): void {
215
+ this.openSteps.set(step, nowMs);
216
+ }
217
+
218
+ /**
219
+ * Record a step's outcome. Pairs with `stepStarted` for duration; if the step
220
+ * was never started, durationMs is 0. `details` is a small non-PII bag of
221
+ * step-specific signals (counts, flags, retries).
222
+ */
223
+ stepEnded(
224
+ step: string,
225
+ outcome: WorkflowStepRecord['outcome'],
226
+ nowMs: number,
227
+ details?: WorkflowStepRecord['details']
228
+ ): void {
229
+ const startedAt = this.openSteps.get(step);
230
+ this.openSteps.delete(step);
231
+ this.steps.push({
232
+ step,
233
+ outcome,
234
+ // `startedAt` can legitimately be 0 (session t0), so check for undefined.
235
+ durationMs: startedAt !== undefined ? Math.max(0, nowMs - startedAt) : 0,
236
+ details: details && Object.keys(details).length ? details : undefined,
237
+ });
238
+ }
239
+
169
240
  /** Merge a camera snapshot (called periodically as frames arrive). */
170
241
  setCamera(c: Partial<CameraDiagnostics>): void {
171
242
  this.camera = { ...this.camera, ...c };
@@ -256,13 +327,17 @@ export class DiagnosticsCollector {
256
327
  /** Build the serialisable snapshot. */
257
328
  snapshot(nowMs: number, isoNow: string): DiagnosticsSnapshot {
258
329
  return {
259
- schemaVersion: 1,
330
+ schemaVersion: 2,
260
331
  generatedAt: isoNow,
261
332
  documentType: this.documentType,
262
333
  dataSource: this.dataSource,
263
334
  totalDurationMs: this.startedAtMs
264
335
  ? Math.max(0, nowMs - this.startedAtMs)
265
336
  : 0,
337
+ steps: this.steps.map((s) => ({
338
+ ...s,
339
+ details: s.details ? { ...s.details } : undefined,
340
+ })),
266
341
  camera: { ...this.camera },
267
342
  mrz: { ...this.mrz },
268
343
  nfc: { ...this.nfc, steps: this.nfc.steps.map((s) => ({ ...s })) },
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
2
  // Version is synced from package.json during build.
3
- export const SDK_VERSION = '1.493.2';
3
+ export const SDK_VERSION = '1.495.0';