pipwave-ekyc-uikit 3.5.0 → 3.6.0-beta.1

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.
@@ -41,11 +41,15 @@
41
41
  "Bash(awk 'NR>=30 && NR<=42 {printf \"%d:[%s]\\\\n\", NR, $0}' a-sc-353927-web-sdk-facematch-selfie-fields.md)",
42
42
  "Bash(perl -0777 -i -pe 's{\\\\*\\\\*Signal-package adapter \\\\+ phase-1 geometry\\\\*\\\\*; delete face-api\\\\.js\\\\.}{**Signal-package adapter + phase-1 geometry**; delete face-api.js **and the `livenessScore` chain, incl. `StartSelfie.ts:137,142` \\(§3 item 5\\)**.}' plan-epic-342056-selfie-action-checking.md)",
43
43
  "Bash(perl -0777 -i -pe 's{outside this story\\\\.\\\\n\\\\n\\\\n# Acceptance Criteria}{outside this story.\\\\n\\\\n# Acceptance Criteria}' stories/a-sc-353927-web-sdk-facematch-selfie-fields.md)",
44
- "Bash(perl -0777 -ne 'print \" found\\\\n\" if /\\\\n\\\\n\\\\n/' stories/a-sc-353927-web-sdk-facematch-selfie-fields.md)"
44
+ "Bash(perl -0777 -ne 'print \" found\\\\n\" if /\\\\n\\\\n\\\\n/' stories/a-sc-353927-web-sdk-facematch-selfie-fields.md)",
45
+ "Bash(python3 -c ' *)",
46
+ "Bash(grep -rn 'export.*\\\\$t\\\\|const $t\\\\|function $t' src/)",
47
+ "Bash(node -e \"const p=require\\('./package.json'\\);console.log\\(p.name,p.version,'private:',p.private,'main:',p.main,'files:',JSON.stringify\\(p.files\\)\\)\")"
45
48
  ],
46
49
  "additionalDirectories": [
47
50
  "/Users/chechin/.claude/skills/rollout-ekyc-uikit",
48
- "/Users/chechin/Documents/2. pipwave Projects/pw-ekyc-web-ui /pw-ekyc-web-ui/docs"
51
+ "/Users/chechin/Documents/2. pipwave Projects/pw-ekyc-web-ui /pw-ekyc-web-ui/docs",
52
+ "/Users/chechin/.claude"
49
53
  ]
50
54
  }
51
55
  }
@@ -0,0 +1,88 @@
1
+ **Code review notes**
2
+
3
+ 18 findings from reviewing `2012a78` and `f647878`, grouped by urgency. Files covered: `card-camera.ts`, `VerifyId.ts`, `manualCapture.ts`, `manualCapture.test.ts`, `en.ts`.
4
+
5
+ ---
6
+
7
+ ### Must fix before merge
8
+
9
+ **1. One failed tap permanently locks the shutter** — `card-camera.ts:627-637`
10
+ `triggerManualCapture()` sets `hasAutoCaptured = true` and locks the button before awaiting `captureImage()`, with no try/catch. If the capture throws (for example iOS Safari after backgrounding, where the video reports width 0) the error disappears, the button stays locked, and manual mode has no other way to capture.
11
+ Fix: wrap it in try/catch. On error, reset the flag, unlock the button, and restore the hint.
12
+
13
+ ---
14
+
15
+ ### To confirm and resolve (no code change expected)
16
+
17
+ **2. The capture is still cropped to the card-ratio frame** — `card-camera.ts:111`, ratio from `src/constant/id.ts:27`
18
+ The overlay frame and `captureImage()` crop still use the credit-card ratio (1.586), so the UA booklet has to be fitted into a card-shaped frame. Understanding is this is expected: we cannot define a different ratio for every doc type per country/region, and since capture is manual, the user adjusts the document to fit the frame themselves. Please confirm and resolve.
19
+
20
+ **3. The flow still asks for a "back side" of the booklet** — `VerifyId.ts:282`, `idCardTypeMapping` says national ID has a back
21
+ After the front capture the user gets the "flip your card" step for a document with no card back. Nothing to change in this MR, since BE currently enforces submission of both sides. Reminder for the future: consider a BE-side change to make the back side optional for booklet-style documents, subject to business requirements. Please acknowledge and resolve.
22
+
23
+ ---
24
+
25
+ ### Recommended (worth doing in this MR)
26
+
27
+ **4. Tapping the shutter gives no feedback** — `src/plugins/card-camera.ts:627-637`
28
+ Auto capture shows the ring filling and a green tick; manual capture shows nothing until the loading screen. Users will assume the button is broken and tap again. This was a rare fallback before, but it is now the only path for UA. Suggest reusing `setRingProgress(1)` + `showCaptureTick()` in `triggerManualCapture`.
29
+
30
+ **5. Scanning brackets show while nothing is scanning** — `src/plugins/card-camera.ts:928`
31
+ The detector corner brackets still render in manual mode but never change colour, since no detection runs. It reads as "the app is scanning", so the user may wait instead of tapping. `disableDetection()` already exists and the face camera uses it for exactly this.
32
+
33
+ **6. The same hint ternary is copy-pasted in three places** — `card-camera.ts:402`, `:588`, `:798`
34
+ `$t(this.manualOnly ? "doc_manual_capture" : "doc_align_card")` appears in three methods. The next person resetting the hint will likely copy nearby code and write `$t("doc_align_card")`, telling UA users to "align your card" with no auto-capture running. One getter used at all three sites:
35
+
36
+ ```ts
37
+ private get idleHint(): string {
38
+ return $t(this.manualOnly ? "doc_manual_capture" : "doc_align_card");
39
+ }
40
+ ```
41
+
42
+ **7. Two separate lists will break when we add a second country** — `src/helper/manualCapture.ts:9-13`
43
+ The check is "country in list A AND doc type in list B". The real rule is per-country ("UA's national ID is a booklet"). If we later add a country whose passport is the booklet, adding `PASSPORT` to the shared list would silently enable manual capture for UA passports too, and the current test would not catch it. One map instead, same amount of code:
44
+
45
+ ```ts
46
+ const MANUAL_CAPTURE_DOCS: Record<string, readonly IdType[]> = {
47
+ UA: [ID_TYPE.NATIONAL_ID],
48
+ };
49
+ return (MANUAL_CAPTURE_DOCS[issuingCountry.toUpperCase()] ?? []).includes(idType);
50
+ ```
51
+
52
+ **8. Doc-type constants live in the wrong file** — `manualCapture.ts:9-13` vs `src/constant/id.ts:4`
53
+ Everything else describing "what a document type does" lives in `constant/id.ts` (`idCardTypeMapping`, `ID_TYPE`, `ID_CARD_RATIO`). These new tables sit in `helper/`, so someone adding a doc type will update `constant/id.ts` and never find this file. Suggest keeping `isManualCaptureOnly()` in `helper/` but moving the constant table next to `idCardTypeMapping`.
54
+
55
+ **9. `updateType` turns the shutter off just to turn it back on** — `card-camera.ts:552-570`
56
+ On a side flip in manual mode we call `disableManualCapture()` then `enableManualCapture()` a few lines later. The round trip only exists to get past the `dataset.manual` guard, and that dependency is invisible unless you read both methods. An early return would let the shutter stay active across the flip:
57
+
58
+ ```ts
59
+ if (this.manualOnly) {
60
+ this.cardType = cardType;
61
+ this.hasAutoCaptured = false;
62
+ updateTitle();
63
+ this.setHint(this.idleHint);
64
+ return;
65
+ }
66
+ ```
67
+
68
+ ---
69
+
70
+ ### Can wait (follow-up is fine)
71
+
72
+ **10.** `src/pageClass/VerifyId.ts:282` — if `defaultCountry` were ever empty, manual mode would silently skip and the upload would send an empty `issuing_country`. Not an issue today since country selection is enforced on the first page, but worth defensive handling if that enforcement is ever removed.
73
+
74
+ **11.** `card-camera.ts:797-798` — the `manualOnly` branch in `cancelHold()` only resets detector state that manual mode never sets, so it is dead code once finding 6's getter exists.
75
+
76
+ **12.** `VerifyId.ts:277`, `card-camera.ts:688`, `:558` — comments are long and sit in the wrong place. The "init() carries no model work" note is a fact about `card-detection.ts` and belongs on `CardDetection.init` itself (`card-detection.ts:303`).
77
+
78
+ **13.** `card-camera.ts:584-594` — the `dataset.manual` early return sits above the "scanner unavailable" dialog, so if anyone ever runs the detector in manual mode the Retry dialog would silently never show. Moving the dialog check up removes the trap.
79
+
80
+ **14.** `card-camera.ts:716`, `:531` — the `screen.orientation` listener is never removed, so every `CARDCAMERA` instance leaks after teardown along with its canvases (~7.7MB each). `_cleanup()` also does not detach `_manualClickHandler`. Pre-existing, but this MR's handler is now part of what gets retained.
81
+
82
+ **15.** `manualCapture.ts:9` — the country rule is hardcoded, unlike `excludedDocTypes` which comes from the backend token. The next booklet country will need a package release plus every merchant upgrading. Fine for a first version, worth raising with backend later.
83
+
84
+ **16.** `card-camera.ts:684`, `VerifyId.ts:282` — `manualOnly` is fixed for the life of the camera and `loadModel()` never runs in manual mode, so a future mid-session mode switch would report "scanner unavailable" on a healthy device. Loading the model inside `startDetection()` would keep it switchable.
85
+
86
+ **17.** `src/translations/index.ts:12` — `mapped[key] || ""` means a second locale added without `doc_manual_capture` renders an empty hint rather than falling back to English. No live impact while `en.ts` is the only locale.
87
+
88
+ **18.** *(addressed in `e97f4fd`)* `card-camera.ts:696` — shutter activation relies on event order: `#takePicButton` only exists when `loadedmetadata` runs because the video `resize` event (which builds the footer) happens to fire first. Verified that Chromium and WebKit both fire `resize` first, so this works today, but the spec does not guarantee the order. Also calling `enableManualCapture()` at the end of `renderCameraBottomUi()` when `manualOnly` is true (safe, it no-ops if already active) would make activation order-independent.