@quiltt/vue 5.1.2

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,703 @@
1
+ import { version as version$1, inject, computed, ref, watch, onMounted, onUnmounted, toValue, defineComponent, h } from 'vue';
2
+ import { AuthAPI, JsonWebTokenParse, cdnBase } from '@quiltt/core';
3
+ import { getSDKAgent as getSDKAgent$1, getBrowserInfo, extractVersionNumber } from '@quiltt/core/utils';
4
+
5
+ const oauthRedirectUrlDeprecationWarning = '[Quiltt] `oauthRedirectUrl` is deprecated. Use `appLauncherUrl` instead. `oauthRedirectUrl` will be removed in the next major release.';
6
+
7
+ /**
8
+ * Gets the Vue version from the runtime
9
+ */ const getVueVersion = ()=>{
10
+ return version$1 || 'unknown';
11
+ };
12
+ /**
13
+ * Detects if running in a Capacitor native environment
14
+ */ const getCapacitorInfo = ()=>{
15
+ if (typeof window === 'undefined') return null;
16
+ try {
17
+ if (window.Capacitor?.isNativePlatform?.()) {
18
+ const platform = window.Capacitor.getPlatform?.() || 'native';
19
+ // Map platform names to correct capitalization
20
+ const platformNames = {
21
+ ios: 'iOS',
22
+ android: 'Android',
23
+ web: 'Web'
24
+ };
25
+ const platformName = platformNames[platform.toLowerCase()] || platform;
26
+ return `Capacitor/${platformName}`;
27
+ }
28
+ } catch {
29
+ // Ignore errors
30
+ }
31
+ return null;
32
+ };
33
+ /**
34
+ * Generates platform information string for Vue web
35
+ * Format: Vue/<version>; <browser>/<version>
36
+ * Or with Capacitor: Vue/<version>; Capacitor/<platform>; <browser>/<version>
37
+ */ const getPlatformInfo = ()=>{
38
+ const versionStr = getVueVersion();
39
+ const capacitorInfo = getCapacitorInfo();
40
+ const browserInfo = getBrowserInfo();
41
+ if (capacitorInfo) {
42
+ return `Vue/${versionStr}; ${capacitorInfo}; ${browserInfo}`;
43
+ }
44
+ return `Vue/${versionStr}; ${browserInfo}`;
45
+ };
46
+ /**
47
+ * Generates User-Agent string for Vue SDK
48
+ * Format: Quiltt/<sdk-version> (Vue/<vue-version>; <browser>/<version>)
49
+ */ const getSDKAgent = (sdkVersion)=>{
50
+ const platformInfo = getPlatformInfo();
51
+ return getSDKAgent$1(sdkVersion, platformInfo);
52
+ };
53
+
54
+ var version = "5.1.2";
55
+
56
+ /**
57
+ * Injection keys and types for Quiltt Vue plugin
58
+ */ // Injection keys for Quiltt state
59
+ const QuilttSessionKey = Symbol.for('quiltt-session');
60
+ const QuilttSetSessionKey = Symbol.for('quiltt-set-session');
61
+ const QuilttClientIdKey = Symbol.for('quiltt-client-id');
62
+
63
+ // Initialize JWT parser
64
+ const parse = JsonWebTokenParse;
65
+ /**
66
+ * Composable for managing Quiltt session state
67
+ *
68
+ * Provides methods for importing, creating, and revoking sessions.
69
+ * Session state is automatically synchronized across components.
70
+ * Requires QuilttPlugin provider context and throws when used without it.
71
+ */ const useQuilttSession = ()=>{
72
+ const sessionRef = inject(QuilttSessionKey);
73
+ const setSession = inject(QuilttSetSessionKey);
74
+ const clientIdRef = inject(QuilttClientIdKey);
75
+ if (!sessionRef || !setSession) {
76
+ throw new Error('[Quiltt] useQuilttSession must be used within a component where QuilttPlugin is installed. ' + 'Make sure to call app.use(QuilttPlugin) before mounting your app.');
77
+ }
78
+ // Create a computed ref for the session
79
+ const session = computed(()=>sessionRef.value);
80
+ // Create AuthAPI instance (memoized based on clientId)
81
+ const getAuth = ()=>new AuthAPI(clientIdRef?.value);
82
+ /**
83
+ * Import an existing session token
84
+ * Validates the token and sets it as the current session
85
+ */ const importSession = async (token, environmentId)=>{
86
+ const auth = getAuth();
87
+ // Is there a token?
88
+ if (!token) return !!sessionRef.value;
89
+ // Is this token already imported?
90
+ if (sessionRef.value && sessionRef.value.token === token) return true;
91
+ const jwt = parse(token);
92
+ // Is this token a valid JWT?
93
+ if (!jwt) return false;
94
+ // Is this token within the expected environment?
95
+ if (environmentId && jwt.claims.eid !== environmentId) return false;
96
+ // Is this token active?
97
+ const response = await auth.ping(token);
98
+ switch(response.status){
99
+ case 200:
100
+ setSession(token);
101
+ return true;
102
+ case 401:
103
+ return false;
104
+ default:
105
+ throw new Error(`AuthAPI.ping: Unexpected response status ${response.status}`);
106
+ }
107
+ };
108
+ /**
109
+ * Start authentication flow with username/email/phone
110
+ * Returns a session token or challenges for passcode
111
+ */ const identifySession = async (payload, callbacks)=>{
112
+ const auth = getAuth();
113
+ const response = await auth.identify(payload);
114
+ switch(response.status){
115
+ case 201:
116
+ setSession(response.data.token);
117
+ if (callbacks.onSuccess) return callbacks.onSuccess();
118
+ break;
119
+ case 202:
120
+ if (callbacks.onChallenged) return callbacks.onChallenged();
121
+ break;
122
+ case 403:
123
+ if (callbacks.onForbidden) return callbacks.onForbidden();
124
+ break;
125
+ case 422:
126
+ if (callbacks.onError) return callbacks.onError(response.data);
127
+ break;
128
+ default:
129
+ throw new Error(`AuthAPI.identify: Unexpected response status ${response.status}`);
130
+ }
131
+ };
132
+ /**
133
+ * Complete authentication with passcode
134
+ */ const authenticateSession = async (payload, callbacks)=>{
135
+ const auth = getAuth();
136
+ const response = await auth.authenticate(payload);
137
+ switch(response.status){
138
+ case 201:
139
+ setSession(response.data.token);
140
+ if (callbacks.onSuccess) return callbacks.onSuccess();
141
+ break;
142
+ case 401:
143
+ if (callbacks.onFailure) return callbacks.onFailure();
144
+ break;
145
+ case 422:
146
+ if (callbacks.onError) return callbacks.onError(response.data);
147
+ break;
148
+ default:
149
+ throw new Error(`AuthAPI.authenticate: Unexpected response status ${response.status}`);
150
+ }
151
+ };
152
+ /**
153
+ * Revoke the current session
154
+ * Invalidates the token on the server and clears local state
155
+ */ const revokeSession = async ()=>{
156
+ if (!sessionRef.value) return;
157
+ const auth = getAuth();
158
+ await auth.revoke(sessionRef.value.token);
159
+ setSession(null);
160
+ };
161
+ /**
162
+ * Forget the current session locally without server call
163
+ * Optionally pass a specific token to guard against async processes clearing wrong session
164
+ */ const forgetSession = (token)=>{
165
+ if (!token || sessionRef.value && token === sessionRef.value.token) {
166
+ setSession(null);
167
+ }
168
+ };
169
+ return {
170
+ session,
171
+ importSession,
172
+ identifySession,
173
+ authenticateSession,
174
+ revokeSession,
175
+ forgetSession
176
+ };
177
+ };
178
+
179
+ /**
180
+ * Load the Quiltt SDK script
181
+ */ const loadScript = (src, nonce)=>{
182
+ return new Promise((resolve, reject)=>{
183
+ // Check if already loaded
184
+ if (typeof Quiltt !== 'undefined') {
185
+ resolve();
186
+ return;
187
+ }
188
+ // Check if script is already in DOM
189
+ const existing = document.querySelector(`script[src^="${src.split('?')[0]}"]`);
190
+ if (existing) {
191
+ existing.addEventListener('load', ()=>resolve());
192
+ existing.addEventListener('error', ()=>reject(new Error('Failed to load Quiltt SDK')));
193
+ return;
194
+ }
195
+ const script = document.createElement('script');
196
+ script.src = src;
197
+ script.async = true;
198
+ if (nonce) script.nonce = nonce;
199
+ script.onload = ()=>resolve();
200
+ script.onerror = ()=>reject(new Error('Failed to load Quiltt SDK'));
201
+ document.head.appendChild(script);
202
+ });
203
+ };
204
+ /**
205
+ * Composable for managing Quiltt Connector
206
+ *
207
+ * Loads the Quiltt SDK script and provides methods to open/manage connectors.
208
+ * This composable can run without QuilttPlugin session context; when unavailable,
209
+ * it logs a warning and continues without authenticated session state.
210
+ */ const useQuilttConnector = (connectorId, options)=>{
211
+ const getConnectorId = ()=>toValue(connectorId);
212
+ const getConnectionId = ()=>toValue(options?.connectionId);
213
+ const getInstitution = ()=>toValue(options?.institution);
214
+ const getOauthRedirectUrl = ()=>toValue(options?.oauthRedirectUrl);
215
+ const getAppLauncherUri = ()=>toValue(options?.appLauncherUrl) ?? getOauthRedirectUrl();
216
+ const session = ref();
217
+ try {
218
+ const quilttSession = useQuilttSession();
219
+ session.value = quilttSession.session.value;
220
+ watch(()=>quilttSession.session.value, (nextSession)=>{
221
+ session.value = nextSession;
222
+ }, {
223
+ immediate: true
224
+ });
225
+ } catch (error) {
226
+ console.warn('[Quiltt] useQuilttConnector: QuilttPlugin not found in the current app context. ' + 'Continuing without session authentication.', error);
227
+ }
228
+ const connector = ref();
229
+ const isLoaded = ref(false);
230
+ const isOpening = ref(false);
231
+ const isConnectorOpen = ref(false);
232
+ // Track previous values
233
+ let prevConnectionId = getConnectionId();
234
+ let prevConnectorId = getConnectorId();
235
+ let prevInstitution = getInstitution();
236
+ let prevAppLauncherUri = getAppLauncherUri();
237
+ let connectorCreated = false;
238
+ // Load SDK script on mount
239
+ onMounted(async ()=>{
240
+ const sdkVersion = extractVersionNumber(version);
241
+ const userAgent = getSDKAgent(sdkVersion);
242
+ const scriptUrl = `${cdnBase}/v1/connector.js?agent=${encodeURIComponent(userAgent)}`;
243
+ try {
244
+ await loadScript(scriptUrl, options?.nonce);
245
+ isLoaded.value = true;
246
+ } catch (error) {
247
+ console.error('[Quiltt] Failed to load SDK:', error);
248
+ }
249
+ });
250
+ // Update authentication when session changes
251
+ watch(()=>session.value?.token, (token)=>{
252
+ if (typeof Quiltt !== 'undefined') {
253
+ Quiltt.authenticate(token);
254
+ }
255
+ }, {
256
+ immediate: true
257
+ });
258
+ // Handle script loaded
259
+ watch(isLoaded, (loaded)=>{
260
+ if (!loaded || typeof Quiltt === 'undefined') return;
261
+ // Authenticate with current session
262
+ Quiltt.authenticate(session.value?.token);
263
+ }, {
264
+ immediate: true
265
+ });
266
+ watch(getOauthRedirectUrl, (oauthRedirectUrl)=>{
267
+ if (oauthRedirectUrl !== undefined) {
268
+ console.warn(oauthRedirectUrlDeprecationWarning);
269
+ }
270
+ }, {
271
+ immediate: true
272
+ });
273
+ // Create/update connector when needed
274
+ const updateConnector = ()=>{
275
+ const currentConnectorId = getConnectorId();
276
+ if (!isLoaded.value || typeof Quiltt === 'undefined' || !currentConnectorId) return;
277
+ const currentConnectionId = getConnectionId();
278
+ const currentInstitution = getInstitution();
279
+ const currentAppLauncherUri = getAppLauncherUri();
280
+ // Check for changes
281
+ const connectionIdChanged = prevConnectionId !== currentConnectionId;
282
+ const connectorIdChanged = prevConnectorId !== currentConnectorId;
283
+ const institutionChanged = prevInstitution !== currentInstitution;
284
+ const appLauncherUrlChanged = prevAppLauncherUri !== currentAppLauncherUri;
285
+ const hasChanges = connectionIdChanged || connectorIdChanged || institutionChanged || appLauncherUrlChanged || !connectorCreated;
286
+ if (hasChanges) {
287
+ if (currentConnectionId) {
288
+ // Reconnect mode
289
+ connector.value = Quiltt.reconnect(currentConnectorId, {
290
+ connectionId: currentConnectionId,
291
+ appLauncherUrl: currentAppLauncherUri
292
+ });
293
+ } else {
294
+ // Connect mode
295
+ connector.value = Quiltt.connect(currentConnectorId, {
296
+ institution: currentInstitution,
297
+ appLauncherUrl: currentAppLauncherUri
298
+ });
299
+ }
300
+ connectorCreated = true;
301
+ prevConnectionId = currentConnectionId;
302
+ prevConnectorId = currentConnectorId;
303
+ prevInstitution = currentInstitution;
304
+ prevAppLauncherUri = currentAppLauncherUri;
305
+ }
306
+ };
307
+ // Watch for changes that require connector update
308
+ watch([
309
+ isLoaded,
310
+ getConnectorId,
311
+ getConnectionId,
312
+ getInstitution,
313
+ getAppLauncherUri
314
+ ], updateConnector, {
315
+ immediate: true
316
+ });
317
+ // Register event handlers when connector changes
318
+ watch(connector, (newConnector, oldConnector)=>{
319
+ if (!newConnector) return;
320
+ // Register handlers
321
+ if (options?.onEvent) {
322
+ newConnector.onEvent(options.onEvent);
323
+ }
324
+ newConnector.onOpen((metadata)=>{
325
+ isConnectorOpen.value = true;
326
+ options?.onOpen?.(metadata);
327
+ });
328
+ if (options?.onLoad) {
329
+ newConnector.onLoad(options.onLoad);
330
+ }
331
+ newConnector.onExit((type, metadata)=>{
332
+ isConnectorOpen.value = false;
333
+ options?.onExit?.(type, metadata);
334
+ });
335
+ if (options?.onExitSuccess) {
336
+ newConnector.onExitSuccess(options.onExitSuccess);
337
+ }
338
+ if (options?.onExitAbort) {
339
+ newConnector.onExitAbort(options.onExitAbort);
340
+ }
341
+ if (options?.onExitError) {
342
+ newConnector.onExitError(options.onExitError);
343
+ }
344
+ }, {
345
+ immediate: true
346
+ });
347
+ // Handle deferred opening
348
+ watch([
349
+ connector,
350
+ isOpening
351
+ ], ([conn, opening])=>{
352
+ if (conn && opening) {
353
+ isOpening.value = false;
354
+ conn.open();
355
+ }
356
+ });
357
+ // Warn on unmount if connector is still open
358
+ onUnmounted(()=>{
359
+ if (isConnectorOpen.value) {
360
+ console.error('[Quiltt] useQuilttConnector: Component unmounted while Connector is still open. ' + 'This may lead to memory leaks or unexpected behavior.');
361
+ }
362
+ });
363
+ /**
364
+ * Open the connector modal
365
+ */ const open = ()=>{
366
+ if (getConnectorId()) {
367
+ isOpening.value = true;
368
+ updateConnector();
369
+ } else {
370
+ throw new Error('Must provide connectorId to open Quiltt Connector');
371
+ }
372
+ };
373
+ return {
374
+ open
375
+ };
376
+ };
377
+
378
+ const QuilttButton = defineComponent({
379
+ name: 'QuilttButton',
380
+ props: {
381
+ /** Quiltt Connector ID */ connectorId: {
382
+ type: String,
383
+ required: true
384
+ },
385
+ /** Existing connection ID for reconnection */ connectionId: {
386
+ type: String,
387
+ default: undefined
388
+ },
389
+ /** Pre-select a specific institution */ institution: {
390
+ type: String,
391
+ default: undefined
392
+ },
393
+ /** Deep link URL for OAuth callbacks (mobile apps) */ appLauncherUrl: {
394
+ type: String,
395
+ default: undefined
396
+ },
397
+ /**
398
+ * @deprecated Use `appLauncherUrl` instead. This property will be removed in a future version.
399
+ * The OAuth redirect URL for mobile or embedded webview flows.
400
+ */ oauthRedirectUrl: {
401
+ type: String,
402
+ default: undefined
403
+ },
404
+ /** Render as a different element */ as: {
405
+ type: String,
406
+ default: 'button'
407
+ }
408
+ },
409
+ emits: {
410
+ /** Connector loaded */ load: (_metadata)=>true,
411
+ /** Connector opened */ open: (_metadata)=>true,
412
+ /** Connection successful */ 'exit-success': (_metadata)=>true,
413
+ /** User cancelled */ 'exit-abort': (_metadata)=>true,
414
+ /** Error occurred */ 'exit-error': (_metadata)=>true,
415
+ /** Connector exited (any reason) */ exit: (_type, _metadata)=>true,
416
+ /** Any connector event */ event: (_type, _metadata)=>true
417
+ },
418
+ setup (props, { emit, slots }) {
419
+ watch(()=>props.oauthRedirectUrl, (value)=>{
420
+ if (value !== undefined) {
421
+ console.warn(oauthRedirectUrlDeprecationWarning);
422
+ }
423
+ }, {
424
+ immediate: true
425
+ });
426
+ const effectiveAppLauncherUri = computed(()=>props.appLauncherUrl ?? props.oauthRedirectUrl);
427
+ const { open } = useQuilttConnector(()=>props.connectorId, {
428
+ connectionId: ()=>props.connectionId,
429
+ institution: ()=>props.institution,
430
+ appLauncherUrl: effectiveAppLauncherUri,
431
+ onEvent: (type, metadata)=>emit('event', type, metadata),
432
+ onOpen: (metadata)=>emit('open', metadata),
433
+ onLoad: (metadata)=>emit('load', metadata),
434
+ onExit: (type, metadata)=>emit('exit', type, metadata),
435
+ onExitSuccess: (metadata)=>emit('exit-success', metadata),
436
+ onExitAbort: (metadata)=>emit('exit-abort', metadata),
437
+ onExitError: (metadata)=>emit('exit-error', metadata)
438
+ });
439
+ const handleClick = ()=>{
440
+ open();
441
+ };
442
+ return ()=>h(props.as, {
443
+ class: 'quiltt-button',
444
+ onClick: handleClick
445
+ }, slots.default?.());
446
+ }
447
+ });
448
+
449
+ const QuilttConnector = defineComponent({
450
+ name: 'QuilttConnector',
451
+ props: {
452
+ /** Quiltt Connector ID */ connectorId: {
453
+ type: String,
454
+ required: true
455
+ },
456
+ /** Existing connection ID for reconnection */ connectionId: {
457
+ type: String,
458
+ default: undefined
459
+ },
460
+ /** Pre-select a specific institution */ institution: {
461
+ type: String,
462
+ default: undefined
463
+ },
464
+ /** Deep link URL for OAuth callbacks (mobile apps) */ appLauncherUrl: {
465
+ type: String,
466
+ default: undefined
467
+ }
468
+ },
469
+ emits: {
470
+ /** Connector loaded */ load: (_metadata)=>true,
471
+ /** Connection successful */ 'exit-success': (_metadata)=>true,
472
+ /** User cancelled */ 'exit-abort': (_metadata)=>true,
473
+ /** Error occurred */ 'exit-error': (_metadata)=>true,
474
+ /** Any connector event */ event: (_type, _metadata)=>true,
475
+ /** OAuth URL requested (for native handling) */ navigate: (_url)=>true
476
+ },
477
+ setup (props, { emit, expose }) {
478
+ const iframeRef = ref();
479
+ const { session } = useQuilttSession();
480
+ const trustedQuilttHostSuffixes = [
481
+ 'quiltt.io',
482
+ 'quiltt.dev',
483
+ 'quiltt.app'
484
+ ];
485
+ const isTrustedQuilttOrigin = (origin)=>{
486
+ try {
487
+ const originUrl = new URL(origin);
488
+ if (originUrl.protocol !== 'https:') {
489
+ return false;
490
+ }
491
+ const hostname = originUrl.hostname.toLowerCase();
492
+ return trustedQuilttHostSuffixes.some((suffix)=>hostname === suffix || hostname.endsWith(`.${suffix}`));
493
+ } catch {
494
+ return false;
495
+ }
496
+ };
497
+ // Connector origin for secure postMessage targeting
498
+ const connectorOrigin = computed(()=>`https://${props.connectorId}.quiltt.app`);
499
+ // Build connector URL
500
+ const connectorUrl = computed(()=>{
501
+ const url = new URL(connectorOrigin.value);
502
+ if (session.value?.token) {
503
+ url.searchParams.set('token', session.value.token);
504
+ }
505
+ if (props.connectionId) {
506
+ url.searchParams.set('connectionId', props.connectionId);
507
+ }
508
+ if (props.institution) {
509
+ url.searchParams.set('institution', props.institution);
510
+ }
511
+ if (props.appLauncherUrl) {
512
+ url.searchParams.set('app_launcher_url', props.appLauncherUrl);
513
+ }
514
+ if (typeof window !== 'undefined') {
515
+ url.searchParams.set('embed_location', window.location.href);
516
+ }
517
+ // Set mode for inline iframe embedding
518
+ url.searchParams.set('mode', 'INLINE');
519
+ return url.toString();
520
+ });
521
+ // Handle messages from the iframe
522
+ // The platform MessageBus sends: { source: 'quiltt', type: 'Load'|'ExitSuccess'|..., ...metadata }
523
+ const handleMessage = (event)=>{
524
+ if (!isTrustedQuilttOrigin(event.origin)) {
525
+ return;
526
+ }
527
+ const data = event.data || {};
528
+ // Validate message is from Quiltt MessageBus
529
+ if (data.source !== 'quiltt' || !data.type) return;
530
+ const { type, connectionId, profileId, connectorSession, url } = data;
531
+ // Build metadata from message fields
532
+ const metadata = {
533
+ connectorId: props.connectorId,
534
+ ...profileId && {
535
+ profileId
536
+ },
537
+ ...connectionId && {
538
+ connectionId
539
+ },
540
+ ...connectorSession && {
541
+ connectorSession
542
+ }
543
+ };
544
+ switch(type){
545
+ case 'Load':
546
+ emit('event', 'Load', metadata);
547
+ emit('load', metadata);
548
+ break;
549
+ case 'ExitSuccess':
550
+ emit('event', 'ExitSuccess', metadata);
551
+ emit('exit-success', metadata);
552
+ break;
553
+ case 'ExitAbort':
554
+ emit('event', 'ExitAbort', metadata);
555
+ emit('exit-abort', metadata);
556
+ break;
557
+ case 'ExitError':
558
+ emit('event', 'ExitError', metadata);
559
+ emit('exit-error', metadata);
560
+ break;
561
+ case 'Navigate':
562
+ if (url) {
563
+ emit('navigate', url);
564
+ }
565
+ break;
566
+ }
567
+ };
568
+ // Build OAuth callback message matching React Native SDK format
569
+ const buildOAuthCallbackMessage = (callbackUrl)=>{
570
+ try {
571
+ const parsedUrl = new URL(callbackUrl);
572
+ const params = {};
573
+ parsedUrl.searchParams.forEach((value, key)=>{
574
+ params[key] = value;
575
+ });
576
+ return {
577
+ source: 'quiltt',
578
+ type: 'OAuthCallback',
579
+ data: {
580
+ url: callbackUrl,
581
+ params
582
+ }
583
+ };
584
+ } catch {
585
+ return {
586
+ source: 'quiltt',
587
+ type: 'OAuthCallback',
588
+ data: {
589
+ url: callbackUrl,
590
+ params: {}
591
+ }
592
+ };
593
+ }
594
+ };
595
+ const handleOAuthCallback = (url)=>{
596
+ iframeRef.value?.contentWindow?.postMessage(buildOAuthCallbackMessage(url), connectorOrigin.value);
597
+ };
598
+ expose({
599
+ handleOAuthCallback
600
+ });
601
+ onMounted(()=>{
602
+ window.addEventListener('message', handleMessage);
603
+ });
604
+ onUnmounted(()=>{
605
+ window.removeEventListener('message', handleMessage);
606
+ });
607
+ return ()=>h('iframe', {
608
+ ref: iframeRef,
609
+ src: connectorUrl.value,
610
+ allow: 'publickey-credentials-get *',
611
+ class: 'quiltt-connector',
612
+ style: {
613
+ border: 'none',
614
+ width: '100%',
615
+ height: '100%'
616
+ }
617
+ });
618
+ }
619
+ });
620
+
621
+ const QuilttContainer = defineComponent({
622
+ name: 'QuilttContainer',
623
+ props: {
624
+ /** Quiltt Connector ID */ connectorId: {
625
+ type: String,
626
+ required: true
627
+ },
628
+ /** Existing connection ID for reconnection */ connectionId: {
629
+ type: String,
630
+ default: undefined
631
+ },
632
+ /** Pre-select a specific institution */ institution: {
633
+ type: String,
634
+ default: undefined
635
+ },
636
+ /** Deep link URL for OAuth callbacks (mobile apps) */ appLauncherUrl: {
637
+ type: String,
638
+ default: undefined
639
+ },
640
+ /**
641
+ * @deprecated Use `appLauncherUrl` instead. This property will be removed in a future version.
642
+ * The OAuth redirect URL for mobile or embedded webview flows.
643
+ */ oauthRedirectUrl: {
644
+ type: String,
645
+ default: undefined
646
+ },
647
+ /** Render as a different element */ as: {
648
+ type: String,
649
+ default: 'div'
650
+ }
651
+ },
652
+ emits: {
653
+ /** Connector loaded */ load: (_metadata)=>true,
654
+ /** Connection successful */ 'exit-success': (_metadata)=>true,
655
+ /** User cancelled */ 'exit-abort': (_metadata)=>true,
656
+ /** Error occurred */ 'exit-error': (_metadata)=>true,
657
+ /** Connector exited (any reason) */ exit: (_type, _metadata)=>true,
658
+ /** Any connector event */ event: (_type, _metadata)=>true
659
+ },
660
+ setup (props, { emit, slots }) {
661
+ watch(()=>props.oauthRedirectUrl, (value)=>{
662
+ if (value !== undefined) {
663
+ console.warn(oauthRedirectUrlDeprecationWarning);
664
+ }
665
+ }, {
666
+ immediate: true
667
+ });
668
+ const effectiveAppLauncherUri = computed(()=>props.appLauncherUrl ?? props.oauthRedirectUrl);
669
+ let openTimeout;
670
+ const { open } = useQuilttConnector(()=>props.connectorId, {
671
+ connectionId: ()=>props.connectionId,
672
+ institution: ()=>props.institution,
673
+ appLauncherUrl: effectiveAppLauncherUri,
674
+ onEvent: (type, metadata)=>emit('event', type, metadata),
675
+ onLoad: (metadata)=>emit('load', metadata),
676
+ onExit: (type, metadata)=>emit('exit', type, metadata),
677
+ onExitSuccess: (metadata)=>emit('exit-success', metadata),
678
+ onExitAbort: (metadata)=>emit('exit-abort', metadata),
679
+ onExitError: (metadata)=>emit('exit-error', metadata)
680
+ });
681
+ onMounted(()=>{
682
+ // Short delay to ensure SDK is loaded
683
+ openTimeout = setTimeout(()=>{
684
+ open();
685
+ }, 100);
686
+ });
687
+ onUnmounted(()=>{
688
+ if (openTimeout) {
689
+ clearTimeout(openTimeout);
690
+ openTimeout = undefined;
691
+ }
692
+ });
693
+ return ()=>h(props.as, {
694
+ class: 'quiltt-container',
695
+ style: {
696
+ width: '100%',
697
+ height: '100%'
698
+ }
699
+ }, slots.default?.());
700
+ }
701
+ });
702
+
703
+ export { QuilttButton, QuilttConnector, QuilttContainer };