@basictech/react 0.7.0-beta.1 → 0.7.0-beta.2

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/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,490 @@ var BasicSync = class extends Dexie2 {
358
250
  }
359
251
  };
360
252
 
361
- // src/db.ts
362
- var baseUrl = "https://api.basic.tech";
363
- async function get({ projectId, accountId, tableName, token }) {
364
- const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;
365
- const response = await fetch(url, {
366
- headers: {
367
- "Authorization": `Bearer ${token}`
253
+ // src/db_ts.ts
254
+ var DBError = class extends Error {
255
+ constructor(message, status, response, originalError) {
256
+ super(message);
257
+ this.status = status;
258
+ this.response = response;
259
+ this.originalError = originalError;
260
+ this.name = "DBError";
261
+ }
262
+ };
263
+ var QueryBuilder = class {
264
+ constructor(tableClient, tableSchema) {
265
+ this.tableClient = tableClient;
266
+ this.tableSchema = tableSchema;
267
+ }
268
+ params = {};
269
+ // Reserved fields that are always allowed
270
+ reservedFields = ["created_at", "updated_at", "id"];
271
+ // Validate field existence in schema
272
+ validateField(field) {
273
+ if (this.tableSchema && !this.reservedFields.includes(field)) {
274
+ if (!this.tableSchema.fields || !(field in this.tableSchema.fields)) {
275
+ throw new Error(`Invalid field: "${field}". Field does not exist in table schema.`);
276
+ }
368
277
  }
369
- });
370
- return response.json();
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
+ }
279
+ // Validate operator based on field type
280
+ validateOperator(field, operator, value) {
281
+ if (!this.tableSchema || this.reservedFields.includes(field)) {
282
+ return;
402
283
  }
403
- });
404
- return response.json();
405
- }
406
-
407
- // src/AuthContext.tsx
408
- import { validateSchema as validateSchema3, compareSchemas } from "@basictech/schema";
284
+ const fieldInfo = this.tableSchema.fields[field];
285
+ if (!fieldInfo)
286
+ return;
287
+ switch (operator) {
288
+ case "gt":
289
+ case "gte":
290
+ case "lt":
291
+ case "lte":
292
+ if (fieldInfo.type !== "number" && fieldInfo.type !== "string") {
293
+ throw new Error(`Operator "${operator}" can only be used with number or string fields. Field "${field}" is type "${fieldInfo.type}".`);
294
+ }
295
+ break;
296
+ case "like":
297
+ case "ilike":
298
+ if (fieldInfo.type !== "string") {
299
+ throw new Error(`Operator "${operator}" can only be used with string fields. Field "${field}" is type "${fieldInfo.type}".`);
300
+ }
301
+ if (typeof value !== "string") {
302
+ throw new Error(`Operator "${operator}" requires a string value. Received: ${typeof value}`);
303
+ }
304
+ break;
305
+ case "in":
306
+ if (!Array.isArray(value)) {
307
+ throw new Error(`Operator "in" requires an array value. Received: ${typeof value}`);
308
+ }
309
+ break;
310
+ case "is":
311
+ if (value !== null && typeof value !== "boolean") {
312
+ throw new Error(`Operator "is" requires null or boolean. Received: ${typeof value}`);
313
+ }
314
+ break;
315
+ }
316
+ }
317
+ // Add ordering to query with schema validation
318
+ order(field, direction = "asc") {
319
+ this.validateField(field);
320
+ this.params.order = `${field}.${direction}`;
321
+ return this;
322
+ }
323
+ // Add filtering to query
324
+ filter(conditions) {
325
+ if (!this.params.filters) {
326
+ this.params.filters = {};
327
+ }
328
+ for (const [field, condition] of Object.entries(conditions)) {
329
+ this.validateField(field);
330
+ if (condition === null || typeof condition !== "object") {
331
+ this.params.filters[field] = condition;
332
+ } else {
333
+ this.params.filters[field] = condition;
334
+ }
335
+ }
336
+ return this;
337
+ }
338
+ // Add limit to query
339
+ limit(count) {
340
+ this.params.limit = count;
341
+ return this;
342
+ }
343
+ // Add offset to query for pagination
344
+ offset(count) {
345
+ this.params.offset = count;
346
+ return this;
347
+ }
348
+ // Auto-execute when awaited
349
+ then(onfulfilled, onrejected) {
350
+ return this.tableClient.executeQuery(this.params).then(onfulfilled, onrejected);
351
+ }
352
+ // Auto-execute when awaited with catch
353
+ catch(onrejected) {
354
+ return this.tableClient.executeQuery(this.params).catch(onrejected);
355
+ }
356
+ // Auto-execute when awaited with finally
357
+ finally(onfinally) {
358
+ return this.tableClient.executeQuery(this.params).finally(onfinally);
359
+ }
360
+ };
361
+ var TableClient = class {
362
+ constructor(baseUrl, projectId, token, table, getToken, schema) {
363
+ this.baseUrl = baseUrl;
364
+ this.projectId = projectId;
365
+ this.token = token;
366
+ this.table = table;
367
+ this.getToken = getToken;
368
+ this.schema = schema;
369
+ if (schema && schema.tables && schema.tables[table]) {
370
+ this.tableSchema = schema.tables[table];
371
+ }
372
+ }
373
+ tableSchema;
374
+ async headers() {
375
+ const token = await this.getToken();
376
+ return {
377
+ Authorization: `Bearer ${token}`,
378
+ "Content-Type": "application/json"
379
+ };
380
+ }
381
+ async handleRequest(request) {
382
+ try {
383
+ const res = await request;
384
+ if (!res.ok) {
385
+ let errorMessage = `Request failed with status ${res.status}`;
386
+ let errorData;
387
+ try {
388
+ const json2 = await res.json();
389
+ errorData = json2;
390
+ if (json2.error || json2.message) {
391
+ const errorDetails = typeof json2.error === "object" ? JSON.stringify(json2.error) : json2.error;
392
+ const messageDetails = typeof json2.message === "object" ? JSON.stringify(json2.message) : json2.message;
393
+ errorMessage = `${res.status} ${res.statusText}: ${messageDetails || errorDetails || "Unknown error"}`;
394
+ }
395
+ } catch (e) {
396
+ console.log("Failed to parse error response:", e);
397
+ errorMessage = `${res.status} ${res.statusText}`;
398
+ }
399
+ throw new DBError(
400
+ errorMessage,
401
+ res.status,
402
+ errorData
403
+ );
404
+ }
405
+ const json = await res.json();
406
+ return json.data;
407
+ } catch (error) {
408
+ console.log("Caught error:", error);
409
+ if (error instanceof Error) {
410
+ console.log("Error type:", error.constructor.name);
411
+ console.log("Error stack:", error.stack);
412
+ }
413
+ if (error instanceof DBError) {
414
+ throw error;
415
+ }
416
+ if (error instanceof TypeError && error.message === "Network request failed") {
417
+ throw new DBError(
418
+ "Network request failed. Please check your internet connection and try again.",
419
+ void 0,
420
+ void 0,
421
+ error
422
+ );
423
+ }
424
+ throw new DBError(
425
+ `Unexpected error: ${error instanceof Error ? error.message : "Unknown error"}`,
426
+ void 0,
427
+ void 0,
428
+ error instanceof Error ? error : void 0
429
+ );
430
+ }
431
+ }
432
+ // Build query string from query options
433
+ buildQueryParams(query) {
434
+ if (!query)
435
+ return "";
436
+ const params = [];
437
+ if (query.id) {
438
+ params.push(`id=${query.id}`);
439
+ }
440
+ if (query.filters) {
441
+ for (const [field, condition] of Object.entries(query.filters)) {
442
+ this.addFilterParam(params, field, condition);
443
+ }
444
+ }
445
+ if (query.order) {
446
+ params.push(`order=${query.order}`);
447
+ }
448
+ if (query.limit !== void 0 && query.limit >= 0) {
449
+ params.push(`limit=${query.limit}`);
450
+ }
451
+ if (query.offset !== void 0 && query.offset >= 0) {
452
+ params.push(`offset=${query.offset}`);
453
+ }
454
+ return params.length > 0 ? `?${params.join("&")}` : "";
455
+ }
456
+ // Helper method to build filter parameters
457
+ addFilterParam(params, field, condition, negate = false) {
458
+ if (condition === null || typeof condition !== "object") {
459
+ if (condition === null) {
460
+ params.push(`${field}=${negate ? "not." : ""}is.null`);
461
+ } else if (typeof condition === "boolean") {
462
+ params.push(`${field}=${negate ? "not." : ""}is.${condition}`);
463
+ } else if (typeof condition === "number") {
464
+ params.push(`${field}=${negate ? "not." : ""}eq.${condition}`);
465
+ } else {
466
+ params.push(`${field}=${negate ? "not." : ""}eq.${encodeURIComponent(String(condition))}`);
467
+ }
468
+ return;
469
+ }
470
+ const operatorObj = condition;
471
+ if (operatorObj.not) {
472
+ this.addFilterParam(params, field, operatorObj.not, true);
473
+ return;
474
+ }
475
+ for (const [op, value] of Object.entries(operatorObj)) {
476
+ if (op === "not")
477
+ continue;
478
+ const operator = op;
479
+ if (value === null) {
480
+ params.push(`${field}=${negate ? "not." : ""}is.null`);
481
+ } else if (operator === "in" && Array.isArray(value)) {
482
+ params.push(`${field}=${negate ? "not." : ""}in.${value.join(",")}`);
483
+ } else if (operator === "is") {
484
+ if (typeof value === "boolean") {
485
+ params.push(`${field}=${negate ? "not." : ""}is.${value}`);
486
+ } else {
487
+ params.push(`${field}=${negate ? "not." : ""}is.null`);
488
+ }
489
+ } else {
490
+ const paramValue = typeof value === "string" ? encodeURIComponent(value) : String(value);
491
+ params.push(`${field}=${negate ? "not." : ""}${operator}.${paramValue}`);
492
+ }
493
+ }
494
+ }
495
+ // Internal method to execute a query with options
496
+ async executeQuery(options) {
497
+ const params = this.buildQueryParams(options);
498
+ const headers = await this.headers();
499
+ return this.handleRequest(
500
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}${params}`, {
501
+ headers
502
+ })
503
+ );
504
+ }
505
+ // Public method to start building a query
506
+ getAll() {
507
+ return new QueryBuilder(this, this.tableSchema);
508
+ }
509
+ // Get a specific item by ID
510
+ async get(id) {
511
+ const headers = await this.headers();
512
+ return this.handleRequest(
513
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}/${id}`, {
514
+ headers
515
+ })
516
+ );
517
+ }
518
+ async create(value) {
519
+ const headers = await this.headers();
520
+ return this.handleRequest(
521
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}`, {
522
+ method: "POST",
523
+ headers,
524
+ body: JSON.stringify({ value })
525
+ })
526
+ );
527
+ }
528
+ async update(id, value) {
529
+ const headers = await this.headers();
530
+ return this.handleRequest(
531
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}/${id}`, {
532
+ method: "PATCH",
533
+ headers,
534
+ body: JSON.stringify({ value })
535
+ })
536
+ );
537
+ }
538
+ async replace(id, value) {
539
+ const headers = await this.headers();
540
+ return this.handleRequest(
541
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}/${id}`, {
542
+ method: "PUT",
543
+ headers,
544
+ body: JSON.stringify({ value })
545
+ })
546
+ );
547
+ }
548
+ async delete(id) {
549
+ const token = await this.getToken();
550
+ const headers = {
551
+ Authorization: `Bearer ${token}`
552
+ };
553
+ return this.handleRequest(
554
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}/${id}`, {
555
+ method: "DELETE",
556
+ headers
557
+ })
558
+ );
559
+ }
560
+ };
561
+ var BasicDBSDK = class {
562
+ projectId;
563
+ getToken;
564
+ baseUrl;
565
+ schema;
566
+ tableNames;
567
+ constructor(config) {
568
+ this.projectId = config.project_id;
569
+ if (config.getToken) {
570
+ this.getToken = config.getToken;
571
+ } else if (config.token) {
572
+ this.getToken = async () => config.token;
573
+ } else {
574
+ throw new Error("Either token or getToken must be provided");
575
+ }
576
+ this.baseUrl = config.baseUrl || "https://api.basic.tech";
577
+ this.schema = config.schema;
578
+ this.tableNames = Object.keys(this.schema.tables);
579
+ }
580
+ // Primary method - table access
581
+ table(name) {
582
+ if (!this.tableNames.includes(name)) {
583
+ throw new Error(`Table '${name}' not found in schema. Available tables: ${this.tableNames.join(", ")}`);
584
+ }
585
+ return new TableClient(
586
+ this.baseUrl,
587
+ this.projectId,
588
+ "",
589
+ // Empty placeholder, will be replaced in headers() method
590
+ name,
591
+ this.getToken,
592
+ this.schema
593
+ // Pass the entire schema to the TableClient
594
+ );
595
+ }
596
+ get tables() {
597
+ return {};
598
+ }
599
+ fields(table) {
600
+ const tableSchema = this.schema.tables[table];
601
+ if (!tableSchema) {
602
+ throw new Error(`Table '${table}' not found in schema`);
603
+ }
604
+ return Object.keys(tableSchema.fields);
605
+ }
606
+ };
409
607
 
410
608
  // package.json
411
- var version = "0.6.0";
609
+ var version = "0.7.0-beta.1";
412
610
 
413
- // src/AuthContext.tsx
414
- import { jsx, jsxs } from "react/jsx-runtime";
611
+ // src/updater/versionUpdater.ts
612
+ var VersionUpdater = class {
613
+ storage;
614
+ currentVersion;
615
+ migrations;
616
+ versionKey = "basic_app_version";
617
+ constructor(storage, currentVersion, migrations = []) {
618
+ this.storage = storage;
619
+ this.currentVersion = currentVersion;
620
+ this.migrations = migrations.sort((a, b) => this.compareVersions(a.fromVersion, b.fromVersion));
621
+ }
622
+ /**
623
+ * Check current stored version and run migrations if needed
624
+ * Only compares major.minor versions, ignoring beta/prerelease parts
625
+ * Example: "0.7.0-beta.1" and "0.7.0" are treated as the same version
626
+ */
627
+ async checkAndUpdate() {
628
+ const storedVersion = await this.getStoredVersion();
629
+ if (!storedVersion) {
630
+ await this.setStoredVersion(this.currentVersion);
631
+ return { updated: false, toVersion: this.currentVersion };
632
+ }
633
+ if (storedVersion === this.currentVersion) {
634
+ return { updated: false, toVersion: this.currentVersion };
635
+ }
636
+ const migrationsToRun = this.getMigrationsToRun(storedVersion, this.currentVersion);
637
+ if (migrationsToRun.length === 0) {
638
+ await this.setStoredVersion(this.currentVersion);
639
+ return { updated: true, fromVersion: storedVersion, toVersion: this.currentVersion };
640
+ }
641
+ for (const migration of migrationsToRun) {
642
+ try {
643
+ console.log(`Running migration from ${migration.fromVersion} to ${migration.toVersion}`);
644
+ await migration.migrate(this.storage);
645
+ } catch (error) {
646
+ console.error(`Migration failed from ${migration.fromVersion} to ${migration.toVersion}:`, error);
647
+ throw new Error(`Migration failed: ${error}`);
648
+ }
649
+ }
650
+ await this.setStoredVersion(this.currentVersion);
651
+ return { updated: true, fromVersion: storedVersion, toVersion: this.currentVersion };
652
+ }
653
+ async getStoredVersion() {
654
+ try {
655
+ const versionData = await this.storage.get(this.versionKey);
656
+ if (!versionData)
657
+ return null;
658
+ const versionInfo = JSON.parse(versionData);
659
+ return versionInfo.version;
660
+ } catch (error) {
661
+ console.warn("Failed to get stored version:", error);
662
+ return null;
663
+ }
664
+ }
665
+ async setStoredVersion(version2) {
666
+ const versionInfo = {
667
+ version: version2,
668
+ lastUpdated: Date.now()
669
+ };
670
+ await this.storage.set(this.versionKey, JSON.stringify(versionInfo));
671
+ }
672
+ getMigrationsToRun(fromVersion, toVersion) {
673
+ return this.migrations.filter((migration) => {
674
+ const storedLessThanMigrationTo = this.compareVersions(fromVersion, migration.toVersion) < 0;
675
+ const currentGreaterThanOrEqualMigrationTo = this.compareVersions(toVersion, migration.toVersion) >= 0;
676
+ console.log(`Checking migration ${migration.fromVersion} \u2192 ${migration.toVersion}:`);
677
+ console.log(` stored ${fromVersion} < migration.to ${migration.toVersion}: ${storedLessThanMigrationTo}`);
678
+ console.log(` current ${toVersion} >= migration.to ${migration.toVersion}: ${currentGreaterThanOrEqualMigrationTo}`);
679
+ const shouldRun = storedLessThanMigrationTo && currentGreaterThanOrEqualMigrationTo;
680
+ console.log(` Should run: ${shouldRun}`);
681
+ return shouldRun;
682
+ });
683
+ }
684
+ /**
685
+ * Simple semantic version comparison (major.minor only, ignoring beta/prerelease)
686
+ * Returns: -1 if a < b, 0 if a === b, 1 if a > b
687
+ */
688
+ compareVersions(a, b) {
689
+ const aMajorMinor = this.extractMajorMinor(a);
690
+ const bMajorMinor = this.extractMajorMinor(b);
691
+ if (aMajorMinor.major !== bMajorMinor.major) {
692
+ return aMajorMinor.major - bMajorMinor.major;
693
+ }
694
+ return aMajorMinor.minor - bMajorMinor.minor;
695
+ }
696
+ /**
697
+ * Extract major.minor from version string, ignoring beta/prerelease
698
+ * Examples: "0.7.0-beta.1" -> {major: 0, minor: 7}
699
+ * "1.2.3" -> {major: 1, minor: 2}
700
+ */
701
+ extractMajorMinor(version2) {
702
+ const cleanVersion = version2.split("-")[0]?.split("+")[0] || version2;
703
+ const parts = cleanVersion.split(".").map(Number);
704
+ return {
705
+ major: parts[0] || 0,
706
+ minor: parts[1] || 0
707
+ };
708
+ }
709
+ /**
710
+ * Add a migration to the updater
711
+ */
712
+ addMigration(migration) {
713
+ this.migrations.push(migration);
714
+ this.migrations.sort((a, b) => this.compareVersions(a.fromVersion, b.fromVersion));
715
+ }
716
+ };
717
+ function createVersionUpdater(storage, currentVersion, migrations = []) {
718
+ return new VersionUpdater(storage, currentVersion, migrations);
719
+ }
720
+
721
+ // src/updater/updateMigrations.ts
722
+ var addMigrationTimestamp = {
723
+ fromVersion: "0.6.0",
724
+ toVersion: "0.7.0",
725
+ async migrate(storage) {
726
+ console.log("Running test migration");
727
+ storage.set("test_migration", "true");
728
+ }
729
+ };
730
+ function getMigrations() {
731
+ return [
732
+ addMigrationTimestamp
733
+ ];
734
+ }
735
+
736
+ // src/utils/storage.ts
415
737
  var LocalStorageAdapter = class {
416
738
  async get(key) {
417
739
  return localStorage.getItem(key);
@@ -423,25 +745,113 @@ var LocalStorageAdapter = class {
423
745
  localStorage.removeItem(key);
424
746
  }
425
747
  };
426
- var BasicContext = createContext({
427
- unicorn: "\u{1F984}",
428
- isAuthReady: false,
429
- isSignedIn: false,
430
- user: null,
431
- signout: () => Promise.resolve(),
432
- signin: () => Promise.resolve(),
433
- signinWithCode: () => new Promise(() => {
434
- }),
435
- getToken: () => new Promise(() => {
436
- }),
437
- getSignInLink: () => Promise.resolve(""),
438
- db: {},
439
- dbStatus: "LOADING" /* LOADING */
440
- });
748
+ var STORAGE_KEYS = {
749
+ REFRESH_TOKEN: "basic_refresh_token",
750
+ USER_INFO: "basic_user_info",
751
+ AUTH_STATE: "basic_auth_state",
752
+ DEBUG: "basic_debug"
753
+ };
754
+ function getCookie(name) {
755
+ let cookieValue = "";
756
+ if (document.cookie && document.cookie !== "") {
757
+ const cookies = document.cookie.split(";");
758
+ for (let i = 0; i < cookies.length; i++) {
759
+ const cookie = cookies[i]?.trim();
760
+ if (cookie && cookie.substring(0, name.length + 1) === name + "=") {
761
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
762
+ break;
763
+ }
764
+ }
765
+ }
766
+ return cookieValue;
767
+ }
768
+ function setCookie(name, value, options) {
769
+ const opts = {
770
+ secure: true,
771
+ sameSite: "Strict",
772
+ httpOnly: false,
773
+ ...options
774
+ };
775
+ let cookieString = `${name}=${value}`;
776
+ if (opts.secure)
777
+ cookieString += "; Secure";
778
+ if (opts.sameSite)
779
+ cookieString += `; SameSite=${opts.sameSite}`;
780
+ if (opts.httpOnly)
781
+ cookieString += "; HttpOnly";
782
+ document.cookie = cookieString;
783
+ }
784
+ function clearCookie(name) {
785
+ document.cookie = `${name}=; Secure; SameSite=Strict`;
786
+ }
787
+
788
+ // src/utils/network.ts
789
+ function isDevelopment(debug) {
790
+ 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;
791
+ }
792
+ async function checkForNewVersion() {
793
+ try {
794
+ const isBeta = version.includes("beta");
795
+ const response = await fetch(`https://registry.npmjs.org/@basictech/react/${isBeta ? "beta" : "latest"}`);
796
+ if (!response.ok) {
797
+ throw new Error("Failed to fetch version from npm");
798
+ }
799
+ const data = await response.json();
800
+ const latestVersion = data.version;
801
+ if (latestVersion !== version) {
802
+ console.warn("[basic] New version available:", latestVersion, `
803
+ run "npm install @basictech/react@${latestVersion}" to update`);
804
+ }
805
+ if (isBeta) {
806
+ log("thank you for being on basictech/react beta :)");
807
+ }
808
+ return {
809
+ hasNewVersion: version !== latestVersion,
810
+ latestVersion,
811
+ currentVersion: version
812
+ };
813
+ } catch (error) {
814
+ log("Error checking for new version:", error);
815
+ return {
816
+ hasNewVersion: false,
817
+ latestVersion: null,
818
+ currentVersion: null
819
+ };
820
+ }
821
+ }
822
+ function cleanOAuthParamsFromUrl() {
823
+ if (window.location.search.includes("code") || window.location.search.includes("state")) {
824
+ const url = new URL(window.location.href);
825
+ url.searchParams.delete("code");
826
+ url.searchParams.delete("state");
827
+ window.history.pushState({}, document.title, url.pathname + url.search);
828
+ log("Cleaned OAuth parameters from URL");
829
+ }
830
+ }
831
+ function getSyncStatus(statusCode) {
832
+ switch (statusCode) {
833
+ case -1:
834
+ return "ERROR";
835
+ case 0:
836
+ return "OFFLINE";
837
+ case 1:
838
+ return "CONNECTING";
839
+ case 2:
840
+ return "ONLINE";
841
+ case 3:
842
+ return "SYNCING";
843
+ case 4:
844
+ return "ERROR_WILL_RETRY";
845
+ default:
846
+ return "UNKNOWN";
847
+ }
848
+ }
849
+
850
+ // src/utils/schema.ts
851
+ import { validateSchema as validateSchema2, compareSchemas } from "@basictech/schema";
441
852
  async function getSchemaStatus(schema) {
442
853
  const projectId = schema.project_id;
443
- let status = "";
444
- const valid = validateSchema3(schema);
854
+ const valid = validateSchema2(schema);
445
855
  if (!valid.valid) {
446
856
  console.warn("BasicDB Error: your local schema is invalid. Please fix errors and try again - sync is disabled");
447
857
  return {
@@ -503,54 +913,55 @@ async function getSchemaStatus(schema) {
503
913
  };
504
914
  }
505
915
  }
506
- function getSyncStatus(statusCode) {
507
- switch (statusCode) {
508
- case -1:
509
- return "ERROR";
510
- case 0:
511
- return "OFFLINE";
512
- case 1:
513
- return "CONNECTING";
514
- case 2:
515
- return "ONLINE";
516
- case 3:
517
- return "SYNCING";
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);
916
+ async function validateAndCheckSchema(schema) {
917
+ const valid = validateSchema2(schema);
918
+ if (!valid.valid) {
919
+ log("Basic Schema is invalid!", valid.errors);
920
+ console.group("Schema Errors");
921
+ let errorMessage = "";
922
+ valid.errors.forEach((error, index) => {
923
+ log(`${index + 1}:`, error.message, ` - at ${error.instancePath}`);
924
+ errorMessage += `${index + 1}: ${error.message} - at ${error.instancePath}
925
+ `;
926
+ });
927
+ console.groupEnd();
547
928
  return {
548
- hasNewVersion: false,
549
- latestVersion: null,
550
- currentVersion: null
929
+ isValid: false,
930
+ schemaStatus: { valid: false },
931
+ errors: valid.errors
551
932
  };
552
933
  }
934
+ let schemaStatus = { valid: false };
935
+ if (schema.version !== 0) {
936
+ schemaStatus = await getSchemaStatus(schema);
937
+ log("schemaStatus", schemaStatus);
938
+ } else {
939
+ log("schema not published - at version 0");
940
+ }
941
+ return {
942
+ isValid: true,
943
+ schemaStatus
944
+ };
553
945
  }
946
+
947
+ // src/AuthContext.tsx
948
+ import { jsx, jsxs } from "react/jsx-runtime";
949
+ var BasicContext = createContext({
950
+ unicorn: "\u{1F984}",
951
+ isAuthReady: false,
952
+ isSignedIn: false,
953
+ user: null,
954
+ signout: () => Promise.resolve(),
955
+ signin: () => Promise.resolve(),
956
+ signinWithCode: () => new Promise(() => {
957
+ }),
958
+ getToken: () => new Promise(() => {
959
+ }),
960
+ getSignInLink: () => Promise.resolve(""),
961
+ db: {},
962
+ remoteDb: {},
963
+ dbStatus: "LOADING" /* LOADING */
964
+ });
554
965
  function BasicProvider({
555
966
  children,
556
967
  project_id,
@@ -569,25 +980,10 @@ function BasicProvider({
569
980
  const [isOnline, setIsOnline] = useState(navigator.onLine);
570
981
  const [pendingRefresh, setPendingRefresh] = useState(false);
571
982
  const syncRef = useRef(null);
983
+ const remoteDbRef = useRef(null);
572
984
  const storageAdapter = storage || new LocalStorageAdapter();
573
- const STORAGE_KEYS = {
574
- REFRESH_TOKEN: "basic_refresh_token",
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
- };
985
+ const isDevMode = () => isDevelopment(debug);
986
+ const cleanOAuthParams = () => cleanOAuthParamsFromUrl();
591
987
  useEffect(() => {
592
988
  const handleOnline = () => {
593
989
  log("Network came back online");
@@ -624,9 +1020,6 @@ function BasicProvider({
624
1020
  syncRef.current.syncable.on("statusChanged", (status, url) => {
625
1021
  setDbStatus(getSyncStatus(status));
626
1022
  });
627
- syncRef.current.syncable.getStatus().then((status) => {
628
- setDbStatus(getSyncStatus(status));
629
- });
630
1023
  if (options.shouldConnect) {
631
1024
  setShouldConnect(true);
632
1025
  } else {
@@ -636,17 +1029,15 @@ function BasicProvider({
636
1029
  }
637
1030
  }
638
1031
  async function checkSchema() {
639
- const valid = validateSchema3(schema);
640
- if (!valid.valid) {
641
- log("Basic Schema is invalid!", valid.errors);
642
- console.group("Schema Errors");
1032
+ const result = await validateAndCheckSchema(schema);
1033
+ if (!result.isValid) {
643
1034
  let errorMessage = "";
644
- valid.errors.forEach((error2, index) => {
645
- log(`${index + 1}:`, error2.message, ` - at ${error2.instancePath}`);
646
- errorMessage += `${index + 1}: ${error2.message} - at ${error2.instancePath}
1035
+ if (result.errors) {
1036
+ result.errors.forEach((error2, index) => {
1037
+ errorMessage += `${index + 1}: ${error2.message} - at ${error2.instancePath}
647
1038
  `;
648
- });
649
- console.groupEnd("Schema Errors");
1039
+ });
1040
+ }
650
1041
  setError({
651
1042
  code: "schema_invalid",
652
1043
  title: "Basic Schema is invalid!",
@@ -655,17 +1046,10 @@ function BasicProvider({
655
1046
  setIsReady(true);
656
1047
  return null;
657
1048
  }
658
- let schemaStatus = { valid: false };
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) {
1049
+ if (result.schemaStatus.valid) {
666
1050
  initDb({ shouldConnect: true });
667
1051
  } else {
668
- log("Schema is invalid!", schemaStatus);
1052
+ log("Schema is invalid!", result.schemaStatus);
669
1053
  initDb({ shouldConnect: false });
670
1054
  }
671
1055
  checkForNewVersion();
@@ -677,43 +1061,72 @@ function BasicProvider({
677
1061
  }
678
1062
  }, []);
679
1063
  useEffect(() => {
680
- if (token && syncRef.current && isSignedIn && shouldConnect) {
681
- connectToDb();
1064
+ async function connectToDb() {
1065
+ if (token && syncRef.current && isSignedIn && shouldConnect) {
1066
+ const tok = await getToken();
1067
+ if (!tok) {
1068
+ log("no token found");
1069
+ return;
1070
+ }
1071
+ log("connecting to db...");
1072
+ syncRef.current?.connect({ access_token: tok }).catch((e) => {
1073
+ log("error connecting to db", e);
1074
+ });
1075
+ }
682
1076
  }
1077
+ connectToDb();
683
1078
  }, [isSignedIn, shouldConnect]);
684
- const connectToDb = async () => {
685
- const tok = await getToken();
686
- if (!tok) {
687
- log("no token found");
688
- return;
1079
+ useEffect(() => {
1080
+ if (project_id && schema && token?.access_token && !remoteDbRef.current) {
1081
+ log("Initializing Remote DB SDK");
1082
+ remoteDbRef.current = new BasicDBSDK({
1083
+ project_id,
1084
+ schema,
1085
+ getToken: () => getToken(),
1086
+ baseUrl: "https://api.basic.tech"
1087
+ });
689
1088
  }
690
- log("connecting to db...");
691
- syncRef.current.connect({ access_token: tok }).catch((e) => {
692
- log("error connecting to db", e);
693
- });
694
- };
1089
+ }, [token, project_id, schema]);
695
1090
  useEffect(() => {
696
1091
  const initializeAuth = async () => {
697
1092
  await storageAdapter.set(STORAGE_KEYS.DEBUG, debug ? "true" : "false");
1093
+ try {
1094
+ const versionUpdater = createVersionUpdater(storageAdapter, version, getMigrations());
1095
+ const updateResult = await versionUpdater.checkAndUpdate();
1096
+ if (updateResult.updated) {
1097
+ log(`App updated from ${updateResult.fromVersion} to ${updateResult.toVersion}`);
1098
+ } else {
1099
+ log(`App version ${updateResult.toVersion} is current`);
1100
+ }
1101
+ } catch (error2) {
1102
+ log("Version update failed:", error2);
1103
+ }
698
1104
  try {
699
1105
  if (window.location.search.includes("code")) {
700
- let code = window.location?.search?.split("code=")[1].split("&")[0];
1106
+ let code = window.location?.search?.split("code=")[1]?.split("&")[0];
1107
+ if (!code)
1108
+ return;
701
1109
  const state = await storageAdapter.get(STORAGE_KEYS.AUTH_STATE);
702
- if (!state || state !== window.location.search.split("state=")[1].split("&")[0]) {
1110
+ const urlState = window.location.search.split("state=")[1]?.split("&")[0];
1111
+ if (!state || state !== urlState) {
703
1112
  log("error: auth state does not match");
704
1113
  setIsAuthReady(true);
705
1114
  await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
706
- cleanOAuthParamsFromUrl();
1115
+ cleanOAuthParams();
707
1116
  return;
708
1117
  }
709
1118
  await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
710
- cleanOAuthParamsFromUrl();
711
- fetchToken(code);
1119
+ cleanOAuthParams();
1120
+ fetchToken(code).catch((error2) => {
1121
+ log("Error fetching token:", error2);
1122
+ });
712
1123
  } else {
713
1124
  const refreshToken = await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
714
1125
  if (refreshToken) {
715
1126
  log("Found refresh token in storage, attempting to refresh access token");
716
- fetchToken(refreshToken);
1127
+ fetchToken(refreshToken).catch((error2) => {
1128
+ log("Error fetching refresh token:", error2);
1129
+ });
717
1130
  } else {
718
1131
  let cookie_token = getCookie("basic_token");
719
1132
  if (cookie_token !== "") {
@@ -762,8 +1175,8 @@ function BasicProvider({
762
1175
  }
763
1176
  await storageAdapter.set(STORAGE_KEYS.USER_INFO, JSON.stringify(user2));
764
1177
  log("Cached user info in storage");
765
- document.cookie = `basic_access_token=${token.access_token}; Secure; SameSite=Strict; HttpOnly=false`;
766
- document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;
1178
+ setCookie("basic_access_token", token?.access_token || "", { httpOnly: false });
1179
+ setCookie("basic_token", JSON.stringify(token));
767
1180
  setUser(user2);
768
1181
  setIsSignedIn(true);
769
1182
  setIsAuthReady(true);
@@ -780,19 +1193,19 @@ function BasicProvider({
780
1193
  if (isExpired) {
781
1194
  log("token is expired - refreshing ...");
782
1195
  try {
783
- const newToken = await fetchToken(token?.refresh_token);
784
- fetchUser(newToken.access_token);
1196
+ const newToken = await fetchToken(token?.refresh_token || "");
1197
+ fetchUser(newToken?.access_token || "");
785
1198
  } catch (error2) {
786
1199
  log("Failed to refresh token in checkToken:", error2);
787
1200
  if (error2.message.includes("offline") || error2.message.includes("Network")) {
788
1201
  log("Network issue - continuing with expired token until online");
789
- fetchUser(token.access_token);
1202
+ fetchUser(token?.access_token || "");
790
1203
  } else {
791
1204
  setIsAuthReady(true);
792
1205
  }
793
1206
  }
794
1207
  } else {
795
- fetchUser(token.access_token);
1208
+ fetchUser(token?.access_token || "");
796
1209
  }
797
1210
  }
798
1211
  if (token) {
@@ -811,14 +1224,14 @@ function BasicProvider({
811
1224
  if (!redirectUrl || !redirectUrl.startsWith("http://") && !redirectUrl.startsWith("https://")) {
812
1225
  throw new Error("Invalid redirect URI provided");
813
1226
  }
814
- let baseUrl2 = "https://api.basic.tech/auth/authorize";
815
- baseUrl2 += `?client_id=${project_id}`;
816
- baseUrl2 += `&redirect_uri=${encodeURIComponent(redirectUrl)}`;
817
- baseUrl2 += `&response_type=code`;
818
- baseUrl2 += `&scope=profile`;
819
- baseUrl2 += `&state=${randomState}`;
1227
+ let baseUrl = "https://api.basic.tech/auth/authorize";
1228
+ baseUrl += `?client_id=${project_id}`;
1229
+ baseUrl += `&redirect_uri=${encodeURIComponent(redirectUrl)}`;
1230
+ baseUrl += `&response_type=code`;
1231
+ baseUrl += `&scope=profile`;
1232
+ baseUrl += `&state=${randomState}`;
820
1233
  log("Generated sign-in link successfully");
821
- return baseUrl2;
1234
+ return baseUrl;
822
1235
  } catch (error2) {
823
1236
  log("Error generating sign-in link:", error2);
824
1237
  throw error2;
@@ -840,7 +1253,7 @@ function BasicProvider({
840
1253
  window.location.href = signInLink;
841
1254
  } catch (error2) {
842
1255
  log("Error during sign-in:", error2);
843
- if (isDevelopment()) {
1256
+ if (isDevMode()) {
844
1257
  setError({
845
1258
  code: "signin_error",
846
1259
  title: "Sign-in Failed",
@@ -864,7 +1277,7 @@ function BasicProvider({
864
1277
  }
865
1278
  }
866
1279
  await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
867
- cleanOAuthParamsFromUrl();
1280
+ cleanOAuthParams();
868
1281
  const token2 = await fetchToken(code);
869
1282
  if (token2) {
870
1283
  log("signinWithCode successful");
@@ -885,16 +1298,16 @@ function BasicProvider({
885
1298
  setUser({});
886
1299
  setIsSignedIn(false);
887
1300
  setToken(null);
888
- document.cookie = `basic_token=; Secure; SameSite=Strict`;
889
- document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
1301
+ clearCookie("basic_token");
1302
+ clearCookie("basic_access_token");
890
1303
  await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
891
1304
  await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
892
1305
  await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
893
1306
  if (syncRef.current) {
894
1307
  (async () => {
895
1308
  try {
896
- await syncRef.current.close();
897
- await syncRef.current.delete({ disableAutoOpen: false });
1309
+ await syncRef.current?.close();
1310
+ await syncRef.current?.delete({ disableAutoOpen: false });
898
1311
  syncRef.current = null;
899
1312
  window?.location?.reload();
900
1313
  } catch (error2) {
@@ -953,20 +1366,6 @@ function BasicProvider({
953
1366
  }
954
1367
  return token?.access_token || "";
955
1368
  };
956
- function getCookie(name) {
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
1369
  const fetchToken = async (code) => {
971
1370
  try {
972
1371
  if (!isOnline) {
@@ -996,8 +1395,8 @@ function BasicProvider({
996
1395
  }
997
1396
  await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
998
1397
  await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
999
- document.cookie = `basic_token=; Secure; SameSite=Strict`;
1000
- document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
1398
+ clearCookie("basic_token");
1399
+ clearCookie("basic_access_token");
1001
1400
  setUser({});
1002
1401
  setIsSignedIn(false);
1003
1402
  setToken(null);
@@ -1010,7 +1409,7 @@ function BasicProvider({
1010
1409
  await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token2.refresh_token);
1011
1410
  log("Updated refresh token in storage");
1012
1411
  }
1013
- document.cookie = `basic_access_token=${token2.access_token}; Secure; SameSite=Strict; HttpOnly=false`;
1412
+ setCookie("basic_access_token", token2.access_token, { httpOnly: false });
1014
1413
  log("Updated access token in cookie");
1015
1414
  }
1016
1415
  return token2;
@@ -1019,8 +1418,8 @@ function BasicProvider({
1019
1418
  if (!error2.message.includes("offline") && !error2.message.includes("Network")) {
1020
1419
  await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
1021
1420
  await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
1022
- document.cookie = `basic_token=; Secure; SameSite=Strict`;
1023
- document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
1421
+ clearCookie("basic_token");
1422
+ clearCookie("basic_access_token");
1024
1423
  setUser({});
1025
1424
  setIsSignedIn(false);
1026
1425
  setToken(null);
@@ -1029,35 +1428,6 @@ function BasicProvider({
1029
1428
  throw error2;
1030
1429
  }
1031
1430
  };
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
1431
  const noDb = {
1062
1432
  collection: () => {
1063
1433
  throw new Error("no basicdb found - initialization failed. double check your schema.");
@@ -1074,9 +1444,10 @@ function BasicProvider({
1074
1444
  getToken,
1075
1445
  getSignInLink,
1076
1446
  db: syncRef.current ? syncRef.current : noDb,
1447
+ remoteDb: remoteDbRef.current ? remoteDbRef.current : noDb,
1077
1448
  dbStatus
1078
1449
  }, children: [
1079
- error && isDevelopment() && /* @__PURE__ */ jsx(ErrorDisplay, { error }),
1450
+ error && isDevMode() && /* @__PURE__ */ jsx(ErrorDisplay, { error }),
1080
1451
  isReady && children
1081
1452
  ] });
1082
1453
  }
@@ -1110,6 +1481,7 @@ function useBasic() {
1110
1481
  // src/index.ts
1111
1482
  import { useLiveQuery as useQuery } from "dexie-react-hooks";
1112
1483
  export {
1484
+ BasicDBSDK,
1113
1485
  BasicProvider,
1114
1486
  useBasic,
1115
1487
  useQuery