secure-ui-components 0.1.1 → 0.1.3

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 (48) hide show
  1. package/README.md +368 -38
  2. package/dist/components/secure-card/secure-card.css +427 -0
  3. package/dist/components/secure-card/secure-card.d.ts +73 -0
  4. package/dist/components/secure-card/secure-card.d.ts.map +1 -0
  5. package/dist/components/secure-card/secure-card.js +787 -0
  6. package/dist/components/secure-card/secure-card.js.map +1 -0
  7. package/dist/components/secure-datetime/secure-datetime.d.ts.map +1 -1
  8. package/dist/components/secure-datetime/secure-datetime.js +13 -22
  9. package/dist/components/secure-datetime/secure-datetime.js.map +1 -1
  10. package/dist/components/secure-file-upload/secure-file-upload.d.ts.map +1 -1
  11. package/dist/components/secure-file-upload/secure-file-upload.js +6 -17
  12. package/dist/components/secure-file-upload/secure-file-upload.js.map +1 -1
  13. package/dist/components/secure-form/secure-form.d.ts.map +1 -1
  14. package/dist/components/secure-form/secure-form.js +133 -16
  15. package/dist/components/secure-form/secure-form.js.map +1 -1
  16. package/dist/components/secure-input/secure-input.d.ts.map +1 -1
  17. package/dist/components/secure-input/secure-input.js +31 -26
  18. package/dist/components/secure-input/secure-input.js.map +1 -1
  19. package/dist/components/secure-select/secure-select.d.ts.map +1 -1
  20. package/dist/components/secure-select/secure-select.js +12 -20
  21. package/dist/components/secure-select/secure-select.js.map +1 -1
  22. package/dist/components/secure-submit-button/secure-submit-button.js +1 -1
  23. package/dist/components/secure-submit-button/secure-submit-button.js.map +1 -1
  24. package/dist/components/secure-table/secure-table.d.ts.map +1 -1
  25. package/dist/components/secure-table/secure-table.js +17 -16
  26. package/dist/components/secure-table/secure-table.js.map +1 -1
  27. package/dist/components/secure-telemetry-provider/secure-telemetry-provider.d.ts +63 -0
  28. package/dist/components/secure-telemetry-provider/secure-telemetry-provider.d.ts.map +1 -0
  29. package/dist/components/secure-telemetry-provider/secure-telemetry-provider.js +198 -0
  30. package/dist/components/secure-telemetry-provider/secure-telemetry-provider.js.map +1 -0
  31. package/dist/components/secure-textarea/secure-textarea.d.ts.map +1 -1
  32. package/dist/components/secure-textarea/secure-textarea.js +12 -20
  33. package/dist/components/secure-textarea/secure-textarea.js.map +1 -1
  34. package/dist/core/base-component.d.ts +23 -1
  35. package/dist/core/base-component.d.ts.map +1 -1
  36. package/dist/core/base-component.js +111 -0
  37. package/dist/core/base-component.js.map +1 -1
  38. package/dist/core/security-config.d.ts.map +1 -1
  39. package/dist/core/security-config.js +5 -21
  40. package/dist/core/security-config.js.map +1 -1
  41. package/dist/core/types.d.ts +129 -8
  42. package/dist/core/types.d.ts.map +1 -1
  43. package/dist/index.d.ts +3 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +2 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/package.json +4 -2
  48. package/package.json +13 -1
package/README.md CHANGED
@@ -1,19 +1,96 @@
1
1
  # secure-ui-components
2
2
 
3
- Security-first Web Component library with zero dependencies.
3
+ Security-first Web Component library with built-in behavioral telemetry. Zero dependencies.
4
4
 
5
5
  **[Live Demo](https://barryprender.github.io/Secure-UI/)** — Try all components in your browser.
6
6
 
7
7
  ## Features
8
8
 
9
- - **8 Secure Components** — Input, Textarea, Select, Form, File Upload, DateTime, Table, Submit Button
9
+ - **10 Secure Components** — Input, Textarea, Select, Form, File Upload, DateTime, Table, Submit Button, Card, Telemetry Provider
10
10
  - **4-Tier Security System** — `public`, `authenticated`, `sensitive`, `critical`
11
+ - **Behavioral Telemetry** — Every field collects typing patterns, paste detection, dwell time, and correction signals automatically
12
+ - **Risk Scoring** — `<secure-form>` aggregates field signals into a session-level risk score at submission
13
+ - **Signed Envelopes** — `<secure-telemetry-provider>` detects automation/headless browsers and signs every submission with HMAC-SHA-256
11
14
  - **Zero Dependencies** — Pure TypeScript, no runtime dependencies
12
15
  - **Progressive Enhancement** — All components render meaningful markup and work without JavaScript
13
16
  - **CSP-Safe** — Styles loaded via `<link>` from `'self'`; no `unsafe-inline` required
14
17
  - **SSR Friendly** — Adopts server-rendered markup on upgrade; no document access in constructors
15
18
  - **Fully Customisable** — CSS Design Tokens + `::part()` API
16
- - **Comprehensive Testing** — 689 tests, 80%+ branch coverage
19
+ - **Comprehensive Testing** — 869 tests, 80%+ branch coverage
20
+
21
+ ---
22
+
23
+ ## Philosophy: Security Telemetry as a First-Class Primitive
24
+
25
+ Traditional form security stops at validation and CSRF protection. Secure-UI goes further — every form submission carries a behavioral fingerprint that travels alongside the user's data, giving the server the context it needs to distinguish real users from bots and credential stuffers in a single atomic request.
26
+
27
+ ```
28
+ Field interaction → Behavioral signals → Risk score → Signed envelope
29
+ (SecureBaseComponent) (SecureForm) (SecureForm) (SecureTelemetryProvider)
30
+ ```
31
+
32
+ **Layer 1 — Field-level signals** (`SecureBaseComponent`)
33
+ Every secure field silently records: dwell time from focus to first keystroke, typing velocity, correction count (backspace/delete), paste detection, autofill detection, focus count, and blur-without-change patterns.
34
+
35
+ **Layer 2 — Session aggregation** (`<secure-form>`)
36
+ At submission, the form queries `getFieldTelemetry()` from every child field, produces per-field snapshots, and computes a composite risk score from 0–100. The telemetry payload travels alongside form data in a single `fetch` request as `_telemetry`.
37
+
38
+ **Layer 3 — Environmental signals** (`<secure-telemetry-provider>`)
39
+ An optional overlay that wraps `<secure-form>`. Monitors for WebDriver/headless flags, DOM script injection (via `MutationObserver`), devtools, suspicious screen dimensions, and pointer/keyboard activity. Signs the final envelope with HMAC-SHA-256 so the server can detect replay attacks.
40
+
41
+ **What the server receives (enhanced submission):**
42
+
43
+ ```json
44
+ {
45
+ "email": "user@example.com",
46
+ "password": "...",
47
+ "_telemetry": {
48
+ "sessionDuration": 14320,
49
+ "fieldCount": 2,
50
+ "riskScore": 5,
51
+ "riskSignals": [],
52
+ "submittedAt": "2026-03-12T18:30:00.000Z",
53
+ "fields": [
54
+ {
55
+ "fieldName": "email",
56
+ "fieldType": "secure-input",
57
+ "dwell": 420,
58
+ "completionTime": 3100,
59
+ "velocity": 4.2,
60
+ "corrections": 1,
61
+ "pasteDetected": false,
62
+ "autofillDetected": false,
63
+ "focusCount": 1,
64
+ "blurWithoutChange": 0
65
+ }
66
+ ],
67
+ "_env": {
68
+ "nonce": "a3f9...",
69
+ "issuedAt": "2026-03-12T18:30:00.000Z",
70
+ "environment": {
71
+ "webdriverDetected": false,
72
+ "headlessDetected": false,
73
+ "mouseMovementDetected": true,
74
+ "pointerType": "mouse"
75
+ },
76
+ "signature": "7d3a..."
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ **Risk signals**
83
+
84
+ | Signal | Condition | Score |
85
+ |--------|-----------|-------|
86
+ | `session_too_fast` | Submitted in under 3 s | +30 |
87
+ | `session_fast` | Submitted in under 8 s | +10 |
88
+ | `all_fields_pasted` | All fields pasted, no keystrokes | +25 |
89
+ | `field_filled_without_focus` | Any field has `focusCount = 0` | +15 |
90
+ | `high_velocity_typing` | Any field velocity > 15 ks/s | +15 |
91
+ | `form_probing` | Field focused/blurred > 1× with no input | +10 |
92
+ | `high_correction_count` | Any field with > 5 corrections | +5 |
93
+ | `autofill_detected` | All fields autofilled (trust signal) | −10 |
17
94
 
18
95
  ---
19
96
 
@@ -27,21 +104,32 @@ npm install secure-ui-components
27
104
 
28
105
  ## Quick Start
29
106
 
107
+ ### With telemetry (recommended)
108
+
109
+ ```html
110
+ <secure-telemetry-provider signing-key="your-per-session-secret">
111
+ <secure-form action="/api/login" method="POST" csrf-token="..." enhance>
112
+ <secure-input label="Email" name="email" type="email" required security-tier="authenticated"></secure-input>
113
+ <secure-input label="Password" name="password" type="password" required security-tier="critical"></secure-input>
114
+ <secure-submit-button label="Sign in" loading-label="Signing in…"></secure-submit-button>
115
+ </secure-form>
116
+ </secure-telemetry-provider>
117
+ ```
118
+
119
+ ```js
120
+ document.querySelector('secure-form').addEventListener('secure-form-submit', (e) => {
121
+ const { formData, telemetry } = e.detail;
122
+ console.log('Risk score:', telemetry.riskScore);
123
+ console.log('Risk signals:', telemetry.riskSignals);
124
+ });
125
+ ```
126
+
30
127
  ### Bundler (Vite, Webpack, Rollup)
31
128
 
32
129
  ```js
33
130
  import 'secure-ui-components/secure-input';
34
131
  import 'secure-ui-components/secure-form';
35
- ```
36
-
37
- ```html
38
- <secure-input
39
- label="Email"
40
- name="email"
41
- type="email"
42
- required
43
- security-tier="authenticated"
44
- ></secure-input>
132
+ import 'secure-ui-components/secure-telemetry-provider';
45
133
  ```
46
134
 
47
135
  ### CDN / Vanilla HTML
@@ -89,7 +177,7 @@ The `security-tier` attribute is **immutable after connection** — changes afte
89
177
 
90
178
  ### `<secure-input>`
91
179
 
92
- Text input with XSS prevention, masking, password strength validation, and rate limiting.
180
+ Text input with XSS prevention, masking, password strength validation, rate limiting, and automatic telemetry collection.
93
181
 
94
182
  **Attributes**
95
183
 
@@ -114,12 +202,13 @@ Text input with XSS prevention, masking, password strength validation, and rate
114
202
  ```js
115
203
  const el = document.querySelector('secure-input');
116
204
 
117
- el.value // get current value (unmasked)
118
- el.value = 'foo' // set value programmatically
119
- el.valid // boolean — passes all validation rules
120
- el.name // field name string
121
- el.getAuditLog() // array of audit log entries
205
+ el.value // get current value (unmasked)
206
+ el.value = 'foo' // set value programmatically
207
+ el.valid // boolean — passes all validation rules
208
+ el.name // field name string
209
+ el.getAuditLog() // AuditLogEntry[]
122
210
  el.clearAuditLog()
211
+ el.getFieldTelemetry() // FieldTelemetry — behavioral signals for this field
123
212
  el.focus()
124
213
  el.blur()
125
214
  ```
@@ -147,11 +236,11 @@ el.blur()
147
236
 
148
237
  ### `<secure-textarea>`
149
238
 
150
- Multi-line input with real-time character counter and rate limiting.
239
+ Multi-line input with real-time character counter, rate limiting, and automatic telemetry collection.
151
240
 
152
241
  **Attributes:** `label`, `name`, `placeholder`, `required`, `disabled`, `readonly`, `minlength`, `maxlength`, `rows`, `cols`, `wrap`, `value`, `security-tier`
153
242
 
154
- **Properties & Methods:** `value`, `name`, `valid`, `getAuditLog()`, `clearAuditLog()`, `focus()`, `blur()`
243
+ **Properties & Methods:** `value`, `name`, `valid`, `getAuditLog()`, `clearAuditLog()`, `getFieldTelemetry()`, `focus()`, `blur()`
155
244
 
156
245
  **Events:** `secure-textarea` → `{ name, value, tier }`
157
246
 
@@ -168,7 +257,7 @@ Multi-line input with real-time character counter and rate limiting.
168
257
 
169
258
  ### `<secure-select>`
170
259
 
171
- Dropdown with option whitelist validation — prevents value injection.
260
+ Dropdown with option whitelist validation — prevents value injection. Telemetry collected on `change` events.
172
261
 
173
262
  **Attributes:** `label`, `name`, `required`, `disabled`, `multiple`, `size`, `value`, `security-tier`
174
263
 
@@ -183,6 +272,7 @@ el.addOption(value, text, selected?)
183
272
  el.removeOption(value)
184
273
  el.clearOptions()
185
274
  el.getAuditLog()
275
+ el.getFieldTelemetry()
186
276
  el.focus()
187
277
  el.blur()
188
278
  ```
@@ -197,13 +287,13 @@ el.blur()
197
287
  </secure-select>
198
288
  ```
199
289
 
200
- Light DOM `<option>` children are transferred to the shadow DOM automatically. Only values added via `<option>` or `addOption()` are accepted — attempts to set an arbitrary value are rejected.
290
+ Light DOM `<option>` children are transferred to the shadow DOM automatically. Only values added via `<option>` or `addOption()` are accepted.
201
291
 
202
292
  ---
203
293
 
204
294
  ### `<secure-form>`
205
295
 
206
- Form container with CSRF protection, field validation, and optional fetch-enhanced submission.
296
+ Form container with CSRF protection, field validation, behavioral telemetry aggregation, and optional fetch-enhanced submission.
207
297
 
208
298
  > `<secure-form>` uses **light DOM** (no Shadow DOM) for native form submission compatibility.
209
299
 
@@ -228,20 +318,33 @@ el.valid // true if all secure child fields pass validation
228
318
  el.securityTier
229
319
  el.getData() // { fieldName: value, … } including CSRF token
230
320
  el.reset()
231
- el.submit() // programmatic submit (triggers validation)
321
+ el.submit() // programmatic submit (triggers validation + telemetry)
232
322
  ```
233
323
 
234
324
  **Events**
235
325
 
236
326
  | Event | Detail |
237
327
  |-------|--------|
238
- | `secure-form-submit` | `{ formData, formElement, preventDefault() }` — cancelable |
239
- | `secure-form-success` | `{ formData, response }` — only fired when `enhance` is set |
328
+ | `secure-form-submit` | `{ formData, formElement, telemetry, preventDefault() }` — cancelable |
329
+ | `secure-form-success` | `{ formData, response, telemetry }` — only when `enhance` is set |
330
+
331
+ **`telemetry` shape** (`SessionTelemetry`):
332
+
333
+ ```ts
334
+ {
335
+ sessionDuration: number; // ms from form mount to submission
336
+ fieldCount: number;
337
+ fields: FieldTelemetrySnapshot[];
338
+ riskScore: number; // 0–100
339
+ riskSignals: string[]; // e.g. ['session_too_fast', 'all_fields_pasted']
340
+ submittedAt: string; // ISO 8601
341
+ }
342
+ ```
240
343
 
241
344
  **Submission modes**
242
345
 
243
- - **Without `enhance`** — native browser form submission. Values from shadow DOM inputs are synced to hidden `<input type="hidden">` fields automatically.
244
- - **With `enhance`** — intercepts submit, validates all fields, sends JSON via `fetch`. Dispatches `secure-form-submit` (cancelable) then `secure-form-success` on success.
346
+ - **Without `enhance`** — native browser form submission. Values from shadow DOM inputs are synced to hidden `<input type="hidden">` fields automatically. Telemetry is available in `secure-form-submit` but not sent to the server.
347
+ - **With `enhance`** — intercepts submit, validates all fields, sends `{ ...formData, _telemetry }` as JSON via `fetch`. Full telemetry payload travels to the server in the same request.
245
348
 
246
349
  **Example**
247
350
 
@@ -253,6 +356,111 @@ el.submit() // programmatic submit (triggers validation)
253
356
  </secure-form>
254
357
  ```
255
358
 
359
+ ```js
360
+ form.addEventListener('secure-form-submit', (e) => {
361
+ const { formData, telemetry } = e.detail;
362
+
363
+ // Block high-risk submissions before they reach your server
364
+ if (telemetry.riskScore >= 50) {
365
+ e.detail.preventDefault();
366
+ showChallenge();
367
+ return;
368
+ }
369
+
370
+ // Log signals for your fraud pipeline
371
+ analytics.track('form_submit', {
372
+ risk: telemetry.riskScore,
373
+ signals: telemetry.riskSignals,
374
+ });
375
+ });
376
+ ```
377
+
378
+ ---
379
+
380
+ ### `<secure-telemetry-provider>`
381
+
382
+ Optional overlay that wraps `<secure-form>` to add environmental signals and HMAC-SHA-256 signing to every submission envelope.
383
+
384
+ > Place this as the outer wrapper. It monitors the entire document for automation markers and DOM tampering during the session.
385
+
386
+ **Attributes**
387
+
388
+ | Attribute | Description |
389
+ |-----------|-------------|
390
+ | `signing-key` | HMAC-SHA-256 key — must also be known server-side to verify the signature |
391
+
392
+ **Properties & Methods**
393
+
394
+ ```js
395
+ const provider = document.querySelector('secure-telemetry-provider');
396
+
397
+ provider.collectSignals() // EnvironmentalSignals — point-in-time snapshot
398
+ provider.getEnvironmentalSignals() // alias for collectSignals()
399
+ provider.sign(signals) // Promise<SignedTelemetryEnvelope>
400
+ ```
401
+
402
+ **What it detects**
403
+
404
+ | Signal | Description |
405
+ |--------|-------------|
406
+ | `webdriverDetected` | `navigator.webdriver` present or truthy |
407
+ | `headlessDetected` | `HeadlessChrome` in userAgent or missing `window.chrome` |
408
+ | `domMutationDetected` | New `<script>` element injected after page load |
409
+ | `injectedScriptCount` | Count of dynamically added `<script>` elements |
410
+ | `devtoolsOpen` | `outerWidth − innerWidth > 160` or `outerHeight − innerHeight > 160` |
411
+ | `suspiciousScreenSize` | Screen width or height is zero or < 100px |
412
+ | `pointerType` | Last pointer event type: `mouse` \| `touch` \| `pen` \| `none` |
413
+ | `mouseMovementDetected` | Any `mousemove` event fired during session |
414
+ | `keyboardActivityDetected` | Any `keydown` event fired during session |
415
+
416
+ **How the envelope is injected**
417
+
418
+ The provider listens for `secure-form-submit` on itself (bubbles from the nested form). It calls `sign()` asynchronously and attaches the result as `detail.telemetry._env`. Since it mutates the same object reference, any handler that awaits a microtask after the event fires will see `_env` populated.
419
+
420
+ **Signed envelope shape** (`SignedTelemetryEnvelope`):
421
+
422
+ ```ts
423
+ {
424
+ nonce: string; // 32-char random hex — detect replays
425
+ issuedAt: string; // ISO 8601
426
+ environment: EnvironmentalSignals;
427
+ signature: string; // HMAC-SHA-256 hex over nonce.issuedAt.JSON(environment)
428
+ }
429
+ ```
430
+
431
+ **Security notes**
432
+
433
+ - The `signing-key` is a *symmetric* secret. For strong guarantees, rotate it per-session via a server nonce endpoint rather than hardcoding it as an attribute.
434
+ - All signals are heuristic — a determined attacker can spoof them. The value is raising the cost of scripted attacks.
435
+ - In non-secure contexts (`http://`) `SubtleCrypto` is unavailable; the signature will be an empty string. The server should treat unsigned envelopes with reduced trust.
436
+
437
+ **Example**
438
+
439
+ ```html
440
+ <secure-telemetry-provider signing-key="per-session-server-issued-key">
441
+ <secure-form action="/api/login" enhance csrf-token="...">
442
+ <secure-input label="Email" name="email" type="email" required></secure-input>
443
+ <secure-input label="Password" name="password" type="password" required security-tier="critical"></secure-input>
444
+ <secure-submit-button label="Sign in"></secure-submit-button>
445
+ </secure-form>
446
+ </secure-telemetry-provider>
447
+ ```
448
+
449
+ ```js
450
+ document.querySelector('secure-form').addEventListener('secure-form-submit', async (e) => {
451
+ const { telemetry } = e.detail;
452
+
453
+ // _env is populated async by the provider — wait a microtask
454
+ await Promise.resolve();
455
+
456
+ if (telemetry._env) {
457
+ console.log('Nonce:', telemetry._env.nonce);
458
+ console.log('Signature:', telemetry._env.signature);
459
+ // Verify signature server-side with the same key
460
+ }
461
+ });
462
+ ```
463
+
256
464
  ---
257
465
 
258
466
  ### `<secure-file-upload>`
@@ -352,6 +560,7 @@ el.name
352
560
  el.getValueAsDate() // Date | null
353
561
  el.setValueFromDate(date) // accepts Date object, sets formatted value
354
562
  el.getAuditLog()
563
+ el.getFieldTelemetry()
355
564
  el.focus()
356
565
  el.blur()
357
566
  ```
@@ -425,6 +634,106 @@ table.columns = [
425
634
 
426
635
  ---
427
636
 
637
+ ### `<secure-card>`
638
+
639
+ Composite credit card form with a live 3D card preview, automatic card type detection, Luhn validation, expiry checking, and aggregate telemetry across all four fields. All inputs render inside a single closed Shadow DOM.
640
+
641
+ **Security model:**
642
+ - Full PAN and CVC are never included in events, audit logs, or hidden form inputs
643
+ - CVC uses native `type="password"` masking — never visible on screen
644
+ - Card number is masked to last-4 on blur
645
+ - Security tier is locked to `critical` and cannot be changed
646
+ - All sensitive state is wiped on `disconnectedCallback`
647
+ - Telemetry from all four inputs (number, expiry, CVC, name) is aggregated into one composite behavioral fingerprint
648
+
649
+ > Raw card data must be passed directly to a PCI-compliant payment processor SDK (e.g. Stripe.js, Braintree). Use `getCardData()` for that handoff — never send raw card numbers or CVCs to your own server.
650
+
651
+ **Attributes**
652
+
653
+ | Attribute | Type | Description |
654
+ |-----------|------|-------------|
655
+ | `label` | string | Legend text displayed above the fields |
656
+ | `name` | string | Base name for hidden form inputs |
657
+ | `show-name` | boolean | Show the optional cardholder name field |
658
+ | `disabled` | boolean | Disable all fields |
659
+ | `required` | boolean | Mark fields as required |
660
+
661
+ **Properties & Methods**
662
+
663
+ ```js
664
+ const card = document.querySelector('secure-card');
665
+
666
+ card.valid // true when all visible fields pass validation
667
+ card.cardType // 'visa' | 'mastercard' | 'amex' | 'discover' | 'diners' | 'jcb' | 'unknown'
668
+ card.last4 // last 4 digits — safe to display and log
669
+ card.name // value of the name attribute
670
+ card.getCardData() // { number, expiry, cvc, name } | null — for payment SDK only
671
+ card.getFieldTelemetry() // composite behavioral signals across all 4 card inputs
672
+ card.reset()
673
+ card.focus()
674
+ card.getAuditLog()
675
+ ```
676
+
677
+ **Events**
678
+
679
+ | Event | Detail |
680
+ |-------|--------|
681
+ | `secure-card` | `{ name, cardType, last4, expiryMonth, expiryYear, cardholderName, valid, tier }` |
682
+ | `secure-audit` | `{ event, tier, timestamp, … }` |
683
+
684
+ Note: the `secure-card` event detail intentionally omits the full PAN and CVC.
685
+
686
+ **CSS Parts**
687
+
688
+ | Part | Element |
689
+ |------|---------|
690
+ | `container` | Outer wrapper |
691
+ | `label` | Legend element |
692
+ | `wrapper` | Input wrapper (per field group) |
693
+ | `number-input` | Card number `<input>` |
694
+ | `expiry-input` | Expiry `<input>` |
695
+ | `cvc-input` | CVC `<input>` |
696
+ | `name-input` | Cardholder name `<input>` |
697
+ | `error` | Error message container (per field) |
698
+
699
+ **Card type detection**
700
+
701
+ | Type | Detected prefix |
702
+ |------|----------------|
703
+ | Visa | `4` |
704
+ | Mastercard | `51–55`, `2221–2720` |
705
+ | Amex | `34`, `37` |
706
+ | Discover | `6011`, `65xx` |
707
+ | Diners | `300–305`, `36`, `38` |
708
+ | JCB | `2131`, `1800`, `35xxx` |
709
+
710
+ **Form participation**
711
+
712
+ Three hidden inputs are created in the light DOM:
713
+ - `{name}` — last 4 digits only (not full PAN)
714
+ - `{name}-expiry` — MM/YY string
715
+ - `{name}-holder` — cardholder name
716
+
717
+ No hidden input is created for CVC.
718
+
719
+ **Example**
720
+
721
+ ```html
722
+ <secure-card name="payment" label="Card details" show-name></secure-card>
723
+ ```
724
+
725
+ ```js
726
+ // When the user clicks Pay — pass directly to your payment SDK
727
+ payButton.addEventListener('click', async () => {
728
+ const data = card.getCardData();
729
+ if (!data) return;
730
+ const token = await stripe.createToken({ number: data.number, exp_month: ..., cvc: data.cvc });
731
+ // Send token.id to your server — never data.number or data.cvc
732
+ });
733
+ ```
734
+
735
+ ---
736
+
428
737
  ### `<secure-submit-button>`
429
738
 
430
739
  Accessible submit button with loading state and automatic form-validity gating.
@@ -453,7 +762,7 @@ el.getAuditLog()
453
762
 
454
763
  ## Common Attributes
455
764
 
456
- All components support:
765
+ All field components support:
457
766
 
458
767
  | Attribute | Type | Description |
459
768
  |-----------|------|-------------|
@@ -466,17 +775,35 @@ All components support:
466
775
 
467
776
  ## Common Properties & Methods
468
777
 
778
+ All field components expose these in addition to component-specific methods:
779
+
469
780
  ```js
470
- el.value // get/set current value
471
- el.valid // boolean — passes all validation rules
472
- el.name // field name string
473
- el.securityTier // current security tier
474
- el.getAuditLog() // AuditLogEntry[]
781
+ el.value // get/set current value
782
+ el.valid // boolean — passes all validation rules
783
+ el.name // field name string
784
+ el.securityTier // current security tier
785
+ el.getAuditLog() // AuditLogEntry[]
475
786
  el.clearAuditLog()
787
+ el.getFieldTelemetry() // FieldTelemetry — behavioral signals (no raw values)
476
788
  el.focus()
477
789
  el.blur()
478
790
  ```
479
791
 
792
+ **`FieldTelemetry` shape:**
793
+
794
+ ```ts
795
+ {
796
+ dwell: number; // ms from focus to first keystroke
797
+ completionTime: number; // ms from first keystroke to blur
798
+ velocity: number; // keystrokes per second
799
+ corrections: number; // backspace / delete event count
800
+ pasteDetected: boolean;
801
+ autofillDetected: boolean;
802
+ focusCount: number;
803
+ blurWithoutChange: number; // focused but left without typing
804
+ }
805
+ ```
806
+
480
807
  ## Common Events
481
808
 
482
809
  | Event | Fired by | Detail |
@@ -486,8 +813,9 @@ el.blur()
486
813
  | `secure-select` | `<secure-select>` | `{ name, value, tier }` |
487
814
  | `secure-datetime` | `<secure-datetime>` | `{ name, value, type, tier }` |
488
815
  | `secure-file-upload` | `<secure-file-upload>` | `{ name, files, tier }` |
489
- | `secure-form-submit` | `<secure-form>` | `{ formData, formElement, preventDefault() }` |
490
- | `secure-form-success` | `<secure-form>` | `{ formData, response }` |
816
+ | `secure-form-submit` | `<secure-form>` | `{ formData, formElement, telemetry, preventDefault() }` |
817
+ | `secure-form-success` | `<secure-form>` | `{ formData, response, telemetry }` |
818
+ | `secure-card` | `<secure-card>` | `{ name, cardType, last4, expiryMonth, expiryYear, cardholderName, valid, tier }` |
491
819
  | `secure-audit` | all components | `{ event, tier, timestamp, … }` |
492
820
  | `table-action` | `<secure-table>` | `{ action, row }` |
493
821
 
@@ -527,7 +855,7 @@ secure-input::part(error) {
527
855
  }
528
856
  ```
529
857
 
530
- **Available parts on all components:** `container`, `label`, `wrapper`, `input` / `textarea` / `select`, `error`, `security-badge`
858
+ **Available parts on all components:** `container`, `label`, `wrapper`, `input` / `textarea` / `select`, `error`
531
859
 
532
860
  See the [Customization Guide](https://github.com/Barryprender/Secure-UI/blob/main/secure-ui-components/docs/customization.md) for a full token reference.
533
861
 
@@ -545,6 +873,8 @@ import 'secure-ui-components/secure-form';
545
873
  import 'secure-ui-components/secure-file-upload';
546
874
  import 'secure-ui-components/secure-datetime';
547
875
  import 'secure-ui-components/secure-table';
876
+ import 'secure-ui-components/secure-card';
877
+ import 'secure-ui-components/secure-telemetry-provider';
548
878
  ```
549
879
 
550
880
  Or import everything at once: