@basictech/react 0.7.0-beta.1 → 0.7.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTH_IMPLEMENTATION_GUIDE.md +2009 -0
- package/changelog.md +12 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +362 -363
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +360 -351
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/AuthContext.tsx +242 -404
- package/src/index.ts +11 -32
- package/src/sync/index.ts +1 -1
- package/src/updater/updateMigrations.ts +22 -0
- package/src/updater/versionUpdater.ts +160 -0
- package/src/utils/network.ts +82 -0
- package/src/utils/schema.ts +120 -0
- package/src/utils/storage.ts +63 -0
- package/src/schema.ts +0 -159
package/dist/index.mjs
CHANGED
|
@@ -127,116 +127,8 @@ var syncProtocol = function() {
|
|
|
127
127
|
});
|
|
128
128
|
};
|
|
129
129
|
|
|
130
|
-
// src/schema.ts
|
|
131
|
-
import Ajv from "ajv";
|
|
132
|
-
var basicJsonSchema = {
|
|
133
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
134
|
-
"type": "object",
|
|
135
|
-
"properties": {
|
|
136
|
-
"project_id": {
|
|
137
|
-
"type": "string"
|
|
138
|
-
},
|
|
139
|
-
"namespace": {
|
|
140
|
-
"type": "string"
|
|
141
|
-
},
|
|
142
|
-
"version": {
|
|
143
|
-
"type": "integer",
|
|
144
|
-
"minimum": 0
|
|
145
|
-
},
|
|
146
|
-
"tables": {
|
|
147
|
-
"type": "object",
|
|
148
|
-
"patternProperties": {
|
|
149
|
-
"^[a-zA-Z0-9_]+$": {
|
|
150
|
-
"type": "object",
|
|
151
|
-
"properties": {
|
|
152
|
-
"name": {
|
|
153
|
-
"type": "string"
|
|
154
|
-
},
|
|
155
|
-
"type": {
|
|
156
|
-
"type": "string",
|
|
157
|
-
"enum": ["collection"]
|
|
158
|
-
},
|
|
159
|
-
"fields": {
|
|
160
|
-
"type": "object",
|
|
161
|
-
"patternProperties": {
|
|
162
|
-
"^[a-zA-Z0-9_]+$": {
|
|
163
|
-
"type": "object",
|
|
164
|
-
"properties": {
|
|
165
|
-
"type": {
|
|
166
|
-
"type": "string",
|
|
167
|
-
"enum": ["string", "boolean", "number", "json"]
|
|
168
|
-
},
|
|
169
|
-
"indexed": {
|
|
170
|
-
"type": "boolean"
|
|
171
|
-
},
|
|
172
|
-
"required": {
|
|
173
|
-
"type": "boolean"
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
"required": ["type"]
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
"additionalProperties": true
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
"required": ["fields"]
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
"additionalProperties": true
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
"required": ["project_id", "version", "tables"]
|
|
189
|
-
};
|
|
190
|
-
var ajv = new Ajv();
|
|
191
|
-
var validator = ajv.compile(basicJsonSchema);
|
|
192
|
-
function validateSchema(schema) {
|
|
193
|
-
const v = validator(schema);
|
|
194
|
-
return {
|
|
195
|
-
valid: v,
|
|
196
|
-
errors: validator.errors || []
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
function validateData(schema, table, data, checkRequired = true) {
|
|
200
|
-
const valid = validateSchema(schema);
|
|
201
|
-
if (!valid.valid) {
|
|
202
|
-
return { valid: false, errors: valid.errors, message: "Schema is invalid" };
|
|
203
|
-
}
|
|
204
|
-
const tableSchema = schema.tables[table];
|
|
205
|
-
if (!tableSchema) {
|
|
206
|
-
return { valid: false, errors: [{ message: `Table ${table} not found in schema` }], message: "Table not found" };
|
|
207
|
-
}
|
|
208
|
-
for (const [fieldName, fieldValue] of Object.entries(data)) {
|
|
209
|
-
const fieldSchema = tableSchema.fields[fieldName];
|
|
210
|
-
if (!fieldSchema) {
|
|
211
|
-
return {
|
|
212
|
-
valid: false,
|
|
213
|
-
errors: [{ message: `Field ${fieldName} not found in schema` }],
|
|
214
|
-
message: "Invalid field"
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
const schemaType = fieldSchema.type;
|
|
218
|
-
const valueType = typeof fieldValue;
|
|
219
|
-
if (schemaType === "string" && valueType !== "string" || schemaType === "number" && valueType !== "number" || schemaType === "boolean" && valueType !== "boolean" || schemaType === "json" && valueType !== "object") {
|
|
220
|
-
return {
|
|
221
|
-
valid: false,
|
|
222
|
-
errors: [{
|
|
223
|
-
message: `Field ${fieldName} should be type ${schemaType}, got ${valueType}`
|
|
224
|
-
}],
|
|
225
|
-
message: "invalid type"
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (checkRequired) {
|
|
230
|
-
for (const [fieldName, fieldSchema] of Object.entries(tableSchema.fields)) {
|
|
231
|
-
if (fieldSchema.required && !data[fieldName]) {
|
|
232
|
-
return { valid: false, errors: [{ message: `Field ${fieldName} is required` }], message: "Required field missing" };
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return { valid: true, errors: [] };
|
|
237
|
-
}
|
|
238
|
-
|
|
239
130
|
// src/sync/index.ts
|
|
131
|
+
import { validateData } from "@basictech/schema";
|
|
240
132
|
syncProtocol();
|
|
241
133
|
var BasicSync = class extends Dexie2 {
|
|
242
134
|
basic_schema;
|
|
@@ -358,60 +250,135 @@ var BasicSync = class extends Dexie2 {
|
|
|
358
250
|
}
|
|
359
251
|
};
|
|
360
252
|
|
|
361
|
-
//
|
|
362
|
-
var
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
253
|
+
// package.json
|
|
254
|
+
var version = "0.7.0-beta.2";
|
|
255
|
+
|
|
256
|
+
// src/updater/versionUpdater.ts
|
|
257
|
+
var VersionUpdater = class {
|
|
258
|
+
storage;
|
|
259
|
+
currentVersion;
|
|
260
|
+
migrations;
|
|
261
|
+
versionKey = "basic_app_version";
|
|
262
|
+
constructor(storage, currentVersion, migrations = []) {
|
|
263
|
+
this.storage = storage;
|
|
264
|
+
this.currentVersion = currentVersion;
|
|
265
|
+
this.migrations = migrations.sort((a, b) => this.compareVersions(a.fromVersion, b.fromVersion));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Check current stored version and run migrations if needed
|
|
269
|
+
* Only compares major.minor versions, ignoring beta/prerelease parts
|
|
270
|
+
* Example: "0.7.0-beta.1" and "0.7.0" are treated as the same version
|
|
271
|
+
*/
|
|
272
|
+
async checkAndUpdate() {
|
|
273
|
+
const storedVersion = await this.getStoredVersion();
|
|
274
|
+
if (!storedVersion) {
|
|
275
|
+
await this.setStoredVersion(this.currentVersion);
|
|
276
|
+
return { updated: false, toVersion: this.currentVersion };
|
|
368
277
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
async function add({ projectId, accountId, tableName, value, token }) {
|
|
373
|
-
const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;
|
|
374
|
-
const response = await fetch(url, {
|
|
375
|
-
method: "POST",
|
|
376
|
-
headers: {
|
|
377
|
-
"Content-Type": "application/json",
|
|
378
|
-
"Authorization": `Bearer ${token}`
|
|
379
|
-
},
|
|
380
|
-
body: JSON.stringify({ "value": value })
|
|
381
|
-
});
|
|
382
|
-
return response.json();
|
|
383
|
-
}
|
|
384
|
-
async function update({ projectId, accountId, tableName, id, value, token }) {
|
|
385
|
-
const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;
|
|
386
|
-
const response = await fetch(url, {
|
|
387
|
-
method: "PATCH",
|
|
388
|
-
headers: {
|
|
389
|
-
"Content-Type": "application/json",
|
|
390
|
-
"Authorization": `Bearer ${token}`
|
|
391
|
-
},
|
|
392
|
-
body: JSON.stringify({ id, value })
|
|
393
|
-
});
|
|
394
|
-
return response.json();
|
|
395
|
-
}
|
|
396
|
-
async function deleteRecord({ projectId, accountId, tableName, id, token }) {
|
|
397
|
-
const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;
|
|
398
|
-
const response = await fetch(url, {
|
|
399
|
-
method: "DELETE",
|
|
400
|
-
headers: {
|
|
401
|
-
"Authorization": `Bearer ${token}`
|
|
278
|
+
if (storedVersion === this.currentVersion) {
|
|
279
|
+
return { updated: false, toVersion: this.currentVersion };
|
|
402
280
|
}
|
|
403
|
-
|
|
404
|
-
|
|
281
|
+
const migrationsToRun = this.getMigrationsToRun(storedVersion, this.currentVersion);
|
|
282
|
+
if (migrationsToRun.length === 0) {
|
|
283
|
+
await this.setStoredVersion(this.currentVersion);
|
|
284
|
+
return { updated: true, fromVersion: storedVersion, toVersion: this.currentVersion };
|
|
285
|
+
}
|
|
286
|
+
for (const migration of migrationsToRun) {
|
|
287
|
+
try {
|
|
288
|
+
console.log(`Running migration from ${migration.fromVersion} to ${migration.toVersion}`);
|
|
289
|
+
await migration.migrate(this.storage);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.error(`Migration failed from ${migration.fromVersion} to ${migration.toVersion}:`, error);
|
|
292
|
+
throw new Error(`Migration failed: ${error}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
await this.setStoredVersion(this.currentVersion);
|
|
296
|
+
return { updated: true, fromVersion: storedVersion, toVersion: this.currentVersion };
|
|
297
|
+
}
|
|
298
|
+
async getStoredVersion() {
|
|
299
|
+
try {
|
|
300
|
+
const versionData = await this.storage.get(this.versionKey);
|
|
301
|
+
if (!versionData)
|
|
302
|
+
return null;
|
|
303
|
+
const versionInfo = JSON.parse(versionData);
|
|
304
|
+
return versionInfo.version;
|
|
305
|
+
} catch (error) {
|
|
306
|
+
console.warn("Failed to get stored version:", error);
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async setStoredVersion(version2) {
|
|
311
|
+
const versionInfo = {
|
|
312
|
+
version: version2,
|
|
313
|
+
lastUpdated: Date.now()
|
|
314
|
+
};
|
|
315
|
+
await this.storage.set(this.versionKey, JSON.stringify(versionInfo));
|
|
316
|
+
}
|
|
317
|
+
getMigrationsToRun(fromVersion, toVersion) {
|
|
318
|
+
return this.migrations.filter((migration) => {
|
|
319
|
+
const storedLessThanMigrationTo = this.compareVersions(fromVersion, migration.toVersion) < 0;
|
|
320
|
+
const currentGreaterThanOrEqualMigrationTo = this.compareVersions(toVersion, migration.toVersion) >= 0;
|
|
321
|
+
console.log(`Checking migration ${migration.fromVersion} \u2192 ${migration.toVersion}:`);
|
|
322
|
+
console.log(` stored ${fromVersion} < migration.to ${migration.toVersion}: ${storedLessThanMigrationTo}`);
|
|
323
|
+
console.log(` current ${toVersion} >= migration.to ${migration.toVersion}: ${currentGreaterThanOrEqualMigrationTo}`);
|
|
324
|
+
const shouldRun = storedLessThanMigrationTo && currentGreaterThanOrEqualMigrationTo;
|
|
325
|
+
console.log(` Should run: ${shouldRun}`);
|
|
326
|
+
return shouldRun;
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Simple semantic version comparison (major.minor only, ignoring beta/prerelease)
|
|
331
|
+
* Returns: -1 if a < b, 0 if a === b, 1 if a > b
|
|
332
|
+
*/
|
|
333
|
+
compareVersions(a, b) {
|
|
334
|
+
const aMajorMinor = this.extractMajorMinor(a);
|
|
335
|
+
const bMajorMinor = this.extractMajorMinor(b);
|
|
336
|
+
if (aMajorMinor.major !== bMajorMinor.major) {
|
|
337
|
+
return aMajorMinor.major - bMajorMinor.major;
|
|
338
|
+
}
|
|
339
|
+
return aMajorMinor.minor - bMajorMinor.minor;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Extract major.minor from version string, ignoring beta/prerelease
|
|
343
|
+
* Examples: "0.7.0-beta.1" -> {major: 0, minor: 7}
|
|
344
|
+
* "1.2.3" -> {major: 1, minor: 2}
|
|
345
|
+
*/
|
|
346
|
+
extractMajorMinor(version2) {
|
|
347
|
+
const cleanVersion = version2.split("-")[0]?.split("+")[0] || version2;
|
|
348
|
+
const parts = cleanVersion.split(".").map(Number);
|
|
349
|
+
return {
|
|
350
|
+
major: parts[0] || 0,
|
|
351
|
+
minor: parts[1] || 0
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Add a migration to the updater
|
|
356
|
+
*/
|
|
357
|
+
addMigration(migration) {
|
|
358
|
+
this.migrations.push(migration);
|
|
359
|
+
this.migrations.sort((a, b) => this.compareVersions(a.fromVersion, b.fromVersion));
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
function createVersionUpdater(storage, currentVersion, migrations = []) {
|
|
363
|
+
return new VersionUpdater(storage, currentVersion, migrations);
|
|
405
364
|
}
|
|
406
365
|
|
|
407
|
-
// src/
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
366
|
+
// src/updater/updateMigrations.ts
|
|
367
|
+
var addMigrationTimestamp = {
|
|
368
|
+
fromVersion: "0.6.0",
|
|
369
|
+
toVersion: "0.7.0",
|
|
370
|
+
async migrate(storage) {
|
|
371
|
+
console.log("Running test migration");
|
|
372
|
+
storage.set("test_migration", "true");
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
function getMigrations() {
|
|
376
|
+
return [
|
|
377
|
+
addMigrationTimestamp
|
|
378
|
+
];
|
|
379
|
+
}
|
|
412
380
|
|
|
413
|
-
// src/
|
|
414
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
381
|
+
// src/utils/storage.ts
|
|
415
382
|
var LocalStorageAdapter = class {
|
|
416
383
|
async get(key) {
|
|
417
384
|
return localStorage.getItem(key);
|
|
@@ -423,25 +390,113 @@ var LocalStorageAdapter = class {
|
|
|
423
390
|
localStorage.removeItem(key);
|
|
424
391
|
}
|
|
425
392
|
};
|
|
426
|
-
var
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
393
|
+
var STORAGE_KEYS = {
|
|
394
|
+
REFRESH_TOKEN: "basic_refresh_token",
|
|
395
|
+
USER_INFO: "basic_user_info",
|
|
396
|
+
AUTH_STATE: "basic_auth_state",
|
|
397
|
+
DEBUG: "basic_debug"
|
|
398
|
+
};
|
|
399
|
+
function getCookie(name) {
|
|
400
|
+
let cookieValue = "";
|
|
401
|
+
if (document.cookie && document.cookie !== "") {
|
|
402
|
+
const cookies = document.cookie.split(";");
|
|
403
|
+
for (let i = 0; i < cookies.length; i++) {
|
|
404
|
+
const cookie = cookies[i]?.trim();
|
|
405
|
+
if (cookie && cookie.substring(0, name.length + 1) === name + "=") {
|
|
406
|
+
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return cookieValue;
|
|
412
|
+
}
|
|
413
|
+
function setCookie(name, value, options) {
|
|
414
|
+
const opts = {
|
|
415
|
+
secure: true,
|
|
416
|
+
sameSite: "Strict",
|
|
417
|
+
httpOnly: false,
|
|
418
|
+
...options
|
|
419
|
+
};
|
|
420
|
+
let cookieString = `${name}=${value}`;
|
|
421
|
+
if (opts.secure)
|
|
422
|
+
cookieString += "; Secure";
|
|
423
|
+
if (opts.sameSite)
|
|
424
|
+
cookieString += `; SameSite=${opts.sameSite}`;
|
|
425
|
+
if (opts.httpOnly)
|
|
426
|
+
cookieString += "; HttpOnly";
|
|
427
|
+
document.cookie = cookieString;
|
|
428
|
+
}
|
|
429
|
+
function clearCookie(name) {
|
|
430
|
+
document.cookie = `${name}=; Secure; SameSite=Strict`;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/utils/network.ts
|
|
434
|
+
function isDevelopment(debug) {
|
|
435
|
+
return window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.includes("localhost") || window.location.hostname.includes("127.0.0.1") || window.location.hostname.includes(".local") || process.env.NODE_ENV === "development" || debug === true;
|
|
436
|
+
}
|
|
437
|
+
async function checkForNewVersion() {
|
|
438
|
+
try {
|
|
439
|
+
const isBeta = version.includes("beta");
|
|
440
|
+
const response = await fetch(`https://registry.npmjs.org/@basictech/react/${isBeta ? "beta" : "latest"}`);
|
|
441
|
+
if (!response.ok) {
|
|
442
|
+
throw new Error("Failed to fetch version from npm");
|
|
443
|
+
}
|
|
444
|
+
const data = await response.json();
|
|
445
|
+
const latestVersion = data.version;
|
|
446
|
+
if (latestVersion !== version) {
|
|
447
|
+
console.warn("[basic] New version available:", latestVersion, `
|
|
448
|
+
run "npm install @basictech/react@${latestVersion}" to update`);
|
|
449
|
+
}
|
|
450
|
+
if (isBeta) {
|
|
451
|
+
log("thank you for being on basictech/react beta :)");
|
|
452
|
+
}
|
|
453
|
+
return {
|
|
454
|
+
hasNewVersion: version !== latestVersion,
|
|
455
|
+
latestVersion,
|
|
456
|
+
currentVersion: version
|
|
457
|
+
};
|
|
458
|
+
} catch (error) {
|
|
459
|
+
log("Error checking for new version:", error);
|
|
460
|
+
return {
|
|
461
|
+
hasNewVersion: false,
|
|
462
|
+
latestVersion: null,
|
|
463
|
+
currentVersion: null
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function cleanOAuthParamsFromUrl() {
|
|
468
|
+
if (window.location.search.includes("code") || window.location.search.includes("state")) {
|
|
469
|
+
const url = new URL(window.location.href);
|
|
470
|
+
url.searchParams.delete("code");
|
|
471
|
+
url.searchParams.delete("state");
|
|
472
|
+
window.history.pushState({}, document.title, url.pathname + url.search);
|
|
473
|
+
log("Cleaned OAuth parameters from URL");
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function getSyncStatus(statusCode) {
|
|
477
|
+
switch (statusCode) {
|
|
478
|
+
case -1:
|
|
479
|
+
return "ERROR";
|
|
480
|
+
case 0:
|
|
481
|
+
return "OFFLINE";
|
|
482
|
+
case 1:
|
|
483
|
+
return "CONNECTING";
|
|
484
|
+
case 2:
|
|
485
|
+
return "ONLINE";
|
|
486
|
+
case 3:
|
|
487
|
+
return "SYNCING";
|
|
488
|
+
case 4:
|
|
489
|
+
return "ERROR_WILL_RETRY";
|
|
490
|
+
default:
|
|
491
|
+
return "UNKNOWN";
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// src/utils/schema.ts
|
|
496
|
+
import { validateSchema as validateSchema2, compareSchemas } from "@basictech/schema";
|
|
441
497
|
async function getSchemaStatus(schema) {
|
|
442
498
|
const projectId = schema.project_id;
|
|
443
|
-
|
|
444
|
-
const valid = validateSchema3(schema);
|
|
499
|
+
const valid = validateSchema2(schema);
|
|
445
500
|
if (!valid.valid) {
|
|
446
501
|
console.warn("BasicDB Error: your local schema is invalid. Please fix errors and try again - sync is disabled");
|
|
447
502
|
return {
|
|
@@ -503,54 +558,54 @@ async function getSchemaStatus(schema) {
|
|
|
503
558
|
};
|
|
504
559
|
}
|
|
505
560
|
}
|
|
506
|
-
function
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
case 4:
|
|
519
|
-
return "ERROR_WILL_RETRY";
|
|
520
|
-
default:
|
|
521
|
-
return "UNKNOWN";
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
async function checkForNewVersion() {
|
|
525
|
-
try {
|
|
526
|
-
const isBeta = version.includes("beta");
|
|
527
|
-
const response = await fetch(`https://registry.npmjs.org/@basictech/react/${isBeta ? "beta" : "latest"}`);
|
|
528
|
-
if (!response.ok) {
|
|
529
|
-
throw new Error("Failed to fetch version from npm");
|
|
530
|
-
}
|
|
531
|
-
const data = await response.json();
|
|
532
|
-
const latestVersion = data.version;
|
|
533
|
-
if (latestVersion !== version) {
|
|
534
|
-
console.warn("[basic] New version available:", latestVersion, `
|
|
535
|
-
run "npm install @basictech/react@${latestVersion}" to update`);
|
|
536
|
-
}
|
|
537
|
-
if (isBeta) {
|
|
538
|
-
log("thank you for being on basictech/react beta :)");
|
|
539
|
-
}
|
|
540
|
-
return {
|
|
541
|
-
hasNewVersion: version !== latestVersion,
|
|
542
|
-
latestVersion,
|
|
543
|
-
currentVersion: version
|
|
544
|
-
};
|
|
545
|
-
} catch (error) {
|
|
546
|
-
log("Error checking for new version:", error);
|
|
561
|
+
async function validateAndCheckSchema(schema) {
|
|
562
|
+
const valid = validateSchema2(schema);
|
|
563
|
+
if (!valid.valid) {
|
|
564
|
+
log("Basic Schema is invalid!", valid.errors);
|
|
565
|
+
console.group("Schema Errors");
|
|
566
|
+
let errorMessage = "";
|
|
567
|
+
valid.errors.forEach((error, index) => {
|
|
568
|
+
log(`${index + 1}:`, error.message, ` - at ${error.instancePath}`);
|
|
569
|
+
errorMessage += `${index + 1}: ${error.message} - at ${error.instancePath}
|
|
570
|
+
`;
|
|
571
|
+
});
|
|
572
|
+
console.groupEnd();
|
|
547
573
|
return {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
574
|
+
isValid: false,
|
|
575
|
+
schemaStatus: { valid: false },
|
|
576
|
+
errors: valid.errors
|
|
551
577
|
};
|
|
552
578
|
}
|
|
579
|
+
let schemaStatus = { valid: false };
|
|
580
|
+
if (schema.version !== 0) {
|
|
581
|
+
schemaStatus = await getSchemaStatus(schema);
|
|
582
|
+
log("schemaStatus", schemaStatus);
|
|
583
|
+
} else {
|
|
584
|
+
log("schema not published - at version 0");
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
isValid: true,
|
|
588
|
+
schemaStatus
|
|
589
|
+
};
|
|
553
590
|
}
|
|
591
|
+
|
|
592
|
+
// src/AuthContext.tsx
|
|
593
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
594
|
+
var BasicContext = createContext({
|
|
595
|
+
unicorn: "\u{1F984}",
|
|
596
|
+
isAuthReady: false,
|
|
597
|
+
isSignedIn: false,
|
|
598
|
+
user: null,
|
|
599
|
+
signout: () => Promise.resolve(),
|
|
600
|
+
signin: () => Promise.resolve(),
|
|
601
|
+
signinWithCode: () => new Promise(() => {
|
|
602
|
+
}),
|
|
603
|
+
getToken: () => new Promise(() => {
|
|
604
|
+
}),
|
|
605
|
+
getSignInLink: () => Promise.resolve(""),
|
|
606
|
+
db: {},
|
|
607
|
+
dbStatus: "LOADING" /* LOADING */
|
|
608
|
+
});
|
|
554
609
|
function BasicProvider({
|
|
555
610
|
children,
|
|
556
611
|
project_id,
|
|
@@ -570,24 +625,8 @@ function BasicProvider({
|
|
|
570
625
|
const [pendingRefresh, setPendingRefresh] = useState(false);
|
|
571
626
|
const syncRef = useRef(null);
|
|
572
627
|
const storageAdapter = storage || new LocalStorageAdapter();
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
USER_INFO: "basic_user_info",
|
|
576
|
-
AUTH_STATE: "basic_auth_state",
|
|
577
|
-
DEBUG: "basic_debug"
|
|
578
|
-
};
|
|
579
|
-
const isDevelopment = () => {
|
|
580
|
-
return window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.includes("localhost") || window.location.hostname.includes("127.0.0.1") || window.location.hostname.includes(".local") || process.env.NODE_ENV === "development" || debug === true;
|
|
581
|
-
};
|
|
582
|
-
const cleanOAuthParamsFromUrl = () => {
|
|
583
|
-
if (window.location.search.includes("code") || window.location.search.includes("state")) {
|
|
584
|
-
const url = new URL(window.location.href);
|
|
585
|
-
url.searchParams.delete("code");
|
|
586
|
-
url.searchParams.delete("state");
|
|
587
|
-
window.history.pushState({}, document.title, url.pathname + url.search);
|
|
588
|
-
log("Cleaned OAuth parameters from URL");
|
|
589
|
-
}
|
|
590
|
-
};
|
|
628
|
+
const isDevMode = () => isDevelopment(debug);
|
|
629
|
+
const cleanOAuthParams = () => cleanOAuthParamsFromUrl();
|
|
591
630
|
useEffect(() => {
|
|
592
631
|
const handleOnline = () => {
|
|
593
632
|
log("Network came back online");
|
|
@@ -598,7 +637,7 @@ function BasicProvider({
|
|
|
598
637
|
if (token) {
|
|
599
638
|
const refreshToken = token.refresh_token || localStorage.getItem("basic_refresh_token");
|
|
600
639
|
if (refreshToken) {
|
|
601
|
-
fetchToken(refreshToken).catch((error2) => {
|
|
640
|
+
fetchToken(refreshToken, true).catch((error2) => {
|
|
602
641
|
log("Retry refresh failed:", error2);
|
|
603
642
|
});
|
|
604
643
|
}
|
|
@@ -624,9 +663,6 @@ function BasicProvider({
|
|
|
624
663
|
syncRef.current.syncable.on("statusChanged", (status, url) => {
|
|
625
664
|
setDbStatus(getSyncStatus(status));
|
|
626
665
|
});
|
|
627
|
-
syncRef.current.syncable.getStatus().then((status) => {
|
|
628
|
-
setDbStatus(getSyncStatus(status));
|
|
629
|
-
});
|
|
630
666
|
if (options.shouldConnect) {
|
|
631
667
|
setShouldConnect(true);
|
|
632
668
|
} else {
|
|
@@ -636,17 +672,15 @@ function BasicProvider({
|
|
|
636
672
|
}
|
|
637
673
|
}
|
|
638
674
|
async function checkSchema() {
|
|
639
|
-
const
|
|
640
|
-
if (!
|
|
641
|
-
log("Basic Schema is invalid!", valid.errors);
|
|
642
|
-
console.group("Schema Errors");
|
|
675
|
+
const result = await validateAndCheckSchema(schema);
|
|
676
|
+
if (!result.isValid) {
|
|
643
677
|
let errorMessage = "";
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
678
|
+
if (result.errors) {
|
|
679
|
+
result.errors.forEach((error2, index) => {
|
|
680
|
+
errorMessage += `${index + 1}: ${error2.message} - at ${error2.instancePath}
|
|
647
681
|
`;
|
|
648
|
-
|
|
649
|
-
|
|
682
|
+
});
|
|
683
|
+
}
|
|
650
684
|
setError({
|
|
651
685
|
code: "schema_invalid",
|
|
652
686
|
title: "Basic Schema is invalid!",
|
|
@@ -655,17 +689,10 @@ function BasicProvider({
|
|
|
655
689
|
setIsReady(true);
|
|
656
690
|
return null;
|
|
657
691
|
}
|
|
658
|
-
|
|
659
|
-
if (schema.version !== 0) {
|
|
660
|
-
schemaStatus = await getSchemaStatus(schema);
|
|
661
|
-
log("schemaStatus", schemaStatus);
|
|
662
|
-
} else {
|
|
663
|
-
log("schema not published - at version 0");
|
|
664
|
-
}
|
|
665
|
-
if (schemaStatus.valid) {
|
|
692
|
+
if (result.schemaStatus.valid) {
|
|
666
693
|
initDb({ shouldConnect: true });
|
|
667
694
|
} else {
|
|
668
|
-
log("Schema is invalid!", schemaStatus);
|
|
695
|
+
log("Schema is invalid!", result.schemaStatus);
|
|
669
696
|
initDb({ shouldConnect: false });
|
|
670
697
|
}
|
|
671
698
|
checkForNewVersion();
|
|
@@ -677,43 +704,61 @@ function BasicProvider({
|
|
|
677
704
|
}
|
|
678
705
|
}, []);
|
|
679
706
|
useEffect(() => {
|
|
680
|
-
|
|
681
|
-
|
|
707
|
+
async function connectToDb() {
|
|
708
|
+
if (token && syncRef.current && isSignedIn && shouldConnect) {
|
|
709
|
+
const tok = await getToken();
|
|
710
|
+
if (!tok) {
|
|
711
|
+
log("no token found");
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
log("connecting to db...");
|
|
715
|
+
syncRef.current?.connect({ access_token: tok }).catch((e) => {
|
|
716
|
+
log("error connecting to db", e);
|
|
717
|
+
});
|
|
718
|
+
}
|
|
682
719
|
}
|
|
720
|
+
connectToDb();
|
|
683
721
|
}, [isSignedIn, shouldConnect]);
|
|
684
|
-
const connectToDb = async () => {
|
|
685
|
-
const tok = await getToken();
|
|
686
|
-
if (!tok) {
|
|
687
|
-
log("no token found");
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
log("connecting to db...");
|
|
691
|
-
syncRef.current.connect({ access_token: tok }).catch((e) => {
|
|
692
|
-
log("error connecting to db", e);
|
|
693
|
-
});
|
|
694
|
-
};
|
|
695
722
|
useEffect(() => {
|
|
696
723
|
const initializeAuth = async () => {
|
|
697
724
|
await storageAdapter.set(STORAGE_KEYS.DEBUG, debug ? "true" : "false");
|
|
725
|
+
try {
|
|
726
|
+
const versionUpdater = createVersionUpdater(storageAdapter, version, getMigrations());
|
|
727
|
+
const updateResult = await versionUpdater.checkAndUpdate();
|
|
728
|
+
if (updateResult.updated) {
|
|
729
|
+
log(`App updated from ${updateResult.fromVersion} to ${updateResult.toVersion}`);
|
|
730
|
+
} else {
|
|
731
|
+
log(`App version ${updateResult.toVersion} is current`);
|
|
732
|
+
}
|
|
733
|
+
} catch (error2) {
|
|
734
|
+
log("Version update failed:", error2);
|
|
735
|
+
}
|
|
698
736
|
try {
|
|
699
737
|
if (window.location.search.includes("code")) {
|
|
700
|
-
let code = window.location?.search?.split("code=")[1]
|
|
738
|
+
let code = window.location?.search?.split("code=")[1]?.split("&")[0];
|
|
739
|
+
if (!code)
|
|
740
|
+
return;
|
|
701
741
|
const state = await storageAdapter.get(STORAGE_KEYS.AUTH_STATE);
|
|
702
|
-
|
|
742
|
+
const urlState = window.location.search.split("state=")[1]?.split("&")[0];
|
|
743
|
+
if (!state || state !== urlState) {
|
|
703
744
|
log("error: auth state does not match");
|
|
704
745
|
setIsAuthReady(true);
|
|
705
746
|
await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
|
|
706
|
-
|
|
747
|
+
cleanOAuthParams();
|
|
707
748
|
return;
|
|
708
749
|
}
|
|
709
750
|
await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
|
|
710
|
-
|
|
711
|
-
fetchToken(code)
|
|
751
|
+
cleanOAuthParams();
|
|
752
|
+
fetchToken(code, false).catch((error2) => {
|
|
753
|
+
log("Error fetching token:", error2);
|
|
754
|
+
});
|
|
712
755
|
} else {
|
|
713
756
|
const refreshToken = await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
|
|
714
757
|
if (refreshToken) {
|
|
715
758
|
log("Found refresh token in storage, attempting to refresh access token");
|
|
716
|
-
fetchToken(refreshToken)
|
|
759
|
+
fetchToken(refreshToken, true).catch((error2) => {
|
|
760
|
+
log("Error fetching refresh token:", error2);
|
|
761
|
+
});
|
|
717
762
|
} else {
|
|
718
763
|
let cookie_token = getCookie("basic_token");
|
|
719
764
|
if (cookie_token !== "") {
|
|
@@ -762,8 +807,8 @@ function BasicProvider({
|
|
|
762
807
|
}
|
|
763
808
|
await storageAdapter.set(STORAGE_KEYS.USER_INFO, JSON.stringify(user2));
|
|
764
809
|
log("Cached user info in storage");
|
|
765
|
-
|
|
766
|
-
|
|
810
|
+
setCookie("basic_access_token", token?.access_token || "", { httpOnly: false });
|
|
811
|
+
setCookie("basic_token", JSON.stringify(token));
|
|
767
812
|
setUser(user2);
|
|
768
813
|
setIsSignedIn(true);
|
|
769
814
|
setIsAuthReady(true);
|
|
@@ -780,19 +825,19 @@ function BasicProvider({
|
|
|
780
825
|
if (isExpired) {
|
|
781
826
|
log("token is expired - refreshing ...");
|
|
782
827
|
try {
|
|
783
|
-
const newToken = await fetchToken(token?.refresh_token);
|
|
784
|
-
fetchUser(newToken
|
|
828
|
+
const newToken = await fetchToken(token?.refresh_token || "", true);
|
|
829
|
+
fetchUser(newToken?.access_token || "");
|
|
785
830
|
} catch (error2) {
|
|
786
831
|
log("Failed to refresh token in checkToken:", error2);
|
|
787
832
|
if (error2.message.includes("offline") || error2.message.includes("Network")) {
|
|
788
833
|
log("Network issue - continuing with expired token until online");
|
|
789
|
-
fetchUser(token
|
|
834
|
+
fetchUser(token?.access_token || "");
|
|
790
835
|
} else {
|
|
791
836
|
setIsAuthReady(true);
|
|
792
837
|
}
|
|
793
838
|
}
|
|
794
839
|
} else {
|
|
795
|
-
fetchUser(token
|
|
840
|
+
fetchUser(token?.access_token || "");
|
|
796
841
|
}
|
|
797
842
|
}
|
|
798
843
|
if (token) {
|
|
@@ -811,14 +856,14 @@ function BasicProvider({
|
|
|
811
856
|
if (!redirectUrl || !redirectUrl.startsWith("http://") && !redirectUrl.startsWith("https://")) {
|
|
812
857
|
throw new Error("Invalid redirect URI provided");
|
|
813
858
|
}
|
|
814
|
-
let
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
859
|
+
let baseUrl = "https://api.basic.tech/auth/authorize";
|
|
860
|
+
baseUrl += `?client_id=${project_id}`;
|
|
861
|
+
baseUrl += `&redirect_uri=${encodeURIComponent(redirectUrl)}`;
|
|
862
|
+
baseUrl += `&response_type=code`;
|
|
863
|
+
baseUrl += `&scope=profile`;
|
|
864
|
+
baseUrl += `&state=${randomState}`;
|
|
820
865
|
log("Generated sign-in link successfully");
|
|
821
|
-
return
|
|
866
|
+
return baseUrl;
|
|
822
867
|
} catch (error2) {
|
|
823
868
|
log("Error generating sign-in link:", error2);
|
|
824
869
|
throw error2;
|
|
@@ -840,7 +885,7 @@ function BasicProvider({
|
|
|
840
885
|
window.location.href = signInLink;
|
|
841
886
|
} catch (error2) {
|
|
842
887
|
log("Error during sign-in:", error2);
|
|
843
|
-
if (
|
|
888
|
+
if (isDevMode()) {
|
|
844
889
|
setError({
|
|
845
890
|
code: "signin_error",
|
|
846
891
|
title: "Sign-in Failed",
|
|
@@ -864,8 +909,8 @@ function BasicProvider({
|
|
|
864
909
|
}
|
|
865
910
|
}
|
|
866
911
|
await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
|
|
867
|
-
|
|
868
|
-
const token2 = await fetchToken(code);
|
|
912
|
+
cleanOAuthParams();
|
|
913
|
+
const token2 = await fetchToken(code, false);
|
|
869
914
|
if (token2) {
|
|
870
915
|
log("signinWithCode successful");
|
|
871
916
|
return { success: true };
|
|
@@ -885,16 +930,16 @@ function BasicProvider({
|
|
|
885
930
|
setUser({});
|
|
886
931
|
setIsSignedIn(false);
|
|
887
932
|
setToken(null);
|
|
888
|
-
|
|
889
|
-
|
|
933
|
+
clearCookie("basic_token");
|
|
934
|
+
clearCookie("basic_access_token");
|
|
890
935
|
await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
|
|
891
936
|
await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
|
|
892
937
|
await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
|
|
893
938
|
if (syncRef.current) {
|
|
894
939
|
(async () => {
|
|
895
940
|
try {
|
|
896
|
-
await syncRef.current
|
|
897
|
-
await syncRef.current
|
|
941
|
+
await syncRef.current?.close();
|
|
942
|
+
await syncRef.current?.delete({ disableAutoOpen: false });
|
|
898
943
|
syncRef.current = null;
|
|
899
944
|
window?.location?.reload();
|
|
900
945
|
} catch (error2) {
|
|
@@ -910,7 +955,7 @@ function BasicProvider({
|
|
|
910
955
|
if (refreshToken) {
|
|
911
956
|
log("No token in memory, attempting to refresh from storage");
|
|
912
957
|
try {
|
|
913
|
-
const newToken = await fetchToken(refreshToken);
|
|
958
|
+
const newToken = await fetchToken(refreshToken, true);
|
|
914
959
|
if (newToken?.access_token) {
|
|
915
960
|
return newToken.access_token;
|
|
916
961
|
}
|
|
@@ -937,7 +982,7 @@ function BasicProvider({
|
|
|
937
982
|
const refreshToken = token?.refresh_token || await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
|
|
938
983
|
if (refreshToken) {
|
|
939
984
|
try {
|
|
940
|
-
const newToken = await fetchToken(refreshToken);
|
|
985
|
+
const newToken = await fetchToken(refreshToken, true);
|
|
941
986
|
return newToken?.access_token || "";
|
|
942
987
|
} catch (error2) {
|
|
943
988
|
log("Failed to refresh expired token:", error2);
|
|
@@ -953,33 +998,26 @@ function BasicProvider({
|
|
|
953
998
|
}
|
|
954
999
|
return token?.access_token || "";
|
|
955
1000
|
};
|
|
956
|
-
|
|
957
|
-
let cookieValue = "";
|
|
958
|
-
if (document.cookie && document.cookie !== "") {
|
|
959
|
-
const cookies = document.cookie.split(";");
|
|
960
|
-
for (let i = 0; i < cookies.length; i++) {
|
|
961
|
-
const cookie = cookies[i].trim();
|
|
962
|
-
if (cookie.substring(0, name.length + 1) === name + "=") {
|
|
963
|
-
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
964
|
-
break;
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
return cookieValue;
|
|
969
|
-
}
|
|
970
|
-
const fetchToken = async (code) => {
|
|
1001
|
+
const fetchToken = async (codeOrRefreshToken, isRefreshToken = false) => {
|
|
971
1002
|
try {
|
|
972
1003
|
if (!isOnline) {
|
|
973
1004
|
log("Network is offline, marking refresh as pending");
|
|
974
1005
|
setPendingRefresh(true);
|
|
975
1006
|
throw new Error("Network offline - refresh will be retried when online");
|
|
976
1007
|
}
|
|
1008
|
+
const requestBody = isRefreshToken ? {
|
|
1009
|
+
grant_type: "refresh_token",
|
|
1010
|
+
refresh_token: codeOrRefreshToken
|
|
1011
|
+
} : {
|
|
1012
|
+
grant_type: "authorization_code",
|
|
1013
|
+
code: codeOrRefreshToken
|
|
1014
|
+
};
|
|
977
1015
|
const token2 = await fetch("https://api.basic.tech/auth/token", {
|
|
978
1016
|
method: "POST",
|
|
979
1017
|
headers: {
|
|
980
1018
|
"Content-Type": "application/json"
|
|
981
1019
|
},
|
|
982
|
-
body: JSON.stringify(
|
|
1020
|
+
body: JSON.stringify(requestBody)
|
|
983
1021
|
}).then((response) => response.json()).catch((error2) => {
|
|
984
1022
|
log("Network error fetching token:", error2);
|
|
985
1023
|
if (!isOnline) {
|
|
@@ -996,8 +1034,8 @@ function BasicProvider({
|
|
|
996
1034
|
}
|
|
997
1035
|
await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
|
|
998
1036
|
await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
|
|
999
|
-
|
|
1000
|
-
|
|
1037
|
+
clearCookie("basic_token");
|
|
1038
|
+
clearCookie("basic_access_token");
|
|
1001
1039
|
setUser({});
|
|
1002
1040
|
setIsSignedIn(false);
|
|
1003
1041
|
setToken(null);
|
|
@@ -1010,7 +1048,7 @@ function BasicProvider({
|
|
|
1010
1048
|
await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token2.refresh_token);
|
|
1011
1049
|
log("Updated refresh token in storage");
|
|
1012
1050
|
}
|
|
1013
|
-
|
|
1051
|
+
setCookie("basic_access_token", token2.access_token, { httpOnly: false });
|
|
1014
1052
|
log("Updated access token in cookie");
|
|
1015
1053
|
}
|
|
1016
1054
|
return token2;
|
|
@@ -1019,8 +1057,8 @@ function BasicProvider({
|
|
|
1019
1057
|
if (!error2.message.includes("offline") && !error2.message.includes("Network")) {
|
|
1020
1058
|
await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
|
|
1021
1059
|
await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
|
|
1022
|
-
|
|
1023
|
-
|
|
1060
|
+
clearCookie("basic_token");
|
|
1061
|
+
clearCookie("basic_access_token");
|
|
1024
1062
|
setUser({});
|
|
1025
1063
|
setIsSignedIn(false);
|
|
1026
1064
|
setToken(null);
|
|
@@ -1029,35 +1067,6 @@ function BasicProvider({
|
|
|
1029
1067
|
throw error2;
|
|
1030
1068
|
}
|
|
1031
1069
|
};
|
|
1032
|
-
const db_ = (tableName) => {
|
|
1033
|
-
const checkSignIn = () => {
|
|
1034
|
-
if (!isSignedIn) {
|
|
1035
|
-
throw new Error("cannot use db. user not logged in.");
|
|
1036
|
-
}
|
|
1037
|
-
};
|
|
1038
|
-
return {
|
|
1039
|
-
get: async () => {
|
|
1040
|
-
checkSignIn();
|
|
1041
|
-
const tok = await getToken();
|
|
1042
|
-
return get({ projectId: project_id, accountId: user.id, tableName, token: tok });
|
|
1043
|
-
},
|
|
1044
|
-
add: async (value) => {
|
|
1045
|
-
checkSignIn();
|
|
1046
|
-
const tok = await getToken();
|
|
1047
|
-
return add({ projectId: project_id, accountId: user.id, tableName, value, token: tok });
|
|
1048
|
-
},
|
|
1049
|
-
update: async (id, value) => {
|
|
1050
|
-
checkSignIn();
|
|
1051
|
-
const tok = await getToken();
|
|
1052
|
-
return update({ projectId: project_id, accountId: user.id, tableName, id, value, token: tok });
|
|
1053
|
-
},
|
|
1054
|
-
delete: async (id) => {
|
|
1055
|
-
checkSignIn();
|
|
1056
|
-
const tok = await getToken();
|
|
1057
|
-
return deleteRecord({ projectId: project_id, accountId: user.id, tableName, id, token: tok });
|
|
1058
|
-
}
|
|
1059
|
-
};
|
|
1060
|
-
};
|
|
1061
1070
|
const noDb = {
|
|
1062
1071
|
collection: () => {
|
|
1063
1072
|
throw new Error("no basicdb found - initialization failed. double check your schema.");
|
|
@@ -1076,7 +1085,7 @@ function BasicProvider({
|
|
|
1076
1085
|
db: syncRef.current ? syncRef.current : noDb,
|
|
1077
1086
|
dbStatus
|
|
1078
1087
|
}, children: [
|
|
1079
|
-
error &&
|
|
1088
|
+
error && isDevMode() && /* @__PURE__ */ jsx(ErrorDisplay, { error }),
|
|
1080
1089
|
isReady && children
|
|
1081
1090
|
] });
|
|
1082
1091
|
}
|