@burnt-labs/expo-satya-attest 3.9.0 → 3.10.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +25 -4
  2. package/PUBLISHING.md +17 -12
  3. package/README.md +8 -3
  4. package/TEELS_OBSERVABILITY.md +128 -0
  5. package/android/build.gradle +2 -2
  6. package/build/components/providerAttest/copy.d.ts.map +1 -1
  7. package/build/components/providerAttest/copy.js +5 -0
  8. package/build/components/providerAttest/copy.js.map +1 -1
  9. package/build/components/providerAttest/teels/teelsFailure.d.ts +2 -0
  10. package/build/components/providerAttest/teels/teelsFailure.d.ts.map +1 -1
  11. package/build/components/providerAttest/teels/teelsFailure.js +31 -5
  12. package/build/components/providerAttest/teels/teelsFailure.js.map +1 -1
  13. package/build/components/providerAttest/teels/teelsProtocol.d.ts +5 -0
  14. package/build/components/providerAttest/teels/teelsProtocol.d.ts.map +1 -1
  15. package/build/components/providerAttest/teels/teelsProtocol.js +42 -14
  16. package/build/components/providerAttest/teels/teelsProtocol.js.map +1 -1
  17. package/build/components/providerAttest/teels/useTeelsProviderFlow.d.ts.map +1 -1
  18. package/build/components/providerAttest/teels/useTeelsProviderFlow.js +63 -21
  19. package/build/components/providerAttest/teels/useTeelsProviderFlow.js.map +1 -1
  20. package/build/components/providerAttest/useFunnelEmitter.d.ts +1 -1
  21. package/build/components/providerAttest/useFunnelEmitter.d.ts.map +1 -1
  22. package/build/components/providerAttest/useFunnelEmitter.js +40 -5
  23. package/build/components/providerAttest/useFunnelEmitter.js.map +1 -1
  24. package/build/sdkEventLog.d.ts +12 -0
  25. package/build/sdkEventLog.d.ts.map +1 -1
  26. package/build/sdkEventLog.js +42 -4
  27. package/build/sdkEventLog.js.map +1 -1
  28. package/build/sdkMetadata.generated.d.ts +1 -1
  29. package/build/sdkMetadata.generated.d.ts.map +1 -1
  30. package/build/sdkMetadata.generated.js +1 -1
  31. package/build/sdkMetadata.generated.js.map +1 -1
  32. package/build/sdkTelemetry.d.ts +6 -0
  33. package/build/sdkTelemetry.d.ts.map +1 -0
  34. package/build/sdkTelemetry.js +32 -0
  35. package/build/sdkTelemetry.js.map +1 -0
  36. package/build/tee/client.d.ts +1 -1
  37. package/build/tee/client.d.ts.map +1 -1
  38. package/build/teelsStageHistory.d.ts +8 -0
  39. package/build/teelsStageHistory.d.ts.map +1 -0
  40. package/build/teelsStageHistory.js +30 -0
  41. package/build/teelsStageHistory.js.map +1 -0
  42. package/build/teelsTelemetry.d.ts +98 -0
  43. package/build/teelsTelemetry.d.ts.map +1 -0
  44. package/build/teelsTelemetry.js +147 -0
  45. package/build/teelsTelemetry.js.map +1 -0
  46. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/libsatya_ffi.a +1 -1
  47. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64_x86_64-simulator/libsatya_ffi.a +1 -1
  48. package/ios/SatyaAttest.podspec +1 -1
  49. package/package.json +3 -2
  50. package/src/components/providerAttest/copy.ts +4 -0
  51. package/src/components/providerAttest/teels/teelsFailure.ts +36 -5
  52. package/src/components/providerAttest/teels/teelsProtocol.ts +59 -14
  53. package/src/components/providerAttest/teels/useTeelsProviderFlow.ts +74 -24
  54. package/src/components/providerAttest/useFunnelEmitter.ts +45 -5
  55. package/src/sdkEventLog.ts +54 -4
  56. package/src/sdkMetadata.generated.ts +1 -1
  57. package/src/sdkTelemetry.ts +35 -0
  58. package/src/teelsStageHistory.ts +39 -0
  59. package/src/teelsTelemetry.ts +158 -0
package/CHANGELOG.md CHANGED
@@ -1,9 +1,30 @@
1
1
  # Changelog
2
2
 
3
- ## 3.9.0 - 2026-09-17
3
+ ## 3.10.0 - 2026-09-22
4
+
5
+ - Keep monitoring ingestion unchanged: SDK-owned versioned `logData` metadata lets Devtool classify warnings and completion without new event types, service deployments, or database migrations.
6
+
7
+ Release candidate; npm publication is required after review and release validation.
8
+
9
+ ### Added
4
10
 
5
- Release preparation; publication and completion of the native/device validation
6
- matrix are still pending.
11
+ - TeeLS stage history in existing event logData, safe structured error causes and recovery guidance through
12
+ the hosted adapter, SDK callbacks and event ingestion. Wrong credentials,
13
+ declined challenges and cancellations are unsuccessful warning outcomes.
14
+ - Existing `ATTESTATION_GENERATED` records hosted artifact receipt with
15
+ `flowOutcome: completed`, separately from independent `ATTESTATION_VERIFIED`.
16
+ The seven event types remain unchanged. Shared telemetry identifies flow type, schema
17
+ version, event sequence and elapsed attempt time. See
18
+ [TeeLS observability](./TEELS_OBSERVABILITY.md) for rollout sequencing and
19
+ required hosted Provider Registry injection updates.
20
+
21
+ ### Fixed
22
+
23
+ - Hosted TeeLS consent dismissal ("Not now") records a cancellation warning
24
+ immediately instead of timing out. Modal teardown from success/error callbacks
25
+ preserves the original result without duplicate terminal events.
26
+
27
+ ## 3.9.0 - 2026-09-17
7
28
 
8
29
  ### Added
9
30
 
@@ -54,7 +75,7 @@ matrix are still pending.
54
75
  cleared. Keep `isolation: 'provider'` when turning automatic reset off.
55
76
  - Reset removes cookies, including persistent/HttpOnly cookies, but leaves local
56
77
  storage and caches intact. External-browser and remote hosted TeeLS sessions
57
- are outside its scope. See [release gates](./PUBLISHING.md#provider-session-release-preparation).
78
+ are outside its scope. See [release gates](./PUBLISHING.md#release-preparation).
58
79
 
59
80
  ## 3.8.0 - 2026-09-14
60
81
 
package/PUBLISHING.md CHANGED
@@ -10,12 +10,17 @@ very large native artifacts. The npm tarball still needs the native artifacts un
10
10
  package is redesigned to download or build them during install, which is not recommended
11
11
  for a plug-and-play Expo SDK.
12
12
 
13
- ## Provider-session release preparation
14
-
15
- The next prepared minor release is **3.9.0**. It adds provider-isolated cookie
16
- stores and the public `clearProviderCookies` API. A version bump or passing
17
- package checks does not establish native device readiness: complete the gates
18
- below before tagging a stable release.
13
+ ## Release preparation
14
+
15
+ The next prepared minor release is **3.10.0**. Version 3.9.0 is already published.
16
+ This release adds TeeLS error context, warning outcomes and stage history in
17
+ `logData`; the original seven event types are unchanged. It requires an npm
18
+ publish after review and validation. Follow the [TeeLS rollout guide](./TEELS_OBSERVABILITY.md)
19
+ for Devtool deployment, hosted adapter updates and the persisted-event device canary.
20
+ No provider-monitor deployment or database migration is required; existing automated
21
+ alerts retain their current counting behavior.
22
+ A version bump or passing package checks does not establish native device readiness:
23
+ complete the gates below before tagging a stable release.
19
24
 
20
25
  1. Keep `package.json`, both root version fields in `package-lock.json`,
21
26
  `ios/SatyaAttest.podspec`, Android `version` / `versionName`, generated SDK
@@ -48,7 +53,7 @@ Local cookie cleanup does not reset remote hosted TeeLS sessions.
48
53
  The package check requires both native session managers, the WebView snapshot
49
54
  helper, adapter script, Android keep rules and public JS/declarations. Host tests
50
55
  use synthetic stores and adapter fixtures; they are not substitutes for device
51
- cookie isolation tests. Until the app builds and device matrix pass, treat 3.9.0
56
+ cookie isolation tests. Until the app builds and device matrix pass, treat 3.10.0
52
57
  as release preparation, not a validated stable release.
53
58
 
54
59
  ## TEE release requirements
@@ -256,7 +261,7 @@ internal/module_scripts/
256
261
  After the release gates pass and publication is authorized, use the consolidated
257
262
  `publish-expo-satya-attest.yml` workflow. A stable tag must match the committed
258
263
  package version and point to a commit on `main`; for this prepared release the
259
- package-specific tag is `expo-satya-attest-v3.9.0`. Creating/pushing that tag starts
264
+ package-specific tag is `expo-satya-attest-v3.10.0`. Creating/pushing that tag starts
260
265
  publication. Manual workflow dispatch is a dry-run.
261
266
 
262
267
  The workflow builds native artifacts, runs the release checks, and publishes
@@ -274,13 +279,13 @@ Every push to `main` publishes a snapshot package to the public npm registry wit
274
279
  unique prerelease version:
275
280
 
276
281
  ```text
277
- 3.9.1-snapshot.<run>.<attempt>.sha-<commit>
282
+ 3.10.1-snapshot.<run>.<attempt>.sha-<commit>
278
283
  ```
279
284
 
280
285
  The snapshot job (in `publish-expo-satya-attest.yml`) increments the package's patch base
281
- in CI before publishing. For example, if `package.json` is `3.9.0`, the snapshot version
282
- is based on `3.9.1`:
283
- `3.9.1-snapshot.<run>.<attempt>.sha-<commit>`. Snapshots are development builds and
286
+ in CI before publishing. For example, if `package.json` is `3.10.0`, the snapshot version
287
+ is based on `3.10.1`:
288
+ `3.10.1-snapshot.<run>.<attempt>.sha-<commit>`. Snapshots are development builds and
284
289
  do not imply completion of the physical-device gates.
285
290
 
286
291
  Snapshots use the `snapshot` dist-tag so test apps do not need to know the generated
package/README.md CHANGED
@@ -5,9 +5,11 @@ the Rust `satya-sdk` / `satya-ffi` pipeline for artifact construction and verifi
5
5
  policy, while Swift and Kotlin provide platform-specific WebView capture, native HTTPS
6
6
  replay, hardware-backed signing, and platform attestation evidence.
7
7
 
8
- **3.9.0 release preparation:** this source includes provider-isolated sessions and
9
- `clearProviderCookies`. The new version has not been published. See the
10
- [changelog](./CHANGELOG.md) and [release requirements](./PUBLISHING.md#provider-session-release-preparation).
8
+ **3.10.0 release candidate:** this source adds TeeLS error context, warning outcomes
9
+ and stage history within the existing seven logging event types. An npm publish
10
+ is required after review and release validation. See the [changelog](./CHANGELOG.md),
11
+ [release requirements](./PUBLISHING.md#release-preparation), and
12
+ [TeeLS rollout guide](./TEELS_OBSERVABILITY.md).
11
13
 
12
14
  The SDK supports native app attestation, opt-in [TEE replay](./TEE_REPLAY.md),
13
15
  single-endpoint and composite proofs, provider-selective partial completion,
@@ -336,6 +338,9 @@ does not need frontend changes. See
336
338
  [Provider Config](./PROVIDER_CONFIG.md#hosted-teels-passthrough-provider-injection)
337
339
  for the adapter and device-validation contract.
338
340
 
341
+ For stage events, warning outcomes, safe error details and deployment order, see
342
+ [TeeLS observability](./TEELS_OBSERVABILITY.md).
343
+
339
344
  Only a non-null, JSON-safe attestation object can complete the flow. If provided,
340
345
  `claimData` is additionally forwarded as a second argument to `onTeelsComplete`.
341
346
  Success is returned only through `onTeelsComplete`; invalid/null data, hosted
@@ -0,0 +1,128 @@
1
+ # TeeLS flow observability
2
+
3
+ TeeLS uses the shared SATYA event logger and session trace. `FAILED` remains an
4
+ unsuccessful terminal. Confirmed wrong credentials, invalid/expired OTP, declined
5
+ approval, cancellation and replaced attempts carry `failureClass: user_action`
6
+ and `logLevel: warn`. Technical errors use `error`; unknown causes stay separately
7
+ classified and count as unsuccessful in reliability metrics. HTTP 400/401/403
8
+ alone never establishes incorrect credentials.
9
+
10
+ ## Events and safe context
11
+
12
+ Every managed attempt emits `telemetrySchemaVersion: 1`, `flowType` (`teels`,
13
+ `native_replay` or `tee_replay`), `attemptIndex`, monotonic `eventSequence`,
14
+ `eventId`, and `totalElapsedMs`. The SDK session remains stable over user retries;
15
+ the WebView bridge attempt ID changes. TeeLS's optional UUID is `teelsSessionId`,
16
+ separate from the SDK session. An internal TeeLS auth retry is not a new SDK
17
+ attempt and may repeat stages.
18
+
19
+ The event enum remains fixed at its existing seven values. TeeLS uses
20
+ `PROVIDER_INIT`, observed `LOGIN_COMPLETED`, `ATTESTATION_GENERATED`, and `FAILED`.
21
+ Stage observations enrich `logData` rather than creating new event types.
22
+ `teelsStage` is one of `initializing`, `navigating`, `entering_credentials`,
23
+ `submitting`, `awaiting_challenge`, `challenge_submitted`, `logged_in`, `extracting`,
24
+ or `attesting`. `LOGIN_COMPLETED` is emitted once when `logged_in` is observed.
25
+ Duplicate consecutive stages are suppressed and at most 64 transitions are
26
+ accepted per attempt. `teelsStageCount` counts accepted transitions;
27
+ `teelsStageHistory` contains the most recent 12 as `stage:elapsedMs` pairs separated
28
+ by commas, with elapsed times bounded to 24 hours. Only closed stage names and
29
+ numbers are retained. Login, completion, failure, cancellation and supersession
30
+ carry this history. A fresh SDK attempt resets it; internal retries retain it.
31
+ Intermediate history is buffered until one of those events, so an app killed
32
+ beforehand cannot upload it. Stage snapshots in Devtool count milestone/failure
33
+ events, not unique stage reach or native replay/capture measurements.
34
+
35
+ Successful hosted receipt emits one terminal `ATTESTATION_GENERATED` with
36
+ `logData.flowType: "teels"`, `completionMode: "hosted"`, and
37
+ `flowOutcome: "completed"`. It does **not** emit `ATTESTATION_VERIFIED` or assert
38
+ `verifierDecision: ok`. Native generation remains nonterminal. Failed attempts
39
+ carry `flowOutcome: "failed"`. The public `onTeelsComplete(attestation, claimData?)`
40
+ callback is unchanged. Independent verification/relying-party acceptance must be
41
+ reported by the component performing that work; receipt is not proof of acceptance.
42
+
43
+ Failures retain the SATYA public code (for example `SATYA_TEELS_FLOW_FAILED`).
44
+ Safe structured context adds `teelsErrorCode`, `teelsStage`, `teelsSessionId`,
45
+ `httpStatus`, `failureClass`, canonical `errorMessage` and `recoveryAction`.
46
+ The same detail is available in the host error's context. Only catalog codes,
47
+ known stages, valid statuses and UUIDs cross the structured bridge boundary.
48
+ Arbitrary provider text stays out of event ingestion; raw auth bodies,
49
+ credentials, OTP values and challenge destinations are never telemetry fields.
50
+ Legacy `login.auth failed: HTTP NNN (fields flagged: ...)` errors preserve only
51
+ the status in telemetry, not the field names and not a guessed credential cause.
52
+
53
+ ## Existing ingestion contract
54
+
55
+ The logger writes an SDK-owned `sdkTelemetry` first property in `logData` after
56
+ sanitization. Its value is `v1|flow|stage|outcome|code`, with ASCII fields padded
57
+ with spaces to widths 13, 20, 9 and 32. Only closed enums enter the header; callers
58
+ cannot supply it. The code is the canonical TeeLS cause, `OTHER_TECHNICAL` for
59
+ other named SDK failures, or empty when unavailable. Failure classification is
60
+ derived from that code. Outcome is checked against the existing event: native
61
+ `ATTESTATION_GENERATED` remains progress, and only explicit completed TeeLS receipt
62
+ is a hosted terminal. The header is preserved first during size fallbacks, unless
63
+ an application's custom logData budget is too small to hold it.
64
+
65
+ Devtool reads this field from the existing blob 10 and validates the same version,
66
+ widths, enums and event consistency in aggregate queries and event details.
67
+ Malformed, scrubbed and legacy records stay unknown for flow/failure aggregates;
68
+ old JSON can still supply error details. The bounded header retains a canonical
69
+ reason even when later JSON is truncated. It is client analytics metadata, not
70
+ security evidence. No additional event or ingestion dimension is required.
71
+
72
+ ## Hosted adapter compatibility
73
+
74
+ Regenerate each hosted provider's injection using:
75
+
76
+ ```sh
77
+ node scripts/generate-hosted-teels-provider-injection.js \
78
+ --origin https://YOUR-HOSTED-PAGE --json
79
+ ```
80
+
81
+ Publish the generated injection through the normal Provider Registry version and
82
+ policy-hash workflow. Existing registry records do not change when this SDK is
83
+ released. Update all enabled TeeLS providers, including `ronde.teels.v1`,
84
+ `perfect.fitness.teels.v1` and `satya.teels.v1`, using each record's actual origins.
85
+
86
+ The adapter preserves one-argument `onSuccess(attestation)` and legacy
87
+ `onSuccess(data, attestation)`, success event/snapshot paths, and `onError(string)`.
88
+ New `onError(string, detail)` forwards the optional detail as the third argument
89
+ to `bridge.fail`; old mobile bridges ignore it. `onStatus(progress)` is forwarded
90
+ only when `bridge.progress` exists. Protocol version remains 1. Progress never
91
+ sets the terminal latch. Origin/provider/attempt checks apply before accepting
92
+ messages; oversize direct posts are ignored, while the SDK-owned bridge converts
93
+ its own oversize terminal payload into a small correlated error.
94
+
95
+ `onClose` before a terminal result forwards `USER_CANCELLED`, including the
96
+ hosted consent screen's **Not now** action even with `dismissible: false`.
97
+ Teardown during a success/error callback preserves that callback's result;
98
+ later closes cannot emit another terminal event. Original host callbacks retain
99
+ their receiver, arguments, return values and exceptions. Regenerate the hosted
100
+ injection to enable this behavior; publishing the mobile SDK alone is insufficient.
101
+
102
+ ## Reporting and rollout
103
+
104
+ These SDK changes ship in **3.10.0** and require publishing
105
+ `@burnt-labs/expo-satya-attest@3.10.0` to npm, then adoption by consuming apps.
106
+ Merging this PR alone does not make the stable package available.
107
+
108
+ Deploy the Devtool reader update, then adopt the SATYA SDK update and publish
109
+ compatible hosted injections alongside TeeLS server/web callbacks. Existing
110
+ monitoring ingestion already preserves these seven event types, warning severity
111
+ and safe logData; this release requires no monitoring-service change or database
112
+ migration. Existing automated alerts keep their current failure-counting behavior. This change adds no native API, but does not waive
113
+ the release/device validation required by the SDK's other pending changes.
114
+
115
+ Devtool displays wrong credentials/cancellation as **Failed · warning** in yellow.
116
+ Completion includes all unsuccessful attempts. Technical reliability excludes
117
+ only confirmed user-action warnings; unknown failures remain in its denominator.
118
+ Both use sample-weighted terminal event counts, not exact unique-attempt conversion.
119
+ Source monitor snapshots and EarnOS worker analytics have independent windows and
120
+ denominators. Existing EarnOS session events do not automatically gain SDK fields.
121
+
122
+ Canary a controlled wrong-password attempt, cancellation, a technical error and
123
+ retry→success on supported iOS/Android runtimes. Verify persisted AE rows and the
124
+ Devtool trace (code, stage, safe reason, color, one terminal), not merely HTTP 202.
125
+ The ingestion endpoint can also accept but decline an unregistered provider.
126
+ Check older SDKs with the new adapter and newer SDKs with cached older pages.
127
+ Rollback emitters/hosted injection versions if needed; leave the compatible
128
+ Devtool reader in place. Old unknown records must not be relabeled as bad credentials.
@@ -4,14 +4,14 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'expo.modules.satyaattest'
7
- version = '3.9.0'
7
+ version = '3.10.0'
8
8
 
9
9
  android {
10
10
  namespace "expo.modules.satyaattest"
11
11
  defaultConfig {
12
12
  consumerProguardFiles 'consumer-rules.pro'
13
13
  versionCode 1
14
- versionName "3.9.0"
14
+ versionName "3.10.0"
15
15
  // StrongBox key attestation needs API 28+; basic Keystore attestation API 24+.
16
16
  minSdkVersion 24
17
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../../src/components/providerAttest/copy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAmCtD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAI1F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAIpE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAeA;AAED,wBAAgB,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CA+B3E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAchF"}
1
+ {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../../src/components/providerAttest/copy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAoCtD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAI1F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAIpE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAeA;AAED,wBAAgB,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CA+B3E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAiBhF"}
@@ -1,3 +1,4 @@
1
+ import { TEELS_ERROR_INFO } from '../../teelsTelemetry';
1
2
  import { SatyaErrorCode } from '../../types/error.types';
2
3
  /**
3
4
  * Gate refusals are permanent for this build+provider: the app is not
@@ -102,6 +103,10 @@ export function friendlyTeelsError(message, code) {
102
103
  return 'The TeeLS flow timed out. Please try again.';
103
104
  }
104
105
  if (code === SatyaErrorCode.TEELS_FLOW_FAILED) {
106
+ for (const info of Object.values(TEELS_ERROR_INFO)) {
107
+ if (message.endsWith(': ' + info.message))
108
+ return info.message + ' ' + info.recoveryAction;
109
+ }
105
110
  return 'The TeeLS flow could not complete. Please try again.';
106
111
  }
107
112
  return friendlyError(message, code);
@@ -1 +1 @@
1
- {"version":3,"file":"copy.js","sourceRoot":"","sources":["../../../src/components/providerAttest/copy.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SatyaProviderFlowPhase } from './types';\nimport { SatyaErrorCode } from '../../types/error.types';\n\n/**\n * Gate refusals are permanent for this build+provider: the app is not\n * registered/approved, or the provider is not granted to it. Retrying cannot\n * help, so the copy must say what is wrong and the UI must not offer \"Try\n * again\" (see isRetryableError).\n */\nconst GATE_ERROR_COPY: Record<string, string> = {\n [SatyaErrorCode.PROVIDER_ACCESS_DENIED]:\n 'This provider is not enabled for this app yet. Contact the app owner to request access.',\n [SatyaErrorCode.APP_NOT_REGISTERED]:\n 'This app is not registered for verification. Contact the app owner.',\n [SatyaErrorCode.APP_DISABLED]:\n 'Verification is turned off for this app right now. Contact the app owner.',\n [SatyaErrorCode.APP_ID_REQUIRED]:\n 'This app is not set up for verification yet. Contact the app owner.',\n [SatyaErrorCode.APP_BINDING_MISMATCH]:\n 'This app build cannot be verified. Contact the app owner.',\n [SatyaErrorCode.APP_PLATFORM_NOT_CONFIGURED]:\n 'This device platform is not set up for verification in this app. Contact the app owner.',\n};\n\n/**\n * Provider/template configuration problems: not the user's fault and not\n * fixable by retrying — same treatment as gate refusals.\n */\nconst CONFIG_ERROR_COPY: Record<string, string> = {\n [SatyaErrorCode.PROVIDER_TEMPLATE_INVALID]:\n 'This provider is not set up correctly in this app yet. Contact the app owner.',\n [SatyaErrorCode.PROVIDER_POLICY_INVALID]:\n 'This provider is not set up correctly in this app yet. Contact the app owner.',\n};\n\n/** Prefer the verifier's explicit answer; otherwise classify local SDK codes. */\nexport function isRetryableError(code?: string | null, retryable?: boolean | null): boolean {\n if (typeof retryable === 'boolean') return retryable;\n if (!code) return true;\n return !(code in GATE_ERROR_COPY) && !(code in CONFIG_ERROR_COPY);\n}\n\nexport function processingCopy(phase: SatyaProviderFlowPhase): string {\n if (phase === 'backendVerify') return 'Finishing verification...';\n if (phase === 'nativeReplay') return 'Securely verifying your account...';\n return 'Verifying your account...';\n}\n\n/**\n * Copy for the cover, which is shown from the moment a login is submitted.\n * The pending tier deliberately does not claim verification has started — at\n * that point the credentials have only been sent.\n */\nexport function coverCopy(options: { pending: boolean; stalled: boolean }): {\n title: string;\n subtitle: string;\n} {\n if (options.stalled) {\n return {\n title: 'Still verifying...',\n subtitle:\n 'This is taking longer than expected. You can return to the provider without ending verification.',\n };\n }\n if (options.pending) {\n return { title: 'Signing you in...', subtitle: 'Just a moment.' };\n }\n return {\n title: 'Verifying your account...',\n subtitle: 'Keep this screen open - it only takes a moment.',\n };\n}\n\nexport function preparingCopy(providerName?: string): string {\n return providerName ? `Connecting to ${providerName}...` : 'Connecting securely...';\n}\n\nexport function friendlyError(message: string, code?: string | null): string {\n // Prefer the typed code: gate refusals and configuration errors have\n // precise, actionable copy and must never fall through to the generic\n // \"try again\" string.\n if (code && GATE_ERROR_COPY[code]) return GATE_ERROR_COPY[code];\n if (code && CONFIG_ERROR_COPY[code]) return CONFIG_ERROR_COPY[code];\n const m = (message || '').toLowerCase();\n if (m.includes('location permission') || m.includes('location access')) {\n return 'Location access is required for this provider. Allow it and try again.';\n }\n if (\n m.includes('403') ||\n m.includes('forbidden') ||\n m.includes('cloudflare') ||\n m.includes('bot')\n ) {\n return 'This provider is blocking automated verification right now. Please try again later.';\n }\n if (m.includes('network') || m.includes('timeout') || m.includes('timed out')) {\n return 'There was a network problem. Check your connection and try again.';\n }\n if (m.includes('request failed from') || m.includes('policy fetch')) {\n return 'Could not reach the verification service. Check your connection and try again.';\n }\n if (m.includes('pin') || m.includes('certificate') || m.includes('tls') || m.includes('secure')) {\n return 'We could not establish a secure connection to this provider. Please try again.';\n }\n if (m.includes('claim') || m.includes('reveal') || m.includes('match')) {\n return 'We could not read the expected details. Make sure you are fully signed in, then try again.';\n }\n return 'Something went wrong. Please try again.';\n}\n\nexport function friendlyTeelsError(message: string, code?: string | null): string {\n if (code === SatyaErrorCode.TEELS_ATTESTATION_MISSING) {\n return 'The provider completed without returning a TeeLS attestation.';\n }\n if (code === SatyaErrorCode.TEELS_BRIDGE_INVALID) {\n return 'The provider returned an invalid TeeLS attestation.';\n }\n if (code === SatyaErrorCode.TEELS_FLOW_TIMEOUT) {\n return 'The TeeLS flow timed out. Please try again.';\n }\n if (code === SatyaErrorCode.TEELS_FLOW_FAILED) {\n return 'The TeeLS flow could not complete. Please try again.';\n }\n return friendlyError(message, code);\n}\n"]}
1
+ {"version":3,"file":"copy.js","sourceRoot":"","sources":["../../../src/components/providerAttest/copy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,eAAe,GAA2B;IAC9C,CAAC,cAAc,CAAC,sBAAsB,CAAC,EACrC,yFAAyF;IAC3F,CAAC,cAAc,CAAC,kBAAkB,CAAC,EACjC,qEAAqE;IACvE,CAAC,cAAc,CAAC,YAAY,CAAC,EAC3B,2EAA2E;IAC7E,CAAC,cAAc,CAAC,eAAe,CAAC,EAC9B,qEAAqE;IACvE,CAAC,cAAc,CAAC,oBAAoB,CAAC,EACnC,2DAA2D;IAC7D,CAAC,cAAc,CAAC,2BAA2B,CAAC,EAC1C,yFAAyF;CAC5F,CAAC;AAEF;;;GAGG;AACH,MAAM,iBAAiB,GAA2B;IAChD,CAAC,cAAc,CAAC,yBAAyB,CAAC,EACxC,+EAA+E;IACjF,CAAC,cAAc,CAAC,uBAAuB,CAAC,EACtC,+EAA+E;CAClF,CAAC;AAEF,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,IAAoB,EAAE,SAA0B;IAC/E,IAAI,OAAO,SAAS,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACrD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,iBAAiB,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAA6B;IAC1D,IAAI,KAAK,KAAK,eAAe;QAAE,OAAO,2BAA2B,CAAC;IAClE,IAAI,KAAK,KAAK,cAAc;QAAE,OAAO,oCAAoC,CAAC;IAC1E,OAAO,2BAA2B,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,OAA+C;IAIvE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO;YACL,KAAK,EAAE,oBAAoB;YAC3B,QAAQ,EACN,kGAAkG;SACrG,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IACpE,CAAC;IACD,OAAO;QACL,KAAK,EAAE,2BAA2B;QAClC,QAAQ,EAAE,iDAAiD;KAC5D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,YAAqB;IACjD,OAAO,YAAY,CAAC,CAAC,CAAC,iBAAiB,YAAY,KAAK,CAAC,CAAC,CAAC,wBAAwB,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,IAAoB;IACjE,qEAAqE;IACrE,sEAAsE;IACtE,sBAAsB;IACtB,IAAI,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC;QAAE,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;IAChE,IAAI,IAAI,IAAI,iBAAiB,CAAC,IAAI,CAAC;QAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACvE,OAAO,wEAAwE,CAAC;IAClF,CAAC;IACD,IACE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QACjB,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;QACvB,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;QACxB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EACjB,CAAC;QACD,OAAO,qFAAqF,CAAC;IAC/F,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9E,OAAO,mEAAmE,CAAC;IAC7E,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACpE,OAAO,gFAAgF,CAAC;IAC1F,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChG,OAAO,gFAAgF,CAAC;IAC1F,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACvE,OAAO,4FAA4F,CAAC;IACtG,CAAC;IACD,OAAO,yCAAyC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,IAAoB;IACtE,IAAI,IAAI,KAAK,cAAc,CAAC,yBAAyB,EAAE,CAAC;QACtD,OAAO,+DAA+D,CAAC;IACzE,CAAC;IACD,IAAI,IAAI,KAAK,cAAc,CAAC,oBAAoB,EAAE,CAAC;QACjD,OAAO,qDAAqD,CAAC;IAC/D,CAAC;IACD,IAAI,IAAI,KAAK,cAAc,CAAC,kBAAkB,EAAE,CAAC;QAC/C,OAAO,6CAA6C,CAAC;IACvD,CAAC;IACD,IAAI,IAAI,KAAK,cAAc,CAAC,iBAAiB,EAAE,CAAC;QAC9C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACnD,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;gBAAE,OAAO,IAAI,CAAC,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC;QAC7F,CAAC;QACD,OAAO,sDAAsD,CAAC;IAChE,CAAC;IACD,OAAO,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACtC,CAAC","sourcesContent":["import type { SatyaProviderFlowPhase } from './types';\nimport { TEELS_ERROR_INFO } from '../../teelsTelemetry';\nimport { SatyaErrorCode } from '../../types/error.types';\n\n/**\n * Gate refusals are permanent for this build+provider: the app is not\n * registered/approved, or the provider is not granted to it. Retrying cannot\n * help, so the copy must say what is wrong and the UI must not offer \"Try\n * again\" (see isRetryableError).\n */\nconst GATE_ERROR_COPY: Record<string, string> = {\n [SatyaErrorCode.PROVIDER_ACCESS_DENIED]:\n 'This provider is not enabled for this app yet. Contact the app owner to request access.',\n [SatyaErrorCode.APP_NOT_REGISTERED]:\n 'This app is not registered for verification. Contact the app owner.',\n [SatyaErrorCode.APP_DISABLED]:\n 'Verification is turned off for this app right now. Contact the app owner.',\n [SatyaErrorCode.APP_ID_REQUIRED]:\n 'This app is not set up for verification yet. Contact the app owner.',\n [SatyaErrorCode.APP_BINDING_MISMATCH]:\n 'This app build cannot be verified. Contact the app owner.',\n [SatyaErrorCode.APP_PLATFORM_NOT_CONFIGURED]:\n 'This device platform is not set up for verification in this app. Contact the app owner.',\n};\n\n/**\n * Provider/template configuration problems: not the user's fault and not\n * fixable by retrying — same treatment as gate refusals.\n */\nconst CONFIG_ERROR_COPY: Record<string, string> = {\n [SatyaErrorCode.PROVIDER_TEMPLATE_INVALID]:\n 'This provider is not set up correctly in this app yet. Contact the app owner.',\n [SatyaErrorCode.PROVIDER_POLICY_INVALID]:\n 'This provider is not set up correctly in this app yet. Contact the app owner.',\n};\n\n/** Prefer the verifier's explicit answer; otherwise classify local SDK codes. */\nexport function isRetryableError(code?: string | null, retryable?: boolean | null): boolean {\n if (typeof retryable === 'boolean') return retryable;\n if (!code) return true;\n return !(code in GATE_ERROR_COPY) && !(code in CONFIG_ERROR_COPY);\n}\n\nexport function processingCopy(phase: SatyaProviderFlowPhase): string {\n if (phase === 'backendVerify') return 'Finishing verification...';\n if (phase === 'nativeReplay') return 'Securely verifying your account...';\n return 'Verifying your account...';\n}\n\n/**\n * Copy for the cover, which is shown from the moment a login is submitted.\n * The pending tier deliberately does not claim verification has started — at\n * that point the credentials have only been sent.\n */\nexport function coverCopy(options: { pending: boolean; stalled: boolean }): {\n title: string;\n subtitle: string;\n} {\n if (options.stalled) {\n return {\n title: 'Still verifying...',\n subtitle:\n 'This is taking longer than expected. You can return to the provider without ending verification.',\n };\n }\n if (options.pending) {\n return { title: 'Signing you in...', subtitle: 'Just a moment.' };\n }\n return {\n title: 'Verifying your account...',\n subtitle: 'Keep this screen open - it only takes a moment.',\n };\n}\n\nexport function preparingCopy(providerName?: string): string {\n return providerName ? `Connecting to ${providerName}...` : 'Connecting securely...';\n}\n\nexport function friendlyError(message: string, code?: string | null): string {\n // Prefer the typed code: gate refusals and configuration errors have\n // precise, actionable copy and must never fall through to the generic\n // \"try again\" string.\n if (code && GATE_ERROR_COPY[code]) return GATE_ERROR_COPY[code];\n if (code && CONFIG_ERROR_COPY[code]) return CONFIG_ERROR_COPY[code];\n const m = (message || '').toLowerCase();\n if (m.includes('location permission') || m.includes('location access')) {\n return 'Location access is required for this provider. Allow it and try again.';\n }\n if (\n m.includes('403') ||\n m.includes('forbidden') ||\n m.includes('cloudflare') ||\n m.includes('bot')\n ) {\n return 'This provider is blocking automated verification right now. Please try again later.';\n }\n if (m.includes('network') || m.includes('timeout') || m.includes('timed out')) {\n return 'There was a network problem. Check your connection and try again.';\n }\n if (m.includes('request failed from') || m.includes('policy fetch')) {\n return 'Could not reach the verification service. Check your connection and try again.';\n }\n if (m.includes('pin') || m.includes('certificate') || m.includes('tls') || m.includes('secure')) {\n return 'We could not establish a secure connection to this provider. Please try again.';\n }\n if (m.includes('claim') || m.includes('reveal') || m.includes('match')) {\n return 'We could not read the expected details. Make sure you are fully signed in, then try again.';\n }\n return 'Something went wrong. Please try again.';\n}\n\nexport function friendlyTeelsError(message: string, code?: string | null): string {\n if (code === SatyaErrorCode.TEELS_ATTESTATION_MISSING) {\n return 'The provider completed without returning a TeeLS attestation.';\n }\n if (code === SatyaErrorCode.TEELS_BRIDGE_INVALID) {\n return 'The provider returned an invalid TeeLS attestation.';\n }\n if (code === SatyaErrorCode.TEELS_FLOW_TIMEOUT) {\n return 'The TeeLS flow timed out. Please try again.';\n }\n if (code === SatyaErrorCode.TEELS_FLOW_FAILED) {\n for (const info of Object.values(TEELS_ERROR_INFO)) {\n if (message.endsWith(': ' + info.message)) return info.message + ' ' + info.recoveryAction;\n }\n return 'The TeeLS flow could not complete. Please try again.';\n }\n return friendlyError(message, code);\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { TeelsBridgeMessageResult } from './teelsProtocol';
2
2
  import type { SdkEventLogData } from '../../../sdkEventLog';
3
+ import { type TeelsErrorDetail } from '../../../teelsTelemetry';
3
4
  import { type SatyaError } from '../../../types/error.types';
4
5
  type TeelsBridgeErrorResult = Extract<TeelsBridgeMessageResult, {
5
6
  kind: 'error';
@@ -7,6 +8,7 @@ type TeelsBridgeErrorResult = Extract<TeelsBridgeMessageResult, {
7
8
  export interface TeelsFailureTelemetry {
8
9
  errorMessage: string;
9
10
  httpStatus?: number;
11
+ detail?: TeelsErrorDetail;
10
12
  }
11
13
  export interface TeelsBridgeFailure {
12
14
  error: SatyaError;
@@ -1 +1 @@
1
- {"version":3,"file":"teelsFailure.d.ts","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsFailure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE/F,KAAK,sBAAsB,GAAG,OAAO,CAAC,wBAAwB,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEnF,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAEtD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,CAW3F;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,eAAe,CAcjB"}
1
+ {"version":3,"file":"teelsFailure.d.ts","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsFailure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE/F,KAAK,sBAAsB,GAAG,OAAO,CAAC,wBAAwB,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEnF,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAEtD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,CA+B3F;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,eAAe,CAuBjB"}
@@ -1,13 +1,30 @@
1
+ import { TEELS_ERROR_INFO } from '../../../teelsTelemetry';
1
2
  import { SATYA_ERROR_MESSAGES, satyaError } from '../../../types/error.types';
2
3
  export function createTeelsBridgeFailure(result) {
3
4
  const baseMessage = SATYA_ERROR_MESSAGES[result.code];
5
+ const detail = result.errorDetail;
6
+ const info = detail ? TEELS_ERROR_INFO[detail.code] : undefined;
4
7
  return {
5
- error: satyaError(result.code, result.detail),
8
+ error: satyaError(result.code, info?.message ?? result.detail, detail
9
+ ? {
10
+ teelsErrorCode: detail.code,
11
+ teelsStage: detail.stage,
12
+ httpStatus: detail.httpStatus,
13
+ teelsSessionId: detail.sessionId,
14
+ failureClass: info?.failureClass,
15
+ recoveryAction: info?.recoveryAction,
16
+ }
17
+ : undefined),
6
18
  telemetry: {
7
- errorMessage: result.telemetryDetail
8
- ? baseMessage + ': ' + result.telemetryDetail
9
- : baseMessage,
10
- ...(typeof result.httpStatus === 'number' ? { httpStatus: result.httpStatus } : {}),
19
+ ...(detail ? { detail } : {}),
20
+ errorMessage: info
21
+ ? info.message
22
+ : result.telemetryDetail
23
+ ? baseMessage + ': ' + result.telemetryDetail
24
+ : baseMessage,
25
+ ...(typeof (detail?.httpStatus ?? result.httpStatus) === 'number'
26
+ ? { httpStatus: detail?.httpStatus ?? result.httpStatus }
27
+ : {}),
11
28
  },
12
29
  };
13
30
  }
@@ -23,6 +40,15 @@ export function buildTeelsFailureLogData(input, providerId, funnelStage) {
23
40
  funnelStage,
24
41
  retryable: typeof context.retryable === 'boolean' ? context.retryable : undefined,
25
42
  httpStatus: telemetry?.httpStatus,
43
+ ...(telemetry?.detail
44
+ ? {
45
+ teelsErrorCode: telemetry.detail.code,
46
+ ...(telemetry.detail.stage ? { teelsStage: telemetry.detail.stage } : {}),
47
+ ...(telemetry.detail.sessionId ? { teelsSessionId: telemetry.detail.sessionId } : {}),
48
+ failureClass: TEELS_ERROR_INFO[telemetry.detail.code].failureClass,
49
+ recoveryAction: TEELS_ERROR_INFO[telemetry.detail.code].recoveryAction,
50
+ }
51
+ : {}),
26
52
  errorId: error.errorId,
27
53
  };
28
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"teelsFailure.js","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsFailure.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAmB,MAAM,4BAA4B,CAAC;AAkB/F,MAAM,UAAU,wBAAwB,CAAC,MAA8B;IACrE,MAAM,WAAW,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtD,OAAO;QACL,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC;QAC7C,SAAS,EAAE;YACT,YAAY,EAAE,MAAM,CAAC,eAAe;gBAClC,CAAC,CAAC,WAAW,GAAG,IAAI,GAAG,MAAM,CAAC,eAAe;gBAC7C,CAAC,CAAC,WAAW;YACf,GAAG,CAAC,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,KAA2B,EAC3B,UAAkB,EAClB,WAAmB;IAEnB,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAC5E,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAA4B,CAAC;IACjE,OAAO;QACL,UAAU;QACV,SAAS,EAAE,KAAK,CAAC,IAAI;QACrB,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;QAChE,QAAQ,EAAE,KAAK,CAAC,KAAK;QACrB,WAAW;QACX,SAAS,EAAE,OAAO,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACjF,UAAU,EAAE,SAAS,EAAE,UAAU;QACjC,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;AACJ,CAAC","sourcesContent":["import type { TeelsBridgeMessageResult } from './teelsProtocol';\nimport type { SdkEventLogData } from '../../../sdkEventLog';\nimport { SATYA_ERROR_MESSAGES, satyaError, type SatyaError } from '../../../types/error.types';\n\ntype TeelsBridgeErrorResult = Extract<TeelsBridgeMessageResult, { kind: 'error' }>;\n\nexport interface TeelsFailureTelemetry {\n errorMessage: string;\n httpStatus?: number;\n}\n\nexport interface TeelsBridgeFailure {\n error: SatyaError;\n telemetry: TeelsFailureTelemetry;\n}\n\nexport type TeelsFailureLogInput =\n | { source: 'sdk'; error: SatyaError }\n | { source: 'bridge'; failure: TeelsBridgeFailure };\n\nexport function createTeelsBridgeFailure(result: TeelsBridgeErrorResult): TeelsBridgeFailure {\n const baseMessage = SATYA_ERROR_MESSAGES[result.code];\n return {\n error: satyaError(result.code, result.detail),\n telemetry: {\n errorMessage: result.telemetryDetail\n ? baseMessage + ': ' + result.telemetryDetail\n : baseMessage,\n ...(typeof result.httpStatus === 'number' ? { httpStatus: result.httpStatus } : {}),\n },\n };\n}\n\nexport function buildTeelsFailureLogData(\n input: TeelsFailureLogInput,\n providerId: string,\n funnelStage: string\n): SdkEventLogData {\n const error = input.source === 'bridge' ? input.failure.error : input.error;\n const telemetry = input.source === 'bridge' ? input.failure.telemetry : undefined;\n const context = (error.context ?? {}) as Record<string, unknown>;\n return {\n providerId,\n errorCode: error.code,\n errorMessage: telemetry ? telemetry.errorMessage : error.message,\n sdkStage: error.stage,\n funnelStage,\n retryable: typeof context.retryable === 'boolean' ? context.retryable : undefined,\n httpStatus: telemetry?.httpStatus,\n errorId: error.errorId,\n };\n}\n"]}
1
+ {"version":3,"file":"teelsFailure.js","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsFailure.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TeelsBridgeMessageResult } from './teelsProtocol';\nimport type { SdkEventLogData } from '../../../sdkEventLog';\nimport { TEELS_ERROR_INFO, type TeelsErrorDetail } from '../../../teelsTelemetry';\nimport { SATYA_ERROR_MESSAGES, satyaError, type SatyaError } from '../../../types/error.types';\n\ntype TeelsBridgeErrorResult = Extract<TeelsBridgeMessageResult, { kind: 'error' }>;\n\nexport interface TeelsFailureTelemetry {\n errorMessage: string;\n httpStatus?: number;\n detail?: TeelsErrorDetail;\n}\n\nexport interface TeelsBridgeFailure {\n error: SatyaError;\n telemetry: TeelsFailureTelemetry;\n}\n\nexport type TeelsFailureLogInput =\n | { source: 'sdk'; error: SatyaError }\n | { source: 'bridge'; failure: TeelsBridgeFailure };\n\nexport function createTeelsBridgeFailure(result: TeelsBridgeErrorResult): TeelsBridgeFailure {\n const baseMessage = SATYA_ERROR_MESSAGES[result.code];\n const detail = result.errorDetail;\n const info = detail ? TEELS_ERROR_INFO[detail.code] : undefined;\n return {\n error: satyaError(\n result.code,\n info?.message ?? result.detail,\n detail\n ? {\n teelsErrorCode: detail.code,\n teelsStage: detail.stage,\n httpStatus: detail.httpStatus,\n teelsSessionId: detail.sessionId,\n failureClass: info?.failureClass,\n recoveryAction: info?.recoveryAction,\n }\n : undefined\n ),\n telemetry: {\n ...(detail ? { detail } : {}),\n errorMessage: info\n ? info.message\n : result.telemetryDetail\n ? baseMessage + ': ' + result.telemetryDetail\n : baseMessage,\n ...(typeof (detail?.httpStatus ?? result.httpStatus) === 'number'\n ? { httpStatus: detail?.httpStatus ?? result.httpStatus }\n : {}),\n },\n };\n}\n\nexport function buildTeelsFailureLogData(\n input: TeelsFailureLogInput,\n providerId: string,\n funnelStage: string\n): SdkEventLogData {\n const error = input.source === 'bridge' ? input.failure.error : input.error;\n const telemetry = input.source === 'bridge' ? input.failure.telemetry : undefined;\n const context = (error.context ?? {}) as Record<string, unknown>;\n return {\n providerId,\n errorCode: error.code,\n errorMessage: telemetry ? telemetry.errorMessage : error.message,\n sdkStage: error.stage,\n funnelStage,\n retryable: typeof context.retryable === 'boolean' ? context.retryable : undefined,\n httpStatus: telemetry?.httpStatus,\n ...(telemetry?.detail\n ? {\n teelsErrorCode: telemetry.detail.code,\n ...(telemetry.detail.stage ? { teelsStage: telemetry.detail.stage } : {}),\n ...(telemetry.detail.sessionId ? { teelsSessionId: telemetry.detail.sessionId } : {}),\n failureClass: TEELS_ERROR_INFO[telemetry.detail.code].failureClass,\n recoveryAction: TEELS_ERROR_INFO[telemetry.detail.code].recoveryAction,\n }\n : {}),\n errorId: error.errorId,\n };\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { type TeelsErrorDetail, type TeelsProgress } from '../../../teelsTelemetry';
1
2
  import type { SatyaProviderInjection } from '../../../types';
2
3
  import { type SatyaErrorCodeValue } from '../../../types/error.types';
3
4
  import type { SatyaTeelsAttestation, SatyaTeelsClaimData } from '../types';
@@ -20,6 +21,9 @@ export interface TeelsBridgeCompletePayload {
20
21
  }
21
22
  export type TeelsBridgeMessageResult = {
22
23
  kind: 'ignore';
24
+ } | {
25
+ kind: 'progress';
26
+ progress: TeelsProgress;
23
27
  } | {
24
28
  kind: 'complete';
25
29
  payload: TeelsBridgeCompletePayload;
@@ -28,6 +32,7 @@ export type TeelsBridgeMessageResult = {
28
32
  code: SatyaErrorCodeValue;
29
33
  detail?: string;
30
34
  telemetryDetail?: string;
35
+ errorDetail?: TeelsErrorDetail;
31
36
  httpStatus?: number;
32
37
  };
33
38
  export declare function createTeelsAttemptId(cryptoSource?: Pick<Crypto, 'getRandomValues' | 'randomUUID'> | null | undefined): string;
@@ -1 +1 @@
1
- {"version":3,"file":"teelsProtocol.d.ts","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsProtocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtF,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE3E,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,8BAA8B,QAAa,CAAC;AACzD,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAC1D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAC7C,eAAO,MAAM,qBAAqB,QAAa,CAAC;AAMhD,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,qBAAqB,CAAC;IACnC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,0BAA0B,CAAA;CAAE,GACzD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEN,wBAAgB,oBAAoB,CAClC,YAAY,GACR,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,GAC9C,IAAI,GACJ,SAA6B,GAChC,MAAM,CAaR;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,sBAAsB,CAAC;CAC3C,GAAG,MAAM,CAwIT;AAED,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,yBAAyB,GACjC,wBAAwB,CAsE1B;AAmDD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAgCtF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWpD;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE"}
1
+ {"version":3,"file":"teelsProtocol.d.ts","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsProtocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtF,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE3E,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,8BAA8B,QAAa,CAAC;AACzD,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAC1D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAC7C,eAAO,MAAM,qBAAqB,QAAa,CAAC;AAOhD,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,qBAAqB,CAAC;IACnC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,0BAA0B,CAAA;CAAE,GACzD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEN,wBAAgB,oBAAoB,CAClC,YAAY,GACR,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,GAC9C,IAAI,GACJ,SAA6B,GAChC,MAAM,CAaR;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,sBAAsB,CAAC;CAC3C,GAAG,MAAM,CAoJT;AAED,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,yBAAyB,GACjC,wBAAwB,CAwF1B;AAsDD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAgCtF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWpD;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE"}
@@ -1,3 +1,4 @@
1
+ import { TEELS_ERROR_INFO, TEELS_STAGES, isTeelsStage, readTeelsErrorDetail, safeTeelsSessionId, } from '../../../teelsTelemetry';
1
2
  import { SatyaErrorCode } from '../../../types/error.types';
2
3
  export const TEELS_BRIDGE_PROTOCOL_VERSION = 1;
3
4
  export const TEELS_BRIDGE_MAX_MESSAGE_BYTES = 256 * 1024;
@@ -7,6 +8,7 @@ export const TEELS_BRIDGE_MAX_NODES = 10_000;
7
8
  export const TEELS_FLOW_TIMEOUT_MS = 5 * 60_000;
8
9
  const TEELS_COMPLETE_MESSAGE = '__satyaTeelsComplete';
9
10
  const TEELS_ERROR_MESSAGE = '__satyaTeelsError';
11
+ const TEELS_PROGRESS_MESSAGE = '__satyaTeelsProgress';
10
12
  let teelsAttemptSequence = 0;
11
13
  export function createTeelsAttemptId(cryptoSource = globalThis.crypto) {
12
14
  if (typeof cryptoSource?.randomUUID === 'function')
@@ -50,12 +52,12 @@ export function buildTeelsBridgeScript(options) {
50
52
  }
51
53
  return bytes;
52
54
  };
53
- const post = (message) => {
55
+ const post = (message, isTerminal = true) => {
54
56
  if (terminal || !window.ReactNativeWebView || typeof window.ReactNativeWebView.postMessage !== 'function') return false;
55
57
  let serialized;
56
58
  try { serialized = JSON.stringify(message); } catch (_) { return false; }
57
59
  if (byteLength(serialized) > maxMessageBytes) return false;
58
- terminal = true;
60
+ terminal = isTerminal;
59
61
  window.ReactNativeWebView.postMessage(serialized);
60
62
  return true;
61
63
  };
@@ -87,10 +89,17 @@ export function buildTeelsBridgeScript(options) {
87
89
  }
88
90
  return bounded ? bounded + ellipsis : undefined;
89
91
  };
90
- const postError = (code, errorMessage) => {
92
+ const projectDetail = (value) => {
93
+ if (!value || typeof value !== 'object' || !${JSON.stringify(Object.keys(TEELS_ERROR_INFO))}.includes(value.code)) return undefined;
94
+ return { code: value.code,
95
+ ...(${JSON.stringify(TEELS_STAGES)}.includes(value.stage) ? { stage: value.stage } : {}),
96
+ ...(Number.isInteger(value.httpStatus) && value.httpStatus >= 100 && value.httpStatus <= 599 ? { httpStatus: value.httpStatus } : {}),
97
+ ...(typeof value.sessionId === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value.sessionId) ? { sessionId: value.sessionId } : {}) };
98
+ };
99
+ const postError = (code, errorMessage, errorDetail) => {
91
100
  const normalizedCode = code === 'attestation_missing' ? 'attestation_missing' : code === 'bridge_invalid' ? 'bridge_invalid' : 'teels_flow_failed';
92
101
  const detail = normalizedCode === 'teels_flow_failed' ? normalizeErrorMessage(errorMessage) : undefined;
93
- return post({ type: ${JSON.stringify(TEELS_ERROR_MESSAGE)}, version: protocolVersion, providerId, attemptId, code: normalizedCode, ...(detail ? { errorMessage: detail } : {}) });
102
+ return post({ type: ${JSON.stringify(TEELS_ERROR_MESSAGE)}, version: protocolVersion, providerId, attemptId, code: normalizedCode, errorDetail: projectDetail(errorDetail), ...(detail ? { errorMessage: detail } : {}) });
94
103
  };
95
104
  const validate = (root) => {
96
105
  if (!root || typeof root !== 'object' || Array.isArray(root)) return false;
@@ -136,8 +145,13 @@ export function buildTeelsBridgeScript(options) {
136
145
  if (byteLength(serialized) > maxMessageBytes) { postError('bridge_invalid'); return; }
137
146
  post(message);
138
147
  },
139
- fail(code, errorMessage) {
140
- postError(code === 'attestation_missing' ? 'attestation_missing' : 'teels_flow_failed', errorMessage);
148
+ fail(code, errorMessage, errorDetail) {
149
+ postError(code === 'attestation_missing' ? 'attestation_missing' : 'teels_flow_failed', errorMessage, errorDetail);
150
+ },
151
+ progress(value) {
152
+ if (!value || !${JSON.stringify(TEELS_STAGES)}.includes(value.stage)) return;
153
+ const safe = projectDetail({ ...value, code: 'TEELS_UNKNOWN_ERROR' });
154
+ post({ type: ${JSON.stringify(TEELS_PROGRESS_MESSAGE)}, version: protocolVersion, providerId, attemptId, stage: safe.stage, sessionId: safe.sessionId }, false);
141
155
  }
142
156
  };
143
157
  Object.defineProperties(bridge, {
@@ -156,12 +170,14 @@ export function buildTeelsBridgeScript(options) {
156
170
  })();`;
157
171
  }
158
172
  export function parseTeelsBridgeMessage(raw, context) {
159
- const oversized = utf8ByteLength(raw) > TEELS_BRIDGE_MAX_MESSAGE_BYTES;
160
- if (oversized) {
161
- return raw.includes('__satyaTeels')
162
- ? { kind: 'error', code: SatyaErrorCode.TEELS_BRIDGE_INVALID }
163
- : { kind: 'ignore' };
164
- }
173
+ // Untrusted frames/old pages cannot settle an attempt, including oversized input.
174
+ if (!isExactOrigin(context.nativeEventUrl, context.expectedOrigin) ||
175
+ !isExactOrigin(context.committedUrl, context.expectedOrigin))
176
+ return { kind: 'ignore' };
177
+ // Our bridge turns oversize terminal payloads into a small correlated error.
178
+ // Do not parse oversized direct posts or guess their provider/attempt from text.
179
+ if (utf8ByteLength(raw) > TEELS_BRIDGE_MAX_MESSAGE_BYTES)
180
+ return { kind: 'ignore' };
165
181
  let decoded;
166
182
  try {
167
183
  decoded = JSON.parse(raw);
@@ -172,7 +188,9 @@ export function parseTeelsBridgeMessage(raw, context) {
172
188
  if (!isRecord(decoded))
173
189
  return { kind: 'ignore' };
174
190
  const type = decoded.type;
175
- if (type !== TEELS_COMPLETE_MESSAGE && type !== TEELS_ERROR_MESSAGE) {
191
+ if (type !== TEELS_COMPLETE_MESSAGE &&
192
+ type !== TEELS_ERROR_MESSAGE &&
193
+ type !== TEELS_PROGRESS_MESSAGE) {
176
194
  return { kind: 'ignore' };
177
195
  }
178
196
  // Origin before correlation and version: only messages from the exact
@@ -187,6 +205,14 @@ export function parseTeelsBridgeMessage(raw, context) {
187
205
  if (decoded.version !== TEELS_BRIDGE_PROTOCOL_VERSION) {
188
206
  return { kind: 'error', code: SatyaErrorCode.TEELS_BRIDGE_INVALID };
189
207
  }
208
+ if (type === TEELS_PROGRESS_MESSAGE) {
209
+ return isTeelsStage(decoded.stage)
210
+ ? {
211
+ kind: 'progress',
212
+ progress: { stage: decoded.stage, sessionId: safeTeelsSessionId(decoded.sessionId) },
213
+ }
214
+ : { kind: 'ignore' };
215
+ }
190
216
  if (type === TEELS_ERROR_MESSAGE) {
191
217
  if (decoded.code === 'attestation_missing') {
192
218
  return { kind: 'error', code: SatyaErrorCode.TEELS_ATTESTATION_MISSING };
@@ -194,11 +220,13 @@ export function parseTeelsBridgeMessage(raw, context) {
194
220
  if (decoded.code === 'teels_flow_failed') {
195
221
  const detail = normalizeTeelsErrorMessage(decoded.errorMessage);
196
222
  const telemetry = projectTeelsErrorForTelemetry(detail);
223
+ const errorDetail = readTeelsErrorDetail(decoded.errorDetail);
197
224
  return {
198
225
  kind: 'error',
199
226
  code: SatyaErrorCode.TEELS_FLOW_FAILED,
200
227
  ...(detail ? { detail } : {}),
201
228
  ...telemetry,
229
+ ...(errorDetail ? { errorDetail } : {}),
202
230
  };
203
231
  }
204
232
  if (decoded.code === 'bridge_invalid') {
@@ -241,7 +269,7 @@ function projectTeelsErrorForTelemetry(detail) {
241
269
  // Closed, PII-free grammar for the currently deployed hosted provider. Keep
242
270
  // arbitrary TeeLS text local in SatyaError; the public ingest gets only this
243
271
  // known stage plus an integer status.
244
- const match = /^login\.auth failed: HTTP ([1-5]\d{2})$/i.exec(detail);
272
+ const match = /^login\.auth failed: HTTP ([1-5]\d{2})(?: \(fields flagged: [^\r\n()]{1,256}\))?$/i.exec(detail);
245
273
  if (!match)
246
274
  return {};
247
275
  const httpStatus = Number(match[1]);