@basictech/react 0.7.0-beta.0 → 0.7.0-beta.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 +1 @@
1
- {"version":3,"sources":["../src/AuthContext.tsx","../src/sync/index.ts","../src/sync/syncProtocol.js","../src/config.ts","../src/db.ts","../package.json","../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, compareSchemas } from '@basictech/schema'\n\nimport { log } from './config'\nimport {version as currentVersion} from '../package.json'\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\nasync function getSchemaStatus(schema: any) {\n const projectId = schema.project_id\n let status = ''\n const valid = validateSchema(schema)\n\n if (!valid.valid) {\n console.warn('BasicDB Error: your local schema is invalid. Please fix errors and try again - sync is disabled')\n return { \n valid: false, \n status: 'invalid',\n latest: null\n }\n }\n\n const latestSchema = await fetch(`https://api.basic.tech/project/${projectId}/schema`)\n .then(res => res.json())\n .then(data => data.data[0].schema)\n .catch(err => {\n return { \n valid: false, \n status: 'error',\n latest: null\n }\n })\n\n console.log('latestSchema', latestSchema)\n\n if (!latestSchema.version) {\n return { \n valid: false, \n status: 'error',\n latest: null\n }\n }\n\n if (latestSchema.version > schema.version) {\n // error_code: schema_behind\n console.warn('BasicDB Error: your local schema version is behind the latest. Found version:', schema.version, 'but expected', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'behind', \n latest: latestSchema\n }\n } else if (latestSchema.version < schema.version) {\n // error_code: schema_ahead\n console.warn('BasicDB Error: your local schema version is ahead of the latest. Found version:', schema.version, 'but expected', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'ahead', \n latest: latestSchema\n }\n } else if (latestSchema.version === schema.version) {\n const changes = compareSchemas(schema, latestSchema)\n if (changes.valid) {\n return { \n valid: true,\n status: 'current',\n latest: latestSchema\n }\n } else {\n // error_code: schema_conflict\n console.warn('BasicDB Error: your local schema is conflicting with the latest. Your version:', schema.version, 'does not match origin version', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'conflict',\n latest: latestSchema\n }\n }\n } else { \n return { \n valid: false, \n status: 'error',\n latest: null\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\nasync function checkForNewVersion(): Promise<{ hasNewVersion: boolean, latestVersion: string | null, currentVersion: string | null }> {\n try {\n\n const isBeta = currentVersion.includes('beta')\n\n const response = await fetch(`https://registry.npmjs.org/@basictech/react/${isBeta ? 'beta' : 'latest'}`);\n if (!response.ok) {\n throw new Error('Failed to fetch version from npm');\n }\n\n const data = await response.json();\n const latestVersion = data.version;\n\n if (latestVersion !== currentVersion) {\n console.warn('[basic] New version available:', latestVersion, `\\nrun \"npm install @basictech/react@${latestVersion}\" to update`);\n }\n if (isBeta) {\n log('thank you for being on basictech/react beta :)')\n }\n \n return {\n hasNewVersion: currentVersion !== latestVersion,\n latestVersion,\n currentVersion\n };\n } catch (error) {\n log('Error checking for new version:', error);\n return {\n hasNewVersion: false,\n latestVersion: null, \n currentVersion: null\n };\n }\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 const [shouldConnect, setShouldConnect] = useState<boolean>(false)\n const [isReady, setIsReady] = useState<boolean>(false)\n\n const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.OFFLINE)\n const [error, setError] = useState<ErrorObject | null>(null)\n\n const syncRef = useRef<BasicSync | null>(null);\n\n useEffect(() => {\n function initDb(options: { shouldConnect: boolean }) {\n if (!syncRef.current) {\n log('Initializing Basic DB')\n syncRef.current = new BasicSync('basicdb', { schema: schema });\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\n if (options.shouldConnect) { \n setShouldConnect(true)\n } else { \n log('Sync is disabled')\n }\n\n setIsReady(true)\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 async function checkSchema() {\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 setIsReady(true)\n return null\n }\n\n\n let schemaStatus = { valid: false }\n if (schema.version !== 0) {\n schemaStatus = await getSchemaStatus(schema)\n log('schemaStatus', schemaStatus)\n }else { \n log(\"schema not published - at version 0\")\n }\n\n if (schemaStatus.valid) {\n initDb({ shouldConnect: true })\n } else {\n log('Schema is invalid!', schemaStatus)\n initDb({ shouldConnect: false })\n }\n \n checkForNewVersion()\n }\n\n if (schema) {\n checkSchema()\n } else {\n setIsReady(true)\n }\n }, []);\n\n\n useEffect(() => {\n if (token && syncRef.current && isSignedIn && shouldConnect) {\n connectToDb()\n }\n }, [isSignedIn, shouldConnect])\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 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 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=profile`\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 if (syncRef.current) {\n (async () => {\n try {\n await syncRef.current.close()\n await syncRef.current.delete({disableAutoOpen: false})\n syncRef.current = null\n window?.location?.reload()\n } catch (error) {\n console.error('Error during database cleanup:', error)\n }\n })()\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\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 const noDb = ({ \n collection: () => {\n throw new Error('no basicdb found - initialization failed. double check your schema.')\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 ? syncRef.current : noDb,\n dbStatus\n }}>\n \n {error && <ErrorDisplay error={error} />}\n {isReady && children}\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 { log } from '../config'\n\nimport { validateSchema, validateData } from '@basictech/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// const SERVER_URL = \"https://pds.basic.id\"\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 = `wss://pds.basic.id/ws`\n\n log('Connecting to', WS_URL)\n\n await this.updateSyncNodes();\n \n log('Starting connection...')\n return this.syncable.connect(\"websocket\", WS_URL, { authToken: access_token, schema: this.basic_schema });\n }\n\n async disconnect() {\n const WS_URL = `wss://pds.basic.id/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 delay to ensure sync nodes are updated // i dont think this helps?\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n if (typeof window !== 'undefined') {\n window.location.reload();\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 log(\"Connecting to\", 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 // send the schema to the server\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 schema: options.schema\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 log(\"caught error\", e)\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:3003\"\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","//@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","{\n \"name\": \"@basictech/react\",\n \"version\": \"0.6.0\",\n \"description\": \"\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"private\": false,\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n },\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n \"ajv\": \"^8.17.1\",\n \"dexie\": \"^4.0.8\",\n \"dexie-observable\": \"^4.0.1-beta.13\",\n \"dexie-react-hooks\": \"^1.1.7\",\n \"dexie-syncable\": \"^4.0.1-beta.13\",\n \"jwt-decode\": \"^4.0.0\",\n \"uuid\": \"^10.0.0\",\n \"@basictech/schema\": \"0.6.0\"\n },\n \"devDependencies\": {\n \"@repo/typescript-config\": \"*\",\n \"tsup\": \"^7.2.0\",\n \"typescript\": \"^5.0.0\"\n },\n \"peerDependencies\": {\n \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n }\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":";AAEA,SAAgB,eAAe,YAAY,WAAW,UAAU,cAAc;AAC9E,SAAS,iBAAiB;;;ACD1B,SAAS,MAAM,cAAc;AAC7B,SAAS,SAAAA,cAA8B;AACvC,OAAO;AACP,OAAO;;;ACJP,SAAS,aAAa;;;ACIf,IAAM,MAAM,IAAI,SAAgB;AACnC,MAAI;AACA,QAAI,aAAa,QAAQ,aAAa,MAAM,QAAQ;AAChD,cAAQ,IAAI,WAAW,GAAG,IAAI;AAAA,IAClC;AAAA,EACJ,SAAS,GAAG;AAAA,EAEZ;AACJ;;;ADTO,IAAM,eAAe,WAAY;AACtC,MAAI,2BAA2B;AAE/B,MAAI,kBAAkB;AAEtB,QAAM,SAAS,qBAAqB,aAAa;AAAA,IAC/C,MAAM,SACJ,SACA,KACA,SACA,cACA,gBACA,SACA,SACA,oBACA,mBACA,WACA,SACA;AAEA,UAAI,YAAY;AAChB,UAAI,kBAAkB,CAAC;AAGvB,UAAI,iBAAiB,GAAG;AACxB,UAAI,KAAK,IAAI,UAAU,GAAG;AAK1B,eAAS,YAAYC,UAASC,eAAcC,UAASC,oBAAmB;AACtE,YAAI,eAAeH,SAAQ,QAAQC,aAAY;AAC/C,UAAE;AACF,wBAAgB,UAAU,SAAS,CAAC,IAAIE;AAcxC,WAAG;AAAA,UACD,KAAK,UAAU;AAAA,YACb,MAAM;AAAA,YACN,SAASH;AAAA,YACT,SAASE;AAAA,YACT,cAAcD;AAAA,YACd;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAKA,SAAG,SAAS,SAAU,OAAO;AAK3B,YAAI,2CAA2C,QAAQ,cAAc;AACrE,WAAG;AAAA,UACD,KAAK,UAAU;AAAA,YACb,MAAM;AAAA,YACN,gBAAgB,QAAQ,kBAAkB;AAAA,YAC1C,WAAW,QAAQ;AAAA,YACnB,QAAQ,QAAQ;AAAA,UAClB,CAAC;AAAA,QACH;AAAA,MAEF;AAGA,SAAG,UAAU,SAAU,OAAO;AAC5B,WAAG,MAAM;AACT,YAAI,cAAc,KAAK;AACvB,gBAAQ,OAAO,SAAS,eAAe;AAAA,MACzC;AAGA,SAAG,UAAU,SAAU,OAAO;AAE5B,gBAAQ,oBAAoB,MAAM,QAAQ,eAAe;AAAA,MAC3D;AAQA,UAAI,eAAe;AAEnB,SAAG,YAAY,SAAU,OAAO;AAC9B,YAAI;AAWF,cAAI,oBAAoB,KAAK,MAAM,MAAM,IAAI;AAC7C,cAAI,qBAAqB,mBAAmB,EAAE,gBAAgB,aAAa,CAAC;AAE5E,cAAI,kBAAkB,QAAQ,kBAAkB;AAC9C,oBAAQ,iBAAiB,kBAAkB;AAC3C,oBAAQ,KAAK;AAEb,wBAAY,SAAS,cAAc,SAAS,iBAAiB;AAE7D,eAAG;AAAA,cACD,KAAK,UAAU;AAAA,gBACb,MAAM;AAAA,gBACN;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF,WAAW,kBAAkB,QAAQ,WAAW;AAC9C;AAAA,cACE,kBAAkB;AAAA,cAClB,kBAAkB;AAAA,cAClB,kBAAkB;AAAA,YACpB;AACA,gBAAI,gBAAgB,CAAC,kBAAkB,SAAS;AAE9C,wBAAU;AAAA;AAAA,gBAER,OAAO,SACLD,UACAC,eACAC,UACAC,oBACA;AACA;AAAA,oBACEH;AAAA,oBACAC;AAAA,oBACAC;AAAA,oBACAC;AAAA,kBACF;AAAA,gBACF;AAAA;AAAA,gBAEA,YAAY,WAAY;AACtB,qBAAG,MAAM;AAAA,gBACX;AAAA,cACF,CAAC;AACD,6BAAe;AAAA,YACjB;AAAA,UACF,WAAW,kBAAkB,QAAQ,OAAO;AAC1C,gBAAIC,aAAY,kBAAkB;AAClC,gBAAI,iBAAiB,gBAAgBA,WAAU,SAAS,CAAC;AACzD,2BAAe;AACf,mBAAO,gBAAgBA,WAAU,SAAS,CAAC;AAAA,UAC7C,WAAW,kBAAkB,QAAQ,SAAS;AAC5C,gBAAIA,aAAY,kBAAkB;AAClC,eAAG,MAAM;AACT,oBAAQ,kBAAkB,SAAS,QAAQ;AAAA,UAC7C,OAAO;AACL,gBAAI,mBAAmB,iBAAiB;AACxC,eAAG,MAAM;AACT,oBAAQ,mBAAmB,QAAQ;AAAA,UACrC;AAAA,QACF,SAAS,GAAG;AACV,aAAG,MAAM;AACT,cAAI,gBAAgB,CAAC;AACrB,kBAAQ,GAAG,QAAQ;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AD5KA,SAAyB,oBAAoB;AAC7C,aAAa;AAgBN,IAAM,YAAN,cAAwBC,OAAM;AAAA,EACnC;AAAA,EAEA,YAAY,MAAc,SAAc;AACtC,UAAM,MAAM,OAAO;AAOnB,SAAK,eAAe,QAAQ;AAC5B,SAAK,QAAQ,CAAC,EAAE,OAAO,KAAK,yBAAyB,KAAK,YAAY,CAAC;AAEvE,SAAK,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;AAMzB,SAAK,WAAW,UAAU,MAAM,KAAK,WAAW,UAAU;AAAA,EAS5D;AAAA,EAEA,MAAM,QAAQ,EAAE,aAAa,GAA6B;AACxD,UAAM,SAAS;AAEf,QAAI,iBAAiB,MAAM;AAE3B,UAAM,KAAK,gBAAgB;AAE3B,QAAI,wBAAwB;AAC5B,WAAO,KAAK,SAAS,QAAQ,aAAa,QAAQ,EAAE,WAAW,cAAc,QAAQ,KAAK,aAAa,CAAC;AAAA,EAC1G;AAAA,EAEA,MAAM,aAAa;AACjB,UAAM,SAAS;AAEf,WAAO,KAAK,SAAS,WAAW,MAAM;AAAA,EACxC;AAAA,EAEA,MAAc,kBAAkB;AAC9B,QAAI;AACF,YAAM,YAAY,MAAM,KAAK,MAAM,YAAY,EAAE,QAAQ;AACzD,YAAM,iBAAiB,UAAU,OAAO,UAAQ,KAAK,SAAS,OAAO;AACrE,UAAI,qBAAqB,cAAc;AAEvC,UAAI,eAAe,SAAS,GAAG;AAG7B,cAAM,gBAAgB,KAAK,IAAI,GAAG,eAAe,IAAI,UAAQ,KAAK,EAAE,CAAC;AAErE,cAAM,cAAc,eAAe,KAAK,UAAQ,KAAK,OAAO,aAAa;AACzE,YAAI,eAAe,YAAY,aAAa,GAAG;AAC7C,cAAI,wDAAwD;AAC5D;AAAA,QACF;AAGA,YAAI,oBAAoB,aAAa;AACrC,YAAI,iDAAiD;AAErD,mBAAW,QAAQ,gBAAgB;AACjC,cAAI,yBAAyB,KAAK,IAAI,KAAK,QAAQ;AACnD,gBAAM,KAAK,MAAM,YAAY,EAAE,OAAO,KAAK,IAAI,EAAE,UAAU,KAAK,OAAO,gBAAgB,IAAI,EAAE,CAAC;AAE9F,cAAI,sBAAsB,KAAK,EAAE,OAAO,KAAK,OAAO,gBAAgB,WAAW,GAAG,EAAE;AAAA,QACtF;AAGA,cAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAI,CAAC;AAEtD,YAAI,OAAO,WAAW,aAAa;AACjC,iBAAO,SAAS,OAAO;AAAA,QACzB;AAAA,MACF;AAEA,UAAI,oBAAoB;AAAA,IAC1B,SAAS,OAAO;AACd,cAAQ,MAAM,oCAAoC,KAAK;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,mBAAmB,IAAS;AAC1B,SAAK,SAAS,GAAG,iBAAiB,EAAE;AAAA,EACtC;AAAA,EAGA,yBAAyB,QAAa;AACpC,UAAM,SAAS,OAAO,QAAQ,OAAO,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAW;AAEtE,YAAM,gBAAgB,OAAO,QAAQ,MAAM,MAAM,EAAE,OAAO,CAAC,CAACC,MAAK,KAAK,MAAW,MAAM,OAAO,EAAE,IAAI,CAAC,CAACA,MAAK,KAAK,MAAW,IAAIA,IAAG,EAAE,EAAE,KAAK,EAAE;AAC7I,aAAO;AAAA,QACL,CAAC,GAAG,GAAG,OAAO;AAAA,MAChB;AAAA,IACF,CAAC;AAED,WAAO,OAAO,OAAO,CAAC,GAAG,GAAG,MAAM;AAAA,EACpC;AAAA,EAEA,YAAY;AAMV,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAW,MAAc;AAGvB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA,MAML,KAAK,KAAK,MAAM,IAAI;AAAA;AAAA,MAGpB,KAAK,CAAC,SAAc;AAGlB,cAAM,QAAQ,aAAa,KAAK,cAAc,MAAM,IAAI;AACxD,YAAI,CAAC,MAAM,OAAO;AAChB,cAAI,gBAAgB,KAAK;AACzB,iBAAO,QAAQ,OAAO,EAAE,GAAI,MAAM,CAAC;AAAA,QACrC;AAEA,eAAO,KAAK,MAAM,IAAI,EAAE,IAAI;AAAA,UAC1B,IAAI,OAAO;AAAA,UACX,GAAG;AAAA,QACL,CAAC;AAAA,MAEH;AAAA,MAEA,KAAK,CAAC,SAAc;AAClB,cAAM,QAAQ,aAAa,KAAK,cAAc,MAAM,IAAI;AACxD,YAAI,CAAC,MAAM,OAAO;AAChB,cAAI,gBAAgB,KAAK;AACzB,iBAAO,QAAQ,OAAO,EAAE,GAAI,MAAM,CAAC;AAAA,QACrC;AAEA,eAAO,KAAK,MAAM,IAAI,EAAE,IAAI;AAAA,UAC1B,IAAI,OAAO;AAAA,UACX,GAAG;AAAA,QACL,CAAC;AAAA,MACH;AAAA,MAEA,QAAQ,CAAC,IAAY,SAAc;AACjC,cAAM,QAAQ,aAAa,KAAK,cAAc,MAAM,MAAM,KAAK;AAC/D,YAAI,CAAC,MAAM,OAAO;AAChB,cAAI,gBAAgB,KAAK;AACzB,iBAAO,QAAQ,OAAO,EAAE,GAAI,MAAM,CAAC;AAAA,QACrC;AAEA,eAAO,KAAK,MAAM,IAAI,EAAE,OAAO,IAAI,IAAI;AAAA,MACzC;AAAA,MAEA,QAAQ,CAAC,OAAe;AACtB,eAAO,KAAK,MAAM,IAAI,EAAE,OAAO,EAAE;AAAA,MACnC;AAAA;AAAA,MAKA,KAAK,OAAO,OAAe;AACzB,eAAO,KAAK,MAAM,IAAI,EAAE,IAAI,EAAE;AAAA,MAChC;AAAA,MAEA,QAAQ,YAAY;AAClB,eAAO,KAAK,MAAM,IAAI,EAAE,QAAQ;AAAA,MAClC;AAAA;AAAA;AAAA,MAKA,OAAO,MAAM,KAAK,MAAM,IAAI;AAAA,MAE5B,QAAQ,CAAC,OAAY,KAAK,MAAM,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ;AAAA,IAE3D;AAAA,EACF;AACF;;;AGxNA,IAAM,UAAU;AAIhB,eAAe,IAAI,EAAE,WAAW,WAAW,WAAW,MAAM,GAAG;AAC3D,QAAM,MAAM,GAAG,OAAO,YAAY,SAAS,OAAO,SAAS,IAAI,SAAS;AACxE,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAC9B,SAAS;AAAA,MACL,iBAAiB,UAAU,KAAK;AAAA,IACpC;AAAA,EACJ,CAAC;AACD,SAAO,SAAS,KAAK;AACzB;AAEA,eAAe,IAAI,EAAE,WAAW,WAAW,WAAW,OAAO,MAAM,GAAG;AAClE,QAAM,MAAM,GAAG,OAAO,YAAY,SAAS,OAAO,SAAS,IAAI,SAAS;AACxE,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAC9B,QAAQ;AAAA,IACR,SAAS;AAAA,MACL,gBAAgB;AAAA,MAChB,iBAAiB,UAAU,KAAK;AAAA,IACpC;AAAA,IACA,MAAM,KAAK,UAAU,EAAC,SAAS,MAAK,CAAC;AAAA,EACzC,CAAC;AACD,SAAO,SAAS,KAAK;AACzB;AAEA,eAAe,OAAO,EAAE,WAAW,WAAW,WAAW,IAAI,OAAO,MAAM,GAAG;AACzE,QAAM,MAAM,GAAG,OAAO,YAAY,SAAS,OAAO,SAAS,IAAI,SAAS,IAAI,EAAE;AAC9E,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAC9B,QAAQ;AAAA,IACR,SAAS;AAAA,MACL,gBAAgB;AAAA,MAChB,iBAAiB,UAAU,KAAK;AAAA,IACpC;AAAA,IACA,MAAM,KAAK,UAAU,EAAC,IAAQ,MAAY,CAAC;AAAA,EAC/C,CAAC;AACD,SAAO,SAAS,KAAK;AACzB;AAEA,eAAe,aAAa,EAAE,WAAW,WAAW,WAAW,IAAI,MAAM,GAAG;AACxE,QAAM,MAAM,GAAG,OAAO,YAAY,SAAS,OAAO,SAAS,IAAI,SAAS,IAAI,EAAE;AAC9E,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAC9B,QAAQ;AAAA,IACR,SAAS;AAAA,MACL,iBAAiB,UAAU,KAAK;AAAA,IACpC;AAAA,EACJ,CAAC;AACD,SAAO,SAAS,KAAK;AACzB;;;AJ5CA,SAAS,kBAAAC,iBAAgB,sBAAsB;;;AKL7C,cAAW;;;AL+jBL,SAac,KAbd;AA9gBD,IAAM,eAAe,cAWzB;AAAA,EACC,SAAS;AAAA,EACT,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,SAAS,MAAM;AAAA,EAAE;AAAA,EACjB,QAAQ,MAAM;AAAA,EAAE;AAAA,EAChB,UAAU,MAAM,IAAI,QAAQ,MAAM;AAAA,EAAE,CAAC;AAAA,EACrC,eAAe,MAAM;AAAA,EACrB,IAAI,CAAC;AAAA,EACL,UAAU;AACd,CAAC;AAcD,eAAe,gBAAgB,QAAa;AACxC,QAAM,YAAY,OAAO;AACzB,MAAI,SAAS;AACb,QAAM,QAAQC,gBAAe,MAAM;AAEnC,MAAI,CAAC,MAAM,OAAO;AACd,YAAQ,KAAK,iGAAiG;AAC9G,WAAO;AAAA,MACH,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACZ;AAAA,EACJ;AAEA,QAAM,eAAe,MAAM,MAAM,kCAAkC,SAAS,SAAS,EACpF,KAAK,SAAO,IAAI,KAAK,CAAC,EACtB,KAAK,UAAQ,KAAK,KAAK,CAAC,EAAE,MAAM,EAChC,MAAM,SAAO;AACV,WAAO;AAAA,MACH,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACZ;AAAA,EACJ,CAAC;AAED,UAAQ,IAAI,gBAAgB,YAAY;AAExC,MAAI,CAAC,aAAa,SAAS;AACvB,WAAO;AAAA,MACH,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACZ;AAAA,EACJ;AAEA,MAAI,aAAa,UAAU,OAAO,SAAS;AAEvC,YAAQ,KAAK,iFAAiF,OAAO,SAAS,gBAAgB,aAAa,SAAS,qBAAqB;AACzK,WAAO;AAAA,MACH,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACZ;AAAA,EACJ,WAAW,aAAa,UAAU,OAAO,SAAS;AAE9C,YAAQ,KAAK,mFAAmF,OAAO,SAAS,gBAAgB,aAAa,SAAS,qBAAqB;AAC3K,WAAO;AAAA,MACH,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACZ;AAAA,EACJ,WAAW,aAAa,YAAY,OAAO,SAAS;AAChD,UAAM,UAAU,eAAe,QAAQ,YAAY;AACnD,QAAI,QAAQ,OAAO;AACf,aAAO;AAAA,QACH,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,MACZ;AAAA,IACJ,OAAO;AAEH,cAAQ,KAAK,kFAAkF,OAAO,SAAS,iCAAiC,aAAa,SAAS,qBAAqB;AAC3L,aAAO;AAAA,QACH,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,MACZ;AAAA,IACJ;AAAA,EACJ,OAAO;AACH,WAAO;AAAA,MACH,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACZ;AAAA,EACJ;AACJ;AAGA,SAAS,cAAc,YAA4B;AAC/C,UAAQ,YAAY;AAAA,IAChB,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EACf;AACJ;AAQA,eAAe,qBAAuH;AAClI,MAAI;AAEA,UAAM,SAAS,QAAe,SAAS,MAAM;AAE7C,UAAM,WAAW,MAAM,MAAM,+CAA+C,SAAS,SAAS,QAAQ,EAAE;AACxG,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACtD;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,gBAAgB,KAAK;AAE3B,QAAI,kBAAkB,SAAgB;AAClC,cAAQ,KAAK,kCAAkC,eAAe;AAAA,oCAAuC,aAAa,aAAa;AAAA,IACnI;AACA,QAAI,QAAQ;AACR,UAAI,gDAAgD;AAAA,IACxD;AAEA,WAAO;AAAA,MACH,eAAe,YAAmB;AAAA,MAClC;AAAA,MACA;AAAA,IACJ;AAAA,EACJ,SAAS,OAAO;AACZ,QAAI,mCAAmC,KAAK;AAC5C,WAAO;AAAA,MACH,eAAe;AAAA,MACf,eAAe;AAAA,MACf,gBAAgB;AAAA,IACpB;AAAA,EACJ;AACJ;AAEO,SAAS,cAAc,EAAE,UAAU,YAAY,QAAQ,QAAQ,MAAM,GAAsF;AAC9J,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AACpD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAkB,KAAK;AAC3D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,IAAI;AACrD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAe,CAAC,CAAC;AACzC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAkB,KAAK;AACjE,QAAM,CAAC,SAAS,UAAU,IAAI,SAAkB,KAAK;AAErD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAmB,uBAAgB;AACnE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA6B,IAAI;AAE3D,QAAM,UAAU,OAAyB,IAAI;AAE7C,YAAU,MAAM;AACZ,aAAS,OAAO,SAAqC;AACjD,UAAI,CAAC,QAAQ,SAAS;AAClB,YAAI,uBAAuB;AAC3B,gBAAQ,UAAU,IAAI,UAAU,WAAW,EAAE,OAAe,CAAC;AAE7D,gBAAQ,QAAQ,SAAS,GAAG,iBAAiB,CAAC,QAAgB,QAAgB;AAC1E,sBAAY,cAAc,MAAM,CAAC;AAAA,QACrC,CAAC;AAED,gBAAQ,QAAQ,SAAS,UAAU,EAAE,KAAK,CAAC,WAAW;AAClD,sBAAY,cAAc,MAAM,CAAC;AAAA,QACrC,CAAC;AAED,YAAI,QAAQ,eAAe;AACvB,2BAAiB,IAAI;AAAA,QACzB,OAAO;AACH,cAAI,kBAAkB;AAAA,QAC1B;AAEA,mBAAW,IAAI;AAAA,MAOnB;AAAA,IACJ;AAEA,mBAAe,cAAc;AACzB,YAAM,QAAQA,gBAAe,MAAM;AACnC,UAAI,CAAC,MAAM,OAAO;AACd,YAAI,4BAA4B,MAAM,MAAM;AAC5C,gBAAQ,MAAM,eAAe;AAC7B,YAAI,eAAe;AACnB,cAAM,OAAO,QAAQ,CAACC,QAAO,UAAU;AACnC,cAAI,GAAG,QAAQ,CAAC,KAAKA,OAAM,SAAS,SAASA,OAAM,YAAY,EAAE;AACjE,0BAAgB,GAAG,QAAQ,CAAC,KAAKA,OAAM,OAAO,SAASA,OAAM,YAAY;AAAA;AAAA,QAC7E,CAAC;AACD,gBAAQ,SAAS,eAAe;AAChC,iBAAS;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,UACP,SAAS;AAAA,QACb,CAAC;AACD,mBAAW,IAAI;AACf,eAAO;AAAA,MACX;AAGA,UAAI,eAAe,EAAE,OAAO,MAAM;AAClC,UAAI,OAAO,YAAY,GAAG;AACtB,uBAAe,MAAM,gBAAgB,MAAM;AAC3C,YAAI,gBAAgB,YAAY;AAAA,MACpC,OAAM;AACF,YAAI,qCAAqC;AAAA,MAC7C;AAEA,UAAI,aAAa,OAAO;AACpB,eAAO,EAAE,eAAe,KAAK,CAAC;AAAA,MAClC,OAAO;AACH,YAAI,sBAAsB,YAAY;AACtC,eAAO,EAAE,eAAe,MAAM,CAAC;AAAA,MACnC;AAEA,yBAAmB;AAAA,IACvB;AAEA,QAAI,QAAQ;AACR,kBAAY;AAAA,IAChB,OAAO;AACH,iBAAW,IAAI;AAAA,IACnB;AAAA,EACJ,GAAG,CAAC,CAAC;AAGL,YAAU,MAAM;AACZ,QAAI,SAAS,QAAQ,WAAW,cAAc,eAAe;AACzD,kBAAY;AAAA,IAChB;AAAA,EACJ,GAAG,CAAC,YAAY,aAAa,CAAC;AAE9B,YAAU,MAAM;AACZ,iBAAa,QAAQ,eAAe,QAAQ,SAAS,OAAO;AAE5D,QAAI;AACA,UAAI,OAAO,SAAS,OAAO,SAAS,MAAM,GAAG;AACzC,YAAI,OAAO,OAAO,UAAU,QAAQ,MAAM,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC;AAElE,cAAM,QAAQ,aAAa,QAAQ,kBAAkB;AACrD,YAAI,CAAC,SAAS,UAAU,OAAO,SAAS,OAAO,MAAM,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG;AAC7E,cAAI,kCAAkC;AACtC,yBAAe,IAAI;AAEnB,uBAAa,WAAW,kBAAkB;AAC1C,iBAAO,QAAQ,UAAU,CAAC,GAAG,SAAS,OAAO,GAAG;AAChD;AAAA,QACJ;AAEA,qBAAa,WAAW,kBAAkB;AAE1C,mBAAW,IAAI;AAAA,MACnB,OAAO;AACH,YAAI,eAAe,UAAU,aAAa;AAC1C,YAAI,iBAAiB,IAAI;AACrB,mBAAS,KAAK,MAAM,YAAY,CAAC;AAAA,QACrC,OAAO;AACH,yBAAe,IAAI;AAAA,QACvB;AAAA,MACJ;AAAA,IAGJ,SAAS,GAAG;AACR,UAAI,wBAAwB,CAAC;AAAA,IACjC;AAAA,EACJ,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACZ,mBAAe,UAAU,WAAmB;AACxC,cAAQ,KAAK,eAAe;AAC5B,YAAMC,QAAO,MAAM,MAAM,wCAAwC;AAAA,QAC7D,QAAQ;AAAA,QACR,SAAS;AAAA,UACL,iBAAiB,UAAU,SAAS;AAAA,QACxC;AAAA,MACJ,CAAC,EACI,KAAK,cAAY,SAAS,KAAK,CAAC,EAChC,MAAM,CAAAD,WAAS,IAAI,UAAUA,MAAK,CAAC;AAExC,UAAIC,MAAK,OAAO;AACZ,YAAI,uBAAuBA,MAAK,KAAK;AAErC;AAAA,MACJ,OAAO;AAEH,iBAAS,SAAS,eAAe,KAAK,UAAU,KAAK,CAAC;AAEtD,YAAI,OAAO,SAAS,OAAO,SAAS,MAAM,GAAG;AACzC,iBAAO,QAAQ,UAAU,CAAC,GAAG,SAAS,OAAO,GAAG;AAAA,QACpD;AAEA,gBAAQA,KAAI;AACZ,sBAAc,IAAI;AAElB,uBAAe,IAAI;AAAA,MACvB;AAAA,IACJ;AAEA,mBAAe,aAAa;AACxB,UAAI,CAAC,OAAO;AACR,YAAI,4BAA4B;AAEhC,uBAAe,IAAI;AACnB;AAAA,MACJ;AAEA,YAAM,UAAU,UAAU,OAAO,YAAY;AAC7C,YAAM,YAAY,QAAQ,OAAO,QAAQ,MAAM,KAAK,IAAI,IAAI;AAE5D,UAAI,WAAW;AACX,YAAI,mCAAmC;AACvC,cAAM,WAAW,MAAM,WAAW,OAAO,OAAO;AAChD,kBAAU,SAAS,YAAY;AAAA,MACnC,OAAO;AACH,kBAAU,MAAM,YAAY;AAAA,MAChC;AAAA,IACJ;AAEA,QAAI,OAAO;AACP,iBAAW;AAAA,IACf;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,cAAc,YAAY;AAC5B,UAAM,MAAM,MAAM,SAAS;AAC3B,QAAI,CAAC,KAAK;AACN,UAAI,gBAAgB;AACpB;AAAA,IACJ;AAEA,QAAI,qBAAqB;AAIzB,YAAQ,QAAQ,QAAQ,EAAE,cAAc,IAAI,CAAC,EACxC,MAAM,CAAC,MAAM;AACV,UAAI,0BAA0B,CAAC;AAAA,IACnC,CAAC;AAAA,EACT;AAEA,QAAM,gBAAgB,MAAM;AACxB,QAAI,yBAAyB;AAE7B,UAAM,cAAc,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AAC1D,iBAAa,QAAQ,oBAAoB,WAAW;AAEpD,QAAIC,WAAU;AACd,IAAAA,YAAW,cAAc,UAAU;AACnC,IAAAA,YAAW,iBAAiB,mBAAmB,OAAO,SAAS,IAAI,CAAC;AACpE,IAAAA,YAAW;AACX,IAAAA,YAAW;AACX,IAAAA,YAAW,UAAU,WAAW;AAEhC,WAAOA;AAAA,EACX;AAEA,QAAM,SAAS,MAAM;AACjB,QAAI,gBAAgB,cAAc,CAAC;AACnC,UAAM,aAAa,cAAc;AAEjC,WAAO,SAAS,OAAO;AAAA,EAC3B;AAEA,QAAM,UAAU,MAAM;AAClB,QAAI,cAAc;AAClB,YAAQ,CAAC,CAAC;AACV,kBAAc,KAAK;AACnB,aAAS,IAAI;AACb,aAAS,SAAS;AAClB,iBAAa,WAAW,kBAAkB;AAQ1C,QAAI,QAAQ,SAAS;AACjB,OAAC,YAAY;AACT,YAAI;AACA,gBAAM,QAAQ,QAAQ,MAAM;AAC5B,gBAAM,QAAQ,QAAQ,OAAO,EAAC,iBAAiB,MAAK,CAAC;AACrD,kBAAQ,UAAU;AAClB,kBAAQ,UAAU,OAAO;AAAA,QAC7B,SAASF,QAAO;AACZ,kBAAQ,MAAM,kCAAkCA,MAAK;AAAA,QACzD;AAAA,MACJ,GAAG;AAAA,IACP;AAAA,EACJ;AAEA,QAAM,WAAW,YAA6B;AAC1C,QAAI,kBAAkB;AAEtB,QAAI,CAAC,OAAO;AACR,UAAI,gBAAgB;AACpB,YAAM,IAAI,MAAM,gBAAgB;AAAA,IACpC;AAEA,UAAM,UAAU,UAAU,OAAO,YAAY;AAC7C,UAAM,YAAY,QAAQ,OAAO,QAAQ,MAAM,KAAK,IAAI,IAAI;AAE5D,QAAI,WAAW;AACX,UAAI,mCAAmC;AACvC,YAAM,WAAW,MAAM,WAAW,OAAO,OAAO;AAChD,aAAO,UAAU,gBAAgB;AAAA,IACrC;AAEA,WAAO,OAAO,gBAAgB;AAAA,EAClC;AAEA,WAAS,UAAU,MAAc;AAC7B,QAAI,cAAc;AAClB,QAAI,SAAS,UAAU,SAAS,WAAW,IAAI;AAC3C,YAAM,UAAU,SAAS,OAAO,MAAM,GAAG;AACzC,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,cAAM,SAAS,QAAQ,CAAC,EAAE,KAAK;AAC/B,YAAI,OAAO,UAAU,GAAG,KAAK,SAAS,CAAC,MAAO,OAAO,KAAM;AACvD,wBAAc,mBAAmB,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC;AAClE;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAEA,QAAM,aAAa,OAAO,SAAiB;AACvC,UAAMG,SAAQ,MAAM,MAAM,qCAAqC;AAAA,MAC3D,QAAQ;AAAA,MACR,SAAS;AAAA,QACL,gBAAgB;AAAA,MACpB;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,KAAW,CAAC;AAAA,IACvC,CAAC,EACI,KAAK,cAAY,SAAS,KAAK,CAAC,EAChC,MAAM,CAAAH,WAAS,IAAI,UAAUA,MAAK,CAAC;AAExC,QAAIG,OAAM,OAAO;AACb,UAAI,wBAAwBA,OAAM,KAAK;AACvC;AAAA,IACJ,OAAO;AAEH,eAASA,MAAK;AAAA,IAClB;AACA,WAAOA;AAAA,EACX;AAGA,QAAM,MAAM,CAAC,cAAsB;AAC/B,UAAM,cAAc,MAAM;AACtB,UAAI,CAAC,YAAY;AACb,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACxD;AAAA,IACJ;AAEA,WAAO;AAAA,MACH,KAAK,YAAY;AACb,oBAAY;AACZ,cAAM,MAAM,MAAM,SAAS;AAC3B,eAAO,IAAI,EAAE,WAAW,YAAY,WAAW,KAAK,IAAI,WAAsB,OAAO,IAAI,CAAC;AAAA,MAC9F;AAAA,MACA,KAAK,OAAO,UAAe;AACvB,oBAAY;AACZ,cAAM,MAAM,MAAM,SAAS;AAC3B,eAAO,IAAI,EAAE,WAAW,YAAY,WAAW,KAAK,IAAI,WAAsB,OAAc,OAAO,IAAI,CAAC;AAAA,MAC5G;AAAA,MACA,QAAQ,OAAO,IAAY,UAAe;AACtC,oBAAY;AACZ,cAAM,MAAM,MAAM,SAAS;AAC3B,eAAO,OAAO,EAAE,WAAW,YAAY,WAAW,KAAK,IAAI,WAAsB,IAAQ,OAAc,OAAO,IAAI,CAAC;AAAA,MACvH;AAAA,MACA,QAAQ,OAAO,OAAe;AAC1B,oBAAY;AACZ,cAAM,MAAM,MAAM,SAAS;AAC3B,eAAO,aAAa,EAAE,WAAW,YAAY,WAAW,KAAK,IAAI,WAAsB,IAAQ,OAAO,IAAI,CAAC;AAAA,MAC/G;AAAA,IAEJ;AAAA,EAEJ;AAEA,QAAM,OAAQ;AAAA,IACV,YAAY,MAAM;AACd,YAAM,IAAI,MAAM,qEAAqE;AAAA,IACzF;AAAA,EACJ;AAEA,SACI,qBAAC,aAAa,UAAb,EAAsB,OAAO;AAAA,IAC1B,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,IAAI,QAAQ,UAAU,QAAQ,UAAU;AAAA,IACxC;AAAA,EACJ,GAEK;AAAA,aAAS,oBAAC,gBAAa,OAAc;AAAA,IACrC,WAAW;AAAA,KAChB;AAER;AAEA,SAAS,aAAa,EAAE,MAAM,GAA2B;AACrD,SAAO,qBAAC,SAAI,OAAO;AAAA,IACf,UAAU;AAAA,IACV,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,YAAY;AAAA,EACf,GACG;AAAA,yBAAC,QAAG,OAAO,EAAC,UAAU,UAAU,SAAS,IAAG,GAAG;AAAA;AAAA,MAAO,MAAM;AAAA,OAAK;AAAA,IACjE,oBAAC,QAAG,OAAO,EAAC,UAAU,UAAU,YAAY,MAAK,GAAI,gBAAM,OAAM;AAAA,IACjE,oBAAC,OAAG,gBAAM,SAAQ;AAAA,KACtB;AACJ;AAQO,SAAS,WAAW;AACvB,SAAO,WAAW,YAAY;AAClC;;;AM/mBA,SAAS,gBAAgB,gBAAgB;","names":["Dexie","changes","baseRevision","partial","onChangesAccepted","requestId","Dexie","key","validateSchema","validateSchema","error","user","baseUrl","token"]}
1
+ {"version":3,"sources":["../src/AuthContext.tsx","../src/sync/index.ts","../src/sync/syncProtocol.js","../src/config.ts","../src/schema.ts","../src/db.ts","../package.json","../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, compareSchemas } from '@basictech/schema'\n\nimport { log } from './config'\nimport {version as currentVersion} from '../package.json'\n\n// Simple storage interface for pluggable storage backends\nexport interface BasicStorage {\n get(key: string): Promise<string | null>\n set(key: string, value: string): Promise<void>\n remove(key: string): Promise<void>\n}\n\n// Default localStorage implementation\nexport class LocalStorageAdapter implements BasicStorage {\n async get(key: string): Promise<string | null> {\n return localStorage.getItem(key)\n }\n \n async set(key: string, value: string): Promise<void> {\n localStorage.setItem(key, value)\n }\n \n async remove(key: string): Promise<void> {\n localStorage.removeItem(key)\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_token: string,\n}\n\nexport const BasicContext = createContext<{\n unicorn: string,\n isAuthReady: boolean,\n isSignedIn: boolean,\n user: User | null,\n signout: () => Promise<void>,\n signin: () => Promise<void>,\n signinWithCode: (code: string, state?: string) => Promise<{ success: boolean, error?: string }>,\n getToken: () => Promise<string>,\n getSignInLink: (redirectUri?: string) => Promise<string>,\n db: any,\n dbStatus: DBStatus\n}>({\n unicorn: \"🦄\",\n isAuthReady: false,\n isSignedIn: false,\n user: null,\n signout: () => Promise.resolve(),\n signin: () => Promise.resolve(),\n signinWithCode: () => new Promise(() => { }),\n getToken: () => new Promise(() => { }),\n getSignInLink: () => Promise.resolve(\"\"),\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\nasync function getSchemaStatus(schema: any) {\n const projectId = schema.project_id\n let status = ''\n const valid = validateSchema(schema)\n\n if (!valid.valid) {\n console.warn('BasicDB Error: your local schema is invalid. Please fix errors and try again - sync is disabled')\n return { \n valid: false, \n status: 'invalid',\n latest: null\n }\n }\n\n const latestSchema = await fetch(`https://api.basic.tech/project/${projectId}/schema`)\n .then(res => res.json())\n .then(data => data.data[0].schema)\n .catch(err => {\n return { \n valid: false, \n status: 'error',\n latest: null\n }\n })\n\n console.log('latestSchema', latestSchema)\n\n if (!latestSchema.version) {\n return { \n valid: false, \n status: 'error',\n latest: null\n }\n }\n\n if (latestSchema.version > schema.version) {\n // error_code: schema_behind\n console.warn('BasicDB Error: your local schema version is behind the latest. Found version:', schema.version, 'but expected', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'behind', \n latest: latestSchema\n }\n } else if (latestSchema.version < schema.version) {\n // error_code: schema_ahead\n console.warn('BasicDB Error: your local schema version is ahead of the latest. Found version:', schema.version, 'but expected', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'ahead', \n latest: latestSchema\n }\n } else if (latestSchema.version === schema.version) {\n const changes = compareSchemas(schema, latestSchema)\n if (changes.valid) {\n return { \n valid: true,\n status: 'current',\n latest: latestSchema\n }\n } else {\n // error_code: schema_conflict\n console.warn('BasicDB Error: your local schema is conflicting with the latest. Your version:', schema.version, 'does not match origin version', latestSchema.version, \" - sync is disabled\")\n return { \n valid: false, \n status: 'conflict',\n latest: latestSchema\n }\n }\n } else { \n return { \n valid: false, \n status: 'error',\n latest: null\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\nasync function checkForNewVersion(): Promise<{ hasNewVersion: boolean, latestVersion: string | null, currentVersion: string | null }> {\n try {\n\n const isBeta = currentVersion.includes('beta')\n\n const response = await fetch(`https://registry.npmjs.org/@basictech/react/${isBeta ? 'beta' : 'latest'}`);\n if (!response.ok) {\n throw new Error('Failed to fetch version from npm');\n }\n\n const data = await response.json();\n const latestVersion = data.version;\n\n if (latestVersion !== currentVersion) {\n console.warn('[basic] New version available:', latestVersion, `\\nrun \"npm install @basictech/react@${latestVersion}\" to update`);\n }\n if (isBeta) {\n log('thank you for being on basictech/react beta :)')\n }\n \n return {\n hasNewVersion: currentVersion !== latestVersion,\n latestVersion,\n currentVersion\n };\n } catch (error) {\n log('Error checking for new version:', error);\n return {\n hasNewVersion: false,\n latestVersion: null, \n currentVersion: null\n };\n }\n}\n\nexport function BasicProvider({ \n children, \n project_id, \n schema, \n debug = false, \n storage \n}: { \n children: React.ReactNode, \n project_id?: string, \n schema?: any, \n debug?: boolean,\n storage?: BasicStorage \n}) {\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 const [shouldConnect, setShouldConnect] = useState<boolean>(false)\n const [isReady, setIsReady] = useState<boolean>(false)\n\n const [dbStatus, setDbStatus] = useState<DBStatus>(DBStatus.OFFLINE)\n const [error, setError] = useState<ErrorObject | null>(null)\n const [isOnline, setIsOnline] = useState<boolean>(navigator.onLine)\n const [pendingRefresh, setPendingRefresh] = useState<boolean>(false)\n\n const syncRef = useRef<BasicSync | null>(null);\n \n // Initialize storage adapter with default localStorage implementation\n const storageAdapter = storage || new LocalStorageAdapter();\n \n // Storage keys\n const STORAGE_KEYS = {\n REFRESH_TOKEN: 'basic_refresh_token',\n USER_INFO: 'basic_user_info',\n AUTH_STATE: 'basic_auth_state',\n DEBUG: 'basic_debug'\n }\n\n // Helper function to check if we're in development mode\n const isDevelopment = () => {\n return (\n window.location.hostname === 'localhost' ||\n window.location.hostname === '127.0.0.1' ||\n window.location.hostname.includes('localhost') ||\n window.location.hostname.includes('127.0.0.1') ||\n window.location.hostname.includes('.local') ||\n process.env.NODE_ENV === 'development' ||\n debug === true\n )\n }\n\n // Helper function to clean OAuth parameters from URL without page reload\n const cleanOAuthParamsFromUrl = () => {\n if (window.location.search.includes('code') || window.location.search.includes('state')) {\n const url = new URL(window.location.href)\n url.searchParams.delete('code')\n url.searchParams.delete('state')\n window.history.pushState({}, document.title, url.pathname + url.search)\n log('Cleaned OAuth parameters from URL')\n }\n }\n\n // Network status monitoring\n useEffect(() => {\n const handleOnline = () => {\n log('Network came back online')\n setIsOnline(true)\n // Retry pending refresh when network comes back\n if (pendingRefresh) {\n log('Retrying pending token refresh')\n setPendingRefresh(false)\n // Trigger a token refresh attempt\n if (token) {\n const refreshToken = token.refresh_token || localStorage.getItem('basic_refresh_token')\n if (refreshToken) {\n fetchToken(refreshToken).catch(error => {\n log('Retry refresh failed:', error)\n })\n }\n }\n }\n }\n \n const handleOffline = () => {\n log('Network went offline')\n setIsOnline(false)\n }\n\n window.addEventListener('online', handleOnline)\n window.addEventListener('offline', handleOffline)\n\n return () => {\n window.removeEventListener('online', handleOnline)\n window.removeEventListener('offline', handleOffline)\n }\n }, [pendingRefresh, token])\n\n useEffect(() => {\n function initDb(options: { shouldConnect: boolean }) {\n if (!syncRef.current) {\n log('Initializing Basic DB')\n syncRef.current = new BasicSync('basicdb', { schema: schema });\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\n if (options.shouldConnect) { \n setShouldConnect(true)\n } else { \n log('Sync is disabled')\n }\n\n setIsReady(true)\n\n \n }\n }\n\n async function checkSchema() {\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 setIsReady(true)\n return null\n }\n\n\n let schemaStatus = { valid: false }\n if (schema.version !== 0) {\n schemaStatus = await getSchemaStatus(schema)\n log('schemaStatus', schemaStatus)\n }else { \n log(\"schema not published - at version 0\")\n }\n\n if (schemaStatus.valid) {\n initDb({ shouldConnect: true })\n } else {\n log('Schema is invalid!', schemaStatus)\n initDb({ shouldConnect: false })\n }\n \n checkForNewVersion()\n }\n\n if (schema) {\n checkSchema()\n } else {\n setIsReady(true)\n }\n }, []);\n\n\n useEffect(() => {\n if (token && syncRef.current && isSignedIn && shouldConnect) {\n connectToDb()\n }\n }, [isSignedIn, shouldConnect])\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 const initializeAuth = async () => {\n await storageAdapter.set(STORAGE_KEYS.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 = await storageAdapter.get(STORAGE_KEYS.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 await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE)\n // Clean OAuth parameters from URL\n cleanOAuthParamsFromUrl()\n return\n }\n\n await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE)\n // Clean OAuth parameters from URL\n cleanOAuthParamsFromUrl()\n\n fetchToken(code) \n } else { \n // Try to restore from localStorage refresh token first\n const refreshToken = await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN)\n if (refreshToken) {\n log('Found refresh token in storage, attempting to refresh access token')\n fetchToken(refreshToken)\n } else {\n // Fallback to cookie for backward compatibility\n let cookie_token = getCookie('basic_token')\n if (cookie_token !== '') {\n const tokenData = JSON.parse(cookie_token)\n setToken(tokenData)\n // Migrate refresh token to storage\n if (tokenData.refresh_token) {\n await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, tokenData.refresh_token)\n }\n } else { \n // Try to load cached user info for offline scenarios\n const cachedUserInfo = await storageAdapter.get(STORAGE_KEYS.USER_INFO)\n if (cachedUserInfo) {\n try {\n const userData = JSON.parse(cachedUserInfo)\n setUser(userData)\n setIsSignedIn(true)\n log('Loaded cached user info for offline mode')\n } catch (error) {\n log('Error parsing cached user info:', error)\n }\n }\n setIsAuthReady(true)\n }\n }\n }\n\n } catch (e) {\n log('error getting token', e)\n }\n }\n \n initializeAuth()\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 // Store refresh token in storage for mobile browser compatibility\n if (token?.refresh_token) {\n await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token.refresh_token)\n }\n \n // Cache user info in storage for offline scenarios\n await storageAdapter.set(STORAGE_KEYS.USER_INFO, JSON.stringify(user))\n log('Cached user info in storage')\n \n // Store access token in cookie for backend authentication\n document.cookie = `basic_access_token=${token.access_token}; Secure; SameSite=Strict; HttpOnly=false`;\n \n // Keep full token in cookie for backward compatibility\n document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;\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 try {\n const newToken = await fetchToken(token?.refresh_token)\n fetchUser(newToken.access_token)\n } catch (error) {\n log('Failed to refresh token in checkToken:', error)\n \n // If it's a network/offline error, continue with expired token\n if (error.message.includes('offline') || error.message.includes('Network')) {\n log('Network issue - continuing with expired token until online')\n fetchUser(token.access_token) // Use expired token for now\n } else {\n // For real auth errors, fetchToken already handles cleanup and signout\n setIsAuthReady(true)\n }\n }\n } else {\n fetchUser(token.access_token)\n }\n }\n\n if (token) {\n checkToken()\n } \n }, [token])\n\n\n\n const getSignInLink = async (redirectUri?: string) => {\n try {\n log('getting sign in link...')\n\n // Validate project_id\n if (!project_id) {\n throw new Error('Project ID is required to generate sign-in link')\n }\n\n const randomState = Math.random().toString(36).substring(6);\n await storageAdapter.set(STORAGE_KEYS.AUTH_STATE, randomState)\n\n // Use provided redirectUri or fallback to current page URL\n const redirectUrl = redirectUri || window.location.href\n\n // Validate redirect URL\n if (!redirectUrl || (!redirectUrl.startsWith('http://') && !redirectUrl.startsWith('https://'))) {\n throw new Error('Invalid redirect URI provided')\n }\n\n let baseUrl = \"https://api.basic.tech/auth/authorize\"\n baseUrl += `?client_id=${project_id}`\n baseUrl += `&redirect_uri=${encodeURIComponent(redirectUrl)}`\n baseUrl += `&response_type=code`\n baseUrl += `&scope=profile`\n baseUrl += `&state=${randomState}`\n\n log('Generated sign-in link successfully')\n return baseUrl;\n\n } catch (error) {\n log('Error generating sign-in link:', error)\n throw error\n }\n }\n\n const signin = async () => {\n try {\n log('signing in...')\n \n // Validate project_id is available\n if (!project_id) {\n log('Error: project_id is required for sign-in')\n throw new Error('Project ID is required for authentication')\n }\n \n const signInLink = await getSignInLink()\n log('Generated sign-in link:', signInLink)\n \n // Validate the generated URL\n if (!signInLink || !signInLink.startsWith('https://')) {\n log('Error: Invalid sign-in link generated')\n throw new Error('Failed to generate valid sign-in URL')\n }\n \n // Perform the redirect\n window.location.href = signInLink\n \n } catch (error) {\n log('Error during sign-in:', error)\n \n // Set error state for UI feedback only in development\n if (isDevelopment()) {\n setError({\n code: 'signin_error',\n title: 'Sign-in Failed',\n message: error.message || 'An error occurred during sign-in. Please try again.'\n })\n }\n \n // Re-throw for any additional error handling\n throw error\n }\n }\n\n const signinWithCode = async (code: string, state?: string): Promise<{ success: boolean, error?: string }> => {\n try {\n log('signinWithCode called with code:', code)\n \n // Validate code format\n if (!code || typeof code !== 'string') {\n return { success: false, error: 'Invalid authorization code' }\n }\n\n // Optional state validation (if provided)\n if (state) {\n const storedState = await storageAdapter.get(STORAGE_KEYS.AUTH_STATE)\n if (storedState && storedState !== state) {\n log('State parameter mismatch:', { provided: state, stored: storedState })\n return { success: false, error: 'State parameter mismatch' }\n }\n }\n\n // Clear auth state\n await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE)\n\n // Clean OAuth parameters from URL if they exist\n cleanOAuthParamsFromUrl()\n\n // Fetch token using the provided code\n const token = await fetchToken(code)\n \n if (token) {\n log('signinWithCode successful')\n return { success: true }\n } else {\n return { success: false, error: 'Failed to exchange code for token' }\n }\n } catch (error) {\n log('signinWithCode error:', error)\n return { \n success: false, \n error: error.message || 'Authentication failed' \n }\n }\n }\n\n const signout = async () => {\n log('signing out!')\n setUser({})\n setIsSignedIn(false)\n setToken(null)\n \n // Clear all authentication data\n document.cookie = `basic_token=; Secure; SameSite=Strict`;\n document.cookie = `basic_access_token=; Secure; SameSite=Strict`;\n await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE)\n await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN)\n await storageAdapter.remove(STORAGE_KEYS.USER_INFO)\n\n // if (syncRef.current) {\n // // WIP - BUG - sometimes connects even after signout\n // syncRef.current.disconnect()\n\n \n // }\n if (syncRef.current) {\n (async () => {\n try {\n await syncRef.current.close()\n await syncRef.current.delete({disableAutoOpen: false})\n syncRef.current = null\n window?.location?.reload()\n } catch (error) {\n console.error('Error during database cleanup:', error)\n }\n })()\n }\n }\n\n const getToken = async (): Promise<string> => {\n log('getting token...')\n\n\n if (!token) {\n // Try to recover from storage refresh token\n const refreshToken = await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN)\n if (refreshToken) {\n log('No token in memory, attempting to refresh from storage')\n try {\n const newToken = await fetchToken(refreshToken)\n if (newToken?.access_token) {\n return newToken.access_token\n }\n } catch (error) {\n log('Failed to refresh token from storage:', error)\n \n // If it's a network/offline error, don't throw - let the app continue with expired token\n if (error.message.includes('offline') || error.message.includes('Network')) {\n log('Network issue - continuing with potentially expired token')\n // Return the last known access token if available, or throw a more specific error\n const lastToken = localStorage.getItem('basic_access_token')\n if (lastToken) {\n return lastToken\n }\n throw new Error('Network offline - authentication will be retried when online')\n }\n \n // For real auth errors, fetchToken already handles cleanup and signout\n throw new Error('Authentication expired. Please sign in again.')\n }\n }\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 refreshToken = token?.refresh_token || await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN)\n if (refreshToken) {\n try {\n const newToken = await fetchToken(refreshToken)\n return newToken?.access_token || ''\n } catch (error) {\n log('Failed to refresh expired token:', error)\n \n // If it's a network/offline error, return the expired token for now\n if (error.message.includes('offline') || error.message.includes('Network')) {\n log('Network issue - using expired token until network is restored')\n return token.access_token // Return expired token for offline use\n }\n \n // For real auth errors, fetchToken already handles cleanup and signout\n throw new Error('Authentication expired. Please sign in again.')\n }\n } else {\n throw new Error('no refresh token available')\n }\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 try {\n // Check if we're offline before attempting network request\n if (!isOnline) {\n log('Network is offline, marking refresh as pending')\n setPendingRefresh(true)\n throw new Error('Network offline - refresh will be retried when online')\n }\n\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 => {\n log('Network error fetching token:', error)\n // If it's a network error and we're offline, don't sign out\n if (!isOnline) {\n setPendingRefresh(true)\n throw new Error('Network offline - refresh will be retried when online')\n }\n throw new Error('Network error during token refresh')\n })\n\n if (token.error) {\n log('error fetching token', token.error)\n \n // Only sign out if it's a real authentication error, not a network issue\n if (token.error.includes('network') || token.error.includes('timeout')) {\n setPendingRefresh(true)\n throw new Error('Network issue - refresh will be retried when online')\n }\n \n // Clear invalid tokens from storage only for real auth errors\n await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN)\n await storageAdapter.remove(STORAGE_KEYS.USER_INFO)\n document.cookie = `basic_token=; Secure; SameSite=Strict`;\n document.cookie = `basic_access_token=; Secure; SameSite=Strict`;\n \n // Sign out user on token refresh failure\n setUser({})\n setIsSignedIn(false)\n setToken(null)\n setIsAuthReady(true)\n \n throw new Error(`Token refresh failed: ${token.error}`)\n } else {\n // log('token', token)\n setToken(token)\n setPendingRefresh(false) // Clear pending flag on success\n \n // Update refresh token in storage when server provides a new one\n if (token.refresh_token) {\n await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token.refresh_token)\n log('Updated refresh token in storage')\n }\n \n // Update access token in cookie for backend authentication\n document.cookie = `basic_access_token=${token.access_token}; Secure; SameSite=Strict; HttpOnly=false`;\n log('Updated access token in cookie')\n }\n return token\n } catch (error) {\n log('Token refresh error:', error)\n \n // Only clear auth data and sign out if it's not a network/offline issue\n if (!error.message.includes('offline') && !error.message.includes('Network')) {\n // Clear all authentication data on real errors\n await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN)\n await storageAdapter.remove(STORAGE_KEYS.USER_INFO)\n document.cookie = `basic_token=; Secure; SameSite=Strict`;\n document.cookie = `basic_access_token=; Secure; SameSite=Strict`;\n \n // Sign out user\n setUser({})\n setIsSignedIn(false)\n setToken(null)\n setIsAuthReady(true)\n }\n \n throw error\n }\n }\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 const noDb = ({ \n collection: () => {\n throw new Error('no basicdb found - initialization failed. double check your schema.')\n }\n })\n\n return (\n <BasicContext.Provider value={{\n unicorn: \"🦄\",\n isAuthReady,\n isSignedIn,\n user,\n signout,\n signin,\n signinWithCode,\n getToken,\n getSignInLink,\n db: syncRef.current ? syncRef.current : noDb,\n dbStatus\n }}>\n \n {error && isDevelopment() && <ErrorDisplay error={error} />}\n {isReady && children}\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 { 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// const SERVER_URL = \"https://pds.basic.id\"\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 = `wss://pds.basic.id/ws`\n\n log('Connecting to', WS_URL)\n\n await this.updateSyncNodes();\n \n log('Starting connection...')\n return this.syncable.connect(\"websocket\", WS_URL, { authToken: access_token, schema: this.basic_schema });\n }\n\n async disconnect() {\n const WS_URL = `wss://pds.basic.id/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 delay to ensure sync nodes are updated // i dont think this helps?\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n if (typeof window !== 'undefined') {\n window.location.reload();\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 log(\"Connecting to\", 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 // send the schema to the server\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 schema: options.schema\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 log(\"caught error\", e)\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:3003\"\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","{\n \"name\": \"@basictech/react\",\n \"version\": \"0.6.0\",\n \"description\": \"\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"private\": false,\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n },\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n \"ajv\": \"^8.17.1\",\n \"dexie\": \"^4.0.8\",\n \"dexie-observable\": \"^4.0.1-beta.13\",\n \"dexie-react-hooks\": \"^1.1.7\",\n \"dexie-syncable\": \"^4.0.1-beta.13\",\n \"jwt-decode\": \"^4.0.0\",\n \"uuid\": \"^10.0.0\",\n \"@basictech/schema\": \"0.6.0\"\n },\n \"devDependencies\": {\n \"@repo/typescript-config\": \"*\",\n \"tsup\": \"^7.2.0\",\n \"typescript\": \"^5.0.0\"\n },\n \"peerDependencies\": {\n \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n }\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","user","baseUrl","token"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basictech/react",
3
- "version": "0.7.0-beta.0",
3
+ "version": "0.7.0-beta.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -24,7 +24,7 @@
24
24
  "dexie-syncable": "^4.0.1-beta.13",
25
25
  "jwt-decode": "^4.0.0",
26
26
  "uuid": "^10.0.0",
27
- "@basictech/schema": "0.7.0-beta.0"
27
+ "@basictech/schema": "0.6.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@repo/typescript-config": "*",
package/readme.md CHANGED
@@ -60,7 +60,7 @@ In your components, you can use the `useBasic` hook to access authentication and
60
60
  import { useBasic } from '@basictech/react';
61
61
 
62
62
  function MyComponent() {
63
- const { user, isSignedIn, signin, signout, db } = useBasic();
63
+ const { user, isSignedIn, signin, signout, signinWithCode, db } = useBasic();
64
64
 
65
65
  if (!isSignedIn) {
66
66
  return <button onClick={signin}>Sign In</button>;
@@ -75,6 +75,117 @@ function MyComponent() {
75
75
  }
76
76
  ```
77
77
 
78
+ ### 3. Manual OAuth Code Handling
79
+
80
+ For custom OAuth flows (mobile apps, server-side redirects, etc.), you can manually handle authorization codes:
81
+
82
+ ```typescript
83
+ import { useBasic } from '@basictech/react';
84
+
85
+ function CustomAuthComponent() {
86
+ const { signinWithCode } = useBasic();
87
+
88
+ const handleOAuthCode = async (code: string, state?: string) => {
89
+ const result = await signinWithCode(code, state);
90
+
91
+ if (result.success) {
92
+ console.log('Successfully authenticated!');
93
+ // Redirect to authenticated area
94
+ } else {
95
+ console.error('Authentication failed:', result.error);
96
+ // Handle error
97
+ }
98
+ };
99
+
100
+ // Example: Handle OAuth code from URL parameters
101
+ useEffect(() => {
102
+ const urlParams = new URLSearchParams(window.location.search);
103
+ const code = urlParams.get('code');
104
+ const state = urlParams.get('state');
105
+
106
+ if (code) {
107
+ handleOAuthCode(code, state || undefined);
108
+ }
109
+ }, []);
110
+
111
+ return <div>Processing authentication...</div>;
112
+ }
113
+ ```
114
+
115
+ #### Mobile App Integration Example:
116
+
117
+ ```typescript
118
+ // React Native or mobile app deep link handling
119
+ const handleDeepLink = (url: string) => {
120
+ const urlParams = new URLSearchParams(url.split('?')[1]);
121
+ const code = urlParams.get('code');
122
+ const state = urlParams.get('state');
123
+
124
+ if (code) {
125
+ signinWithCode(code, state || undefined);
126
+ }
127
+ };
128
+ ```
129
+
130
+ #### Server-Side OAuth Example:
131
+
132
+ ```typescript
133
+ // When OAuth happens server-side and you receive the code
134
+ const handleServerOAuth = async (serverCode: string) => {
135
+ const result = await signinWithCode(serverCode);
136
+
137
+ if (result.success) {
138
+ // Redirect to authenticated area
139
+ window.location.href = '/dashboard';
140
+ } else {
141
+ // Show error message
142
+ alert(`Authentication failed: ${result.error}`);
143
+ }
144
+ };
145
+ ```
146
+
147
+ ### 4. Custom OAuth Redirect URIs
148
+
149
+ You can specify custom redirect URIs for OAuth flows:
150
+
151
+ ```typescript
152
+ import { useBasic } from '@basictech/react';
153
+
154
+ function CustomAuthComponent() {
155
+ const { getSignInLink } = useBasic();
156
+
157
+ const handleCustomRedirect = () => {
158
+ // Use a custom redirect URI
159
+ const signInUrl = getSignInLink('https://yourapp.com/auth/callback');
160
+ window.location.href = signInUrl;
161
+ };
162
+
163
+ const handleDefaultRedirect = () => {
164
+ // Use default redirect (current page URL)
165
+ const signInUrl = getSignInLink();
166
+ window.location.href = signInUrl;
167
+ };
168
+
169
+ return (
170
+ <div>
171
+ <button onClick={handleCustomRedirect}>
172
+ Sign In (Custom Redirect)
173
+ </button>
174
+ <button onClick={handleDefaultRedirect}>
175
+ Sign In (Default Redirect)
176
+ </button>
177
+ </div>
178
+ );
179
+ }
180
+ ```
181
+
182
+ #### Use Cases for Custom Redirect URIs:
183
+
184
+ - **Mobile Apps**: Redirect to app-specific URLs
185
+ - **Multi-Domain**: Redirect to different domains based on context
186
+ - **Testing**: Use test-specific callback URLs
187
+ - **Subdomains**: Redirect to specific subdomains
188
+
78
189
  ## API Reference
79
190
 
80
191
 
@@ -128,8 +239,23 @@ Returns an object with the following properties and methods:
128
239
  - `isSignedIn`: Boolean indicating if the user is signed in
129
240
  - `signin()`: Function to initiate the sign-in process
130
241
  - `signout()`: Function to sign out the user
242
+ - `signinWithCode(code: string, state?: string)`: Function to manually handle OAuth authorization codes
243
+ - `getSignInLink(redirectUri?: string)`: Function to generate OAuth sign-in URLs
131
244
  - `db`: Object for database operations
132
245
 
246
+ #### signinWithCode Parameters:
247
+ - `code` (required): The OAuth authorization code received from the OAuth provider
248
+ - `state` (optional): The state parameter for CSRF protection validation
249
+
250
+ #### signinWithCode Returns:
251
+ - `Promise<{ success: boolean, error?: string }>`: Returns success status and optional error message
252
+
253
+ #### getSignInLink Parameters:
254
+ - `redirectUri` (optional): Custom redirect URI for OAuth flow. If not provided, defaults to current page URL
255
+
256
+ #### getSignInLink Returns:
257
+ - `string`: Complete OAuth authorization URL
258
+
133
259
 
134
260
 
135
261
  db methods: