korajs 1.0.0-beta.10 → 1.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +105 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +105 -3
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
package/dist/index.cjs
CHANGED
|
@@ -1317,6 +1317,7 @@ function createSyncQuerySubscriptionHook(getSyncEngine) {
|
|
|
1317
1317
|
// src/initialize-app.ts
|
|
1318
1318
|
async function initializeApp(config, emitter, mergeEngine) {
|
|
1319
1319
|
const adapterType = config.store?.adapter ?? detectAdapterType();
|
|
1320
|
+
let effectiveAdapterType = adapterType;
|
|
1320
1321
|
const baseDbName = config.store?.name ?? "kora-db";
|
|
1321
1322
|
const authBinding = config.sync?.authClient ?? null;
|
|
1322
1323
|
const authUserId = config.store?.namespaceByAuthUser && authBinding?.resolveUserId ? await authBinding.resolveUserId() : void 0;
|
|
@@ -1357,6 +1358,7 @@ async function initializeApp(config, emitter, mergeEngine) {
|
|
|
1357
1358
|
emitter,
|
|
1358
1359
|
config.store?.workerResponseTimeoutMs
|
|
1359
1360
|
);
|
|
1361
|
+
effectiveAdapterType = "indexeddb";
|
|
1360
1362
|
store = buildStore(adapter);
|
|
1361
1363
|
await store.open();
|
|
1362
1364
|
emitter.emit({
|
|
@@ -1368,6 +1370,7 @@ async function initializeApp(config, emitter, mergeEngine) {
|
|
|
1368
1370
|
message: `OPFS persistence is unavailable (${fallbackReason}) for database "${dbName}"; Kora is using durable IndexedDB instead.`
|
|
1369
1371
|
});
|
|
1370
1372
|
} catch {
|
|
1373
|
+
effectiveAdapterType = "sqlite-wasm";
|
|
1371
1374
|
adapter = await createAdapter(
|
|
1372
1375
|
"sqlite-wasm",
|
|
1373
1376
|
dbName,
|
|
@@ -1413,6 +1416,8 @@ async function initializeApp(config, emitter, mergeEngine) {
|
|
|
1413
1416
|
url: config.sync.url,
|
|
1414
1417
|
transport: config.sync.transport,
|
|
1415
1418
|
auth: syncAuth,
|
|
1419
|
+
authState: authBinding?.resolveSyncState,
|
|
1420
|
+
querySubsets: config.sync.querySubsets,
|
|
1416
1421
|
batchSize: config.sync.batchSize,
|
|
1417
1422
|
schemaVersion: config.sync.schemaVersion ?? config.schema.version,
|
|
1418
1423
|
scopeMap,
|
|
@@ -1449,7 +1454,15 @@ async function initializeApp(config, emitter, mergeEngine) {
|
|
|
1449
1454
|
unsubscribeLocalOperations,
|
|
1450
1455
|
authBinding,
|
|
1451
1456
|
blobStore,
|
|
1452
|
-
blobChunkProvider
|
|
1457
|
+
blobChunkProvider,
|
|
1458
|
+
storeInfo: {
|
|
1459
|
+
baseName: baseDbName,
|
|
1460
|
+
databaseName: dbName,
|
|
1461
|
+
authUserId: authUserId ?? null,
|
|
1462
|
+
persistence: effectiveAdapterType,
|
|
1463
|
+
durable: adapter.getStorageOpenState?.()?.persistent ?? adapterType !== "sqlite-wasm",
|
|
1464
|
+
isolationState: "ready"
|
|
1465
|
+
}
|
|
1453
1466
|
};
|
|
1454
1467
|
}
|
|
1455
1468
|
function emitOpfsUnavailable(emitter, dbName, reason) {
|
|
@@ -1573,6 +1586,66 @@ function createSyncControl(options) {
|
|
|
1573
1586
|
state.syncStatusBridge?.refresh();
|
|
1574
1587
|
}
|
|
1575
1588
|
},
|
|
1589
|
+
async setQuerySubsets(subsets) {
|
|
1590
|
+
await ready;
|
|
1591
|
+
state.syncEngine?.setQuerySubsets(subsets);
|
|
1592
|
+
},
|
|
1593
|
+
async waitForSettled(options2 = {}) {
|
|
1594
|
+
await ready;
|
|
1595
|
+
const upload = options2.upload ?? true;
|
|
1596
|
+
const download = options2.download ?? "active-view";
|
|
1597
|
+
const classify = () => {
|
|
1598
|
+
const status = state.syncEngine?.getStatus() ?? offlineSyncStatus();
|
|
1599
|
+
if (status.phase === "suspended")
|
|
1600
|
+
return { outcome: "suspended", reason: status.reason ?? "suspended", status };
|
|
1601
|
+
if (status.blockedFailure)
|
|
1602
|
+
return { outcome: "blocked", failure: status.blockedFailure, status };
|
|
1603
|
+
if (status.phase === "offline") return { outcome: "offline", status };
|
|
1604
|
+
const uploadDone = !upload || status.pendingOperations === 0 && (status.inFlightUploadOperations ?? 0) === 0;
|
|
1605
|
+
const downloadDone = download === false || status.activeViewComplete;
|
|
1606
|
+
return uploadDone && downloadDone ? { outcome: "settled", status } : null;
|
|
1607
|
+
};
|
|
1608
|
+
return await new Promise((resolve) => {
|
|
1609
|
+
let done = false;
|
|
1610
|
+
let unsubscribeReady = false;
|
|
1611
|
+
let cleanupPending = false;
|
|
1612
|
+
let timer = null;
|
|
1613
|
+
let unsubscribe = () => {
|
|
1614
|
+
};
|
|
1615
|
+
const finish = (result) => {
|
|
1616
|
+
if (done) return;
|
|
1617
|
+
done = true;
|
|
1618
|
+
if (unsubscribeReady) unsubscribe();
|
|
1619
|
+
else cleanupPending = true;
|
|
1620
|
+
if (timer) clearTimeout(timer);
|
|
1621
|
+
options2.signal?.removeEventListener("abort", onAbort);
|
|
1622
|
+
resolve(result);
|
|
1623
|
+
};
|
|
1624
|
+
const check = () => {
|
|
1625
|
+
const result = classify();
|
|
1626
|
+
if (result) finish(result);
|
|
1627
|
+
};
|
|
1628
|
+
const onAbort = () => finish({
|
|
1629
|
+
outcome: "aborted",
|
|
1630
|
+
status: state.syncEngine?.getStatus() ?? offlineSyncStatus()
|
|
1631
|
+
});
|
|
1632
|
+
unsubscribe = state.syncStatusBridge?.subscribe(check) ?? (() => {
|
|
1633
|
+
});
|
|
1634
|
+
unsubscribeReady = true;
|
|
1635
|
+
if (cleanupPending) unsubscribe();
|
|
1636
|
+
options2.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1637
|
+
if (options2.timeoutMs !== void 0)
|
|
1638
|
+
timer = setTimeout(
|
|
1639
|
+
() => finish({
|
|
1640
|
+
outcome: "timeout",
|
|
1641
|
+
status: state.syncEngine?.getStatus() ?? offlineSyncStatus()
|
|
1642
|
+
}),
|
|
1643
|
+
options2.timeoutMs
|
|
1644
|
+
);
|
|
1645
|
+
if (options2.signal?.aborted) onAbort();
|
|
1646
|
+
else check();
|
|
1647
|
+
});
|
|
1648
|
+
},
|
|
1576
1649
|
getStatus() {
|
|
1577
1650
|
if (state.syncEngine) {
|
|
1578
1651
|
return state.syncEngine.getStatus();
|
|
@@ -1609,13 +1682,22 @@ function createSyncControl(options) {
|
|
|
1609
1682
|
state: "disconnected",
|
|
1610
1683
|
status: {
|
|
1611
1684
|
status: "offline",
|
|
1685
|
+
phase: "offline",
|
|
1612
1686
|
reconnecting: false,
|
|
1613
1687
|
pendingOperations: 0,
|
|
1614
1688
|
lastSyncedAt: null,
|
|
1615
1689
|
lastSuccessfulPush: null,
|
|
1616
1690
|
lastSuccessfulPull: null,
|
|
1617
1691
|
conflicts: 0,
|
|
1618
|
-
clockSkewMs: null
|
|
1692
|
+
clockSkewMs: null,
|
|
1693
|
+
inFlightUploadOperations: 0,
|
|
1694
|
+
hasInFlightDeliveryBatch: false,
|
|
1695
|
+
activeViewId: "",
|
|
1696
|
+
activeViewComplete: false,
|
|
1697
|
+
initialSync: { complete: false, receivedBatches: 0, totalBatches: null, progress: null },
|
|
1698
|
+
deliveryWatermark: 0,
|
|
1699
|
+
serverFrontier: null,
|
|
1700
|
+
blockedFailure: null
|
|
1619
1701
|
},
|
|
1620
1702
|
nodeId: "",
|
|
1621
1703
|
url: config.sync?.url ?? "",
|
|
@@ -1675,8 +1757,15 @@ var AuthSyncCoordinator = class {
|
|
|
1675
1757
|
if (!engine) {
|
|
1676
1758
|
return;
|
|
1677
1759
|
}
|
|
1760
|
+
engine.notifyAuthChanged?.();
|
|
1761
|
+
const authState = await this.authBinding.resolveSyncState?.();
|
|
1762
|
+
if (authState?.state === "loading" || authState?.state === "signed-out") {
|
|
1763
|
+
await engine.stop();
|
|
1764
|
+
await engine.start();
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1678
1767
|
const headers = await this.authBinding.auth();
|
|
1679
|
-
if (!headers.token) {
|
|
1768
|
+
if (!headers.token && authState?.state !== "anonymous") {
|
|
1680
1769
|
await engine.stop();
|
|
1681
1770
|
return;
|
|
1682
1771
|
}
|
|
@@ -1952,6 +2041,14 @@ function createApp(config) {
|
|
|
1952
2041
|
let unsubscribeSync = null;
|
|
1953
2042
|
let unsubscribeAudit = null;
|
|
1954
2043
|
let unsubscribeLocalOperations = null;
|
|
2044
|
+
let currentStoreInfo = {
|
|
2045
|
+
baseName: config.store?.name ?? "kora-db",
|
|
2046
|
+
databaseName: "",
|
|
2047
|
+
authUserId: null,
|
|
2048
|
+
persistence: config.store?.adapter ?? "sqlite-wasm",
|
|
2049
|
+
durable: false,
|
|
2050
|
+
isolationState: "closed"
|
|
2051
|
+
};
|
|
1955
2052
|
const syncState = {
|
|
1956
2053
|
syncEngine: null,
|
|
1957
2054
|
syncStatusBridge: null,
|
|
@@ -1975,6 +2072,7 @@ function createApp(config) {
|
|
|
1975
2072
|
config.blob?.chunkSize,
|
|
1976
2073
|
() => enumerateLiveBlobRefs(init.store, config.schema)
|
|
1977
2074
|
);
|
|
2075
|
+
currentStoreInfo = init.storeInfo;
|
|
1978
2076
|
wireSyncLifecycleAfterReady(config, emitter, syncState, init);
|
|
1979
2077
|
});
|
|
1980
2078
|
const getStore = () => store;
|
|
@@ -2031,6 +2129,9 @@ function createApp(config) {
|
|
|
2031
2129
|
getQueryStoreCache() {
|
|
2032
2130
|
return queryStoreCache;
|
|
2033
2131
|
},
|
|
2132
|
+
storeInfo() {
|
|
2133
|
+
return { ...currentStoreInfo };
|
|
2134
|
+
},
|
|
2034
2135
|
transaction(fn) {
|
|
2035
2136
|
return executeTransaction(fn);
|
|
2036
2137
|
},
|
|
@@ -2064,6 +2165,7 @@ function createApp(config) {
|
|
|
2064
2165
|
await store.close();
|
|
2065
2166
|
store = null;
|
|
2066
2167
|
}
|
|
2168
|
+
currentStoreInfo = { ...currentStoreInfo, isolationState: "closed" };
|
|
2067
2169
|
emitter.clear();
|
|
2068
2170
|
},
|
|
2069
2171
|
async exportBackup(options) {
|