@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.
@@ -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
- export function BasicProvider({ children, project_id, schema, debug = false }: { children: React.ReactNode, project_id: string, schema: any, debug?: boolean }) {
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.LOADING)
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
- // log('db is open', syncRef.current.isOpen())
180
- // syncRef.current.open()
181
- // .then(() => {
182
- // log("is open now:", syncRef.current.isOpen())
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
- initDb()
266
+ if (schema) {
267
+ checkSchema()
268
+ } else {
269
+ setIsReady(true)
270
+ }
188
271
  }, []);
189
272
 
273
+
190
274
  useEffect(() => {
191
- if (!syncRef.current) {
192
- return
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
- {syncRef.current ? children : null}
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
- // Add a 1 second delay before returning // i dont think this helps?
108
- await new Promise(resolve => setTimeout(resolve, 2000));
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');