@basictech/react 0.7.0-beta.5 → 0.7.0-beta.7
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/.turbo/turbo-build.log +10 -10
- package/changelog.md +12 -0
- package/dist/index.d.mts +266 -13
- package/dist/index.d.ts +266 -13
- package/dist/index.js +645 -184
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +625 -172
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/readme.md +203 -209
- package/src/AuthContext.tsx +197 -54
- package/src/core/db/RemoteCollection.ts +294 -0
- package/src/core/db/RemoteDB.ts +40 -0
- package/src/core/db/index.ts +7 -0
- package/src/core/db/types.ts +128 -0
- package/src/index.ts +25 -9
- package/src/sync/index.ts +133 -54
- package/src/db.ts +0 -55
package/dist/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
6
11
|
var __export = (target, all) => {
|
|
7
12
|
for (var name in all)
|
|
8
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -15,12 +20,160 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
20
|
}
|
|
16
21
|
return to;
|
|
17
22
|
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
18
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
32
|
|
|
33
|
+
// src/config.ts
|
|
34
|
+
var log;
|
|
35
|
+
var init_config = __esm({
|
|
36
|
+
"src/config.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
log = (...args) => {
|
|
39
|
+
try {
|
|
40
|
+
if (localStorage.getItem("basic_debug") === "true") {
|
|
41
|
+
console.log("[basic]", ...args);
|
|
42
|
+
}
|
|
43
|
+
} catch (e) {
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// src/sync/syncProtocol.js
|
|
50
|
+
var syncProtocol_exports = {};
|
|
51
|
+
__export(syncProtocol_exports, {
|
|
52
|
+
syncProtocol: () => syncProtocol
|
|
53
|
+
});
|
|
54
|
+
var import_dexie, syncProtocol;
|
|
55
|
+
var init_syncProtocol = __esm({
|
|
56
|
+
"src/sync/syncProtocol.js"() {
|
|
57
|
+
"use strict";
|
|
58
|
+
"use client";
|
|
59
|
+
import_dexie = require("dexie");
|
|
60
|
+
init_config();
|
|
61
|
+
syncProtocol = function() {
|
|
62
|
+
log("Initializing syncProtocol");
|
|
63
|
+
var RECONNECT_DELAY = 5e3;
|
|
64
|
+
import_dexie.Dexie.Syncable.registerSyncProtocol("websocket", {
|
|
65
|
+
sync: function(context, url, options, baseRevision, syncedRevision, changes, partial, applyRemoteChanges, onChangesAccepted, onSuccess, onError) {
|
|
66
|
+
var requestId = 0;
|
|
67
|
+
var acceptCallbacks = {};
|
|
68
|
+
log("Connecting to", url);
|
|
69
|
+
var ws = new WebSocket(url);
|
|
70
|
+
function sendChanges(changes2, baseRevision2, partial2, onChangesAccepted2) {
|
|
71
|
+
log("sendChanges", changes2.length, baseRevision2);
|
|
72
|
+
++requestId;
|
|
73
|
+
acceptCallbacks[requestId.toString()] = onChangesAccepted2;
|
|
74
|
+
ws.send(
|
|
75
|
+
JSON.stringify({
|
|
76
|
+
type: "changes",
|
|
77
|
+
changes: changes2,
|
|
78
|
+
partial: partial2,
|
|
79
|
+
baseRevision: baseRevision2,
|
|
80
|
+
requestId
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
ws.onopen = function(event) {
|
|
85
|
+
log("Opening socket - sending clientIdentity", context.clientIdentity);
|
|
86
|
+
ws.send(
|
|
87
|
+
JSON.stringify({
|
|
88
|
+
type: "clientIdentity",
|
|
89
|
+
clientIdentity: context.clientIdentity || null,
|
|
90
|
+
authToken: options.authToken,
|
|
91
|
+
schema: options.schema
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
ws.onerror = function(event) {
|
|
96
|
+
ws.close();
|
|
97
|
+
log("ws.onerror", event);
|
|
98
|
+
onError(event?.message, RECONNECT_DELAY);
|
|
99
|
+
};
|
|
100
|
+
ws.onclose = function(event) {
|
|
101
|
+
onError("Socket closed: " + event.reason, RECONNECT_DELAY);
|
|
102
|
+
};
|
|
103
|
+
var isFirstRound = true;
|
|
104
|
+
ws.onmessage = function(event) {
|
|
105
|
+
try {
|
|
106
|
+
var requestFromServer = JSON.parse(event.data);
|
|
107
|
+
log("requestFromServer", requestFromServer, { acceptCallback, isFirstRound });
|
|
108
|
+
if (requestFromServer.type == "clientIdentity") {
|
|
109
|
+
context.clientIdentity = requestFromServer.clientIdentity;
|
|
110
|
+
context.save();
|
|
111
|
+
sendChanges(changes, baseRevision, partial, onChangesAccepted);
|
|
112
|
+
ws.send(
|
|
113
|
+
JSON.stringify({
|
|
114
|
+
type: "subscribe",
|
|
115
|
+
syncedRevision
|
|
116
|
+
})
|
|
117
|
+
);
|
|
118
|
+
} else if (requestFromServer.type == "changes") {
|
|
119
|
+
applyRemoteChanges(
|
|
120
|
+
requestFromServer.changes,
|
|
121
|
+
requestFromServer.currentRevision,
|
|
122
|
+
requestFromServer.partial
|
|
123
|
+
);
|
|
124
|
+
if (isFirstRound && !requestFromServer.partial) {
|
|
125
|
+
onSuccess({
|
|
126
|
+
// Specify a react function that will react on additional client changes
|
|
127
|
+
react: function(changes2, baseRevision2, partial2, onChangesAccepted2) {
|
|
128
|
+
sendChanges(
|
|
129
|
+
changes2,
|
|
130
|
+
baseRevision2,
|
|
131
|
+
partial2,
|
|
132
|
+
onChangesAccepted2
|
|
133
|
+
);
|
|
134
|
+
},
|
|
135
|
+
// Specify a disconnect function that will close our socket so that we dont continue to monitor changes.
|
|
136
|
+
disconnect: function() {
|
|
137
|
+
ws.close();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
isFirstRound = false;
|
|
141
|
+
}
|
|
142
|
+
} else if (requestFromServer.type == "ack") {
|
|
143
|
+
var requestId2 = requestFromServer.requestId;
|
|
144
|
+
var acceptCallback = acceptCallbacks[requestId2.toString()];
|
|
145
|
+
acceptCallback();
|
|
146
|
+
delete acceptCallbacks[requestId2.toString()];
|
|
147
|
+
} else if (requestFromServer.type == "error") {
|
|
148
|
+
var requestId2 = requestFromServer.requestId;
|
|
149
|
+
ws.close();
|
|
150
|
+
onError(requestFromServer.message, Infinity);
|
|
151
|
+
} else {
|
|
152
|
+
log("unknown message", requestFromServer);
|
|
153
|
+
ws.close();
|
|
154
|
+
onError("unknown message", Infinity);
|
|
155
|
+
}
|
|
156
|
+
} catch (e) {
|
|
157
|
+
ws.close();
|
|
158
|
+
log("caught error", e);
|
|
159
|
+
onError(e, Infinity);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
20
168
|
// src/index.ts
|
|
21
169
|
var src_exports = {};
|
|
22
170
|
__export(src_exports, {
|
|
23
171
|
BasicProvider: () => BasicProvider,
|
|
172
|
+
NotAuthenticatedError: () => NotAuthenticatedError,
|
|
173
|
+
RemoteCollection: () => RemoteCollection,
|
|
174
|
+
RemoteDB: () => RemoteDB,
|
|
175
|
+
RemoteDBError: () => RemoteDBError,
|
|
176
|
+
STORAGE_KEYS: () => STORAGE_KEYS,
|
|
24
177
|
useBasic: () => useBasic,
|
|
25
178
|
useQuery: () => import_dexie_react_hooks.useLiveQuery
|
|
26
179
|
});
|
|
@@ -33,131 +186,32 @@ var import_jwt_decode = require("jwt-decode");
|
|
|
33
186
|
// src/sync/index.ts
|
|
34
187
|
var import_uuid = require("uuid");
|
|
35
188
|
var import_dexie2 = require("dexie");
|
|
36
|
-
|
|
37
|
-
var import_dexie_observable = require("dexie-observable");
|
|
38
|
-
|
|
39
|
-
// src/sync/syncProtocol.js
|
|
40
|
-
var import_dexie = require("dexie");
|
|
41
|
-
|
|
42
|
-
// src/config.ts
|
|
43
|
-
var log = (...args) => {
|
|
44
|
-
try {
|
|
45
|
-
if (localStorage.getItem("basic_debug") === "true") {
|
|
46
|
-
console.log("[basic]", ...args);
|
|
47
|
-
}
|
|
48
|
-
} catch (e) {
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// src/sync/syncProtocol.js
|
|
53
|
-
var syncProtocol = function() {
|
|
54
|
-
log("Initializing syncProtocol");
|
|
55
|
-
var RECONNECT_DELAY = 5e3;
|
|
56
|
-
import_dexie.Dexie.Syncable.registerSyncProtocol("websocket", {
|
|
57
|
-
sync: function(context, url, options, baseRevision, syncedRevision, changes, partial, applyRemoteChanges, onChangesAccepted, onSuccess, onError) {
|
|
58
|
-
var requestId = 0;
|
|
59
|
-
var acceptCallbacks = {};
|
|
60
|
-
log("Connecting to", url);
|
|
61
|
-
var ws = new WebSocket(url);
|
|
62
|
-
function sendChanges(changes2, baseRevision2, partial2, onChangesAccepted2) {
|
|
63
|
-
log("sendChanges", changes2.length, baseRevision2);
|
|
64
|
-
++requestId;
|
|
65
|
-
acceptCallbacks[requestId.toString()] = onChangesAccepted2;
|
|
66
|
-
ws.send(
|
|
67
|
-
JSON.stringify({
|
|
68
|
-
type: "changes",
|
|
69
|
-
changes: changes2,
|
|
70
|
-
partial: partial2,
|
|
71
|
-
baseRevision: baseRevision2,
|
|
72
|
-
requestId
|
|
73
|
-
})
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
ws.onopen = function(event) {
|
|
77
|
-
log("Opening socket - sending clientIdentity", context.clientIdentity);
|
|
78
|
-
ws.send(
|
|
79
|
-
JSON.stringify({
|
|
80
|
-
type: "clientIdentity",
|
|
81
|
-
clientIdentity: context.clientIdentity || null,
|
|
82
|
-
authToken: options.authToken,
|
|
83
|
-
schema: options.schema
|
|
84
|
-
})
|
|
85
|
-
);
|
|
86
|
-
};
|
|
87
|
-
ws.onerror = function(event) {
|
|
88
|
-
ws.close();
|
|
89
|
-
log("ws.onerror", event);
|
|
90
|
-
onError(event?.message, RECONNECT_DELAY);
|
|
91
|
-
};
|
|
92
|
-
ws.onclose = function(event) {
|
|
93
|
-
onError("Socket closed: " + event.reason, RECONNECT_DELAY);
|
|
94
|
-
};
|
|
95
|
-
var isFirstRound = true;
|
|
96
|
-
ws.onmessage = function(event) {
|
|
97
|
-
try {
|
|
98
|
-
var requestFromServer = JSON.parse(event.data);
|
|
99
|
-
log("requestFromServer", requestFromServer, { acceptCallback, isFirstRound });
|
|
100
|
-
if (requestFromServer.type == "clientIdentity") {
|
|
101
|
-
context.clientIdentity = requestFromServer.clientIdentity;
|
|
102
|
-
context.save();
|
|
103
|
-
sendChanges(changes, baseRevision, partial, onChangesAccepted);
|
|
104
|
-
ws.send(
|
|
105
|
-
JSON.stringify({
|
|
106
|
-
type: "subscribe",
|
|
107
|
-
syncedRevision
|
|
108
|
-
})
|
|
109
|
-
);
|
|
110
|
-
} else if (requestFromServer.type == "changes") {
|
|
111
|
-
applyRemoteChanges(
|
|
112
|
-
requestFromServer.changes,
|
|
113
|
-
requestFromServer.currentRevision,
|
|
114
|
-
requestFromServer.partial
|
|
115
|
-
);
|
|
116
|
-
if (isFirstRound && !requestFromServer.partial) {
|
|
117
|
-
onSuccess({
|
|
118
|
-
// Specify a react function that will react on additional client changes
|
|
119
|
-
react: function(changes2, baseRevision2, partial2, onChangesAccepted2) {
|
|
120
|
-
sendChanges(
|
|
121
|
-
changes2,
|
|
122
|
-
baseRevision2,
|
|
123
|
-
partial2,
|
|
124
|
-
onChangesAccepted2
|
|
125
|
-
);
|
|
126
|
-
},
|
|
127
|
-
// Specify a disconnect function that will close our socket so that we dont continue to monitor changes.
|
|
128
|
-
disconnect: function() {
|
|
129
|
-
ws.close();
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
isFirstRound = false;
|
|
133
|
-
}
|
|
134
|
-
} else if (requestFromServer.type == "ack") {
|
|
135
|
-
var requestId2 = requestFromServer.requestId;
|
|
136
|
-
var acceptCallback = acceptCallbacks[requestId2.toString()];
|
|
137
|
-
acceptCallback();
|
|
138
|
-
delete acceptCallbacks[requestId2.toString()];
|
|
139
|
-
} else if (requestFromServer.type == "error") {
|
|
140
|
-
var requestId2 = requestFromServer.requestId;
|
|
141
|
-
ws.close();
|
|
142
|
-
onError(requestFromServer.message, Infinity);
|
|
143
|
-
} else {
|
|
144
|
-
log("unknown message", requestFromServer);
|
|
145
|
-
ws.close();
|
|
146
|
-
onError("unknown message", Infinity);
|
|
147
|
-
}
|
|
148
|
-
} catch (e) {
|
|
149
|
-
ws.close();
|
|
150
|
-
log("caught error", e);
|
|
151
|
-
onError(e, Infinity);
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
// src/sync/index.ts
|
|
189
|
+
init_config();
|
|
159
190
|
var import_schema = require("@basictech/schema");
|
|
160
|
-
|
|
191
|
+
var dexieExtensionsLoaded = false;
|
|
192
|
+
var initPromise = null;
|
|
193
|
+
async function initDexieExtensions() {
|
|
194
|
+
if (dexieExtensionsLoaded)
|
|
195
|
+
return;
|
|
196
|
+
if (typeof window === "undefined")
|
|
197
|
+
return;
|
|
198
|
+
if (initPromise)
|
|
199
|
+
return initPromise;
|
|
200
|
+
initPromise = (async () => {
|
|
201
|
+
try {
|
|
202
|
+
await import("dexie-syncable");
|
|
203
|
+
await import("dexie-observable");
|
|
204
|
+
const { syncProtocol: syncProtocol2 } = await Promise.resolve().then(() => (init_syncProtocol(), syncProtocol_exports));
|
|
205
|
+
syncProtocol2();
|
|
206
|
+
dexieExtensionsLoaded = true;
|
|
207
|
+
log("Dexie extensions loaded successfully");
|
|
208
|
+
} catch (error) {
|
|
209
|
+
console.error("Failed to load Dexie extensions:", error);
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
})();
|
|
213
|
+
return initPromise;
|
|
214
|
+
}
|
|
161
215
|
var BasicSync = class extends import_dexie2.Dexie {
|
|
162
216
|
basic_schema;
|
|
163
217
|
constructor(name, options) {
|
|
@@ -223,63 +277,388 @@ var BasicSync = class extends import_dexie2.Dexie {
|
|
|
223
277
|
return this.syncable;
|
|
224
278
|
}
|
|
225
279
|
collection(name) {
|
|
280
|
+
if (this.basic_schema?.tables && !this.basic_schema.tables[name]) {
|
|
281
|
+
throw new Error(`Table "${name}" not found in schema`);
|
|
282
|
+
}
|
|
283
|
+
const table = this.table(name);
|
|
226
284
|
return {
|
|
227
285
|
/**
|
|
228
286
|
* Returns the underlying Dexie table
|
|
229
287
|
* @type {Dexie.Table}
|
|
230
288
|
*/
|
|
231
|
-
ref:
|
|
289
|
+
ref: table,
|
|
232
290
|
// --- WRITE ---- //
|
|
233
|
-
|
|
291
|
+
/**
|
|
292
|
+
* Add a new record - returns the full object with generated id
|
|
293
|
+
*/
|
|
294
|
+
add: async (data) => {
|
|
234
295
|
const valid = (0, import_schema.validateData)(this.basic_schema, name, data);
|
|
235
296
|
if (!valid.valid) {
|
|
236
297
|
log("Invalid data", valid);
|
|
237
|
-
|
|
298
|
+
throw new Error(valid.message || "Data validation failed");
|
|
238
299
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
300
|
+
const id = (0, import_uuid.v7)();
|
|
301
|
+
const fullData = { id, ...data };
|
|
302
|
+
await table.add(fullData);
|
|
303
|
+
return fullData;
|
|
243
304
|
},
|
|
244
|
-
|
|
305
|
+
/**
|
|
306
|
+
* Put (upsert) a record - returns the full object
|
|
307
|
+
*/
|
|
308
|
+
put: async (data) => {
|
|
309
|
+
if (!data.id) {
|
|
310
|
+
throw new Error("put() requires an id field");
|
|
311
|
+
}
|
|
245
312
|
const valid = (0, import_schema.validateData)(this.basic_schema, name, data);
|
|
246
313
|
if (!valid.valid) {
|
|
247
314
|
log("Invalid data", valid);
|
|
248
|
-
|
|
315
|
+
throw new Error(valid.message || "Data validation failed");
|
|
249
316
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
...data
|
|
253
|
-
});
|
|
317
|
+
await table.put(data);
|
|
318
|
+
return data;
|
|
254
319
|
},
|
|
255
|
-
|
|
320
|
+
/**
|
|
321
|
+
* Update an existing record - returns updated object or null
|
|
322
|
+
*/
|
|
323
|
+
update: async (id, data) => {
|
|
324
|
+
if (!id) {
|
|
325
|
+
throw new Error("update() requires an id");
|
|
326
|
+
}
|
|
256
327
|
const valid = (0, import_schema.validateData)(this.basic_schema, name, data, false);
|
|
257
328
|
if (!valid.valid) {
|
|
258
329
|
log("Invalid data", valid);
|
|
259
|
-
|
|
330
|
+
throw new Error(valid.message || "Data validation failed");
|
|
331
|
+
}
|
|
332
|
+
const updated = await table.update(id, data);
|
|
333
|
+
if (updated === 0) {
|
|
334
|
+
return null;
|
|
260
335
|
}
|
|
261
|
-
|
|
336
|
+
const record = await table.get(id);
|
|
337
|
+
return record || null;
|
|
262
338
|
},
|
|
263
|
-
|
|
264
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Delete a record - returns true if deleted, false if not found
|
|
341
|
+
*/
|
|
342
|
+
delete: async (id) => {
|
|
343
|
+
if (!id) {
|
|
344
|
+
throw new Error("delete() requires an id");
|
|
345
|
+
}
|
|
346
|
+
const exists = await table.get(id);
|
|
347
|
+
if (!exists) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
await table.delete(id);
|
|
351
|
+
return true;
|
|
265
352
|
},
|
|
266
353
|
// --- READ ---- //
|
|
354
|
+
/**
|
|
355
|
+
* Get a single record by id - returns null if not found
|
|
356
|
+
*/
|
|
267
357
|
get: async (id) => {
|
|
268
|
-
|
|
358
|
+
if (!id) {
|
|
359
|
+
throw new Error("get() requires an id");
|
|
360
|
+
}
|
|
361
|
+
const record = await table.get(id);
|
|
362
|
+
return record || null;
|
|
269
363
|
},
|
|
364
|
+
/**
|
|
365
|
+
* Get all records in the collection
|
|
366
|
+
*/
|
|
270
367
|
getAll: async () => {
|
|
271
|
-
return
|
|
368
|
+
return table.toArray();
|
|
272
369
|
},
|
|
273
370
|
// --- QUERY ---- //
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
371
|
+
/**
|
|
372
|
+
* Filter records using a predicate function
|
|
373
|
+
*/
|
|
374
|
+
filter: async (fn) => {
|
|
375
|
+
return table.filter(fn).toArray();
|
|
376
|
+
},
|
|
377
|
+
/**
|
|
378
|
+
* Get the raw Dexie table for advanced queries
|
|
379
|
+
* @deprecated Use ref instead
|
|
380
|
+
*/
|
|
381
|
+
query: () => table
|
|
277
382
|
};
|
|
278
383
|
}
|
|
279
384
|
};
|
|
280
385
|
|
|
386
|
+
// src/core/db/types.ts
|
|
387
|
+
var RemoteDBError = class extends Error {
|
|
388
|
+
status;
|
|
389
|
+
response;
|
|
390
|
+
constructor(message, status, response) {
|
|
391
|
+
super(message);
|
|
392
|
+
this.name = "RemoteDBError";
|
|
393
|
+
this.status = status;
|
|
394
|
+
this.response = response;
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// src/core/db/RemoteCollection.ts
|
|
399
|
+
var import_schema2 = require("@basictech/schema");
|
|
400
|
+
var NotAuthenticatedError = class extends Error {
|
|
401
|
+
constructor(message = "Not authenticated") {
|
|
402
|
+
super(message);
|
|
403
|
+
this.name = "NotAuthenticatedError";
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
var RemoteCollection = class {
|
|
407
|
+
tableName;
|
|
408
|
+
config;
|
|
409
|
+
constructor(tableName, config) {
|
|
410
|
+
this.tableName = tableName;
|
|
411
|
+
this.config = config;
|
|
412
|
+
}
|
|
413
|
+
log(...args) {
|
|
414
|
+
if (this.config.debug) {
|
|
415
|
+
console.log("[RemoteDB]", ...args);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Check if an error is a "not authenticated" error
|
|
420
|
+
*/
|
|
421
|
+
isNotAuthenticatedError(error) {
|
|
422
|
+
if (error instanceof Error) {
|
|
423
|
+
const message = error.message.toLowerCase();
|
|
424
|
+
return message.includes("no token") || message.includes("not authenticated") || message.includes("please sign in");
|
|
425
|
+
}
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Helper to make authenticated API requests
|
|
430
|
+
* Automatically retries once on 401 (token expired) by refreshing the token
|
|
431
|
+
*/
|
|
432
|
+
async request(method, path, body, isRetry = false) {
|
|
433
|
+
const token = await this.config.getToken();
|
|
434
|
+
const url = `${this.config.serverUrl}${path}`;
|
|
435
|
+
this.log(`${method} ${url}`, body ? JSON.stringify(body) : "");
|
|
436
|
+
const response = await fetch(url, {
|
|
437
|
+
method,
|
|
438
|
+
headers: {
|
|
439
|
+
"Content-Type": "application/json",
|
|
440
|
+
"Authorization": `Bearer ${token}`
|
|
441
|
+
},
|
|
442
|
+
...body ? { body: JSON.stringify(body) } : {}
|
|
443
|
+
});
|
|
444
|
+
const responseData = await response.json().catch(() => ({}));
|
|
445
|
+
if (!response.ok) {
|
|
446
|
+
if (response.status === 401 && !isRetry) {
|
|
447
|
+
this.log("Got 401, retrying with fresh token...");
|
|
448
|
+
return this.request(method, path, body, true);
|
|
449
|
+
}
|
|
450
|
+
if (this.config.debug) {
|
|
451
|
+
console.error(`[RemoteDB] Error ${response.status}:`, responseData);
|
|
452
|
+
}
|
|
453
|
+
if (response.status === 401 && this.config.onAuthError) {
|
|
454
|
+
this.config.onAuthError({
|
|
455
|
+
status: response.status,
|
|
456
|
+
message: "Authentication failed",
|
|
457
|
+
response: responseData
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
const errorMessage = responseData.message || responseData.error || responseData.detail || (typeof responseData === "string" ? responseData : `API request failed: ${response.status}`);
|
|
461
|
+
throw new RemoteDBError(errorMessage, response.status, responseData);
|
|
462
|
+
}
|
|
463
|
+
this.log("Response:", responseData);
|
|
464
|
+
return responseData;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Validate data against schema if available
|
|
468
|
+
*/
|
|
469
|
+
validateData(data, checkRequired = true) {
|
|
470
|
+
if (this.config.schema) {
|
|
471
|
+
const result = (0, import_schema2.validateData)(this.config.schema, this.tableName, data, checkRequired);
|
|
472
|
+
if (!result.valid) {
|
|
473
|
+
throw new Error(result.message || "Data validation failed");
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get the base path for this collection
|
|
479
|
+
*/
|
|
480
|
+
get basePath() {
|
|
481
|
+
return `/account/${this.config.projectId}/db/${this.tableName}`;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Add a new record to the collection
|
|
485
|
+
* The server generates the ID
|
|
486
|
+
* Requires authentication - throws NotAuthenticatedError if not signed in
|
|
487
|
+
*/
|
|
488
|
+
async add(data) {
|
|
489
|
+
this.validateData(data, true);
|
|
490
|
+
try {
|
|
491
|
+
const result = await this.request(
|
|
492
|
+
"POST",
|
|
493
|
+
this.basePath,
|
|
494
|
+
{ value: data }
|
|
495
|
+
);
|
|
496
|
+
return result.data;
|
|
497
|
+
} catch (error) {
|
|
498
|
+
if (this.isNotAuthenticatedError(error)) {
|
|
499
|
+
throw new NotAuthenticatedError("Sign in required to add items");
|
|
500
|
+
}
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Put (upsert) a record - requires id
|
|
506
|
+
* Requires authentication - throws NotAuthenticatedError if not signed in
|
|
507
|
+
*/
|
|
508
|
+
async put(data) {
|
|
509
|
+
if (!data.id) {
|
|
510
|
+
throw new Error("put() requires an id field");
|
|
511
|
+
}
|
|
512
|
+
const { id, ...rest } = data;
|
|
513
|
+
this.validateData(rest, true);
|
|
514
|
+
try {
|
|
515
|
+
const result = await this.request(
|
|
516
|
+
"PUT",
|
|
517
|
+
`${this.basePath}/${id}`,
|
|
518
|
+
{ value: rest }
|
|
519
|
+
);
|
|
520
|
+
return result.data || data;
|
|
521
|
+
} catch (error) {
|
|
522
|
+
if (this.isNotAuthenticatedError(error)) {
|
|
523
|
+
throw new NotAuthenticatedError("Sign in required to update items");
|
|
524
|
+
}
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Update an existing record by id
|
|
530
|
+
* Requires authentication - throws NotAuthenticatedError if not signed in
|
|
531
|
+
*/
|
|
532
|
+
async update(id, data) {
|
|
533
|
+
if (!id) {
|
|
534
|
+
throw new Error("update() requires an id");
|
|
535
|
+
}
|
|
536
|
+
this.validateData(data, false);
|
|
537
|
+
try {
|
|
538
|
+
const result = await this.request(
|
|
539
|
+
"PATCH",
|
|
540
|
+
`${this.basePath}/${id}`,
|
|
541
|
+
{ value: data }
|
|
542
|
+
);
|
|
543
|
+
return result.data || null;
|
|
544
|
+
} catch (error) {
|
|
545
|
+
if (error instanceof RemoteDBError && error.status === 404) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
if (this.isNotAuthenticatedError(error)) {
|
|
549
|
+
throw new NotAuthenticatedError("Sign in required to update items");
|
|
550
|
+
}
|
|
551
|
+
throw error;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Delete a record by id
|
|
556
|
+
* Requires authentication - throws NotAuthenticatedError if not signed in
|
|
557
|
+
*/
|
|
558
|
+
async delete(id) {
|
|
559
|
+
if (!id) {
|
|
560
|
+
throw new Error("delete() requires an id");
|
|
561
|
+
}
|
|
562
|
+
try {
|
|
563
|
+
await this.request(
|
|
564
|
+
"DELETE",
|
|
565
|
+
`${this.basePath}/${id}`
|
|
566
|
+
);
|
|
567
|
+
return true;
|
|
568
|
+
} catch (error) {
|
|
569
|
+
if (error instanceof RemoteDBError && error.status === 404) {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
if (this.isNotAuthenticatedError(error)) {
|
|
573
|
+
throw new NotAuthenticatedError("Sign in required to delete items");
|
|
574
|
+
}
|
|
575
|
+
throw error;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Get a single record by id
|
|
580
|
+
* Returns null if not authenticated (graceful degradation for read operations)
|
|
581
|
+
*/
|
|
582
|
+
async get(id) {
|
|
583
|
+
if (!id) {
|
|
584
|
+
throw new Error("get() requires an id");
|
|
585
|
+
}
|
|
586
|
+
try {
|
|
587
|
+
const result = await this.request(
|
|
588
|
+
"GET",
|
|
589
|
+
`${this.basePath}?id=${id}`
|
|
590
|
+
);
|
|
591
|
+
return result.data?.[0] || null;
|
|
592
|
+
} catch (error) {
|
|
593
|
+
if (this.isNotAuthenticatedError(error)) {
|
|
594
|
+
this.log("Not authenticated - returning null for get()");
|
|
595
|
+
}
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Get all records in the collection
|
|
601
|
+
* Returns empty array if not authenticated (graceful degradation for read operations)
|
|
602
|
+
*/
|
|
603
|
+
async getAll() {
|
|
604
|
+
try {
|
|
605
|
+
const result = await this.request(
|
|
606
|
+
"GET",
|
|
607
|
+
this.basePath
|
|
608
|
+
);
|
|
609
|
+
return result.data || [];
|
|
610
|
+
} catch (error) {
|
|
611
|
+
if (this.isNotAuthenticatedError(error)) {
|
|
612
|
+
this.log("Not authenticated - returning empty array for getAll()");
|
|
613
|
+
return [];
|
|
614
|
+
}
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Filter records using a predicate function
|
|
620
|
+
* Note: This fetches all records and filters client-side
|
|
621
|
+
* Returns empty array if not authenticated (graceful degradation for read operations)
|
|
622
|
+
*/
|
|
623
|
+
async filter(fn) {
|
|
624
|
+
const all = await this.getAll();
|
|
625
|
+
return all.filter(fn);
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* ref is not available for remote collections
|
|
629
|
+
*/
|
|
630
|
+
ref = void 0;
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
// src/core/db/RemoteDB.ts
|
|
634
|
+
var RemoteDB = class {
|
|
635
|
+
config;
|
|
636
|
+
collections = /* @__PURE__ */ new Map();
|
|
637
|
+
constructor(config) {
|
|
638
|
+
this.config = config;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Get a collection by name
|
|
642
|
+
* Collections are cached for reuse
|
|
643
|
+
*/
|
|
644
|
+
collection(name) {
|
|
645
|
+
if (this.collections.has(name)) {
|
|
646
|
+
return this.collections.get(name);
|
|
647
|
+
}
|
|
648
|
+
if (this.config.schema?.tables && !this.config.schema.tables[name]) {
|
|
649
|
+
throw new Error(`Table "${name}" not found in schema`);
|
|
650
|
+
}
|
|
651
|
+
const collection = new RemoteCollection(name, this.config);
|
|
652
|
+
this.collections.set(name, collection);
|
|
653
|
+
return collection;
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
// src/AuthContext.tsx
|
|
658
|
+
init_config();
|
|
659
|
+
|
|
281
660
|
// package.json
|
|
282
|
-
var version = "0.7.0-beta.
|
|
661
|
+
var version = "0.7.0-beta.6";
|
|
283
662
|
|
|
284
663
|
// src/updater/versionUpdater.ts
|
|
285
664
|
var VersionUpdater = class {
|
|
@@ -461,6 +840,7 @@ function clearCookie(name) {
|
|
|
461
840
|
}
|
|
462
841
|
|
|
463
842
|
// src/utils/network.ts
|
|
843
|
+
init_config();
|
|
464
844
|
function isDevelopment(debug) {
|
|
465
845
|
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;
|
|
466
846
|
}
|
|
@@ -523,10 +903,11 @@ function getSyncStatus(statusCode) {
|
|
|
523
903
|
}
|
|
524
904
|
|
|
525
905
|
// src/utils/schema.ts
|
|
526
|
-
var
|
|
906
|
+
var import_schema3 = require("@basictech/schema");
|
|
907
|
+
init_config();
|
|
527
908
|
async function getSchemaStatus(schema) {
|
|
528
909
|
const projectId = schema.project_id;
|
|
529
|
-
const valid = (0,
|
|
910
|
+
const valid = (0, import_schema3.validateSchema)(schema);
|
|
530
911
|
if (!valid.valid) {
|
|
531
912
|
console.warn("BasicDB Error: your local schema is invalid. Please fix errors and try again - sync is disabled");
|
|
532
913
|
return {
|
|
@@ -565,7 +946,7 @@ async function getSchemaStatus(schema) {
|
|
|
565
946
|
latest: latestSchema
|
|
566
947
|
};
|
|
567
948
|
} else if (latestSchema.version === schema.version) {
|
|
568
|
-
const changes = (0,
|
|
949
|
+
const changes = (0, import_schema3.compareSchemas)(schema, latestSchema);
|
|
569
950
|
if (changes.valid) {
|
|
570
951
|
return {
|
|
571
952
|
valid: true,
|
|
@@ -589,7 +970,7 @@ async function getSchemaStatus(schema) {
|
|
|
589
970
|
}
|
|
590
971
|
}
|
|
591
972
|
async function validateAndCheckSchema(schema) {
|
|
592
|
-
const valid = (0,
|
|
973
|
+
const valid = (0, import_schema3.validateSchema)(schema);
|
|
593
974
|
if (!valid.valid) {
|
|
594
975
|
log("Basic Schema is invalid!", valid.errors);
|
|
595
976
|
console.group("Schema Errors");
|
|
@@ -626,29 +1007,44 @@ var DEFAULT_AUTH_CONFIG = {
|
|
|
626
1007
|
server_url: "https://api.basic.tech",
|
|
627
1008
|
ws_url: "wss://pds.basic.id/ws"
|
|
628
1009
|
};
|
|
1010
|
+
var noDb = {
|
|
1011
|
+
collection: () => {
|
|
1012
|
+
throw new Error("no basicdb found - initialization failed. double check your schema.");
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
629
1015
|
var BasicContext = (0, import_react.createContext)({
|
|
630
|
-
|
|
631
|
-
|
|
1016
|
+
// Auth state
|
|
1017
|
+
isReady: false,
|
|
632
1018
|
isSignedIn: false,
|
|
633
1019
|
user: null,
|
|
634
|
-
|
|
1020
|
+
// Auth actions
|
|
1021
|
+
signIn: () => Promise.resolve(),
|
|
1022
|
+
signOut: () => Promise.resolve(),
|
|
1023
|
+
signInWithCode: () => Promise.resolve({ success: false }),
|
|
1024
|
+
// Token management
|
|
1025
|
+
getToken: () => Promise.reject(new Error("no token")),
|
|
1026
|
+
getSignInUrl: () => Promise.resolve(""),
|
|
1027
|
+
// DB access
|
|
1028
|
+
db: noDb,
|
|
1029
|
+
dbStatus: "LOADING" /* LOADING */,
|
|
1030
|
+
dbMode: "sync",
|
|
1031
|
+
// Legacy aliases
|
|
1032
|
+
isAuthReady: false,
|
|
635
1033
|
signin: () => Promise.resolve(),
|
|
636
|
-
|
|
637
|
-
}),
|
|
638
|
-
|
|
639
|
-
}),
|
|
640
|
-
getSignInLink: () => Promise.resolve(""),
|
|
641
|
-
db: {},
|
|
642
|
-
dbStatus: "LOADING" /* LOADING */
|
|
1034
|
+
signout: () => Promise.resolve(),
|
|
1035
|
+
signinWithCode: () => Promise.resolve({ success: false }),
|
|
1036
|
+
getSignInLink: () => Promise.resolve("")
|
|
643
1037
|
});
|
|
644
1038
|
function BasicProvider({
|
|
645
1039
|
children,
|
|
646
|
-
project_id,
|
|
1040
|
+
project_id: project_id_prop,
|
|
647
1041
|
schema,
|
|
648
1042
|
debug = false,
|
|
649
1043
|
storage,
|
|
650
|
-
auth
|
|
1044
|
+
auth,
|
|
1045
|
+
dbMode = "sync"
|
|
651
1046
|
}) {
|
|
1047
|
+
const project_id = schema?.project_id || project_id_prop;
|
|
652
1048
|
const [isAuthReady, setIsAuthReady] = (0, import_react.useState)(false);
|
|
653
1049
|
const [isSignedIn, setIsSignedIn] = (0, import_react.useState)(false);
|
|
654
1050
|
const [token, setToken] = (0, import_react.useState)(null);
|
|
@@ -660,6 +1056,7 @@ function BasicProvider({
|
|
|
660
1056
|
const [isOnline, setIsOnline] = (0, import_react.useState)(navigator.onLine);
|
|
661
1057
|
const [pendingRefresh, setPendingRefresh] = (0, import_react.useState)(false);
|
|
662
1058
|
const syncRef = (0, import_react.useRef)(null);
|
|
1059
|
+
const remoteDbRef = (0, import_react.useRef)(null);
|
|
663
1060
|
const storageAdapter = storage || new LocalStorageAdapter();
|
|
664
1061
|
const authConfig = {
|
|
665
1062
|
scopes: auth?.scopes || DEFAULT_AUTH_CONFIG.scopes,
|
|
@@ -699,9 +1096,10 @@ function BasicProvider({
|
|
|
699
1096
|
};
|
|
700
1097
|
}, [pendingRefresh, token]);
|
|
701
1098
|
(0, import_react.useEffect)(() => {
|
|
702
|
-
function
|
|
1099
|
+
async function initSyncDb(options) {
|
|
703
1100
|
if (!syncRef.current) {
|
|
704
|
-
log("Initializing Basic DB");
|
|
1101
|
+
log("Initializing Basic Sync DB");
|
|
1102
|
+
await initDexieExtensions();
|
|
705
1103
|
syncRef.current = new BasicSync("basicdb", { schema });
|
|
706
1104
|
syncRef.current.syncable.on("statusChanged", (status, url) => {
|
|
707
1105
|
setDbStatus(getSyncStatus(status));
|
|
@@ -714,6 +1112,33 @@ function BasicProvider({
|
|
|
714
1112
|
setIsReady(true);
|
|
715
1113
|
}
|
|
716
1114
|
}
|
|
1115
|
+
function initRemoteDb() {
|
|
1116
|
+
if (!remoteDbRef.current) {
|
|
1117
|
+
if (!project_id) {
|
|
1118
|
+
setError({
|
|
1119
|
+
code: "missing_project_id",
|
|
1120
|
+
title: "Project ID Required",
|
|
1121
|
+
message: "Remote mode requires a project_id. Provide it via schema.project_id or the project_id prop."
|
|
1122
|
+
});
|
|
1123
|
+
setIsReady(true);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
log("Initializing Basic Remote DB");
|
|
1127
|
+
remoteDbRef.current = new RemoteDB({
|
|
1128
|
+
serverUrl: authConfig.server_url,
|
|
1129
|
+
projectId: project_id,
|
|
1130
|
+
getToken,
|
|
1131
|
+
schema,
|
|
1132
|
+
debug,
|
|
1133
|
+
onAuthError: (error2) => {
|
|
1134
|
+
log("RemoteDB auth error:", error2);
|
|
1135
|
+
signout();
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
setDbStatus("ONLINE" /* ONLINE */);
|
|
1139
|
+
setIsReady(true);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
717
1142
|
async function checkSchema() {
|
|
718
1143
|
const result = await validateAndCheckSchema(schema);
|
|
719
1144
|
if (!result.isValid) {
|
|
@@ -732,18 +1157,26 @@ function BasicProvider({
|
|
|
732
1157
|
setIsReady(true);
|
|
733
1158
|
return null;
|
|
734
1159
|
}
|
|
735
|
-
if (
|
|
736
|
-
|
|
1160
|
+
if (dbMode === "remote") {
|
|
1161
|
+
initRemoteDb();
|
|
737
1162
|
} else {
|
|
738
|
-
|
|
739
|
-
|
|
1163
|
+
if (result.schemaStatus.valid) {
|
|
1164
|
+
await initSyncDb({ shouldConnect: true });
|
|
1165
|
+
} else {
|
|
1166
|
+
log("Schema is invalid!", result.schemaStatus);
|
|
1167
|
+
await initSyncDb({ shouldConnect: false });
|
|
1168
|
+
}
|
|
740
1169
|
}
|
|
741
1170
|
checkForNewVersion();
|
|
742
1171
|
}
|
|
743
1172
|
if (schema) {
|
|
744
1173
|
checkSchema();
|
|
745
1174
|
} else {
|
|
746
|
-
|
|
1175
|
+
if (dbMode === "remote" && project_id) {
|
|
1176
|
+
initRemoteDb();
|
|
1177
|
+
} else {
|
|
1178
|
+
setIsReady(true);
|
|
1179
|
+
}
|
|
747
1180
|
}
|
|
748
1181
|
}, []);
|
|
749
1182
|
(0, import_react.useEffect)(() => {
|
|
@@ -890,8 +1323,14 @@ function BasicProvider({
|
|
|
890
1323
|
const isExpired = decoded.exp && decoded.exp < Date.now() / 1e3 + expirationBuffer;
|
|
891
1324
|
if (isExpired) {
|
|
892
1325
|
log("token is expired - refreshing ...");
|
|
1326
|
+
const refreshToken = token?.refresh_token;
|
|
1327
|
+
if (!refreshToken) {
|
|
1328
|
+
log("Error: No refresh token available for expired token");
|
|
1329
|
+
setIsAuthReady(true);
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
893
1332
|
try {
|
|
894
|
-
const newToken = await fetchToken(
|
|
1333
|
+
const newToken = await fetchToken(refreshToken, true);
|
|
895
1334
|
fetchUser(newToken?.access_token || "");
|
|
896
1335
|
} catch (error2) {
|
|
897
1336
|
log("Failed to refresh token in checkToken:", error2);
|
|
@@ -1098,6 +1537,11 @@ function BasicProvider({
|
|
|
1098
1537
|
return token?.access_token || "";
|
|
1099
1538
|
};
|
|
1100
1539
|
const fetchToken = async (codeOrRefreshToken, isRefreshToken = false) => {
|
|
1540
|
+
if (!codeOrRefreshToken || codeOrRefreshToken.trim() === "") {
|
|
1541
|
+
const errorMsg = isRefreshToken ? "Refresh token is empty or undefined" : "Authorization code is empty or undefined";
|
|
1542
|
+
log("Error:", errorMsg);
|
|
1543
|
+
throw new Error(errorMsg);
|
|
1544
|
+
}
|
|
1101
1545
|
if (isRefreshToken && refreshPromiseRef.current) {
|
|
1102
1546
|
log("Reusing in-flight refresh token request");
|
|
1103
1547
|
return refreshPromiseRef.current;
|
|
@@ -1210,24 +1654,36 @@ function BasicProvider({
|
|
|
1210
1654
|
}
|
|
1211
1655
|
return refreshPromise;
|
|
1212
1656
|
};
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
1657
|
+
const getCurrentDb = () => {
|
|
1658
|
+
if (dbMode === "remote") {
|
|
1659
|
+
return remoteDbRef.current || noDb;
|
|
1216
1660
|
}
|
|
1661
|
+
return syncRef.current || noDb;
|
|
1217
1662
|
};
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
isAuthReady,
|
|
1663
|
+
const contextValue = {
|
|
1664
|
+
// Auth state (new naming)
|
|
1665
|
+
isReady: isAuthReady,
|
|
1221
1666
|
isSignedIn,
|
|
1222
1667
|
user,
|
|
1223
|
-
|
|
1668
|
+
// Auth actions (new camelCase naming)
|
|
1669
|
+
signIn: signin,
|
|
1670
|
+
signOut: signout,
|
|
1671
|
+
signInWithCode: signinWithCode,
|
|
1672
|
+
// Token management
|
|
1673
|
+
getToken,
|
|
1674
|
+
getSignInUrl: getSignInLink,
|
|
1675
|
+
// DB access
|
|
1676
|
+
db: getCurrentDb(),
|
|
1677
|
+
dbStatus,
|
|
1678
|
+
dbMode,
|
|
1679
|
+
// Legacy aliases (deprecated)
|
|
1680
|
+
isAuthReady,
|
|
1224
1681
|
signin,
|
|
1682
|
+
signout,
|
|
1225
1683
|
signinWithCode,
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
dbStatus
|
|
1230
|
-
}, children: [
|
|
1684
|
+
getSignInLink
|
|
1685
|
+
};
|
|
1686
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(BasicContext.Provider, { value: contextValue, children: [
|
|
1231
1687
|
error && isDevMode() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorDisplay, { error }),
|
|
1232
1688
|
isReady && children
|
|
1233
1689
|
] });
|
|
@@ -1264,6 +1720,11 @@ var import_dexie_react_hooks = require("dexie-react-hooks");
|
|
|
1264
1720
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1265
1721
|
0 && (module.exports = {
|
|
1266
1722
|
BasicProvider,
|
|
1723
|
+
NotAuthenticatedError,
|
|
1724
|
+
RemoteCollection,
|
|
1725
|
+
RemoteDB,
|
|
1726
|
+
RemoteDBError,
|
|
1727
|
+
STORAGE_KEYS,
|
|
1267
1728
|
useBasic,
|
|
1268
1729
|
useQuery
|
|
1269
1730
|
});
|