@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.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,19 +15,12 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
31
21
  var src_exports = {};
32
22
  __export(src_exports, {
23
+ BasicDBSDK: () => BasicDBSDK,
33
24
  BasicProvider: () => BasicProvider,
34
25
  useBasic: () => useBasic,
35
26
  useQuery: () => import_dexie_react_hooks.useLiveQuery
@@ -165,116 +156,8 @@ var syncProtocol = function() {
165
156
  });
166
157
  };
167
158
 
168
- // src/schema.ts
169
- var import_ajv = __toESM(require("ajv"));
170
- var basicJsonSchema = {
171
- "$schema": "http://json-schema.org/draft-07/schema#",
172
- "type": "object",
173
- "properties": {
174
- "project_id": {
175
- "type": "string"
176
- },
177
- "namespace": {
178
- "type": "string"
179
- },
180
- "version": {
181
- "type": "integer",
182
- "minimum": 0
183
- },
184
- "tables": {
185
- "type": "object",
186
- "patternProperties": {
187
- "^[a-zA-Z0-9_]+$": {
188
- "type": "object",
189
- "properties": {
190
- "name": {
191
- "type": "string"
192
- },
193
- "type": {
194
- "type": "string",
195
- "enum": ["collection"]
196
- },
197
- "fields": {
198
- "type": "object",
199
- "patternProperties": {
200
- "^[a-zA-Z0-9_]+$": {
201
- "type": "object",
202
- "properties": {
203
- "type": {
204
- "type": "string",
205
- "enum": ["string", "boolean", "number", "json"]
206
- },
207
- "indexed": {
208
- "type": "boolean"
209
- },
210
- "required": {
211
- "type": "boolean"
212
- }
213
- },
214
- "required": ["type"]
215
- }
216
- },
217
- "additionalProperties": true
218
- }
219
- },
220
- "required": ["fields"]
221
- }
222
- },
223
- "additionalProperties": true
224
- }
225
- },
226
- "required": ["project_id", "version", "tables"]
227
- };
228
- var ajv = new import_ajv.default();
229
- var validator = ajv.compile(basicJsonSchema);
230
- function validateSchema(schema) {
231
- const v = validator(schema);
232
- return {
233
- valid: v,
234
- errors: validator.errors || []
235
- };
236
- }
237
- function validateData(schema, table, data, checkRequired = true) {
238
- const valid = validateSchema(schema);
239
- if (!valid.valid) {
240
- return { valid: false, errors: valid.errors, message: "Schema is invalid" };
241
- }
242
- const tableSchema = schema.tables[table];
243
- if (!tableSchema) {
244
- return { valid: false, errors: [{ message: `Table ${table} not found in schema` }], message: "Table not found" };
245
- }
246
- for (const [fieldName, fieldValue] of Object.entries(data)) {
247
- const fieldSchema = tableSchema.fields[fieldName];
248
- if (!fieldSchema) {
249
- return {
250
- valid: false,
251
- errors: [{ message: `Field ${fieldName} not found in schema` }],
252
- message: "Invalid field"
253
- };
254
- }
255
- const schemaType = fieldSchema.type;
256
- const valueType = typeof fieldValue;
257
- if (schemaType === "string" && valueType !== "string" || schemaType === "number" && valueType !== "number" || schemaType === "boolean" && valueType !== "boolean" || schemaType === "json" && valueType !== "object") {
258
- return {
259
- valid: false,
260
- errors: [{
261
- message: `Field ${fieldName} should be type ${schemaType}, got ${valueType}`
262
- }],
263
- message: "invalid type"
264
- };
265
- }
266
- }
267
- if (checkRequired) {
268
- for (const [fieldName, fieldSchema] of Object.entries(tableSchema.fields)) {
269
- if (fieldSchema.required && !data[fieldName]) {
270
- return { valid: false, errors: [{ message: `Field ${fieldName} is required` }], message: "Required field missing" };
271
- }
272
- }
273
- }
274
- return { valid: true, errors: [] };
275
- }
276
-
277
159
  // src/sync/index.ts
160
+ var import_schema = require("@basictech/schema");
278
161
  syncProtocol();
279
162
  var BasicSync = class extends import_dexie2.Dexie {
280
163
  basic_schema;
@@ -349,7 +232,7 @@ var BasicSync = class extends import_dexie2.Dexie {
349
232
  ref: this.table(name),
350
233
  // --- WRITE ---- //
351
234
  add: (data) => {
352
- const valid = validateData(this.basic_schema, name, data);
235
+ const valid = (0, import_schema.validateData)(this.basic_schema, name, data);
353
236
  if (!valid.valid) {
354
237
  log("Invalid data", valid);
355
238
  return Promise.reject({ ...valid });
@@ -360,7 +243,7 @@ var BasicSync = class extends import_dexie2.Dexie {
360
243
  });
361
244
  },
362
245
  put: (data) => {
363
- const valid = validateData(this.basic_schema, name, data);
246
+ const valid = (0, import_schema.validateData)(this.basic_schema, name, data);
364
247
  if (!valid.valid) {
365
248
  log("Invalid data", valid);
366
249
  return Promise.reject({ ...valid });
@@ -371,7 +254,7 @@ var BasicSync = class extends import_dexie2.Dexie {
371
254
  });
372
255
  },
373
256
  update: (id, data) => {
374
- const valid = validateData(this.basic_schema, name, data, false);
257
+ const valid = (0, import_schema.validateData)(this.basic_schema, name, data, false);
375
258
  if (!valid.valid) {
376
259
  log("Invalid data", valid);
377
260
  return Promise.reject({ ...valid });
@@ -396,60 +279,490 @@ var BasicSync = class extends import_dexie2.Dexie {
396
279
  }
397
280
  };
398
281
 
399
- // src/db.ts
400
- var baseUrl = "https://api.basic.tech";
401
- async function get({ projectId, accountId, tableName, token }) {
402
- const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;
403
- const response = await fetch(url, {
404
- headers: {
405
- "Authorization": `Bearer ${token}`
282
+ // src/db_ts.ts
283
+ var DBError = class extends Error {
284
+ constructor(message, status, response, originalError) {
285
+ super(message);
286
+ this.status = status;
287
+ this.response = response;
288
+ this.originalError = originalError;
289
+ this.name = "DBError";
290
+ }
291
+ };
292
+ var QueryBuilder = class {
293
+ constructor(tableClient, tableSchema) {
294
+ this.tableClient = tableClient;
295
+ this.tableSchema = tableSchema;
296
+ }
297
+ params = {};
298
+ // Reserved fields that are always allowed
299
+ reservedFields = ["created_at", "updated_at", "id"];
300
+ // Validate field existence in schema
301
+ validateField(field) {
302
+ if (this.tableSchema && !this.reservedFields.includes(field)) {
303
+ if (!this.tableSchema.fields || !(field in this.tableSchema.fields)) {
304
+ throw new Error(`Invalid field: "${field}". Field does not exist in table schema.`);
305
+ }
406
306
  }
407
- });
408
- return response.json();
409
- }
410
- async function add({ projectId, accountId, tableName, value, token }) {
411
- const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}`;
412
- const response = await fetch(url, {
413
- method: "POST",
414
- headers: {
415
- "Content-Type": "application/json",
416
- "Authorization": `Bearer ${token}`
417
- },
418
- body: JSON.stringify({ "value": value })
419
- });
420
- return response.json();
421
- }
422
- async function update({ projectId, accountId, tableName, id, value, token }) {
423
- const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;
424
- const response = await fetch(url, {
425
- method: "PATCH",
426
- headers: {
427
- "Content-Type": "application/json",
428
- "Authorization": `Bearer ${token}`
429
- },
430
- body: JSON.stringify({ id, value })
431
- });
432
- return response.json();
433
- }
434
- async function deleteRecord({ projectId, accountId, tableName, id, token }) {
435
- const url = `${baseUrl}/project/${projectId}/db/${accountId}/${tableName}/${id}`;
436
- const response = await fetch(url, {
437
- method: "DELETE",
438
- headers: {
439
- "Authorization": `Bearer ${token}`
307
+ }
308
+ // Validate operator based on field type
309
+ validateOperator(field, operator, value) {
310
+ if (!this.tableSchema || this.reservedFields.includes(field)) {
311
+ return;
440
312
  }
441
- });
442
- return response.json();
443
- }
444
-
445
- // src/AuthContext.tsx
446
- var import_schema2 = require("@basictech/schema");
313
+ const fieldInfo = this.tableSchema.fields[field];
314
+ if (!fieldInfo)
315
+ return;
316
+ switch (operator) {
317
+ case "gt":
318
+ case "gte":
319
+ case "lt":
320
+ case "lte":
321
+ if (fieldInfo.type !== "number" && fieldInfo.type !== "string") {
322
+ throw new Error(`Operator "${operator}" can only be used with number or string fields. Field "${field}" is type "${fieldInfo.type}".`);
323
+ }
324
+ break;
325
+ case "like":
326
+ case "ilike":
327
+ if (fieldInfo.type !== "string") {
328
+ throw new Error(`Operator "${operator}" can only be used with string fields. Field "${field}" is type "${fieldInfo.type}".`);
329
+ }
330
+ if (typeof value !== "string") {
331
+ throw new Error(`Operator "${operator}" requires a string value. Received: ${typeof value}`);
332
+ }
333
+ break;
334
+ case "in":
335
+ if (!Array.isArray(value)) {
336
+ throw new Error(`Operator "in" requires an array value. Received: ${typeof value}`);
337
+ }
338
+ break;
339
+ case "is":
340
+ if (value !== null && typeof value !== "boolean") {
341
+ throw new Error(`Operator "is" requires null or boolean. Received: ${typeof value}`);
342
+ }
343
+ break;
344
+ }
345
+ }
346
+ // Add ordering to query with schema validation
347
+ order(field, direction = "asc") {
348
+ this.validateField(field);
349
+ this.params.order = `${field}.${direction}`;
350
+ return this;
351
+ }
352
+ // Add filtering to query
353
+ filter(conditions) {
354
+ if (!this.params.filters) {
355
+ this.params.filters = {};
356
+ }
357
+ for (const [field, condition] of Object.entries(conditions)) {
358
+ this.validateField(field);
359
+ if (condition === null || typeof condition !== "object") {
360
+ this.params.filters[field] = condition;
361
+ } else {
362
+ this.params.filters[field] = condition;
363
+ }
364
+ }
365
+ return this;
366
+ }
367
+ // Add limit to query
368
+ limit(count) {
369
+ this.params.limit = count;
370
+ return this;
371
+ }
372
+ // Add offset to query for pagination
373
+ offset(count) {
374
+ this.params.offset = count;
375
+ return this;
376
+ }
377
+ // Auto-execute when awaited
378
+ then(onfulfilled, onrejected) {
379
+ return this.tableClient.executeQuery(this.params).then(onfulfilled, onrejected);
380
+ }
381
+ // Auto-execute when awaited with catch
382
+ catch(onrejected) {
383
+ return this.tableClient.executeQuery(this.params).catch(onrejected);
384
+ }
385
+ // Auto-execute when awaited with finally
386
+ finally(onfinally) {
387
+ return this.tableClient.executeQuery(this.params).finally(onfinally);
388
+ }
389
+ };
390
+ var TableClient = class {
391
+ constructor(baseUrl, projectId, token, table, getToken, schema) {
392
+ this.baseUrl = baseUrl;
393
+ this.projectId = projectId;
394
+ this.token = token;
395
+ this.table = table;
396
+ this.getToken = getToken;
397
+ this.schema = schema;
398
+ if (schema && schema.tables && schema.tables[table]) {
399
+ this.tableSchema = schema.tables[table];
400
+ }
401
+ }
402
+ tableSchema;
403
+ async headers() {
404
+ const token = await this.getToken();
405
+ return {
406
+ Authorization: `Bearer ${token}`,
407
+ "Content-Type": "application/json"
408
+ };
409
+ }
410
+ async handleRequest(request) {
411
+ try {
412
+ const res = await request;
413
+ if (!res.ok) {
414
+ let errorMessage = `Request failed with status ${res.status}`;
415
+ let errorData;
416
+ try {
417
+ const json2 = await res.json();
418
+ errorData = json2;
419
+ if (json2.error || json2.message) {
420
+ const errorDetails = typeof json2.error === "object" ? JSON.stringify(json2.error) : json2.error;
421
+ const messageDetails = typeof json2.message === "object" ? JSON.stringify(json2.message) : json2.message;
422
+ errorMessage = `${res.status} ${res.statusText}: ${messageDetails || errorDetails || "Unknown error"}`;
423
+ }
424
+ } catch (e) {
425
+ console.log("Failed to parse error response:", e);
426
+ errorMessage = `${res.status} ${res.statusText}`;
427
+ }
428
+ throw new DBError(
429
+ errorMessage,
430
+ res.status,
431
+ errorData
432
+ );
433
+ }
434
+ const json = await res.json();
435
+ return json.data;
436
+ } catch (error) {
437
+ console.log("Caught error:", error);
438
+ if (error instanceof Error) {
439
+ console.log("Error type:", error.constructor.name);
440
+ console.log("Error stack:", error.stack);
441
+ }
442
+ if (error instanceof DBError) {
443
+ throw error;
444
+ }
445
+ if (error instanceof TypeError && error.message === "Network request failed") {
446
+ throw new DBError(
447
+ "Network request failed. Please check your internet connection and try again.",
448
+ void 0,
449
+ void 0,
450
+ error
451
+ );
452
+ }
453
+ throw new DBError(
454
+ `Unexpected error: ${error instanceof Error ? error.message : "Unknown error"}`,
455
+ void 0,
456
+ void 0,
457
+ error instanceof Error ? error : void 0
458
+ );
459
+ }
460
+ }
461
+ // Build query string from query options
462
+ buildQueryParams(query) {
463
+ if (!query)
464
+ return "";
465
+ const params = [];
466
+ if (query.id) {
467
+ params.push(`id=${query.id}`);
468
+ }
469
+ if (query.filters) {
470
+ for (const [field, condition] of Object.entries(query.filters)) {
471
+ this.addFilterParam(params, field, condition);
472
+ }
473
+ }
474
+ if (query.order) {
475
+ params.push(`order=${query.order}`);
476
+ }
477
+ if (query.limit !== void 0 && query.limit >= 0) {
478
+ params.push(`limit=${query.limit}`);
479
+ }
480
+ if (query.offset !== void 0 && query.offset >= 0) {
481
+ params.push(`offset=${query.offset}`);
482
+ }
483
+ return params.length > 0 ? `?${params.join("&")}` : "";
484
+ }
485
+ // Helper method to build filter parameters
486
+ addFilterParam(params, field, condition, negate = false) {
487
+ if (condition === null || typeof condition !== "object") {
488
+ if (condition === null) {
489
+ params.push(`${field}=${negate ? "not." : ""}is.null`);
490
+ } else if (typeof condition === "boolean") {
491
+ params.push(`${field}=${negate ? "not." : ""}is.${condition}`);
492
+ } else if (typeof condition === "number") {
493
+ params.push(`${field}=${negate ? "not." : ""}eq.${condition}`);
494
+ } else {
495
+ params.push(`${field}=${negate ? "not." : ""}eq.${encodeURIComponent(String(condition))}`);
496
+ }
497
+ return;
498
+ }
499
+ const operatorObj = condition;
500
+ if (operatorObj.not) {
501
+ this.addFilterParam(params, field, operatorObj.not, true);
502
+ return;
503
+ }
504
+ for (const [op, value] of Object.entries(operatorObj)) {
505
+ if (op === "not")
506
+ continue;
507
+ const operator = op;
508
+ if (value === null) {
509
+ params.push(`${field}=${negate ? "not." : ""}is.null`);
510
+ } else if (operator === "in" && Array.isArray(value)) {
511
+ params.push(`${field}=${negate ? "not." : ""}in.${value.join(",")}`);
512
+ } else if (operator === "is") {
513
+ if (typeof value === "boolean") {
514
+ params.push(`${field}=${negate ? "not." : ""}is.${value}`);
515
+ } else {
516
+ params.push(`${field}=${negate ? "not." : ""}is.null`);
517
+ }
518
+ } else {
519
+ const paramValue = typeof value === "string" ? encodeURIComponent(value) : String(value);
520
+ params.push(`${field}=${negate ? "not." : ""}${operator}.${paramValue}`);
521
+ }
522
+ }
523
+ }
524
+ // Internal method to execute a query with options
525
+ async executeQuery(options) {
526
+ const params = this.buildQueryParams(options);
527
+ const headers = await this.headers();
528
+ return this.handleRequest(
529
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}${params}`, {
530
+ headers
531
+ })
532
+ );
533
+ }
534
+ // Public method to start building a query
535
+ getAll() {
536
+ return new QueryBuilder(this, this.tableSchema);
537
+ }
538
+ // Get a specific item by ID
539
+ async get(id) {
540
+ const headers = await this.headers();
541
+ return this.handleRequest(
542
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}/${id}`, {
543
+ headers
544
+ })
545
+ );
546
+ }
547
+ async create(value) {
548
+ const headers = await this.headers();
549
+ return this.handleRequest(
550
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}`, {
551
+ method: "POST",
552
+ headers,
553
+ body: JSON.stringify({ value })
554
+ })
555
+ );
556
+ }
557
+ async update(id, value) {
558
+ const headers = await this.headers();
559
+ return this.handleRequest(
560
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}/${id}`, {
561
+ method: "PATCH",
562
+ headers,
563
+ body: JSON.stringify({ value })
564
+ })
565
+ );
566
+ }
567
+ async replace(id, value) {
568
+ const headers = await this.headers();
569
+ return this.handleRequest(
570
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}/${id}`, {
571
+ method: "PUT",
572
+ headers,
573
+ body: JSON.stringify({ value })
574
+ })
575
+ );
576
+ }
577
+ async delete(id) {
578
+ const token = await this.getToken();
579
+ const headers = {
580
+ Authorization: `Bearer ${token}`
581
+ };
582
+ return this.handleRequest(
583
+ fetch(`${this.baseUrl}/account/${this.projectId}/db/${this.table}/${id}`, {
584
+ method: "DELETE",
585
+ headers
586
+ })
587
+ );
588
+ }
589
+ };
590
+ var BasicDBSDK = class {
591
+ projectId;
592
+ getToken;
593
+ baseUrl;
594
+ schema;
595
+ tableNames;
596
+ constructor(config) {
597
+ this.projectId = config.project_id;
598
+ if (config.getToken) {
599
+ this.getToken = config.getToken;
600
+ } else if (config.token) {
601
+ this.getToken = async () => config.token;
602
+ } else {
603
+ throw new Error("Either token or getToken must be provided");
604
+ }
605
+ this.baseUrl = config.baseUrl || "https://api.basic.tech";
606
+ this.schema = config.schema;
607
+ this.tableNames = Object.keys(this.schema.tables);
608
+ }
609
+ // Primary method - table access
610
+ table(name) {
611
+ if (!this.tableNames.includes(name)) {
612
+ throw new Error(`Table '${name}' not found in schema. Available tables: ${this.tableNames.join(", ")}`);
613
+ }
614
+ return new TableClient(
615
+ this.baseUrl,
616
+ this.projectId,
617
+ "",
618
+ // Empty placeholder, will be replaced in headers() method
619
+ name,
620
+ this.getToken,
621
+ this.schema
622
+ // Pass the entire schema to the TableClient
623
+ );
624
+ }
625
+ get tables() {
626
+ return {};
627
+ }
628
+ fields(table) {
629
+ const tableSchema = this.schema.tables[table];
630
+ if (!tableSchema) {
631
+ throw new Error(`Table '${table}' not found in schema`);
632
+ }
633
+ return Object.keys(tableSchema.fields);
634
+ }
635
+ };
447
636
 
448
637
  // package.json
449
- var version = "0.6.0";
638
+ var version = "0.7.0-beta.1";
450
639
 
451
- // src/AuthContext.tsx
452
- var import_jsx_runtime = require("react/jsx-runtime");
640
+ // src/updater/versionUpdater.ts
641
+ var VersionUpdater = class {
642
+ storage;
643
+ currentVersion;
644
+ migrations;
645
+ versionKey = "basic_app_version";
646
+ constructor(storage, currentVersion, migrations = []) {
647
+ this.storage = storage;
648
+ this.currentVersion = currentVersion;
649
+ this.migrations = migrations.sort((a, b) => this.compareVersions(a.fromVersion, b.fromVersion));
650
+ }
651
+ /**
652
+ * Check current stored version and run migrations if needed
653
+ * Only compares major.minor versions, ignoring beta/prerelease parts
654
+ * Example: "0.7.0-beta.1" and "0.7.0" are treated as the same version
655
+ */
656
+ async checkAndUpdate() {
657
+ const storedVersion = await this.getStoredVersion();
658
+ if (!storedVersion) {
659
+ await this.setStoredVersion(this.currentVersion);
660
+ return { updated: false, toVersion: this.currentVersion };
661
+ }
662
+ if (storedVersion === this.currentVersion) {
663
+ return { updated: false, toVersion: this.currentVersion };
664
+ }
665
+ const migrationsToRun = this.getMigrationsToRun(storedVersion, this.currentVersion);
666
+ if (migrationsToRun.length === 0) {
667
+ await this.setStoredVersion(this.currentVersion);
668
+ return { updated: true, fromVersion: storedVersion, toVersion: this.currentVersion };
669
+ }
670
+ for (const migration of migrationsToRun) {
671
+ try {
672
+ console.log(`Running migration from ${migration.fromVersion} to ${migration.toVersion}`);
673
+ await migration.migrate(this.storage);
674
+ } catch (error) {
675
+ console.error(`Migration failed from ${migration.fromVersion} to ${migration.toVersion}:`, error);
676
+ throw new Error(`Migration failed: ${error}`);
677
+ }
678
+ }
679
+ await this.setStoredVersion(this.currentVersion);
680
+ return { updated: true, fromVersion: storedVersion, toVersion: this.currentVersion };
681
+ }
682
+ async getStoredVersion() {
683
+ try {
684
+ const versionData = await this.storage.get(this.versionKey);
685
+ if (!versionData)
686
+ return null;
687
+ const versionInfo = JSON.parse(versionData);
688
+ return versionInfo.version;
689
+ } catch (error) {
690
+ console.warn("Failed to get stored version:", error);
691
+ return null;
692
+ }
693
+ }
694
+ async setStoredVersion(version2) {
695
+ const versionInfo = {
696
+ version: version2,
697
+ lastUpdated: Date.now()
698
+ };
699
+ await this.storage.set(this.versionKey, JSON.stringify(versionInfo));
700
+ }
701
+ getMigrationsToRun(fromVersion, toVersion) {
702
+ return this.migrations.filter((migration) => {
703
+ const storedLessThanMigrationTo = this.compareVersions(fromVersion, migration.toVersion) < 0;
704
+ const currentGreaterThanOrEqualMigrationTo = this.compareVersions(toVersion, migration.toVersion) >= 0;
705
+ console.log(`Checking migration ${migration.fromVersion} \u2192 ${migration.toVersion}:`);
706
+ console.log(` stored ${fromVersion} < migration.to ${migration.toVersion}: ${storedLessThanMigrationTo}`);
707
+ console.log(` current ${toVersion} >= migration.to ${migration.toVersion}: ${currentGreaterThanOrEqualMigrationTo}`);
708
+ const shouldRun = storedLessThanMigrationTo && currentGreaterThanOrEqualMigrationTo;
709
+ console.log(` Should run: ${shouldRun}`);
710
+ return shouldRun;
711
+ });
712
+ }
713
+ /**
714
+ * Simple semantic version comparison (major.minor only, ignoring beta/prerelease)
715
+ * Returns: -1 if a < b, 0 if a === b, 1 if a > b
716
+ */
717
+ compareVersions(a, b) {
718
+ const aMajorMinor = this.extractMajorMinor(a);
719
+ const bMajorMinor = this.extractMajorMinor(b);
720
+ if (aMajorMinor.major !== bMajorMinor.major) {
721
+ return aMajorMinor.major - bMajorMinor.major;
722
+ }
723
+ return aMajorMinor.minor - bMajorMinor.minor;
724
+ }
725
+ /**
726
+ * Extract major.minor from version string, ignoring beta/prerelease
727
+ * Examples: "0.7.0-beta.1" -> {major: 0, minor: 7}
728
+ * "1.2.3" -> {major: 1, minor: 2}
729
+ */
730
+ extractMajorMinor(version2) {
731
+ const cleanVersion = version2.split("-")[0]?.split("+")[0] || version2;
732
+ const parts = cleanVersion.split(".").map(Number);
733
+ return {
734
+ major: parts[0] || 0,
735
+ minor: parts[1] || 0
736
+ };
737
+ }
738
+ /**
739
+ * Add a migration to the updater
740
+ */
741
+ addMigration(migration) {
742
+ this.migrations.push(migration);
743
+ this.migrations.sort((a, b) => this.compareVersions(a.fromVersion, b.fromVersion));
744
+ }
745
+ };
746
+ function createVersionUpdater(storage, currentVersion, migrations = []) {
747
+ return new VersionUpdater(storage, currentVersion, migrations);
748
+ }
749
+
750
+ // src/updater/updateMigrations.ts
751
+ var addMigrationTimestamp = {
752
+ fromVersion: "0.6.0",
753
+ toVersion: "0.7.0",
754
+ async migrate(storage) {
755
+ console.log("Running test migration");
756
+ storage.set("test_migration", "true");
757
+ }
758
+ };
759
+ function getMigrations() {
760
+ return [
761
+ addMigrationTimestamp
762
+ ];
763
+ }
764
+
765
+ // src/utils/storage.ts
453
766
  var LocalStorageAdapter = class {
454
767
  async get(key) {
455
768
  return localStorage.getItem(key);
@@ -461,24 +774,112 @@ var LocalStorageAdapter = class {
461
774
  localStorage.removeItem(key);
462
775
  }
463
776
  };
464
- var BasicContext = (0, import_react.createContext)({
465
- unicorn: "\u{1F984}",
466
- isAuthReady: false,
467
- isSignedIn: false,
468
- user: null,
469
- signout: () => Promise.resolve(),
470
- signin: () => Promise.resolve(),
471
- signinWithCode: () => new Promise(() => {
472
- }),
473
- getToken: () => new Promise(() => {
474
- }),
475
- getSignInLink: () => Promise.resolve(""),
476
- db: {},
477
- dbStatus: "LOADING" /* LOADING */
478
- });
777
+ var STORAGE_KEYS = {
778
+ REFRESH_TOKEN: "basic_refresh_token",
779
+ USER_INFO: "basic_user_info",
780
+ AUTH_STATE: "basic_auth_state",
781
+ DEBUG: "basic_debug"
782
+ };
783
+ function getCookie(name) {
784
+ let cookieValue = "";
785
+ if (document.cookie && document.cookie !== "") {
786
+ const cookies = document.cookie.split(";");
787
+ for (let i = 0; i < cookies.length; i++) {
788
+ const cookie = cookies[i]?.trim();
789
+ if (cookie && cookie.substring(0, name.length + 1) === name + "=") {
790
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
791
+ break;
792
+ }
793
+ }
794
+ }
795
+ return cookieValue;
796
+ }
797
+ function setCookie(name, value, options) {
798
+ const opts = {
799
+ secure: true,
800
+ sameSite: "Strict",
801
+ httpOnly: false,
802
+ ...options
803
+ };
804
+ let cookieString = `${name}=${value}`;
805
+ if (opts.secure)
806
+ cookieString += "; Secure";
807
+ if (opts.sameSite)
808
+ cookieString += `; SameSite=${opts.sameSite}`;
809
+ if (opts.httpOnly)
810
+ cookieString += "; HttpOnly";
811
+ document.cookie = cookieString;
812
+ }
813
+ function clearCookie(name) {
814
+ document.cookie = `${name}=; Secure; SameSite=Strict`;
815
+ }
816
+
817
+ // src/utils/network.ts
818
+ function isDevelopment(debug) {
819
+ 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;
820
+ }
821
+ async function checkForNewVersion() {
822
+ try {
823
+ const isBeta = version.includes("beta");
824
+ const response = await fetch(`https://registry.npmjs.org/@basictech/react/${isBeta ? "beta" : "latest"}`);
825
+ if (!response.ok) {
826
+ throw new Error("Failed to fetch version from npm");
827
+ }
828
+ const data = await response.json();
829
+ const latestVersion = data.version;
830
+ if (latestVersion !== version) {
831
+ console.warn("[basic] New version available:", latestVersion, `
832
+ run "npm install @basictech/react@${latestVersion}" to update`);
833
+ }
834
+ if (isBeta) {
835
+ log("thank you for being on basictech/react beta :)");
836
+ }
837
+ return {
838
+ hasNewVersion: version !== latestVersion,
839
+ latestVersion,
840
+ currentVersion: version
841
+ };
842
+ } catch (error) {
843
+ log("Error checking for new version:", error);
844
+ return {
845
+ hasNewVersion: false,
846
+ latestVersion: null,
847
+ currentVersion: null
848
+ };
849
+ }
850
+ }
851
+ function cleanOAuthParamsFromUrl() {
852
+ if (window.location.search.includes("code") || window.location.search.includes("state")) {
853
+ const url = new URL(window.location.href);
854
+ url.searchParams.delete("code");
855
+ url.searchParams.delete("state");
856
+ window.history.pushState({}, document.title, url.pathname + url.search);
857
+ log("Cleaned OAuth parameters from URL");
858
+ }
859
+ }
860
+ function getSyncStatus(statusCode) {
861
+ switch (statusCode) {
862
+ case -1:
863
+ return "ERROR";
864
+ case 0:
865
+ return "OFFLINE";
866
+ case 1:
867
+ return "CONNECTING";
868
+ case 2:
869
+ return "ONLINE";
870
+ case 3:
871
+ return "SYNCING";
872
+ case 4:
873
+ return "ERROR_WILL_RETRY";
874
+ default:
875
+ return "UNKNOWN";
876
+ }
877
+ }
878
+
879
+ // src/utils/schema.ts
880
+ var import_schema2 = require("@basictech/schema");
479
881
  async function getSchemaStatus(schema) {
480
882
  const projectId = schema.project_id;
481
- let status = "";
482
883
  const valid = (0, import_schema2.validateSchema)(schema);
483
884
  if (!valid.valid) {
484
885
  console.warn("BasicDB Error: your local schema is invalid. Please fix errors and try again - sync is disabled");
@@ -541,54 +942,55 @@ async function getSchemaStatus(schema) {
541
942
  };
542
943
  }
543
944
  }
544
- function getSyncStatus(statusCode) {
545
- switch (statusCode) {
546
- case -1:
547
- return "ERROR";
548
- case 0:
549
- return "OFFLINE";
550
- case 1:
551
- return "CONNECTING";
552
- case 2:
553
- return "ONLINE";
554
- case 3:
555
- return "SYNCING";
556
- case 4:
557
- return "ERROR_WILL_RETRY";
558
- default:
559
- return "UNKNOWN";
560
- }
561
- }
562
- async function checkForNewVersion() {
563
- try {
564
- const isBeta = version.includes("beta");
565
- const response = await fetch(`https://registry.npmjs.org/@basictech/react/${isBeta ? "beta" : "latest"}`);
566
- if (!response.ok) {
567
- throw new Error("Failed to fetch version from npm");
568
- }
569
- const data = await response.json();
570
- const latestVersion = data.version;
571
- if (latestVersion !== version) {
572
- console.warn("[basic] New version available:", latestVersion, `
573
- run "npm install @basictech/react@${latestVersion}" to update`);
574
- }
575
- if (isBeta) {
576
- log("thank you for being on basictech/react beta :)");
577
- }
578
- return {
579
- hasNewVersion: version !== latestVersion,
580
- latestVersion,
581
- currentVersion: version
582
- };
583
- } catch (error) {
584
- log("Error checking for new version:", error);
945
+ async function validateAndCheckSchema(schema) {
946
+ const valid = (0, import_schema2.validateSchema)(schema);
947
+ if (!valid.valid) {
948
+ log("Basic Schema is invalid!", valid.errors);
949
+ console.group("Schema Errors");
950
+ let errorMessage = "";
951
+ valid.errors.forEach((error, index) => {
952
+ log(`${index + 1}:`, error.message, ` - at ${error.instancePath}`);
953
+ errorMessage += `${index + 1}: ${error.message} - at ${error.instancePath}
954
+ `;
955
+ });
956
+ console.groupEnd();
585
957
  return {
586
- hasNewVersion: false,
587
- latestVersion: null,
588
- currentVersion: null
958
+ isValid: false,
959
+ schemaStatus: { valid: false },
960
+ errors: valid.errors
589
961
  };
590
962
  }
963
+ let schemaStatus = { valid: false };
964
+ if (schema.version !== 0) {
965
+ schemaStatus = await getSchemaStatus(schema);
966
+ log("schemaStatus", schemaStatus);
967
+ } else {
968
+ log("schema not published - at version 0");
969
+ }
970
+ return {
971
+ isValid: true,
972
+ schemaStatus
973
+ };
591
974
  }
975
+
976
+ // src/AuthContext.tsx
977
+ var import_jsx_runtime = require("react/jsx-runtime");
978
+ var BasicContext = (0, import_react.createContext)({
979
+ unicorn: "\u{1F984}",
980
+ isAuthReady: false,
981
+ isSignedIn: false,
982
+ user: null,
983
+ signout: () => Promise.resolve(),
984
+ signin: () => Promise.resolve(),
985
+ signinWithCode: () => new Promise(() => {
986
+ }),
987
+ getToken: () => new Promise(() => {
988
+ }),
989
+ getSignInLink: () => Promise.resolve(""),
990
+ db: {},
991
+ remoteDb: {},
992
+ dbStatus: "LOADING" /* LOADING */
993
+ });
592
994
  function BasicProvider({
593
995
  children,
594
996
  project_id,
@@ -607,25 +1009,10 @@ function BasicProvider({
607
1009
  const [isOnline, setIsOnline] = (0, import_react.useState)(navigator.onLine);
608
1010
  const [pendingRefresh, setPendingRefresh] = (0, import_react.useState)(false);
609
1011
  const syncRef = (0, import_react.useRef)(null);
1012
+ const remoteDbRef = (0, import_react.useRef)(null);
610
1013
  const storageAdapter = storage || new LocalStorageAdapter();
611
- const STORAGE_KEYS = {
612
- REFRESH_TOKEN: "basic_refresh_token",
613
- USER_INFO: "basic_user_info",
614
- AUTH_STATE: "basic_auth_state",
615
- DEBUG: "basic_debug"
616
- };
617
- const isDevelopment = () => {
618
- 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;
619
- };
620
- const cleanOAuthParamsFromUrl = () => {
621
- if (window.location.search.includes("code") || window.location.search.includes("state")) {
622
- const url = new URL(window.location.href);
623
- url.searchParams.delete("code");
624
- url.searchParams.delete("state");
625
- window.history.pushState({}, document.title, url.pathname + url.search);
626
- log("Cleaned OAuth parameters from URL");
627
- }
628
- };
1014
+ const isDevMode = () => isDevelopment(debug);
1015
+ const cleanOAuthParams = () => cleanOAuthParamsFromUrl();
629
1016
  (0, import_react.useEffect)(() => {
630
1017
  const handleOnline = () => {
631
1018
  log("Network came back online");
@@ -662,9 +1049,6 @@ function BasicProvider({
662
1049
  syncRef.current.syncable.on("statusChanged", (status, url) => {
663
1050
  setDbStatus(getSyncStatus(status));
664
1051
  });
665
- syncRef.current.syncable.getStatus().then((status) => {
666
- setDbStatus(getSyncStatus(status));
667
- });
668
1052
  if (options.shouldConnect) {
669
1053
  setShouldConnect(true);
670
1054
  } else {
@@ -674,17 +1058,15 @@ function BasicProvider({
674
1058
  }
675
1059
  }
676
1060
  async function checkSchema() {
677
- const valid = (0, import_schema2.validateSchema)(schema);
678
- if (!valid.valid) {
679
- log("Basic Schema is invalid!", valid.errors);
680
- console.group("Schema Errors");
1061
+ const result = await validateAndCheckSchema(schema);
1062
+ if (!result.isValid) {
681
1063
  let errorMessage = "";
682
- valid.errors.forEach((error2, index) => {
683
- log(`${index + 1}:`, error2.message, ` - at ${error2.instancePath}`);
684
- errorMessage += `${index + 1}: ${error2.message} - at ${error2.instancePath}
1064
+ if (result.errors) {
1065
+ result.errors.forEach((error2, index) => {
1066
+ errorMessage += `${index + 1}: ${error2.message} - at ${error2.instancePath}
685
1067
  `;
686
- });
687
- console.groupEnd("Schema Errors");
1068
+ });
1069
+ }
688
1070
  setError({
689
1071
  code: "schema_invalid",
690
1072
  title: "Basic Schema is invalid!",
@@ -693,17 +1075,10 @@ function BasicProvider({
693
1075
  setIsReady(true);
694
1076
  return null;
695
1077
  }
696
- let schemaStatus = { valid: false };
697
- if (schema.version !== 0) {
698
- schemaStatus = await getSchemaStatus(schema);
699
- log("schemaStatus", schemaStatus);
700
- } else {
701
- log("schema not published - at version 0");
702
- }
703
- if (schemaStatus.valid) {
1078
+ if (result.schemaStatus.valid) {
704
1079
  initDb({ shouldConnect: true });
705
1080
  } else {
706
- log("Schema is invalid!", schemaStatus);
1081
+ log("Schema is invalid!", result.schemaStatus);
707
1082
  initDb({ shouldConnect: false });
708
1083
  }
709
1084
  checkForNewVersion();
@@ -715,43 +1090,72 @@ function BasicProvider({
715
1090
  }
716
1091
  }, []);
717
1092
  (0, import_react.useEffect)(() => {
718
- if (token && syncRef.current && isSignedIn && shouldConnect) {
719
- connectToDb();
1093
+ async function connectToDb() {
1094
+ if (token && syncRef.current && isSignedIn && shouldConnect) {
1095
+ const tok = await getToken();
1096
+ if (!tok) {
1097
+ log("no token found");
1098
+ return;
1099
+ }
1100
+ log("connecting to db...");
1101
+ syncRef.current?.connect({ access_token: tok }).catch((e) => {
1102
+ log("error connecting to db", e);
1103
+ });
1104
+ }
720
1105
  }
1106
+ connectToDb();
721
1107
  }, [isSignedIn, shouldConnect]);
722
- const connectToDb = async () => {
723
- const tok = await getToken();
724
- if (!tok) {
725
- log("no token found");
726
- return;
1108
+ (0, import_react.useEffect)(() => {
1109
+ if (project_id && schema && token?.access_token && !remoteDbRef.current) {
1110
+ log("Initializing Remote DB SDK");
1111
+ remoteDbRef.current = new BasicDBSDK({
1112
+ project_id,
1113
+ schema,
1114
+ getToken: () => getToken(),
1115
+ baseUrl: "https://api.basic.tech"
1116
+ });
727
1117
  }
728
- log("connecting to db...");
729
- syncRef.current.connect({ access_token: tok }).catch((e) => {
730
- log("error connecting to db", e);
731
- });
732
- };
1118
+ }, [token, project_id, schema]);
733
1119
  (0, import_react.useEffect)(() => {
734
1120
  const initializeAuth = async () => {
735
1121
  await storageAdapter.set(STORAGE_KEYS.DEBUG, debug ? "true" : "false");
1122
+ try {
1123
+ const versionUpdater = createVersionUpdater(storageAdapter, version, getMigrations());
1124
+ const updateResult = await versionUpdater.checkAndUpdate();
1125
+ if (updateResult.updated) {
1126
+ log(`App updated from ${updateResult.fromVersion} to ${updateResult.toVersion}`);
1127
+ } else {
1128
+ log(`App version ${updateResult.toVersion} is current`);
1129
+ }
1130
+ } catch (error2) {
1131
+ log("Version update failed:", error2);
1132
+ }
736
1133
  try {
737
1134
  if (window.location.search.includes("code")) {
738
- let code = window.location?.search?.split("code=")[1].split("&")[0];
1135
+ let code = window.location?.search?.split("code=")[1]?.split("&")[0];
1136
+ if (!code)
1137
+ return;
739
1138
  const state = await storageAdapter.get(STORAGE_KEYS.AUTH_STATE);
740
- if (!state || state !== window.location.search.split("state=")[1].split("&")[0]) {
1139
+ const urlState = window.location.search.split("state=")[1]?.split("&")[0];
1140
+ if (!state || state !== urlState) {
741
1141
  log("error: auth state does not match");
742
1142
  setIsAuthReady(true);
743
1143
  await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
744
- cleanOAuthParamsFromUrl();
1144
+ cleanOAuthParams();
745
1145
  return;
746
1146
  }
747
1147
  await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
748
- cleanOAuthParamsFromUrl();
749
- fetchToken(code);
1148
+ cleanOAuthParams();
1149
+ fetchToken(code).catch((error2) => {
1150
+ log("Error fetching token:", error2);
1151
+ });
750
1152
  } else {
751
1153
  const refreshToken = await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
752
1154
  if (refreshToken) {
753
1155
  log("Found refresh token in storage, attempting to refresh access token");
754
- fetchToken(refreshToken);
1156
+ fetchToken(refreshToken).catch((error2) => {
1157
+ log("Error fetching refresh token:", error2);
1158
+ });
755
1159
  } else {
756
1160
  let cookie_token = getCookie("basic_token");
757
1161
  if (cookie_token !== "") {
@@ -800,8 +1204,8 @@ function BasicProvider({
800
1204
  }
801
1205
  await storageAdapter.set(STORAGE_KEYS.USER_INFO, JSON.stringify(user2));
802
1206
  log("Cached user info in storage");
803
- document.cookie = `basic_access_token=${token.access_token}; Secure; SameSite=Strict; HttpOnly=false`;
804
- document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;
1207
+ setCookie("basic_access_token", token?.access_token || "", { httpOnly: false });
1208
+ setCookie("basic_token", JSON.stringify(token));
805
1209
  setUser(user2);
806
1210
  setIsSignedIn(true);
807
1211
  setIsAuthReady(true);
@@ -818,19 +1222,19 @@ function BasicProvider({
818
1222
  if (isExpired) {
819
1223
  log("token is expired - refreshing ...");
820
1224
  try {
821
- const newToken = await fetchToken(token?.refresh_token);
822
- fetchUser(newToken.access_token);
1225
+ const newToken = await fetchToken(token?.refresh_token || "");
1226
+ fetchUser(newToken?.access_token || "");
823
1227
  } catch (error2) {
824
1228
  log("Failed to refresh token in checkToken:", error2);
825
1229
  if (error2.message.includes("offline") || error2.message.includes("Network")) {
826
1230
  log("Network issue - continuing with expired token until online");
827
- fetchUser(token.access_token);
1231
+ fetchUser(token?.access_token || "");
828
1232
  } else {
829
1233
  setIsAuthReady(true);
830
1234
  }
831
1235
  }
832
1236
  } else {
833
- fetchUser(token.access_token);
1237
+ fetchUser(token?.access_token || "");
834
1238
  }
835
1239
  }
836
1240
  if (token) {
@@ -849,14 +1253,14 @@ function BasicProvider({
849
1253
  if (!redirectUrl || !redirectUrl.startsWith("http://") && !redirectUrl.startsWith("https://")) {
850
1254
  throw new Error("Invalid redirect URI provided");
851
1255
  }
852
- let baseUrl2 = "https://api.basic.tech/auth/authorize";
853
- baseUrl2 += `?client_id=${project_id}`;
854
- baseUrl2 += `&redirect_uri=${encodeURIComponent(redirectUrl)}`;
855
- baseUrl2 += `&response_type=code`;
856
- baseUrl2 += `&scope=profile`;
857
- baseUrl2 += `&state=${randomState}`;
1256
+ let baseUrl = "https://api.basic.tech/auth/authorize";
1257
+ baseUrl += `?client_id=${project_id}`;
1258
+ baseUrl += `&redirect_uri=${encodeURIComponent(redirectUrl)}`;
1259
+ baseUrl += `&response_type=code`;
1260
+ baseUrl += `&scope=profile`;
1261
+ baseUrl += `&state=${randomState}`;
858
1262
  log("Generated sign-in link successfully");
859
- return baseUrl2;
1263
+ return baseUrl;
860
1264
  } catch (error2) {
861
1265
  log("Error generating sign-in link:", error2);
862
1266
  throw error2;
@@ -878,7 +1282,7 @@ function BasicProvider({
878
1282
  window.location.href = signInLink;
879
1283
  } catch (error2) {
880
1284
  log("Error during sign-in:", error2);
881
- if (isDevelopment()) {
1285
+ if (isDevMode()) {
882
1286
  setError({
883
1287
  code: "signin_error",
884
1288
  title: "Sign-in Failed",
@@ -902,7 +1306,7 @@ function BasicProvider({
902
1306
  }
903
1307
  }
904
1308
  await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
905
- cleanOAuthParamsFromUrl();
1309
+ cleanOAuthParams();
906
1310
  const token2 = await fetchToken(code);
907
1311
  if (token2) {
908
1312
  log("signinWithCode successful");
@@ -923,16 +1327,16 @@ function BasicProvider({
923
1327
  setUser({});
924
1328
  setIsSignedIn(false);
925
1329
  setToken(null);
926
- document.cookie = `basic_token=; Secure; SameSite=Strict`;
927
- document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
1330
+ clearCookie("basic_token");
1331
+ clearCookie("basic_access_token");
928
1332
  await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
929
1333
  await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
930
1334
  await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
931
1335
  if (syncRef.current) {
932
1336
  (async () => {
933
1337
  try {
934
- await syncRef.current.close();
935
- await syncRef.current.delete({ disableAutoOpen: false });
1338
+ await syncRef.current?.close();
1339
+ await syncRef.current?.delete({ disableAutoOpen: false });
936
1340
  syncRef.current = null;
937
1341
  window?.location?.reload();
938
1342
  } catch (error2) {
@@ -991,20 +1395,6 @@ function BasicProvider({
991
1395
  }
992
1396
  return token?.access_token || "";
993
1397
  };
994
- function getCookie(name) {
995
- let cookieValue = "";
996
- if (document.cookie && document.cookie !== "") {
997
- const cookies = document.cookie.split(";");
998
- for (let i = 0; i < cookies.length; i++) {
999
- const cookie = cookies[i].trim();
1000
- if (cookie.substring(0, name.length + 1) === name + "=") {
1001
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
1002
- break;
1003
- }
1004
- }
1005
- }
1006
- return cookieValue;
1007
- }
1008
1398
  const fetchToken = async (code) => {
1009
1399
  try {
1010
1400
  if (!isOnline) {
@@ -1034,8 +1424,8 @@ function BasicProvider({
1034
1424
  }
1035
1425
  await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
1036
1426
  await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
1037
- document.cookie = `basic_token=; Secure; SameSite=Strict`;
1038
- document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
1427
+ clearCookie("basic_token");
1428
+ clearCookie("basic_access_token");
1039
1429
  setUser({});
1040
1430
  setIsSignedIn(false);
1041
1431
  setToken(null);
@@ -1048,7 +1438,7 @@ function BasicProvider({
1048
1438
  await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token2.refresh_token);
1049
1439
  log("Updated refresh token in storage");
1050
1440
  }
1051
- document.cookie = `basic_access_token=${token2.access_token}; Secure; SameSite=Strict; HttpOnly=false`;
1441
+ setCookie("basic_access_token", token2.access_token, { httpOnly: false });
1052
1442
  log("Updated access token in cookie");
1053
1443
  }
1054
1444
  return token2;
@@ -1057,8 +1447,8 @@ function BasicProvider({
1057
1447
  if (!error2.message.includes("offline") && !error2.message.includes("Network")) {
1058
1448
  await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
1059
1449
  await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
1060
- document.cookie = `basic_token=; Secure; SameSite=Strict`;
1061
- document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
1450
+ clearCookie("basic_token");
1451
+ clearCookie("basic_access_token");
1062
1452
  setUser({});
1063
1453
  setIsSignedIn(false);
1064
1454
  setToken(null);
@@ -1067,35 +1457,6 @@ function BasicProvider({
1067
1457
  throw error2;
1068
1458
  }
1069
1459
  };
1070
- const db_ = (tableName) => {
1071
- const checkSignIn = () => {
1072
- if (!isSignedIn) {
1073
- throw new Error("cannot use db. user not logged in.");
1074
- }
1075
- };
1076
- return {
1077
- get: async () => {
1078
- checkSignIn();
1079
- const tok = await getToken();
1080
- return get({ projectId: project_id, accountId: user.id, tableName, token: tok });
1081
- },
1082
- add: async (value) => {
1083
- checkSignIn();
1084
- const tok = await getToken();
1085
- return add({ projectId: project_id, accountId: user.id, tableName, value, token: tok });
1086
- },
1087
- update: async (id, value) => {
1088
- checkSignIn();
1089
- const tok = await getToken();
1090
- return update({ projectId: project_id, accountId: user.id, tableName, id, value, token: tok });
1091
- },
1092
- delete: async (id) => {
1093
- checkSignIn();
1094
- const tok = await getToken();
1095
- return deleteRecord({ projectId: project_id, accountId: user.id, tableName, id, token: tok });
1096
- }
1097
- };
1098
- };
1099
1460
  const noDb = {
1100
1461
  collection: () => {
1101
1462
  throw new Error("no basicdb found - initialization failed. double check your schema.");
@@ -1112,9 +1473,10 @@ function BasicProvider({
1112
1473
  getToken,
1113
1474
  getSignInLink,
1114
1475
  db: syncRef.current ? syncRef.current : noDb,
1476
+ remoteDb: remoteDbRef.current ? remoteDbRef.current : noDb,
1115
1477
  dbStatus
1116
1478
  }, children: [
1117
- error && isDevelopment() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorDisplay, { error }),
1479
+ error && isDevMode() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorDisplay, { error }),
1118
1480
  isReady && children
1119
1481
  ] });
1120
1482
  }
@@ -1149,6 +1511,7 @@ function useBasic() {
1149
1511
  var import_dexie_react_hooks = require("dexie-react-hooks");
1150
1512
  // Annotate the CommonJS export names for ESM import in node:
1151
1513
  0 && (module.exports = {
1514
+ BasicDBSDK,
1152
1515
  BasicProvider,
1153
1516
  useBasic,
1154
1517
  useQuery