@basictech/react 0.2.0-beta.6 → 0.2.0-beta.8
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/.turbo/turbo-build.log +10 -10
- package/changelog.md +15 -0
- package/dist/index.d.mts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +59 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +59 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/readme.md +79 -29
- package/src/AuthContext.tsx +67 -39
- package/src/index.ts +14 -2
- package/src/sync/index.ts +8 -5
- package/src/sync/syncProtocol.js +1 -1
package/src/AuthContext.tsx
CHANGED
|
@@ -79,7 +79,7 @@ type Token = {
|
|
|
79
79
|
|
|
80
80
|
export const BasicContext = createContext<{
|
|
81
81
|
unicorn: string,
|
|
82
|
-
|
|
82
|
+
isAuthReady: boolean,
|
|
83
83
|
isSignedIn: boolean,
|
|
84
84
|
user: User | null,
|
|
85
85
|
signout: () => void,
|
|
@@ -90,7 +90,7 @@ export const BasicContext = createContext<{
|
|
|
90
90
|
dbStatus: DBStatus
|
|
91
91
|
}>({
|
|
92
92
|
unicorn: "🦄",
|
|
93
|
-
|
|
93
|
+
isAuthReady: false,
|
|
94
94
|
isSignedIn: false,
|
|
95
95
|
user: null,
|
|
96
96
|
signout: () => { },
|
|
@@ -98,7 +98,7 @@ export const BasicContext = createContext<{
|
|
|
98
98
|
getToken: () => new Promise(() => { }),
|
|
99
99
|
getSignInLink: () => "",
|
|
100
100
|
db: {},
|
|
101
|
-
dbStatus: DBStatus.
|
|
101
|
+
dbStatus: DBStatus.LOADING
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
const EmptyDB: BasicSyncType = {
|
|
@@ -140,17 +140,16 @@ type ErrorObject = {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
export function BasicProvider({ children, project_id, schema, debug = false }: { children: React.ReactNode, project_id: string, schema: any, debug?: boolean }) {
|
|
143
|
-
const [
|
|
144
|
-
const [isSignedIn, setIsSignedIn] = useState(false)
|
|
143
|
+
const [isAuthReady, setIsAuthReady] = useState(false)
|
|
144
|
+
const [isSignedIn, setIsSignedIn] = useState<boolean>(false)
|
|
145
145
|
const [token, setToken] = useState<Token | null>(null)
|
|
146
|
-
const [authCode, setAuthCode] = useState<string | null>(null)
|
|
147
146
|
const [user, setUser] = useState<User>({})
|
|
148
147
|
|
|
149
148
|
const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.LOADING)
|
|
149
|
+
const [error, setError] = useState<ErrorObject | null>(null)
|
|
150
150
|
|
|
151
151
|
const syncRef = useRef<BasicSync | null>(null);
|
|
152
152
|
|
|
153
|
-
const [error, setError] = useState<ErrorObject | null>(null)
|
|
154
153
|
|
|
155
154
|
useEffect(() => {
|
|
156
155
|
function initDb() {
|
|
@@ -173,6 +172,7 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
173
172
|
|
|
174
173
|
|
|
175
174
|
if (!syncRef.current) {
|
|
175
|
+
log('Initializing BasicDB')
|
|
176
176
|
syncRef.current = new BasicSync('basicdb', { schema: schema });
|
|
177
177
|
|
|
178
178
|
// log('db is open', syncRef.current.isOpen())
|
|
@@ -180,30 +180,41 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
180
180
|
// .then(() => {
|
|
181
181
|
// log("is open now:", syncRef.current.isOpen())
|
|
182
182
|
// })
|
|
183
|
-
|
|
184
|
-
syncRef.current.handleStatusChange((status: number, url: string) => {
|
|
185
|
-
setDbStatus(getSyncStatus(status))
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
syncRef.current.syncable.getStatus().then((status) => {
|
|
189
|
-
log('sync status', getSyncStatus(status))
|
|
190
|
-
})
|
|
191
183
|
}
|
|
192
|
-
|
|
193
184
|
}
|
|
194
185
|
|
|
195
186
|
initDb()
|
|
196
187
|
}, []);
|
|
197
188
|
|
|
189
|
+
useEffect(() => {
|
|
190
|
+
if (!syncRef.current) {
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// syncRef.current.handleStatusChange((status: number, url: string) => {
|
|
195
|
+
// setDbStatus(getSyncStatus(status))
|
|
196
|
+
// })
|
|
197
|
+
|
|
198
|
+
syncRef.current.syncable.on('statusChanged', (status: number, url: string) => {
|
|
199
|
+
setDbStatus(getSyncStatus(status))
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
syncRef.current.syncable.getStatus().then((status) => {
|
|
203
|
+
setDbStatus(getSyncStatus(status))
|
|
204
|
+
})
|
|
205
|
+
}, [syncRef.current])
|
|
198
206
|
|
|
199
|
-
//todo:
|
|
200
|
-
//add random state to signin link & verify random state
|
|
201
207
|
|
|
202
208
|
const connectToDb = async () => {
|
|
203
|
-
|
|
204
209
|
const tok = await getToken()
|
|
210
|
+
if (!tok) {
|
|
211
|
+
log('no token found')
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
log('connecting to db...')
|
|
205
216
|
|
|
206
|
-
|
|
217
|
+
// TODO: handle if signed out after connect() is already called
|
|
207
218
|
|
|
208
219
|
syncRef.current.connect({ access_token: tok })
|
|
209
220
|
.catch((e) => {
|
|
@@ -220,14 +231,15 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
220
231
|
const getSignInLink = () => {
|
|
221
232
|
log('getting sign in link...')
|
|
222
233
|
|
|
223
|
-
const randomState = Math.random().toString(36).substring(
|
|
234
|
+
const randomState = Math.random().toString(36).substring(6);
|
|
235
|
+
localStorage.setItem('basic_auth_state', randomState)
|
|
224
236
|
|
|
225
237
|
let baseUrl = "https://api.basic.tech/auth/authorize"
|
|
226
238
|
baseUrl += `?client_id=${project_id}`
|
|
227
239
|
baseUrl += `&redirect_uri=${encodeURIComponent(window.location.href)}`
|
|
228
240
|
baseUrl += `&response_type=code`
|
|
229
241
|
baseUrl += `&scope=openid`
|
|
230
|
-
baseUrl += `&state
|
|
242
|
+
baseUrl += `&state=${randomState}`
|
|
231
243
|
|
|
232
244
|
return baseUrl;
|
|
233
245
|
}
|
|
@@ -244,8 +256,8 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
244
256
|
setUser({})
|
|
245
257
|
setIsSignedIn(false)
|
|
246
258
|
setToken(null)
|
|
247
|
-
setAuthCode(null)
|
|
248
259
|
document.cookie = `basic_token=; Secure; SameSite=Strict`;
|
|
260
|
+
localStorage.removeItem('basic_auth_state')
|
|
249
261
|
}
|
|
250
262
|
|
|
251
263
|
const getToken = async (): Promise<string> => {
|
|
@@ -308,24 +320,32 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
308
320
|
localStorage.setItem('basic_debug', debug ? 'true' : 'false')
|
|
309
321
|
|
|
310
322
|
try {
|
|
311
|
-
let cookie_token = getCookie('basic_token')
|
|
312
|
-
if (cookie_token !== '') {
|
|
313
|
-
setToken(JSON.parse(cookie_token))
|
|
314
|
-
}
|
|
315
|
-
|
|
316
323
|
if (window.location.search.includes('code')) {
|
|
317
324
|
let code = window.location?.search?.split('code=')[1].split('&')[0]
|
|
318
|
-
// log('code found', code)
|
|
319
325
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
326
|
+
const state = localStorage.getItem('basic_auth_state')
|
|
327
|
+
if (!state || state !== window.location.search.split('state=')[1].split('&')[0]) {
|
|
328
|
+
log('error: auth state does not match')
|
|
329
|
+
setIsAuthReady(true)
|
|
323
330
|
|
|
324
|
-
|
|
331
|
+
localStorage.removeItem('basic_auth_state')
|
|
332
|
+
window.history.pushState({}, document.title, "/");
|
|
333
|
+
return
|
|
334
|
+
}
|
|
325
335
|
|
|
326
|
-
|
|
327
|
-
|
|
336
|
+
localStorage.removeItem('basic_auth_state')
|
|
337
|
+
|
|
338
|
+
fetchToken(code)
|
|
339
|
+
} else {
|
|
340
|
+
let cookie_token = getCookie('basic_token')
|
|
341
|
+
if (cookie_token !== '') {
|
|
342
|
+
setToken(JSON.parse(cookie_token))
|
|
343
|
+
} else {
|
|
344
|
+
setIsAuthReady(true)
|
|
345
|
+
}
|
|
328
346
|
}
|
|
347
|
+
|
|
348
|
+
|
|
329
349
|
} catch (e) {
|
|
330
350
|
log('error getting cookie', e)
|
|
331
351
|
}
|
|
@@ -333,6 +353,7 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
333
353
|
|
|
334
354
|
useEffect(() => {
|
|
335
355
|
async function fetchUser(acc_token: string) {
|
|
356
|
+
console.info('fetching user')
|
|
336
357
|
const user = await fetch('https://api.basic.tech/auth/userInfo', {
|
|
337
358
|
method: 'GET',
|
|
338
359
|
headers: {
|
|
@@ -349,15 +370,23 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
349
370
|
} else {
|
|
350
371
|
// log('user', user)
|
|
351
372
|
document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;
|
|
373
|
+
|
|
374
|
+
if (window.location.search.includes('code')) {
|
|
375
|
+
window.history.pushState({}, document.title, "/");
|
|
376
|
+
}
|
|
377
|
+
|
|
352
378
|
setUser(user)
|
|
353
379
|
setIsSignedIn(true)
|
|
354
|
-
|
|
380
|
+
|
|
381
|
+
setIsAuthReady(true)
|
|
355
382
|
}
|
|
356
383
|
}
|
|
357
384
|
|
|
358
385
|
async function checkToken() {
|
|
359
386
|
if (!token) {
|
|
360
387
|
log('error: no user token found')
|
|
388
|
+
|
|
389
|
+
setIsAuthReady(true)
|
|
361
390
|
return
|
|
362
391
|
}
|
|
363
392
|
|
|
@@ -375,8 +404,7 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
375
404
|
|
|
376
405
|
if (token) {
|
|
377
406
|
checkToken()
|
|
378
|
-
|
|
379
|
-
}
|
|
407
|
+
}
|
|
380
408
|
}, [token])
|
|
381
409
|
|
|
382
410
|
|
|
@@ -416,7 +444,7 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
416
444
|
return (
|
|
417
445
|
<BasicContext.Provider value={{
|
|
418
446
|
unicorn: "🦄",
|
|
419
|
-
|
|
447
|
+
isAuthReady,
|
|
420
448
|
isSignedIn,
|
|
421
449
|
user,
|
|
422
450
|
signout,
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { useBasic, BasicProvider } from "./AuthContext";
|
|
2
|
-
import { useLiveQuery
|
|
2
|
+
import { useLiveQuery } from "dexie-react-hooks";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function useQuery(queryable: any) {
|
|
6
|
+
return useLiveQuery(() => {
|
|
7
|
+
if (typeof queryable === 'function') {
|
|
8
|
+
return queryable();
|
|
9
|
+
}
|
|
10
|
+
return queryable;
|
|
11
|
+
}, [queryable], []);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
3
15
|
|
|
4
16
|
export {
|
|
5
17
|
useBasic, BasicProvider, useQuery
|
|
6
|
-
}
|
|
18
|
+
}
|
package/src/sync/index.ts
CHANGED
|
@@ -136,7 +136,6 @@ export class BasicSync extends Dexie {
|
|
|
136
136
|
return this.syncable
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
|
|
140
139
|
collection(name: string) {
|
|
141
140
|
// TODO: check against schema
|
|
142
141
|
|
|
@@ -175,12 +174,12 @@ export class BasicSync extends Dexie {
|
|
|
175
174
|
|
|
176
175
|
// --- READ ---- //
|
|
177
176
|
|
|
178
|
-
get: (id: string) => {
|
|
179
|
-
return this.table(name).get(id)
|
|
177
|
+
get: async (id: string) => {
|
|
178
|
+
return this.table(name).get(id)
|
|
180
179
|
},
|
|
181
180
|
|
|
182
|
-
getAll: () => {
|
|
183
|
-
return this.table(name).toArray()
|
|
181
|
+
getAll: async () => {
|
|
182
|
+
return this.table(name).toArray();
|
|
184
183
|
},
|
|
185
184
|
|
|
186
185
|
// --- QUERY ---- //
|
|
@@ -193,3 +192,7 @@ export class BasicSync extends Dexie {
|
|
|
193
192
|
}
|
|
194
193
|
}
|
|
195
194
|
}
|
|
195
|
+
|
|
196
|
+
class QueryMethod {
|
|
197
|
+
|
|
198
|
+
}
|
package/src/sync/syncProtocol.js
CHANGED
|
@@ -86,6 +86,7 @@ export const syncProtocol = function () {
|
|
|
86
86
|
|
|
87
87
|
// If socket is closed (network disconnected), inform framework and make it reconnect
|
|
88
88
|
ws.onclose = function (event) {
|
|
89
|
+
// console.log('🙅 ws.onclose', event)
|
|
89
90
|
onError("Socket closed: " + event.reason, RECONNECT_DELAY);
|
|
90
91
|
};
|
|
91
92
|
|
|
@@ -124,7 +125,6 @@ export const syncProtocol = function () {
|
|
|
124
125
|
syncedRevision: syncedRevision,
|
|
125
126
|
}),
|
|
126
127
|
);
|
|
127
|
-
} else if (requestFromServer.type == "error") {
|
|
128
128
|
} else if (requestFromServer.type == "changes") {
|
|
129
129
|
applyRemoteChanges(
|
|
130
130
|
requestFromServer.changes,
|