@syndew/oluso-sdk 0.0.0-stage → 0.1.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.
@@ -0,0 +1,810 @@
1
+ /**
2
+ * SDK Configuration
3
+ */
4
+ interface OlusoConfig {
5
+ /**
6
+ * Base URL of the Oluso server
7
+ * @example "https://auth.oluso.io"
8
+ */
9
+ serverUrl: string;
10
+ /**
11
+ * Tenant identifier (subdomain or ID). Leave it out when the server URL is the tenant's own host, or when your
12
+ * `fetch` already names the tenant.
13
+ * @example "acme" or "tenant_abc123"
14
+ */
15
+ tenant?: string;
16
+ /**
17
+ * Optional public API key for rate limiting/analytics
18
+ * Not used for authentication - journeys handle their own auth
19
+ */
20
+ apiKey?: string;
21
+ /**
22
+ * Custom fetch implementation (for SSR or testing)
23
+ */
24
+ fetch?: typeof fetch;
25
+ /**
26
+ * Extra headers for each request, e.g. the signed-in user's access token (and DPoP proof) for a session your
27
+ * own backend started for that user. Called per request with its method and URL.
28
+ */
29
+ headers?: (request: {
30
+ method: string;
31
+ url: string;
32
+ }) => Record<string, string> | Promise<Record<string, string>>;
33
+ }
34
+ /**
35
+ * Field definition from a journey policy
36
+ */
37
+ interface JourneyField {
38
+ name: string;
39
+ type: 'text' | 'email' | 'password' | 'number' | 'date' | 'tel' | 'url' | 'textarea' | 'select' | 'radio' | 'checkbox';
40
+ label: string;
41
+ placeholder?: string;
42
+ description?: string;
43
+ required: boolean;
44
+ options?: Array<{
45
+ value: string;
46
+ label: string;
47
+ }>;
48
+ validation?: {
49
+ minLength?: number;
50
+ maxLength?: number;
51
+ pattern?: string;
52
+ min?: number;
53
+ max?: number;
54
+ };
55
+ }
56
+ /**
57
+ * Journey metadata returned from the API
58
+ */
59
+ interface JourneyInfo {
60
+ id: string;
61
+ name: string;
62
+ type: string;
63
+ description?: string;
64
+ fields: JourneyField[];
65
+ ui?: {
66
+ title?: string;
67
+ logoUrl?: string;
68
+ primaryColor?: string;
69
+ backgroundColor?: string;
70
+ };
71
+ requiresAuthentication: boolean;
72
+ }
73
+ /**
74
+ * Submission result
75
+ */
76
+ interface SubmissionResult {
77
+ success: boolean;
78
+ submissionId?: string;
79
+ message?: string;
80
+ redirectUrl?: string;
81
+ errors?: Record<string, string>;
82
+ }
83
+ /**
84
+ * A journey running step by step through the headless API (start, step, session).
85
+ * Every headless call returns the session as it stands after the call.
86
+ */
87
+ interface JourneySession {
88
+ sessionId: string;
89
+ /** The journey's slug */
90
+ slug: string;
91
+ status: 'in_progress' | 'completed' | 'failed' | 'cancelled' | 'expired';
92
+ success: boolean;
93
+ completed: boolean;
94
+ /** The step waiting for input, while in progress */
95
+ currentStep?: string;
96
+ /** Same as currentStep: set while there is a step to complete */
97
+ nextStep?: string;
98
+ completedSteps: string[];
99
+ expiresAt?: string;
100
+ /** What to render for the current step */
101
+ step?: JourneyStepView;
102
+ /** The step continues elsewhere (e.g. an external identity provider) */
103
+ redirectUrl?: string;
104
+ /** Authentication journeys: the authorization code to redeem with the PKCE verifier */
105
+ code?: string;
106
+ /** Data-collection journeys: the success message once completed */
107
+ message?: string;
108
+ error?: string;
109
+ errorDescription?: string;
110
+ }
111
+ /** A step to render: its definition and the model the server renders it from */
112
+ interface JourneyStepView {
113
+ id: string;
114
+ /** Step type, e.g. local_login, mfa, dynamic_form */
115
+ type: string;
116
+ displayName?: string;
117
+ /** The server view the step renders as */
118
+ view?: string;
119
+ /** Fields, options, messages and errors for the step */
120
+ model?: Record<string, unknown>;
121
+ /** The step as a form any client can draw (see JourneyStepForm) */
122
+ form?: JourneyStepForm;
123
+ /** The hosted view's markup, for a step that has no form description (custom pages, plugin views) */
124
+ html?: string;
125
+ actions: JourneyStepAction[];
126
+ }
127
+ /**
128
+ * A step as a form. Posting its fields with the clicked action's name and value is exactly what the hosted page
129
+ * posts, so any journey step can be drawn by any client.
130
+ */
131
+ interface JourneyStepForm {
132
+ title?: string;
133
+ description?: string;
134
+ /** What went wrong with the last submission */
135
+ error?: string;
136
+ /** Something to tell the person that isn't an error */
137
+ notice?: string;
138
+ fields: JourneyFormField[];
139
+ /** The buttons, in order; each posts the fields with its own name and value */
140
+ actions: JourneyFormAction[];
141
+ links: JourneyFormLink[];
142
+ /** Browser work for the step: passkey, captcha, QR code, recovery codes or waiting */
143
+ widget?: JourneyFormWidget;
144
+ }
145
+ type JourneyFormFieldType = 'text' | 'email' | 'password' | 'number' | 'date' | 'tel' | 'url' | 'textarea' | 'select' | 'radio' | 'checkbox' | 'file' | 'hidden' | 'otp' | 'content';
146
+ interface JourneyFormField {
147
+ name: string;
148
+ type: JourneyFormFieldType | string;
149
+ label?: string;
150
+ placeholder?: string;
151
+ description?: string;
152
+ /** Guidance under the input, e.g. upload limits */
153
+ hint?: string;
154
+ required: boolean;
155
+ readOnly: boolean;
156
+ value?: string;
157
+ error?: string;
158
+ options?: JourneyFormOption[];
159
+ pattern?: string;
160
+ patternError?: string;
161
+ minLength?: number;
162
+ maxLength?: number;
163
+ min?: string;
164
+ max?: string;
165
+ rows?: number;
166
+ autocomplete?: string;
167
+ autofocus: boolean;
168
+ accept?: string;
169
+ maxFiles?: number;
170
+ maxFileSizeMb?: number;
171
+ capture?: string;
172
+ /** Phone: countries to pick from; the country is posted as `${name}__country` */
173
+ countries?: JourneyFormCountry[];
174
+ country?: string;
175
+ showWhen?: JourneyFormCondition;
176
+ /** Shown only while every one of these is met too */
177
+ showWhenAll?: JourneyFormCondition[];
178
+ group?: string;
179
+ }
180
+ interface JourneyFormOption {
181
+ value: string;
182
+ label: string;
183
+ description?: string;
184
+ disabled: boolean;
185
+ }
186
+ interface JourneyFormCountry {
187
+ code: string;
188
+ name: string;
189
+ dialCode: string;
190
+ flag?: string;
191
+ }
192
+ interface JourneyFormCondition {
193
+ field: string;
194
+ operator: string;
195
+ value?: string;
196
+ }
197
+ interface JourneyFormAction {
198
+ /** The posted name; absent for a button that posts no name of its own */
199
+ name?: string;
200
+ value?: string;
201
+ label: string;
202
+ /** Text shown with the button, e.g. "Didn't get the code?" before a resend link */
203
+ description?: string;
204
+ /** A question to confirm before the button posts; the renderer asks inline */
205
+ confirm?: string;
206
+ /** More values the button posts */
207
+ values?: Record<string, string>;
208
+ /** False: the button posts only its own name, value and values, none of the step's fields */
209
+ postsFields: boolean;
210
+ kind: 'primary' | 'secondary' | 'link' | 'cancel' | string;
211
+ skipValidation: boolean;
212
+ }
213
+ interface JourneyFormLink {
214
+ label: string;
215
+ url: string;
216
+ }
217
+ interface JourneyFormWidget {
218
+ type: 'webauthn_get' | 'webauthn_create' | 'captcha' | 'qr' | 'codes' | 'poll' | string;
219
+ data?: Record<string, unknown>;
220
+ /** Where the widget's result is posted */
221
+ resultField?: string;
222
+ /** The action posted with the result */
223
+ submit?: JourneyFormAction;
224
+ }
225
+ interface JourneyStepAction {
226
+ id: string;
227
+ label: string;
228
+ isPrimary: boolean;
229
+ isCancel: boolean;
230
+ }
231
+ /** The session after a step was submitted */
232
+ type StepResult = JourneySession;
233
+ /**
234
+ * Event types emitted by the SDK
235
+ */
236
+ type OlusoEventType = 'journey:started' | 'journey:step' | 'journey:completed' | 'journey:error' | 'submission:success' | 'submission:error' | 'auth:success' | 'auth:error';
237
+ interface OlusoEvent {
238
+ type: OlusoEventType;
239
+ /** The journey's slug */
240
+ slug: string;
241
+ /** The headless session, for journey events */
242
+ sessionId?: string;
243
+ data?: unknown;
244
+ error?: Error;
245
+ }
246
+ type OlusoEventListener = (event: OlusoEvent) => void;
247
+
248
+ /**
249
+ * Oluso SDK Client
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * const oluso = new OlusoClient({
254
+ * serverUrl: 'https://auth.oluso.io',
255
+ * tenant: 'acme',
256
+ * });
257
+ *
258
+ * // Get journey info (form fields, etc.)
259
+ * const journey = await oluso.getJourney('waitlist');
260
+ *
261
+ * // Submit data
262
+ * const result = await oluso.submit('waitlist', {
263
+ * email: 'user@example.com',
264
+ * name: 'John Doe',
265
+ * });
266
+ * ```
267
+ */
268
+ declare class OlusoClient {
269
+ private config;
270
+ private fetchFn;
271
+ private listeners;
272
+ constructor(config: OlusoConfig);
273
+ /**
274
+ * Get journey information including form fields. Journeys are named by slug.
275
+ */
276
+ getJourney(slug: string): Promise<JourneyInfo>;
277
+ /**
278
+ * Submit data to a data collection journey (waitlist, contact, survey, etc.)
279
+ */
280
+ submit(slug: string, data: Record<string, unknown>, options?: {
281
+ /** Client-side metadata */
282
+ metadata?: Record<string, string>;
283
+ /** Honeypot field for spam detection */
284
+ honeypot?: string;
285
+ }): Promise<SubmissionResult>;
286
+ /**
287
+ * Start a multi-step journey and run its first step. Without data the session's `step`
288
+ * is the first step to render; with data, that is the first step's input.
289
+ */
290
+ startJourney(slug: string, data?: Record<string, unknown>): Promise<JourneySession>;
291
+ /**
292
+ * Start a sign-in (or any authentication) journey for a public client. When the session completes it carries an
293
+ * authorization code, redeemed at the token endpoint with the PKCE verifier and redirect_uri "postmessage". Use
294
+ * this when your app keeps its own tokens; OlusoAuth.mountSignIn does the whole round trip for you.
295
+ */
296
+ startAuthJourney(slug: string, auth: {
297
+ clientId: string;
298
+ codeChallenge: string;
299
+ scope?: string;
300
+ }, data?: Record<string, unknown>): Promise<JourneySession>;
301
+ /**
302
+ * Submit input (or an action such as "resend") for the session's current step.
303
+ * The result is the session afterwards: the next step to render, or the completion.
304
+ */
305
+ submitStep(sessionId: string, data?: Record<string, unknown>, action?: string): Promise<StepResult>;
306
+ /**
307
+ * Submit the current step the way a form posts it: every field, files under their field's name, and the
308
+ * clicked button's name and value. Use this for steps with file fields; `action` is a step action such as "init".
309
+ */
310
+ submitStepForm(sessionId: string, form: FormData, action?: string): Promise<StepResult>;
311
+ /** The server this client talks to */
312
+ get serverUrl(): string;
313
+ /**
314
+ * Get where a multi-step session stands (status, current step), without running it
315
+ */
316
+ getSession(sessionId: string): Promise<JourneySession>;
317
+ /**
318
+ * URL of the hosted journey page (/journey/start/{slug}) to redirect to
319
+ */
320
+ getJourneyUrl(slug: string, options?: {
321
+ redirectUri?: string;
322
+ state?: string;
323
+ }): string;
324
+ /**
325
+ * URL of the hosted journey page (/journey/start/{slug}) for an iframe
326
+ */
327
+ getEmbedUrl(slug: string, options?: {
328
+ theme?: 'light' | 'dark';
329
+ hideHeader?: boolean;
330
+ }): string;
331
+ /**
332
+ * Subscribe to SDK events
333
+ */
334
+ on(event: OlusoEventType | '*', listener: OlusoEventListener): () => void;
335
+ /**
336
+ * Unsubscribe from SDK events
337
+ */
338
+ off(event: OlusoEventType | '*', listener: OlusoEventListener): void;
339
+ private emit;
340
+ private request;
341
+ }
342
+ /**
343
+ * Custom error class for SDK errors
344
+ */
345
+ declare class OlusoError extends Error {
346
+ readonly status: number;
347
+ readonly code?: string | undefined;
348
+ readonly fieldErrors?: Record<string, string> | undefined;
349
+ constructor(message: string, status: number, code?: string | undefined, fieldErrors?: Record<string, string> | undefined);
350
+ }
351
+
352
+ /**
353
+ * Oluso Embed Script
354
+ *
355
+ * Drop-in script for running journeys (waitlists, contact forms, surveys, sign-ups) as a modal or inline in a
356
+ * page, step by step. No framework dependencies - works with any HTML page.
357
+ *
358
+ * Usage (declarative):
359
+ * <script src="https://cdn.oluso.io/sdk/embed.js"></script>
360
+ * <div data-oluso-trigger
361
+ * data-oluso-server="https://auth.yoursite.com"
362
+ * data-oluso-tenant="acme"
363
+ * data-oluso-journey="waitlist"
364
+ * data-oluso-button-text="Join Waitlist">
365
+ * </div>
366
+ *
367
+ * Usage (inline, e.g. a contact form in the page):
368
+ * <div data-oluso-inline
369
+ * data-oluso-server="https://auth.yoursite.com"
370
+ * data-oluso-tenant="acme"
371
+ * data-oluso-journey="contact-us">
372
+ * </div>
373
+ *
374
+ * Usage (programmatic):
375
+ * <script src="https://cdn.oluso.io/sdk/embed.js"></script>
376
+ * <button onclick="Oluso.open()">Join</button>
377
+ * <script>
378
+ * Oluso.init({
379
+ * serverUrl: 'https://auth.yoursite.com',
380
+ * tenant: 'acme',
381
+ * journey: 'waitlist',
382
+ * });
383
+ * </script>
384
+ */
385
+ interface EmbedConfig {
386
+ serverUrl: string;
387
+ tenant: string;
388
+ journey: string;
389
+ buttonText?: string;
390
+ title?: string;
391
+ description?: string;
392
+ successTitle?: string;
393
+ successMessage?: string;
394
+ successCta?: {
395
+ text: string;
396
+ url: string;
397
+ };
398
+ theme?: 'dark' | 'light' | 'auto';
399
+ accentColor?: string;
400
+ /** Called with the completed session */
401
+ onSuccess?: (data: Record<string, unknown>) => void;
402
+ onError?: (error: Error) => void;
403
+ }
404
+
405
+ /** Text the renderer shows itself; everything about a step comes from the server in the person's language. */
406
+ interface JourneyLabels {
407
+ loading: string;
408
+ completed: string;
409
+ failed: string;
410
+ expired: string;
411
+ restart: string;
412
+ takePhoto: string;
413
+ copy: string;
414
+ copied: string;
415
+ passkey: string;
416
+ retry: string;
417
+ waiting: string;
418
+ unavailable: string;
419
+ }
420
+ interface MountJourneyOptions {
421
+ client: OlusoClient;
422
+ /** Start this journey (a waitlist, a contact form, a survey, a sign-up). */
423
+ slug?: string;
424
+ /** Input for the first step. */
425
+ data?: Record<string, unknown>;
426
+ /** Continue a session started elsewhere, e.g. one your backend started for the signed-in user. */
427
+ session?: JourneySession;
428
+ /** Start the session yourself, e.g. a sign-in journey with PKCE. */
429
+ start?: () => Promise<JourneySession>;
430
+ /** After every step the server returns. */
431
+ onStep?: (session: JourneySession) => void;
432
+ /** When the journey completes. */
433
+ onComplete?: (session: JourneySession) => void | Promise<void>;
434
+ /** When the journey fails, expires or a request fails. */
435
+ onError?: (error: Error, session?: JourneySession) => void;
436
+ /** When a step continues elsewhere (an external identity provider, a checkout). Defaults to navigating there. */
437
+ onRedirect?: (url: string, session: JourneySession) => void;
438
+ /** Show the completion message when done (default true). */
439
+ showCompletion?: boolean;
440
+ theme?: 'light' | 'dark' | 'auto';
441
+ /** Skip the default styles; style `.oluso-journey__*` yourself. */
442
+ unstyled?: boolean;
443
+ labels?: Partial<JourneyLabels>;
444
+ }
445
+ interface JourneyMount {
446
+ /** The session as it stands. */
447
+ readonly session: JourneySession | undefined;
448
+ /** Start again from the first step (only for journeys started by slug or `start`). */
449
+ restart(): Promise<void>;
450
+ destroy(): void;
451
+ }
452
+ type Element = HTMLElement;
453
+ /**
454
+ * Renders any journey into `container` and runs it step by step: forms, sign-in, verification codes, passkeys,
455
+ * captcha, consent, file uploads. Steps the server describes are drawn natively; a step that only has hosted markup
456
+ * is shown as that markup.
457
+ */
458
+ declare function mountJourney(container: Element, options: MountJourneyOptions): JourneyMount;
459
+
460
+ /**
461
+ * Whether a field's current values meet a showWhen condition, with the server's semantics: positive operators pass
462
+ * when any value matches, negative ones when none does.
463
+ */
464
+ declare function conditionMet(condition: JourneyFormCondition, values: string[]): boolean;
465
+
466
+ interface OidcEndpoints {
467
+ /** Authorization endpoint */
468
+ authorization?: string;
469
+ /** Token endpoint */
470
+ token?: string;
471
+ /** UserInfo endpoint */
472
+ userinfo?: string;
473
+ /** End session / logout endpoint */
474
+ endSession?: string;
475
+ /** JWKS URI */
476
+ jwks?: string;
477
+ }
478
+ interface OlusoAuthConfig {
479
+ /** Base URL of the Oluso server */
480
+ serverUrl: string;
481
+ /** Tenant identifier */
482
+ tenant: string;
483
+ /** OAuth2 client ID (public client) */
484
+ clientId: string;
485
+ /** Redirect URI for OIDC code flow (optional if using inline/modal auth) */
486
+ redirectUri?: string;
487
+ /** Scopes to request (default: "openid profile email") */
488
+ scopes?: string;
489
+ /**
490
+ * Manual OIDC endpoint overrides. If not provided, endpoints are
491
+ * discovered from the server's .well-known/openid-configuration document.
492
+ */
493
+ endpoints?: OidcEndpoints;
494
+ /** Slug of the sign-in journey (default: "signin") */
495
+ signInJourney?: string;
496
+ /** Slug of the sign-up journey (default: "signup") */
497
+ signUpJourney?: string;
498
+ /** Slug of the password-reset journey (default: "password-reset") */
499
+ passwordResetJourney?: string;
500
+ /** Token storage strategy */
501
+ storage?: 'memory' | 'localStorage' | 'sessionStorage';
502
+ /** Public API key for journey endpoints */
503
+ apiKey?: string;
504
+ /** Callback when auth state changes */
505
+ onAuthStateChange?: (user: OlusoUser | null) => void;
506
+ }
507
+ interface OlusoUser {
508
+ /** Subject (user ID) */
509
+ sub: string;
510
+ /** Display name */
511
+ name?: string;
512
+ /** Email address */
513
+ email?: string;
514
+ /** Whether email is verified */
515
+ emailVerified?: boolean;
516
+ /** User roles */
517
+ roles: string[];
518
+ /** User permissions */
519
+ permissions: string[];
520
+ /** Tenant ID */
521
+ tenantId?: string;
522
+ /** Raw ID token claims */
523
+ claims: Record<string, unknown>;
524
+ }
525
+ interface TokenSet {
526
+ accessToken: string;
527
+ idToken?: string;
528
+ refreshToken?: string;
529
+ expiresAt: number;
530
+ tokenType: string;
531
+ scope?: string;
532
+ }
533
+ interface AuthResult {
534
+ success: boolean;
535
+ user?: OlusoUser;
536
+ tokens?: TokenSet;
537
+ error?: string;
538
+ code?: string;
539
+ /** The journey needs another step (e.g. "mfa"): continue it with continueStep(sessionId, ...) */
540
+ requiresStep?: string;
541
+ sessionId?: string;
542
+ /** What to render for that step */
543
+ step?: JourneyStepView;
544
+ /** The step continues at an external identity provider */
545
+ redirectUrl?: string;
546
+ }
547
+ interface JourneyStepData {
548
+ /** Current step identifier */
549
+ step: string;
550
+ /** Fields to display for this step */
551
+ fields: JourneyField[];
552
+ /** Step title */
553
+ title?: string;
554
+ /** Step description */
555
+ description?: string;
556
+ }
557
+ /** Options for signInWithPasskey */
558
+ interface PasskeyOptions {
559
+ /** Username for username-based flow. Omit for discoverable credential (usernameless) flow. */
560
+ username?: string;
561
+ /** Whether to use conditional mediation (passkey autofill in input fields) */
562
+ conditional?: boolean;
563
+ /** Abort signal to cancel the passkey prompt */
564
+ signal?: AbortSignal;
565
+ }
566
+ /** Options for signInWithFedCM */
567
+ interface FedCmOptions {
568
+ /** Whether to use auto-reauthentication (silent sign-in if user previously approved) */
569
+ autoReauth?: boolean;
570
+ /** Nonce for token binding */
571
+ nonce?: string;
572
+ /** Login hint (email or username) to pre-select an account */
573
+ loginHint?: string;
574
+ }
575
+ /** WebAuthn assertion options returned by the server */
576
+ interface WebAuthnAssertionOptions {
577
+ assertionId: string;
578
+ challenge: string;
579
+ timeout: number;
580
+ rpId?: string;
581
+ allowCredentials?: Array<{
582
+ type: string;
583
+ id: string;
584
+ transports?: string[];
585
+ }>;
586
+ userVerification: string;
587
+ }
588
+ /** Options for OlusoAuth.mountSignIn. */
589
+ interface MountSignInOptions {
590
+ /** Slug of the journey to run (default: the configured sign-in journey) */
591
+ journey?: string;
592
+ /** Called with the outcome once the journey completes and the code is redeemed */
593
+ onSignedIn?: (result: AuthResult) => void;
594
+ onError?: (error: Error) => void;
595
+ /** A step continues at an external identity provider; defaults to navigating there */
596
+ onRedirect?: (url: string) => void;
597
+ theme?: 'light' | 'dark' | 'auto';
598
+ unstyled?: boolean;
599
+ labels?: Partial<JourneyLabels>;
600
+ }
601
+
602
+ /**
603
+ * Oluso Auth Client
604
+ *
605
+ * Handles authentication via OIDC (redirect), the hosted journey in a modal, or the
606
+ * journey run step by step from your own UI (inline). Inline journeys complete with an
607
+ * authorization code bound to this client's PKCE verifier, redeemed for tokens here.
608
+ *
609
+ * @example
610
+ * ```typescript
611
+ * const auth = new OlusoAuth({
612
+ * serverUrl: 'https://auth.yoursite.com',
613
+ * tenant: 'acme',
614
+ * clientId: 'my-spa-client',
615
+ * });
616
+ *
617
+ * // Inline auth (no redirect)
618
+ * const result = await auth.signIn({ username: 'user@example.com', password: '...' });
619
+ * if (result.success) {
620
+ * console.log('Logged in as', result.user.name);
621
+ * }
622
+ *
623
+ * // Check roles
624
+ * if (auth.hasRole('admin')) { ... }
625
+ * ```
626
+ */
627
+ declare class OlusoAuth {
628
+ private config;
629
+ private storage;
630
+ private user;
631
+ private resolvedEndpoints;
632
+ private discoveryPromise;
633
+ /** PKCE verifiers of inline journeys still in progress, by session */
634
+ private readonly journeyVerifiers;
635
+ constructor(config: OlusoAuthConfig);
636
+ /**
637
+ * Sign in.
638
+ * - With data: run the sign-in journey inline with these inputs (programmatic, first-party
639
+ * only). If another step follows (e.g. MFA), the result has requiresStep, sessionId and
640
+ * the step to render; continue with continueStep().
641
+ * - Without data: open the hosted journey in a secure iframe modal (safe for any site)
642
+ */
643
+ signIn(data?: Record<string, unknown>): Promise<AuthResult>;
644
+ /**
645
+ * Sign up.
646
+ * - With data: run the sign-up journey inline (programmatic, first-party only)
647
+ * - Without data: open the hosted journey in a secure iframe modal
648
+ */
649
+ signUp(data?: Record<string, unknown>): Promise<AuthResult>;
650
+ /**
651
+ * Sign in with a passkey (WebAuthn).
652
+ * No form or iframe needed — the browser shows a native biometric/key prompt.
653
+ * Works with discoverable credentials (usernameless) or username-based flow.
654
+ *
655
+ * @example
656
+ * ```typescript
657
+ * // Discoverable credential (passkey autofill or prompt)
658
+ * const result = await auth.signInWithPasskey();
659
+ *
660
+ * // Username-based (shows credentials for specific user)
661
+ * const result = await auth.signInWithPasskey({ username: 'user@example.com' });
662
+ *
663
+ * // Conditional mediation (passkey suggestions in input fields)
664
+ * const result = await auth.signInWithPasskey({ conditional: true });
665
+ * ```
666
+ */
667
+ signInWithPasskey(options?: PasskeyOptions): Promise<AuthResult>;
668
+ /**
669
+ * Sign in with FedCM (Federated Credential Management).
670
+ * Opens a browser-native account picker — no redirect or popup needed.
671
+ * Requires the user to be already authenticated on the Oluso server (has session cookie).
672
+ *
673
+ * Browser support: Chrome/Edge 132+ (the provider `params` that carry the PKCE challenge).
674
+ * The page origin must be registered for the client (CORS origin or redirect URI).
675
+ *
676
+ * @example
677
+ * ```typescript
678
+ * const result = await auth.signInWithFedCM();
679
+ * if (result.success) {
680
+ * console.log('Signed in as', result.user.name);
681
+ * }
682
+ * ```
683
+ */
684
+ signInWithFedCM(options?: FedCmOptions): Promise<AuthResult>;
685
+ /**
686
+ * Render the sign-in journey into `container` and sign in without leaving the page, e.g. in a modal when the
687
+ * session has expired. Every step the journey has (password, MFA, passkey, consent) is shown; when it completes,
688
+ * the code is redeemed and `onSignedIn` gets the result.
689
+ */
690
+ mountSignIn(container: HTMLElement, options?: MountSignInOptions): JourneyMount;
691
+ /**
692
+ * Continue an inline journey with the input for its current step (e.g. an MFA code)
693
+ */
694
+ continueStep(sessionId: string, data: Record<string, unknown>): Promise<AuthResult>;
695
+ /**
696
+ * Get the fields/config of a data-collection journey (for rendering in UI)
697
+ */
698
+ getJourneyStep(journeySlug: string): Promise<JourneyStepData | null>;
699
+ /**
700
+ * Redirect to the Oluso login page (standard OIDC Authorization Code + PKCE)
701
+ */
702
+ loginWithRedirect(options?: {
703
+ prompt?: 'login' | 'consent' | 'none';
704
+ state?: string;
705
+ }): Promise<void>;
706
+ /**
707
+ * Handle the OIDC callback (exchange code for tokens)
708
+ */
709
+ handleCallback(callbackUrl?: string): Promise<AuthResult>;
710
+ /**
711
+ * Get the current user (null if not authenticated)
712
+ */
713
+ getUser(): OlusoUser | null;
714
+ /**
715
+ * Check if user is authenticated (has valid tokens)
716
+ */
717
+ isAuthenticated(): boolean;
718
+ /**
719
+ * Get the current access token (for API calls)
720
+ */
721
+ getAccessToken(): string | null;
722
+ /**
723
+ * Check if user has a specific role
724
+ */
725
+ hasRole(role: string): boolean;
726
+ /**
727
+ * Check if user has any of the specified roles
728
+ */
729
+ hasAnyRole(...roles: string[]): boolean;
730
+ /**
731
+ * Check if user has a specific permission
732
+ */
733
+ hasPermission(permission: string): boolean;
734
+ /**
735
+ * Refresh the access token using the refresh token
736
+ */
737
+ refreshToken(): Promise<boolean>;
738
+ /**
739
+ * Log out — clear tokens and optionally redirect to end session.
740
+ * If redirect is true, uses discovered or configured end_session_endpoint.
741
+ */
742
+ logout(options?: {
743
+ redirect?: boolean;
744
+ postLogoutRedirectUri?: string;
745
+ }): void;
746
+ /**
747
+ * Fetch the user's profile from the userinfo endpoint
748
+ */
749
+ fetchUserInfo(): Promise<OlusoUser | null>;
750
+ /**
751
+ * Opens a secure iframe modal for authentication.
752
+ * Credentials are entered inside the iframe (auth server origin).
753
+ * Returns tokens via postMessage + PKCE code exchange.
754
+ */
755
+ private openAuthModal;
756
+ /**
757
+ * Get OIDC endpoints — uses manual overrides, falls back to discovery.
758
+ */
759
+ private getEndpoints;
760
+ private discoverEndpoints;
761
+ private defaultEndpoints;
762
+ private executeJourney;
763
+ /**
764
+ * Completed: redeem the code with the journey's verifier. In progress: hand back the step
765
+ * to render (an error from the step's last input, e.g. a wrong password, rides along).
766
+ */
767
+ private handleJourneyResult;
768
+ private processTokenResponse;
769
+ private parseIdToken;
770
+ private claimsToUser;
771
+ private parseArrayClaim;
772
+ private buildHeaders;
773
+ private generatePkce;
774
+ private base64UrlEncode;
775
+ private base64UrlDecode;
776
+ /**
777
+ * Exchange an authorization code for tokens via the token endpoint.
778
+ * Used by passkey, FedCM, and modal auth flows.
779
+ */
780
+ private exchangeCodeForTokens;
781
+ }
782
+
783
+ /**
784
+ * Token storage abstraction
785
+ */
786
+ interface TokenStorage {
787
+ getTokens(): TokenSet | null;
788
+ setTokens(tokens: TokenSet): void;
789
+ clear(): void;
790
+ }
791
+
792
+ /**
793
+ * Create an Oluso client instance
794
+ *
795
+ * @example
796
+ * ```typescript
797
+ * import { createClient } from '@syndew/oluso-sdk';
798
+ *
799
+ * const oluso = createClient({
800
+ * serverUrl: 'https://auth.yoursite.com',
801
+ * tenant: 'acme',
802
+ * });
803
+ *
804
+ * // Submit to a waitlist
805
+ * await oluso.submit('waitlist', { email: 'user@example.com' });
806
+ * ```
807
+ */
808
+ declare function createClient(config: OlusoConfig): OlusoClient;
809
+
810
+ export { type AuthResult, type EmbedConfig, type FedCmOptions, type JourneyField, type JourneyFormAction, type JourneyFormCondition, type JourneyFormCountry, type JourneyFormField, type JourneyFormFieldType, type JourneyFormLink, type JourneyFormOption, type JourneyFormWidget, type JourneyInfo, type JourneyLabels, type JourneyMount, type JourneySession, type JourneyStepAction, type JourneyStepData, type JourneyStepForm, type JourneyStepView, type MountJourneyOptions, type MountSignInOptions, type OidcEndpoints, OlusoAuth, type OlusoAuthConfig, OlusoClient, type OlusoConfig, OlusoError, type OlusoEvent, type OlusoEventListener, type OlusoEventType, type OlusoUser, type PasskeyOptions, type StepResult, type SubmissionResult, type TokenSet, type TokenStorage, type WebAuthnAssertionOptions, conditionMet, createClient, mountJourney };