@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 +271 -18
- package/dist/angular.cjs +1 -1
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.d.cts +1 -1
- package/dist/angular.d.ts +1 -1
- package/dist/angular.js +1 -1
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +140 -62
- package/dist/index.d.ts +140 -62
- package/dist/index.global.js +2 -2
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/{trymellon-Ca4kob_K.d.cts → trymellon-BCB_c_Ud.d.cts} +131 -59
- package/dist/{trymellon-Ca4kob_K.d.ts → trymellon-BCB_c_Ud.d.ts} +131 -59
- package/dist/vue.d.cts +1 -1
- package/dist/vue.d.ts +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
330
|
+
credentialId: string,
|
|
156
331
|
status: string,
|
|
157
|
-
|
|
332
|
+
sessionToken: string,
|
|
158
333
|
user: {
|
|
159
|
-
|
|
160
|
-
|
|
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.
|
|
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
|
-
|
|
371
|
+
sessionToken: string,
|
|
197
372
|
user: {
|
|
198
|
-
|
|
199
|
-
|
|
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
|
|
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
|