@truly-you/trulyyou-web-sdk 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/sdk/TrulyYouSDK.d.ts +7 -0
- package/package.json +1 -1
- package/src/sdk/TrulyYouSDK.ts +47 -52
|
@@ -17,8 +17,14 @@ export declare class TrulyYouSDK {
|
|
|
17
17
|
private getKeyIdByAuthFlowId;
|
|
18
18
|
/**
|
|
19
19
|
* Fetch app branding from SDK backend
|
|
20
|
+
* Returns true if authFlowId was successfully loaded
|
|
20
21
|
*/
|
|
21
22
|
private fetchBranding;
|
|
23
|
+
/**
|
|
24
|
+
* Ensure authFlowId is loaded before proceeding with signing operations
|
|
25
|
+
* Throws error if authFlowId cannot be loaded
|
|
26
|
+
*/
|
|
27
|
+
private ensureAuthFlowIdLoaded;
|
|
22
28
|
/**
|
|
23
29
|
* Generate QR code with app icon overlaid in center
|
|
24
30
|
*/
|
|
@@ -45,6 +51,7 @@ export declare class TrulyYouSDK {
|
|
|
45
51
|
/**
|
|
46
52
|
* Probe iframe to check if key exists in iframe's localStorage
|
|
47
53
|
* Also checks backend to verify key exists and is active
|
|
54
|
+
* REQUIRES authFlowId to be loaded first
|
|
48
55
|
*/
|
|
49
56
|
private probeIframeForKey;
|
|
50
57
|
/**
|
package/package.json
CHANGED
package/src/sdk/TrulyYouSDK.ts
CHANGED
|
@@ -63,9 +63,13 @@ export class TrulyYouSDK {
|
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
65
|
* Fetch app branding from SDK backend
|
|
66
|
+
* Returns true if authFlowId was successfully loaded
|
|
66
67
|
*/
|
|
67
|
-
private async fetchBranding(): Promise<
|
|
68
|
-
if (!this.authAppId)
|
|
68
|
+
private async fetchBranding(): Promise<boolean> {
|
|
69
|
+
if (!this.authAppId) {
|
|
70
|
+
console.warn('[SDK]: Cannot fetch branding - authAppId not configured')
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
69
73
|
|
|
70
74
|
try {
|
|
71
75
|
// Call SDK backend API directly
|
|
@@ -88,13 +92,37 @@ export class TrulyYouSDK {
|
|
|
88
92
|
authFlowId: app.authFlowId
|
|
89
93
|
}
|
|
90
94
|
console.log('[SDK]: Branding and authFlowId fetched and cached:', this.brandingCache)
|
|
95
|
+
return !!app.authFlowId
|
|
91
96
|
}
|
|
92
97
|
}
|
|
98
|
+
console.warn('[SDK]: Failed to fetch branding - response not ok or missing app data')
|
|
99
|
+
return false
|
|
93
100
|
} catch (error) {
|
|
94
101
|
console.warn('[SDK]: Error fetching branding:', error)
|
|
102
|
+
return false
|
|
95
103
|
}
|
|
96
104
|
}
|
|
97
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Ensure authFlowId is loaded before proceeding with signing operations
|
|
108
|
+
* Throws error if authFlowId cannot be loaded
|
|
109
|
+
*/
|
|
110
|
+
private async ensureAuthFlowIdLoaded(): Promise<void> {
|
|
111
|
+
if (this.brandingCache?.authFlowId) {
|
|
112
|
+
console.log('[SDK]: authFlowId already loaded:', this.brandingCache.authFlowId)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log('[SDK]: authFlowId not yet loaded, fetching branding...')
|
|
117
|
+
const success = await this.fetchBranding()
|
|
118
|
+
|
|
119
|
+
if (!success || !this.brandingCache?.authFlowId) {
|
|
120
|
+
throw new Error('authFlowId is required for signing but not available. Please check that your app configuration includes an authFlowId.')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log('[SDK]: authFlowId loaded successfully:', this.brandingCache.authFlowId)
|
|
124
|
+
}
|
|
125
|
+
|
|
98
126
|
/**
|
|
99
127
|
* Generate QR code with app icon overlaid in center
|
|
100
128
|
*/
|
|
@@ -279,8 +307,17 @@ export class TrulyYouSDK {
|
|
|
279
307
|
/**
|
|
280
308
|
* Probe iframe to check if key exists in iframe's localStorage
|
|
281
309
|
* Also checks backend to verify key exists and is active
|
|
310
|
+
* REQUIRES authFlowId to be loaded first
|
|
282
311
|
*/
|
|
283
312
|
private async probeIframeForKey(): Promise<string | null> {
|
|
313
|
+
// Ensure authFlowId is loaded before probing
|
|
314
|
+
await this.ensureAuthFlowIdLoaded()
|
|
315
|
+
|
|
316
|
+
if (!this.brandingCache?.authFlowId) {
|
|
317
|
+
console.error('[SDK-PROBE]: authFlowId is required but not available after fetch')
|
|
318
|
+
return null
|
|
319
|
+
}
|
|
320
|
+
|
|
284
321
|
return new Promise((resolve) => {
|
|
285
322
|
try {
|
|
286
323
|
const origin = window.location.origin
|
|
@@ -292,103 +329,58 @@ export class TrulyYouSDK {
|
|
|
292
329
|
probeUrl.searchParams.set('probe', 'true')
|
|
293
330
|
probeUrl.searchParams.set('origin', origin)
|
|
294
331
|
|
|
295
|
-
// Add authFlowId
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
} else {
|
|
300
|
-
console.log('[SDK-PROBE]: No authFlowId available in cache, will check for any key')
|
|
301
|
-
}
|
|
332
|
+
// Add authFlowId (guaranteed to exist now after ensureAuthFlowIdLoaded)
|
|
333
|
+
const authFlowId = this.brandingCache!.authFlowId!
|
|
334
|
+
probeUrl.searchParams.set('authFlowId', authFlowId)
|
|
335
|
+
console.log('[SDK-PROBE]: Adding authFlowId to probe:', authFlowId)
|
|
302
336
|
|
|
303
337
|
iframe.src = probeUrl.toString()
|
|
304
|
-
|
|
305
|
-
console.log('[SDK-PROBE]: Creating probe iframe with URL:', probeUrl.toString())
|
|
306
|
-
console.log('[SDK-PROBE]: Current origin:', origin)
|
|
307
|
-
console.log('[SDK-PROBE]: Frontend URL:', this.frontendUrl)
|
|
308
338
|
|
|
309
339
|
let timeout: NodeJS.Timeout | undefined
|
|
310
|
-
let globalTimeout: NodeJS.Timeout | undefined
|
|
311
340
|
let backendCheckPromise: Promise<boolean> | null = null
|
|
312
|
-
let globalListener: ((e: MessageEvent) => void) | undefined
|
|
313
341
|
|
|
314
342
|
const cleanup = () => {
|
|
315
343
|
window.removeEventListener('message', handleMessage)
|
|
316
|
-
if (globalListener) {
|
|
317
|
-
window.removeEventListener('message', globalListener)
|
|
318
|
-
}
|
|
319
344
|
if (iframe.parentNode) {
|
|
320
345
|
iframe.parentNode.removeChild(iframe)
|
|
321
346
|
}
|
|
322
347
|
if (timeout) {
|
|
323
348
|
clearTimeout(timeout)
|
|
324
349
|
}
|
|
325
|
-
if (globalTimeout) {
|
|
326
|
-
clearTimeout(globalTimeout)
|
|
327
|
-
}
|
|
328
350
|
}
|
|
329
351
|
|
|
330
352
|
const handleMessage = async (event: MessageEvent) => {
|
|
331
353
|
const data = event.data as any
|
|
332
354
|
|
|
333
|
-
// Log ALL messages during probe to debug
|
|
334
|
-
console.log('[SDK-PROBE-DEBUG]: Message received - type:', data?.type, 'origin:', event.origin, 'data:', data)
|
|
335
|
-
|
|
336
355
|
// Only process probe-related messages
|
|
337
356
|
if (data?.type === 'KEY_CHECK_RESULT' || data?.type === 'KEY_CHECK_FAILED') {
|
|
338
|
-
console.log('[SDK-PROBE]: Processing probe message:', event.data, 'from origin:', event.origin)
|
|
339
|
-
|
|
340
357
|
try {
|
|
341
358
|
const frontendOrigin = new URL(this.frontendUrl).origin
|
|
342
|
-
console.log('[SDK-PROBE]: Checking origin - expected:', frontendOrigin, 'received:', event.origin)
|
|
343
359
|
if (event.origin !== frontendOrigin) {
|
|
344
|
-
console.log('[SDK-PROBE]: Origin mismatch, ignoring message')
|
|
345
360
|
return
|
|
346
361
|
}
|
|
347
|
-
|
|
348
362
|
} catch (e) {
|
|
349
|
-
console.log('[SDK-PROBE]: Origin check failed, using hostname fallback')
|
|
350
363
|
if (!event.origin.includes(window.location.hostname)) {
|
|
351
|
-
console.log('[SDK-PROBE]: Hostname not in origin, ignoring message')
|
|
352
364
|
return
|
|
353
365
|
}
|
|
354
366
|
}
|
|
355
|
-
|
|
356
|
-
console.log('[SDK-PROBE]: Message passed origin check, type:', data?.type)
|
|
357
367
|
|
|
358
368
|
if (data?.type === 'KEY_CHECK_RESULT') {
|
|
359
|
-
console.log('[SDK-PROBE]: KEY_CHECK_RESULT received - hasKey:', data.hasKey, 'keyId:', data.keyId)
|
|
360
369
|
cleanup()
|
|
361
370
|
if (data.hasKey && data.keyId) {
|
|
362
|
-
// Key found in localStorage - it will be validated when used in /api/signatures/create
|
|
363
371
|
resolve(data.keyId)
|
|
364
372
|
} else {
|
|
365
373
|
resolve(null)
|
|
366
374
|
}
|
|
367
375
|
} else if (data?.type === 'KEY_CHECK_FAILED') {
|
|
368
|
-
console.log('[SDK-PROBE]: KEY_CHECK_FAILED received')
|
|
369
376
|
cleanup()
|
|
370
377
|
resolve(null)
|
|
371
378
|
}
|
|
372
379
|
}
|
|
373
380
|
}
|
|
374
381
|
|
|
375
|
-
console.log('[SDK-PROBE]: Registering message listener on window')
|
|
376
382
|
window.addEventListener('message', handleMessage)
|
|
377
|
-
console.log('[SDK-PROBE]: Message listener registered, appending iframe')
|
|
378
383
|
document.body.appendChild(iframe)
|
|
379
|
-
console.log('[SDK-PROBE]: Iframe appended to body, waiting for response...')
|
|
380
|
-
|
|
381
|
-
// Also add a temporary global listener to see if ANY messages arrive
|
|
382
|
-
globalListener = (e: MessageEvent) => {
|
|
383
|
-
console.log('[SDK-PROBE-GLOBAL]: Any message received:', e.data, 'from:', e.origin)
|
|
384
|
-
}
|
|
385
|
-
window.addEventListener('message', globalListener)
|
|
386
|
-
globalTimeout = setTimeout(() => {
|
|
387
|
-
if (globalListener) {
|
|
388
|
-
window.removeEventListener('message', globalListener)
|
|
389
|
-
console.log('[SDK-PROBE-GLOBAL]: Removed temporary global listener')
|
|
390
|
-
}
|
|
391
|
-
}, 5000)
|
|
392
384
|
|
|
393
385
|
// Timeout to allow for React hydration on sign page
|
|
394
386
|
timeout = setTimeout(() => {
|
|
@@ -1705,7 +1697,7 @@ export class TrulyYouSDK {
|
|
|
1705
1697
|
}
|
|
1706
1698
|
|
|
1707
1699
|
// Step 2: Mobile device - use existing keyId if provided, otherwise probe
|
|
1708
|
-
let keyId = existingKeyId
|
|
1700
|
+
let keyId: string | null | undefined = existingKeyId
|
|
1709
1701
|
|
|
1710
1702
|
if (!keyId) {
|
|
1711
1703
|
console.log('[SDK]: Mobile device detected, probing iframe for existing key...')
|
|
@@ -1743,6 +1735,9 @@ export class TrulyYouSDK {
|
|
|
1743
1735
|
url: string,
|
|
1744
1736
|
options: FetchOptions = {}
|
|
1745
1737
|
): Promise<FetchResult> {
|
|
1738
|
+
// Ensure authFlowId is loaded before any signing operations
|
|
1739
|
+
await this.ensureAuthFlowIdLoaded()
|
|
1740
|
+
|
|
1746
1741
|
// Declare signatureId at function scope so it's accessible in catch block
|
|
1747
1742
|
let signatureId: string | undefined = undefined
|
|
1748
1743
|
try {
|