@basictech/react 0.2.2 → 0.4.0-beta.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.
- package/changelog.md +23 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +106 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +107 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/AuthContext.tsx +131 -60
- package/src/sync/index.ts +5 -2
package/src/AuthContext.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import { jwtDecode } from 'jwt-decode'
|
|
|
5
5
|
|
|
6
6
|
import { BasicSync } from './sync'
|
|
7
7
|
import { get, add, update, deleteRecord } from './db'
|
|
8
|
-
import { validateSchema } from '@basictech/schema'
|
|
8
|
+
import { validateSchema, compareSchemas } from '@basictech/schema'
|
|
9
9
|
|
|
10
10
|
import { log } from './config'
|
|
11
11
|
|
|
@@ -16,29 +16,6 @@ schema todo:
|
|
|
16
16
|
relations
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
// const example = {
|
|
21
|
-
// project_id: '123',
|
|
22
|
-
// version: 0,
|
|
23
|
-
// tables: {
|
|
24
|
-
// example: {
|
|
25
|
-
// name: 'example',
|
|
26
|
-
// type: 'collection',
|
|
27
|
-
// fields: {
|
|
28
|
-
// id: {
|
|
29
|
-
// type: 'uuid',
|
|
30
|
-
// primary: true,
|
|
31
|
-
// },
|
|
32
|
-
// value: {
|
|
33
|
-
// type: 'string',
|
|
34
|
-
// indexed: true,
|
|
35
|
-
// },
|
|
36
|
-
// }
|
|
37
|
-
// }
|
|
38
|
-
// }
|
|
39
|
-
// }
|
|
40
|
-
|
|
41
|
-
|
|
42
19
|
type BasicSyncType = {
|
|
43
20
|
basic_schema: any;
|
|
44
21
|
connect: (options: { access_token: string }) => void;
|
|
@@ -114,6 +91,81 @@ const EmptyDB: BasicSyncType = {
|
|
|
114
91
|
}
|
|
115
92
|
}
|
|
116
93
|
|
|
94
|
+
async function getSchemaStatus(schema: any) {
|
|
95
|
+
const projectId = schema.project_id
|
|
96
|
+
let status = ''
|
|
97
|
+
const valid = validateSchema(schema)
|
|
98
|
+
|
|
99
|
+
if (!valid.valid) {
|
|
100
|
+
console.warn('BasicDB Error: your local schema is invalid. Please fix errors and try again - sync is disabled')
|
|
101
|
+
return {
|
|
102
|
+
valid: false,
|
|
103
|
+
status: 'invalid',
|
|
104
|
+
latest: null
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const latestSchema = await fetch(`https://api.basic.tech/project/${projectId}/schema`)
|
|
109
|
+
.then(res => res.json())
|
|
110
|
+
.then(data => data.data[0].schema)
|
|
111
|
+
.catch(err => {
|
|
112
|
+
return {
|
|
113
|
+
valid: false,
|
|
114
|
+
status: 'error',
|
|
115
|
+
latest: null
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
if (!latestSchema.version) {
|
|
120
|
+
return {
|
|
121
|
+
valid: false,
|
|
122
|
+
status: 'error',
|
|
123
|
+
latest: null
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (latestSchema.version > schema.version) {
|
|
128
|
+
// error_code: schema_behind
|
|
129
|
+
console.warn('BasicDB Error: your local schema version is behind the latest. Found version:', schema.version, 'but expected', latestSchema.version, " - sync is disabled")
|
|
130
|
+
return {
|
|
131
|
+
valid: false,
|
|
132
|
+
status: 'behind',
|
|
133
|
+
latest: latestSchema
|
|
134
|
+
}
|
|
135
|
+
} else if (latestSchema.version < schema.version) {
|
|
136
|
+
// error_code: schema_ahead
|
|
137
|
+
console.warn('BasicDB Error: your local schema version is ahead of the latest. Found version:', schema.version, 'but expected', latestSchema.version, " - sync is disabled")
|
|
138
|
+
return {
|
|
139
|
+
valid: false,
|
|
140
|
+
status: 'ahead',
|
|
141
|
+
latest: latestSchema
|
|
142
|
+
}
|
|
143
|
+
} else if (latestSchema.version === schema.version) {
|
|
144
|
+
const changes = compareSchemas(schema, latestSchema)
|
|
145
|
+
if (changes.valid) {
|
|
146
|
+
return {
|
|
147
|
+
valid: true,
|
|
148
|
+
status: 'current',
|
|
149
|
+
latest: latestSchema
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
// error_code: schema_conflict
|
|
153
|
+
console.warn('BasicDB Error: your local schema is conflicting with the latest. Your version:', schema.version, 'does not match origin version', latestSchema.version, " - sync is disabled")
|
|
154
|
+
return {
|
|
155
|
+
valid: false,
|
|
156
|
+
status: 'conflict',
|
|
157
|
+
latest: latestSchema
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
return {
|
|
162
|
+
valid: false,
|
|
163
|
+
status: 'error',
|
|
164
|
+
latest: null
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
117
169
|
|
|
118
170
|
function getSyncStatus(statusCode: number): string {
|
|
119
171
|
switch (statusCode) {
|
|
@@ -140,20 +192,48 @@ type ErrorObject = {
|
|
|
140
192
|
message: string;
|
|
141
193
|
}
|
|
142
194
|
|
|
143
|
-
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
export function BasicProvider({ children, project_id, schema, debug = false }: { children: React.ReactNode, project_id: string, schema?: any, debug?: boolean }) {
|
|
144
198
|
const [isAuthReady, setIsAuthReady] = useState(false)
|
|
145
199
|
const [isSignedIn, setIsSignedIn] = useState<boolean>(false)
|
|
146
200
|
const [token, setToken] = useState<Token | null>(null)
|
|
147
201
|
const [user, setUser] = useState<User>({})
|
|
202
|
+
const [shouldConnect, setShouldConnect] = useState<boolean>(false)
|
|
203
|
+
const [isReady, setIsReady] = useState<boolean>(false)
|
|
148
204
|
|
|
149
|
-
const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.
|
|
205
|
+
const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.OFFLINE)
|
|
150
206
|
const [error, setError] = useState<ErrorObject | null>(null)
|
|
151
207
|
|
|
152
208
|
const syncRef = useRef<BasicSync | null>(null);
|
|
153
209
|
|
|
154
|
-
|
|
155
210
|
useEffect(() => {
|
|
156
211
|
function initDb() {
|
|
212
|
+
if (!syncRef.current) {
|
|
213
|
+
log('Initializing BasicDB')
|
|
214
|
+
syncRef.current = new BasicSync('basicdb', { schema: schema });
|
|
215
|
+
|
|
216
|
+
syncRef.current.syncable.on('statusChanged', (status: number, url: string) => {
|
|
217
|
+
setDbStatus(getSyncStatus(status))
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
syncRef.current.syncable.getStatus().then((status) => {
|
|
221
|
+
setDbStatus(getSyncStatus(status))
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
setShouldConnect(true)
|
|
226
|
+
setIsReady(true)
|
|
227
|
+
|
|
228
|
+
// log('db is open', syncRef.current.isOpen())
|
|
229
|
+
// syncRef.current.open()
|
|
230
|
+
// .then(() => {
|
|
231
|
+
// log("is open now:", syncRef.current.isOpen())
|
|
232
|
+
// })
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function checkSchema() {
|
|
157
237
|
const valid = validateSchema(schema)
|
|
158
238
|
if (!valid.valid) {
|
|
159
239
|
log('Basic Schema is invalid!', valid.errors)
|
|
@@ -169,42 +249,33 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
169
249
|
title: 'Basic Schema is invalid!',
|
|
170
250
|
message: errorMessage
|
|
171
251
|
})
|
|
252
|
+
setIsReady(true)
|
|
172
253
|
return null
|
|
173
254
|
}
|
|
174
255
|
|
|
175
|
-
if (!syncRef.current) {
|
|
176
|
-
log('Initializing BasicDB')
|
|
177
|
-
syncRef.current = new BasicSync('basicdb', { schema: schema });
|
|
178
256
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
257
|
+
const schemaStatus = await getSchemaStatus(schema)
|
|
258
|
+
|
|
259
|
+
if (schemaStatus.valid) {
|
|
260
|
+
initDb()
|
|
261
|
+
} else {
|
|
262
|
+
setIsReady(true)
|
|
184
263
|
}
|
|
185
264
|
}
|
|
186
265
|
|
|
187
|
-
|
|
266
|
+
if (schema) {
|
|
267
|
+
checkSchema()
|
|
268
|
+
} else {
|
|
269
|
+
setIsReady(true)
|
|
270
|
+
}
|
|
188
271
|
}, []);
|
|
189
272
|
|
|
273
|
+
|
|
190
274
|
useEffect(() => {
|
|
191
|
-
if (
|
|
192
|
-
|
|
275
|
+
if (token && syncRef.current && isSignedIn && shouldConnect) {
|
|
276
|
+
connectToDb()
|
|
193
277
|
}
|
|
194
|
-
|
|
195
|
-
// syncRef.current.handleStatusChange((status: number, url: string) => {
|
|
196
|
-
// setDbStatus(getSyncStatus(status))
|
|
197
|
-
// })
|
|
198
|
-
|
|
199
|
-
syncRef.current.syncable.on('statusChanged', (status: number, url: string) => {
|
|
200
|
-
setDbStatus(getSyncStatus(status))
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
syncRef.current.syncable.getStatus().then((status) => {
|
|
204
|
-
setDbStatus(getSyncStatus(status))
|
|
205
|
-
})
|
|
206
|
-
}, [syncRef.current])
|
|
207
|
-
|
|
278
|
+
}, [isSignedIn, shouldConnect])
|
|
208
279
|
|
|
209
280
|
const connectToDb = async () => {
|
|
210
281
|
const tok = await getToken()
|
|
@@ -223,12 +294,6 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
223
294
|
})
|
|
224
295
|
}
|
|
225
296
|
|
|
226
|
-
useEffect(() => {
|
|
227
|
-
if (token && syncRef.current && isSignedIn && isSignedIn) {
|
|
228
|
-
connectToDb()
|
|
229
|
-
}
|
|
230
|
-
}, [isSignedIn])
|
|
231
|
-
|
|
232
297
|
const getSignInLink = () => {
|
|
233
298
|
log('getting sign in link...')
|
|
234
299
|
|
|
@@ -447,6 +512,12 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
447
512
|
|
|
448
513
|
}
|
|
449
514
|
|
|
515
|
+
const noDb = ({
|
|
516
|
+
collection: () => {
|
|
517
|
+
throw new Error('no basicdb found - schema is not provided')
|
|
518
|
+
}
|
|
519
|
+
})
|
|
520
|
+
|
|
450
521
|
return (
|
|
451
522
|
<BasicContext.Provider value={{
|
|
452
523
|
unicorn: "🦄",
|
|
@@ -457,11 +528,11 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
|
|
|
457
528
|
signin,
|
|
458
529
|
getToken,
|
|
459
530
|
getSignInLink,
|
|
460
|
-
db: syncRef.current,
|
|
531
|
+
db: syncRef.current ? syncRef.current : noDb,
|
|
461
532
|
dbStatus
|
|
462
533
|
}}>
|
|
463
534
|
{error && <ErrorDisplay error={error} />}
|
|
464
|
-
{
|
|
535
|
+
{isReady && children}
|
|
465
536
|
</BasicContext.Provider>
|
|
466
537
|
)
|
|
467
538
|
}
|
package/src/sync/index.ts
CHANGED
|
@@ -104,9 +104,12 @@ export class BasicSync extends Dexie {
|
|
|
104
104
|
log(`HEISENBUG: Setting ${node.id} to ${node.id === largestNodeId ? 'master' : '0'}`);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
//
|
|
108
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
107
|
+
// add delay to ensure sync nodes are updated // i dont think this helps?
|
|
108
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
109
109
|
|
|
110
|
+
if (typeof window !== 'undefined') {
|
|
111
|
+
window.location.reload();
|
|
112
|
+
}
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
log('Sync nodes updated');
|