@basictech/react 0.8.0-beta.1 → 0.8.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/changelog.md +12 -0
- package/dist/index.d.mts +59 -43
- package/dist/index.d.ts +59 -43
- package/dist/index.js +1015 -200
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1006 -193
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
- package/readme.md +33 -0
- package/src/AuthContext.tsx +157 -177
- package/src/context.tsx +104 -0
- package/src/core/auth/AuthManager.ts +64 -40
- package/src/dev/BasicDevToolbar.tsx +665 -0
- package/src/index.ts +3 -2
- package/src/sync/syncProtocol.js +30 -0
- package/src/utils/network.ts +69 -16
package/dist/index.mjs
CHANGED
|
@@ -137,14 +137,37 @@ var init_syncProtocol = __esm({
|
|
|
137
137
|
onError("Authentication failed: " + (err.message || err), RECONNECT_DELAY);
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
|
+
function handleVisibilityResume() {
|
|
141
|
+
if (document.visibilityState === "visible" && ws.readyState === WebSocket.OPEN) {
|
|
142
|
+
log("Page became visible - refreshing token for WebSocket");
|
|
143
|
+
resolveGetToken()({ forceRefresh: true }).then(function(newToken) {
|
|
144
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
145
|
+
ws.send(JSON.stringify({ type: "tokenUpdate", authToken: newToken }));
|
|
146
|
+
scheduleTokenRefresh(newToken);
|
|
147
|
+
}
|
|
148
|
+
}).catch(function(err) {
|
|
149
|
+
log("Token refresh on visibility resume failed:", err);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (typeof document !== "undefined") {
|
|
154
|
+
document.addEventListener("visibilitychange", handleVisibilityResume);
|
|
155
|
+
}
|
|
156
|
+
function cleanupVisibilityListener() {
|
|
157
|
+
if (typeof document !== "undefined") {
|
|
158
|
+
document.removeEventListener("visibilitychange", handleVisibilityResume);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
140
161
|
ws.onerror = function(event) {
|
|
141
162
|
clearRefreshTimer();
|
|
163
|
+
cleanupVisibilityListener();
|
|
142
164
|
ws.close();
|
|
143
165
|
log("ws.onerror", event);
|
|
144
166
|
onError(event?.message, RECONNECT_DELAY);
|
|
145
167
|
};
|
|
146
168
|
ws.onclose = function(event) {
|
|
147
169
|
clearRefreshTimer();
|
|
170
|
+
cleanupVisibilityListener();
|
|
148
171
|
onError("Socket closed: " + event.reason, RECONNECT_DELAY);
|
|
149
172
|
};
|
|
150
173
|
var isFirstRound = true;
|
|
@@ -181,6 +204,7 @@ var init_syncProtocol = __esm({
|
|
|
181
204
|
},
|
|
182
205
|
disconnect: function() {
|
|
183
206
|
clearRefreshTimer();
|
|
207
|
+
cleanupVisibilityListener();
|
|
184
208
|
ws.close();
|
|
185
209
|
}
|
|
186
210
|
});
|
|
@@ -216,8 +240,809 @@ var init_syncProtocol = __esm({
|
|
|
216
240
|
}
|
|
217
241
|
});
|
|
218
242
|
|
|
243
|
+
// package.json
|
|
244
|
+
var version;
|
|
245
|
+
var init_package = __esm({
|
|
246
|
+
"package.json"() {
|
|
247
|
+
version = "0.8.0-beta.3";
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// src/utils/network.ts
|
|
252
|
+
import semver from "semver";
|
|
253
|
+
function isDevelopment(debug) {
|
|
254
|
+
if (debug === true) return true;
|
|
255
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV === "development") return true;
|
|
256
|
+
if (typeof window === "undefined" || !window.location) return false;
|
|
257
|
+
const host = window.location.hostname;
|
|
258
|
+
return host === "localhost" || host === "127.0.0.1" || host.includes("localhost") || host.includes("127.0.0.1") || host.includes(".local");
|
|
259
|
+
}
|
|
260
|
+
function normalizeVersion(v) {
|
|
261
|
+
if (v == null) return null;
|
|
262
|
+
const t = String(v).trim();
|
|
263
|
+
return t.length ? t : null;
|
|
264
|
+
}
|
|
265
|
+
function versionsMatch(a, b) {
|
|
266
|
+
const na = a.trim();
|
|
267
|
+
const nb = b.trim();
|
|
268
|
+
if (na === nb) return true;
|
|
269
|
+
const va = semver.valid(na);
|
|
270
|
+
const vb = semver.valid(nb);
|
|
271
|
+
if (va && vb) return semver.eq(va, vb);
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
function usesBetaDistTag(version2) {
|
|
275
|
+
const pre = semver.prerelease(version2);
|
|
276
|
+
const id = pre?.[0];
|
|
277
|
+
return typeof id === "string" && id.toLowerCase() === "beta";
|
|
278
|
+
}
|
|
279
|
+
async function checkForNewVersion() {
|
|
280
|
+
try {
|
|
281
|
+
const currentVersion = normalizeVersion(version);
|
|
282
|
+
if (!currentVersion) {
|
|
283
|
+
return { hasNewVersion: false, latestVersion: null, currentVersion: null };
|
|
284
|
+
}
|
|
285
|
+
const response = await fetch("https://registry.npmjs.org/@basictech/react", {
|
|
286
|
+
headers: { Accept: "application/vnd.npm.install-v1+json" }
|
|
287
|
+
});
|
|
288
|
+
if (!response.ok) {
|
|
289
|
+
throw new Error("Failed to fetch version from npm");
|
|
290
|
+
}
|
|
291
|
+
const data = await response.json();
|
|
292
|
+
const distTags = data["dist-tags"] ?? {};
|
|
293
|
+
const rawRegistry = usesBetaDistTag(currentVersion) ? distTags.beta ?? distTags.latest : distTags.latest;
|
|
294
|
+
const latestVersion = normalizeVersion(rawRegistry ?? null);
|
|
295
|
+
if (!latestVersion) {
|
|
296
|
+
throw new Error("Missing dist-tags from npm registry");
|
|
297
|
+
}
|
|
298
|
+
const same = versionsMatch(currentVersion, latestVersion);
|
|
299
|
+
if (!same && isDevelopment()) {
|
|
300
|
+
log("[basic] version check mismatch:", {
|
|
301
|
+
currentVersion,
|
|
302
|
+
registryVersion: latestVersion,
|
|
303
|
+
channel: usesBetaDistTag(currentVersion) ? "beta" : "latest"
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (!same) {
|
|
307
|
+
console.warn("[basic] New version available:", latestVersion, `
|
|
308
|
+
run "npm install @basictech/react@${latestVersion}" to update`);
|
|
309
|
+
}
|
|
310
|
+
if (usesBetaDistTag(currentVersion)) {
|
|
311
|
+
log("thank you for being on basictech/react beta :)");
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
hasNewVersion: !same,
|
|
315
|
+
latestVersion,
|
|
316
|
+
currentVersion
|
|
317
|
+
};
|
|
318
|
+
} catch (error) {
|
|
319
|
+
log("Error checking for new version:", error);
|
|
320
|
+
return {
|
|
321
|
+
hasNewVersion: false,
|
|
322
|
+
latestVersion: null,
|
|
323
|
+
currentVersion: null
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function cleanOAuthParamsFromUrl() {
|
|
328
|
+
if (window.location.search.includes("code") || window.location.search.includes("state")) {
|
|
329
|
+
const url = new URL(window.location.href);
|
|
330
|
+
url.searchParams.delete("code");
|
|
331
|
+
url.searchParams.delete("state");
|
|
332
|
+
window.history.replaceState({}, document.title, url.pathname + url.search);
|
|
333
|
+
log("Cleaned OAuth parameters from URL");
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function getSyncStatus(statusCode) {
|
|
337
|
+
switch (statusCode) {
|
|
338
|
+
case -1:
|
|
339
|
+
return "ERROR";
|
|
340
|
+
case 0:
|
|
341
|
+
return "OFFLINE";
|
|
342
|
+
case 1:
|
|
343
|
+
return "CONNECTING";
|
|
344
|
+
case 2:
|
|
345
|
+
return "ONLINE";
|
|
346
|
+
case 3:
|
|
347
|
+
return "SYNCING";
|
|
348
|
+
case 4:
|
|
349
|
+
return "ERROR_WILL_RETRY";
|
|
350
|
+
default:
|
|
351
|
+
return "UNKNOWN";
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
var init_network = __esm({
|
|
355
|
+
"src/utils/network.ts"() {
|
|
356
|
+
"use strict";
|
|
357
|
+
init_config();
|
|
358
|
+
init_package();
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// src/context.tsx
|
|
363
|
+
import { createContext, useContext } from "react";
|
|
364
|
+
function useBasic() {
|
|
365
|
+
return useContext(BasicContext);
|
|
366
|
+
}
|
|
367
|
+
var DBStatus, noDb, BasicContext;
|
|
368
|
+
var init_context = __esm({
|
|
369
|
+
"src/context.tsx"() {
|
|
370
|
+
"use strict";
|
|
371
|
+
DBStatus = /* @__PURE__ */ ((DBStatus2) => {
|
|
372
|
+
DBStatus2["LOADING"] = "LOADING";
|
|
373
|
+
DBStatus2["OFFLINE"] = "OFFLINE";
|
|
374
|
+
DBStatus2["CONNECTING"] = "CONNECTING";
|
|
375
|
+
DBStatus2["ONLINE"] = "ONLINE";
|
|
376
|
+
DBStatus2["SYNCING"] = "SYNCING";
|
|
377
|
+
DBStatus2["ERROR"] = "ERROR";
|
|
378
|
+
DBStatus2["ERROR_WILL_RETRY"] = "ERROR_WILL_RETRY";
|
|
379
|
+
DBStatus2["ERROR_TOKEN_EXPIRED"] = "ERROR_TOKEN_EXPIRED";
|
|
380
|
+
return DBStatus2;
|
|
381
|
+
})(DBStatus || {});
|
|
382
|
+
noDb = {
|
|
383
|
+
collection: () => {
|
|
384
|
+
throw new Error("no basicdb found - initialization failed. double check your schema.");
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
BasicContext = createContext({
|
|
388
|
+
isReady: false,
|
|
389
|
+
isSignedIn: false,
|
|
390
|
+
user: null,
|
|
391
|
+
did: null,
|
|
392
|
+
scope: null,
|
|
393
|
+
hasScope: () => false,
|
|
394
|
+
missingScopes: () => [],
|
|
395
|
+
signIn: () => Promise.resolve(),
|
|
396
|
+
signInWithHandle: () => Promise.resolve(),
|
|
397
|
+
signOut: () => Promise.resolve(),
|
|
398
|
+
signInWithCode: () => Promise.resolve({ success: false }),
|
|
399
|
+
getToken: (_options) => Promise.reject(new Error("no token")),
|
|
400
|
+
getSignInUrl: () => Promise.resolve(""),
|
|
401
|
+
db: noDb,
|
|
402
|
+
dbStatus: "LOADING" /* LOADING */,
|
|
403
|
+
dbMode: "sync",
|
|
404
|
+
devInfo: null,
|
|
405
|
+
refreshSchemaStatus: async () => {
|
|
406
|
+
},
|
|
407
|
+
isAuthReady: false,
|
|
408
|
+
signin: () => Promise.resolve(),
|
|
409
|
+
signout: () => Promise.resolve(),
|
|
410
|
+
signinWithCode: () => Promise.resolve({ success: false }),
|
|
411
|
+
getSignInLink: () => Promise.resolve("")
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// src/dev/BasicDevToolbar.tsx
|
|
417
|
+
var BasicDevToolbar_exports = {};
|
|
418
|
+
__export(BasicDevToolbar_exports, {
|
|
419
|
+
BasicDevToolbar: () => BasicDevToolbar
|
|
420
|
+
});
|
|
421
|
+
import { useCallback, useMemo, useState } from "react";
|
|
422
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
423
|
+
function toneForAuth(isReady, isSignedIn) {
|
|
424
|
+
if (!isReady) return "muted";
|
|
425
|
+
if (isSignedIn) return "ok";
|
|
426
|
+
return "warn";
|
|
427
|
+
}
|
|
428
|
+
function toneForDb(dbMode, dbStatus) {
|
|
429
|
+
if (dbMode === "remote") return dbStatus === "ONLINE" /* ONLINE */ ? "ok" : "warn";
|
|
430
|
+
if (dbStatus === "ONLINE" /* ONLINE */ || dbStatus === "SYNCING" /* SYNCING */) return "ok";
|
|
431
|
+
if (dbStatus === "CONNECTING" /* CONNECTING */ || dbStatus === "LOADING" /* LOADING */) return "warn";
|
|
432
|
+
if (dbStatus === "OFFLINE" /* OFFLINE */) return "muted";
|
|
433
|
+
return "bad";
|
|
434
|
+
}
|
|
435
|
+
function toneForSchema(info) {
|
|
436
|
+
if (!info) return "muted";
|
|
437
|
+
if (info.valid && info.status === "current") return "ok";
|
|
438
|
+
if (info.status === "unpublished") return "warn";
|
|
439
|
+
if (info.status === "no_schema") return "muted";
|
|
440
|
+
return "bad";
|
|
441
|
+
}
|
|
442
|
+
function dbStatusLabel(status) {
|
|
443
|
+
switch (status) {
|
|
444
|
+
case "LOADING" /* LOADING */:
|
|
445
|
+
return "Initializing";
|
|
446
|
+
case "OFFLINE" /* OFFLINE */:
|
|
447
|
+
return "Offline";
|
|
448
|
+
case "CONNECTING" /* CONNECTING */:
|
|
449
|
+
return "Connecting";
|
|
450
|
+
case "ONLINE" /* ONLINE */:
|
|
451
|
+
return "Connected";
|
|
452
|
+
case "SYNCING" /* SYNCING */:
|
|
453
|
+
return "Syncing";
|
|
454
|
+
case "ERROR" /* ERROR */:
|
|
455
|
+
return "Error";
|
|
456
|
+
case "ERROR_WILL_RETRY" /* ERROR_WILL_RETRY */:
|
|
457
|
+
return "Retrying";
|
|
458
|
+
case "ERROR_TOKEN_EXPIRED" /* ERROR_TOKEN_EXPIRED */:
|
|
459
|
+
return "Token refresh";
|
|
460
|
+
default:
|
|
461
|
+
return String(status);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function chipColor(tone) {
|
|
465
|
+
switch (tone) {
|
|
466
|
+
case "ok":
|
|
467
|
+
return "#22c55e";
|
|
468
|
+
case "warn":
|
|
469
|
+
return "#eab308";
|
|
470
|
+
case "bad":
|
|
471
|
+
return "#ef4444";
|
|
472
|
+
default:
|
|
473
|
+
return "#71717a";
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function displayDid(did) {
|
|
477
|
+
return did || "\u2014";
|
|
478
|
+
}
|
|
479
|
+
function displayUserLine(user) {
|
|
480
|
+
const parts = [];
|
|
481
|
+
if (user.sub) parts.push(`sub: ${user.sub}`);
|
|
482
|
+
if (user.email) parts.push(`email: ${user.email}`);
|
|
483
|
+
if (user.name) parts.push(`name: ${user.name}`);
|
|
484
|
+
return parts.length ? parts.join(" \xB7 ") : "\u2014";
|
|
485
|
+
}
|
|
486
|
+
function ClipboardIcon() {
|
|
487
|
+
return /* @__PURE__ */ jsxs(
|
|
488
|
+
"svg",
|
|
489
|
+
{
|
|
490
|
+
width: "14",
|
|
491
|
+
height: "14",
|
|
492
|
+
viewBox: "0 0 24 24",
|
|
493
|
+
fill: "none",
|
|
494
|
+
stroke: "currentColor",
|
|
495
|
+
strokeWidth: "2",
|
|
496
|
+
strokeLinecap: "round",
|
|
497
|
+
strokeLinejoin: "round",
|
|
498
|
+
"aria-hidden": true,
|
|
499
|
+
children: [
|
|
500
|
+
/* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
501
|
+
/* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
502
|
+
]
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
function SectionHeader({ children }) {
|
|
507
|
+
return /* @__PURE__ */ jsx(
|
|
508
|
+
"div",
|
|
509
|
+
{
|
|
510
|
+
style: {
|
|
511
|
+
fontSize: 10,
|
|
512
|
+
fontWeight: 700,
|
|
513
|
+
color: "#e4e4e7",
|
|
514
|
+
letterSpacing: "0.07em",
|
|
515
|
+
textTransform: "uppercase",
|
|
516
|
+
marginBottom: 8
|
|
517
|
+
},
|
|
518
|
+
children
|
|
519
|
+
}
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
function SectionRule() {
|
|
523
|
+
const bleed = PANEL_PAD_X;
|
|
524
|
+
return /* @__PURE__ */ jsx(
|
|
525
|
+
"div",
|
|
526
|
+
{
|
|
527
|
+
role: "separator",
|
|
528
|
+
style: {
|
|
529
|
+
height: 1,
|
|
530
|
+
background: "rgba(255, 255, 255, 0.055)",
|
|
531
|
+
marginLeft: -bleed,
|
|
532
|
+
marginRight: -bleed,
|
|
533
|
+
marginTop: 14,
|
|
534
|
+
marginBottom: 10,
|
|
535
|
+
width: `calc(100% + ${bleed * 2}px)`
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
function CopyableRow({
|
|
541
|
+
rowKey,
|
|
542
|
+
label,
|
|
543
|
+
copyText,
|
|
544
|
+
copiedKey,
|
|
545
|
+
onCopied,
|
|
546
|
+
children
|
|
547
|
+
}) {
|
|
548
|
+
const [hover, setHover] = useState(false);
|
|
549
|
+
const canCopy = copyText.length > 0;
|
|
550
|
+
const handleClick = useCallback(
|
|
551
|
+
(e) => {
|
|
552
|
+
e.stopPropagation();
|
|
553
|
+
if (!canCopy) return;
|
|
554
|
+
void navigator.clipboard.writeText(copyText).then(() => onCopied(rowKey));
|
|
555
|
+
},
|
|
556
|
+
[canCopy, copyText, onCopied, rowKey]
|
|
557
|
+
);
|
|
558
|
+
return /* @__PURE__ */ jsxs(
|
|
559
|
+
"div",
|
|
560
|
+
{
|
|
561
|
+
role: canCopy ? "button" : void 0,
|
|
562
|
+
tabIndex: canCopy ? 0 : void 0,
|
|
563
|
+
onClick: canCopy ? handleClick : void 0,
|
|
564
|
+
onKeyDown: canCopy ? (e) => {
|
|
565
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
566
|
+
e.preventDefault();
|
|
567
|
+
handleClick(e);
|
|
568
|
+
}
|
|
569
|
+
} : void 0,
|
|
570
|
+
onMouseEnter: () => setHover(true),
|
|
571
|
+
onMouseLeave: () => setHover(false),
|
|
572
|
+
style: {
|
|
573
|
+
display: "flex",
|
|
574
|
+
gap: 8,
|
|
575
|
+
marginBottom: 6,
|
|
576
|
+
alignItems: "flex-start",
|
|
577
|
+
borderRadius: 6,
|
|
578
|
+
padding: "4px 6px",
|
|
579
|
+
marginLeft: -6,
|
|
580
|
+
marginRight: -6,
|
|
581
|
+
cursor: canCopy ? "pointer" : "default",
|
|
582
|
+
background: hover && canCopy ? "rgba(255,255,255,0.06)" : "transparent",
|
|
583
|
+
transition: "background 0.12s ease"
|
|
584
|
+
},
|
|
585
|
+
children: [
|
|
586
|
+
/* @__PURE__ */ jsx("span", { style: { color: "#a1a1aa", minWidth: 88, flexShrink: 0, paddingTop: 2 }, children: label }),
|
|
587
|
+
/* @__PURE__ */ jsx(
|
|
588
|
+
"span",
|
|
589
|
+
{
|
|
590
|
+
style: {
|
|
591
|
+
flex: 1,
|
|
592
|
+
minWidth: 0,
|
|
593
|
+
wordBreak: "break-all",
|
|
594
|
+
paddingTop: 2,
|
|
595
|
+
lineHeight: 1.35
|
|
596
|
+
},
|
|
597
|
+
children
|
|
598
|
+
}
|
|
599
|
+
),
|
|
600
|
+
canCopy && /* @__PURE__ */ jsx(
|
|
601
|
+
"span",
|
|
602
|
+
{
|
|
603
|
+
style: {
|
|
604
|
+
flexShrink: 0,
|
|
605
|
+
color: copiedKey === rowKey ? "#22c55e" : "#71717a",
|
|
606
|
+
opacity: hover || copiedKey === rowKey ? 1 : 0,
|
|
607
|
+
transition: "opacity 0.12s ease, color 0.12s ease",
|
|
608
|
+
paddingTop: 2,
|
|
609
|
+
display: "flex",
|
|
610
|
+
alignItems: "flex-start"
|
|
611
|
+
},
|
|
612
|
+
title: "Copy value",
|
|
613
|
+
children: copiedKey === rowKey ? /* @__PURE__ */ jsx("span", { style: { fontSize: 10 }, children: "\u2713" }) : /* @__PURE__ */ jsx(ClipboardIcon, {})
|
|
614
|
+
}
|
|
615
|
+
)
|
|
616
|
+
]
|
|
617
|
+
}
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
function BasicDevToolbar({ enabled = true, debug }) {
|
|
621
|
+
const {
|
|
622
|
+
isReady,
|
|
623
|
+
isSignedIn,
|
|
624
|
+
user,
|
|
625
|
+
did,
|
|
626
|
+
scope,
|
|
627
|
+
missingScopes,
|
|
628
|
+
dbMode,
|
|
629
|
+
dbStatus,
|
|
630
|
+
devInfo,
|
|
631
|
+
refreshSchemaStatus
|
|
632
|
+
} = useBasic();
|
|
633
|
+
const [open, setOpen] = useState(false);
|
|
634
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
635
|
+
const [copied, setCopied] = useState(false);
|
|
636
|
+
const [rowCopied, setRowCopied] = useState(null);
|
|
637
|
+
const show = enabled && typeof window !== "undefined" && isDevelopment(debug);
|
|
638
|
+
const authTone = toneForAuth(isReady, isSignedIn);
|
|
639
|
+
const dbTone = toneForDb(dbMode, dbStatus);
|
|
640
|
+
const schemaTone = toneForSchema(devInfo);
|
|
641
|
+
const syncTone = dbMode === "remote" ? "muted" : dbTone === "ok" || dbStatus === "SYNCING" /* SYNCING */ ? "ok" : dbTone === "warn" ? "warn" : dbTone === "bad" ? "bad" : "muted";
|
|
642
|
+
const handleRefreshSchema = useCallback(async () => {
|
|
643
|
+
setRefreshing(true);
|
|
644
|
+
try {
|
|
645
|
+
await refreshSchemaStatus();
|
|
646
|
+
} finally {
|
|
647
|
+
setRefreshing(false);
|
|
648
|
+
}
|
|
649
|
+
}, [refreshSchemaStatus]);
|
|
650
|
+
const missingList = missingScopes();
|
|
651
|
+
const debugPayload = useMemo(() => {
|
|
652
|
+
return {
|
|
653
|
+
sdkVersion: version,
|
|
654
|
+
isReady,
|
|
655
|
+
isSignedIn,
|
|
656
|
+
did: did ?? null,
|
|
657
|
+
user: user ? {
|
|
658
|
+
sub: user.sub,
|
|
659
|
+
email: user.email,
|
|
660
|
+
name: user.name,
|
|
661
|
+
picture: user.picture
|
|
662
|
+
} : null,
|
|
663
|
+
scope,
|
|
664
|
+
missingScopes: missingList,
|
|
665
|
+
dbMode,
|
|
666
|
+
dbStatus,
|
|
667
|
+
indexedDbName: dbMode === "sync" ? INDEXED_DB_NAME : null,
|
|
668
|
+
schema: devInfo
|
|
669
|
+
};
|
|
670
|
+
}, [isReady, isSignedIn, did, user, scope, dbMode, dbStatus, devInfo, missingList]);
|
|
671
|
+
const handleCopy = useCallback(async () => {
|
|
672
|
+
try {
|
|
673
|
+
await navigator.clipboard.writeText(JSON.stringify(debugPayload, null, 2));
|
|
674
|
+
setCopied(true);
|
|
675
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
676
|
+
} catch {
|
|
677
|
+
}
|
|
678
|
+
}, [debugPayload]);
|
|
679
|
+
const onRowCopied = useCallback((key) => {
|
|
680
|
+
setRowCopied(key);
|
|
681
|
+
setTimeout(() => setRowCopied((k) => k === key ? null : k), 1500);
|
|
682
|
+
}, []);
|
|
683
|
+
if (!show) return null;
|
|
684
|
+
const shell = {
|
|
685
|
+
position: "fixed",
|
|
686
|
+
bottom: 12,
|
|
687
|
+
left: "50%",
|
|
688
|
+
transform: "translateX(-50%)",
|
|
689
|
+
zIndex: 99999,
|
|
690
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
|
691
|
+
fontSize: 11,
|
|
692
|
+
color: "#e4e4e7",
|
|
693
|
+
pointerEvents: "auto"
|
|
694
|
+
};
|
|
695
|
+
const bar = {
|
|
696
|
+
display: "flex",
|
|
697
|
+
alignItems: "center",
|
|
698
|
+
gap: 8,
|
|
699
|
+
padding: "8px 12px",
|
|
700
|
+
borderRadius: 999,
|
|
701
|
+
background: "rgba(24, 24, 27, 0.92)",
|
|
702
|
+
border: "1px solid rgba(63, 63, 70, 0.9)",
|
|
703
|
+
boxShadow: "0 8px 32px rgba(0,0,0,0.35)",
|
|
704
|
+
cursor: "pointer",
|
|
705
|
+
userSelect: "none"
|
|
706
|
+
};
|
|
707
|
+
const dot = (tone) => /* @__PURE__ */ jsx(
|
|
708
|
+
"span",
|
|
709
|
+
{
|
|
710
|
+
style: {
|
|
711
|
+
display: "block",
|
|
712
|
+
boxSizing: "border-box",
|
|
713
|
+
width: 6,
|
|
714
|
+
height: 6,
|
|
715
|
+
minWidth: 6,
|
|
716
|
+
minHeight: 6,
|
|
717
|
+
maxWidth: 6,
|
|
718
|
+
maxHeight: 6,
|
|
719
|
+
borderRadius: "50%",
|
|
720
|
+
background: chipColor(tone),
|
|
721
|
+
flexShrink: 0
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
);
|
|
725
|
+
const dotSlot = (title, tone) => /* @__PURE__ */ jsx(
|
|
726
|
+
"span",
|
|
727
|
+
{
|
|
728
|
+
title,
|
|
729
|
+
style: {
|
|
730
|
+
display: "inline-flex",
|
|
731
|
+
alignItems: "center",
|
|
732
|
+
justifyContent: "center",
|
|
733
|
+
width: 6,
|
|
734
|
+
height: 6,
|
|
735
|
+
flexShrink: 0,
|
|
736
|
+
lineHeight: 0
|
|
737
|
+
},
|
|
738
|
+
children: dot(tone)
|
|
739
|
+
}
|
|
740
|
+
);
|
|
741
|
+
const panel = {
|
|
742
|
+
marginBottom: 8,
|
|
743
|
+
maxHeight: "50vh",
|
|
744
|
+
overflow: "auto",
|
|
745
|
+
padding: PANEL_PAD_X,
|
|
746
|
+
borderRadius: 10,
|
|
747
|
+
background: "rgba(24, 24, 27, 0.96)",
|
|
748
|
+
border: "1px solid rgba(63, 63, 70, 0.9)",
|
|
749
|
+
boxShadow: "0 8px 32px rgba(0,0,0,0.35)",
|
|
750
|
+
minWidth: 300,
|
|
751
|
+
maxWidth: "min(560px, calc(100vw - 24px))"
|
|
752
|
+
};
|
|
753
|
+
const syncStatusText = dbStatusLabel(dbStatus);
|
|
754
|
+
return /* @__PURE__ */ jsxs("div", { style: shell, children: [
|
|
755
|
+
open && /* @__PURE__ */ jsxs("div", { style: panel, children: [
|
|
756
|
+
/* @__PURE__ */ jsxs("div", { style: { marginBottom: 12 }, children: [
|
|
757
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 600, fontSize: 12 }, children: "Basic SDK" }),
|
|
758
|
+
/* @__PURE__ */ jsxs("div", { style: { color: "#71717a", fontSize: 10, marginTop: 2 }, children: [
|
|
759
|
+
"v",
|
|
760
|
+
version
|
|
761
|
+
] })
|
|
762
|
+
] }),
|
|
763
|
+
/* @__PURE__ */ jsx(SectionHeader, { children: "Auth" }),
|
|
764
|
+
/* @__PURE__ */ jsx(
|
|
765
|
+
CopyableRow,
|
|
766
|
+
{
|
|
767
|
+
rowKey: "ready",
|
|
768
|
+
label: "Ready",
|
|
769
|
+
copyText: String(isReady),
|
|
770
|
+
copiedKey: rowCopied,
|
|
771
|
+
onCopied: onRowCopied,
|
|
772
|
+
children: String(isReady)
|
|
773
|
+
}
|
|
774
|
+
),
|
|
775
|
+
/* @__PURE__ */ jsx(
|
|
776
|
+
CopyableRow,
|
|
777
|
+
{
|
|
778
|
+
rowKey: "signedIn",
|
|
779
|
+
label: "Signed in",
|
|
780
|
+
copyText: String(isSignedIn),
|
|
781
|
+
copiedKey: rowCopied,
|
|
782
|
+
onCopied: onRowCopied,
|
|
783
|
+
children: String(isSignedIn)
|
|
784
|
+
}
|
|
785
|
+
),
|
|
786
|
+
/* @__PURE__ */ jsx(
|
|
787
|
+
CopyableRow,
|
|
788
|
+
{
|
|
789
|
+
rowKey: "did",
|
|
790
|
+
label: "DID",
|
|
791
|
+
copyText: did || "",
|
|
792
|
+
copiedKey: rowCopied,
|
|
793
|
+
onCopied: onRowCopied,
|
|
794
|
+
children: displayDid(did)
|
|
795
|
+
}
|
|
796
|
+
),
|
|
797
|
+
/* @__PURE__ */ jsx(
|
|
798
|
+
CopyableRow,
|
|
799
|
+
{
|
|
800
|
+
rowKey: "user",
|
|
801
|
+
label: "User",
|
|
802
|
+
copyText: user ? displayUserLine(user) : "",
|
|
803
|
+
copiedKey: rowCopied,
|
|
804
|
+
onCopied: onRowCopied,
|
|
805
|
+
children: user ? displayUserLine(user) : "\u2014"
|
|
806
|
+
}
|
|
807
|
+
),
|
|
808
|
+
/* @__PURE__ */ jsx(
|
|
809
|
+
CopyableRow,
|
|
810
|
+
{
|
|
811
|
+
rowKey: "scopes",
|
|
812
|
+
label: "Scopes",
|
|
813
|
+
copyText: scope || "",
|
|
814
|
+
copiedKey: rowCopied,
|
|
815
|
+
onCopied: onRowCopied,
|
|
816
|
+
children: scope || "\u2014"
|
|
817
|
+
}
|
|
818
|
+
),
|
|
819
|
+
/* @__PURE__ */ jsx(
|
|
820
|
+
CopyableRow,
|
|
821
|
+
{
|
|
822
|
+
rowKey: "missingScopes",
|
|
823
|
+
label: "Missing scopes",
|
|
824
|
+
copyText: missingList.length ? missingList.join(", ") : "",
|
|
825
|
+
copiedKey: rowCopied,
|
|
826
|
+
onCopied: onRowCopied,
|
|
827
|
+
children: missingList.length ? missingList.join(", ") : "\u2014"
|
|
828
|
+
}
|
|
829
|
+
),
|
|
830
|
+
/* @__PURE__ */ jsx(SectionRule, {}),
|
|
831
|
+
/* @__PURE__ */ jsx(SectionHeader, { children: "Database" }),
|
|
832
|
+
/* @__PURE__ */ jsx(
|
|
833
|
+
CopyableRow,
|
|
834
|
+
{
|
|
835
|
+
rowKey: "dbMode",
|
|
836
|
+
label: "Mode",
|
|
837
|
+
copyText: dbMode,
|
|
838
|
+
copiedKey: rowCopied,
|
|
839
|
+
onCopied: onRowCopied,
|
|
840
|
+
children: dbMode
|
|
841
|
+
}
|
|
842
|
+
),
|
|
843
|
+
/* @__PURE__ */ jsx(
|
|
844
|
+
CopyableRow,
|
|
845
|
+
{
|
|
846
|
+
rowKey: "indexedDb",
|
|
847
|
+
label: "IndexedDB",
|
|
848
|
+
copyText: dbMode === "sync" ? INDEXED_DB_NAME : "",
|
|
849
|
+
copiedKey: rowCopied,
|
|
850
|
+
onCopied: onRowCopied,
|
|
851
|
+
children: dbMode === "sync" ? INDEXED_DB_NAME : "\u2014"
|
|
852
|
+
}
|
|
853
|
+
),
|
|
854
|
+
/* @__PURE__ */ jsx(
|
|
855
|
+
CopyableRow,
|
|
856
|
+
{
|
|
857
|
+
rowKey: "syncStatus",
|
|
858
|
+
label: "Sync / status",
|
|
859
|
+
copyText: syncStatusText,
|
|
860
|
+
copiedKey: rowCopied,
|
|
861
|
+
onCopied: onRowCopied,
|
|
862
|
+
children: syncStatusText
|
|
863
|
+
}
|
|
864
|
+
),
|
|
865
|
+
/* @__PURE__ */ jsx(SectionRule, {}),
|
|
866
|
+
/* @__PURE__ */ jsx(SectionHeader, { children: "Schema" }),
|
|
867
|
+
devInfo ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
868
|
+
/* @__PURE__ */ jsx(
|
|
869
|
+
CopyableRow,
|
|
870
|
+
{
|
|
871
|
+
rowKey: "schemaProject",
|
|
872
|
+
label: "Project",
|
|
873
|
+
copyText: devInfo.projectId ?? "",
|
|
874
|
+
copiedKey: rowCopied,
|
|
875
|
+
onCopied: onRowCopied,
|
|
876
|
+
children: devInfo.projectId ?? "\u2014"
|
|
877
|
+
}
|
|
878
|
+
),
|
|
879
|
+
/* @__PURE__ */ jsx(
|
|
880
|
+
CopyableRow,
|
|
881
|
+
{
|
|
882
|
+
rowKey: "schemaLocalVer",
|
|
883
|
+
label: "Local version",
|
|
884
|
+
copyText: devInfo.localVersion !== void 0 && devInfo.localVersion !== null ? String(devInfo.localVersion) : "",
|
|
885
|
+
copiedKey: rowCopied,
|
|
886
|
+
onCopied: onRowCopied,
|
|
887
|
+
children: devInfo.localVersion ?? "\u2014"
|
|
888
|
+
}
|
|
889
|
+
),
|
|
890
|
+
/* @__PURE__ */ jsx(
|
|
891
|
+
CopyableRow,
|
|
892
|
+
{
|
|
893
|
+
rowKey: "schemaRemote",
|
|
894
|
+
label: "Remote check",
|
|
895
|
+
copyText: devInfo.status,
|
|
896
|
+
copiedKey: rowCopied,
|
|
897
|
+
onCopied: onRowCopied,
|
|
898
|
+
children: devInfo.status
|
|
899
|
+
}
|
|
900
|
+
),
|
|
901
|
+
/* @__PURE__ */ jsx(
|
|
902
|
+
CopyableRow,
|
|
903
|
+
{
|
|
904
|
+
rowKey: "schemaValid",
|
|
905
|
+
label: "Valid",
|
|
906
|
+
copyText: String(devInfo.valid),
|
|
907
|
+
copiedKey: rowCopied,
|
|
908
|
+
onCopied: onRowCopied,
|
|
909
|
+
children: String(devInfo.valid)
|
|
910
|
+
}
|
|
911
|
+
),
|
|
912
|
+
/* @__PURE__ */ jsx(
|
|
913
|
+
CopyableRow,
|
|
914
|
+
{
|
|
915
|
+
rowKey: "schemaChecked",
|
|
916
|
+
label: "Checked",
|
|
917
|
+
copyText: devInfo.lastCheckedAt ? new Date(devInfo.lastCheckedAt).toISOString() : "",
|
|
918
|
+
copiedKey: rowCopied,
|
|
919
|
+
onCopied: onRowCopied,
|
|
920
|
+
children: devInfo.lastCheckedAt ? new Date(devInfo.lastCheckedAt).toLocaleString() : "\u2014"
|
|
921
|
+
}
|
|
922
|
+
),
|
|
923
|
+
devInfo.error ? /* @__PURE__ */ jsx(
|
|
924
|
+
CopyableRow,
|
|
925
|
+
{
|
|
926
|
+
rowKey: "schemaError",
|
|
927
|
+
label: "Error",
|
|
928
|
+
copyText: devInfo.error,
|
|
929
|
+
copiedKey: rowCopied,
|
|
930
|
+
onCopied: onRowCopied,
|
|
931
|
+
children: devInfo.error
|
|
932
|
+
}
|
|
933
|
+
) : null
|
|
934
|
+
] }) : /* @__PURE__ */ jsx(
|
|
935
|
+
CopyableRow,
|
|
936
|
+
{
|
|
937
|
+
rowKey: "schemaStatus",
|
|
938
|
+
label: "Status",
|
|
939
|
+
copyText: "No schema on provider",
|
|
940
|
+
copiedKey: rowCopied,
|
|
941
|
+
onCopied: onRowCopied,
|
|
942
|
+
children: "No schema on provider"
|
|
943
|
+
}
|
|
944
|
+
),
|
|
945
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, marginTop: 12, flexWrap: "wrap" }, children: [
|
|
946
|
+
/* @__PURE__ */ jsx(
|
|
947
|
+
"button",
|
|
948
|
+
{
|
|
949
|
+
type: "button",
|
|
950
|
+
onClick: (e) => {
|
|
951
|
+
e.stopPropagation();
|
|
952
|
+
void handleRefreshSchema();
|
|
953
|
+
},
|
|
954
|
+
disabled: refreshing,
|
|
955
|
+
style: {
|
|
956
|
+
padding: "6px 10px",
|
|
957
|
+
borderRadius: 6,
|
|
958
|
+
border: "1px solid #3f3f46",
|
|
959
|
+
background: "#27272a",
|
|
960
|
+
color: "#e4e4e7",
|
|
961
|
+
cursor: refreshing ? "wait" : "pointer",
|
|
962
|
+
fontSize: 11,
|
|
963
|
+
fontFamily: "inherit"
|
|
964
|
+
},
|
|
965
|
+
children: refreshing ? "Refreshing\u2026" : "Refresh schema"
|
|
966
|
+
}
|
|
967
|
+
),
|
|
968
|
+
/* @__PURE__ */ jsx(
|
|
969
|
+
"button",
|
|
970
|
+
{
|
|
971
|
+
type: "button",
|
|
972
|
+
onClick: (e) => {
|
|
973
|
+
e.stopPropagation();
|
|
974
|
+
void handleCopy();
|
|
975
|
+
},
|
|
976
|
+
style: {
|
|
977
|
+
padding: "6px 10px",
|
|
978
|
+
borderRadius: 6,
|
|
979
|
+
border: "1px solid #3f3f46",
|
|
980
|
+
background: "#27272a",
|
|
981
|
+
color: "#e4e4e7",
|
|
982
|
+
cursor: "pointer",
|
|
983
|
+
fontSize: 11,
|
|
984
|
+
fontFamily: "inherit"
|
|
985
|
+
},
|
|
986
|
+
children: copied ? "Copied" : "Copy debug info"
|
|
987
|
+
}
|
|
988
|
+
)
|
|
989
|
+
] })
|
|
990
|
+
] }),
|
|
991
|
+
/* @__PURE__ */ jsxs(
|
|
992
|
+
"button",
|
|
993
|
+
{
|
|
994
|
+
type: "button",
|
|
995
|
+
"aria-expanded": open,
|
|
996
|
+
onClick: () => setOpen((o) => !o),
|
|
997
|
+
style: {
|
|
998
|
+
...bar,
|
|
999
|
+
border: "none",
|
|
1000
|
+
width: "100%",
|
|
1001
|
+
cursor: "pointer"
|
|
1002
|
+
},
|
|
1003
|
+
children: [
|
|
1004
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600, letterSpacing: 0.02 }, children: "Basic" }),
|
|
1005
|
+
/* @__PURE__ */ jsxs(
|
|
1006
|
+
"span",
|
|
1007
|
+
{
|
|
1008
|
+
style: {
|
|
1009
|
+
display: "inline-flex",
|
|
1010
|
+
alignItems: "center",
|
|
1011
|
+
gap: 6,
|
|
1012
|
+
marginLeft: 8,
|
|
1013
|
+
height: 6,
|
|
1014
|
+
flexShrink: 0,
|
|
1015
|
+
lineHeight: 0
|
|
1016
|
+
},
|
|
1017
|
+
children: [
|
|
1018
|
+
dotSlot("Auth", authTone),
|
|
1019
|
+
dotSlot("DB", dbTone),
|
|
1020
|
+
dotSlot("Sync", syncTone),
|
|
1021
|
+
dotSlot("Schema", schemaTone)
|
|
1022
|
+
]
|
|
1023
|
+
}
|
|
1024
|
+
),
|
|
1025
|
+
/* @__PURE__ */ jsx("span", { style: { color: "#71717a", marginLeft: 4 }, children: open ? "\u25BE" : "\u25B4" })
|
|
1026
|
+
]
|
|
1027
|
+
}
|
|
1028
|
+
)
|
|
1029
|
+
] });
|
|
1030
|
+
}
|
|
1031
|
+
var INDEXED_DB_NAME, PANEL_PAD_X;
|
|
1032
|
+
var init_BasicDevToolbar = __esm({
|
|
1033
|
+
"src/dev/BasicDevToolbar.tsx"() {
|
|
1034
|
+
"use strict";
|
|
1035
|
+
"use client";
|
|
1036
|
+
init_context();
|
|
1037
|
+
init_package();
|
|
1038
|
+
init_network();
|
|
1039
|
+
INDEXED_DB_NAME = "basicdb";
|
|
1040
|
+
PANEL_PAD_X = 12;
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
1043
|
+
|
|
219
1044
|
// src/AuthContext.tsx
|
|
220
|
-
import {
|
|
1045
|
+
import { useCallback as useCallback2, useEffect, useRef, useState as useState2, Suspense, lazy } from "react";
|
|
221
1046
|
|
|
222
1047
|
// src/sync/index.ts
|
|
223
1048
|
init_config();
|
|
@@ -808,75 +1633,8 @@ async function resolveHandle(handle) {
|
|
|
808
1633
|
return resolved;
|
|
809
1634
|
}
|
|
810
1635
|
|
|
811
|
-
// src/utils/network.ts
|
|
812
|
-
init_config();
|
|
813
|
-
|
|
814
|
-
// package.json
|
|
815
|
-
var version = "0.8.0-beta.1";
|
|
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
1636
|
// src/core/auth/AuthManager.ts
|
|
1637
|
+
init_network();
|
|
880
1638
|
init_config();
|
|
881
1639
|
function generateCodeVerifier() {
|
|
882
1640
|
const array = new Uint8Array(32);
|
|
@@ -1024,8 +1782,11 @@ var AuthManager = class {
|
|
|
1024
1782
|
const refreshToken = await this.storage.get(STORAGE_KEYS.REFRESH_TOKEN);
|
|
1025
1783
|
if (refreshToken) {
|
|
1026
1784
|
log("Found refresh token in storage, attempting to refresh access token");
|
|
1027
|
-
this.exchangeToken(refreshToken, true).catch((error) => {
|
|
1785
|
+
this.exchangeToken(refreshToken, true).catch(async (error) => {
|
|
1028
1786
|
log("Error fetching refresh token:", error);
|
|
1787
|
+
if (this.isNetworkError(error)) {
|
|
1788
|
+
await this.restoreCachedUser();
|
|
1789
|
+
}
|
|
1029
1790
|
});
|
|
1030
1791
|
} else {
|
|
1031
1792
|
const cachedUserInfo = await this.storage.get(STORAGE_KEYS.USER_INFO);
|
|
@@ -1094,7 +1855,8 @@ var AuthManager = class {
|
|
|
1094
1855
|
log("Token refresh already in progress, waiting...");
|
|
1095
1856
|
try {
|
|
1096
1857
|
const newToken = await this.refreshPromise;
|
|
1097
|
-
|
|
1858
|
+
if (!newToken?.access_token) throw new Error("Token refresh returned empty access token");
|
|
1859
|
+
return newToken.access_token;
|
|
1098
1860
|
} catch (error) {
|
|
1099
1861
|
log("In-flight refresh failed:", error);
|
|
1100
1862
|
if (this.isNetworkError(error)) {
|
|
@@ -1108,7 +1870,8 @@ var AuthManager = class {
|
|
|
1108
1870
|
if (refreshToken) {
|
|
1109
1871
|
try {
|
|
1110
1872
|
const newToken = await this.exchangeToken(refreshToken, true);
|
|
1111
|
-
|
|
1873
|
+
if (!newToken?.access_token) throw new Error("Token refresh returned empty access token");
|
|
1874
|
+
return newToken.access_token;
|
|
1112
1875
|
} catch (error) {
|
|
1113
1876
|
log("Failed to refresh expired token:", error);
|
|
1114
1877
|
if (this.isNetworkError(error)) {
|
|
@@ -1121,7 +1884,8 @@ var AuthManager = class {
|
|
|
1121
1884
|
throw new Error("no refresh token available");
|
|
1122
1885
|
}
|
|
1123
1886
|
}
|
|
1124
|
-
|
|
1887
|
+
if (!this.token.access_token) throw new Error("Token exists but access_token is empty");
|
|
1888
|
+
return this.token.access_token;
|
|
1125
1889
|
}
|
|
1126
1890
|
async getSignInUrl(redirectUri, endpoints) {
|
|
1127
1891
|
log("getting sign in link...");
|
|
@@ -1130,7 +1894,7 @@ var AuthManager = class {
|
|
|
1130
1894
|
}
|
|
1131
1895
|
const pdsEndpoints = endpoints || this.defaultPdsEndpoints();
|
|
1132
1896
|
await this.storage.set(STORAGE_KEYS.PDS_ENDPOINTS, JSON.stringify(pdsEndpoints));
|
|
1133
|
-
const randomState =
|
|
1897
|
+
const randomState = base64UrlEncode(crypto.getRandomValues(new Uint8Array(16)));
|
|
1134
1898
|
await this.storage.set(STORAGE_KEYS.AUTH_STATE, randomState);
|
|
1135
1899
|
const redirectUrl = redirectUri || window.location.href;
|
|
1136
1900
|
if (!redirectUrl || !redirectUrl.startsWith("http://") && !redirectUrl.startsWith("https://")) {
|
|
@@ -1249,7 +2013,10 @@ var AuthManager = class {
|
|
|
1249
2013
|
return requested.filter((s) => !granted.has(s));
|
|
1250
2014
|
}
|
|
1251
2015
|
/**
|
|
1252
|
-
* Register online/offline handlers that retry pending
|
|
2016
|
+
* Register online/offline and visibility handlers that retry pending
|
|
2017
|
+
* refreshes and proactively refresh tokens when the app resumes from
|
|
2018
|
+
* background (critical for PWAs and mobile browsers where timers are
|
|
2019
|
+
* frozen while backgrounded).
|
|
1253
2020
|
* Returns a cleanup function for useEffect teardown.
|
|
1254
2021
|
*/
|
|
1255
2022
|
setupNetworkListeners() {
|
|
@@ -1271,11 +2038,25 @@ var AuthManager = class {
|
|
|
1271
2038
|
log("Network went offline");
|
|
1272
2039
|
this.isOnline = false;
|
|
1273
2040
|
};
|
|
2041
|
+
const handleVisibilityChange = () => {
|
|
2042
|
+
if (document.visibilityState === "visible" && this.isSignedIn) {
|
|
2043
|
+
log("App became visible - checking token freshness");
|
|
2044
|
+
this.getToken().catch((err) => {
|
|
2045
|
+
log("Token refresh on visibility resume failed:", err);
|
|
2046
|
+
});
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
1274
2049
|
window.addEventListener("online", handleOnline);
|
|
1275
2050
|
window.addEventListener("offline", handleOffline);
|
|
2051
|
+
if (typeof document !== "undefined") {
|
|
2052
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
2053
|
+
}
|
|
1276
2054
|
return () => {
|
|
1277
2055
|
window.removeEventListener("online", handleOnline);
|
|
1278
2056
|
window.removeEventListener("offline", handleOffline);
|
|
2057
|
+
if (typeof document !== "undefined") {
|
|
2058
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
2059
|
+
}
|
|
1279
2060
|
};
|
|
1280
2061
|
}
|
|
1281
2062
|
// ------------------------------------------------------------------
|
|
@@ -1338,39 +2119,26 @@ var AuthManager = class {
|
|
|
1338
2119
|
const decoded = jwtDecode(this.token.access_token);
|
|
1339
2120
|
if (decoded.sub) this.did = decoded.sub;
|
|
1340
2121
|
if (decoded.scope) this.tokenScope = decoded.scope;
|
|
1341
|
-
|
|
1342
|
-
const isExpired = decoded.exp && decoded.exp < Date.now() / 1e3 + expirationBuffer;
|
|
1343
|
-
if (isExpired) {
|
|
1344
|
-
log("token is expired - refreshing ...");
|
|
1345
|
-
const refreshToken = this.token.refresh_token;
|
|
1346
|
-
if (!refreshToken) {
|
|
1347
|
-
log("Error: No refresh token available for expired token");
|
|
1348
|
-
this.isAuthReady = true;
|
|
1349
|
-
this.notify();
|
|
1350
|
-
return;
|
|
1351
|
-
}
|
|
1352
|
-
try {
|
|
1353
|
-
const newToken = await this.exchangeToken(refreshToken, true);
|
|
1354
|
-
await this.fetchUser(newToken?.access_token || "");
|
|
1355
|
-
} catch (error) {
|
|
1356
|
-
log("Failed to refresh token in processNewToken:", error);
|
|
1357
|
-
if (this.isNetworkError(error)) {
|
|
1358
|
-
log("Network issue - continuing with expired token until online");
|
|
1359
|
-
await this.fetchUser(this.token.access_token);
|
|
1360
|
-
} else {
|
|
1361
|
-
this.isAuthReady = true;
|
|
1362
|
-
this.notify();
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
} else {
|
|
1366
|
-
await this.fetchUser(this.token.access_token);
|
|
1367
|
-
}
|
|
2122
|
+
await this.fetchUser(this.token.access_token);
|
|
1368
2123
|
} catch (error) {
|
|
1369
2124
|
log("Error processing token:", error);
|
|
1370
2125
|
this.isAuthReady = true;
|
|
1371
2126
|
this.notify();
|
|
1372
2127
|
}
|
|
1373
2128
|
}
|
|
2129
|
+
async restoreCachedUser() {
|
|
2130
|
+
const cached = await this.storage.get(STORAGE_KEYS.USER_INFO);
|
|
2131
|
+
if (cached) {
|
|
2132
|
+
try {
|
|
2133
|
+
this.user = JSON.parse(cached);
|
|
2134
|
+
this.isSignedIn = true;
|
|
2135
|
+
log("Restored cached user info for offline mode");
|
|
2136
|
+
} catch {
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
this.isAuthReady = true;
|
|
2140
|
+
this.notify();
|
|
2141
|
+
}
|
|
1374
2142
|
async fetchUser(accessToken) {
|
|
1375
2143
|
log("fetching user");
|
|
1376
2144
|
try {
|
|
@@ -1404,8 +2172,12 @@ var AuthManager = class {
|
|
|
1404
2172
|
this.notify();
|
|
1405
2173
|
} catch (error) {
|
|
1406
2174
|
log("Failed to fetch user info:", error);
|
|
1407
|
-
this.
|
|
1408
|
-
|
|
2175
|
+
if (this.isNetworkError(error)) {
|
|
2176
|
+
await this.restoreCachedUser();
|
|
2177
|
+
} else {
|
|
2178
|
+
this.isAuthReady = true;
|
|
2179
|
+
this.notify();
|
|
2180
|
+
}
|
|
1409
2181
|
}
|
|
1410
2182
|
}
|
|
1411
2183
|
/**
|
|
@@ -1501,9 +2273,12 @@ var AuthManager = class {
|
|
|
1501
2273
|
this.pendingRefresh = true;
|
|
1502
2274
|
throw new Error("Network issue - refresh will be retried when online");
|
|
1503
2275
|
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
2276
|
+
const definitiveErrors = ["invalid_grant", "invalid_client", "unauthorized_client"];
|
|
2277
|
+
if (typeof token.error === "string" && definitiveErrors.includes(token.error)) {
|
|
2278
|
+
await this.clearStoredAuth();
|
|
2279
|
+
this.resetAuthState();
|
|
2280
|
+
this.notify();
|
|
2281
|
+
}
|
|
1507
2282
|
throw new Error(`Token refresh failed: ${token.error}`);
|
|
1508
2283
|
} else {
|
|
1509
2284
|
this.token = token;
|
|
@@ -1524,7 +2299,9 @@ var AuthManager = class {
|
|
|
1524
2299
|
return token;
|
|
1525
2300
|
} catch (error) {
|
|
1526
2301
|
log("Token refresh error:", error);
|
|
1527
|
-
|
|
2302
|
+
const msg = error instanceof Error ? error.message : "";
|
|
2303
|
+
const alreadyHandled = msg.startsWith("Token refresh failed:");
|
|
2304
|
+
if (!alreadyHandled && !this.isNetworkError(error)) {
|
|
1528
2305
|
await this.clearStoredAuth();
|
|
1529
2306
|
this.resetAuthState();
|
|
1530
2307
|
this.notify();
|
|
@@ -1568,6 +2345,7 @@ var AuthManager = class {
|
|
|
1568
2345
|
await this.storage.remove(STORAGE_KEYS.PDS_ENDPOINTS);
|
|
1569
2346
|
}
|
|
1570
2347
|
isNetworkError(error) {
|
|
2348
|
+
if (error instanceof TypeError) return true;
|
|
1571
2349
|
if (error instanceof Error) {
|
|
1572
2350
|
return error.message.includes("offline") || error.message.includes("Network");
|
|
1573
2351
|
}
|
|
@@ -1577,6 +2355,7 @@ var AuthManager = class {
|
|
|
1577
2355
|
|
|
1578
2356
|
// src/AuthContext.tsx
|
|
1579
2357
|
init_config();
|
|
2358
|
+
init_package();
|
|
1580
2359
|
|
|
1581
2360
|
// src/updater/versionUpdater.ts
|
|
1582
2361
|
init_config();
|
|
@@ -1701,6 +2480,9 @@ function getMigrations() {
|
|
|
1701
2480
|
];
|
|
1702
2481
|
}
|
|
1703
2482
|
|
|
2483
|
+
// src/AuthContext.tsx
|
|
2484
|
+
init_network();
|
|
2485
|
+
|
|
1704
2486
|
// src/utils/schema.ts
|
|
1705
2487
|
init_config();
|
|
1706
2488
|
import { validateSchema, compareSchemas } from "@basictech/schema";
|
|
@@ -1800,57 +2582,18 @@ async function validateAndCheckSchema(schema) {
|
|
|
1800
2582
|
}
|
|
1801
2583
|
|
|
1802
2584
|
// src/AuthContext.tsx
|
|
1803
|
-
|
|
2585
|
+
init_context();
|
|
2586
|
+
init_context();
|
|
2587
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2588
|
+
var BasicDevToolbar2 = lazy(
|
|
2589
|
+
() => Promise.resolve().then(() => (init_BasicDevToolbar(), BasicDevToolbar_exports)).then((m) => ({ default: m.BasicDevToolbar }))
|
|
2590
|
+
);
|
|
1804
2591
|
var DEFAULT_AUTH_CONFIG = {
|
|
1805
2592
|
scopes: "profile,email,app:admin",
|
|
1806
2593
|
pds_url: "https://pds.basic.id",
|
|
1807
2594
|
admin_url: "https://api.basic.tech",
|
|
1808
2595
|
ws_url: "wss://pds.basic.id/ws"
|
|
1809
2596
|
};
|
|
1810
|
-
var DBStatus = /* @__PURE__ */ ((DBStatus2) => {
|
|
1811
|
-
DBStatus2["LOADING"] = "LOADING";
|
|
1812
|
-
DBStatus2["OFFLINE"] = "OFFLINE";
|
|
1813
|
-
DBStatus2["CONNECTING"] = "CONNECTING";
|
|
1814
|
-
DBStatus2["ONLINE"] = "ONLINE";
|
|
1815
|
-
DBStatus2["SYNCING"] = "SYNCING";
|
|
1816
|
-
DBStatus2["ERROR"] = "ERROR";
|
|
1817
|
-
DBStatus2["ERROR_WILL_RETRY"] = "ERROR_WILL_RETRY";
|
|
1818
|
-
DBStatus2["ERROR_TOKEN_EXPIRED"] = "ERROR_TOKEN_EXPIRED";
|
|
1819
|
-
return DBStatus2;
|
|
1820
|
-
})(DBStatus || {});
|
|
1821
|
-
var noDb = {
|
|
1822
|
-
collection: () => {
|
|
1823
|
-
throw new Error("no basicdb found - initialization failed. double check your schema.");
|
|
1824
|
-
}
|
|
1825
|
-
};
|
|
1826
|
-
var BasicContext = createContext({
|
|
1827
|
-
// Auth state
|
|
1828
|
-
isReady: false,
|
|
1829
|
-
isSignedIn: false,
|
|
1830
|
-
user: null,
|
|
1831
|
-
did: null,
|
|
1832
|
-
scope: null,
|
|
1833
|
-
hasScope: () => false,
|
|
1834
|
-
missingScopes: () => [],
|
|
1835
|
-
// Auth actions
|
|
1836
|
-
signIn: () => Promise.resolve(),
|
|
1837
|
-
signInWithHandle: () => Promise.resolve(),
|
|
1838
|
-
signOut: () => Promise.resolve(),
|
|
1839
|
-
signInWithCode: () => Promise.resolve({ success: false }),
|
|
1840
|
-
// Token management
|
|
1841
|
-
getToken: (_options) => Promise.reject(new Error("no token")),
|
|
1842
|
-
getSignInUrl: () => Promise.resolve(""),
|
|
1843
|
-
// DB access
|
|
1844
|
-
db: noDb,
|
|
1845
|
-
dbStatus: "LOADING" /* LOADING */,
|
|
1846
|
-
dbMode: "sync",
|
|
1847
|
-
// Legacy aliases
|
|
1848
|
-
isAuthReady: false,
|
|
1849
|
-
signin: () => Promise.resolve(),
|
|
1850
|
-
signout: () => Promise.resolve(),
|
|
1851
|
-
signinWithCode: () => Promise.resolve({ success: false }),
|
|
1852
|
-
getSignInLink: () => Promise.resolve("")
|
|
1853
|
-
});
|
|
1854
2597
|
function snapshotAuth(mgr) {
|
|
1855
2598
|
return {
|
|
1856
2599
|
isSignedIn: mgr.isSignedIn,
|
|
@@ -1868,7 +2611,8 @@ function BasicProvider({
|
|
|
1868
2611
|
debug = false,
|
|
1869
2612
|
storage,
|
|
1870
2613
|
auth,
|
|
1871
|
-
dbMode = "sync"
|
|
2614
|
+
dbMode = "sync",
|
|
2615
|
+
devToolbar = false
|
|
1872
2616
|
}) {
|
|
1873
2617
|
const project_id = schema?.project_id || project_id_prop;
|
|
1874
2618
|
if (auth?.server_url && !auth?.pds_url) {
|
|
@@ -1883,7 +2627,9 @@ function BasicProvider({
|
|
|
1883
2627
|
const scopesString = Array.isArray(authConfig.scopes) ? authConfig.scopes.join(" ") : authConfig.scopes;
|
|
1884
2628
|
const storageRef = useRef(storage || new LocalStorageAdapter());
|
|
1885
2629
|
const storageAdapter = storageRef.current;
|
|
1886
|
-
const
|
|
2630
|
+
const schemaRef = useRef(schema);
|
|
2631
|
+
schemaRef.current = schema;
|
|
2632
|
+
const [authState, setAuthState] = useState2({
|
|
1887
2633
|
isSignedIn: false,
|
|
1888
2634
|
hasToken: false,
|
|
1889
2635
|
isAuthReady: false,
|
|
@@ -1907,11 +2653,47 @@ function BasicProvider({
|
|
|
1907
2653
|
}
|
|
1908
2654
|
const syncRef = useRef(null);
|
|
1909
2655
|
const remoteDbRef = useRef(null);
|
|
1910
|
-
const [shouldConnect, setShouldConnect] =
|
|
1911
|
-
const [dbStatus, setDbStatus] =
|
|
1912
|
-
const [isReady, setIsReady] =
|
|
1913
|
-
const [error, setError] =
|
|
2656
|
+
const [shouldConnect, setShouldConnect] = useState2(false);
|
|
2657
|
+
const [dbStatus, setDbStatus] = useState2("OFFLINE" /* OFFLINE */);
|
|
2658
|
+
const [isReady, setIsReady] = useState2(false);
|
|
2659
|
+
const [error, setError] = useState2(null);
|
|
2660
|
+
const [schemaDevInfo, setSchemaDevInfo] = useState2(null);
|
|
1914
2661
|
const isDevMode = () => isDevelopment(debug);
|
|
2662
|
+
const refreshSchemaStatus = useCallback2(async () => {
|
|
2663
|
+
const s = schemaRef.current;
|
|
2664
|
+
if (!s) {
|
|
2665
|
+
setSchemaDevInfo(
|
|
2666
|
+
project_id ? {
|
|
2667
|
+
projectId: project_id,
|
|
2668
|
+
localVersion: void 0,
|
|
2669
|
+
status: "no_schema",
|
|
2670
|
+
valid: false,
|
|
2671
|
+
lastCheckedAt: Date.now()
|
|
2672
|
+
} : null
|
|
2673
|
+
);
|
|
2674
|
+
return;
|
|
2675
|
+
}
|
|
2676
|
+
const result = await validateAndCheckSchema(s);
|
|
2677
|
+
if (!result.isValid) {
|
|
2678
|
+
const errText = result.errors?.map((e) => e.message || "").join("; ") || "invalid";
|
|
2679
|
+
setSchemaDevInfo({
|
|
2680
|
+
projectId: s.project_id ?? null,
|
|
2681
|
+
localVersion: s.version,
|
|
2682
|
+
status: "invalid",
|
|
2683
|
+
valid: false,
|
|
2684
|
+
lastCheckedAt: Date.now(),
|
|
2685
|
+
error: errText
|
|
2686
|
+
});
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
setSchemaDevInfo({
|
|
2690
|
+
projectId: s.project_id ?? null,
|
|
2691
|
+
localVersion: s.version,
|
|
2692
|
+
status: result.schemaStatus.status ?? "unknown",
|
|
2693
|
+
valid: result.schemaStatus.valid,
|
|
2694
|
+
lastCheckedAt: Date.now()
|
|
2695
|
+
});
|
|
2696
|
+
}, [project_id]);
|
|
1915
2697
|
useEffect(() => {
|
|
1916
2698
|
const runVersionUpdater = async () => {
|
|
1917
2699
|
try {
|
|
@@ -1973,6 +2755,10 @@ function BasicProvider({
|
|
|
1973
2755
|
debug,
|
|
1974
2756
|
onAuthError: (error2) => {
|
|
1975
2757
|
log("RemoteDB auth error:", error2);
|
|
2758
|
+
if (error2.errorType === "forbidden") {
|
|
2759
|
+
log("403 Forbidden - user lacks required scope, not signing out");
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
1976
2762
|
handleSignOut();
|
|
1977
2763
|
}
|
|
1978
2764
|
});
|
|
@@ -1985,11 +2771,19 @@ function BasicProvider({
|
|
|
1985
2771
|
if (!result.isValid) {
|
|
1986
2772
|
let errorMessage = "";
|
|
1987
2773
|
if (result.errors) {
|
|
1988
|
-
result.errors.forEach((
|
|
1989
|
-
errorMessage += `${index + 1}: ${
|
|
2774
|
+
result.errors.forEach((err, index) => {
|
|
2775
|
+
errorMessage += `${index + 1}: ${err.message} - at ${err.instancePath}
|
|
1990
2776
|
`;
|
|
1991
2777
|
});
|
|
1992
2778
|
}
|
|
2779
|
+
setSchemaDevInfo({
|
|
2780
|
+
projectId: schema?.project_id ?? null,
|
|
2781
|
+
localVersion: schema?.version,
|
|
2782
|
+
status: "invalid",
|
|
2783
|
+
valid: false,
|
|
2784
|
+
lastCheckedAt: Date.now(),
|
|
2785
|
+
error: errorMessage.trim() || void 0
|
|
2786
|
+
});
|
|
1993
2787
|
setError({
|
|
1994
2788
|
code: "schema_invalid",
|
|
1995
2789
|
title: "Basic Schema is invalid!",
|
|
@@ -1998,6 +2792,13 @@ function BasicProvider({
|
|
|
1998
2792
|
setIsReady(true);
|
|
1999
2793
|
return null;
|
|
2000
2794
|
}
|
|
2795
|
+
setSchemaDevInfo({
|
|
2796
|
+
projectId: schema?.project_id ?? null,
|
|
2797
|
+
localVersion: schema?.version,
|
|
2798
|
+
status: result.schemaStatus.status ?? "unknown",
|
|
2799
|
+
valid: result.schemaStatus.valid,
|
|
2800
|
+
lastCheckedAt: Date.now()
|
|
2801
|
+
});
|
|
2001
2802
|
if (dbMode === "remote") {
|
|
2002
2803
|
initRemoteDb();
|
|
2003
2804
|
} else {
|
|
@@ -2017,6 +2818,15 @@ function BasicProvider({
|
|
|
2017
2818
|
if (schema) {
|
|
2018
2819
|
checkSchema();
|
|
2019
2820
|
} else {
|
|
2821
|
+
setSchemaDevInfo(
|
|
2822
|
+
project_id ? {
|
|
2823
|
+
projectId: project_id,
|
|
2824
|
+
localVersion: void 0,
|
|
2825
|
+
status: "no_schema",
|
|
2826
|
+
valid: false,
|
|
2827
|
+
lastCheckedAt: Date.now()
|
|
2828
|
+
} : null
|
|
2829
|
+
);
|
|
2020
2830
|
if (dbMode === "remote" && project_id) {
|
|
2021
2831
|
initRemoteDb();
|
|
2022
2832
|
} else {
|
|
@@ -2083,68 +2893,71 @@ function BasicProvider({
|
|
|
2083
2893
|
return syncRef.current || noDb;
|
|
2084
2894
|
};
|
|
2085
2895
|
const contextValue = {
|
|
2086
|
-
// Auth state
|
|
2087
2896
|
isReady: authState.isAuthReady,
|
|
2088
2897
|
isSignedIn: authState.isSignedIn,
|
|
2089
2898
|
user: authState.user,
|
|
2090
2899
|
did: authState.did,
|
|
2091
2900
|
scope: authState.tokenScope,
|
|
2092
|
-
hasScope: (
|
|
2901
|
+
hasScope: (s) => authRef.current.hasScope(s),
|
|
2093
2902
|
missingScopes: () => authRef.current.missingScopes(),
|
|
2094
|
-
// Auth actions
|
|
2095
2903
|
signIn: handleSignIn,
|
|
2096
2904
|
signInWithHandle: handleSignInWithHandle,
|
|
2097
2905
|
signOut: handleSignOut,
|
|
2098
2906
|
signInWithCode: (code, state) => authRef.current.signInWithCode(code, state),
|
|
2099
|
-
// Token management
|
|
2100
2907
|
getToken: (opts) => authRef.current.getToken(opts),
|
|
2101
2908
|
getSignInUrl: (redirectUri) => authRef.current.getSignInUrl(redirectUri),
|
|
2102
|
-
// DB access
|
|
2103
2909
|
db: getCurrentDb(),
|
|
2104
2910
|
dbStatus,
|
|
2105
2911
|
dbMode,
|
|
2106
|
-
|
|
2912
|
+
devInfo: schemaDevInfo,
|
|
2913
|
+
refreshSchemaStatus,
|
|
2107
2914
|
isAuthReady: authState.isAuthReady,
|
|
2108
2915
|
signin: handleSignIn,
|
|
2109
2916
|
signout: handleSignOut,
|
|
2110
2917
|
signinWithCode: (code, state) => authRef.current.signInWithCode(code, state),
|
|
2111
2918
|
getSignInLink: (redirectUri) => authRef.current.getSignInUrl(redirectUri)
|
|
2112
2919
|
};
|
|
2113
|
-
return /* @__PURE__ */
|
|
2114
|
-
error && isDevMode() && /* @__PURE__ */
|
|
2920
|
+
return /* @__PURE__ */ jsxs2(BasicContext.Provider, { value: contextValue, children: [
|
|
2921
|
+
error && isDevMode() && /* @__PURE__ */ jsx2(ErrorDisplay, { error }),
|
|
2922
|
+
devToolbar && isDevMode() && /* @__PURE__ */ jsx2(Suspense, { fallback: null, children: /* @__PURE__ */ jsx2(BasicDevToolbar2, { debug }) }),
|
|
2115
2923
|
isReady && children
|
|
2116
2924
|
] });
|
|
2117
2925
|
}
|
|
2118
2926
|
function ErrorDisplay({ error }) {
|
|
2119
|
-
return /* @__PURE__ */
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
|
|
2927
|
+
return /* @__PURE__ */ jsxs2(
|
|
2928
|
+
"div",
|
|
2929
|
+
{
|
|
2930
|
+
style: {
|
|
2931
|
+
position: "absolute",
|
|
2932
|
+
top: 20,
|
|
2933
|
+
left: 20,
|
|
2934
|
+
color: "black",
|
|
2935
|
+
backgroundColor: "#f8d7da",
|
|
2936
|
+
border: "1px solid #f5c6cb",
|
|
2937
|
+
borderRadius: "4px",
|
|
2938
|
+
padding: "20px",
|
|
2939
|
+
maxWidth: "400px",
|
|
2940
|
+
margin: "20px auto",
|
|
2941
|
+
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)",
|
|
2942
|
+
fontFamily: "monospace"
|
|
2943
|
+
},
|
|
2944
|
+
children: [
|
|
2945
|
+
/* @__PURE__ */ jsxs2("h3", { style: { fontSize: "0.8rem", opacity: 0.8 }, children: [
|
|
2946
|
+
"code: ",
|
|
2947
|
+
error.code
|
|
2948
|
+
] }),
|
|
2949
|
+
/* @__PURE__ */ jsx2("h1", { style: { fontSize: "1.2rem", lineHeight: 1.5 }, children: error.title }),
|
|
2950
|
+
/* @__PURE__ */ jsx2("p", { children: error.message })
|
|
2951
|
+
]
|
|
2952
|
+
}
|
|
2953
|
+
);
|
|
2143
2954
|
}
|
|
2144
2955
|
|
|
2145
2956
|
// src/index.ts
|
|
2957
|
+
init_BasicDevToolbar();
|
|
2146
2958
|
import { useLiveQuery as useQuery } from "dexie-react-hooks";
|
|
2147
2959
|
export {
|
|
2960
|
+
BasicDevToolbar,
|
|
2148
2961
|
BasicProvider,
|
|
2149
2962
|
DBStatus,
|
|
2150
2963
|
NotAuthenticatedError,
|