@trymellon/js 1.1.3 → 1.3.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.
package/README.MD CHANGED
@@ -49,6 +49,138 @@ npm install @trymellon/js
49
49
 
50
50
  ---
51
51
 
52
+ ## Framework support & entry points
53
+
54
+ The SDK is **framework-agnostic**. Use the main entry for Vanilla JS, Svelte, or any environment; use framework-specific entry points for React, Vue, and Angular to get hooks/services and tree-shaking.
55
+
56
+ | Entry point | Use case | Exports |
57
+ |-------------|----------|---------|
58
+ | `@trymellon/js` | Vanilla JS, Svelte, Node, or any bundler | `TryMellon`, `TryMellon.isSupported()`, `Result`, `ok`, `err`, `isTryMellonError`, types |
59
+ | `@trymellon/js/react` | React 18+ | `TryMellonProvider`, `useTryMellon`, `useRegister`, `useAuthenticate` |
60
+ | `@trymellon/js/vue` | Vue 3 (Composition API) | `provideTryMellon`, `useTryMellon`, `useRegister`, `useAuthenticate`, `TryMellonKey` |
61
+ | `@trymellon/js/angular` | Angular (standalone or NgModule) | `TryMellonService`, `provideTryMellonConfig`, `TRYMELLON_CONFIG` |
62
+
63
+ **Runtime:** ESM and CJS supported. For UMD/script tag use `@trymellon/js/umd` or the built `dist/index.global.js` (exposes `window.TryMellon`).
64
+
65
+ ### React
66
+
67
+ ```bash
68
+ npm install @trymellon/js
69
+ ```
70
+
71
+ ```tsx
72
+ import { TryMellon } from '@trymellon/js'
73
+ import { TryMellonProvider, useTryMellon, useRegister, useAuthenticate } from '@trymellon/js/react'
74
+
75
+ const client = new TryMellon({ appId: 'app_live_xxxx', publishableKey: 'key_live_xxxx' })
76
+
77
+ function App() {
78
+ return (
79
+ <TryMellonProvider client={client}>
80
+ <LoginForm />
81
+ </TryMellonProvider>
82
+ )
83
+ }
84
+
85
+ function LoginForm() {
86
+ const { execute: register, loading } = useRegister()
87
+ const { execute: authenticate } = useAuthenticate()
88
+
89
+ const onRegister = () => register({ externalUserId: 'user_123' })
90
+ const onLogin = () => authenticate({ externalUserId: 'user_123' })
91
+
92
+ return (
93
+ <>
94
+ <button onClick={onRegister} disabled={loading}>Register passkey</button>
95
+ <button onClick={onLogin} disabled={loading}>Sign in</button>
96
+ </>
97
+ )
98
+ }
99
+ ```
100
+
101
+ - **Requirements:** React 18+. Create a `TryMellon` instance (e.g. at app root), wrap your app (or auth subtree) with `TryMellonProvider` passing `client={client}`; then use `useTryMellon()`, `useRegister()`, and `useAuthenticate()` in children.
102
+
103
+ ### Vue
104
+
105
+ ```bash
106
+ npm install @trymellon/js
107
+ ```
108
+
109
+ ```vue
110
+ <script setup lang="ts">
111
+ import { TryMellon } from '@trymellon/js'
112
+ import { provideTryMellon, useTryMellon, useRegister, useAuthenticate } from '@trymellon/js/vue'
113
+
114
+ const client = new TryMellon({ appId: 'app_live_xxxx', publishableKey: 'key_live_xxxx' })
115
+ provideTryMellon(client)
116
+
117
+ const { execute: register, loading } = useRegister()
118
+ const { execute: authenticate } = useAuthenticate()
119
+
120
+ const onRegister = () => register({ externalUserId: 'user_123' })
121
+ const onLogin = () => authenticate({ externalUserId: 'user_123' })
122
+ </script>
123
+
124
+ <template>
125
+ <button @click="onRegister" :disabled="loading">Register passkey</button>
126
+ <button @click="onLogin" :disabled="loading">Sign in</button>
127
+ </template>
128
+ ```
129
+
130
+ - **Requirements:** Vue 3 with Composition API. Create a `TryMellon` instance and call `provideTryMellon(client)` once (e.g. in root or a parent); then use `useTryMellon()`, `useRegister()`, and `useAuthenticate()` in components.
131
+
132
+ ### Angular
133
+
134
+ ```bash
135
+ npm install @trymellon/js
136
+ ```
137
+
138
+ In your app config (e.g. `app.config.ts` or root module):
139
+
140
+ ```typescript
141
+ import { provideTryMellonConfig } from '@trymellon/js/angular'
142
+
143
+ export const appConfig = {
144
+ providers: [
145
+ provideTryMellonConfig({
146
+ appId: 'app_live_xxxx',
147
+ publishableKey: 'key_live_xxxx',
148
+ }),
149
+ ],
150
+ }
151
+ ```
152
+
153
+ In a component or service:
154
+
155
+ ```typescript
156
+ import { TryMellonService } from '@trymellon/js/angular'
157
+
158
+ @Injectable({ providedIn: 'root' })
159
+ export class AuthService {
160
+ private tryMellon = inject(TryMellonService)
161
+
162
+ register(userId: string) {
163
+ return this.tryMellon.client.register({ externalUserId: userId })
164
+ }
165
+
166
+ authenticate(userId: string) {
167
+ return this.tryMellon.client.authenticate({ externalUserId: userId })
168
+ }
169
+ }
170
+ ```
171
+
172
+ - **Requirements:** Angular (standalone or NgModule). Add `provideTryMellonConfig(config)` to your app `providers`; inject `TryMellonService` and use `.client` for `register()`, `authenticate()`, and other methods.
173
+
174
+ ### Vanilla JavaScript
175
+
176
+ Use the main entry and instantiate `TryMellon` directly (see Quickstart below). Works in any ES module or CJS environment. For script-tag usage, use the UMD build: `@trymellon/js/umd` or `dist/index.global.js`; the global is `window.TryMellon`.
177
+
178
+ ### Svelte (and other frameworks)
179
+
180
+ No dedicated adapter. Use the **main entry** `@trymellon/js`: create one `TryMellon` instance (e.g. in a module or store) and call `register()` / `authenticate()` from your components. Same API as Quickstart; no provider required.
181
+
182
+ ---
183
+
52
184
  ## Quickstart (5 minutes)
53
185
 
54
186
  ```bash
@@ -58,21 +190,29 @@ npm install @trymellon/js
58
190
  ```typescript
59
191
  import { TryMellon } from '@trymellon/js'
60
192
 
61
- const client = new TryMellon({
193
+ // 1. Initialize safely (Factory Pattern)
194
+ const clientResult = TryMellon.create({
62
195
  appId: 'app_live_xxxx', // From your TryMellon dashboard
63
196
  publishableKey: 'key_live_xxxx', // Application API key
64
197
  })
65
198
 
66
- // Register passkey (camelCase recommended in options)
199
+ if (!clientResult.ok) {
200
+ console.error('Invalid config:', clientResult.error.message);
201
+ throw clientResult.error;
202
+ }
203
+
204
+ const client = clientResult.value;
205
+
206
+ // 2. Register passkey (camelCase recommended in options)
67
207
  const registerResult = await client.register({ externalUserId: 'user_123' })
68
208
  if (registerResult.ok) {
69
- console.log('Session token:', registerResult.value.session_token)
209
+ console.log('Session token:', registerResult.value.sessionToken)
70
210
  }
71
211
 
72
- // Authenticate
212
+ // 3. Authenticate
73
213
  const authResult = await client.authenticate({ externalUserId: 'user_123' })
74
214
  if (authResult.ok) {
75
- console.log('Session token:', authResult.value.session_token)
215
+ console.log('Session token:', authResult.value.sessionToken)
76
216
  }
77
217
  ```
78
218
 
@@ -107,6 +247,41 @@ const client = new TryMellon({
107
247
 
108
248
  ---
109
249
 
250
+ ## Sandbox / development mode
251
+
252
+ For local development or testing the integration flow without a real backend or WebAuthn (e.g. no passkey hardware), enable **sandbox mode**. With `sandbox: true`, `register()` and `authenticate()` return immediately with a fixed session token and a demo user—no API or WebAuthn calls.
253
+
254
+ **Configuration:**
255
+
256
+ - `sandbox` (optional): Set to `true` to enable sandbox mode.
257
+ - `sandboxToken` (optional): Custom token to return. If not set, the exported constant `SANDBOX_SESSION_TOKEN` is used.
258
+
259
+ **Exported constant:** Import `SANDBOX_SESSION_TOKEN` from `@trymellon/js` so your backend can recognize the sandbox token in development. **Your backend MUST NOT accept this token in production**—only in development. See [Backend validation](https://trymellon.com/docs/backend-validation) for the hook contract.
260
+
261
+ **Example:**
262
+
263
+ ```typescript
264
+ import { TryMellon, SANDBOX_SESSION_TOKEN } from '@trymellon/js'
265
+
266
+ const client = new TryMellon({
267
+ sandbox: true,
268
+ appId: 'sandbox',
269
+ publishableKey: 'sandbox',
270
+ })
271
+
272
+ const result = await client.authenticate({ externalUserId: 'dev_user_1' })
273
+ if (result.ok) {
274
+ // result.value.sessionToken === SANDBOX_SESSION_TOKEN
275
+ await fetch('/api/login', {
276
+ method: 'POST',
277
+ headers: { 'Content-Type': 'application/json' },
278
+ body: JSON.stringify({ sessionToken: result.value.sessionToken }),
279
+ })
280
+ }
281
+ ```
282
+
283
+ ---
284
+
110
285
  ## Basic usage
111
286
 
112
287
  ### Check WebAuthn support
@@ -136,7 +311,7 @@ await fetch('/api/login', {
136
311
  method: 'POST',
137
312
  headers: { 'Content-Type': 'application/json' },
138
313
  body: JSON.stringify({
139
- sessionToken: result.value.session_token
314
+ sessionToken: result.value.sessionToken
140
315
  })
141
316
  })
142
317
  ```
@@ -152,12 +327,12 @@ await fetch('/api/login', {
152
327
  ```typescript
153
328
  {
154
329
  success: true,
155
- credential_id: string,
330
+ credentialId: string,
156
331
  status: string,
157
- session_token: string,
332
+ sessionToken: string,
158
333
  user: {
159
- user_id: string,
160
- external_user_id: string,
334
+ userId: string,
335
+ externalUserId: string,
161
336
  email?: string,
162
337
  metadata?: Record<string, unknown>
163
338
  }
@@ -177,7 +352,7 @@ await fetch('/api/login', {
177
352
  method: 'POST',
178
353
  headers: { 'Content-Type': 'application/json' },
179
354
  body: JSON.stringify({
180
- sessionToken: result.session_token
355
+ sessionToken: result.value.sessionToken
181
356
  })
182
357
  })
183
358
  ```
@@ -193,10 +368,10 @@ await fetch('/api/login', {
193
368
  ```typescript
194
369
  {
195
370
  authenticated: boolean,
196
- session_token: string,
371
+ sessionToken: string,
197
372
  user: {
198
- user_id: string,
199
- external_user_id: string,
373
+ userId: string,
374
+ externalUserId: string,
200
375
  email?: string,
201
376
  metadata?: Record<string, unknown>
202
377
  },
@@ -347,6 +522,62 @@ async function authenticateWithEmail(userId: string) {
347
522
 
348
523
  ---
349
524
 
525
+ ## Cross-Device Authentication (QR Login)
526
+
527
+ Enable users to sign in on a desktop device by scanning a QR code with their mobile phone (where their passkey is stored).
528
+
529
+ ### 1. Desktop: Initialize and Show QR
530
+
531
+ ```typescript
532
+ // Initialize session
533
+ const initResult = await client.auth.crossDevice.init()
534
+ if (!initResult.ok) { console.error(initResult.error); return }
535
+
536
+ const { session_id, qr_url } = initResult.value
537
+
538
+ // Show QR code with `qr_url`
539
+ renderQrCode(qr_url)
540
+
541
+ // Start polling for approval
542
+ // Use AbortController to cancel if user leaves the page
543
+ const controller = new AbortController()
544
+
545
+ const pollResult = await client.auth.crossDevice.waitForSession(
546
+ session_id,
547
+ controller.signal
548
+ )
549
+
550
+ if (!pollResult.ok) {
551
+ if (pollResult.error.code === 'TIMEOUT') {
552
+ showError('QR code expired')
553
+ }
554
+ return
555
+ }
556
+
557
+ // Success!
558
+ console.log('Session token:', pollResult.value.sessionToken)
559
+ ```
560
+
561
+ ### 2. Mobile: Approve Login
562
+
563
+ When the user scans the QR code, your mobile web app should handle the URL (containing `session_id`) and call `approve`:
564
+
565
+ ```typescript
566
+ // Extract session_id from URL query params
567
+ const sessionId = getSessionIdFromUrl()
568
+
569
+ // Trigger WebAuthn flow on mobile
570
+ const approveResult = await client.auth.crossDevice.approve(sessionId)
571
+
572
+ if (approveResult.ok) {
573
+ showSuccess('Process complete! Check your desktop.')
574
+ } else {
575
+ showError('Failed to approve login: ' + approveResult.error.message)
576
+ }
577
+ ```
578
+
579
+ ---
580
+
350
581
  ## Result type
351
582
 
352
583
  The SDK exports the `Result<T, E>` type and the `ok(value)` and `err(error)` helpers for typing and building results (useful in tests or utilities):
@@ -486,15 +717,16 @@ Then create your own session in your system.
486
717
 
487
718
  ## Features
488
719
 
489
- * ✅ **Zero runtime dependencies** – No external runtime dependencies
490
- * ✅ **TypeScript first** – Full types and strict mode
491
- * ✅ **Framework agnostic** – Works with React, Vue, Angular, Vanilla JS, etc.
720
+ * ✅ **Zero runtime dependencies** – No external runtime dependencies in the core bundle
721
+ * ✅ **TypeScript first** – Full types and strict mode; all entry points typed
722
+ * ✅ **Framework support** – Dedicated entry points: `@trymellon/js` (core), `@trymellon/js/react`, `@trymellon/js/vue`, `@trymellon/js/angular`; Vanilla and Svelte use core
492
723
  * ✅ **Automatic retries** – Exponential backoff for transient errors
493
724
  * ✅ **Thorough validation** – Input and API response validation
494
725
  * ✅ **Robust error handling** – Typed, descriptive errors
495
726
  * ✅ **Events for UX** – Event system for spinners and analytics
496
727
  * ✅ **Email fallback** – OTP by email when WebAuthn is unavailable
497
728
  * ✅ **Operation cancellation** – AbortSignal support
729
+ * ✅ **Cross-Device Auth** – QR Login flow support (Desktop to Mobile)
498
730
  * ✅ **Automatic detection** – Origin and WebAuthn support detected automatically
499
731
 
500
732
  ---
@@ -581,10 +813,31 @@ The SDK can send anonymous telemetry (event + latency, no user identifiers) when
581
813
 
582
814
  ---
583
815
 
816
+ ## Specification summary (for project ingestion)
817
+
818
+ Projects integrating this SDK should document in their README:
819
+
820
+ - **SDK:** `@trymellon/js` (and optionally `/react`, `/vue`, `/angular` if using those entry points)
821
+ - **Node:** >= 18 (per `engines`)
822
+ - **Browsers:** WebAuthn-capable (Chrome, Safari, Firefox, Edge); HTTPS required except `localhost`
823
+ - **Config:** `appId` and `publishableKey` from TryMellon dashboard; optional `apiBaseUrl` for self-hosted API
824
+ - **Backend:** Must validate `session_token` via TryMellon API (`GET /v1/sessions/validate`) and create own session
825
+
826
+ Framework-specific: React uses `TryMellonProvider` + hooks; Vue uses `provideTryMellon` + composables; Angular uses `provideTryMellonConfig` + `TryMellonService`; Vanilla/Svelte use core `TryMellon` only.
827
+
828
+ ---
829
+
830
+ ## Contact & landing
831
+
832
+ - **Landing:** [https://trymellon-landing.pages.dev/](https://trymellon-landing.pages.dev/)
833
+ - **Contact:** [siliangrove@gmail.com](mailto:siliangrove@gmail.com) — Sales inquiries by email only.
834
+
835
+ ---
836
+
584
837
  ## Additional documentation
585
838
 
586
839
  - [API Reference](./documentation/API.md) – Full API reference
587
- - [Usage examples](./documentation/EXAMPLES.md) – Practical integration examples
840
+ - [Usage examples](./documentation/EXAMPLES.md) – Practical integration examples (React, Vue, Vanilla, events, fallback)
588
841
  - [Contributing](./documentation/CONTRIBUTING.md) – How to contribute (including running tests, coverage, Angular, E2E, audit and workflow lint locally)
589
842
  - [CI standards (fintech)](./documentation/CI-FINTECH-STANDARDS.md) – Coverage, security, E2E and workflow validation criteria
590
843
 
package/dist/angular.cjs CHANGED
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- "use strict";var Fe=Object.create;var C=Object.defineProperty;var Ee=Object.getOwnPropertyDescriptor;var Le=Object.getOwnPropertyNames;var Ke=Object.prototype.hasOwnProperty;var be=(e,r)=>(r=Symbol[e])?r:Symbol.for("Symbol."+e),F=e=>{throw TypeError(e)};var je=(e,r,t)=>r in e?C(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var Re=(e,r)=>C(e,"name",{value:r,configurable:!0});var qe=(e,r)=>{for(var t in r)C(e,t,{get:r[t],enumerable:!0})},Ve=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Le(r))!Ke.call(e,s)&&s!==t&&C(e,s,{get:()=>r[s],enumerable:!(n=Ee(r,s))||n.enumerable});return e};var We=e=>Ve(C({},"__esModule",{value:!0}),e);var _e=e=>[,,,Fe(e?.[be("metadata")]??null)],Te=["class","method","getter","setter","accessor","field","value","get","set"],U=e=>e!==void 0&&typeof e!="function"?F("Function expected"):e,Be=(e,r,t,n,s)=>({kind:Te[e],name:r,metadata:n,addInitializer:i=>t._?F("Already initialized"):s.push(U(i||null))}),Ye=(e,r)=>je(r,be("metadata"),e[3]),ve=(e,r,t,n)=>{for(var s=0,i=e[r>>1],u=i&&i.length;s<u;s++)r&1?i[s].call(t):n=i[s].call(t,n);return n},Ae=(e,r,t,n,s,i)=>{var u,p,g,y,m,d=r&7,_=!!(r&8),R=!!(r&16),E=d>3?e.length+1:d?_?1:2:0,S=Te[d+5],N=d>3&&(e[E-1]=[]),z=e[E]||(e[E]=[]),A=d&&(!R&&!_&&(s=s.prototype),d<5&&(d>3||!R)&&Ee(d<4?s:{get[t](){return ye(this,i)},set[t](v){return he(this,i,v)}},t));d?R&&d<4&&Re(i,(d>2?"set ":d>1?"get ":"")+t):Re(s,t);for(var J=n.length-1;J>=0;J--)y=Be(d,t,g={},e[3],z),d&&(y.static=_,y.private=R,m=y.access={has:R?v=>He(s,v):v=>t in v},d^3&&(m.get=R?v=>(d^1?ye:Ge)(v,s,d^4?i:A.get):v=>v[t]),d>2&&(m.set=R?(v,Z)=>he(v,s,Z,d^4?i:A.set):(v,Z)=>v[t]=Z)),p=(0,n[J])(d?d<4?R?i:A[S]:d>4?void 0:{get:A.get,set:A.set}:s,y),g._=1,d^4||p===void 0?U(p)&&(d>4?N.unshift(p):d?R?i=p:A[S]=p:s=p):typeof p!="object"||p===null?F("Object expected"):(U(u=p.get)&&(A.get=u),U(u=p.set)&&(A.set=u),U(u=p.init)&&N.unshift(u));return d||Ye(e,s),A&&C(s,t,A),R?d^4?i:A:s};var Q=(e,r,t)=>r.has(e)||F("Cannot "+t),He=(e,r)=>Object(r)!==r?F('Cannot use the "in" operator on this value'):e.has(r),ye=(e,r,t)=>(Q(e,r,"read from private field"),t?t.call(e):r.get(e));var he=(e,r,t,n)=>(Q(e,r,"write to private field"),n?n.call(e,t):r.set(e,t),t),Ge=(e,r,t)=>(Q(e,r,"access private method"),t);var hr={};qe(hr,{TRYMELLON_CONFIG:()=>K,TryMellonService:()=>M,provideTryMellonConfig:()=>yr});module.exports=We(hr);var D=require("@angular/core");var h=e=>({ok:!0,value:e}),c=e=>({ok:!1,error:e});var j=class e extends Error{code;details;isTryMellonError=!0;constructor(r,t,n){super(t),this.name="TryMellonError",this.code=r,this.details=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}},$e={NOT_SUPPORTED:"WebAuthn is not supported in this environment",USER_CANCELLED:"User cancelled the operation",PASSKEY_NOT_FOUND:"Passkey not found",SESSION_EXPIRED:"Session has expired",NETWORK_FAILURE:"Network request failed",INVALID_ARGUMENT:"Invalid argument provided",TIMEOUT:"Operation timed out",ABORTED:"Operation was aborted",UNKNOWN_ERROR:"An unknown error occurred"};function b(e,r,t){return new j(e,r??$e[e],t)}function Xe(e){return e instanceof j||typeof e=="object"&&e!==null&&"isTryMellonError"in e&&e.isTryMellonError===!0}function ee(){return b("NOT_SUPPORTED")}function I(e,r){return b("INVALID_ARGUMENT",`Invalid argument: ${e} - ${r}`,{field:e,reason:r})}function Ie(e){return b("UNKNOWN_ERROR",`Failed to ${e} credential`,{operation:e})}function re(e){return b("NOT_SUPPORTED",`No base64 ${e==="encode"?"encoding":"decoding"} available`,{type:e})}function Se(e,r){try{let t=new URL(e);if(t.protocol!=="https:"&&t.protocol!=="http:")throw I(r,"must use http or https protocol")}catch(t){throw Xe(t)?t:I(r,"must be a valid URL")}}function q(e,r,t,n){if(e<t||e>n)throw I(r,`must be between ${t} and ${n}`)}function V(e,r){if(typeof e!="string"||e.length===0)throw I(r,"must be a non-empty string");if(!/^[A-Za-z0-9_-]+$/.test(e))throw I(r,"must be a valid base64url string")}var ze={NotAllowedError:"USER_CANCELLED",AbortError:"ABORTED",NotSupportedError:"NOT_SUPPORTED",SecurityError:"NOT_SUPPORTED",InvalidStateError:"UNKNOWN_ERROR",UnknownError:"UNKNOWN_ERROR"};function T(e){if(e instanceof DOMException){let r=e.name,t=e.message||"WebAuthn operation failed",n=ze[r]??"UNKNOWN_ERROR";return b(n,t,{originalError:e})}return e instanceof Error?b("UNKNOWN_ERROR",e.message,{originalError:e}):b("UNKNOWN_ERROR","An unknown error occurred",{originalError:e})}function f(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function l(e){return typeof e=="string"}function P(e){return typeof e=="number"&&Number.isFinite(e)}function W(e){return typeof e=="boolean"}function w(e){return Array.isArray(e)}function o(e,r){return c(b("NETWORK_FAILURE",e,{...r,originalData:r?.originalData}))}function a(e,r){return e[r]}function te(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"session_id");if(!l(r))return o("Invalid API response: session_id must be string",{field:"session_id",originalData:e});let t=a(e,"challenge");if(!f(t))return o("Invalid API response: challenge must be object",{field:"challenge",originalData:e});let n=a(t,"rp");if(!f(n)||!l(n.name)||!l(n.id))return o("Invalid API response: challenge.rp must have name and id strings",{originalData:e});let s=a(t,"user");if(!f(s)||!l(s.id)||!l(s.name)||!l(s.displayName))return o("Invalid API response: challenge.user must have id, name, displayName strings",{originalData:e});let i=a(t,"challenge");if(!l(i))return o("Invalid API response: challenge.challenge must be string",{originalData:e});let u=a(t,"pubKeyCredParams");if(!w(u))return o("Invalid API response: challenge.pubKeyCredParams must be array",{originalData:e});for(let m of u)if(!f(m)||m.type!=="public-key"||!P(m.alg))return o("Invalid API response: pubKeyCredParams items must have type and alg",{originalData:e});let p=t.timeout;if(p!==void 0&&!P(p))return o("Invalid API response: challenge.timeout must be number",{originalData:e});let g=t.excludeCredentials;if(g!==void 0){if(!w(g))return o("Invalid API response: excludeCredentials must be array",{originalData:e});for(let m of g)if(!f(m)||m.type!=="public-key"||!l(m.id))return o("Invalid API response: excludeCredentials items must have id and type",{originalData:e})}let y=t.authenticatorSelection;return y!==void 0&&!f(y)?o("Invalid API response: authenticatorSelection must be object",{originalData:e}):h({session_id:r,challenge:{rp:n,user:s,challenge:i,pubKeyCredParams:u,...p!==void 0&&{timeout:p},...g!==void 0&&{excludeCredentials:g},...y!==void 0&&{authenticatorSelection:y}}})}function ne(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"session_id");if(!l(r))return o("Invalid API response: session_id must be string",{field:"session_id",originalData:e});let t=a(e,"challenge");if(!f(t))return o("Invalid API response: challenge must be object",{field:"challenge",originalData:e});let n=a(t,"challenge"),s=a(t,"rpId"),i=t.allowCredentials;if(!l(n))return o("Invalid API response: challenge.challenge must be string",{originalData:e});if(!l(s))return o("Invalid API response: challenge.rpId must be string",{originalData:e});if(i!==void 0&&!w(i))return o("Invalid API response: allowCredentials must be array",{originalData:e});if(i){for(let g of i)if(!f(g)||g.type!=="public-key"||!l(g.id))return o("Invalid API response: allowCredentials items must have id and type",{originalData:e})}let u=t.timeout;if(u!==void 0&&!P(u))return o("Invalid API response: challenge.timeout must be number",{originalData:e});let p=t.userVerification;return p!==void 0&&!["required","preferred","discouraged"].includes(String(p))?o("Invalid API response: userVerification must be required|preferred|discouraged",{originalData:e}):h({session_id:r,challenge:{challenge:n,rpId:s,allowCredentials:i??[],...u!==void 0&&{timeout:u},...p!==void 0&&{userVerification:p}}})}function se(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"credential_id"),t=a(e,"status"),n=a(e,"session_token"),s=a(e,"user");if(!l(r))return o("Invalid API response: credential_id must be string",{field:"credential_id",originalData:e});if(!l(t))return o("Invalid API response: status must be string",{field:"status",originalData:e});if(!l(n))return o("Invalid API response: session_token must be string",{field:"session_token",originalData:e});if(!f(s))return o("Invalid API response: user must be object",{field:"user",originalData:e});let i=a(s,"user_id"),u=a(s,"external_user_id");if(!l(i)||!l(u))return o("Invalid API response: user must have user_id and external_user_id strings",{originalData:e});let p=s.email,g=s.metadata;return p!==void 0&&!l(p)?o("Invalid API response: user.email must be string",{originalData:e}):g!==void 0&&(typeof g!="object"||g===null)?o("Invalid API response: user.metadata must be object",{originalData:e}):h({credential_id:r,status:t,session_token:n,user:{user_id:i,external_user_id:u,...p!==void 0&&{email:p},...g!==void 0&&{metadata:g}}})}function ie(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"authenticated"),t=a(e,"session_token"),n=a(e,"user"),s=a(e,"signals");if(!W(r))return o("Invalid API response: authenticated must be boolean",{field:"authenticated",originalData:e});if(!l(t))return o("Invalid API response: session_token must be string",{field:"session_token",originalData:e});if(!f(n))return o("Invalid API response: user must be object",{field:"user",originalData:e});let i=a(n,"user_id"),u=a(n,"external_user_id");return!l(i)||!l(u)?o("Invalid API response: user must have user_id and external_user_id strings",{originalData:e}):s!==void 0&&!f(s)?o("Invalid API response: signals must be object",{originalData:e}):h({authenticated:r,session_token:t,user:{user_id:i,external_user_id:u,...n.email!==void 0&&{email:n.email},...n.metadata!==void 0&&{metadata:n.metadata}},signals:s})}function oe(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"valid"),t=a(e,"user_id"),n=a(e,"external_user_id"),s=a(e,"tenant_id"),i=a(e,"app_id");return W(r)?l(t)?l(n)?l(s)?l(i)?h({valid:r,user_id:t,external_user_id:n,tenant_id:s,app_id:i}):o("Invalid API response: app_id must be string",{field:"app_id",originalData:e}):o("Invalid API response: tenant_id must be string",{field:"tenant_id",originalData:e}):o("Invalid API response: external_user_id must be string",{field:"external_user_id",originalData:e}):o("Invalid API response: user_id must be string",{field:"user_id",originalData:e}):o("Invalid API response: valid must be boolean",{field:"valid",originalData:e})}function ae(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"sessionToken");return l(r)?h({sessionToken:r}):o("Invalid API response: sessionToken must be string",{field:"sessionToken",originalData:e})}var Je=["pending_passkey","pending_data","completed"],Ze=["pending_data","completed"];function le(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"session_id"),t=a(e,"onboarding_url"),n=a(e,"expires_in");return l(r)?l(t)?P(n)?h({session_id:r,onboarding_url:t,expires_in:n}):o("Invalid API response: expires_in must be number",{field:"expires_in",originalData:e}):o("Invalid API response: onboarding_url must be string",{field:"onboarding_url",originalData:e}):o("Invalid API response: session_id must be string",{field:"session_id",originalData:e})}function ue(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"status"),t=a(e,"onboarding_url"),n=a(e,"expires_in");return!l(r)||!Je.includes(r)?o("Invalid API response: status must be pending_passkey|pending_data|completed",{field:"status",originalData:e}):l(t)?P(n)?h({status:r,onboarding_url:t,expires_in:n}):o("Invalid API response: expires_in must be number",{originalData:e}):o("Invalid API response: onboarding_url must be string",{originalData:e})}function pe(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"session_id"),t=a(e,"status"),n=a(e,"onboarding_url");if(!l(r))return o("Invalid API response: session_id must be string",{field:"session_id",originalData:e});if(t!=="pending_passkey")return o("Invalid API response: status must be pending_passkey",{field:"status",originalData:e});if(!l(n))return o("Invalid API response: onboarding_url must be string",{originalData:e});let s=e.challenge,i;if(s!==void 0){let u=Qe(s);if(!u.ok)return u;i=u.value}return h({session_id:r,status:"pending_passkey",onboarding_url:n,...i!==void 0&&{challenge:i}})}function Qe(e){if(!f(e))return o("Invalid API response: challenge must be object",{originalData:e});let r=a(e,"rp"),t=a(e,"user"),n=a(e,"challenge"),s=a(e,"pubKeyCredParams");if(!f(r)||!l(r.name)||!l(r.id))return o("Invalid API response: challenge.rp must have name and id",{originalData:e});if(!f(t)||!l(t.id)||!l(t.name)||!l(t.displayName))return o("Invalid API response: challenge.user must have id, name, displayName",{originalData:e});if(!l(n))return o("Invalid API response: challenge.challenge must be string",{originalData:e});if(!w(s))return o("Invalid API response: challenge.pubKeyCredParams must be array",{originalData:e});for(let i of s)if(!f(i)||i.type!=="public-key"||!P(i.alg))return o("Invalid API response: pubKeyCredParams items must have type and alg",{originalData:e});return h({rp:r,user:t,challenge:n,pubKeyCredParams:s})}function de(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"session_id"),t=a(e,"status"),n=a(e,"user_id"),s=a(e,"tenant_id");return l(r)?!l(t)||!Ze.includes(t)?o("Invalid API response: status must be pending_data|completed",{originalData:e}):l(n)?l(s)?h({session_id:r,status:t,user_id:n,tenant_id:s}):o("Invalid API response: tenant_id must be string",{originalData:e}):o("Invalid API response: user_id must be string",{originalData:e}):o("Invalid API response: session_id must be string",{originalData:e})}function ce(e){if(!f(e))return o("Invalid API response: expected object",{originalData:e});let r=a(e,"session_id"),t=a(e,"status"),n=a(e,"user_id"),s=a(e,"tenant_id"),i=a(e,"session_token");return l(r)?t!=="completed"?o("Invalid API response: status must be completed",{originalData:e}):!l(n)||!l(s)||!l(i)?o("Invalid API response: user_id, tenant_id, session_token must be strings",{originalData:e}):h({session_id:r,status:"completed",user_id:n,tenant_id:s,session_token:i}):o("Invalid API response: session_id must be string",{originalData:e})}var B=class{constructor(r,t,n={}){this.httpClient=r;this.baseUrl=t;this.defaultHeaders=n}mergeHeaders(r){return{...this.defaultHeaders,...r}}async post(r,t,n){let s=`${this.baseUrl}${r}`,i=await this.httpClient.post(s,t,this.mergeHeaders());return i.ok?n(i.value):c(i.error)}async get(r,t,n){let s=`${this.baseUrl}${r}`,i=await this.httpClient.get(s,this.mergeHeaders(n));return i.ok?t(i.value):c(i.error)}async startRegister(r){return this.post("/v1/passkeys/register/start",r,te)}async startAuth(r){return this.post("/v1/passkeys/auth/start",r,ne)}async finishRegister(r){return this.post("/v1/passkeys/register/finish",r,se)}async finishAuth(r){return this.post("/v1/passkeys/auth/finish",r,ie)}async validateSession(r){return this.get("/v1/sessions/validate",oe,{Authorization:`Bearer ${r}`})}async startEmailFallback(r){let t=`${this.baseUrl}/v1/fallback/email/start`,n=await this.httpClient.post(t,{userId:r},this.mergeHeaders());return n.ok?h(void 0):c(n.error)}async verifyEmailCode(r,t){return this.post("/v1/fallback/email/verify",{userId:r,code:t},ae)}async startOnboarding(r){return this.post("/onboarding/start",r,le)}async getOnboardingStatus(r){return this.get(`/onboarding/${r}/status`,ue)}async getOnboardingRegister(r){return this.get(`/onboarding/${r}/register`,pe)}async registerOnboardingPasskey(r,t){return this.post(`/onboarding/${r}/register-passkey`,t,de)}async completeOnboarding(r,t){return this.post(`/onboarding/${r}/complete`,t,ce)}};var er=3e4;function rr(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2,11)}`}function Oe(e,r){let t=r*Math.pow(2,e);return Math.min(t,er)}function tr(e,r){return e!=="GET"?!1:r>=500||r===429}var Y=class{constructor(r,t=0,n=1e3,s){this.timeoutMs=r;this.maxRetries=t;this.retryDelayMs=n;this.logger=s}async get(r,t){return this.request(r,{method:"GET",headers:t})}async post(r,t,n){return this.request(r,{method:"POST",body:JSON.stringify(t),headers:{"Content-Type":"application/json",...n}})}async request(r,t){let n=(t.method??"GET").toUpperCase(),s=rr(),i=new Headers(t.headers);i.set("X-Request-Id",s),this.logger&&this.logger.debug("request",{requestId:s,url:r,method:n});let u;for(let p=0;p<=this.maxRetries;p++)try{let g=new AbortController,y=setTimeout(()=>g.abort(),this.timeoutMs),m=await fetch(r,{...t,headers:i,signal:g.signal});if(clearTimeout(y),!m.ok){let _;try{_=await m.json()}catch{}let R=_,E=R?.message??m.statusText,S=R?.error??"NETWORK_FAILURE",N=b(S,E,{requestId:s,status:m.status,statusText:m.statusText,data:_});if(tr(n,m.status)&&p<this.maxRetries){u=N,await new Promise(z=>setTimeout(z,Oe(p,this.retryDelayMs)));continue}return c(N)}let d=await m.json();return h(d)}catch(g){if(u=g,n==="GET"&&p<this.maxRetries)await new Promise(m=>setTimeout(m,Oe(p,this.retryDelayMs)));else break}return u instanceof Error&&u.name==="AbortError"?c(b("TIMEOUT","Request timed out",{requestId:s})):c(b("NETWORK_FAILURE",u instanceof Error?u.message:"Request failed",{requestId:s,cause:u}))}};function k(){try{return!(typeof navigator>"u"||!navigator.credentials||typeof PublicKeyCredential>"u")}catch{return!1}}async function nr(){try{return!k()||typeof PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable!="function"?!1:await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return!1}}async function Pe(){let e=k(),r=await nr();return{isPasskeySupported:e,platformAuthenticatorAvailable:r,recommendedFlow:e?"passkey":"fallback"}}function O(e){let r=new Uint8Array(e),t="";for(let s=0;s<r.length;s++)t+=String.fromCharCode(r[s]??0);let n="";if(typeof btoa<"u")n=btoa(t);else if(typeof Buffer<"u")n=Buffer.from(t,"binary").toString("base64");else throw re("encode");return n.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function sr(e){let r=e.replace(/-/g,"+").replace(/_/g,"/"),t=r.length%4;t!==0&&(r+="=".repeat(4-t));let n="";if(typeof atob<"u")n=atob(r);else if(typeof Buffer<"u")n=Buffer.from(r,"base64").toString("binary");else throw re("decode");let s=new Uint8Array(n.length);for(let i=0;i<n.length;i++)s[i]=n.charCodeAt(i);return s}function x(e){let r=sr(e),t=new ArrayBuffer(r.length);return new Uint8Array(t).set(r),t}function L(e,r="create"){if(!e||typeof e!="object"||!("id"in e)||!("rawId"in e)||!("response"in e))throw Ie(r)}function ke(e){return e!==null&&typeof e=="object"&&"clientDataJSON"in e&&e.clientDataJSON instanceof ArrayBuffer}function H(e){if(!e.response)throw b("UNKNOWN_ERROR","Credential response is missing",{credential:e});let r=e.response;if(!ke(r))throw b("UNKNOWN_ERROR","Invalid credential response structure",{response:r});if(!("attestationObject"in r))throw b("UNKNOWN_ERROR","Invalid credential response structure for register: attestationObject is missing",{response:r});let t=r.clientDataJSON,n=r.attestationObject;return{id:e.id,rawId:O(e.rawId),response:{clientDataJSON:O(t),attestationObject:O(n)},type:"public-key"}}function Me(e){if(!e.response)throw b("UNKNOWN_ERROR","Credential response is missing",{credential:e});let r=e.response;if(!ke(r))throw b("UNKNOWN_ERROR","Invalid credential response structure",{response:r});if(!("authenticatorData"in r)||!("signature"in r))throw b("UNKNOWN_ERROR","Invalid credential response structure for auth: authenticatorData or signature is missing",{response:r});let t=r.clientDataJSON,n=r.authenticatorData,s=r.signature,i=r.userHandle;return{id:e.id,rawId:O(e.rawId),response:{authenticatorData:O(n),clientDataJSON:O(t),signature:O(s),...i&&{userHandle:O(i)}},type:"public-key"}}function ge(e,r){try{V(e.challenge,"challenge"),V(e.user.id,"user.id");let t=x(e.challenge),n=x(e.user.id),s={userVerification:"preferred"};e.authenticatorSelection&&(s={...e.authenticatorSelection}),r&&(s={...s,authenticatorAttachment:r});let i={rp:{id:e.rp.id,name:e.rp.name},user:{id:n,name:e.user.name,displayName:e.user.displayName},challenge:t,pubKeyCredParams:e.pubKeyCredParams,...e.timeout!==void 0&&{timeout:e.timeout},attestation:"none",authenticatorSelection:s,...e.excludeCredentials&&{excludeCredentials:e.excludeCredentials.map(u=>({id:x(u.id),type:u.type,...u.transports&&{transports:u.transports}}))}};return h({publicKey:i})}catch(t){return c(T(t))}}function ir(e,r){try{V(e.challenge,"challenge");let t=x(e.challenge);return h({publicKey:{challenge:t,rpId:e.rpId,...e.timeout!==void 0&&{timeout:e.timeout},userVerification:e.userVerification??"preferred",...e.allowCredentials&&{allowCredentials:e.allowCredentials.map(n=>({id:x(n.id),type:n.type,...n.transports&&{transports:n.transports}}))}},...r!==void 0&&{mediation:r}})}catch(t){return c(T(t))}}async function Ce(e,r,t){t.emit("start",{type:"start",operation:"register"});try{let n=e.externalUserId??e.external_user_id;if(!n||typeof n!="string"||n.trim()==="")return c(I("external_user_id","must be provided (use externalUserId or external_user_id)"));if(!k())return c(ee());let s=await r.startRegister({external_user_id:n.trim()});if(!s.ok)return t.emit("error",{type:"error",error:s.error}),c(s.error);let i=s.value,u=i.session_id,p=ge(i.challenge,e.authenticatorType);if(!p.ok)return t.emit("error",{type:"error",error:p.error}),c(p.error);let g=p.value;e.signal&&(g.signal=e.signal);let y;try{y=await navigator.credentials.create(g)}catch(R){let E=T(R);return t.emit("error",{type:"error",error:E}),c(E)}try{L(y,"create")}catch(R){let E=T(R);return t.emit("error",{type:"error",error:E}),c(E)}let m;try{m=H(y)}catch(R){let E=T(R);return t.emit("error",{type:"error",error:E}),c(E)}let d=await r.finishRegister({session_id:u,credential:m});if(!d.ok)return t.emit("error",{type:"error",error:d.error}),c(d.error);let _=d.value;return t.emit("success",{type:"success",operation:"register"}),h({success:!0,credential_id:_.credential_id,status:_.status,session_token:_.session_token,user:_.user})}catch(n){let s=T(n);return t.emit("error",{type:"error",error:s}),c(s)}}async function we(e,r,t){t.emit("start",{type:"start",operation:"authenticate"});try{let n=e.externalUserId??e.external_user_id;if(!n||typeof n!="string"||n.trim()==="")return c(I("external_user_id","must be provided (use externalUserId or external_user_id)"));if(!k())return c(ee());let s=await r.startAuth({external_user_id:n.trim()});if(!s.ok)return t.emit("error",{type:"error",error:s.error}),c(s.error);let i=s.value,u=i.session_id,p=ir(i.challenge,e.mediation);if(!p.ok)return t.emit("error",{type:"error",error:p.error}),c(p.error);let g=p.value;e.signal&&(g.signal=e.signal);let y;try{y=await navigator.credentials.get(g)}catch(R){let E=T(R);return t.emit("error",{type:"error",error:E}),c(E)}try{L(y,"get")}catch(R){let E=T(R);return t.emit("error",{type:"error",error:E}),c(E)}let m;try{m=Me(y)}catch(R){let E=T(R);return t.emit("error",{type:"error",error:E}),c(E)}let d=await r.finishAuth({session_id:u,credential:m});if(!d.ok)return t.emit("error",{type:"error",error:d.error}),c(d.error);let _=d.value;return t.emit("success",{type:"success",operation:"authenticate"}),h({authenticated:_.authenticated,session_token:_.session_token,user:_.user,signals:_.signals})}catch(n){let s=T(n);return t.emit("error",{type:"error",error:s}),c(s)}}var or=2e3,ar=60,G=class{constructor(r){this.apiClient=r}async startFlow(r){let t=await this.apiClient.startOnboarding({user_role:r.user_role});if(!t.ok)return c(t.error);let{session_id:n}=t.value;for(let s=0;s<ar;s++){await new Promise(g=>setTimeout(g,or));let i=await this.apiClient.getOnboardingStatus(n);if(!i.ok)return c(i.error);let u=i.value.status,p=i.value.onboarding_url;if(u==="pending_passkey"){let g=await this.apiClient.getOnboardingRegister(n);if(!g.ok)return c(g.error);let y=g.value;if(!y.challenge)return c(b("NOT_SUPPORTED","Onboarding requires user action - complete passkey registration at the provided onboarding_url",{onboarding_url:p}));let m=ge(y.challenge);if(!m.ok)return c(m.error);let d;try{d=await navigator.credentials.create(m.value)}catch(S){return c(T(S))}try{L(d,"create")}catch(S){return c(T(S))}let _;try{_=H(d)}catch(S){return c(T(S))}let R=await this.apiClient.registerOnboardingPasskey(n,{credential:_,challenge:y.challenge.challenge});return R.ok?await this.apiClient.completeOnboarding(n,{company_name:r.company_name}):c(R.error)}if(u==="completed")return await this.apiClient.completeOnboarding(n,{company_name:r.company_name})}return c(b("TIMEOUT","Onboarding timed out"))}};var $=class{handlers;constructor(){this.handlers=new Map}on(r,t){let n=this.handlers.get(r);return n||(n=new Set,this.handlers.set(r,n)),n.add(t),()=>{this.off(r,t)}}off(r,t){let n=this.handlers.get(r);n&&(n.delete(t),n.size===0&&this.handlers.delete(r))}emit(r,t){let n=this.handlers.get(r);n&&n.forEach(s=>{try{s(t)}catch{}})}removeAllListeners(){this.handlers.clear()}};var xe="https://api.trymellonauth.com",De="https://api.trymellonauth.com/v1/telemetry";function Ne(e){return{async send(r){let t=JSON.stringify(r);if(typeof navigator<"u"&&typeof navigator.sendBeacon=="function"){navigator.sendBeacon(e,t);return}typeof fetch<"u"&&await fetch(e,{method:"POST",body:t,headers:{"Content-Type":"application/json"},keepalive:!0})}}}function me(e,r){return{event:e,latencyMs:r,ok:!0}}var X=class{apiClient;eventEmitter;telemetrySender;onboarding;constructor(r){let t=r.appId,n=r.publishableKey;if(!t||typeof t!="string"||t.trim()==="")throw I("appId","must be a non-empty string");if(!n||typeof n!="string"||n.trim()==="")throw I("publishableKey","must be a non-empty string");let s=r.apiBaseUrl??xe;Se(s,"apiBaseUrl");let i=r.timeoutMs??3e4;q(i,"timeoutMs",1e3,3e5),r.maxRetries!==void 0&&q(r.maxRetries,"maxRetries",0,10),r.retryDelayMs!==void 0&&q(r.retryDelayMs,"retryDelayMs",100,1e4);let u=r.maxRetries??3,p=r.retryDelayMs??1e3,g=new Y(i,u,p,r.logger),y={"X-App-Id":t.trim(),Authorization:`Bearer ${n.trim()}`};this.apiClient=new B(g,s,y),this.onboarding=new G(this.apiClient),this.eventEmitter=new $,r.enableTelemetry&&(this.telemetrySender=r.telemetrySender??Ne(r.telemetryEndpoint??De))}static isSupported(){return k()}async register(r){let t=Date.now(),n=await Ce(r,this.apiClient,this.eventEmitter);return n.ok&&this.telemetrySender&&this.telemetrySender.send(me("register",Date.now()-t)).catch(()=>{}),n}async authenticate(r){let t=Date.now(),n=await we(r,this.apiClient,this.eventEmitter);return n.ok&&this.telemetrySender&&this.telemetrySender.send(me("authenticate",Date.now()-t)).catch(()=>{}),n}async validateSession(r){return this.apiClient.validateSession(r)}async getStatus(){return Pe()}on(r,t){return this.eventEmitter.on(r,t)}version(){return"1.1.3"}fallback={email:{start:async r=>this.apiClient.startEmailFallback(r.userId),verify:async r=>this.apiClient.verifyEmailCode(r.userId,r.code)}}};var K=new D.InjectionToken("TRYMELLON_CONFIG"),Ue,fe;Ue=[(0,D.Injectable)({providedIn:"root"})];var M=class{config=(0,D.inject)(K,{optional:!0});_client=null;get client(){if(this._client==null){if(this.config==null)throw new Error("TryMellonService: provide TRYMELLON_CONFIG (e.g. via provideTryMellonConfig(config))");this._client=new X(this.config)}return this._client}};fe=_e(null),M=Ae(fe,0,"TryMellonService",Ue,M),ve(fe,1,M);function yr(e){return{provide:K,useValue:e}}0&&(module.exports={TRYMELLON_CONFIG,TryMellonService,provideTryMellonConfig});
2
+ "use strict";var Je=Object.create;var k=Object.defineProperty;var Ce=Object.getOwnPropertyDescriptor;var Ze=Object.getOwnPropertyNames;var Qe=Object.prototype.hasOwnProperty;var xe=(e,r)=>(r=Symbol[e])?r:Symbol.for("Symbol."+e),K=e=>{throw TypeError(e)};var er=(e,r,t)=>r in e?k(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var Ae=(e,r)=>k(e,"name",{value:r,configurable:!0});var rr=(e,r)=>{for(var t in r)k(e,t,{get:r[t],enumerable:!0})},tr=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Ze(r))!Qe.call(e,s)&&s!==t&&k(e,s,{get:()=>r[s],enumerable:!(n=Ce(r,s))||n.enumerable});return e};var nr=e=>tr(k({},"__esModule",{value:!0}),e);var Pe=e=>[,,,Je(e?.[xe("metadata")]??null)],Me=["class","method","getter","setter","accessor","field","value","get","set"],L=e=>e!==void 0&&typeof e!="function"?K("Function expected"):e,sr=(e,r,t,n,s)=>({kind:Me[e],name:r,metadata:n,addInitializer:i=>t._?K("Already initialized"):s.push(L(i||null))}),ir=(e,r)=>er(r,xe("metadata"),e[3]),De=(e,r,t,n)=>{for(var s=0,i=e[r>>1],l=i&&i.length;s<l;s++)r&1?i[s].call(t):n=i[s].call(t,n);return n},ke=(e,r,t,n,s,i)=>{var l,c,u,h,m,g=r&7,I=!!(r&8),v=!!(r&16),D=g>3?e.length+1:g?I?1:2:0,A=Me[g+5],F=g>3&&(e[D-1]=[]),Z=e[D]||(e[D]=[]),T=g&&(!v&&!I&&(s=s.prototype),g<5&&(g>3||!v)&&Ce(g<4?s:{get[t](){return Se(this,i)},set[t](_){return Oe(this,i,_)}},t));g?v&&g<4&&Ae(i,(g>2?"set ":g>1?"get ":"")+t):Ae(s,t);for(var Q=n.length-1;Q>=0;Q--)h=sr(g,t,u={},e[3],Z),g&&(h.static=I,h.private=v,m=h.access={has:v?_=>or(s,_):_=>t in _},g^3&&(m.get=v?_=>(g^1?Se:ar)(_,s,g^4?i:T.get):_=>_[t]),g>2&&(m.set=v?(_,ee)=>Oe(_,s,ee,g^4?i:T.set):(_,ee)=>_[t]=ee)),c=(0,n[Q])(g?g<4?v?i:T[A]:g>4?void 0:{get:T.get,set:T.set}:s,h),u._=1,g^4||c===void 0?L(c)&&(g>4?F.unshift(c):g?v?i=c:T[A]=c:s=c):typeof c!="object"||c===null?K("Object expected"):(L(l=c.get)&&(T.get=l),L(l=c.set)&&(T.set=l),L(l=c.init)&&F.unshift(l));return g||ir(e,s),T&&k(s,t,T),v?g^4?i:T:s};var re=(e,r,t)=>r.has(e)||K("Cannot "+t),or=(e,r)=>Object(r)!==r?K('Cannot use the "in" operator on this value'):e.has(r),Se=(e,r,t)=>(re(e,r,"read from private field"),t?t.call(e):r.get(e));var Oe=(e,r,t,n)=>(re(e,r,"write to private field"),n?n.call(e,t):r.set(e,t),t),ar=(e,r,t)=>(re(e,r,"access private method"),t);var Ar={};rr(Ar,{TRYMELLON_CONFIG:()=>q,TryMellonService:()=>M,provideTryMellonConfig:()=>Ir});module.exports=nr(Ar);var U=require("@angular/core");var f=e=>({ok:!0,value:e}),a=e=>({ok:!1,error:e});var j=class e extends Error{code;details;isTryMellonError=!0;constructor(r,t,n){super(t),this.name="TryMellonError",this.code=r,this.details=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}},lr={NOT_SUPPORTED:"WebAuthn is not supported in this environment",USER_CANCELLED:"User cancelled the operation",PASSKEY_NOT_FOUND:"Passkey not found",SESSION_EXPIRED:"Session has expired",NETWORK_FAILURE:"Network request failed",INVALID_ARGUMENT:"Invalid argument provided",TIMEOUT:"Operation timed out",ABORTED:"Operation was aborted",ABORT_ERROR:"Operation aborted by user or timeout",UNKNOWN_ERROR:"An unknown error occurred"};function y(e,r,t){return new j(e,r??lr[e],t)}function te(e){return e instanceof j||typeof e=="object"&&e!==null&&"isTryMellonError"in e&&e.isTryMellonError===!0}function ne(){return y("NOT_SUPPORTED")}function b(e,r){return y("INVALID_ARGUMENT",`Invalid argument: ${e} - ${r}`,{field:e,reason:r})}function we(e){return y("UNKNOWN_ERROR",`Failed to ${e} credential`,{operation:e})}function se(e){return y("NOT_SUPPORTED",`No base64 ${e==="encode"?"encoding":"decoding"} available`,{type:e})}function ie(e,r){try{let t=new URL(e);if(t.protocol!=="https:"&&t.protocol!=="http:")throw b(r,"must use http or https protocol")}catch(t){throw te(t)?t:b(r,"must be a valid URL")}}function C(e,r,t,n){if(!Number.isFinite(e))throw b(r,"must be a finite number");if(e<t||e>n)throw b(r,`must be between ${t} and ${n}`)}function B(e,r){if(typeof e!="string"||e.length===0)throw b(r,"must be a non-empty string");if(!/^[A-Za-z0-9_-]+$/.test(e))throw b(r,"must be a valid base64url string")}var ur={NotAllowedError:"USER_CANCELLED",AbortError:"ABORTED",NotSupportedError:"NOT_SUPPORTED",SecurityError:"NOT_SUPPORTED",InvalidStateError:"UNKNOWN_ERROR",UnknownError:"UNKNOWN_ERROR"};function E(e){if(e instanceof DOMException){let r=e.name,t=e.message||"WebAuthn operation failed",n=ur[r]??"UNKNOWN_ERROR";return y(n,t,{originalError:e})}return e instanceof Error?y("UNKNOWN_ERROR",e.message,{originalError:e}):y("UNKNOWN_ERROR","An unknown error occurred",{originalError:e})}function R(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function p(e){return typeof e=="string"}function O(e){return typeof e=="number"&&Number.isFinite(e)}function V(e){return typeof e=="boolean"}function w(e){return Array.isArray(e)}function o(e,r){return a(y("UNKNOWN_ERROR",e,{...r,originalData:r?.originalData}))}function d(e,r){return e[r]}function oe(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"session_id");if(!p(r))return o("Invalid API response: session_id must be string",{field:"session_id",originalData:e});let t=d(e,"challenge");if(!R(t))return o("Invalid API response: challenge must be object",{field:"challenge",originalData:e});let n=d(t,"rp");if(!R(n)||!p(n.name)||!p(n.id))return o("Invalid API response: challenge.rp must have name and id strings",{originalData:e});let s=d(t,"user");if(!R(s)||!p(s.id)||!p(s.name)||!p(s.displayName))return o("Invalid API response: challenge.user must have id, name, displayName strings",{originalData:e});let i=d(t,"challenge");if(!p(i))return o("Invalid API response: challenge.challenge must be string",{originalData:e});let l=d(t,"pubKeyCredParams");if(!w(l))return o("Invalid API response: challenge.pubKeyCredParams must be array",{originalData:e});for(let m of l)if(!R(m)||m.type!=="public-key"||!O(m.alg))return o("Invalid API response: pubKeyCredParams items must have type and alg",{originalData:e});let c=t.timeout;if(c!==void 0&&!O(c))return o("Invalid API response: challenge.timeout must be number",{originalData:e});let u=t.excludeCredentials;if(u!==void 0){if(!w(u))return o("Invalid API response: excludeCredentials must be array",{originalData:e});for(let m of u)if(!R(m)||m.type!=="public-key"||!p(m.id))return o("Invalid API response: excludeCredentials items must have id and type",{originalData:e})}let h=t.authenticatorSelection;return h!==void 0&&!R(h)?o("Invalid API response: authenticatorSelection must be object",{originalData:e}):f({session_id:r,challenge:{rp:n,user:s,challenge:i,pubKeyCredParams:l,...c!==void 0&&{timeout:c},...u!==void 0&&{excludeCredentials:u},...h!==void 0&&{authenticatorSelection:h}}})}function ae(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"session_id");if(!p(r))return o("Invalid API response: session_id must be string",{field:"session_id",originalData:e});let t=d(e,"challenge");if(!R(t))return o("Invalid API response: challenge must be object",{field:"challenge",originalData:e});let n=d(t,"challenge"),s=d(t,"rpId"),i=t.allowCredentials;if(!p(n))return o("Invalid API response: challenge.challenge must be string",{originalData:e});if(!p(s))return o("Invalid API response: challenge.rpId must be string",{originalData:e});if(i!==void 0&&!w(i))return o("Invalid API response: allowCredentials must be array",{originalData:e});if(i){for(let u of i)if(!R(u)||u.type!=="public-key"||!p(u.id))return o("Invalid API response: allowCredentials items must have id and type",{originalData:e})}let l=t.timeout;if(l!==void 0&&!O(l))return o("Invalid API response: challenge.timeout must be number",{originalData:e});let c=t.userVerification;return c!==void 0&&!["required","preferred","discouraged"].includes(String(c))?o("Invalid API response: userVerification must be required|preferred|discouraged",{originalData:e}):f({session_id:r,challenge:{challenge:n,rpId:s,allowCredentials:i??[],...l!==void 0&&{timeout:l},...c!==void 0&&{userVerification:c}}})}function le(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"credential_id"),t=d(e,"status"),n=d(e,"session_token"),s=d(e,"user");if(!p(r))return o("Invalid API response: credential_id must be string",{field:"credential_id",originalData:e});if(!p(t))return o("Invalid API response: status must be string",{field:"status",originalData:e});if(!p(n))return o("Invalid API response: session_token must be string",{field:"session_token",originalData:e});if(!R(s))return o("Invalid API response: user must be object",{field:"user",originalData:e});let i=d(s,"user_id"),l=d(s,"external_user_id");if(!p(i)||!p(l))return o("Invalid API response: user must have user_id and external_user_id strings",{originalData:e});let c=s.email,u=s.metadata;return c!==void 0&&!p(c)?o("Invalid API response: user.email must be string",{originalData:e}):u!==void 0&&(typeof u!="object"||u===null)?o("Invalid API response: user.metadata must be object",{originalData:e}):f({credential_id:r,status:t,session_token:n,user:{user_id:i,external_user_id:l,...c!==void 0&&{email:c},...u!==void 0&&{metadata:u}}})}function ue(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"authenticated"),t=d(e,"session_token"),n=d(e,"user"),s=d(e,"signals");if(!V(r))return o("Invalid API response: authenticated must be boolean",{field:"authenticated",originalData:e});if(!p(t))return o("Invalid API response: session_token must be string",{field:"session_token",originalData:e});if(!R(n))return o("Invalid API response: user must be object",{field:"user",originalData:e});let i=d(n,"user_id"),l=d(n,"external_user_id");return!p(i)||!p(l)?o("Invalid API response: user must have user_id and external_user_id strings",{originalData:e}):s!==void 0&&!R(s)?o("Invalid API response: signals must be object",{originalData:e}):f({authenticated:r,session_token:t,user:{user_id:i,external_user_id:l,...n.email!==void 0&&{email:n.email},...n.metadata!==void 0&&{metadata:n.metadata}},signals:s})}function pe(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"valid"),t=d(e,"user_id"),n=d(e,"external_user_id"),s=d(e,"tenant_id"),i=d(e,"app_id");return V(r)?p(t)?p(n)?p(s)?p(i)?f({valid:r,user_id:t,external_user_id:n,tenant_id:s,app_id:i}):o("Invalid API response: app_id must be string",{field:"app_id",originalData:e}):o("Invalid API response: tenant_id must be string",{field:"tenant_id",originalData:e}):o("Invalid API response: external_user_id must be string",{field:"external_user_id",originalData:e}):o("Invalid API response: user_id must be string",{field:"user_id",originalData:e}):o("Invalid API response: valid must be boolean",{field:"valid",originalData:e})}function de(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"sessionToken");return p(r)?f({sessionToken:r}):o("Invalid API response: sessionToken must be string",{field:"sessionToken",originalData:e})}var pr=["pending_passkey","pending_data","completed"],dr=["pending_data","completed"];function ce(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"session_id"),t=d(e,"onboarding_url"),n=d(e,"expires_in");return p(r)?p(t)?O(n)?f({session_id:r,onboarding_url:t,expires_in:n}):o("Invalid API response: expires_in must be number",{field:"expires_in",originalData:e}):o("Invalid API response: onboarding_url must be string",{field:"onboarding_url",originalData:e}):o("Invalid API response: session_id must be string",{field:"session_id",originalData:e})}function me(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"status"),t=d(e,"onboarding_url"),n=d(e,"expires_in");return!p(r)||!pr.includes(r)?o("Invalid API response: status must be pending_passkey|pending_data|completed",{field:"status",originalData:e}):p(t)?O(n)?f({status:r,onboarding_url:t,expires_in:n}):o("Invalid API response: expires_in must be number",{originalData:e}):o("Invalid API response: onboarding_url must be string",{originalData:e})}function ge(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"session_id"),t=d(e,"status"),n=d(e,"onboarding_url");if(!p(r))return o("Invalid API response: session_id must be string",{field:"session_id",originalData:e});if(t!=="pending_passkey")return o("Invalid API response: status must be pending_passkey",{field:"status",originalData:e});if(!p(n))return o("Invalid API response: onboarding_url must be string",{originalData:e});let s=e.challenge,i;if(s!==void 0){let l=cr(s);if(!l.ok)return l;i=l.value}return f({session_id:r,status:"pending_passkey",onboarding_url:n,...i!==void 0&&{challenge:i}})}function cr(e){if(!R(e))return o("Invalid API response: challenge must be object",{originalData:e});let r=d(e,"rp"),t=d(e,"user"),n=d(e,"challenge"),s=d(e,"pubKeyCredParams");if(!R(r)||!p(r.name)||!p(r.id))return o("Invalid API response: challenge.rp must have name and id",{originalData:e});if(!R(t)||!p(t.id)||!p(t.name)||!p(t.displayName))return o("Invalid API response: challenge.user must have id, name, displayName",{originalData:e});if(!p(n))return o("Invalid API response: challenge.challenge must be string",{originalData:e});if(!w(s))return o("Invalid API response: challenge.pubKeyCredParams must be array",{originalData:e});for(let i of s)if(!R(i)||i.type!=="public-key"||!O(i.alg))return o("Invalid API response: pubKeyCredParams items must have type and alg",{originalData:e});return f({rp:r,user:t,challenge:n,pubKeyCredParams:s})}function fe(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"session_id"),t=d(e,"status"),n=d(e,"user_id"),s=d(e,"tenant_id");return p(r)?!p(t)||!dr.includes(t)?o("Invalid API response: status must be pending_data|completed",{originalData:e}):p(n)?p(s)?f({session_id:r,status:t,user_id:n,tenant_id:s}):o("Invalid API response: tenant_id must be string",{originalData:e}):o("Invalid API response: user_id must be string",{originalData:e}):o("Invalid API response: session_id must be string",{originalData:e})}function Re(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=d(e,"session_id"),t=d(e,"status"),n=d(e,"user_id"),s=d(e,"tenant_id"),i=d(e,"session_token");return p(r)?t!=="completed"?o("Invalid API response: status must be completed",{originalData:e}):!p(n)||!p(s)||!p(i)?o("Invalid API response: user_id, tenant_id, session_token must be strings",{originalData:e}):f({session_id:r,status:"completed",user_id:n,tenant_id:s,session_token:i}):o("Invalid API response: session_id must be string",{originalData:e})}function ye(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=e.session_id,t=e.qr_url,n=e.expires_at;return!p(r)||!p(t)||!p(n)?o("Invalid API response: missing required fields",{originalData:e}):f({session_id:r,qr_url:t,expires_at:n})}function he(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=e.status;return!p(r)||!["pending","authenticated","completed"].includes(r)?o("Invalid API response: invalid status",{originalData:e}):f({status:r,user_id:e.user_id,session_token:e.session_token})}function be(e){if(!R(e))return o("Invalid API response: expected object",{originalData:e});let r=e.options;return R(r)?f({options:r}):o("Invalid API response: options are required",{originalData:e})}var W=class{constructor(r,t,n={}){this.httpClient=r;this.baseUrl=t;this.defaultHeaders=n}mergeHeaders(r){return{...this.defaultHeaders,...r}}async post(r,t,n){let s=`${this.baseUrl}${r}`,i=await this.httpClient.post(s,t,this.mergeHeaders());return i.ok?n(i.value):a(i.error)}async get(r,t,n){let s=`${this.baseUrl}${r}`,i=await this.httpClient.get(s,this.mergeHeaders(n));return i.ok?t(i.value):a(i.error)}async startRegister(r){return this.post("/v1/passkeys/register/start",r,oe)}async startAuth(r){return this.post("/v1/passkeys/auth/start",r,ae)}async finishRegister(r){return this.post("/v1/passkeys/register/finish",r,le)}async finishAuthentication(r){return this.post("/v1/passkeys/auth/finish",r,ue)}async validateSession(r){return this.get("/v1/sessions/validate",pe,{Authorization:`Bearer ${r}`})}async startEmailFallback(r){let t=`${this.baseUrl}/v1/fallback/email/start`,n=await this.httpClient.post(t,{userId:r},this.mergeHeaders());return n.ok?f(void 0):a(n.error)}async verifyEmailCode(r,t){return this.post("/v1/fallback/email/verify",{userId:r,code:t},de)}async startOnboarding(r){return this.post("/onboarding/start",r,ce)}async getOnboardingStatus(r){return this.get(`/onboarding/${r}/status`,me)}async getOnboardingRegister(r){return this.get(`/onboarding/${r}/register`,ge)}async registerOnboardingPasskey(r,t){return this.post(`/onboarding/${r}/register-passkey`,t,fe)}async completeOnboarding(r,t){return this.post(`/onboarding/${r}/complete`,t,Re)}async initCrossDeviceAuth(){return this.post("/v1/auth/cross-device/init",{},ye)}async getCrossDeviceStatus(r){return this.get(`/v1/auth/cross-device/status/${r}`,he)}async getCrossDeviceContext(r){return this.get(`/v1/auth/cross-device/context/${r}`,be)}async verifyCrossDeviceAuth(r){let t=`${this.baseUrl}/v1/auth/cross-device/verify`,n=await this.httpClient.post(t,r,this.mergeHeaders());return n.ok?f(void 0):a(n.error)}};var mr=3e4;function gr(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2,11)}`}function Ne(e,r){let t=r*Math.pow(2,e);return Math.min(t,mr)}function fr(e,r){return e!=="GET"?!1:r>=500||r===429}var H=class{constructor(r,t=0,n=1e3,s){this.timeoutMs=r;this.maxRetries=t;this.retryDelayMs=n;this.logger=s}async get(r,t){return this.request(r,{method:"GET",headers:t})}async post(r,t,n){return this.request(r,{method:"POST",body:JSON.stringify(t),headers:{"Content-Type":"application/json",...n}})}async request(r,t){let n=(t.method??"GET").toUpperCase(),s=gr(),i=new Headers(t.headers);i.set("X-Request-Id",s),this.logger&&this.logger.debug("request",{requestId:s,url:r,method:n});let l;for(let c=0;c<=this.maxRetries;c++)try{let u=new AbortController,h=setTimeout(()=>u.abort(),this.timeoutMs);try{let m=await fetch(r,{...t,headers:i,signal:u.signal});if(!m.ok){let I;try{I=await m.json()}catch{}let v=I,D=v?.message??m.statusText,A=v?.error??"NETWORK_FAILURE",F=y(A,D,{requestId:s,status:m.status,statusText:m.statusText,data:I});if(fr(n,m.status)&&c<this.maxRetries){l=F,await new Promise(Z=>setTimeout(Z,Ne(c,this.retryDelayMs)));continue}return a(F)}let g=await m.json();return f(g)}finally{clearTimeout(h)}}catch(u){if(l=u,n==="GET"&&c<this.maxRetries)await new Promise(m=>setTimeout(m,Ne(c,this.retryDelayMs)));else break}return l instanceof Error&&l.name==="AbortError"?a(y("TIMEOUT","Request timed out",{requestId:s})):a(y("NETWORK_FAILURE",l instanceof Error?l.message:"Request failed",{requestId:s,cause:l}))}};function x(){try{return!(typeof navigator>"u"||!navigator.credentials||typeof PublicKeyCredential>"u")}catch{return!1}}async function Rr(){try{return!x()||typeof PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable!="function"?!1:await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return!1}}async function Ue(){let e=x(),r=await Rr();return{isPasskeySupported:e,platformAuthenticatorAvailable:r,recommendedFlow:e?"passkey":"fallback"}}function S(e){let r=new Uint8Array(e),t="";for(let s=0;s<r.length;s++)t+=String.fromCharCode(r[s]??0);let n="";if(typeof btoa<"u")n=btoa(t);else if(typeof Buffer<"u")n=Buffer.from(t,"binary").toString("base64");else throw se("encode");return n.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function yr(e){let r=e.replace(/-/g,"+").replace(/_/g,"/"),t=r.length%4;t!==0&&(r+="=".repeat(4-t));let n="";if(typeof atob<"u")n=atob(r);else if(typeof Buffer<"u")n=Buffer.from(r,"base64").toString("binary");else throw se("decode");let s=new Uint8Array(n.length);for(let i=0;i<n.length;i++)s[i]=n.charCodeAt(i);return s}function N(e){let r=yr(e),t=new ArrayBuffer(r.length);return new Uint8Array(t).set(r),t}function P(e,r="create"){if(!e||typeof e!="object"||!("id"in e)||!("rawId"in e)||!("response"in e))throw we(r)}function Fe(e){return e!==null&&typeof e=="object"&&"clientDataJSON"in e&&e.clientDataJSON instanceof ArrayBuffer}function Y(e){if(!e.response)throw y("UNKNOWN_ERROR","Credential response is missing",{credential:e});let r=e.response;if(!Fe(r))throw y("UNKNOWN_ERROR","Invalid credential response structure",{response:r});if(!("attestationObject"in r))throw y("UNKNOWN_ERROR","Invalid credential response structure for register: attestationObject is missing",{response:r});let t=r.clientDataJSON,n=r.attestationObject;return{id:e.id,rawId:S(e.rawId),response:{clientDataJSON:S(t),attestationObject:S(n)},type:"public-key"}}function $(e){if(!e.response)throw y("UNKNOWN_ERROR","Credential response is missing",{credential:e});let r=e.response;if(!Fe(r))throw y("UNKNOWN_ERROR","Invalid credential response structure",{response:r});if(!("authenticatorData"in r)||!("signature"in r))throw y("UNKNOWN_ERROR","Invalid credential response structure for auth: authenticatorData or signature is missing",{response:r});let t=r.clientDataJSON,n=r.authenticatorData,s=r.signature,i=r.userHandle;return{id:e.id,rawId:S(e.rawId),response:{authenticatorData:S(n),clientDataJSON:S(t),signature:S(s),...i&&{userHandle:S(i)}},type:"public-key"}}function ve(e,r){try{B(e.challenge,"challenge"),B(e.user.id,"user.id");let t=N(e.challenge),n=N(e.user.id),s={userVerification:"preferred"};e.authenticatorSelection&&(s={...e.authenticatorSelection}),r&&(s={...s,authenticatorAttachment:r});let i={rp:{id:e.rp.id,name:e.rp.name},user:{id:n,name:e.user.name,displayName:e.user.displayName},challenge:t,pubKeyCredParams:e.pubKeyCredParams,...e.timeout!==void 0&&{timeout:e.timeout},attestation:"none",authenticatorSelection:s,...e.excludeCredentials&&{excludeCredentials:e.excludeCredentials.map(l=>({id:N(l.id),type:l.type,...l.transports&&{transports:l.transports}}))}};return f({publicKey:i})}catch(t){return a(E(t))}}function Ee(e,r){try{B(e.challenge,"challenge");let t=N(e.challenge);return f({publicKey:{challenge:t,rpId:e.rpId,...e.timeout!==void 0&&{timeout:e.timeout},userVerification:e.userVerification??"preferred",...e.allowCredentials&&{allowCredentials:e.allowCredentials.map(n=>({id:N(n.id),type:n.type,...n.transports&&{transports:n.transports}}))}},...r!==void 0&&{mediation:r}})}catch(t){return a(E(t))}}async function Le(e,r,t){try{if(t.emit("start",{type:"start",operation:"register"}),!x()){let m=ne();return t.emit("error",{type:"error",error:m}),a(m)}let n=e.externalUserId??e.external_user_id;if(!n||typeof n!="string"||n.trim()===""){let m=b("externalUserId","must be a non-empty string");return t.emit("error",{type:"error",error:m}),a(m)}let s=await r.startRegister({external_user_id:n});if(!s.ok)return t.emit("error",{type:"error",error:s.error}),a(s.error);let i=ve(s.value.challenge,e.authenticatorType);if(!i.ok)return t.emit("error",{type:"error",error:i.error}),a(i.error);let l={...i.value,...e.signal&&{signal:e.signal}},c=await navigator.credentials.create(l);if(!c){let m=b("credential","creation failed");return t.emit("error",{type:"error",error:m}),a(m)}try{P(c)}catch(m){let g=E(m);return t.emit("error",{type:"error",error:g}),a(g)}let u=await r.finishRegister({session_id:s.value.session_id,credential:Y(c)});if(!u.ok)return t.emit("error",{type:"error",error:u.error}),a(u.error);let h={success:!0,credentialId:u.value.credential_id,credential_id:u.value.credential_id,status:u.value.status,sessionToken:u.value.session_token,user:{userId:u.value.user.user_id,externalUserId:u.value.user.external_user_id,email:u.value.user.email,metadata:u.value.user.metadata}};return t.emit("success",{type:"success",operation:"register"}),f(h)}catch(n){let s=E(n);return t.emit("error",{type:"error",error:s}),a(s)}}async function Ke(e,r,t){try{if(t.emit("start",{type:"start",operation:"authenticate"}),!x()){let m=ne();return t.emit("error",{type:"error",error:m}),a(m)}let n=e.externalUserId??e.external_user_id;if(!n||typeof n!="string"||n.trim()===""){let m=b("externalUserId","must be a non-empty string");return t.emit("error",{type:"error",error:m}),a(m)}let s=await r.startAuth({external_user_id:n});if(!s.ok)return t.emit("error",{type:"error",error:s.error}),a(s.error);let i=Ee(s.value.challenge,e.mediation);if(!i.ok)return t.emit("error",{type:"error",error:i.error}),a(i.error);let l={...i.value,...e.signal&&{signal:e.signal}},c=await navigator.credentials.get(l);if(!c){let m=b("credential","retrieval failed");return t.emit("error",{type:"error",error:m}),a(m)}try{P(c)}catch(m){let g=E(m);return t.emit("error",{type:"error",error:g}),a(g)}let u=await r.finishAuthentication({session_id:s.value.session_id,credential:$(c)});if(!u.ok)return t.emit("error",{type:"error",error:u.error}),a(u.error);let h={authenticated:u.value.authenticated,sessionToken:u.value.session_token,user:{userId:u.value.user.user_id,externalUserId:u.value.user.external_user_id,email:u.value.user.email,metadata:u.value.user.metadata},signals:u.value.signals};return t.emit("success",{type:"success",operation:"authenticate"}),f(h)}catch(n){let s=E(n);return t.emit("error",{type:"error",error:s}),a(s)}}var hr=2e3,br=60,G=class{constructor(r){this.apiClient=r}async startFlow(r){let t=await this.apiClient.startOnboarding({user_role:r.user_role});if(!t.ok)return a(t.error);let{session_id:n}=t.value;for(let s=0;s<br;s++){await new Promise(u=>setTimeout(u,hr));let i=await this.apiClient.getOnboardingStatus(n);if(!i.ok)return a(i.error);let l=i.value.status,c=i.value.onboarding_url;if(l==="pending_passkey"){let u=await this.apiClient.getOnboardingRegister(n);if(!u.ok)return a(u.error);let h=u.value;if(!h.challenge)return a(y("NOT_SUPPORTED","Onboarding requires user action - complete passkey registration at the provided onboarding_url",{onboarding_url:c}));let m=ve(h.challenge);if(!m.ok)return a(m.error);let g;try{g=await navigator.credentials.create(m.value)}catch(A){return a(E(A))}try{P(g,"create")}catch(A){return a(E(A))}let I;try{I=Y(g)}catch(A){return a(E(A))}let v=await this.apiClient.registerOnboardingPasskey(n,{credential:I,challenge:h.challenge.challenge});return v.ok?await this.apiClient.completeOnboarding(n,{company_name:r.company_name}):a(v.error)}if(l==="completed")return await this.apiClient.completeOnboarding(n,{company_name:r.company_name})}return a(y("TIMEOUT","Onboarding timed out"))}};var vr=2e3,Er=60,X=class{constructor(r){this.apiClient=r}async init(){return this.apiClient.initCrossDeviceAuth()}async waitForSession(r,t){for(let n=0;n<Er;n++){if(t?.aborted)return a(y("ABORT_ERROR","Operation aborted by user or timeout"));let s=await this.apiClient.getCrossDeviceStatus(r);if(!s.ok)return a(s.error);if(s.value.status==="completed")return!s.value.session_token||!s.value.user_id?a(y("UNKNOWN_ERROR","Missing data in completed session")):f({session_token:s.value.session_token,user_id:s.value.user_id});if(t?.aborted)return a(y("ABORT_ERROR","Operation aborted by user or timeout"));if(await new Promise(i=>{let l=setTimeout(()=>{i(null),t?.removeEventListener("abort",c)},vr),c=()=>{clearTimeout(l),i(null)};t?.addEventListener("abort",c)}),t?.aborted)return a(y("ABORT_ERROR","Operation aborted by user or timeout"))}return a(y("TIMEOUT","Cross-device authentication timed out"))}async approve(r){let t=await this.apiClient.getCrossDeviceContext(r);if(!t.ok)return a(t.error);let n=Ee(t.value.options);if(!n.ok)return a(n.error);let s;try{s=await navigator.credentials.get(n.value)}catch(l){return a(E(l))}try{P(s,"get")}catch(l){return a(E(l))}let i;try{i=$(s)}catch(l){return a(E(l))}return this.apiClient.verifyCrossDeviceAuth({session_id:r,credential:i})}};var z=class{handlers;constructor(){this.handlers=new Map}on(r,t){let n=this.handlers.get(r);return n||(n=new Set,this.handlers.set(r,n)),n.add(t),()=>{this.off(r,t)}}off(r,t){let n=this.handlers.get(r);n&&(n.delete(t),n.size===0&&this.handlers.delete(r))}emit(r,t){let n=this.handlers.get(r);n&&n.forEach(s=>{try{s(t)}catch{}})}removeAllListeners(){this.handlers.clear()}};var _e="https://api.trymellonauth.com",qe="https://api.trymellonauth.com/v1/telemetry";var je="trymellon_sandbox_session_token_v1";function Be(e){return{async send(r){let t=JSON.stringify(r);if(typeof navigator<"u"&&typeof navigator.sendBeacon=="function"){navigator.sendBeacon(e,t);return}typeof fetch<"u"&&await fetch(e,{method:"POST",body:t,headers:{"Content-Type":"application/json"},keepalive:!0})}}}function Te(e,r){return{event:e,latencyMs:r,ok:!0}}var J=class e{sandbox;sandboxToken;apiClient;eventEmitter;telemetrySender;crossDeviceManager;onboarding;static create(r){try{let t=r.appId,n=r.publishableKey;if(!t||typeof t!="string"||t.trim()==="")return a(b("appId","must be a non-empty string"));if(!n||typeof n!="string"||n.trim()==="")return a(b("publishableKey","must be a non-empty string"));let s=r.apiBaseUrl??_e;ie(s,"apiBaseUrl");let i=r.timeoutMs??3e4;return C(i,"timeoutMs",1e3,3e5),r.maxRetries!==void 0&&C(r.maxRetries,"maxRetries",0,10),r.retryDelayMs!==void 0&&C(r.retryDelayMs,"retryDelayMs",100,1e4),f(new e(r))}catch(t){return te(t)?a(t):a(b("config",t.message))}}constructor(r){this.sandbox=r.sandbox===!0,this.sandboxToken=this.sandbox&&r.sandboxToken!=null&&r.sandboxToken!==""?r.sandboxToken:je;let t=r.appId,n=r.publishableKey;if(!t||typeof t!="string"||t.trim()==="")throw b("appId","must be a non-empty string");if(!n||typeof n!="string"||n.trim()==="")throw b("publishableKey","must be a non-empty string");let s=r.apiBaseUrl??_e;ie(s,"apiBaseUrl");let i=r.timeoutMs??3e4;C(i,"timeoutMs",1e3,3e5),r.maxRetries!==void 0&&C(r.maxRetries,"maxRetries",0,10),r.retryDelayMs!==void 0&&C(r.retryDelayMs,"retryDelayMs",100,1e4);let l=r.maxRetries??3,c=r.retryDelayMs??1e3,u=new H(i,l,c,r.logger),h={"X-App-Id":t.trim(),Authorization:`Bearer ${n.trim()}`};this.apiClient=new W(u,s,h),this.onboarding=new G(this.apiClient),this.crossDeviceManager=new X(this.apiClient),this.eventEmitter=new z,r.enableTelemetry&&(this.telemetrySender=r.telemetrySender??Be(r.telemetryEndpoint??qe))}static isSupported(){return x()}async register(r){if(this.sandbox){let s=r.externalUserId??r.external_user_id??"sandbox";return Promise.resolve(f({success:!0,credentialId:"",status:"sandbox",sessionToken:this.sandboxToken,user:{userId:"sandbox-user",externalUserId:typeof s=="string"?s:"sandbox"}}))}let t=Date.now(),n=await Le(r,this.apiClient,this.eventEmitter);return n.ok&&this.telemetrySender&&this.telemetrySender.send(Te("register",Date.now()-t)).catch(()=>{}),n}async authenticate(r){if(this.sandbox){let s=r.externalUserId??r.external_user_id??"sandbox";return Promise.resolve(f({authenticated:!0,sessionToken:this.sandboxToken,user:{userId:"sandbox-user",externalUserId:typeof s=="string"?s:"sandbox"}}))}let t=Date.now(),n=await Ke(r,this.apiClient,this.eventEmitter);return n.ok&&this.telemetrySender&&this.telemetrySender.send(Te("authenticate",Date.now()-t)).catch(()=>{}),n}async validateSession(r){return this.sandbox&&r===this.sandboxToken?Promise.resolve(f({valid:!0,user_id:"sandbox-user",external_user_id:"sandbox",tenant_id:"sandbox-tenant",app_id:"sandbox-app"})):this.apiClient.validateSession(r)}async getStatus(){return Ue()}on(r,t){return this.eventEmitter.on(r,t)}version(){return"1.3.0"}fallback={email:{start:async r=>this.apiClient.startEmailFallback(r.userId),verify:async r=>this.apiClient.verifyEmailCode(r.userId,r.code)}};auth={crossDevice:{init:()=>this.crossDeviceManager.init(),waitForSession:(r,t)=>this.crossDeviceManager.waitForSession(r,t),approve:r=>this.crossDeviceManager.approve(r)}}};var q=new U.InjectionToken("TRYMELLON_CONFIG"),ze,Ie;ze=[(0,U.Injectable)({providedIn:"root"})];var M=class{config=(0,U.inject)(q,{optional:!0});_client=null;get client(){if(this._client==null){if(this.config==null)throw new Error("TryMellonService: provide TRYMELLON_CONFIG (e.g. via provideTryMellonConfig(config))");this._client=new J(this.config)}return this._client}};Ie=Pe(null),M=ke(Ie,0,"TryMellonService",ze,M),De(Ie,1,M);function Ir(e){return{provide:q,useValue:e}}0&&(module.exports={TRYMELLON_CONFIG,TryMellonService,provideTryMellonConfig});
3
3
  //# sourceMappingURL=angular.cjs.map