@basictech/react 0.2.0-beta.9 → 0.2.1

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.
@@ -1,6 +1,6 @@
1
1
 
2
2
  
3
- > @basictech/react@0.2.0-beta.7 build
3
+ > @basictech/react@0.2.0-beta.11 build
4
4
  > tsup
5
5
 
6
6
  CLI Building entry: src/index.ts
@@ -11,13 +11,13 @@
11
11
  CLI Cleaning output folder
12
12
  CJS Build start
13
13
  ESM Build start
14
- CJS dist/index.js 22.22 KB
15
- CJS dist/index.js.map 45.33 KB
16
- CJS ⚡️ Build success in 14ms
17
- ESM dist/index.mjs 19.99 KB
18
- ESM dist/index.mjs.map 45.28 KB
19
- ESM ⚡️ Build success in 14ms
14
+ CJS dist/index.js 24.60 KB
15
+ CJS dist/index.js.map 51.73 KB
16
+ CJS ⚡️ Build success in 13ms
17
+ ESM dist/index.mjs 22.39 KB
18
+ ESM dist/index.mjs.map 51.69 KB
19
+ ESM ⚡️ Build success in 13ms
20
20
  DTS Build start
21
- DTS ⚡️ Build success in 934ms
22
- DTS dist/index.d.ts 1003.00 B
23
- DTS dist/index.d.mts 1003.00 B
21
+ DTS ⚡️ Build success in 1177ms
22
+ DTS dist/index.d.ts 1006.00 B
23
+ DTS dist/index.d.mts 1006.00 B
package/changelog.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # 1.3.4
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @basictech/schema@0.2.0
9
+
10
+ ## 0.2.0
11
+
12
+ ### Minor Changes
13
+
14
+ - 5890f4c: changed isLoaded to isAuthReady and fixed dbStatus hooks for useBasic
15
+ - ba294c5: dependency updates
16
+ - cd827af: add schema validation
17
+ - 1a3fe80: schema validation bugfix
18
+ - 13594a9: added basic-sync
19
+ - ba294c5: dependency update
20
+ - f035281: remove sync lib
21
+ - 4841960: rebuild tsup
22
+ - 96e0156: update schema validation
23
+ - cda3d16: add schema validation
24
+ - 2c898ae: update useQuery hook
25
+
26
+ - no need to pass param as a function, can now enter query directly
27
+ - defaults to empty array when loading
28
+
29
+ - 90ccdd7: add debug option
30
+ - 4841960: test build
31
+ - f035281: remove sync library
32
+ - ef528e9: added schema package - test
33
+
34
+ ### Patch Changes
35
+
36
+ - 3c7b34e: version changes mostly
37
+ - c085672: reset versions
38
+ - Updated dependencies [96e0156]
39
+ - Updated dependencies [ef528e9]
40
+ - @basictech/schema@0.1.0
41
+
42
+ ## 0.2.0-beta.11
43
+
44
+ ### Minor Changes
45
+
46
+ - update schema validation
47
+
48
+ ### Patch Changes
49
+
50
+ - Updated dependencies
51
+ - @basictech/schema@0.1.0-beta.1
52
+
53
+ ## 0.2.0-beta.10
54
+
55
+ ### Minor Changes
56
+
57
+ - added schema package - test
58
+
59
+ ### Patch Changes
60
+
61
+ - Updated dependencies
62
+ - @basictech/schema@0.1.0-beta.0
63
+
3
64
  ## 0.2.0-beta.9
4
65
 
5
66
  ### Minor Changes
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { ErrorObject } from 'ajv';
3
+ export { useLiveQuery as useQuery } from 'dexie-react-hooks';
4
4
 
5
5
  declare enum DBStatus {
6
6
  LOADING = "LOADING",
@@ -38,97 +38,4 @@ declare function useBasic(): {
38
38
  dbStatus: DBStatus;
39
39
  };
40
40
 
41
- declare const basicJsonSchema: {
42
- $schema: string;
43
- type: string;
44
- properties: {
45
- project_id: {
46
- type: string;
47
- };
48
- namespace: {
49
- type: string;
50
- };
51
- version: {
52
- type: string;
53
- minimum: number;
54
- };
55
- tables: {
56
- type: string;
57
- patternProperties: {
58
- "^[a-zA-Z0-9_]+$": {
59
- type: string;
60
- properties: {
61
- name: {
62
- type: string;
63
- };
64
- type: {
65
- type: string;
66
- enum: string[];
67
- };
68
- fields: {
69
- type: string;
70
- patternProperties: {
71
- "^[a-zA-Z0-9_]+$": {
72
- type: string;
73
- properties: {
74
- type: {
75
- type: string;
76
- enum: string[];
77
- };
78
- indexed: {
79
- type: string;
80
- };
81
- required: {
82
- type: string;
83
- };
84
- };
85
- required: string[];
86
- };
87
- };
88
- additionalProperties: boolean;
89
- };
90
- };
91
- required: string[];
92
- };
93
- };
94
- additionalProperties: boolean;
95
- };
96
- };
97
- required: string[];
98
- };
99
- type Schema = typeof basicJsonSchema;
100
- declare function generateEmptySchema(): void;
101
- /**
102
- * Validate a schema
103
- * only checks if the schema is formatted correctly, not if can be published
104
- * @param schema - The schema to validate
105
- * @returns {valid: boolean, errors: any[]} - The validation result
106
- */
107
- declare function validateSchema(schema: Schema): {
108
- valid: boolean;
109
- errors: ErrorObject[];
110
- };
111
- declare function validateData(schema: any, table: string, data: Record<string, any>, checkRequired?: boolean): {
112
- valid: boolean;
113
- errors: ErrorObject<string, Record<string, any>, unknown>[];
114
- message: string;
115
- } | {
116
- valid: boolean;
117
- errors: {
118
- message: string;
119
- }[];
120
- message: string;
121
- } | {
122
- valid: boolean;
123
- errors: never[];
124
- message?: undefined;
125
- };
126
-
127
- declare function useQuery(queryable: any): any;
128
- declare const sc: {
129
- validateSchema: typeof validateSchema;
130
- validateData: typeof validateData;
131
- generateEmptySchema: typeof generateEmptySchema;
132
- };
133
-
134
- export { BasicProvider, sc, useBasic, useQuery };
41
+ export { BasicProvider, useBasic };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { ErrorObject } from 'ajv';
3
+ export { useLiveQuery as useQuery } from 'dexie-react-hooks';
4
4
 
5
5
  declare enum DBStatus {
6
6
  LOADING = "LOADING",
@@ -38,97 +38,4 @@ declare function useBasic(): {
38
38
  dbStatus: DBStatus;
39
39
  };
40
40
 
41
- declare const basicJsonSchema: {
42
- $schema: string;
43
- type: string;
44
- properties: {
45
- project_id: {
46
- type: string;
47
- };
48
- namespace: {
49
- type: string;
50
- };
51
- version: {
52
- type: string;
53
- minimum: number;
54
- };
55
- tables: {
56
- type: string;
57
- patternProperties: {
58
- "^[a-zA-Z0-9_]+$": {
59
- type: string;
60
- properties: {
61
- name: {
62
- type: string;
63
- };
64
- type: {
65
- type: string;
66
- enum: string[];
67
- };
68
- fields: {
69
- type: string;
70
- patternProperties: {
71
- "^[a-zA-Z0-9_]+$": {
72
- type: string;
73
- properties: {
74
- type: {
75
- type: string;
76
- enum: string[];
77
- };
78
- indexed: {
79
- type: string;
80
- };
81
- required: {
82
- type: string;
83
- };
84
- };
85
- required: string[];
86
- };
87
- };
88
- additionalProperties: boolean;
89
- };
90
- };
91
- required: string[];
92
- };
93
- };
94
- additionalProperties: boolean;
95
- };
96
- };
97
- required: string[];
98
- };
99
- type Schema = typeof basicJsonSchema;
100
- declare function generateEmptySchema(): void;
101
- /**
102
- * Validate a schema
103
- * only checks if the schema is formatted correctly, not if can be published
104
- * @param schema - The schema to validate
105
- * @returns {valid: boolean, errors: any[]} - The validation result
106
- */
107
- declare function validateSchema(schema: Schema): {
108
- valid: boolean;
109
- errors: ErrorObject[];
110
- };
111
- declare function validateData(schema: any, table: string, data: Record<string, any>, checkRequired?: boolean): {
112
- valid: boolean;
113
- errors: ErrorObject<string, Record<string, any>, unknown>[];
114
- message: string;
115
- } | {
116
- valid: boolean;
117
- errors: {
118
- message: string;
119
- }[];
120
- message: string;
121
- } | {
122
- valid: boolean;
123
- errors: never[];
124
- message?: undefined;
125
- };
126
-
127
- declare function useQuery(queryable: any): any;
128
- declare const sc: {
129
- validateSchema: typeof validateSchema;
130
- validateData: typeof validateData;
131
- generateEmptySchema: typeof generateEmptySchema;
132
- };
133
-
134
- export { BasicProvider, sc, useBasic, useQuery };
41
+ export { BasicProvider, useBasic };
package/dist/index.js CHANGED
@@ -31,9 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  BasicProvider: () => BasicProvider,
34
- sc: () => sc,
35
34
  useBasic: () => useBasic,
36
- useQuery: () => useQuery
35
+ useQuery: () => import_dexie_react_hooks.useLiveQuery
37
36
  });
38
37
  module.exports = __toCommonJS(src_exports);
39
38
 
@@ -226,8 +225,6 @@ var basicJsonSchema = {
226
225
  };
227
226
  var ajv = new import_ajv.default();
228
227
  var validator = ajv.compile(basicJsonSchema);
229
- function generateEmptySchema() {
230
- }
231
228
  function validateSchema(schema) {
232
229
  const v = validator(schema);
233
230
  return {
@@ -292,6 +289,10 @@ var BasicSync = class extends import_dexie2.Dexie {
292
289
  log("Starting connection...");
293
290
  return this.syncable.connect("websocket", WS_URL, { authToken: access_token });
294
291
  }
292
+ async disconnect() {
293
+ const WS_URL = `${SERVER_URL}/ws`;
294
+ return this.syncable.disconnect(WS_URL);
295
+ }
295
296
  async updateSyncNodes() {
296
297
  try {
297
298
  const syncNodes = await this.table("_syncNodes").toArray();
@@ -436,6 +437,7 @@ async function deleteRecord({ projectId, accountId, tableName, id, token }) {
436
437
  }
437
438
 
438
439
  // src/AuthContext.tsx
440
+ var import_schema2 = require("@basictech/schema");
439
441
  var import_jsx_runtime = require("react/jsx-runtime");
440
442
  var BasicContext = (0, import_react.createContext)({
441
443
  unicorn: "\u{1F984}",
@@ -480,7 +482,7 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
480
482
  const syncRef = (0, import_react.useRef)(null);
481
483
  (0, import_react.useEffect)(() => {
482
484
  function initDb() {
483
- const valid = validateSchema(schema);
485
+ const valid = (0, import_schema2.validateSchema)(schema);
484
486
  if (!valid.valid) {
485
487
  log("Basic Schema is invalid!", valid.errors);
486
488
  console.group("Schema Errors");
@@ -528,10 +530,10 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
528
530
  });
529
531
  };
530
532
  (0, import_react.useEffect)(() => {
531
- if (token && syncRef.current) {
533
+ if (token && syncRef.current && isSignedIn && isSignedIn) {
532
534
  connectToDb();
533
535
  }
534
- }, [token]);
536
+ }, [isSignedIn]);
535
537
  const getSignInLink = () => {
536
538
  log("getting sign in link...");
537
539
  const randomState = Math.random().toString(36).substring(6);
@@ -556,6 +558,9 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
556
558
  setToken(null);
557
559
  document.cookie = `basic_token=; Secure; SameSite=Strict`;
558
560
  localStorage.removeItem("basic_auth_state");
561
+ if (syncRef.current) {
562
+ syncRef.current.disconnect();
563
+ }
559
564
  };
560
565
  const getToken = async () => {
561
566
  log("getting token...");
@@ -745,23 +750,9 @@ function useBasic() {
745
750
 
746
751
  // src/index.ts
747
752
  var import_dexie_react_hooks = require("dexie-react-hooks");
748
- function useQuery(queryable) {
749
- return (0, import_dexie_react_hooks.useLiveQuery)(() => {
750
- if (typeof queryable === "function") {
751
- return queryable();
752
- }
753
- return queryable;
754
- }, [queryable], []);
755
- }
756
- var sc = {
757
- validateSchema,
758
- validateData,
759
- generateEmptySchema
760
- };
761
753
  // Annotate the CommonJS export names for ESM import in node:
762
754
  0 && (module.exports = {
763
755
  BasicProvider,
764
- sc,
765
756
  useBasic,
766
757
  useQuery
767
758
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/AuthContext.tsx","../src/sync/index.ts","../src/sync/syncProtocol.js","../src/config.ts","../src/schema.ts","../src/db.ts"],"sourcesContent":["import { useBasic, BasicProvider } from \"./AuthContext\";\nimport { useLiveQuery } from \"dexie-react-hooks\";\nimport { validateSchema, validateData, generateEmptySchema } from \"./schema\";\n\n\nfunction useQuery(queryable: any) {\n return useLiveQuery(() => {\n if (typeof queryable === 'function') {\n return queryable();\n }\n return queryable;\n }, [queryable], []);\n}\n\n\nconst sc = { \n validateSchema: validateSchema,\n validateData: validateData,\n generateEmptySchema: generateEmptySchema\n}\n\nexport {\n useBasic, BasicProvider, useQuery, sc\n}\n","// @ts-nocheck\n\nimport React, { createContext, useContext, useEffect, useState, useRef } from 'react'\nimport { jwtDecode } from 'jwt-decode'\n\nimport { BasicSync } from './sync'\nimport { get, add, update, deleteRecord } from './db'\nimport { validateSchema } from './schema'\n\nimport { log } from './config'\n\n/*\nschema todo:\n field types\n array types\n relations\n*/\n\n\n// const example = {\n// project_id: '123',\n// version: 0,\n// tables: {\n// example: {\n// name: 'example',\n// type: 'collection',\n// fields: {\n// id: {\n// type: 'uuid',\n// primary: true,\n// },\n// value: {\n// type: 'string',\n// indexed: true,\n// },\n// }\n// }\n// }\n// }\n\n\ntype BasicSyncType = {\n basic_schema: any;\n connect: (options: { access_token: string }) => void;\n debugeroo: () => void;\n collection: (name: string) => {\n ref: {\n toArray: () => Promise<any[]>;\n count: () => Promise<number>;\n };\n };\n [key: string]: any; // For other potential methods and properties\n};\n\n\nenum DBStatus {\n LOADING = \"LOADING\",\n OFFLINE = \"OFFLINE\",\n CONNECTING = \"CONNECTING\",\n ONLINE = \"ONLINE\",\n SYNCING = \"SYNCING\",\n ERROR = \"ERROR\"\n}\n\ntype User = {\n name?: string,\n email?: string,\n id?: string,\n primaryEmailAddress?: {\n emailAddress: string\n },\n fullName?: string\n}\ntype Token = {\n access_token: string,\n token_type: string,\n expires_in: number,\n refresh: string,\n}\n\nexport const BasicContext = createContext<{\n unicorn: string,\n isAuthReady: boolean,\n isSignedIn: boolean,\n user: User | null,\n signout: () => void,\n signin: () => void,\n getToken: () => Promise<string>,\n getSignInLink: () => string,\n db: any,\n dbStatus: DBStatus\n}>({\n unicorn: \"🦄\",\n isAuthReady: false,\n isSignedIn: false,\n user: null,\n signout: () => { },\n signin: () => { },\n getToken: () => new Promise(() => { }),\n getSignInLink: () => \"\",\n db: {},\n dbStatus: DBStatus.LOADING\n});\n\nconst EmptyDB: BasicSyncType = {\n isOpen: false,\n collection: () => {\n return {\n ref: {\n toArray: () => [],\n count: () => 0\n }\n }\n }\n}\n\n\nfunction getSyncStatus(statusCode: number): string {\n switch (statusCode) {\n case -1:\n return \"ERROR\";\n case 0:\n return \"OFFLINE\";\n case 1:\n return \"CONNECTING\";\n case 2:\n return \"ONLINE\";\n case 3:\n return \"SYNCING\";\n case 4:\n return \"ERROR_WILL_RETRY\";\n default:\n return \"UNKNOWN\";\n }\n}\n\ntype ErrorObject = {\n code: string;\n title: string;\n message: string;\n}\n\nexport function BasicProvider({ children, project_id, schema, debug = false }: { children: React.ReactNode, project_id: string, schema: any, debug?: boolean }) {\n const [isAuthReady, setIsAuthReady] = useState(false)\n const [isSignedIn, setIsSignedIn] = useState<boolean>(false)\n const [token, setToken] = useState<Token | null>(null)\n const [user, setUser] = useState<User>({})\n\n const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.LOADING)\n const [error, setError] = useState<ErrorObject | null>(null)\n\n const syncRef = useRef<BasicSync | null>(null);\n\n\n useEffect(() => {\n function initDb() {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n log('Basic Schema is invalid!', valid.errors)\n console.group('Schema Errors')\n let errorMessage = ''\n valid.errors.forEach((error, index) => {\n log(`${index + 1}:`, error.message, ` - at ${error.instancePath}`)\n errorMessage += `${index + 1}: ${error.message} - at ${error.instancePath}\\n`\n })\n console.groupEnd('Schema Errors')\n setError({\n code: 'schema_invalid',\n title: 'Basic Schema is invalid!',\n message: errorMessage\n })\n return null\n }\n\n if (!syncRef.current) {\n log('Initializing BasicDB')\n syncRef.current = new BasicSync('basicdb', { schema: schema });\n\n // log('db is open', syncRef.current.isOpen())\n // syncRef.current.open()\n // .then(() => {\n // log(\"is open now:\", syncRef.current.isOpen())\n // })\n }\n }\n\n initDb()\n }, []);\n\n useEffect(() => {\n if (!syncRef.current) {\n return\n }\n\n // syncRef.current.handleStatusChange((status: number, url: string) => {\n // setDbStatus(getSyncStatus(status))\n // })\n\n syncRef.current.syncable.on('statusChanged', (status: number, url: string) => {\n setDbStatus(getSyncStatus(status))\n })\n\n syncRef.current.syncable.getStatus().then((status) => {\n setDbStatus(getSyncStatus(status))\n })\n }, [syncRef.current])\n\n\n const connectToDb = async () => {\n const tok = await getToken()\n if (!tok) {\n log('no token found')\n return\n }\n\n log('connecting to db...')\n\n // TODO: handle if signed out after connect() is already called\n\n syncRef.current.connect({ access_token: tok })\n .catch((e) => {\n log('error connecting to db', e)\n })\n }\n\n useEffect(() => {\n if (token && syncRef.current) {\n connectToDb()\n }\n }, [token])\n\n const getSignInLink = () => {\n log('getting sign in link...')\n\n const randomState = Math.random().toString(36).substring(6);\n localStorage.setItem('basic_auth_state', randomState)\n\n let baseUrl = \"https://api.basic.tech/auth/authorize\"\n baseUrl += `?client_id=${project_id}`\n baseUrl += `&redirect_uri=${encodeURIComponent(window.location.href)}`\n baseUrl += `&response_type=code`\n baseUrl += `&scope=openid`\n baseUrl += `&state=${randomState}`\n\n return baseUrl;\n }\n\n const signin = () => {\n log('signing in: ', getSignInLink())\n const signInLink = getSignInLink()\n //todo: change to the other thing?\n window.location.href = signInLink;\n }\n\n const signout = () => {\n log('signing out!')\n setUser({})\n setIsSignedIn(false)\n setToken(null)\n document.cookie = `basic_token=; Secure; SameSite=Strict`;\n localStorage.removeItem('basic_auth_state')\n }\n\n const getToken = async (): Promise<string> => {\n log('getting token...')\n\n if (!token) {\n log('no token found')\n throw new Error('no token found')\n }\n\n const decoded = jwtDecode(token?.access_token)\n const isExpired = decoded.exp && decoded.exp < Date.now() / 1000\n\n if (isExpired) {\n log('token is expired - refreshing ...')\n const newToken = await fetchToken(token?.refresh)\n return newToken?.access_token || ''\n }\n\n return token?.access_token || ''\n }\n\n function getCookie(name: string) {\n let cookieValue = '';\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i].trim();\n if (cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n }\n\n const fetchToken = async (code: string) => {\n const token = await fetch('https://api.basic.tech/auth/token', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ code: code })\n })\n .then(response => response.json())\n .catch(error => log('Error:', error))\n\n if (token.error) {\n log('error fetching token', token.error)\n return\n } else {\n // log('token', token)\n setToken(token)\n }\n return token\n }\n\n useEffect(() => {\n localStorage.setItem('basic_debug', debug ? 'true' : 'false')\n\n try {\n if (window.location.search.includes('code')) {\n let code = window.location?.search?.split('code=')[1].split('&')[0]\n\n const state = localStorage.getItem('basic_auth_state')\n if (!state || state !== window.location.search.split('state=')[1].split('&')[0]) {\n log('error: auth state does not match')\n setIsAuthReady(true)\n\n localStorage.removeItem('basic_auth_state')\n window.history.pushState({}, document.title, \"/\");\n return\n }\n\n localStorage.removeItem('basic_auth_state')\n\n fetchToken(code) \n } else { \n let cookie_token = getCookie('basic_token')\n if (cookie_token !== '') {\n setToken(JSON.parse(cookie_token))\n } else { \n setIsAuthReady(true)\n }\n }\n\n\n } catch (e) {\n log('error getting cookie', e)\n }\n }, [])\n\n useEffect(() => {\n async function fetchUser(acc_token: string) {\n console.info('fetching user')\n const user = await fetch('https://api.basic.tech/auth/userInfo', {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${acc_token}`\n }\n })\n .then(response => response.json())\n .catch(error => log('Error:', error))\n\n if (user.error) {\n log('error fetching user', user.error)\n // refreshToken()\n return\n } else {\n // log('user', user)\n document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;\n \n if (window.location.search.includes('code')) {\n window.history.pushState({}, document.title, \"/\");\n }\n \n setUser(user)\n setIsSignedIn(true)\n\n setIsAuthReady(true)\n }\n }\n\n async function checkToken() {\n if (!token) {\n log('error: no user token found')\n\n setIsAuthReady(true)\n return\n }\n\n const decoded = jwtDecode(token?.access_token)\n const isExpired = decoded.exp && decoded.exp < Date.now() / 1000\n\n if (isExpired) {\n log('token is expired - refreshing ...')\n const newToken = await fetchToken(token?.refresh)\n fetchUser(newToken.access_token)\n } else {\n fetchUser(token.access_token)\n }\n }\n\n if (token) {\n checkToken()\n } \n }, [token])\n\n\n const db_ = (tableName: string) => {\n const checkSignIn = () => {\n if (!isSignedIn) {\n throw new Error('cannot use db. user not logged in.')\n }\n }\n\n return {\n get: async () => {\n checkSignIn()\n const tok = await getToken()\n return get({ projectId: project_id, accountId: user.id, tableName: tableName, token: tok })\n },\n add: async (value: any) => {\n checkSignIn()\n const tok = await getToken()\n return add({ projectId: project_id, accountId: user.id, tableName: tableName, value: value, token: tok })\n },\n update: async (id: string, value: any) => {\n checkSignIn()\n const tok = await getToken()\n return update({ projectId: project_id, accountId: user.id, tableName: tableName, id: id, value: value, token: tok })\n },\n delete: async (id: string) => {\n checkSignIn()\n const tok = await getToken()\n return deleteRecord({ projectId: project_id, accountId: user.id, tableName: tableName, id: id, token: tok })\n }\n\n }\n\n }\n\n return (\n <BasicContext.Provider value={{\n unicorn: \"🦄\",\n isAuthReady,\n isSignedIn,\n user,\n signout,\n signin,\n getToken,\n getSignInLink,\n db: syncRef.current,\n dbStatus\n }}>\n {error && <ErrorDisplay error={error} />}\n {syncRef.current ? children : null}\n </BasicContext.Provider>\n )\n}\n\nfunction ErrorDisplay({ error }: { error: ErrorObject }) {\n return <div style={{ \n position: 'absolute',\n top: 20, \n left: 20,\n color: 'black',\n backgroundColor: '#f8d7da',\n border: '1px solid #f5c6cb',\n borderRadius: '4px',\n padding: '20px',\n maxWidth: '400px',\n margin: '20px auto',\n boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',\n fontFamily: 'monospace', \n }}>\n <h3 style={{fontSize: '0.8rem', opacity: 0.8}}>code: {error.code}</h3>\n <h1 style={{fontSize: '1.2rem', lineHeight: '1.5'}}>{error.title}</h1>\n <p>{error.message}</p>\n </div>\n}\n\n/*\npossible errors: \n- projectid missing / invalid\n- schema missing / invalid\n*/\n\nexport function useBasic() {\n return useContext(BasicContext);\n}\n","\"use client\"\n\nimport { v7 as uuidv7 } from 'uuid';\nimport { Dexie, PromiseExtended } from 'dexie';\nimport 'dexie-syncable';\nimport 'dexie-observable';\n\nimport { syncProtocol } from './syncProtocol'\nimport { SERVER_URL, log } from '../config'\n\nimport { validateSchema, validateData } from '../schema'\nsyncProtocol()\n\n\n// const DexieSyncStatus = {\n// \"-1\": \"ERROR\",\n// \"0\": \"OFFLINE\",\n// \"1\": \"CONNECTING\",\n// \"2\": \"ONLINE\",\n// \"3\": \"SYNCING\",\n// \"4\": \"ERROR_WILL_RETRY\"\n// }\n\n\n\n\n\nexport class BasicSync extends Dexie {\n basic_schema: any\n\n constructor(name: string, options: any) {\n super(name, options);\n\n // --- INIT SCHEMA --- // \n\n //todo: handle versions?\n\n // TODO: validate schema\n this.basic_schema = options.schema\n this.version(1).stores(this._convertSchemaToDxSchema(this.basic_schema))\n\n this.version(2).stores({})\n // this.verssion\n\n\n // create an alias for toArray\n // @ts-ignore\n this.Collection.prototype.get = this.Collection.prototype.toArray\n\n\n // --- SYNC --- // \n\n // this.syncable.on(\"statusChanged\", (status, url) => { \n // console.log(\"statusChanged\", status, url)\n // })\n\n }\n\n async connect({ access_token }: { access_token: string }) {\n // const WS_URL = \"ws://localhost:3003/ws\"\n const WS_URL = `${SERVER_URL}/ws`\n\n \n // Update sync nodes\n await this.updateSyncNodes();\n \n // Proceed with the WebSocket connection\n \n log('Starting connection...')\n return this.syncable.connect(\"websocket\", WS_URL, { authToken: access_token });\n }\n\n private async updateSyncNodes() {\n try {\n const syncNodes = await this.table('_syncNodes').toArray();\n const localSyncNodes = syncNodes.filter(node => node.type === 'local');\n log('Local sync nodes:', localSyncNodes);\n\n if (localSyncNodes.length > 1) {\n\n \n const largestNodeId = Math.max(...localSyncNodes.map(node => node.id));\n // Check if the largest node is already the master\n const largestNode = localSyncNodes.find(node => node.id === largestNodeId);\n if (largestNode && largestNode.isMaster === 1) {\n log('Largest node is already the master. No changes needed.');\n return; // Exit the function early as no changes are needed\n }\n\n\n log('Largest node id:', largestNodeId);\n log('HEISENBUG: More than one local sync node found.')\n\n for (const node of localSyncNodes) {\n log(`Local sync node keys:`, node.id, node.isMaster);\n await this.table('_syncNodes').update(node.id, { isMaster: node.id === largestNodeId ? 1 : 0 });\n\n log(`HEISENBUG: Setting ${node.id} to ${node.id === largestNodeId ? 'master' : '0'}`);\n }\n\n // Add a 1 second delay before returning // i dont think this helps?\n await new Promise(resolve => setTimeout(resolve, 2000));\n\n }\n\n log('Sync nodes updated');\n } catch (error) {\n console.error('Error updating _syncNodes table:', error);\n }\n }\n\n handleStatusChange(fn: any) {\n this.syncable.on(\"statusChanged\", fn)\n }\n\n\n _convertSchemaToDxSchema(schema: any) {\n const stores = Object.entries(schema.tables).map(([key, table]: any) => {\n\n const indexedFields = Object.entries(table.fields).filter(([key, field]: any) => field.indexed).map(([key, field]: any) => `,${key}`).join('')\n return {\n [key]: 'id' + indexedFields\n }\n })\n\n return Object.assign({}, ...stores)\n }\n\n debugeroo() {\n // console.log(\"debugeroo\", this.syncable)\n\n // this.syncable.list().then(x => console.log(x))\n\n // this.syncable\n return this.syncable\n }\n\n collection(name: string) {\n // TODO: check against schema\n\n return {\n\n /**\n * Returns the underlying Dexie table\n * @type {Dexie.Table}\n */\n ref: this.table(name),\n\n // --- WRITE ---- // \n add: (data: any) => {\n // log(\"Adding data to\", name, data)\n\n const valid = validateData(this.basic_schema, name, data)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).add({\n id: uuidv7(),\n ...data\n })\n\n },\n\n put: (data: any) => {\n const valid = validateData(this.basic_schema, name, data)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).put({\n id: uuidv7(),\n ...data\n })\n },\n\n update: (id: string, data: any) => {\n const valid = validateData(this.basic_schema, name, data, false)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).update(id, data)\n },\n\n delete: (id: string) => {\n return this.table(name).delete(id)\n },\n\n\n // --- READ ---- // \n\n get: async (id: string) => {\n return this.table(name).get(id) \n },\n\n getAll: async () => {\n return this.table(name).toArray();\n },\n\n // --- QUERY ---- // \n // TODO: lots to do here. simplifing creating querie, filtering/ordering/limit, and execute\n\n query: () => this.table(name),\n\n filter: (fn: any) => this.table(name).filter(fn).toArray(),\n\n }\n }\n}\n\nclass QueryMethod { \n\n}\n","\"use client\"\nimport { Dexie } from \"dexie\";\nimport { log } from \"../config\";\n\nexport const syncProtocol = function () {\n log(\"Initializing syncProtocol\");\n // Constants:\n var RECONNECT_DELAY = 5000; // Reconnect delay in case of errors such as network down.\n\n Dexie.Syncable.registerSyncProtocol(\"websocket\", {\n sync: function (\n context,\n url,\n options,\n baseRevision,\n syncedRevision,\n changes,\n partial,\n applyRemoteChanges,\n onChangesAccepted,\n onSuccess,\n onError,\n ) {\n // The following vars are needed because we must know which callback to ack when server sends it's ack to us.\n var requestId = 0;\n var acceptCallbacks = {};\n\n // Connect the WebSocket to given url:\n var ws = new WebSocket(url);\n\n // console.log(\"ws OPTIONS\", options);\n\n // sendChanges() method:\n function sendChanges(changes, baseRevision, partial, onChangesAccepted) {\n log(\"sendChanges\", changes.length, baseRevision);\n ++requestId;\n acceptCallbacks[requestId.toString()] = onChangesAccepted;\n\n // In this example, the server expects the following JSON format of the request:\n // {\n // type: \"changes\"\n // baseRevision: baseRevision,\n // changes: changes,\n // partial: partial,\n // requestId: id\n // }\n // To make the sample simplified, we assume the server has the exact same specification of how changes are structured.\n // In real world, you would have to pre-process the changes array to fit the server specification.\n // However, this example shows how to deal with the WebSocket to fullfill the API.\n\n ws.send(\n JSON.stringify({\n type: \"changes\",\n changes: changes,\n partial: partial,\n baseRevision: baseRevision,\n requestId: requestId,\n }),\n );\n }\n\n\n\n // When WebSocket opens, send our changes to the server.\n ws.onopen = function (event) {\n // Initiate this socket connection by sending our clientIdentity. If we dont have a clientIdentity yet,\n // server will call back with a new client identity that we should use in future WebSocket connections.\n \n log(\"Opening socket - sending clientIdentity\", context.clientIdentity);\n ws.send(\n JSON.stringify({\n type: \"clientIdentity\",\n clientIdentity: context.clientIdentity || null,\n authToken: options.authToken\n }),\n );\n\n };\n\n // If network down or other error, tell the framework to reconnect again in some time:\n ws.onerror = function (event) {\n ws.close();\n log(\"ws.onerror\", event);\n onError(event?.message, RECONNECT_DELAY);\n };\n\n // If socket is closed (network disconnected), inform framework and make it reconnect\n ws.onclose = function (event) {\n // console.log('🙅 ws.onclose', event)\n onError(\"Socket closed: \" + event.reason, RECONNECT_DELAY);\n };\n\n // isFirstRound: Will need to call onSuccess() only when we are in sync the first time.\n // onSuccess() will unblock Dexie to be used by application code.\n // If for example app code writes: db.friends.where('shoeSize').above(40).toArray(callback), the execution of that query\n // will not run until we have called onSuccess(). This is because we want application code to get results that are as\n // accurate as possible. Specifically when connected the first time and the entire DB is being synced down to the browser,\n // it is important that queries starts running first when db is in sync.\n var isFirstRound = true;\n // When message arrive from the server, deal with the message accordingly:\n ws.onmessage = function (event) {\n try {\n // Assume we have a server that should send JSON messages of the following format:\n // {\n // type: \"clientIdentity\", \"changes\", \"ack\" or \"error\"\n // clientIdentity: unique value for our database client node to persist in the context. (Only applicable if type=\"clientIdentity\")\n // message: Error message (Only applicable if type=\"error\")\n // requestId: ID of change request that is acked by the server (Only applicable if type=\"ack\" or \"error\")\n // changes: changes from server (Only applicable if type=\"changes\")\n // lastRevision: last revision of changes sent (applicable if type=\"changes\")\n // partial: true if server has additionalChanges to send. False if these changes were the last known. (applicable if type=\"changes\")\n // }\n var requestFromServer = JSON.parse(event.data);\n log(\"requestFromServer\", requestFromServer, { acceptCallback, isFirstRound });\n\n if (requestFromServer.type == \"clientIdentity\") {\n context.clientIdentity = requestFromServer.clientIdentity;\n context.save();\n\n sendChanges(changes, baseRevision, partial, onChangesAccepted);\n\n ws.send(\n JSON.stringify({\n type: \"subscribe\",\n syncedRevision: syncedRevision,\n }),\n );\n } else if (requestFromServer.type == \"changes\") {\n applyRemoteChanges(\n requestFromServer.changes,\n requestFromServer.currentRevision,\n requestFromServer.partial,\n );\n if (isFirstRound && !requestFromServer.partial) {\n // Since this is the first sync round and server sais we've got all changes - now is the time to call onsuccess()\n onSuccess({\n // Specify a react function that will react on additional client changes\n react: function (\n changes,\n baseRevision,\n partial,\n onChangesAccepted,\n ) {\n sendChanges(\n changes,\n baseRevision,\n partial,\n onChangesAccepted,\n );\n },\n // Specify a disconnect function that will close our socket so that we dont continue to monitor changes.\n disconnect: function () {\n ws.close();\n },\n });\n isFirstRound = false;\n }\n } else if (requestFromServer.type == \"ack\") {\n var requestId = requestFromServer.requestId;\n var acceptCallback = acceptCallbacks[requestId.toString()];\n acceptCallback(); // Tell framework that server has acknowledged the changes sent.\n delete acceptCallbacks[requestId.toString()];\n } else if (requestFromServer.type == \"error\") {\n var requestId = requestFromServer.requestId;\n ws.close();\n onError(requestFromServer.message, Infinity); // Don't reconnect - an error in application level means we have done something wrong.\n } else {\n log(\"unknown message\", requestFromServer);\n ws.close();\n onError(\"unknown message\", Infinity);\n }\n } catch (e) {\n ws.close();\n onError(e, Infinity); // Something went crazy. Server sends invalid format or our code is buggy. Dont reconnect - it would continue failing.\n }\n };\n },\n });\n};\n","\nexport const SERVER_URL = \"https://api.basic.tech\"\n// export const SERVER_URL = \"http://localhost:3000\"\n\n\nexport const log = (...args: any[]) => {\n try { \n if (localStorage.getItem('basic_debug') === 'true') {\n console.log('[basic]', ...args)\n }\n } catch (e) {\n // console.log('error logging', e)\n }\n}\n\n// export const log = (message: string, ...args: any[]) => {\n// try {\n// if (process.env.NODE_ENV === 'development') {\n// const stack = new Error().stack;\n// const caller = stack?.split('\\n')[2]?.trim();\n// console.log(`[basic] ${message}`, ...args);\n// // console.log(`[stack] ${caller}`);\n// }\n// } catch (e) {\n// console.error('Error in logWithStack:', e);\n// }\n// }\n","// Basic Schema Library\n// utils for validating and interacting with Basic schemas\nimport Ajv, { ErrorObject } from 'ajv'\n\nconst basicJsonSchema = {\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"type\": \"object\",\n \"properties\": {\n \"project_id\": {\n \"type\": \"string\"\n },\n \"namespace\": {\n \"type\": \"string\",\n },\n \"version\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"tables\": {\n \"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9_]+$\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"collection\"]\n },\n \"fields\": {\n \"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9_]+$\": {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"string\", \"boolean\", \"number\", \"json\"]\n },\n \"indexed\": {\n \"type\": \"boolean\"\n }, \n \"required\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\"type\"]\n }\n },\n \"additionalProperties\": true\n }\n },\n \"required\": [\"fields\"]\n }\n },\n \"additionalProperties\": true\n }\n },\n \"required\": [\"project_id\", \"version\", \"tables\"]\n }\nconst ajv = new Ajv()\nconst validator = ajv.compile(basicJsonSchema)\n\ntype Schema = typeof basicJsonSchema\n\nfunction generateEmptySchema() {\n \n}\n\n\n/**\n * Validate a schema\n * only checks if the schema is formatted correctly, not if can be published\n * @param schema - The schema to validate\n * @returns {valid: boolean, errors: any[]} - The validation result\n */\nfunction validateSchema(schema: Schema) : {valid: boolean, errors: ErrorObject[]} {\n const v = validator(schema)\n return { \n valid: v,\n errors: validator.errors || []\n }\n}\n\n// type ErrorObject = {\n// keyword: string;\n// instancePath: string; \n// schemaPath: string;\n// params: Record<string, any>;\n// propertyName?: string;\n// message?: string;\n// schema?: any;\n// parentSchema?: any;\n// data?: any;\n// }\n\n\nfunction validateData(schema: any, table: string, data: Record<string, any>, checkRequired: boolean = true) {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n return { valid: false, errors: valid.errors, message: \"Schema is invalid\" }\n }\n\n const tableSchema = schema.tables[table]\n\n if (!tableSchema) {\n return { valid: false, errors: [{ message: `Table ${table} not found in schema` }], message: \"Table not found\" }\n }\n\n for (const [fieldName, fieldValue] of Object.entries(data)) {\n const fieldSchema = tableSchema.fields[fieldName]\n \n if (!fieldSchema) {\n return { \n valid: false, \n errors: [{ message: `Field ${fieldName} not found in schema` }],\n message: \"Invalid field\"\n }\n }\n\n const schemaType = fieldSchema.type\n const valueType = typeof fieldValue\n\n if (\n (schemaType === 'string' && valueType !== 'string') ||\n (schemaType === 'number' && valueType !== 'number') ||\n (schemaType === 'boolean' && valueType !== 'boolean') ||\n (schemaType === 'json' && valueType !== 'object')\n ) {\n return {\n valid: false,\n errors: [{ \n message: `Field ${fieldName} should be type ${schemaType}, got ${valueType}` \n }],\n message: \"invalid type\"\n }\n }\n }\n\n if (checkRequired) {\n for (const [fieldName, fieldSchema] of Object.entries(tableSchema.fields)) {\n if ((fieldSchema as { required?: boolean }).required && !data[fieldName]) {\n return { valid: false, errors: [{ message: `Field ${fieldName} is required` }], message: \"Required field missing\" }\n }\n }\n }\n\n return { valid: true, errors: [] }\n}\n\n\nexport {\n validateSchema,\n validateData,\n generateEmptySchema\n}\n\n","//@ts-nocheck\n\nconst baseUrl = 'https://api.basic.tech';\n// const baseUrl = 'http://localhost:3000';\n\n\nasync function get({ projectId, accountId, tableName, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;\n const response = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${token}`\n }\n });\n return response.json();\n}\n\nasync function add({ projectId, accountId, tableName, value, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`\n },\n body: JSON.stringify({\"value\": value})\n });\n return response.json();\n}\n\nasync function update({ projectId, accountId, tableName, id, value, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;\n const response = await fetch(url, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`\n },\n body: JSON.stringify({id: id, value: value})\n });\n return response.json();\n}\n\nasync function deleteRecord({ projectId, accountId, tableName, id, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;\n const response = await fetch(url, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${token}`\n }\n });\n return response.json();\n}\n\nexport { get, add, update, deleteRecord };\n\n"],"mappings":"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","names":["import_dexie","changes","baseRevision","partial","onChangesAccepted","requestId","Ajv","key","uuidv7","error","baseUrl","token","user"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/AuthContext.tsx","../src/sync/index.ts","../src/sync/syncProtocol.js","../src/config.ts","../src/schema.ts","../src/db.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { useBasic, BasicProvider } from \"./AuthContext\";\nimport { useLiveQuery as useQuery } from \"dexie-react-hooks\";\n\n// const useQuery = (queryable: any) => {\n// const [loading, setLoading] = useState(true)\n// const [error, setError] = useState<Error | null>(null)\n\n// const result = useLiveQuery(async () => {\n// try {\n// setLoading(true)\n// setError(null)\n \n// // if (typeof queryable === 'function') {\n// // return await queryable()\n// // }\n// return queryable\n \n// } catch (err) {\n// setError(err instanceof Error ? err : new Error('Unknown error'))\n// return undefined\n// } finally {\n// setLoading(false)\n// }\n// }, [queryable])\n\n// return {\n// data: result,\n// loading,\n// error\n// }\n// }\n\n\n\nexport {\n useBasic, BasicProvider, useQuery\n}\n","// @ts-nocheck\n\nimport React, { createContext, useContext, useEffect, useState, useRef } from 'react'\nimport { jwtDecode } from 'jwt-decode'\n\nimport { BasicSync } from './sync'\nimport { get, add, update, deleteRecord } from './db'\nimport { validateSchema } from '@basictech/schema'\n\nimport { log } from './config'\n\n/*\nschema todo:\n field types\n array types\n relations\n*/\n\n\n// const example = {\n// project_id: '123',\n// version: 0,\n// tables: {\n// example: {\n// name: 'example',\n// type: 'collection',\n// fields: {\n// id: {\n// type: 'uuid',\n// primary: true,\n// },\n// value: {\n// type: 'string',\n// indexed: true,\n// },\n// }\n// }\n// }\n// }\n\n\ntype BasicSyncType = {\n basic_schema: any;\n connect: (options: { access_token: string }) => void;\n debugeroo: () => void;\n collection: (name: string) => {\n ref: {\n toArray: () => Promise<any[]>;\n count: () => Promise<number>;\n };\n };\n [key: string]: any; // For other potential methods and properties\n};\n\n\nenum DBStatus {\n LOADING = \"LOADING\",\n OFFLINE = \"OFFLINE\",\n CONNECTING = \"CONNECTING\",\n ONLINE = \"ONLINE\",\n SYNCING = \"SYNCING\",\n ERROR = \"ERROR\"\n}\n\ntype User = {\n name?: string,\n email?: string,\n id?: string,\n primaryEmailAddress?: {\n emailAddress: string\n },\n fullName?: string\n}\ntype Token = {\n access_token: string,\n token_type: string,\n expires_in: number,\n refresh: string,\n}\n\nexport const BasicContext = createContext<{\n unicorn: string,\n isAuthReady: boolean,\n isSignedIn: boolean,\n user: User | null,\n signout: () => void,\n signin: () => void,\n getToken: () => Promise<string>,\n getSignInLink: () => string,\n db: any,\n dbStatus: DBStatus\n}>({\n unicorn: \"🦄\",\n isAuthReady: false,\n isSignedIn: false,\n user: null,\n signout: () => { },\n signin: () => { },\n getToken: () => new Promise(() => { }),\n getSignInLink: () => \"\",\n db: {},\n dbStatus: DBStatus.LOADING\n});\n\nconst EmptyDB: BasicSyncType = {\n isOpen: false,\n collection: () => {\n return {\n ref: {\n toArray: () => [],\n count: () => 0\n }\n }\n }\n}\n\n\nfunction getSyncStatus(statusCode: number): string {\n switch (statusCode) {\n case -1:\n return \"ERROR\";\n case 0:\n return \"OFFLINE\";\n case 1:\n return \"CONNECTING\";\n case 2:\n return \"ONLINE\";\n case 3:\n return \"SYNCING\";\n case 4:\n return \"ERROR_WILL_RETRY\";\n default:\n return \"UNKNOWN\";\n }\n}\n\ntype ErrorObject = {\n code: string;\n title: string;\n message: string;\n}\n\nexport function BasicProvider({ children, project_id, schema, debug = false }: { children: React.ReactNode, project_id: string, schema: any, debug?: boolean }) {\n const [isAuthReady, setIsAuthReady] = useState(false)\n const [isSignedIn, setIsSignedIn] = useState<boolean>(false)\n const [token, setToken] = useState<Token | null>(null)\n const [user, setUser] = useState<User>({})\n\n const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.LOADING)\n const [error, setError] = useState<ErrorObject | null>(null)\n\n const syncRef = useRef<BasicSync | null>(null);\n\n\n useEffect(() => {\n function initDb() {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n log('Basic Schema is invalid!', valid.errors)\n console.group('Schema Errors')\n let errorMessage = ''\n valid.errors.forEach((error, index) => {\n log(`${index + 1}:`, error.message, ` - at ${error.instancePath}`)\n errorMessage += `${index + 1}: ${error.message} - at ${error.instancePath}\\n`\n })\n console.groupEnd('Schema Errors')\n setError({\n code: 'schema_invalid',\n title: 'Basic Schema is invalid!',\n message: errorMessage\n })\n return null\n }\n\n if (!syncRef.current) {\n log('Initializing BasicDB')\n syncRef.current = new BasicSync('basicdb', { schema: schema });\n\n // log('db is open', syncRef.current.isOpen())\n // syncRef.current.open()\n // .then(() => {\n // log(\"is open now:\", syncRef.current.isOpen())\n // })\n }\n }\n\n initDb()\n }, []);\n\n useEffect(() => {\n if (!syncRef.current) {\n return\n }\n\n // syncRef.current.handleStatusChange((status: number, url: string) => {\n // setDbStatus(getSyncStatus(status))\n // })\n\n syncRef.current.syncable.on('statusChanged', (status: number, url: string) => {\n setDbStatus(getSyncStatus(status))\n })\n\n syncRef.current.syncable.getStatus().then((status) => {\n setDbStatus(getSyncStatus(status))\n })\n }, [syncRef.current])\n\n\n const connectToDb = async () => {\n const tok = await getToken()\n if (!tok) {\n log('no token found')\n return\n }\n\n log('connecting to db...')\n\n // TODO: handle if signed out after connect() is already called\n\n syncRef.current.connect({ access_token: tok })\n .catch((e) => {\n log('error connecting to db', e)\n })\n }\n\n useEffect(() => {\n if (token && syncRef.current && isSignedIn && isSignedIn) {\n connectToDb()\n }\n }, [isSignedIn])\n\n const getSignInLink = () => {\n log('getting sign in link...')\n\n const randomState = Math.random().toString(36).substring(6);\n localStorage.setItem('basic_auth_state', randomState)\n\n let baseUrl = \"https://api.basic.tech/auth/authorize\"\n baseUrl += `?client_id=${project_id}`\n baseUrl += `&redirect_uri=${encodeURIComponent(window.location.href)}`\n baseUrl += `&response_type=code`\n baseUrl += `&scope=openid`\n baseUrl += `&state=${randomState}`\n\n return baseUrl;\n }\n\n const signin = () => {\n log('signing in: ', getSignInLink())\n const signInLink = getSignInLink()\n //todo: change to the other thing?\n window.location.href = signInLink;\n }\n\n const signout = () => {\n log('signing out!')\n setUser({})\n setIsSignedIn(false)\n setToken(null)\n document.cookie = `basic_token=; Secure; SameSite=Strict`;\n localStorage.removeItem('basic_auth_state')\n\n if (syncRef.current) {\n // WIP - BUG - sometimes connects even after signout\n syncRef.current.disconnect()\n }\n }\n\n const getToken = async (): Promise<string> => {\n log('getting token...')\n\n if (!token) {\n log('no token found')\n throw new Error('no token found')\n }\n\n const decoded = jwtDecode(token?.access_token)\n const isExpired = decoded.exp && decoded.exp < Date.now() / 1000\n\n if (isExpired) {\n log('token is expired - refreshing ...')\n const newToken = await fetchToken(token?.refresh)\n return newToken?.access_token || ''\n }\n\n return token?.access_token || ''\n }\n\n function getCookie(name: string) {\n let cookieValue = '';\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i].trim();\n if (cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n }\n\n const fetchToken = async (code: string) => {\n const token = await fetch('https://api.basic.tech/auth/token', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ code: code })\n })\n .then(response => response.json())\n .catch(error => log('Error:', error))\n\n if (token.error) {\n log('error fetching token', token.error)\n return\n } else {\n // log('token', token)\n setToken(token)\n }\n return token\n }\n\n useEffect(() => {\n localStorage.setItem('basic_debug', debug ? 'true' : 'false')\n\n try {\n if (window.location.search.includes('code')) {\n let code = window.location?.search?.split('code=')[1].split('&')[0]\n\n const state = localStorage.getItem('basic_auth_state')\n if (!state || state !== window.location.search.split('state=')[1].split('&')[0]) {\n log('error: auth state does not match')\n setIsAuthReady(true)\n\n localStorage.removeItem('basic_auth_state')\n window.history.pushState({}, document.title, \"/\");\n return\n }\n\n localStorage.removeItem('basic_auth_state')\n\n fetchToken(code) \n } else { \n let cookie_token = getCookie('basic_token')\n if (cookie_token !== '') {\n setToken(JSON.parse(cookie_token))\n } else { \n setIsAuthReady(true)\n }\n }\n\n\n } catch (e) {\n log('error getting cookie', e)\n }\n }, [])\n\n useEffect(() => {\n async function fetchUser(acc_token: string) {\n console.info('fetching user')\n const user = await fetch('https://api.basic.tech/auth/userInfo', {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${acc_token}`\n }\n })\n .then(response => response.json())\n .catch(error => log('Error:', error))\n\n if (user.error) {\n log('error fetching user', user.error)\n // refreshToken()\n return\n } else {\n // log('user', user)\n document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;\n \n if (window.location.search.includes('code')) {\n window.history.pushState({}, document.title, \"/\");\n }\n \n setUser(user)\n setIsSignedIn(true)\n\n setIsAuthReady(true)\n }\n }\n\n async function checkToken() {\n if (!token) {\n log('error: no user token found')\n\n setIsAuthReady(true)\n return\n }\n\n const decoded = jwtDecode(token?.access_token)\n const isExpired = decoded.exp && decoded.exp < Date.now() / 1000\n\n if (isExpired) {\n log('token is expired - refreshing ...')\n const newToken = await fetchToken(token?.refresh)\n fetchUser(newToken.access_token)\n } else {\n fetchUser(token.access_token)\n }\n }\n\n if (token) {\n checkToken()\n } \n }, [token])\n\n\n const db_ = (tableName: string) => {\n const checkSignIn = () => {\n if (!isSignedIn) {\n throw new Error('cannot use db. user not logged in.')\n }\n }\n\n return {\n get: async () => {\n checkSignIn()\n const tok = await getToken()\n return get({ projectId: project_id, accountId: user.id, tableName: tableName, token: tok })\n },\n add: async (value: any) => {\n checkSignIn()\n const tok = await getToken()\n return add({ projectId: project_id, accountId: user.id, tableName: tableName, value: value, token: tok })\n },\n update: async (id: string, value: any) => {\n checkSignIn()\n const tok = await getToken()\n return update({ projectId: project_id, accountId: user.id, tableName: tableName, id: id, value: value, token: tok })\n },\n delete: async (id: string) => {\n checkSignIn()\n const tok = await getToken()\n return deleteRecord({ projectId: project_id, accountId: user.id, tableName: tableName, id: id, token: tok })\n }\n\n }\n\n }\n\n return (\n <BasicContext.Provider value={{\n unicorn: \"🦄\",\n isAuthReady,\n isSignedIn,\n user,\n signout,\n signin,\n getToken,\n getSignInLink,\n db: syncRef.current,\n dbStatus\n }}>\n {error && <ErrorDisplay error={error} />}\n {syncRef.current ? children : null}\n </BasicContext.Provider>\n )\n}\n\nfunction ErrorDisplay({ error }: { error: ErrorObject }) {\n return <div style={{ \n position: 'absolute',\n top: 20, \n left: 20,\n color: 'black',\n backgroundColor: '#f8d7da',\n border: '1px solid #f5c6cb',\n borderRadius: '4px',\n padding: '20px',\n maxWidth: '400px',\n margin: '20px auto',\n boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',\n fontFamily: 'monospace', \n }}>\n <h3 style={{fontSize: '0.8rem', opacity: 0.8}}>code: {error.code}</h3>\n <h1 style={{fontSize: '1.2rem', lineHeight: '1.5'}}>{error.title}</h1>\n <p>{error.message}</p>\n </div>\n}\n\n/*\npossible errors: \n- projectid missing / invalid\n- schema missing / invalid\n*/\n\nexport function useBasic() {\n return useContext(BasicContext);\n}\n","\"use client\"\n\nimport { v7 as uuidv7 } from 'uuid';\nimport { Dexie, PromiseExtended } from 'dexie';\nimport 'dexie-syncable';\nimport 'dexie-observable';\n\nimport { syncProtocol } from './syncProtocol'\nimport { SERVER_URL, log } from '../config'\n\nimport { validateSchema, validateData } from '../schema'\nsyncProtocol()\n\n\n// const DexieSyncStatus = {\n// \"-1\": \"ERROR\",\n// \"0\": \"OFFLINE\",\n// \"1\": \"CONNECTING\",\n// \"2\": \"ONLINE\",\n// \"3\": \"SYNCING\",\n// \"4\": \"ERROR_WILL_RETRY\"\n// }\n\n\n\n\n\nexport class BasicSync extends Dexie {\n basic_schema: any\n\n constructor(name: string, options: any) {\n super(name, options);\n\n // --- INIT SCHEMA --- // \n\n //todo: handle versions?\n\n // TODO: validate schema\n this.basic_schema = options.schema\n this.version(1).stores(this._convertSchemaToDxSchema(this.basic_schema))\n\n this.version(2).stores({})\n // this.verssion\n\n\n // create an alias for toArray\n // @ts-ignore\n this.Collection.prototype.get = this.Collection.prototype.toArray\n\n\n // --- SYNC --- // \n\n // this.syncable.on(\"statusChanged\", (status, url) => { \n // console.log(\"statusChanged\", status, url)\n // })\n\n }\n\n async connect({ access_token }: { access_token: string }) {\n // const WS_URL = \"ws://localhost:3003/ws\"\n const WS_URL = `${SERVER_URL}/ws`\n\n \n // Update sync nodes\n await this.updateSyncNodes();\n \n // Proceed with the WebSocket connection\n \n log('Starting connection...')\n return this.syncable.connect(\"websocket\", WS_URL, { authToken: access_token });\n }\n\n async disconnect() {\n const WS_URL = `${SERVER_URL}/ws`\n\n return this.syncable.disconnect(WS_URL) \n }\n\n private async updateSyncNodes() {\n try {\n const syncNodes = await this.table('_syncNodes').toArray();\n const localSyncNodes = syncNodes.filter(node => node.type === 'local');\n log('Local sync nodes:', localSyncNodes);\n\n if (localSyncNodes.length > 1) {\n\n \n const largestNodeId = Math.max(...localSyncNodes.map(node => node.id));\n // Check if the largest node is already the master\n const largestNode = localSyncNodes.find(node => node.id === largestNodeId);\n if (largestNode && largestNode.isMaster === 1) {\n log('Largest node is already the master. No changes needed.');\n return; // Exit the function early as no changes are needed\n }\n\n\n log('Largest node id:', largestNodeId);\n log('HEISENBUG: More than one local sync node found.')\n\n for (const node of localSyncNodes) {\n log(`Local sync node keys:`, node.id, node.isMaster);\n await this.table('_syncNodes').update(node.id, { isMaster: node.id === largestNodeId ? 1 : 0 });\n\n log(`HEISENBUG: Setting ${node.id} to ${node.id === largestNodeId ? 'master' : '0'}`);\n }\n\n // Add a 1 second delay before returning // i dont think this helps?\n await new Promise(resolve => setTimeout(resolve, 2000));\n\n }\n\n log('Sync nodes updated');\n } catch (error) {\n console.error('Error updating _syncNodes table:', error);\n }\n }\n\n handleStatusChange(fn: any) {\n this.syncable.on(\"statusChanged\", fn)\n }\n\n\n _convertSchemaToDxSchema(schema: any) {\n const stores = Object.entries(schema.tables).map(([key, table]: any) => {\n\n const indexedFields = Object.entries(table.fields).filter(([key, field]: any) => field.indexed).map(([key, field]: any) => `,${key}`).join('')\n return {\n [key]: 'id' + indexedFields\n }\n })\n\n return Object.assign({}, ...stores)\n }\n\n debugeroo() {\n // console.log(\"debugeroo\", this.syncable)\n\n // this.syncable.list().then(x => console.log(x))\n\n // this.syncable\n return this.syncable\n }\n\n collection(name: string) {\n // TODO: check against schema\n\n return {\n\n /**\n * Returns the underlying Dexie table\n * @type {Dexie.Table}\n */\n ref: this.table(name),\n\n // --- WRITE ---- // \n add: (data: any) => {\n // log(\"Adding data to\", name, data)\n\n const valid = validateData(this.basic_schema, name, data)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).add({\n id: uuidv7(),\n ...data\n })\n\n },\n\n put: (data: any) => {\n const valid = validateData(this.basic_schema, name, data)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).put({\n id: uuidv7(),\n ...data\n })\n },\n\n update: (id: string, data: any) => {\n const valid = validateData(this.basic_schema, name, data, false)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).update(id, data)\n },\n\n delete: (id: string) => {\n return this.table(name).delete(id)\n },\n\n\n // --- READ ---- // \n\n get: async (id: string) => {\n return this.table(name).get(id) \n },\n\n getAll: async () => {\n return this.table(name).toArray();\n },\n\n // --- QUERY ---- // \n // TODO: lots to do here. simplifing creating querie, filtering/ordering/limit, and execute\n\n query: () => this.table(name),\n\n filter: (fn: any) => this.table(name).filter(fn).toArray(),\n\n }\n }\n}\n\nclass QueryMethod { \n\n}\n","\"use client\"\nimport { Dexie } from \"dexie\";\nimport { log } from \"../config\";\n\nexport const syncProtocol = function () {\n log(\"Initializing syncProtocol\");\n // Constants:\n var RECONNECT_DELAY = 5000; // Reconnect delay in case of errors such as network down.\n\n Dexie.Syncable.registerSyncProtocol(\"websocket\", {\n sync: function (\n context,\n url,\n options,\n baseRevision,\n syncedRevision,\n changes,\n partial,\n applyRemoteChanges,\n onChangesAccepted,\n onSuccess,\n onError,\n ) {\n // The following vars are needed because we must know which callback to ack when server sends it's ack to us.\n var requestId = 0;\n var acceptCallbacks = {};\n\n // Connect the WebSocket to given url:\n var ws = new WebSocket(url);\n\n // console.log(\"ws OPTIONS\", options);\n\n // sendChanges() method:\n function sendChanges(changes, baseRevision, partial, onChangesAccepted) {\n log(\"sendChanges\", changes.length, baseRevision);\n ++requestId;\n acceptCallbacks[requestId.toString()] = onChangesAccepted;\n\n // In this example, the server expects the following JSON format of the request:\n // {\n // type: \"changes\"\n // baseRevision: baseRevision,\n // changes: changes,\n // partial: partial,\n // requestId: id\n // }\n // To make the sample simplified, we assume the server has the exact same specification of how changes are structured.\n // In real world, you would have to pre-process the changes array to fit the server specification.\n // However, this example shows how to deal with the WebSocket to fullfill the API.\n\n ws.send(\n JSON.stringify({\n type: \"changes\",\n changes: changes,\n partial: partial,\n baseRevision: baseRevision,\n requestId: requestId,\n }),\n );\n }\n\n\n\n // When WebSocket opens, send our changes to the server.\n ws.onopen = function (event) {\n // Initiate this socket connection by sending our clientIdentity. If we dont have a clientIdentity yet,\n // server will call back with a new client identity that we should use in future WebSocket connections.\n \n log(\"Opening socket - sending clientIdentity\", context.clientIdentity);\n ws.send(\n JSON.stringify({\n type: \"clientIdentity\",\n clientIdentity: context.clientIdentity || null,\n authToken: options.authToken\n }),\n );\n\n };\n\n // If network down or other error, tell the framework to reconnect again in some time:\n ws.onerror = function (event) {\n ws.close();\n log(\"ws.onerror\", event);\n onError(event?.message, RECONNECT_DELAY);\n };\n\n // If socket is closed (network disconnected), inform framework and make it reconnect\n ws.onclose = function (event) {\n // console.log('🙅 ws.onclose', event)\n onError(\"Socket closed: \" + event.reason, RECONNECT_DELAY);\n };\n\n // isFirstRound: Will need to call onSuccess() only when we are in sync the first time.\n // onSuccess() will unblock Dexie to be used by application code.\n // If for example app code writes: db.friends.where('shoeSize').above(40).toArray(callback), the execution of that query\n // will not run until we have called onSuccess(). This is because we want application code to get results that are as\n // accurate as possible. Specifically when connected the first time and the entire DB is being synced down to the browser,\n // it is important that queries starts running first when db is in sync.\n var isFirstRound = true;\n // When message arrive from the server, deal with the message accordingly:\n ws.onmessage = function (event) {\n try {\n // Assume we have a server that should send JSON messages of the following format:\n // {\n // type: \"clientIdentity\", \"changes\", \"ack\" or \"error\"\n // clientIdentity: unique value for our database client node to persist in the context. (Only applicable if type=\"clientIdentity\")\n // message: Error message (Only applicable if type=\"error\")\n // requestId: ID of change request that is acked by the server (Only applicable if type=\"ack\" or \"error\")\n // changes: changes from server (Only applicable if type=\"changes\")\n // lastRevision: last revision of changes sent (applicable if type=\"changes\")\n // partial: true if server has additionalChanges to send. False if these changes were the last known. (applicable if type=\"changes\")\n // }\n var requestFromServer = JSON.parse(event.data);\n log(\"requestFromServer\", requestFromServer, { acceptCallback, isFirstRound });\n\n if (requestFromServer.type == \"clientIdentity\") {\n context.clientIdentity = requestFromServer.clientIdentity;\n context.save();\n\n sendChanges(changes, baseRevision, partial, onChangesAccepted);\n\n ws.send(\n JSON.stringify({\n type: \"subscribe\",\n syncedRevision: syncedRevision,\n }),\n );\n } else if (requestFromServer.type == \"changes\") {\n applyRemoteChanges(\n requestFromServer.changes,\n requestFromServer.currentRevision,\n requestFromServer.partial,\n );\n if (isFirstRound && !requestFromServer.partial) {\n // Since this is the first sync round and server sais we've got all changes - now is the time to call onsuccess()\n onSuccess({\n // Specify a react function that will react on additional client changes\n react: function (\n changes,\n baseRevision,\n partial,\n onChangesAccepted,\n ) {\n sendChanges(\n changes,\n baseRevision,\n partial,\n onChangesAccepted,\n );\n },\n // Specify a disconnect function that will close our socket so that we dont continue to monitor changes.\n disconnect: function () {\n ws.close();\n },\n });\n isFirstRound = false;\n }\n } else if (requestFromServer.type == \"ack\") {\n var requestId = requestFromServer.requestId;\n var acceptCallback = acceptCallbacks[requestId.toString()];\n acceptCallback(); // Tell framework that server has acknowledged the changes sent.\n delete acceptCallbacks[requestId.toString()];\n } else if (requestFromServer.type == \"error\") {\n var requestId = requestFromServer.requestId;\n ws.close();\n onError(requestFromServer.message, Infinity); // Don't reconnect - an error in application level means we have done something wrong.\n } else {\n log(\"unknown message\", requestFromServer);\n ws.close();\n onError(\"unknown message\", Infinity);\n }\n } catch (e) {\n ws.close();\n onError(e, Infinity); // Something went crazy. Server sends invalid format or our code is buggy. Dont reconnect - it would continue failing.\n }\n };\n },\n });\n};\n","\nexport const SERVER_URL = \"https://api.basic.tech\"\n// export const SERVER_URL = \"http://localhost:3000\"\n\n\nexport const log = (...args: any[]) => {\n try { \n if (localStorage.getItem('basic_debug') === 'true') {\n console.log('[basic]', ...args)\n }\n } catch (e) {\n // console.log('error logging', e)\n }\n}\n\n// export const log = (message: string, ...args: any[]) => {\n// try {\n// if (process.env.NODE_ENV === 'development') {\n// const stack = new Error().stack;\n// const caller = stack?.split('\\n')[2]?.trim();\n// console.log(`[basic] ${message}`, ...args);\n// // console.log(`[stack] ${caller}`);\n// }\n// } catch (e) {\n// console.error('Error in logWithStack:', e);\n// }\n// }\n","// Basic Schema Library\n// utils for validating and interacting with Basic schemas\nimport Ajv, { ErrorObject } from 'ajv'\n\nconst basicJsonSchema = {\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"type\": \"object\",\n \"properties\": {\n \"project_id\": {\n \"type\": \"string\"\n },\n \"namespace\": {\n \"type\": \"string\",\n },\n \"version\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"tables\": {\n \"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9_]+$\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"collection\"]\n },\n \"fields\": {\n \"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9_]+$\": {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"string\", \"boolean\", \"number\", \"json\"]\n },\n \"indexed\": {\n \"type\": \"boolean\"\n }, \n \"required\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\"type\"]\n }\n },\n \"additionalProperties\": true\n }\n },\n \"required\": [\"fields\"]\n }\n },\n \"additionalProperties\": true\n }\n },\n \"required\": [\"project_id\", \"version\", \"tables\"]\n }\nconst ajv = new Ajv()\nconst validator = ajv.compile(basicJsonSchema)\n\ntype Schema = typeof basicJsonSchema\n\nfunction generateEmptySchema() {\n \n}\n\n\n/**\n * Validate a schema\n * only checks if the schema is formatted correctly, not if can be published\n * @param schema - The schema to validate\n * @returns {valid: boolean, errors: any[]} - The validation result\n */\nfunction validateSchema(schema: Schema) : {valid: boolean, errors: ErrorObject[]} {\n const v = validator(schema)\n return { \n valid: v,\n errors: validator.errors || []\n }\n}\n\n// type ErrorObject = {\n// keyword: string;\n// instancePath: string; \n// schemaPath: string;\n// params: Record<string, any>;\n// propertyName?: string;\n// message?: string;\n// schema?: any;\n// parentSchema?: any;\n// data?: any;\n// }\n\n\nfunction validateData(schema: any, table: string, data: Record<string, any>, checkRequired: boolean = true) {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n return { valid: false, errors: valid.errors, message: \"Schema is invalid\" }\n }\n\n const tableSchema = schema.tables[table]\n\n if (!tableSchema) {\n return { valid: false, errors: [{ message: `Table ${table} not found in schema` }], message: \"Table not found\" }\n }\n\n for (const [fieldName, fieldValue] of Object.entries(data)) {\n const fieldSchema = tableSchema.fields[fieldName]\n \n if (!fieldSchema) {\n return { \n valid: false, \n errors: [{ message: `Field ${fieldName} not found in schema` }],\n message: \"Invalid field\"\n }\n }\n\n const schemaType = fieldSchema.type\n const valueType = typeof fieldValue\n\n if (\n (schemaType === 'string' && valueType !== 'string') ||\n (schemaType === 'number' && valueType !== 'number') ||\n (schemaType === 'boolean' && valueType !== 'boolean') ||\n (schemaType === 'json' && valueType !== 'object')\n ) {\n return {\n valid: false,\n errors: [{ \n message: `Field ${fieldName} should be type ${schemaType}, got ${valueType}` \n }],\n message: \"invalid type\"\n }\n }\n }\n\n if (checkRequired) {\n for (const [fieldName, fieldSchema] of Object.entries(tableSchema.fields)) {\n if ((fieldSchema as { required?: boolean }).required && !data[fieldName]) {\n return { valid: false, errors: [{ message: `Field ${fieldName} is required` }], message: \"Required field missing\" }\n }\n }\n }\n\n return { valid: true, errors: [] }\n}\n\n\nexport {\n validateSchema,\n validateData,\n generateEmptySchema\n}\n\n","//@ts-nocheck\n\nconst baseUrl = 'https://api.basic.tech';\n// const baseUrl = 'http://localhost:3000';\n\n\nasync function get({ projectId, accountId, tableName, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;\n const response = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${token}`\n }\n });\n return response.json();\n}\n\nasync function add({ projectId, accountId, tableName, value, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`\n },\n body: JSON.stringify({\"value\": value})\n });\n return response.json();\n}\n\nasync function update({ projectId, accountId, tableName, id, value, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;\n const response = await fetch(url, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`\n },\n body: JSON.stringify({id: id, value: value})\n });\n return response.json();\n}\n\nasync function deleteRecord({ projectId, accountId, tableName, id, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;\n const response = await fetch(url, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${token}`\n }\n });\n return response.json();\n}\n\nexport { get, add, update, deleteRecord };\n\n"],"mappings":"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","names":["useQuery","import_dexie","changes","baseRevision","partial","onChangesAccepted","requestId","Ajv","key","uuidv7","import_schema","error","baseUrl","token","user"]}
package/dist/index.mjs CHANGED
@@ -187,8 +187,6 @@ var basicJsonSchema = {
187
187
  };
188
188
  var ajv = new Ajv();
189
189
  var validator = ajv.compile(basicJsonSchema);
190
- function generateEmptySchema() {
191
- }
192
190
  function validateSchema(schema) {
193
191
  const v = validator(schema);
194
192
  return {
@@ -253,6 +251,10 @@ var BasicSync = class extends Dexie2 {
253
251
  log("Starting connection...");
254
252
  return this.syncable.connect("websocket", WS_URL, { authToken: access_token });
255
253
  }
254
+ async disconnect() {
255
+ const WS_URL = `${SERVER_URL}/ws`;
256
+ return this.syncable.disconnect(WS_URL);
257
+ }
256
258
  async updateSyncNodes() {
257
259
  try {
258
260
  const syncNodes = await this.table("_syncNodes").toArray();
@@ -397,6 +399,7 @@ async function deleteRecord({ projectId, accountId, tableName, id, token }) {
397
399
  }
398
400
 
399
401
  // src/AuthContext.tsx
402
+ import { validateSchema as validateSchema3 } from "@basictech/schema";
400
403
  import { jsx, jsxs } from "react/jsx-runtime";
401
404
  var BasicContext = createContext({
402
405
  unicorn: "\u{1F984}",
@@ -441,7 +444,7 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
441
444
  const syncRef = useRef(null);
442
445
  useEffect(() => {
443
446
  function initDb() {
444
- const valid = validateSchema(schema);
447
+ const valid = validateSchema3(schema);
445
448
  if (!valid.valid) {
446
449
  log("Basic Schema is invalid!", valid.errors);
447
450
  console.group("Schema Errors");
@@ -489,10 +492,10 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
489
492
  });
490
493
  };
491
494
  useEffect(() => {
492
- if (token && syncRef.current) {
495
+ if (token && syncRef.current && isSignedIn && isSignedIn) {
493
496
  connectToDb();
494
497
  }
495
- }, [token]);
498
+ }, [isSignedIn]);
496
499
  const getSignInLink = () => {
497
500
  log("getting sign in link...");
498
501
  const randomState = Math.random().toString(36).substring(6);
@@ -517,6 +520,9 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
517
520
  setToken(null);
518
521
  document.cookie = `basic_token=; Secure; SameSite=Strict`;
519
522
  localStorage.removeItem("basic_auth_state");
523
+ if (syncRef.current) {
524
+ syncRef.current.disconnect();
525
+ }
520
526
  };
521
527
  const getToken = async () => {
522
528
  log("getting token...");
@@ -705,23 +711,9 @@ function useBasic() {
705
711
  }
706
712
 
707
713
  // src/index.ts
708
- import { useLiveQuery } from "dexie-react-hooks";
709
- function useQuery(queryable) {
710
- return useLiveQuery(() => {
711
- if (typeof queryable === "function") {
712
- return queryable();
713
- }
714
- return queryable;
715
- }, [queryable], []);
716
- }
717
- var sc = {
718
- validateSchema,
719
- validateData,
720
- generateEmptySchema
721
- };
714
+ import { useLiveQuery as useQuery } from "dexie-react-hooks";
722
715
  export {
723
716
  BasicProvider,
724
- sc,
725
717
  useBasic,
726
718
  useQuery
727
719
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/AuthContext.tsx","../src/sync/index.ts","../src/sync/syncProtocol.js","../src/config.ts","../src/schema.ts","../src/db.ts","../src/index.ts"],"sourcesContent":["// @ts-nocheck\n\nimport React, { createContext, useContext, useEffect, useState, useRef } from 'react'\nimport { jwtDecode } from 'jwt-decode'\n\nimport { BasicSync } from './sync'\nimport { get, add, update, deleteRecord } from './db'\nimport { validateSchema } from './schema'\n\nimport { log } from './config'\n\n/*\nschema todo:\n field types\n array types\n relations\n*/\n\n\n// const example = {\n// project_id: '123',\n// version: 0,\n// tables: {\n// example: {\n// name: 'example',\n// type: 'collection',\n// fields: {\n// id: {\n// type: 'uuid',\n// primary: true,\n// },\n// value: {\n// type: 'string',\n// indexed: true,\n// },\n// }\n// }\n// }\n// }\n\n\ntype BasicSyncType = {\n basic_schema: any;\n connect: (options: { access_token: string }) => void;\n debugeroo: () => void;\n collection: (name: string) => {\n ref: {\n toArray: () => Promise<any[]>;\n count: () => Promise<number>;\n };\n };\n [key: string]: any; // For other potential methods and properties\n};\n\n\nenum DBStatus {\n LOADING = \"LOADING\",\n OFFLINE = \"OFFLINE\",\n CONNECTING = \"CONNECTING\",\n ONLINE = \"ONLINE\",\n SYNCING = \"SYNCING\",\n ERROR = \"ERROR\"\n}\n\ntype User = {\n name?: string,\n email?: string,\n id?: string,\n primaryEmailAddress?: {\n emailAddress: string\n },\n fullName?: string\n}\ntype Token = {\n access_token: string,\n token_type: string,\n expires_in: number,\n refresh: string,\n}\n\nexport const BasicContext = createContext<{\n unicorn: string,\n isAuthReady: boolean,\n isSignedIn: boolean,\n user: User | null,\n signout: () => void,\n signin: () => void,\n getToken: () => Promise<string>,\n getSignInLink: () => string,\n db: any,\n dbStatus: DBStatus\n}>({\n unicorn: \"🦄\",\n isAuthReady: false,\n isSignedIn: false,\n user: null,\n signout: () => { },\n signin: () => { },\n getToken: () => new Promise(() => { }),\n getSignInLink: () => \"\",\n db: {},\n dbStatus: DBStatus.LOADING\n});\n\nconst EmptyDB: BasicSyncType = {\n isOpen: false,\n collection: () => {\n return {\n ref: {\n toArray: () => [],\n count: () => 0\n }\n }\n }\n}\n\n\nfunction getSyncStatus(statusCode: number): string {\n switch (statusCode) {\n case -1:\n return \"ERROR\";\n case 0:\n return \"OFFLINE\";\n case 1:\n return \"CONNECTING\";\n case 2:\n return \"ONLINE\";\n case 3:\n return \"SYNCING\";\n case 4:\n return \"ERROR_WILL_RETRY\";\n default:\n return \"UNKNOWN\";\n }\n}\n\ntype ErrorObject = {\n code: string;\n title: string;\n message: string;\n}\n\nexport function BasicProvider({ children, project_id, schema, debug = false }: { children: React.ReactNode, project_id: string, schema: any, debug?: boolean }) {\n const [isAuthReady, setIsAuthReady] = useState(false)\n const [isSignedIn, setIsSignedIn] = useState<boolean>(false)\n const [token, setToken] = useState<Token | null>(null)\n const [user, setUser] = useState<User>({})\n\n const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.LOADING)\n const [error, setError] = useState<ErrorObject | null>(null)\n\n const syncRef = useRef<BasicSync | null>(null);\n\n\n useEffect(() => {\n function initDb() {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n log('Basic Schema is invalid!', valid.errors)\n console.group('Schema Errors')\n let errorMessage = ''\n valid.errors.forEach((error, index) => {\n log(`${index + 1}:`, error.message, ` - at ${error.instancePath}`)\n errorMessage += `${index + 1}: ${error.message} - at ${error.instancePath}\\n`\n })\n console.groupEnd('Schema Errors')\n setError({\n code: 'schema_invalid',\n title: 'Basic Schema is invalid!',\n message: errorMessage\n })\n return null\n }\n\n if (!syncRef.current) {\n log('Initializing BasicDB')\n syncRef.current = new BasicSync('basicdb', { schema: schema });\n\n // log('db is open', syncRef.current.isOpen())\n // syncRef.current.open()\n // .then(() => {\n // log(\"is open now:\", syncRef.current.isOpen())\n // })\n }\n }\n\n initDb()\n }, []);\n\n useEffect(() => {\n if (!syncRef.current) {\n return\n }\n\n // syncRef.current.handleStatusChange((status: number, url: string) => {\n // setDbStatus(getSyncStatus(status))\n // })\n\n syncRef.current.syncable.on('statusChanged', (status: number, url: string) => {\n setDbStatus(getSyncStatus(status))\n })\n\n syncRef.current.syncable.getStatus().then((status) => {\n setDbStatus(getSyncStatus(status))\n })\n }, [syncRef.current])\n\n\n const connectToDb = async () => {\n const tok = await getToken()\n if (!tok) {\n log('no token found')\n return\n }\n\n log('connecting to db...')\n\n // TODO: handle if signed out after connect() is already called\n\n syncRef.current.connect({ access_token: tok })\n .catch((e) => {\n log('error connecting to db', e)\n })\n }\n\n useEffect(() => {\n if (token && syncRef.current) {\n connectToDb()\n }\n }, [token])\n\n const getSignInLink = () => {\n log('getting sign in link...')\n\n const randomState = Math.random().toString(36).substring(6);\n localStorage.setItem('basic_auth_state', randomState)\n\n let baseUrl = \"https://api.basic.tech/auth/authorize\"\n baseUrl += `?client_id=${project_id}`\n baseUrl += `&redirect_uri=${encodeURIComponent(window.location.href)}`\n baseUrl += `&response_type=code`\n baseUrl += `&scope=openid`\n baseUrl += `&state=${randomState}`\n\n return baseUrl;\n }\n\n const signin = () => {\n log('signing in: ', getSignInLink())\n const signInLink = getSignInLink()\n //todo: change to the other thing?\n window.location.href = signInLink;\n }\n\n const signout = () => {\n log('signing out!')\n setUser({})\n setIsSignedIn(false)\n setToken(null)\n document.cookie = `basic_token=; Secure; SameSite=Strict`;\n localStorage.removeItem('basic_auth_state')\n }\n\n const getToken = async (): Promise<string> => {\n log('getting token...')\n\n if (!token) {\n log('no token found')\n throw new Error('no token found')\n }\n\n const decoded = jwtDecode(token?.access_token)\n const isExpired = decoded.exp && decoded.exp < Date.now() / 1000\n\n if (isExpired) {\n log('token is expired - refreshing ...')\n const newToken = await fetchToken(token?.refresh)\n return newToken?.access_token || ''\n }\n\n return token?.access_token || ''\n }\n\n function getCookie(name: string) {\n let cookieValue = '';\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i].trim();\n if (cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n }\n\n const fetchToken = async (code: string) => {\n const token = await fetch('https://api.basic.tech/auth/token', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ code: code })\n })\n .then(response => response.json())\n .catch(error => log('Error:', error))\n\n if (token.error) {\n log('error fetching token', token.error)\n return\n } else {\n // log('token', token)\n setToken(token)\n }\n return token\n }\n\n useEffect(() => {\n localStorage.setItem('basic_debug', debug ? 'true' : 'false')\n\n try {\n if (window.location.search.includes('code')) {\n let code = window.location?.search?.split('code=')[1].split('&')[0]\n\n const state = localStorage.getItem('basic_auth_state')\n if (!state || state !== window.location.search.split('state=')[1].split('&')[0]) {\n log('error: auth state does not match')\n setIsAuthReady(true)\n\n localStorage.removeItem('basic_auth_state')\n window.history.pushState({}, document.title, \"/\");\n return\n }\n\n localStorage.removeItem('basic_auth_state')\n\n fetchToken(code) \n } else { \n let cookie_token = getCookie('basic_token')\n if (cookie_token !== '') {\n setToken(JSON.parse(cookie_token))\n } else { \n setIsAuthReady(true)\n }\n }\n\n\n } catch (e) {\n log('error getting cookie', e)\n }\n }, [])\n\n useEffect(() => {\n async function fetchUser(acc_token: string) {\n console.info('fetching user')\n const user = await fetch('https://api.basic.tech/auth/userInfo', {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${acc_token}`\n }\n })\n .then(response => response.json())\n .catch(error => log('Error:', error))\n\n if (user.error) {\n log('error fetching user', user.error)\n // refreshToken()\n return\n } else {\n // log('user', user)\n document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;\n \n if (window.location.search.includes('code')) {\n window.history.pushState({}, document.title, \"/\");\n }\n \n setUser(user)\n setIsSignedIn(true)\n\n setIsAuthReady(true)\n }\n }\n\n async function checkToken() {\n if (!token) {\n log('error: no user token found')\n\n setIsAuthReady(true)\n return\n }\n\n const decoded = jwtDecode(token?.access_token)\n const isExpired = decoded.exp && decoded.exp < Date.now() / 1000\n\n if (isExpired) {\n log('token is expired - refreshing ...')\n const newToken = await fetchToken(token?.refresh)\n fetchUser(newToken.access_token)\n } else {\n fetchUser(token.access_token)\n }\n }\n\n if (token) {\n checkToken()\n } \n }, [token])\n\n\n const db_ = (tableName: string) => {\n const checkSignIn = () => {\n if (!isSignedIn) {\n throw new Error('cannot use db. user not logged in.')\n }\n }\n\n return {\n get: async () => {\n checkSignIn()\n const tok = await getToken()\n return get({ projectId: project_id, accountId: user.id, tableName: tableName, token: tok })\n },\n add: async (value: any) => {\n checkSignIn()\n const tok = await getToken()\n return add({ projectId: project_id, accountId: user.id, tableName: tableName, value: value, token: tok })\n },\n update: async (id: string, value: any) => {\n checkSignIn()\n const tok = await getToken()\n return update({ projectId: project_id, accountId: user.id, tableName: tableName, id: id, value: value, token: tok })\n },\n delete: async (id: string) => {\n checkSignIn()\n const tok = await getToken()\n return deleteRecord({ projectId: project_id, accountId: user.id, tableName: tableName, id: id, token: tok })\n }\n\n }\n\n }\n\n return (\n <BasicContext.Provider value={{\n unicorn: \"🦄\",\n isAuthReady,\n isSignedIn,\n user,\n signout,\n signin,\n getToken,\n getSignInLink,\n db: syncRef.current,\n dbStatus\n }}>\n {error && <ErrorDisplay error={error} />}\n {syncRef.current ? children : null}\n </BasicContext.Provider>\n )\n}\n\nfunction ErrorDisplay({ error }: { error: ErrorObject }) {\n return <div style={{ \n position: 'absolute',\n top: 20, \n left: 20,\n color: 'black',\n backgroundColor: '#f8d7da',\n border: '1px solid #f5c6cb',\n borderRadius: '4px',\n padding: '20px',\n maxWidth: '400px',\n margin: '20px auto',\n boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',\n fontFamily: 'monospace', \n }}>\n <h3 style={{fontSize: '0.8rem', opacity: 0.8}}>code: {error.code}</h3>\n <h1 style={{fontSize: '1.2rem', lineHeight: '1.5'}}>{error.title}</h1>\n <p>{error.message}</p>\n </div>\n}\n\n/*\npossible errors: \n- projectid missing / invalid\n- schema missing / invalid\n*/\n\nexport function useBasic() {\n return useContext(BasicContext);\n}\n","\"use client\"\n\nimport { v7 as uuidv7 } from 'uuid';\nimport { Dexie, PromiseExtended } from 'dexie';\nimport 'dexie-syncable';\nimport 'dexie-observable';\n\nimport { syncProtocol } from './syncProtocol'\nimport { SERVER_URL, log } from '../config'\n\nimport { validateSchema, validateData } from '../schema'\nsyncProtocol()\n\n\n// const DexieSyncStatus = {\n// \"-1\": \"ERROR\",\n// \"0\": \"OFFLINE\",\n// \"1\": \"CONNECTING\",\n// \"2\": \"ONLINE\",\n// \"3\": \"SYNCING\",\n// \"4\": \"ERROR_WILL_RETRY\"\n// }\n\n\n\n\n\nexport class BasicSync extends Dexie {\n basic_schema: any\n\n constructor(name: string, options: any) {\n super(name, options);\n\n // --- INIT SCHEMA --- // \n\n //todo: handle versions?\n\n // TODO: validate schema\n this.basic_schema = options.schema\n this.version(1).stores(this._convertSchemaToDxSchema(this.basic_schema))\n\n this.version(2).stores({})\n // this.verssion\n\n\n // create an alias for toArray\n // @ts-ignore\n this.Collection.prototype.get = this.Collection.prototype.toArray\n\n\n // --- SYNC --- // \n\n // this.syncable.on(\"statusChanged\", (status, url) => { \n // console.log(\"statusChanged\", status, url)\n // })\n\n }\n\n async connect({ access_token }: { access_token: string }) {\n // const WS_URL = \"ws://localhost:3003/ws\"\n const WS_URL = `${SERVER_URL}/ws`\n\n \n // Update sync nodes\n await this.updateSyncNodes();\n \n // Proceed with the WebSocket connection\n \n log('Starting connection...')\n return this.syncable.connect(\"websocket\", WS_URL, { authToken: access_token });\n }\n\n private async updateSyncNodes() {\n try {\n const syncNodes = await this.table('_syncNodes').toArray();\n const localSyncNodes = syncNodes.filter(node => node.type === 'local');\n log('Local sync nodes:', localSyncNodes);\n\n if (localSyncNodes.length > 1) {\n\n \n const largestNodeId = Math.max(...localSyncNodes.map(node => node.id));\n // Check if the largest node is already the master\n const largestNode = localSyncNodes.find(node => node.id === largestNodeId);\n if (largestNode && largestNode.isMaster === 1) {\n log('Largest node is already the master. No changes needed.');\n return; // Exit the function early as no changes are needed\n }\n\n\n log('Largest node id:', largestNodeId);\n log('HEISENBUG: More than one local sync node found.')\n\n for (const node of localSyncNodes) {\n log(`Local sync node keys:`, node.id, node.isMaster);\n await this.table('_syncNodes').update(node.id, { isMaster: node.id === largestNodeId ? 1 : 0 });\n\n log(`HEISENBUG: Setting ${node.id} to ${node.id === largestNodeId ? 'master' : '0'}`);\n }\n\n // Add a 1 second delay before returning // i dont think this helps?\n await new Promise(resolve => setTimeout(resolve, 2000));\n\n }\n\n log('Sync nodes updated');\n } catch (error) {\n console.error('Error updating _syncNodes table:', error);\n }\n }\n\n handleStatusChange(fn: any) {\n this.syncable.on(\"statusChanged\", fn)\n }\n\n\n _convertSchemaToDxSchema(schema: any) {\n const stores = Object.entries(schema.tables).map(([key, table]: any) => {\n\n const indexedFields = Object.entries(table.fields).filter(([key, field]: any) => field.indexed).map(([key, field]: any) => `,${key}`).join('')\n return {\n [key]: 'id' + indexedFields\n }\n })\n\n return Object.assign({}, ...stores)\n }\n\n debugeroo() {\n // console.log(\"debugeroo\", this.syncable)\n\n // this.syncable.list().then(x => console.log(x))\n\n // this.syncable\n return this.syncable\n }\n\n collection(name: string) {\n // TODO: check against schema\n\n return {\n\n /**\n * Returns the underlying Dexie table\n * @type {Dexie.Table}\n */\n ref: this.table(name),\n\n // --- WRITE ---- // \n add: (data: any) => {\n // log(\"Adding data to\", name, data)\n\n const valid = validateData(this.basic_schema, name, data)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).add({\n id: uuidv7(),\n ...data\n })\n\n },\n\n put: (data: any) => {\n const valid = validateData(this.basic_schema, name, data)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).put({\n id: uuidv7(),\n ...data\n })\n },\n\n update: (id: string, data: any) => {\n const valid = validateData(this.basic_schema, name, data, false)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).update(id, data)\n },\n\n delete: (id: string) => {\n return this.table(name).delete(id)\n },\n\n\n // --- READ ---- // \n\n get: async (id: string) => {\n return this.table(name).get(id) \n },\n\n getAll: async () => {\n return this.table(name).toArray();\n },\n\n // --- QUERY ---- // \n // TODO: lots to do here. simplifing creating querie, filtering/ordering/limit, and execute\n\n query: () => this.table(name),\n\n filter: (fn: any) => this.table(name).filter(fn).toArray(),\n\n }\n }\n}\n\nclass QueryMethod { \n\n}\n","\"use client\"\nimport { Dexie } from \"dexie\";\nimport { log } from \"../config\";\n\nexport const syncProtocol = function () {\n log(\"Initializing syncProtocol\");\n // Constants:\n var RECONNECT_DELAY = 5000; // Reconnect delay in case of errors such as network down.\n\n Dexie.Syncable.registerSyncProtocol(\"websocket\", {\n sync: function (\n context,\n url,\n options,\n baseRevision,\n syncedRevision,\n changes,\n partial,\n applyRemoteChanges,\n onChangesAccepted,\n onSuccess,\n onError,\n ) {\n // The following vars are needed because we must know which callback to ack when server sends it's ack to us.\n var requestId = 0;\n var acceptCallbacks = {};\n\n // Connect the WebSocket to given url:\n var ws = new WebSocket(url);\n\n // console.log(\"ws OPTIONS\", options);\n\n // sendChanges() method:\n function sendChanges(changes, baseRevision, partial, onChangesAccepted) {\n log(\"sendChanges\", changes.length, baseRevision);\n ++requestId;\n acceptCallbacks[requestId.toString()] = onChangesAccepted;\n\n // In this example, the server expects the following JSON format of the request:\n // {\n // type: \"changes\"\n // baseRevision: baseRevision,\n // changes: changes,\n // partial: partial,\n // requestId: id\n // }\n // To make the sample simplified, we assume the server has the exact same specification of how changes are structured.\n // In real world, you would have to pre-process the changes array to fit the server specification.\n // However, this example shows how to deal with the WebSocket to fullfill the API.\n\n ws.send(\n JSON.stringify({\n type: \"changes\",\n changes: changes,\n partial: partial,\n baseRevision: baseRevision,\n requestId: requestId,\n }),\n );\n }\n\n\n\n // When WebSocket opens, send our changes to the server.\n ws.onopen = function (event) {\n // Initiate this socket connection by sending our clientIdentity. If we dont have a clientIdentity yet,\n // server will call back with a new client identity that we should use in future WebSocket connections.\n \n log(\"Opening socket - sending clientIdentity\", context.clientIdentity);\n ws.send(\n JSON.stringify({\n type: \"clientIdentity\",\n clientIdentity: context.clientIdentity || null,\n authToken: options.authToken\n }),\n );\n\n };\n\n // If network down or other error, tell the framework to reconnect again in some time:\n ws.onerror = function (event) {\n ws.close();\n log(\"ws.onerror\", event);\n onError(event?.message, RECONNECT_DELAY);\n };\n\n // If socket is closed (network disconnected), inform framework and make it reconnect\n ws.onclose = function (event) {\n // console.log('🙅 ws.onclose', event)\n onError(\"Socket closed: \" + event.reason, RECONNECT_DELAY);\n };\n\n // isFirstRound: Will need to call onSuccess() only when we are in sync the first time.\n // onSuccess() will unblock Dexie to be used by application code.\n // If for example app code writes: db.friends.where('shoeSize').above(40).toArray(callback), the execution of that query\n // will not run until we have called onSuccess(). This is because we want application code to get results that are as\n // accurate as possible. Specifically when connected the first time and the entire DB is being synced down to the browser,\n // it is important that queries starts running first when db is in sync.\n var isFirstRound = true;\n // When message arrive from the server, deal with the message accordingly:\n ws.onmessage = function (event) {\n try {\n // Assume we have a server that should send JSON messages of the following format:\n // {\n // type: \"clientIdentity\", \"changes\", \"ack\" or \"error\"\n // clientIdentity: unique value for our database client node to persist in the context. (Only applicable if type=\"clientIdentity\")\n // message: Error message (Only applicable if type=\"error\")\n // requestId: ID of change request that is acked by the server (Only applicable if type=\"ack\" or \"error\")\n // changes: changes from server (Only applicable if type=\"changes\")\n // lastRevision: last revision of changes sent (applicable if type=\"changes\")\n // partial: true if server has additionalChanges to send. False if these changes were the last known. (applicable if type=\"changes\")\n // }\n var requestFromServer = JSON.parse(event.data);\n log(\"requestFromServer\", requestFromServer, { acceptCallback, isFirstRound });\n\n if (requestFromServer.type == \"clientIdentity\") {\n context.clientIdentity = requestFromServer.clientIdentity;\n context.save();\n\n sendChanges(changes, baseRevision, partial, onChangesAccepted);\n\n ws.send(\n JSON.stringify({\n type: \"subscribe\",\n syncedRevision: syncedRevision,\n }),\n );\n } else if (requestFromServer.type == \"changes\") {\n applyRemoteChanges(\n requestFromServer.changes,\n requestFromServer.currentRevision,\n requestFromServer.partial,\n );\n if (isFirstRound && !requestFromServer.partial) {\n // Since this is the first sync round and server sais we've got all changes - now is the time to call onsuccess()\n onSuccess({\n // Specify a react function that will react on additional client changes\n react: function (\n changes,\n baseRevision,\n partial,\n onChangesAccepted,\n ) {\n sendChanges(\n changes,\n baseRevision,\n partial,\n onChangesAccepted,\n );\n },\n // Specify a disconnect function that will close our socket so that we dont continue to monitor changes.\n disconnect: function () {\n ws.close();\n },\n });\n isFirstRound = false;\n }\n } else if (requestFromServer.type == \"ack\") {\n var requestId = requestFromServer.requestId;\n var acceptCallback = acceptCallbacks[requestId.toString()];\n acceptCallback(); // Tell framework that server has acknowledged the changes sent.\n delete acceptCallbacks[requestId.toString()];\n } else if (requestFromServer.type == \"error\") {\n var requestId = requestFromServer.requestId;\n ws.close();\n onError(requestFromServer.message, Infinity); // Don't reconnect - an error in application level means we have done something wrong.\n } else {\n log(\"unknown message\", requestFromServer);\n ws.close();\n onError(\"unknown message\", Infinity);\n }\n } catch (e) {\n ws.close();\n onError(e, Infinity); // Something went crazy. Server sends invalid format or our code is buggy. Dont reconnect - it would continue failing.\n }\n };\n },\n });\n};\n","\nexport const SERVER_URL = \"https://api.basic.tech\"\n// export const SERVER_URL = \"http://localhost:3000\"\n\n\nexport const log = (...args: any[]) => {\n try { \n if (localStorage.getItem('basic_debug') === 'true') {\n console.log('[basic]', ...args)\n }\n } catch (e) {\n // console.log('error logging', e)\n }\n}\n\n// export const log = (message: string, ...args: any[]) => {\n// try {\n// if (process.env.NODE_ENV === 'development') {\n// const stack = new Error().stack;\n// const caller = stack?.split('\\n')[2]?.trim();\n// console.log(`[basic] ${message}`, ...args);\n// // console.log(`[stack] ${caller}`);\n// }\n// } catch (e) {\n// console.error('Error in logWithStack:', e);\n// }\n// }\n","// Basic Schema Library\n// utils for validating and interacting with Basic schemas\nimport Ajv, { ErrorObject } from 'ajv'\n\nconst basicJsonSchema = {\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"type\": \"object\",\n \"properties\": {\n \"project_id\": {\n \"type\": \"string\"\n },\n \"namespace\": {\n \"type\": \"string\",\n },\n \"version\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"tables\": {\n \"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9_]+$\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"collection\"]\n },\n \"fields\": {\n \"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9_]+$\": {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"string\", \"boolean\", \"number\", \"json\"]\n },\n \"indexed\": {\n \"type\": \"boolean\"\n }, \n \"required\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\"type\"]\n }\n },\n \"additionalProperties\": true\n }\n },\n \"required\": [\"fields\"]\n }\n },\n \"additionalProperties\": true\n }\n },\n \"required\": [\"project_id\", \"version\", \"tables\"]\n }\nconst ajv = new Ajv()\nconst validator = ajv.compile(basicJsonSchema)\n\ntype Schema = typeof basicJsonSchema\n\nfunction generateEmptySchema() {\n \n}\n\n\n/**\n * Validate a schema\n * only checks if the schema is formatted correctly, not if can be published\n * @param schema - The schema to validate\n * @returns {valid: boolean, errors: any[]} - The validation result\n */\nfunction validateSchema(schema: Schema) : {valid: boolean, errors: ErrorObject[]} {\n const v = validator(schema)\n return { \n valid: v,\n errors: validator.errors || []\n }\n}\n\n// type ErrorObject = {\n// keyword: string;\n// instancePath: string; \n// schemaPath: string;\n// params: Record<string, any>;\n// propertyName?: string;\n// message?: string;\n// schema?: any;\n// parentSchema?: any;\n// data?: any;\n// }\n\n\nfunction validateData(schema: any, table: string, data: Record<string, any>, checkRequired: boolean = true) {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n return { valid: false, errors: valid.errors, message: \"Schema is invalid\" }\n }\n\n const tableSchema = schema.tables[table]\n\n if (!tableSchema) {\n return { valid: false, errors: [{ message: `Table ${table} not found in schema` }], message: \"Table not found\" }\n }\n\n for (const [fieldName, fieldValue] of Object.entries(data)) {\n const fieldSchema = tableSchema.fields[fieldName]\n \n if (!fieldSchema) {\n return { \n valid: false, \n errors: [{ message: `Field ${fieldName} not found in schema` }],\n message: \"Invalid field\"\n }\n }\n\n const schemaType = fieldSchema.type\n const valueType = typeof fieldValue\n\n if (\n (schemaType === 'string' && valueType !== 'string') ||\n (schemaType === 'number' && valueType !== 'number') ||\n (schemaType === 'boolean' && valueType !== 'boolean') ||\n (schemaType === 'json' && valueType !== 'object')\n ) {\n return {\n valid: false,\n errors: [{ \n message: `Field ${fieldName} should be type ${schemaType}, got ${valueType}` \n }],\n message: \"invalid type\"\n }\n }\n }\n\n if (checkRequired) {\n for (const [fieldName, fieldSchema] of Object.entries(tableSchema.fields)) {\n if ((fieldSchema as { required?: boolean }).required && !data[fieldName]) {\n return { valid: false, errors: [{ message: `Field ${fieldName} is required` }], message: \"Required field missing\" }\n }\n }\n }\n\n return { valid: true, errors: [] }\n}\n\n\nexport {\n validateSchema,\n validateData,\n generateEmptySchema\n}\n\n","//@ts-nocheck\n\nconst baseUrl = 'https://api.basic.tech';\n// const baseUrl = 'http://localhost:3000';\n\n\nasync function get({ projectId, accountId, tableName, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;\n const response = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${token}`\n }\n });\n return response.json();\n}\n\nasync function add({ projectId, accountId, tableName, value, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`\n },\n body: JSON.stringify({\"value\": value})\n });\n return response.json();\n}\n\nasync function update({ projectId, accountId, tableName, id, value, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;\n const response = await fetch(url, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`\n },\n body: JSON.stringify({id: id, value: value})\n });\n return response.json();\n}\n\nasync function deleteRecord({ projectId, accountId, tableName, id, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;\n const response = await fetch(url, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${token}`\n }\n });\n return response.json();\n}\n\nexport { get, add, update, deleteRecord };\n\n","import { useBasic, BasicProvider } from \"./AuthContext\";\nimport { useLiveQuery } from \"dexie-react-hooks\";\nimport { validateSchema, validateData, generateEmptySchema } from \"./schema\";\n\n\nfunction useQuery(queryable: any) {\n return useLiveQuery(() => {\n if (typeof queryable === 'function') {\n return queryable();\n }\n return queryable;\n }, [queryable], []);\n}\n\n\nconst sc = { \n validateSchema: validateSchema,\n validateData: validateData,\n generateEmptySchema: generateEmptySchema\n}\n\nexport {\n useBasic, BasicProvider, useQuery, sc\n}\n"],"mappings":"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","names":["Dexie","changes","baseRevision","partial","onChangesAccepted","requestId","Dexie","key","error","baseUrl","token","user"]}
1
+ {"version":3,"sources":["../src/AuthContext.tsx","../src/sync/index.ts","../src/sync/syncProtocol.js","../src/config.ts","../src/schema.ts","../src/db.ts","../src/index.ts"],"sourcesContent":["// @ts-nocheck\n\nimport React, { createContext, useContext, useEffect, useState, useRef } from 'react'\nimport { jwtDecode } from 'jwt-decode'\n\nimport { BasicSync } from './sync'\nimport { get, add, update, deleteRecord } from './db'\nimport { validateSchema } from '@basictech/schema'\n\nimport { log } from './config'\n\n/*\nschema todo:\n field types\n array types\n relations\n*/\n\n\n// const example = {\n// project_id: '123',\n// version: 0,\n// tables: {\n// example: {\n// name: 'example',\n// type: 'collection',\n// fields: {\n// id: {\n// type: 'uuid',\n// primary: true,\n// },\n// value: {\n// type: 'string',\n// indexed: true,\n// },\n// }\n// }\n// }\n// }\n\n\ntype BasicSyncType = {\n basic_schema: any;\n connect: (options: { access_token: string }) => void;\n debugeroo: () => void;\n collection: (name: string) => {\n ref: {\n toArray: () => Promise<any[]>;\n count: () => Promise<number>;\n };\n };\n [key: string]: any; // For other potential methods and properties\n};\n\n\nenum DBStatus {\n LOADING = \"LOADING\",\n OFFLINE = \"OFFLINE\",\n CONNECTING = \"CONNECTING\",\n ONLINE = \"ONLINE\",\n SYNCING = \"SYNCING\",\n ERROR = \"ERROR\"\n}\n\ntype User = {\n name?: string,\n email?: string,\n id?: string,\n primaryEmailAddress?: {\n emailAddress: string\n },\n fullName?: string\n}\ntype Token = {\n access_token: string,\n token_type: string,\n expires_in: number,\n refresh: string,\n}\n\nexport const BasicContext = createContext<{\n unicorn: string,\n isAuthReady: boolean,\n isSignedIn: boolean,\n user: User | null,\n signout: () => void,\n signin: () => void,\n getToken: () => Promise<string>,\n getSignInLink: () => string,\n db: any,\n dbStatus: DBStatus\n}>({\n unicorn: \"🦄\",\n isAuthReady: false,\n isSignedIn: false,\n user: null,\n signout: () => { },\n signin: () => { },\n getToken: () => new Promise(() => { }),\n getSignInLink: () => \"\",\n db: {},\n dbStatus: DBStatus.LOADING\n});\n\nconst EmptyDB: BasicSyncType = {\n isOpen: false,\n collection: () => {\n return {\n ref: {\n toArray: () => [],\n count: () => 0\n }\n }\n }\n}\n\n\nfunction getSyncStatus(statusCode: number): string {\n switch (statusCode) {\n case -1:\n return \"ERROR\";\n case 0:\n return \"OFFLINE\";\n case 1:\n return \"CONNECTING\";\n case 2:\n return \"ONLINE\";\n case 3:\n return \"SYNCING\";\n case 4:\n return \"ERROR_WILL_RETRY\";\n default:\n return \"UNKNOWN\";\n }\n}\n\ntype ErrorObject = {\n code: string;\n title: string;\n message: string;\n}\n\nexport function BasicProvider({ children, project_id, schema, debug = false }: { children: React.ReactNode, project_id: string, schema: any, debug?: boolean }) {\n const [isAuthReady, setIsAuthReady] = useState(false)\n const [isSignedIn, setIsSignedIn] = useState<boolean>(false)\n const [token, setToken] = useState<Token | null>(null)\n const [user, setUser] = useState<User>({})\n\n const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.LOADING)\n const [error, setError] = useState<ErrorObject | null>(null)\n\n const syncRef = useRef<BasicSync | null>(null);\n\n\n useEffect(() => {\n function initDb() {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n log('Basic Schema is invalid!', valid.errors)\n console.group('Schema Errors')\n let errorMessage = ''\n valid.errors.forEach((error, index) => {\n log(`${index + 1}:`, error.message, ` - at ${error.instancePath}`)\n errorMessage += `${index + 1}: ${error.message} - at ${error.instancePath}\\n`\n })\n console.groupEnd('Schema Errors')\n setError({\n code: 'schema_invalid',\n title: 'Basic Schema is invalid!',\n message: errorMessage\n })\n return null\n }\n\n if (!syncRef.current) {\n log('Initializing BasicDB')\n syncRef.current = new BasicSync('basicdb', { schema: schema });\n\n // log('db is open', syncRef.current.isOpen())\n // syncRef.current.open()\n // .then(() => {\n // log(\"is open now:\", syncRef.current.isOpen())\n // })\n }\n }\n\n initDb()\n }, []);\n\n useEffect(() => {\n if (!syncRef.current) {\n return\n }\n\n // syncRef.current.handleStatusChange((status: number, url: string) => {\n // setDbStatus(getSyncStatus(status))\n // })\n\n syncRef.current.syncable.on('statusChanged', (status: number, url: string) => {\n setDbStatus(getSyncStatus(status))\n })\n\n syncRef.current.syncable.getStatus().then((status) => {\n setDbStatus(getSyncStatus(status))\n })\n }, [syncRef.current])\n\n\n const connectToDb = async () => {\n const tok = await getToken()\n if (!tok) {\n log('no token found')\n return\n }\n\n log('connecting to db...')\n\n // TODO: handle if signed out after connect() is already called\n\n syncRef.current.connect({ access_token: tok })\n .catch((e) => {\n log('error connecting to db', e)\n })\n }\n\n useEffect(() => {\n if (token && syncRef.current && isSignedIn && isSignedIn) {\n connectToDb()\n }\n }, [isSignedIn])\n\n const getSignInLink = () => {\n log('getting sign in link...')\n\n const randomState = Math.random().toString(36).substring(6);\n localStorage.setItem('basic_auth_state', randomState)\n\n let baseUrl = \"https://api.basic.tech/auth/authorize\"\n baseUrl += `?client_id=${project_id}`\n baseUrl += `&redirect_uri=${encodeURIComponent(window.location.href)}`\n baseUrl += `&response_type=code`\n baseUrl += `&scope=openid`\n baseUrl += `&state=${randomState}`\n\n return baseUrl;\n }\n\n const signin = () => {\n log('signing in: ', getSignInLink())\n const signInLink = getSignInLink()\n //todo: change to the other thing?\n window.location.href = signInLink;\n }\n\n const signout = () => {\n log('signing out!')\n setUser({})\n setIsSignedIn(false)\n setToken(null)\n document.cookie = `basic_token=; Secure; SameSite=Strict`;\n localStorage.removeItem('basic_auth_state')\n\n if (syncRef.current) {\n // WIP - BUG - sometimes connects even after signout\n syncRef.current.disconnect()\n }\n }\n\n const getToken = async (): Promise<string> => {\n log('getting token...')\n\n if (!token) {\n log('no token found')\n throw new Error('no token found')\n }\n\n const decoded = jwtDecode(token?.access_token)\n const isExpired = decoded.exp && decoded.exp < Date.now() / 1000\n\n if (isExpired) {\n log('token is expired - refreshing ...')\n const newToken = await fetchToken(token?.refresh)\n return newToken?.access_token || ''\n }\n\n return token?.access_token || ''\n }\n\n function getCookie(name: string) {\n let cookieValue = '';\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i].trim();\n if (cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n }\n\n const fetchToken = async (code: string) => {\n const token = await fetch('https://api.basic.tech/auth/token', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ code: code })\n })\n .then(response => response.json())\n .catch(error => log('Error:', error))\n\n if (token.error) {\n log('error fetching token', token.error)\n return\n } else {\n // log('token', token)\n setToken(token)\n }\n return token\n }\n\n useEffect(() => {\n localStorage.setItem('basic_debug', debug ? 'true' : 'false')\n\n try {\n if (window.location.search.includes('code')) {\n let code = window.location?.search?.split('code=')[1].split('&')[0]\n\n const state = localStorage.getItem('basic_auth_state')\n if (!state || state !== window.location.search.split('state=')[1].split('&')[0]) {\n log('error: auth state does not match')\n setIsAuthReady(true)\n\n localStorage.removeItem('basic_auth_state')\n window.history.pushState({}, document.title, \"/\");\n return\n }\n\n localStorage.removeItem('basic_auth_state')\n\n fetchToken(code) \n } else { \n let cookie_token = getCookie('basic_token')\n if (cookie_token !== '') {\n setToken(JSON.parse(cookie_token))\n } else { \n setIsAuthReady(true)\n }\n }\n\n\n } catch (e) {\n log('error getting cookie', e)\n }\n }, [])\n\n useEffect(() => {\n async function fetchUser(acc_token: string) {\n console.info('fetching user')\n const user = await fetch('https://api.basic.tech/auth/userInfo', {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${acc_token}`\n }\n })\n .then(response => response.json())\n .catch(error => log('Error:', error))\n\n if (user.error) {\n log('error fetching user', user.error)\n // refreshToken()\n return\n } else {\n // log('user', user)\n document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;\n \n if (window.location.search.includes('code')) {\n window.history.pushState({}, document.title, \"/\");\n }\n \n setUser(user)\n setIsSignedIn(true)\n\n setIsAuthReady(true)\n }\n }\n\n async function checkToken() {\n if (!token) {\n log('error: no user token found')\n\n setIsAuthReady(true)\n return\n }\n\n const decoded = jwtDecode(token?.access_token)\n const isExpired = decoded.exp && decoded.exp < Date.now() / 1000\n\n if (isExpired) {\n log('token is expired - refreshing ...')\n const newToken = await fetchToken(token?.refresh)\n fetchUser(newToken.access_token)\n } else {\n fetchUser(token.access_token)\n }\n }\n\n if (token) {\n checkToken()\n } \n }, [token])\n\n\n const db_ = (tableName: string) => {\n const checkSignIn = () => {\n if (!isSignedIn) {\n throw new Error('cannot use db. user not logged in.')\n }\n }\n\n return {\n get: async () => {\n checkSignIn()\n const tok = await getToken()\n return get({ projectId: project_id, accountId: user.id, tableName: tableName, token: tok })\n },\n add: async (value: any) => {\n checkSignIn()\n const tok = await getToken()\n return add({ projectId: project_id, accountId: user.id, tableName: tableName, value: value, token: tok })\n },\n update: async (id: string, value: any) => {\n checkSignIn()\n const tok = await getToken()\n return update({ projectId: project_id, accountId: user.id, tableName: tableName, id: id, value: value, token: tok })\n },\n delete: async (id: string) => {\n checkSignIn()\n const tok = await getToken()\n return deleteRecord({ projectId: project_id, accountId: user.id, tableName: tableName, id: id, token: tok })\n }\n\n }\n\n }\n\n return (\n <BasicContext.Provider value={{\n unicorn: \"🦄\",\n isAuthReady,\n isSignedIn,\n user,\n signout,\n signin,\n getToken,\n getSignInLink,\n db: syncRef.current,\n dbStatus\n }}>\n {error && <ErrorDisplay error={error} />}\n {syncRef.current ? children : null}\n </BasicContext.Provider>\n )\n}\n\nfunction ErrorDisplay({ error }: { error: ErrorObject }) {\n return <div style={{ \n position: 'absolute',\n top: 20, \n left: 20,\n color: 'black',\n backgroundColor: '#f8d7da',\n border: '1px solid #f5c6cb',\n borderRadius: '4px',\n padding: '20px',\n maxWidth: '400px',\n margin: '20px auto',\n boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',\n fontFamily: 'monospace', \n }}>\n <h3 style={{fontSize: '0.8rem', opacity: 0.8}}>code: {error.code}</h3>\n <h1 style={{fontSize: '1.2rem', lineHeight: '1.5'}}>{error.title}</h1>\n <p>{error.message}</p>\n </div>\n}\n\n/*\npossible errors: \n- projectid missing / invalid\n- schema missing / invalid\n*/\n\nexport function useBasic() {\n return useContext(BasicContext);\n}\n","\"use client\"\n\nimport { v7 as uuidv7 } from 'uuid';\nimport { Dexie, PromiseExtended } from 'dexie';\nimport 'dexie-syncable';\nimport 'dexie-observable';\n\nimport { syncProtocol } from './syncProtocol'\nimport { SERVER_URL, log } from '../config'\n\nimport { validateSchema, validateData } from '../schema'\nsyncProtocol()\n\n\n// const DexieSyncStatus = {\n// \"-1\": \"ERROR\",\n// \"0\": \"OFFLINE\",\n// \"1\": \"CONNECTING\",\n// \"2\": \"ONLINE\",\n// \"3\": \"SYNCING\",\n// \"4\": \"ERROR_WILL_RETRY\"\n// }\n\n\n\n\n\nexport class BasicSync extends Dexie {\n basic_schema: any\n\n constructor(name: string, options: any) {\n super(name, options);\n\n // --- INIT SCHEMA --- // \n\n //todo: handle versions?\n\n // TODO: validate schema\n this.basic_schema = options.schema\n this.version(1).stores(this._convertSchemaToDxSchema(this.basic_schema))\n\n this.version(2).stores({})\n // this.verssion\n\n\n // create an alias for toArray\n // @ts-ignore\n this.Collection.prototype.get = this.Collection.prototype.toArray\n\n\n // --- SYNC --- // \n\n // this.syncable.on(\"statusChanged\", (status, url) => { \n // console.log(\"statusChanged\", status, url)\n // })\n\n }\n\n async connect({ access_token }: { access_token: string }) {\n // const WS_URL = \"ws://localhost:3003/ws\"\n const WS_URL = `${SERVER_URL}/ws`\n\n \n // Update sync nodes\n await this.updateSyncNodes();\n \n // Proceed with the WebSocket connection\n \n log('Starting connection...')\n return this.syncable.connect(\"websocket\", WS_URL, { authToken: access_token });\n }\n\n async disconnect() {\n const WS_URL = `${SERVER_URL}/ws`\n\n return this.syncable.disconnect(WS_URL) \n }\n\n private async updateSyncNodes() {\n try {\n const syncNodes = await this.table('_syncNodes').toArray();\n const localSyncNodes = syncNodes.filter(node => node.type === 'local');\n log('Local sync nodes:', localSyncNodes);\n\n if (localSyncNodes.length > 1) {\n\n \n const largestNodeId = Math.max(...localSyncNodes.map(node => node.id));\n // Check if the largest node is already the master\n const largestNode = localSyncNodes.find(node => node.id === largestNodeId);\n if (largestNode && largestNode.isMaster === 1) {\n log('Largest node is already the master. No changes needed.');\n return; // Exit the function early as no changes are needed\n }\n\n\n log('Largest node id:', largestNodeId);\n log('HEISENBUG: More than one local sync node found.')\n\n for (const node of localSyncNodes) {\n log(`Local sync node keys:`, node.id, node.isMaster);\n await this.table('_syncNodes').update(node.id, { isMaster: node.id === largestNodeId ? 1 : 0 });\n\n log(`HEISENBUG: Setting ${node.id} to ${node.id === largestNodeId ? 'master' : '0'}`);\n }\n\n // Add a 1 second delay before returning // i dont think this helps?\n await new Promise(resolve => setTimeout(resolve, 2000));\n\n }\n\n log('Sync nodes updated');\n } catch (error) {\n console.error('Error updating _syncNodes table:', error);\n }\n }\n\n handleStatusChange(fn: any) {\n this.syncable.on(\"statusChanged\", fn)\n }\n\n\n _convertSchemaToDxSchema(schema: any) {\n const stores = Object.entries(schema.tables).map(([key, table]: any) => {\n\n const indexedFields = Object.entries(table.fields).filter(([key, field]: any) => field.indexed).map(([key, field]: any) => `,${key}`).join('')\n return {\n [key]: 'id' + indexedFields\n }\n })\n\n return Object.assign({}, ...stores)\n }\n\n debugeroo() {\n // console.log(\"debugeroo\", this.syncable)\n\n // this.syncable.list().then(x => console.log(x))\n\n // this.syncable\n return this.syncable\n }\n\n collection(name: string) {\n // TODO: check against schema\n\n return {\n\n /**\n * Returns the underlying Dexie table\n * @type {Dexie.Table}\n */\n ref: this.table(name),\n\n // --- WRITE ---- // \n add: (data: any) => {\n // log(\"Adding data to\", name, data)\n\n const valid = validateData(this.basic_schema, name, data)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).add({\n id: uuidv7(),\n ...data\n })\n\n },\n\n put: (data: any) => {\n const valid = validateData(this.basic_schema, name, data)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).put({\n id: uuidv7(),\n ...data\n })\n },\n\n update: (id: string, data: any) => {\n const valid = validateData(this.basic_schema, name, data, false)\n if (!valid.valid) {\n log('Invalid data', valid)\n return Promise.reject({ ... valid })\n }\n\n return this.table(name).update(id, data)\n },\n\n delete: (id: string) => {\n return this.table(name).delete(id)\n },\n\n\n // --- READ ---- // \n\n get: async (id: string) => {\n return this.table(name).get(id) \n },\n\n getAll: async () => {\n return this.table(name).toArray();\n },\n\n // --- QUERY ---- // \n // TODO: lots to do here. simplifing creating querie, filtering/ordering/limit, and execute\n\n query: () => this.table(name),\n\n filter: (fn: any) => this.table(name).filter(fn).toArray(),\n\n }\n }\n}\n\nclass QueryMethod { \n\n}\n","\"use client\"\nimport { Dexie } from \"dexie\";\nimport { log } from \"../config\";\n\nexport const syncProtocol = function () {\n log(\"Initializing syncProtocol\");\n // Constants:\n var RECONNECT_DELAY = 5000; // Reconnect delay in case of errors such as network down.\n\n Dexie.Syncable.registerSyncProtocol(\"websocket\", {\n sync: function (\n context,\n url,\n options,\n baseRevision,\n syncedRevision,\n changes,\n partial,\n applyRemoteChanges,\n onChangesAccepted,\n onSuccess,\n onError,\n ) {\n // The following vars are needed because we must know which callback to ack when server sends it's ack to us.\n var requestId = 0;\n var acceptCallbacks = {};\n\n // Connect the WebSocket to given url:\n var ws = new WebSocket(url);\n\n // console.log(\"ws OPTIONS\", options);\n\n // sendChanges() method:\n function sendChanges(changes, baseRevision, partial, onChangesAccepted) {\n log(\"sendChanges\", changes.length, baseRevision);\n ++requestId;\n acceptCallbacks[requestId.toString()] = onChangesAccepted;\n\n // In this example, the server expects the following JSON format of the request:\n // {\n // type: \"changes\"\n // baseRevision: baseRevision,\n // changes: changes,\n // partial: partial,\n // requestId: id\n // }\n // To make the sample simplified, we assume the server has the exact same specification of how changes are structured.\n // In real world, you would have to pre-process the changes array to fit the server specification.\n // However, this example shows how to deal with the WebSocket to fullfill the API.\n\n ws.send(\n JSON.stringify({\n type: \"changes\",\n changes: changes,\n partial: partial,\n baseRevision: baseRevision,\n requestId: requestId,\n }),\n );\n }\n\n\n\n // When WebSocket opens, send our changes to the server.\n ws.onopen = function (event) {\n // Initiate this socket connection by sending our clientIdentity. If we dont have a clientIdentity yet,\n // server will call back with a new client identity that we should use in future WebSocket connections.\n \n log(\"Opening socket - sending clientIdentity\", context.clientIdentity);\n ws.send(\n JSON.stringify({\n type: \"clientIdentity\",\n clientIdentity: context.clientIdentity || null,\n authToken: options.authToken\n }),\n );\n\n };\n\n // If network down or other error, tell the framework to reconnect again in some time:\n ws.onerror = function (event) {\n ws.close();\n log(\"ws.onerror\", event);\n onError(event?.message, RECONNECT_DELAY);\n };\n\n // If socket is closed (network disconnected), inform framework and make it reconnect\n ws.onclose = function (event) {\n // console.log('🙅 ws.onclose', event)\n onError(\"Socket closed: \" + event.reason, RECONNECT_DELAY);\n };\n\n // isFirstRound: Will need to call onSuccess() only when we are in sync the first time.\n // onSuccess() will unblock Dexie to be used by application code.\n // If for example app code writes: db.friends.where('shoeSize').above(40).toArray(callback), the execution of that query\n // will not run until we have called onSuccess(). This is because we want application code to get results that are as\n // accurate as possible. Specifically when connected the first time and the entire DB is being synced down to the browser,\n // it is important that queries starts running first when db is in sync.\n var isFirstRound = true;\n // When message arrive from the server, deal with the message accordingly:\n ws.onmessage = function (event) {\n try {\n // Assume we have a server that should send JSON messages of the following format:\n // {\n // type: \"clientIdentity\", \"changes\", \"ack\" or \"error\"\n // clientIdentity: unique value for our database client node to persist in the context. (Only applicable if type=\"clientIdentity\")\n // message: Error message (Only applicable if type=\"error\")\n // requestId: ID of change request that is acked by the server (Only applicable if type=\"ack\" or \"error\")\n // changes: changes from server (Only applicable if type=\"changes\")\n // lastRevision: last revision of changes sent (applicable if type=\"changes\")\n // partial: true if server has additionalChanges to send. False if these changes were the last known. (applicable if type=\"changes\")\n // }\n var requestFromServer = JSON.parse(event.data);\n log(\"requestFromServer\", requestFromServer, { acceptCallback, isFirstRound });\n\n if (requestFromServer.type == \"clientIdentity\") {\n context.clientIdentity = requestFromServer.clientIdentity;\n context.save();\n\n sendChanges(changes, baseRevision, partial, onChangesAccepted);\n\n ws.send(\n JSON.stringify({\n type: \"subscribe\",\n syncedRevision: syncedRevision,\n }),\n );\n } else if (requestFromServer.type == \"changes\") {\n applyRemoteChanges(\n requestFromServer.changes,\n requestFromServer.currentRevision,\n requestFromServer.partial,\n );\n if (isFirstRound && !requestFromServer.partial) {\n // Since this is the first sync round and server sais we've got all changes - now is the time to call onsuccess()\n onSuccess({\n // Specify a react function that will react on additional client changes\n react: function (\n changes,\n baseRevision,\n partial,\n onChangesAccepted,\n ) {\n sendChanges(\n changes,\n baseRevision,\n partial,\n onChangesAccepted,\n );\n },\n // Specify a disconnect function that will close our socket so that we dont continue to monitor changes.\n disconnect: function () {\n ws.close();\n },\n });\n isFirstRound = false;\n }\n } else if (requestFromServer.type == \"ack\") {\n var requestId = requestFromServer.requestId;\n var acceptCallback = acceptCallbacks[requestId.toString()];\n acceptCallback(); // Tell framework that server has acknowledged the changes sent.\n delete acceptCallbacks[requestId.toString()];\n } else if (requestFromServer.type == \"error\") {\n var requestId = requestFromServer.requestId;\n ws.close();\n onError(requestFromServer.message, Infinity); // Don't reconnect - an error in application level means we have done something wrong.\n } else {\n log(\"unknown message\", requestFromServer);\n ws.close();\n onError(\"unknown message\", Infinity);\n }\n } catch (e) {\n ws.close();\n onError(e, Infinity); // Something went crazy. Server sends invalid format or our code is buggy. Dont reconnect - it would continue failing.\n }\n };\n },\n });\n};\n","\nexport const SERVER_URL = \"https://api.basic.tech\"\n// export const SERVER_URL = \"http://localhost:3000\"\n\n\nexport const log = (...args: any[]) => {\n try { \n if (localStorage.getItem('basic_debug') === 'true') {\n console.log('[basic]', ...args)\n }\n } catch (e) {\n // console.log('error logging', e)\n }\n}\n\n// export const log = (message: string, ...args: any[]) => {\n// try {\n// if (process.env.NODE_ENV === 'development') {\n// const stack = new Error().stack;\n// const caller = stack?.split('\\n')[2]?.trim();\n// console.log(`[basic] ${message}`, ...args);\n// // console.log(`[stack] ${caller}`);\n// }\n// } catch (e) {\n// console.error('Error in logWithStack:', e);\n// }\n// }\n","// Basic Schema Library\n// utils for validating and interacting with Basic schemas\nimport Ajv, { ErrorObject } from 'ajv'\n\nconst basicJsonSchema = {\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"type\": \"object\",\n \"properties\": {\n \"project_id\": {\n \"type\": \"string\"\n },\n \"namespace\": {\n \"type\": \"string\",\n },\n \"version\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"tables\": {\n \"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9_]+$\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"collection\"]\n },\n \"fields\": {\n \"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9_]+$\": {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"string\", \"boolean\", \"number\", \"json\"]\n },\n \"indexed\": {\n \"type\": \"boolean\"\n }, \n \"required\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\"type\"]\n }\n },\n \"additionalProperties\": true\n }\n },\n \"required\": [\"fields\"]\n }\n },\n \"additionalProperties\": true\n }\n },\n \"required\": [\"project_id\", \"version\", \"tables\"]\n }\nconst ajv = new Ajv()\nconst validator = ajv.compile(basicJsonSchema)\n\ntype Schema = typeof basicJsonSchema\n\nfunction generateEmptySchema() {\n \n}\n\n\n/**\n * Validate a schema\n * only checks if the schema is formatted correctly, not if can be published\n * @param schema - The schema to validate\n * @returns {valid: boolean, errors: any[]} - The validation result\n */\nfunction validateSchema(schema: Schema) : {valid: boolean, errors: ErrorObject[]} {\n const v = validator(schema)\n return { \n valid: v,\n errors: validator.errors || []\n }\n}\n\n// type ErrorObject = {\n// keyword: string;\n// instancePath: string; \n// schemaPath: string;\n// params: Record<string, any>;\n// propertyName?: string;\n// message?: string;\n// schema?: any;\n// parentSchema?: any;\n// data?: any;\n// }\n\n\nfunction validateData(schema: any, table: string, data: Record<string, any>, checkRequired: boolean = true) {\n const valid = validateSchema(schema)\n if (!valid.valid) {\n return { valid: false, errors: valid.errors, message: \"Schema is invalid\" }\n }\n\n const tableSchema = schema.tables[table]\n\n if (!tableSchema) {\n return { valid: false, errors: [{ message: `Table ${table} not found in schema` }], message: \"Table not found\" }\n }\n\n for (const [fieldName, fieldValue] of Object.entries(data)) {\n const fieldSchema = tableSchema.fields[fieldName]\n \n if (!fieldSchema) {\n return { \n valid: false, \n errors: [{ message: `Field ${fieldName} not found in schema` }],\n message: \"Invalid field\"\n }\n }\n\n const schemaType = fieldSchema.type\n const valueType = typeof fieldValue\n\n if (\n (schemaType === 'string' && valueType !== 'string') ||\n (schemaType === 'number' && valueType !== 'number') ||\n (schemaType === 'boolean' && valueType !== 'boolean') ||\n (schemaType === 'json' && valueType !== 'object')\n ) {\n return {\n valid: false,\n errors: [{ \n message: `Field ${fieldName} should be type ${schemaType}, got ${valueType}` \n }],\n message: \"invalid type\"\n }\n }\n }\n\n if (checkRequired) {\n for (const [fieldName, fieldSchema] of Object.entries(tableSchema.fields)) {\n if ((fieldSchema as { required?: boolean }).required && !data[fieldName]) {\n return { valid: false, errors: [{ message: `Field ${fieldName} is required` }], message: \"Required field missing\" }\n }\n }\n }\n\n return { valid: true, errors: [] }\n}\n\n\nexport {\n validateSchema,\n validateData,\n generateEmptySchema\n}\n\n","//@ts-nocheck\n\nconst baseUrl = 'https://api.basic.tech';\n// const baseUrl = 'http://localhost:3000';\n\n\nasync function get({ projectId, accountId, tableName, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;\n const response = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${token}`\n }\n });\n return response.json();\n}\n\nasync function add({ projectId, accountId, tableName, value, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`\n },\n body: JSON.stringify({\"value\": value})\n });\n return response.json();\n}\n\nasync function update({ projectId, accountId, tableName, id, value, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;\n const response = await fetch(url, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`\n },\n body: JSON.stringify({id: id, value: value})\n });\n return response.json();\n}\n\nasync function deleteRecord({ projectId, accountId, tableName, id, token }) {\n const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;\n const response = await fetch(url, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${token}`\n }\n });\n return response.json();\n}\n\nexport { get, add, update, deleteRecord };\n\n","import { useState } from \"react\";\nimport { useBasic, BasicProvider } from \"./AuthContext\";\nimport { useLiveQuery as useQuery } from \"dexie-react-hooks\";\n\n// const useQuery = (queryable: any) => {\n// const [loading, setLoading] = useState(true)\n// const [error, setError] = useState<Error | null>(null)\n\n// const result = useLiveQuery(async () => {\n// try {\n// setLoading(true)\n// setError(null)\n \n// // if (typeof queryable === 'function') {\n// // return await queryable()\n// // }\n// return queryable\n \n// } catch (err) {\n// setError(err instanceof Error ? err : new Error('Unknown error'))\n// return undefined\n// } finally {\n// setLoading(false)\n// }\n// }, [queryable])\n\n// return {\n// data: result,\n// loading,\n// error\n// }\n// }\n\n\n\nexport {\n useBasic, BasicProvider, useQuery\n}\n"],"mappings":"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","names":["Dexie","changes","baseRevision","partial","onChangesAccepted","requestId","Dexie","key","validateSchema","validateSchema","error","baseUrl","token","user"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basictech/react",
3
- "version": "0.2.0-beta.9",
3
+ "version": "0.2.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -23,7 +23,8 @@
23
23
  "dexie-react-hooks": "^1.1.7",
24
24
  "dexie-syncable": "^4.0.1-beta.13",
25
25
  "jwt-decode": "^4.0.0",
26
- "uuid": "^10.0.0"
26
+ "uuid": "^10.0.0",
27
+ "@basictech/schema": "0.2.0"
27
28
  },
28
29
  "devDependencies": {
29
30
  "@repo/typescript-config": "*",
@@ -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 './schema'
8
+ import { validateSchema } from '@basictech/schema'
9
9
 
10
10
  import { log } from './config'
11
11
 
@@ -224,10 +224,10 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
224
224
  }
225
225
 
226
226
  useEffect(() => {
227
- if (token && syncRef.current) {
227
+ if (token && syncRef.current && isSignedIn && isSignedIn) {
228
228
  connectToDb()
229
229
  }
230
- }, [token])
230
+ }, [isSignedIn])
231
231
 
232
232
  const getSignInLink = () => {
233
233
  log('getting sign in link...')
@@ -259,6 +259,11 @@ export function BasicProvider({ children, project_id, schema, debug = false }: {
259
259
  setToken(null)
260
260
  document.cookie = `basic_token=; Secure; SameSite=Strict`;
261
261
  localStorage.removeItem('basic_auth_state')
262
+
263
+ if (syncRef.current) {
264
+ // WIP - BUG - sometimes connects even after signout
265
+ syncRef.current.disconnect()
266
+ }
262
267
  }
263
268
 
264
269
  const getToken = async (): Promise<string> => {
package/src/config.ts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  export const SERVER_URL = "https://api.basic.tech"
3
- // export const SERVER_URL = "http://localhost:3000"
3
+ // export const SERVER_URL = "http://localhost:3000"
4
4
 
5
5
 
6
6
  export const log = (...args: any[]) => {
package/src/index.ts CHANGED
@@ -1,24 +1,38 @@
1
+ import { useState } from "react";
1
2
  import { useBasic, BasicProvider } from "./AuthContext";
2
- import { useLiveQuery } from "dexie-react-hooks";
3
- import { validateSchema, validateData, generateEmptySchema } from "./schema";
3
+ import { useLiveQuery as useQuery } from "dexie-react-hooks";
4
4
 
5
+ // const useQuery = (queryable: any) => {
6
+ // const [loading, setLoading] = useState(true)
7
+ // const [error, setError] = useState<Error | null>(null)
5
8
 
6
- function useQuery(queryable: any) {
7
- return useLiveQuery(() => {
8
- if (typeof queryable === 'function') {
9
- return queryable();
10
- }
11
- return queryable;
12
- }, [queryable], []);
13
- }
9
+ // const result = useLiveQuery(async () => {
10
+ // try {
11
+ // setLoading(true)
12
+ // setError(null)
13
+
14
+ // // if (typeof queryable === 'function') {
15
+ // // return await queryable()
16
+ // // }
17
+ // return queryable
18
+
19
+ // } catch (err) {
20
+ // setError(err instanceof Error ? err : new Error('Unknown error'))
21
+ // return undefined
22
+ // } finally {
23
+ // setLoading(false)
24
+ // }
25
+ // }, [queryable])
26
+
27
+ // return {
28
+ // data: result,
29
+ // loading,
30
+ // error
31
+ // }
32
+ // }
14
33
 
15
34
 
16
- const sc = {
17
- validateSchema: validateSchema,
18
- validateData: validateData,
19
- generateEmptySchema: generateEmptySchema
20
- }
21
35
 
22
36
  export {
23
- useBasic, BasicProvider, useQuery, sc
37
+ useBasic, BasicProvider, useQuery
24
38
  }
package/src/sync/index.ts CHANGED
@@ -70,6 +70,12 @@ export class BasicSync extends Dexie {
70
70
  return this.syncable.connect("websocket", WS_URL, { authToken: access_token });
71
71
  }
72
72
 
73
+ async disconnect() {
74
+ const WS_URL = `${SERVER_URL}/ws`
75
+
76
+ return this.syncable.disconnect(WS_URL)
77
+ }
78
+
73
79
  private async updateSyncNodes() {
74
80
  try {
75
81
  const syncNodes = await this.table('_syncNodes').toArray();