@trymellon/js 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,421 @@
1
+ type Result<T, E> = {
2
+ ok: true;
3
+ value: T;
4
+ } | {
5
+ ok: false;
6
+ error: E;
7
+ };
8
+ declare const ok: <T>(value: T) => Result<T, never>;
9
+ declare const err: <E>(error: E) => Result<never, E>;
10
+
11
+ type TryMellonErrorCode = 'NOT_SUPPORTED' | 'USER_CANCELLED' | 'PASSKEY_NOT_FOUND' | 'SESSION_EXPIRED' | 'NETWORK_FAILURE' | 'INVALID_ARGUMENT' | 'TIMEOUT' | 'ABORTED' | 'UNKNOWN_ERROR';
12
+ declare class TryMellonError extends Error {
13
+ readonly code: TryMellonErrorCode;
14
+ readonly details?: unknown;
15
+ readonly isTryMellonError = true;
16
+ constructor(code: TryMellonErrorCode, message: string, details?: unknown);
17
+ }
18
+ declare function createError(code: TryMellonErrorCode, message?: string, details?: unknown): TryMellonError;
19
+ declare function isTryMellonError(error: unknown): error is TryMellonError;
20
+ declare function createNotSupportedError(): TryMellonError;
21
+ declare function createUserCancelledError(): TryMellonError;
22
+ declare function createNetworkError(cause?: Error): TryMellonError;
23
+ declare function createTimeoutError(): TryMellonError;
24
+ declare function createInvalidArgumentError(field: string, reason: string): TryMellonError;
25
+ declare function mapWebAuthnError(error: unknown): TryMellonError;
26
+
27
+ interface HttpClient {
28
+ get<T>(url: string, headers?: Record<string, string>): Promise<Result<T, TryMellonError>>;
29
+ post<T>(url: string, body: unknown, headers?: Record<string, string>): Promise<Result<T, TryMellonError>>;
30
+ }
31
+
32
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
33
+ interface Logger {
34
+ debug(message: string, meta?: Record<string, unknown>): void;
35
+ info(message: string, meta?: Record<string, unknown>): void;
36
+ warn(message: string, meta?: Record<string, unknown>): void;
37
+ error(message: string, meta?: Record<string, unknown>): void;
38
+ }
39
+
40
+ type TelemetryEvent = 'register' | 'authenticate';
41
+ type TelemetryPayload = {
42
+ event: TelemetryEvent;
43
+ latencyMs: number;
44
+ ok: true;
45
+ };
46
+ interface TelemetrySender {
47
+ send(payload: TelemetryPayload): Promise<void>;
48
+ }
49
+
50
+ type TryMellonConfig = {
51
+ /** Application identifier (tenant). Required for API requests. */
52
+ appId: string;
53
+ /** API key for authentication. Required for API requests. */
54
+ publishableKey: string;
55
+ apiBaseUrl?: string;
56
+ timeoutMs?: number;
57
+ maxRetries?: number;
58
+ retryDelayMs?: number;
59
+ /** Optional logger for request/error correlation (e.g. requestId). */
60
+ logger?: Logger;
61
+ /** If true, send anonymous telemetry (event + latency) after successful register/authenticate. */
62
+ enableTelemetry?: boolean;
63
+ /** Custom telemetry sender; used when enableTelemetry is true. Defaults to TryMellon endpoint. */
64
+ telemetrySender?: TelemetrySender;
65
+ /** Endpoint for default telemetry sender when enableTelemetry is true and telemetrySender not set. */
66
+ telemetryEndpoint?: string;
67
+ };
68
+ type RegisterOptions = {
69
+ /** User identifier (recommended: camelCase). */
70
+ externalUserId?: string;
71
+ /** User identifier (snake_case alias). */
72
+ external_user_id?: string;
73
+ authenticatorType?: 'platform' | 'cross-platform';
74
+ signal?: AbortSignal;
75
+ };
76
+ type RegisterResult = {
77
+ success: true;
78
+ credential_id: string;
79
+ status: string;
80
+ session_token: string;
81
+ user: {
82
+ user_id: string;
83
+ external_user_id: string;
84
+ email?: string;
85
+ metadata?: Record<string, unknown>;
86
+ };
87
+ };
88
+ type AuthenticateOptions = {
89
+ /** User identifier (recommended: camelCase). */
90
+ externalUserId?: string;
91
+ /** User identifier (snake_case alias). */
92
+ external_user_id?: string;
93
+ hint?: string;
94
+ signal?: AbortSignal;
95
+ /** Conditional UI mediation for passkey autofill / conditional UI. */
96
+ mediation?: 'optional' | 'conditional' | 'required';
97
+ };
98
+ type AuthenticateResult = {
99
+ authenticated: boolean;
100
+ session_token: string;
101
+ user: {
102
+ user_id: string;
103
+ external_user_id: string;
104
+ email?: string;
105
+ metadata?: Record<string, unknown>;
106
+ };
107
+ signals: {
108
+ userVerification?: boolean;
109
+ backupEligible?: boolean;
110
+ backupStatus?: boolean;
111
+ };
112
+ };
113
+ type ClientStatus = {
114
+ isPasskeySupported: boolean;
115
+ platformAuthenticatorAvailable: boolean;
116
+ recommendedFlow: 'passkey' | 'fallback';
117
+ };
118
+ type TryMellonEvent = 'start' | 'success' | 'error' | 'cancelled';
119
+ type EventPayload = {
120
+ type: 'start';
121
+ operation: 'register' | 'authenticate';
122
+ } | {
123
+ type: 'success';
124
+ operation: 'register' | 'authenticate';
125
+ } | {
126
+ type: 'error';
127
+ error: TryMellonError;
128
+ } | {
129
+ type: 'cancelled';
130
+ operation: 'register' | 'authenticate';
131
+ };
132
+ type EventHandler = (payload: EventPayload) => void;
133
+ type EmailFallbackStartOptions = {
134
+ userId: string;
135
+ };
136
+ type EmailFallbackVerifyOptions = {
137
+ userId: string;
138
+ code: string;
139
+ };
140
+ type EmailFallbackVerifyResult = {
141
+ sessionToken: string;
142
+ };
143
+ type OnboardingStartOptions = {
144
+ user_role: 'maintainer' | 'app_user';
145
+ };
146
+ type OnboardingStartResult = {
147
+ session_id: string;
148
+ onboarding_url: string;
149
+ expires_in: number;
150
+ };
151
+ type OnboardingStatusResult = {
152
+ status: 'pending_passkey' | 'pending_data' | 'completed';
153
+ onboarding_url: string;
154
+ expires_in: number;
155
+ };
156
+ type OnboardingRegisterResult = {
157
+ session_id: string;
158
+ status: 'pending_passkey';
159
+ onboarding_url: string;
160
+ };
161
+ type OnboardingRegisterPasskeyOptions = {
162
+ session_id: string;
163
+ credential: {
164
+ id: string;
165
+ rawId: string;
166
+ response: {
167
+ clientDataJSON: string;
168
+ attestationObject: string;
169
+ };
170
+ type: 'public-key';
171
+ };
172
+ tenant_id?: string;
173
+ challenge: string;
174
+ };
175
+ type OnboardingRegisterPasskeyResult = {
176
+ session_id: string;
177
+ status: 'pending_data' | 'completed';
178
+ user_id: string;
179
+ tenant_id: string;
180
+ };
181
+ type OnboardingCompleteOptions = {
182
+ session_id: string;
183
+ company_name?: string;
184
+ };
185
+ type OnboardingCompleteResult = {
186
+ session_id: string;
187
+ status: 'completed';
188
+ user_id: string;
189
+ tenant_id: string;
190
+ session_token: string;
191
+ };
192
+ type RegisterStartRequest = {
193
+ external_user_id: string;
194
+ };
195
+ type AuthStartRequest = {
196
+ external_user_id: string;
197
+ };
198
+ type RegisterFinishRequest = {
199
+ session_id: string;
200
+ credential: {
201
+ id: string;
202
+ rawId: string;
203
+ response: {
204
+ clientDataJSON: string;
205
+ attestationObject: string;
206
+ };
207
+ type: 'public-key';
208
+ };
209
+ };
210
+ type AuthFinishRequest = {
211
+ session_id: string;
212
+ credential: {
213
+ id: string;
214
+ rawId: string;
215
+ response: {
216
+ authenticatorData: string;
217
+ clientDataJSON: string;
218
+ signature: string;
219
+ userHandle?: string;
220
+ };
221
+ type: 'public-key';
222
+ };
223
+ };
224
+ type RegisterStartResponse = {
225
+ challenge: {
226
+ rp: {
227
+ name: string;
228
+ id: string;
229
+ };
230
+ user: {
231
+ id: string;
232
+ name: string;
233
+ displayName: string;
234
+ };
235
+ challenge: string;
236
+ pubKeyCredParams: Array<{
237
+ type: 'public-key';
238
+ alg: number;
239
+ }>;
240
+ timeout?: number;
241
+ excludeCredentials?: Array<{
242
+ id: string;
243
+ type: 'public-key';
244
+ transports?: string[];
245
+ }>;
246
+ authenticatorSelection?: {
247
+ userVerification?: 'required' | 'preferred' | 'discouraged';
248
+ residentKey?: 'required' | 'preferred' | 'discouraged';
249
+ authenticatorAttachment?: 'platform' | 'cross-platform';
250
+ };
251
+ };
252
+ session_id: string;
253
+ };
254
+ type AuthStartResponse = {
255
+ challenge: {
256
+ challenge: string;
257
+ rpId: string;
258
+ allowCredentials: Array<{
259
+ id: string;
260
+ type: 'public-key';
261
+ transports?: string[];
262
+ }>;
263
+ timeout?: number;
264
+ userVerification?: 'required' | 'preferred' | 'discouraged';
265
+ };
266
+ session_id: string;
267
+ };
268
+ type RegisterFinishResponse = {
269
+ credential_id: string;
270
+ status: string;
271
+ session_token: string;
272
+ user: {
273
+ user_id: string;
274
+ external_user_id: string;
275
+ email?: string;
276
+ metadata?: Record<string, unknown>;
277
+ };
278
+ };
279
+ type AuthFinishResponse = {
280
+ authenticated: boolean;
281
+ user: {
282
+ user_id: string;
283
+ external_user_id: string;
284
+ email?: string;
285
+ metadata?: Record<string, unknown>;
286
+ };
287
+ signals: {
288
+ userVerification?: boolean;
289
+ backupEligible?: boolean;
290
+ backupStatus?: boolean;
291
+ };
292
+ session_token: string;
293
+ };
294
+ type SessionValidateResponse = {
295
+ valid: boolean;
296
+ user_id: string;
297
+ external_user_id: string;
298
+ tenant_id: string;
299
+ app_id: string;
300
+ };
301
+ type OnboardingStartRequest = {
302
+ user_role: 'maintainer' | 'app_user';
303
+ };
304
+ type OnboardingStartResponse = {
305
+ session_id: string;
306
+ onboarding_url: string;
307
+ expires_in: number;
308
+ };
309
+ type OnboardingStatusResponse = {
310
+ status: 'pending_passkey' | 'pending_data' | 'completed';
311
+ onboarding_url: string;
312
+ expires_in: number;
313
+ };
314
+ type OnboardingRegisterResponse = {
315
+ session_id: string;
316
+ status: 'pending_passkey';
317
+ onboarding_url: string;
318
+ };
319
+ type OnboardingRegisterPasskeyRequest = {
320
+ credential: {
321
+ id: string;
322
+ rawId: string;
323
+ response: {
324
+ clientDataJSON: string;
325
+ attestationObject: string;
326
+ };
327
+ type: 'public-key';
328
+ };
329
+ tenant_id?: string;
330
+ challenge: string;
331
+ };
332
+ type OnboardingRegisterPasskeyResponse = {
333
+ session_id: string;
334
+ status: 'pending_data' | 'completed';
335
+ user_id: string;
336
+ tenant_id: string;
337
+ };
338
+ type OnboardingCompleteRequest = {
339
+ company_name?: string;
340
+ };
341
+ type OnboardingCompleteResponse = {
342
+ session_id: string;
343
+ status: 'completed';
344
+ user_id: string;
345
+ tenant_id: string;
346
+ session_token: string;
347
+ };
348
+
349
+ /** Response may include optional challenge for same-device passkey registration */
350
+ type OnboardingRegisterResponseWithChallenge = OnboardingRegisterResponse & {
351
+ challenge?: RegisterStartResponse['challenge'];
352
+ };
353
+
354
+ declare class ApiClient {
355
+ private readonly httpClient;
356
+ private readonly baseUrl;
357
+ private readonly defaultHeaders;
358
+ constructor(httpClient: HttpClient, baseUrl: string, defaultHeaders?: Record<string, string>);
359
+ private mergeHeaders;
360
+ private post;
361
+ private get;
362
+ startRegister(request: RegisterStartRequest): Promise<Result<RegisterStartResponse, TryMellonError>>;
363
+ startAuth(request: AuthStartRequest): Promise<Result<AuthStartResponse, TryMellonError>>;
364
+ finishRegister(request: RegisterFinishRequest): Promise<Result<RegisterFinishResponse, TryMellonError>>;
365
+ finishAuth(request: AuthFinishRequest): Promise<Result<AuthFinishResponse, TryMellonError>>;
366
+ validateSession(sessionToken: string): Promise<Result<SessionValidateResponse, TryMellonError>>;
367
+ startEmailFallback(userId: string): Promise<Result<void, TryMellonError>>;
368
+ verifyEmailCode(userId: string, code: string): Promise<Result<{
369
+ sessionToken: string;
370
+ }, TryMellonError>>;
371
+ startOnboarding(request: OnboardingStartRequest): Promise<Result<OnboardingStartResponse, TryMellonError>>;
372
+ getOnboardingStatus(sessionId: string): Promise<Result<OnboardingStatusResponse, TryMellonError>>;
373
+ getOnboardingRegister(sessionId: string): Promise<Result<OnboardingRegisterResponseWithChallenge, TryMellonError>>;
374
+ registerOnboardingPasskey(sessionId: string, request: OnboardingRegisterPasskeyRequest): Promise<Result<OnboardingRegisterPasskeyResponse, TryMellonError>>;
375
+ completeOnboarding(sessionId: string, request: OnboardingCompleteRequest): Promise<Result<OnboardingCompleteResponse, TryMellonError>>;
376
+ }
377
+
378
+ declare class OnboardingManager {
379
+ private readonly apiClient;
380
+ constructor(apiClient: ApiClient);
381
+ /**
382
+ * Executes the full onboarding flow in a single call.
383
+ * 1. Starts onboarding
384
+ * 2. Polls for 'pending_passkey' or 'completed' status
385
+ * 3. If pending_passkey: when API returns challenge, registers passkey (WebAuthn) then completes onboarding
386
+ * 4. If pending_passkey but API does not return challenge: returns NOT_SUPPORTED with onboarding_url for user to complete elsewhere
387
+ */
388
+ startFlow(options: OnboardingStartOptions & {
389
+ company_name?: string;
390
+ }): Promise<Result<OnboardingCompleteResult, TryMellonError>>;
391
+ }
392
+
393
+ declare class TryMellon {
394
+ private apiClient;
395
+ private eventEmitter;
396
+ private telemetrySender;
397
+ onboarding: OnboardingManager;
398
+ constructor(config: TryMellonConfig);
399
+ static isSupported(): boolean;
400
+ register(options: RegisterOptions): Promise<Result<RegisterResult, TryMellonError>>;
401
+ authenticate(options: AuthenticateOptions): Promise<Result<AuthenticateResult, TryMellonError>>;
402
+ validateSession(sessionToken: string): Promise<Result<SessionValidateResponse, TryMellonError>>;
403
+ getStatus(): Promise<ClientStatus>;
404
+ on(event: TryMellonEvent, handler: EventHandler): () => void;
405
+ version(): string;
406
+ fallback: {
407
+ email: {
408
+ start: (options: EmailFallbackStartOptions) => Promise<Result<void, TryMellonError>>;
409
+ verify: (options: EmailFallbackVerifyOptions) => Promise<Result<EmailFallbackVerifyResult, TryMellonError>>;
410
+ };
411
+ };
412
+ }
413
+
414
+ declare class ConsoleLogger implements Logger {
415
+ debug(message: string, meta?: Record<string, unknown>): void;
416
+ info(message: string, meta?: Record<string, unknown>): void;
417
+ warn(message: string, meta?: Record<string, unknown>): void;
418
+ error(message: string, meta?: Record<string, unknown>): void;
419
+ }
420
+
421
+ export { type AuthenticateOptions, type AuthenticateResult, type ClientStatus, ConsoleLogger, type EmailFallbackStartOptions, type EmailFallbackVerifyOptions, type EmailFallbackVerifyResult, type EventHandler, type EventPayload, type LogLevel, type Logger, type OnboardingCompleteOptions, type OnboardingCompleteResult, type OnboardingRegisterPasskeyOptions, type OnboardingRegisterPasskeyResult, type OnboardingRegisterResult, type OnboardingStartOptions, type OnboardingStartResult, type OnboardingStatusResult, type RegisterOptions, type RegisterResult, type Result, type SessionValidateResponse, TryMellon, type TryMellonConfig, TryMellonError, type TryMellonErrorCode, type TryMellonEvent, createError, createInvalidArgumentError, createNetworkError, createNotSupportedError, createTimeoutError, createUserCancelledError, err, isTryMellonError, mapWebAuthnError, ok };
@@ -0,0 +1,3 @@
1
+ var TryMellon=(function(exports){'use strict';var R=e=>({ok:true,value:e}),u=e=>({ok:false,error:e});var M=class e extends Error{code;details;isTryMellonError=true;constructor(r,t,n){super(t),this.name="TryMellonError",this.code=r,this.details=n,Error.captureStackTrace&&Error.captureStackTrace(this,e);}},ye={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 f(e,r,t){return new M(e,r??ye[e],t)}function se(e){return e instanceof M||typeof e=="object"&&e!==null&&"isTryMellonError"in e&&e.isTryMellonError===true}function C(){return f("NOT_SUPPORTED")}function he(){return f("USER_CANCELLED")}function be(e){return f("NETWORK_FAILURE",void 0,{cause:e?.message,originalError:e})}function Ee(){return f("TIMEOUT")}function A(e,r){return f("INVALID_ARGUMENT",`Invalid argument: ${e} - ${r}`,{field:e,reason:r})}function ie(e){return f("UNKNOWN_ERROR",`Failed to ${e} credential`,{operation:e})}function q(e){return f("NOT_SUPPORTED",`No base64 ${e==="encode"?"encoding":"decoding"} available`,{type:e})}function oe(e,r){try{let t=new URL(e);if(t.protocol!=="https:"&&t.protocol!=="http:")throw A(r,"must use http or https protocol")}catch(t){throw se(t)?t:A(r,"must be a valid URL")}}function x(e,r,t,n){if(e<t||e>n)throw A(r,`must be between ${t} and ${n}`)}function D(e,r){if(typeof e!="string"||e.length===0)throw A(r,"must be a non-empty string");if(!/^[A-Za-z0-9_-]+$/.test(e))throw A(r,"must be a valid base64url string")}var _e={NotAllowedError:"USER_CANCELLED",AbortError:"ABORTED",NotSupportedError:"NOT_SUPPORTED",SecurityError:"NOT_SUPPORTED",InvalidStateError:"UNKNOWN_ERROR",UnknownError:"UNKNOWN_ERROR"};function _(e){if(e instanceof DOMException){let r=e.name,t=e.message||"WebAuthn operation failed",n=_e[r]??"UNKNOWN_ERROR";return f(n,t,{originalError:e})}return e instanceof Error?f("UNKNOWN_ERROR",e.message,{originalError:e}):f("UNKNOWN_ERROR","An unknown error occurred",{originalError:e})}function g(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function l(e){return typeof e=="string"}function I(e){return typeof e=="number"&&Number.isFinite(e)}function N(e){return typeof e=="boolean"}function P(e){return Array.isArray(e)}function i(e,r){return u(f("NETWORK_FAILURE",e,{...r,originalData:r?.originalData}))}function a(e,r){return e[r]}function V(e){if(!g(e))return i("Invalid API response: expected object",{originalData:e});let r=a(e,"session_id");if(!l(r))return i("Invalid API response: session_id must be string",{field:"session_id",originalData:e});let t=a(e,"challenge");if(!g(t))return i("Invalid API response: challenge must be object",{field:"challenge",originalData:e});let n=a(t,"rp");if(!g(n)||!l(n.name)||!l(n.id))return i("Invalid API response: challenge.rp must have name and id strings",{originalData:e});let s=a(t,"user");if(!g(s)||!l(s.id)||!l(s.name)||!l(s.displayName))return i("Invalid API response: challenge.user must have id, name, displayName strings",{originalData:e});let o=a(t,"challenge");if(!l(o))return i("Invalid API response: challenge.challenge must be string",{originalData:e});let p=a(t,"pubKeyCredParams");if(!P(p))return i("Invalid API response: challenge.pubKeyCredParams must be array",{originalData:e});for(let m of p)if(!g(m)||m.type!=="public-key"||!I(m.alg))return i("Invalid API response: pubKeyCredParams items must have type and alg",{originalData:e});let d=t.timeout;if(d!==void 0&&!I(d))return i("Invalid API response: challenge.timeout must be number",{originalData:e});let c=t.excludeCredentials;if(c!==void 0){if(!P(c))return i("Invalid API response: excludeCredentials must be array",{originalData:e});for(let m of c)if(!g(m)||m.type!=="public-key"||!l(m.id))return i("Invalid API response: excludeCredentials items must have id and type",{originalData:e})}let y=t.authenticatorSelection;return y!==void 0&&!g(y)?i("Invalid API response: authenticatorSelection must be object",{originalData:e}):R({session_id:r,challenge:{rp:n,user:s,challenge:o,pubKeyCredParams:p,...d!==void 0&&{timeout:d},...c!==void 0&&{excludeCredentials:c},...y!==void 0&&{authenticatorSelection:y}}})}function W(e){if(!g(e))return i("Invalid API response: expected object",{originalData:e});let r=a(e,"session_id");if(!l(r))return i("Invalid API response: session_id must be string",{field:"session_id",originalData:e});let t=a(e,"challenge");if(!g(t))return i("Invalid API response: challenge must be object",{field:"challenge",originalData:e});let n=a(t,"challenge"),s=a(t,"rpId"),o=t.allowCredentials;if(!l(n))return i("Invalid API response: challenge.challenge must be string",{originalData:e});if(!l(s))return i("Invalid API response: challenge.rpId must be string",{originalData:e});if(o!==void 0&&!P(o))return i("Invalid API response: allowCredentials must be array",{originalData:e});if(o){for(let c of o)if(!g(c)||c.type!=="public-key"||!l(c.id))return i("Invalid API response: allowCredentials items must have id and type",{originalData:e})}let p=t.timeout;if(p!==void 0&&!I(p))return i("Invalid API response: challenge.timeout must be number",{originalData:e});let d=t.userVerification;return d!==void 0&&!["required","preferred","discouraged"].includes(String(d))?i("Invalid API response: userVerification must be required|preferred|discouraged",{originalData:e}):R({session_id:r,challenge:{challenge:n,rpId:s,allowCredentials:o??[],...p!==void 0&&{timeout:p},...d!==void 0&&{userVerification:d}}})}function B(e){if(!g(e))return i("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 i("Invalid API response: credential_id must be string",{field:"credential_id",originalData:e});if(!l(t))return i("Invalid API response: status must be string",{field:"status",originalData:e});if(!l(n))return i("Invalid API response: session_token must be string",{field:"session_token",originalData:e});if(!g(s))return i("Invalid API response: user must be object",{field:"user",originalData:e});let o=a(s,"user_id"),p=a(s,"external_user_id");if(!l(o)||!l(p))return i("Invalid API response: user must have user_id and external_user_id strings",{originalData:e});let d=s.email,c=s.metadata;return d!==void 0&&!l(d)?i("Invalid API response: user.email must be string",{originalData:e}):c!==void 0&&(typeof c!="object"||c===null)?i("Invalid API response: user.metadata must be object",{originalData:e}):R({credential_id:r,status:t,session_token:n,user:{user_id:o,external_user_id:p,...d!==void 0&&{email:d},...c!==void 0&&{metadata:c}}})}function $(e){if(!g(e))return i("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(!N(r))return i("Invalid API response: authenticated must be boolean",{field:"authenticated",originalData:e});if(!l(t))return i("Invalid API response: session_token must be string",{field:"session_token",originalData:e});if(!g(n))return i("Invalid API response: user must be object",{field:"user",originalData:e});let o=a(n,"user_id"),p=a(n,"external_user_id");return !l(o)||!l(p)?i("Invalid API response: user must have user_id and external_user_id strings",{originalData:e}):s!==void 0&&!g(s)?i("Invalid API response: signals must be object",{originalData:e}):R({authenticated:r,session_token:t,user:{user_id:o,external_user_id:p,...n.email!==void 0&&{email:n.email},...n.metadata!==void 0&&{metadata:n.metadata}},signals:s})}function H(e){if(!g(e))return i("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"),o=a(e,"app_id");return N(r)?l(t)?l(n)?l(s)?l(o)?R({valid:r,user_id:t,external_user_id:n,tenant_id:s,app_id:o}):i("Invalid API response: app_id must be string",{field:"app_id",originalData:e}):i("Invalid API response: tenant_id must be string",{field:"tenant_id",originalData:e}):i("Invalid API response: external_user_id must be string",{field:"external_user_id",originalData:e}):i("Invalid API response: user_id must be string",{field:"user_id",originalData:e}):i("Invalid API response: valid must be boolean",{field:"valid",originalData:e})}function Y(e){if(!g(e))return i("Invalid API response: expected object",{originalData:e});let r=a(e,"sessionToken");return l(r)?R({sessionToken:r}):i("Invalid API response: sessionToken must be string",{field:"sessionToken",originalData:e})}var Te=["pending_passkey","pending_data","completed"],Ae=["pending_data","completed"];function X(e){if(!g(e))return i("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)?I(n)?R({session_id:r,onboarding_url:t,expires_in:n}):i("Invalid API response: expires_in must be number",{field:"expires_in",originalData:e}):i("Invalid API response: onboarding_url must be string",{field:"onboarding_url",originalData:e}):i("Invalid API response: session_id must be string",{field:"session_id",originalData:e})}function z(e){if(!g(e))return i("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)||!Te.includes(r)?i("Invalid API response: status must be pending_passkey|pending_data|completed",{field:"status",originalData:e}):l(t)?I(n)?R({status:r,onboarding_url:t,expires_in:n}):i("Invalid API response: expires_in must be number",{originalData:e}):i("Invalid API response: onboarding_url must be string",{originalData:e})}function G(e){if(!g(e))return i("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 i("Invalid API response: session_id must be string",{field:"session_id",originalData:e});if(t!=="pending_passkey")return i("Invalid API response: status must be pending_passkey",{field:"status",originalData:e});if(!l(n))return i("Invalid API response: onboarding_url must be string",{originalData:e});let s=e.challenge,o;if(s!==void 0){let p=ve(s);if(!p.ok)return p;o=p.value;}return R({session_id:r,status:"pending_passkey",onboarding_url:n,...o!==void 0&&{challenge:o}})}function ve(e){if(!g(e))return i("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(!g(r)||!l(r.name)||!l(r.id))return i("Invalid API response: challenge.rp must have name and id",{originalData:e});if(!g(t)||!l(t.id)||!l(t.name)||!l(t.displayName))return i("Invalid API response: challenge.user must have id, name, displayName",{originalData:e});if(!l(n))return i("Invalid API response: challenge.challenge must be string",{originalData:e});if(!P(s))return i("Invalid API response: challenge.pubKeyCredParams must be array",{originalData:e});for(let o of s)if(!g(o)||o.type!=="public-key"||!I(o.alg))return i("Invalid API response: pubKeyCredParams items must have type and alg",{originalData:e});return R({rp:r,user:t,challenge:n,pubKeyCredParams:s})}function J(e){if(!g(e))return i("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)||!Ae.includes(t)?i("Invalid API response: status must be pending_data|completed",{originalData:e}):l(n)?l(s)?R({session_id:r,status:t,user_id:n,tenant_id:s}):i("Invalid API response: tenant_id must be string",{originalData:e}):i("Invalid API response: user_id must be string",{originalData:e}):i("Invalid API response: session_id must be string",{originalData:e})}function Z(e){if(!g(e))return i("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"),o=a(e,"session_token");return l(r)?t!=="completed"?i("Invalid API response: status must be completed",{originalData:e}):!l(n)||!l(s)||!l(o)?i("Invalid API response: user_id, tenant_id, session_token must be strings",{originalData:e}):R({session_id:r,status:"completed",user_id:n,tenant_id:s,session_token:o}):i("Invalid API response: session_id must be string",{originalData:e})}var U=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}`,o=await this.httpClient.post(s,t,this.mergeHeaders());return o.ok?n(o.value):u(o.error)}async get(r,t,n){let s=`${this.baseUrl}${r}`,o=await this.httpClient.get(s,this.mergeHeaders(n));return o.ok?t(o.value):u(o.error)}async startRegister(r){return this.post("/v1/passkeys/register/start",r,V)}async startAuth(r){return this.post("/v1/passkeys/auth/start",r,W)}async finishRegister(r){return this.post("/v1/passkeys/register/finish",r,B)}async finishAuth(r){return this.post("/v1/passkeys/auth/finish",r,$)}async validateSession(r){return this.get("/v1/sessions/validate",H,{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?R(void 0):u(n.error)}async verifyEmailCode(r,t){return this.post("/v1/fallback/email/verify",{userId:r,code:t},Y)}async startOnboarding(r){return this.post("/onboarding/start",r,X)}async getOnboardingStatus(r){return this.get(`/onboarding/${r}/status`,z)}async getOnboardingRegister(r){return this.get(`/onboarding/${r}/register`,G)}async registerOnboardingPasskey(r,t){return this.post(`/onboarding/${r}/register-passkey`,t,J)}async completeOnboarding(r,t){return this.post(`/onboarding/${r}/complete`,t,Z)}};var Ie=3e4;function Se(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2,11)}`}function ae(e,r){let t=r*Math.pow(2,e);return Math.min(t,Ie)}function Oe(e,r){return e!=="GET"?false:r>=500||r===429}var F=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=Se(),o=new Headers(t.headers);o.set("X-Request-Id",s),this.logger&&this.logger.debug("request",{requestId:s,url:r,method:n});let p;for(let d=0;d<=this.maxRetries;d++)try{let c=new AbortController,y=setTimeout(()=>c.abort(),this.timeoutMs),m=await fetch(r,{...t,headers:o,signal:c.signal});if(clearTimeout(y),!m.ok){let E;try{E=await m.json();}catch{}let b=E,h=b?.message??m.statusText,S=b?.error??"NETWORK_FAILURE",ne=f(S,h,{requestId:s,status:m.status,statusText:m.statusText,data:E});if(Oe(n,m.status)&&d<this.maxRetries){p=ne,await new Promise(Re=>setTimeout(Re,ae(d,this.retryDelayMs)));continue}return u(ne)}let T=await m.json();return R(T)}catch(c){if(p=c,n==="GET"&&d<this.maxRetries)await new Promise(m=>setTimeout(m,ae(d,this.retryDelayMs)));else break}return p instanceof Error&&p.name==="AbortError"?u(f("TIMEOUT","Request timed out",{requestId:s})):u(f("NETWORK_FAILURE",p instanceof Error?p.message:"Request failed",{requestId:s,cause:p}))}};function O(){try{return !(typeof navigator>"u"||!navigator.credentials||typeof PublicKeyCredential>"u")}catch{return false}}async function Pe(){try{return !O()||typeof PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable!="function"?false:await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return false}}async function le(){let e=O(),r=await Pe();return {isPasskeySupported:e,platformAuthenticatorAvailable:r,recommendedFlow:e?"passkey":"fallback"}}function v(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 q("encode");return n.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function ke(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 q("decode");let s=new Uint8Array(n.length);for(let o=0;o<n.length;o++)s[o]=n.charCodeAt(o);return s}function k(e){let r=ke(e),t=new ArrayBuffer(r.length);return new Uint8Array(t).set(r),t}function w(e,r="create"){if(!e||typeof e!="object"||!("id"in e)||!("rawId"in e)||!("response"in e))throw ie(r)}function ue(e){return e!==null&&typeof e=="object"&&"clientDataJSON"in e&&e.clientDataJSON instanceof ArrayBuffer}function L(e){if(!e.response)throw f("UNKNOWN_ERROR","Credential response is missing",{credential:e});let r=e.response;if(!ue(r))throw f("UNKNOWN_ERROR","Invalid credential response structure",{response:r});if(!("attestationObject"in r))throw f("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:v(e.rawId),response:{clientDataJSON:v(t),attestationObject:v(n)},type:"public-key"}}function pe(e){if(!e.response)throw f("UNKNOWN_ERROR","Credential response is missing",{credential:e});let r=e.response;if(!ue(r))throw f("UNKNOWN_ERROR","Invalid credential response structure",{response:r});if(!("authenticatorData"in r)||!("signature"in r))throw f("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,o=r.userHandle;return {id:e.id,rawId:v(e.rawId),response:{authenticatorData:v(n),clientDataJSON:v(t),signature:v(s),...o&&{userHandle:v(o)}},type:"public-key"}}function Q(e,r){try{D(e.challenge,"challenge"),D(e.user.id,"user.id");let t=k(e.challenge),n=k(e.user.id),s={userVerification:"preferred"};e.authenticatorSelection&&(s={...e.authenticatorSelection}),r&&(s={...s,authenticatorAttachment:r});let o={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(p=>({id:k(p.id),type:p.type,...p.transports&&{transports:p.transports}}))}};return R({publicKey:o})}catch(t){return u(_(t))}}function Me(e,r){try{D(e.challenge,"challenge");let t=k(e.challenge);return R({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:k(n.id),type:n.type,...n.transports&&{transports:n.transports}}))}},...r!==void 0&&{mediation:r}})}catch(t){return u(_(t))}}async function de(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 u(A("external_user_id","must be provided (use externalUserId or external_user_id)"));if(!O())return u(C());let s=await r.startRegister({external_user_id:n.trim()});if(!s.ok)return t.emit("error",{type:"error",error:s.error}),u(s.error);let o=s.value,p=o.session_id,d=Q(o.challenge,e.authenticatorType);if(!d.ok)return t.emit("error",{type:"error",error:d.error}),u(d.error);let c=d.value;e.signal&&(c.signal=e.signal);let y;try{y=await navigator.credentials.create(c);}catch(b){let h=_(b);return t.emit("error",{type:"error",error:h}),u(h)}try{w(y,"create");}catch(b){let h=_(b);return t.emit("error",{type:"error",error:h}),u(h)}let m;try{m=L(y);}catch(b){let h=_(b);return t.emit("error",{type:"error",error:h}),u(h)}let T=await r.finishRegister({session_id:p,credential:m});if(!T.ok)return t.emit("error",{type:"error",error:T.error}),u(T.error);let E=T.value;return t.emit("success",{type:"success",operation:"register"}),R({success:true,credential_id:E.credential_id,status:E.status,session_token:E.session_token,user:E.user})}catch(n){let s=_(n);return t.emit("error",{type:"error",error:s}),u(s)}}async function ce(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 u(A("external_user_id","must be provided (use externalUserId or external_user_id)"));if(!O())return u(C());let s=await r.startAuth({external_user_id:n.trim()});if(!s.ok)return t.emit("error",{type:"error",error:s.error}),u(s.error);let o=s.value,p=o.session_id,d=Me(o.challenge,e.mediation);if(!d.ok)return t.emit("error",{type:"error",error:d.error}),u(d.error);let c=d.value;e.signal&&(c.signal=e.signal);let y;try{y=await navigator.credentials.get(c);}catch(b){let h=_(b);return t.emit("error",{type:"error",error:h}),u(h)}try{w(y,"get");}catch(b){let h=_(b);return t.emit("error",{type:"error",error:h}),u(h)}let m;try{m=pe(y);}catch(b){let h=_(b);return t.emit("error",{type:"error",error:h}),u(h)}let T=await r.finishAuth({session_id:p,credential:m});if(!T.ok)return t.emit("error",{type:"error",error:T.error}),u(T.error);let E=T.value;return t.emit("success",{type:"success",operation:"authenticate"}),R({authenticated:E.authenticated,session_token:E.session_token,user:E.user,signals:E.signals})}catch(n){let s=_(n);return t.emit("error",{type:"error",error:s}),u(s)}}var we=2e3,Ce=60,K=class{constructor(r){this.apiClient=r;}async startFlow(r){let t=await this.apiClient.startOnboarding({user_role:r.user_role});if(!t.ok)return u(t.error);let{session_id:n}=t.value;for(let s=0;s<Ce;s++){await new Promise(c=>setTimeout(c,we));let o=await this.apiClient.getOnboardingStatus(n);if(!o.ok)return u(o.error);let p=o.value.status,d=o.value.onboarding_url;if(p==="pending_passkey"){let c=await this.apiClient.getOnboardingRegister(n);if(!c.ok)return u(c.error);let y=c.value;if(!y.challenge)return u(f("NOT_SUPPORTED","Onboarding requires user action - complete passkey registration at the provided onboarding_url",{onboarding_url:d}));let m=Q(y.challenge);if(!m.ok)return u(m.error);let T;try{T=await navigator.credentials.create(m.value);}catch(S){return u(_(S))}try{w(T,"create");}catch(S){return u(_(S))}let E;try{E=L(T);}catch(S){return u(_(S))}let b=await this.apiClient.registerOnboardingPasskey(n,{credential:E,challenge:y.challenge.challenge});return b.ok?await this.apiClient.completeOnboarding(n,{company_name:r.company_name}):u(b.error)}if(p==="completed")return await this.apiClient.completeOnboarding(n,{company_name:r.company_name})}return u(f("TIMEOUT","Onboarding timed out"))}};var j=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 ge="https://api.trymellonauth.com",me="https://api.trymellonauth.com/v1/telemetry";function fe(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:true});}}}function ee(e,r){return {event:e,latencyMs:r,ok:true}}var re=class{apiClient;eventEmitter;telemetrySender;onboarding;constructor(r){let t=r.appId,n=r.publishableKey;if(!t||typeof t!="string"||t.trim()==="")throw A("appId","must be a non-empty string");if(!n||typeof n!="string"||n.trim()==="")throw A("publishableKey","must be a non-empty string");let s=r.apiBaseUrl??ge;oe(s,"apiBaseUrl");let o=r.timeoutMs??3e4;x(o,"timeoutMs",1e3,3e5),r.maxRetries!==void 0&&x(r.maxRetries,"maxRetries",0,10),r.retryDelayMs!==void 0&&x(r.retryDelayMs,"retryDelayMs",100,1e4);let p=r.maxRetries??3,d=r.retryDelayMs??1e3,c=new F(o,p,d,r.logger),y={"X-App-Id":t.trim(),Authorization:`Bearer ${n.trim()}`};this.apiClient=new U(c,s,y),this.onboarding=new K(this.apiClient),this.eventEmitter=new j,r.enableTelemetry&&(this.telemetrySender=r.telemetrySender??fe(r.telemetryEndpoint??me));}static isSupported(){return O()}async register(r){let t=Date.now(),n=await de(r,this.apiClient,this.eventEmitter);return n.ok&&this.telemetrySender&&this.telemetrySender.send(ee("register",Date.now()-t)).catch(()=>{}),n}async authenticate(r){let t=Date.now(),n=await ce(r,this.apiClient,this.eventEmitter);return n.ok&&this.telemetrySender&&this.telemetrySender.send(ee("authenticate",Date.now()-t)).catch(()=>{}),n}async validateSession(r){return this.apiClient.validateSession(r)}async getStatus(){return le()}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 te=class{debug(r,t){t&&Object.keys(t).length>0?console.debug(`[TryMellon] ${r}`,t):console.debug(`[TryMellon] ${r}`);}info(r,t){t&&Object.keys(t).length>0?console.info(`[TryMellon] ${r}`,t):console.info(`[TryMellon] ${r}`);}warn(r,t){t&&Object.keys(t).length>0?console.warn(`[TryMellon] ${r}`,t):console.warn(`[TryMellon] ${r}`);}error(r,t){t&&Object.keys(t).length>0?console.error(`[TryMellon] ${r}`,t):console.error(`[TryMellon] ${r}`);}};
2
+ exports.ConsoleLogger=te;exports.TryMellon=re;exports.TryMellonError=M;exports.createError=f;exports.createInvalidArgumentError=A;exports.createNetworkError=be;exports.createNotSupportedError=C;exports.createTimeoutError=Ee;exports.createUserCancelledError=he;exports.err=u;exports.isTryMellonError=se;exports.mapWebAuthnError=_;exports.ok=R;return exports;})({});//# sourceMappingURL=index.global.js.map
3
+ //# sourceMappingURL=index.global.js.map