@basictech/react 0.7.0-beta.4 → 0.7.0-beta.6
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/changelog.md +12 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +179 -103
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +179 -103
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/AuthContext.tsx +233 -120
- package/src/sync/index.ts +4 -4
- package/src/utils/storage.ts +1 -0
package/src/AuthContext.tsx
CHANGED
|
@@ -16,6 +16,7 @@ export type { BasicStorage, LocalStorageAdapter } from './utils/storage'
|
|
|
16
16
|
export type AuthConfig = {
|
|
17
17
|
scopes?: string | string[];
|
|
18
18
|
server_url?: string;
|
|
19
|
+
ws_url?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export type BasicProviderProps = {
|
|
@@ -27,15 +28,16 @@ export type BasicProviderProps = {
|
|
|
27
28
|
auth?: AuthConfig;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const DEFAULT_AUTH_CONFIG
|
|
31
|
-
scopes: 'profile
|
|
32
|
-
server_url: 'https://api.basic.tech'
|
|
33
|
-
|
|
31
|
+
const DEFAULT_AUTH_CONFIG = {
|
|
32
|
+
scopes: 'profile,email,app:admin',
|
|
33
|
+
server_url: 'https://api.basic.tech',
|
|
34
|
+
ws_url: 'wss://pds.basic.id/ws'
|
|
35
|
+
} as const
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
type BasicSyncType = {
|
|
37
39
|
basic_schema: any;
|
|
38
|
-
connect: (options: { access_token: string }) => void;
|
|
40
|
+
connect: (options: { access_token: string; ws_url?: string }) => void;
|
|
39
41
|
debugeroo: () => void;
|
|
40
42
|
collection: (name: string) => {
|
|
41
43
|
ref: {
|
|
@@ -128,9 +130,10 @@ export function BasicProvider({
|
|
|
128
130
|
const storageAdapter = storage || new LocalStorageAdapter();
|
|
129
131
|
|
|
130
132
|
// Merge auth config with defaults
|
|
131
|
-
const authConfig
|
|
133
|
+
const authConfig = {
|
|
132
134
|
scopes: auth?.scopes || DEFAULT_AUTH_CONFIG.scopes,
|
|
133
|
-
server_url: auth?.server_url || DEFAULT_AUTH_CONFIG.server_url
|
|
135
|
+
server_url: auth?.server_url || DEFAULT_AUTH_CONFIG.server_url,
|
|
136
|
+
ws_url: auth?.ws_url || DEFAULT_AUTH_CONFIG.ws_url
|
|
134
137
|
}
|
|
135
138
|
|
|
136
139
|
// Normalize scopes to space-separated string
|
|
@@ -138,6 +141,9 @@ export function BasicProvider({
|
|
|
138
141
|
? authConfig.scopes.join(' ')
|
|
139
142
|
: authConfig.scopes;
|
|
140
143
|
|
|
144
|
+
// Token refresh mutex to prevent concurrent refreshes
|
|
145
|
+
const refreshPromiseRef = useRef<Promise<Token | null> | null>(null);
|
|
146
|
+
|
|
141
147
|
const isDevMode = () => isDevelopment(debug)
|
|
142
148
|
|
|
143
149
|
const cleanOAuthParams = () => cleanOAuthParamsFromUrl()
|
|
@@ -245,7 +251,10 @@ export function BasicProvider({
|
|
|
245
251
|
|
|
246
252
|
log('connecting to db...')
|
|
247
253
|
|
|
248
|
-
syncRef.current?.connect({
|
|
254
|
+
syncRef.current?.connect({
|
|
255
|
+
access_token: tok,
|
|
256
|
+
ws_url: authConfig.ws_url
|
|
257
|
+
})
|
|
249
258
|
.catch((e) => {
|
|
250
259
|
log('error connecting to db', e)
|
|
251
260
|
})
|
|
@@ -259,6 +268,19 @@ export function BasicProvider({
|
|
|
259
268
|
const initializeAuth = async () => {
|
|
260
269
|
await storageAdapter.set(STORAGE_KEYS.DEBUG, debug ? 'true' : 'false')
|
|
261
270
|
|
|
271
|
+
// Check if server URL has changed - if so, clear tokens
|
|
272
|
+
const storedServerUrl = await storageAdapter.get(STORAGE_KEYS.SERVER_URL)
|
|
273
|
+
if (storedServerUrl && storedServerUrl !== authConfig.server_url) {
|
|
274
|
+
log('Server URL changed, clearing stored tokens')
|
|
275
|
+
await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN)
|
|
276
|
+
await storageAdapter.remove(STORAGE_KEYS.USER_INFO)
|
|
277
|
+
await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE)
|
|
278
|
+
await storageAdapter.remove(STORAGE_KEYS.REDIRECT_URI)
|
|
279
|
+
clearCookie('basic_token')
|
|
280
|
+
clearCookie('basic_access_token')
|
|
281
|
+
}
|
|
282
|
+
await storageAdapter.set(STORAGE_KEYS.SERVER_URL, authConfig.server_url)
|
|
283
|
+
|
|
262
284
|
try {
|
|
263
285
|
const versionUpdater = createVersionUpdater(storageAdapter, currentVersion, getMigrations())
|
|
264
286
|
const updateResult = await versionUpdater.checkAndUpdate()
|
|
@@ -337,19 +359,25 @@ export function BasicProvider({
|
|
|
337
359
|
useEffect(() => {
|
|
338
360
|
async function fetchUser(acc_token: string) {
|
|
339
361
|
console.info('fetching user')
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
362
|
+
try {
|
|
363
|
+
const response = await fetch(`${authConfig.server_url}/auth/userInfo`, {
|
|
364
|
+
method: 'GET',
|
|
365
|
+
headers: {
|
|
366
|
+
'Authorization': `Bearer ${acc_token}`
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
if (!response.ok) {
|
|
371
|
+
throw new Error(`Failed to fetch user info: ${response.status}`)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const user = await response.json()
|
|
375
|
+
|
|
376
|
+
if (user.error) {
|
|
377
|
+
log('error fetching user', user.error)
|
|
378
|
+
throw new Error(`User info error: ${user.error}`)
|
|
344
379
|
}
|
|
345
|
-
})
|
|
346
|
-
.then(response => response.json())
|
|
347
|
-
.catch(error => log('Error:', error))
|
|
348
380
|
|
|
349
|
-
if (user.error) {
|
|
350
|
-
log('error fetching user', user.error)
|
|
351
|
-
return
|
|
352
|
-
} else {
|
|
353
381
|
if (token?.refresh_token) {
|
|
354
382
|
await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token.refresh_token)
|
|
355
383
|
}
|
|
@@ -362,7 +390,10 @@ export function BasicProvider({
|
|
|
362
390
|
|
|
363
391
|
setUser(user)
|
|
364
392
|
setIsSignedIn(true)
|
|
365
|
-
|
|
393
|
+
setIsAuthReady(true)
|
|
394
|
+
} catch (error) {
|
|
395
|
+
log('Failed to fetch user info:', error)
|
|
396
|
+
// Don't clear tokens here - may be temporary network issue
|
|
366
397
|
setIsAuthReady(true)
|
|
367
398
|
}
|
|
368
399
|
}
|
|
@@ -376,12 +407,20 @@ export function BasicProvider({
|
|
|
376
407
|
}
|
|
377
408
|
|
|
378
409
|
const decoded = jwtDecode(token?.access_token)
|
|
379
|
-
|
|
410
|
+
// Add 5 second buffer to prevent edge cases
|
|
411
|
+
const expirationBuffer = 5
|
|
412
|
+
const isExpired = decoded.exp && decoded.exp < (Date.now() / 1000) + expirationBuffer
|
|
380
413
|
|
|
381
414
|
if (isExpired) {
|
|
382
415
|
log('token is expired - refreshing ...')
|
|
416
|
+
const refreshToken = token?.refresh_token
|
|
417
|
+
if (!refreshToken) {
|
|
418
|
+
log('Error: No refresh token available for expired token')
|
|
419
|
+
setIsAuthReady(true)
|
|
420
|
+
return
|
|
421
|
+
}
|
|
383
422
|
try {
|
|
384
|
-
const newToken = await fetchToken(
|
|
423
|
+
const newToken = await fetchToken(refreshToken, true)
|
|
385
424
|
fetchUser(newToken?.access_token || '')
|
|
386
425
|
} catch (error) {
|
|
387
426
|
log('Failed to refresh token in checkToken:', error)
|
|
@@ -452,7 +491,10 @@ export function BasicProvider({
|
|
|
452
491
|
const signInLink = await getSignInLink()
|
|
453
492
|
log('Generated sign-in link:', signInLink)
|
|
454
493
|
|
|
455
|
-
|
|
494
|
+
// Validate URL format (supports https://, http://, and custom URI schemes)
|
|
495
|
+
try {
|
|
496
|
+
new URL(signInLink)
|
|
497
|
+
} catch {
|
|
456
498
|
log('Error: Invalid sign-in link generated')
|
|
457
499
|
throw new Error('Failed to generate valid sign-in URL')
|
|
458
500
|
}
|
|
@@ -522,6 +564,7 @@ export function BasicProvider({
|
|
|
522
564
|
await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN)
|
|
523
565
|
await storageAdapter.remove(STORAGE_KEYS.USER_INFO)
|
|
524
566
|
await storageAdapter.remove(STORAGE_KEYS.REDIRECT_URI)
|
|
567
|
+
await storageAdapter.remove(STORAGE_KEYS.SERVER_URL)
|
|
525
568
|
if (syncRef.current) {
|
|
526
569
|
(async () => {
|
|
527
570
|
try {
|
|
@@ -544,6 +587,21 @@ export function BasicProvider({
|
|
|
544
587
|
const refreshToken = await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN)
|
|
545
588
|
if (refreshToken) {
|
|
546
589
|
log('No token in memory, attempting to refresh from storage')
|
|
590
|
+
|
|
591
|
+
// Check if refresh is already in progress
|
|
592
|
+
if (refreshPromiseRef.current) {
|
|
593
|
+
log('Token refresh already in progress, waiting...')
|
|
594
|
+
try {
|
|
595
|
+
const newToken = await refreshPromiseRef.current
|
|
596
|
+
if (newToken?.access_token) {
|
|
597
|
+
return newToken.access_token
|
|
598
|
+
}
|
|
599
|
+
} catch (error) {
|
|
600
|
+
log('In-flight refresh failed:', error)
|
|
601
|
+
throw error
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
547
605
|
try {
|
|
548
606
|
const newToken = await fetchToken(refreshToken, true)
|
|
549
607
|
if (newToken?.access_token) {
|
|
@@ -569,10 +627,31 @@ export function BasicProvider({
|
|
|
569
627
|
}
|
|
570
628
|
|
|
571
629
|
const decoded = jwtDecode(token?.access_token)
|
|
572
|
-
|
|
630
|
+
// Add 5 second buffer to prevent edge cases where token expires during request
|
|
631
|
+
const expirationBuffer = 5
|
|
632
|
+
const isExpired = decoded.exp && decoded.exp < (Date.now() / 1000) + expirationBuffer
|
|
573
633
|
|
|
574
634
|
if (isExpired) {
|
|
575
635
|
log('token is expired - refreshing ...')
|
|
636
|
+
|
|
637
|
+
// Check if refresh is already in progress
|
|
638
|
+
if (refreshPromiseRef.current) {
|
|
639
|
+
log('Token refresh already in progress, waiting...')
|
|
640
|
+
try {
|
|
641
|
+
const newToken = await refreshPromiseRef.current
|
|
642
|
+
return newToken?.access_token || ''
|
|
643
|
+
} catch (error) {
|
|
644
|
+
log('In-flight refresh failed:', error)
|
|
645
|
+
|
|
646
|
+
if ((error as Error).message.includes('offline') || (error as Error).message.includes('Network')) {
|
|
647
|
+
log('Network issue - using expired token until network is restored')
|
|
648
|
+
return token.access_token
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
throw error
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
576
655
|
const refreshToken = token?.refresh_token || await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN)
|
|
577
656
|
if (refreshToken) {
|
|
578
657
|
try {
|
|
@@ -596,124 +675,158 @@ export function BasicProvider({
|
|
|
596
675
|
return token?.access_token || ''
|
|
597
676
|
}
|
|
598
677
|
|
|
599
|
-
const fetchToken = async (codeOrRefreshToken: string, isRefreshToken: boolean = false) => {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
678
|
+
const fetchToken = async (codeOrRefreshToken: string, isRefreshToken: boolean = false): Promise<Token | null> => {
|
|
679
|
+
// Validate input
|
|
680
|
+
if (!codeOrRefreshToken || codeOrRefreshToken.trim() === '') {
|
|
681
|
+
const errorMsg = isRefreshToken ? 'Refresh token is empty or undefined' : 'Authorization code is empty or undefined'
|
|
682
|
+
log('Error:', errorMsg)
|
|
683
|
+
throw new Error(errorMsg)
|
|
684
|
+
}
|
|
606
685
|
|
|
607
|
-
|
|
686
|
+
// If this is a refresh token request and one is already in progress, return that promise
|
|
687
|
+
if (isRefreshToken && refreshPromiseRef.current) {
|
|
688
|
+
log('Reusing in-flight refresh token request')
|
|
689
|
+
return refreshPromiseRef.current
|
|
690
|
+
}
|
|
608
691
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
if (project_id) {
|
|
617
|
-
requestBody.client_id = project_id
|
|
618
|
-
}
|
|
619
|
-
} else {
|
|
620
|
-
// Authorization code exchange
|
|
621
|
-
requestBody = {
|
|
622
|
-
grant_type: 'authorization_code',
|
|
623
|
-
code: codeOrRefreshToken
|
|
692
|
+
// Create new promise for this refresh attempt
|
|
693
|
+
const refreshPromise = (async (): Promise<Token | null> => {
|
|
694
|
+
try {
|
|
695
|
+
if (!isOnline) {
|
|
696
|
+
log('Network is offline, marking refresh as pending')
|
|
697
|
+
setPendingRefresh(true)
|
|
698
|
+
throw new Error('Network offline - refresh will be retried when online')
|
|
624
699
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
if (
|
|
629
|
-
|
|
630
|
-
|
|
700
|
+
|
|
701
|
+
let requestBody: any
|
|
702
|
+
|
|
703
|
+
if (isRefreshToken) {
|
|
704
|
+
// Refresh token request
|
|
705
|
+
requestBody = {
|
|
706
|
+
grant_type: 'refresh_token',
|
|
707
|
+
refresh_token: codeOrRefreshToken
|
|
708
|
+
}
|
|
709
|
+
// Include client_id if available for validation
|
|
710
|
+
if (project_id) {
|
|
711
|
+
requestBody.client_id = project_id
|
|
712
|
+
}
|
|
631
713
|
} else {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
714
|
+
// Authorization code exchange
|
|
715
|
+
requestBody = {
|
|
716
|
+
grant_type: 'authorization_code',
|
|
717
|
+
code: codeOrRefreshToken
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Retrieve stored redirect_uri (required by OAuth2 spec)
|
|
721
|
+
const storedRedirectUri = await storageAdapter.get(STORAGE_KEYS.REDIRECT_URI)
|
|
722
|
+
if (storedRedirectUri) {
|
|
723
|
+
requestBody.redirect_uri = storedRedirectUri
|
|
724
|
+
log('Including redirect_uri in token exchange:', storedRedirectUri)
|
|
725
|
+
} else {
|
|
726
|
+
log('Warning: No redirect_uri found in storage for token exchange')
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Include client_id for validation
|
|
730
|
+
if (project_id) {
|
|
731
|
+
requestBody.client_id = project_id
|
|
732
|
+
}
|
|
638
733
|
}
|
|
639
|
-
}
|
|
640
734
|
|
|
641
|
-
|
|
735
|
+
log('Token exchange request body:', { ...requestBody, refresh_token: isRefreshToken ? '[REDACTED]' : undefined, code: !isRefreshToken ? '[REDACTED]' : undefined })
|
|
642
736
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
737
|
+
const token = await fetch(`${authConfig.server_url}/auth/token`, {
|
|
738
|
+
method: 'POST',
|
|
739
|
+
headers: {
|
|
740
|
+
'Content-Type': 'application/json'
|
|
741
|
+
},
|
|
742
|
+
body: JSON.stringify(requestBody)
|
|
743
|
+
})
|
|
744
|
+
.then(response => response.json())
|
|
745
|
+
.catch(error => {
|
|
746
|
+
log('Network error fetching token:', error)
|
|
747
|
+
if (!isOnline) {
|
|
748
|
+
setPendingRefresh(true)
|
|
749
|
+
throw new Error('Network offline - refresh will be retried when online')
|
|
750
|
+
}
|
|
751
|
+
throw new Error('Network error during token refresh')
|
|
752
|
+
})
|
|
753
|
+
|
|
754
|
+
if (token.error) {
|
|
755
|
+
log('error fetching token', token.error)
|
|
756
|
+
|
|
757
|
+
if (token.error.includes('network') || token.error.includes('timeout')) {
|
|
654
758
|
setPendingRefresh(true)
|
|
655
|
-
throw new Error('Network
|
|
759
|
+
throw new Error('Network issue - refresh will be retried when online')
|
|
656
760
|
}
|
|
657
|
-
throw new Error('Network error during token refresh')
|
|
658
|
-
})
|
|
659
761
|
|
|
660
|
-
|
|
661
|
-
|
|
762
|
+
await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN)
|
|
763
|
+
await storageAdapter.remove(STORAGE_KEYS.USER_INFO)
|
|
764
|
+
await storageAdapter.remove(STORAGE_KEYS.REDIRECT_URI)
|
|
765
|
+
await storageAdapter.remove(STORAGE_KEYS.SERVER_URL)
|
|
766
|
+
clearCookie('basic_token');
|
|
767
|
+
clearCookie('basic_access_token');
|
|
662
768
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
769
|
+
setUser({})
|
|
770
|
+
setIsSignedIn(false)
|
|
771
|
+
setToken(null)
|
|
772
|
+
setIsAuthReady(true)
|
|
667
773
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
clearCookie('basic_access_token');
|
|
774
|
+
throw new Error(`Token refresh failed: ${token.error}`)
|
|
775
|
+
} else {
|
|
776
|
+
setToken(token)
|
|
777
|
+
setPendingRefresh(false)
|
|
673
778
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
779
|
+
if (token.refresh_token) {
|
|
780
|
+
await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token.refresh_token)
|
|
781
|
+
log('Updated refresh token in storage')
|
|
782
|
+
}
|
|
678
783
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
784
|
+
// Clean up redirect_uri after successful token exchange
|
|
785
|
+
if (!isRefreshToken) {
|
|
786
|
+
await storageAdapter.remove(STORAGE_KEYS.REDIRECT_URI)
|
|
787
|
+
log('Cleaned up redirect_uri from storage after successful exchange')
|
|
788
|
+
}
|
|
683
789
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
log('Updated
|
|
790
|
+
setCookie('basic_access_token', token.access_token, { httpOnly: false });
|
|
791
|
+
setCookie('basic_token', JSON.stringify(token));
|
|
792
|
+
log('Updated access token and full token in cookies')
|
|
687
793
|
}
|
|
794
|
+
return token
|
|
795
|
+
} catch (error) {
|
|
796
|
+
log('Token refresh error:', error)
|
|
688
797
|
|
|
689
|
-
|
|
690
|
-
|
|
798
|
+
if (!(error as Error).message.includes('offline') && !(error as Error).message.includes('Network')) {
|
|
799
|
+
await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN)
|
|
800
|
+
await storageAdapter.remove(STORAGE_KEYS.USER_INFO)
|
|
691
801
|
await storageAdapter.remove(STORAGE_KEYS.REDIRECT_URI)
|
|
692
|
-
|
|
802
|
+
await storageAdapter.remove(STORAGE_KEYS.SERVER_URL)
|
|
803
|
+
clearCookie('basic_token');
|
|
804
|
+
clearCookie('basic_access_token');
|
|
805
|
+
|
|
806
|
+
setUser({})
|
|
807
|
+
setIsSignedIn(false)
|
|
808
|
+
setToken(null)
|
|
809
|
+
setIsAuthReady(true)
|
|
693
810
|
}
|
|
694
811
|
|
|
695
|
-
|
|
696
|
-
log('Updated access token in cookie')
|
|
812
|
+
throw error
|
|
697
813
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
setToken(null)
|
|
712
|
-
setIsAuthReady(true)
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
throw error
|
|
814
|
+
})()
|
|
815
|
+
|
|
816
|
+
// Store promise if this is a refresh token request
|
|
817
|
+
if (isRefreshToken) {
|
|
818
|
+
refreshPromiseRef.current = refreshPromise
|
|
819
|
+
|
|
820
|
+
// Clear the promise reference when done (success or failure)
|
|
821
|
+
refreshPromise.finally(() => {
|
|
822
|
+
if (refreshPromiseRef.current === refreshPromise) {
|
|
823
|
+
refreshPromiseRef.current = null
|
|
824
|
+
log('Cleared refresh promise reference')
|
|
825
|
+
}
|
|
826
|
+
})
|
|
716
827
|
}
|
|
828
|
+
|
|
829
|
+
return refreshPromise
|
|
717
830
|
}
|
|
718
831
|
|
|
719
832
|
const noDb = ({
|
package/src/sync/index.ts
CHANGED
|
@@ -56,8 +56,8 @@ export class BasicSync extends Dexie {
|
|
|
56
56
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
async connect({ access_token }: { access_token: string }) {
|
|
60
|
-
const WS_URL =
|
|
59
|
+
async connect({ access_token, ws_url }: { access_token: string, ws_url?: string }) {
|
|
60
|
+
const WS_URL = ws_url || 'wss://pds.basic.id/ws'
|
|
61
61
|
|
|
62
62
|
log('Connecting to', WS_URL)
|
|
63
63
|
|
|
@@ -67,8 +67,8 @@ export class BasicSync extends Dexie {
|
|
|
67
67
|
return this.syncable.connect("websocket", WS_URL, { authToken: access_token, schema: this.basic_schema });
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
async disconnect() {
|
|
71
|
-
const WS_URL =
|
|
70
|
+
async disconnect({ ws_url }: { ws_url?: string } = {}) {
|
|
71
|
+
const WS_URL = ws_url || 'wss://pds.basic.id/ws'
|
|
72
72
|
|
|
73
73
|
return this.syncable.disconnect(WS_URL)
|
|
74
74
|
}
|