alinea 2.0.0-preview.11 → 2.0.0-preview.13
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/.init/content/pages/welcome.json +1 -1
- package/dist/.mcp/later/dev.json +1 -1
- package/dist/.mcp/online/dev.json +1 -1
- package/dist/adapter/next/cms.js +16 -8
- package/dist/adapter/next/dashboardUrl.d.ts +6 -0
- package/dist/adapter/next/dashboardUrl.js +13 -0
- package/dist/adapter/next/syncCheck.d.ts +15 -2
- package/dist/adapter/next/syncCheck.js +26 -9
- package/dist/backend/Handler.js +5 -1
- package/dist/backend/api/BlobStore.d.ts +21 -0
- package/dist/backend/api/BlobStore.js +63 -0
- package/dist/backend/api/CreateBackend.js +10 -8
- package/dist/backend/api/DatabaseApi.d.ts +4 -1
- package/dist/backend/api/DatabaseApi.js +88 -4
- package/dist/backend/api/GithubApi.js +47 -24
- package/dist/backend/api/database.js +6 -6
- package/dist/bundled.d.ts +687 -248
- package/dist/chunks/{bun-sqlite-5SHXN3AT.js → bun-sqlite-RI6BYU5S.js} +3 -3
- package/dist/chunks/{chunk-YCQR5GRT.js → chunk-3QFSGTGF.js} +2 -3
- package/dist/chunks/{chunk-QJGGYF6E.js → chunk-4ZA6KZHS.js} +5 -5
- package/dist/chunks/{chunk-ASYKC6IE.js → chunk-5H4D5JQL.js} +1 -1
- package/dist/chunks/{chunk-ETWOY4AL.js → chunk-A2I6MCCS.js} +1 -1
- package/dist/chunks/{chunk-W5AXN7GH.js → chunk-CYVOGRSD.js} +1 -2
- package/dist/chunks/{chunk-TIJTT5ZI.js → chunk-G43W7AME.js} +1 -0
- package/dist/chunks/{chunk-RE523BQ7.js → chunk-HOETF6HN.js} +5829 -5830
- package/dist/chunks/{chunk-AIU6CMVT.js → chunk-PTYZMV5G.js} +1 -1
- package/dist/chunks/{chunk-JOF663EG.js → chunk-QHHMKJUO.js} +1 -1
- package/dist/chunks/{chunk-66YZ47TY.js → chunk-RAR44T5O.js} +1 -1
- package/dist/chunks/{chunk-QSN6RH6X.js → chunk-VA6NC3MI.js} +1 -1
- package/dist/chunks/{node-sqlite-XVNTNMCY.js → node-sqlite-C7VJ2NSN.js} +3 -3
- package/dist/cli/Mcp.js +1 -1
- package/dist/cli/Serve.js +1 -1
- package/dist/cli/bin.js +2 -3
- package/dist/cli/generate/GenerateDashboard.js +17 -5
- package/dist/cli/serve/mcp/DevMcp.js +1 -1
- package/dist/cli/serve/mcp/McpTools.js +29 -1
- package/dist/cli/static/dashboard/entry.js +2 -1
- package/dist/cloud/CloudRemote.js +1 -1
- package/dist/components/Alert.js +3 -3
- package/dist/components/AppShell.js +2 -2
- package/dist/components/Badge.d.ts +3 -1
- package/dist/components/Badge.js +5 -3
- package/dist/components/Breadcrumbs.js +6 -6
- package/dist/components/Button.d.ts +6 -1
- package/dist/components/Button.js +14 -5
- package/dist/components/Calendar.js +20 -20
- package/dist/components/Checkbox.js +9 -9
- package/dist/components/CheckboxGroup.js +4 -4
- package/dist/components/Collapsible.js +3 -3
- package/dist/components/ColorSwatch.js +2 -2
- package/dist/components/ColorSwatchPicker.js +2 -2
- package/dist/components/ComboBox.js +7 -7
- package/dist/components/Command.js +10 -9
- package/dist/components/ContentCard.d.ts +3 -1
- package/dist/components/ContentCard.js +39 -17
- package/dist/components/ContentGrid.js +15 -15
- package/dist/components/DataList.js +2 -2
- package/dist/components/DateField.js +2 -2
- package/dist/components/DatePicker.js +2 -2
- package/dist/components/DateRangePicker.js +2 -2
- package/dist/components/Dialog.js +6 -6
- package/dist/components/DropZone.js +4 -4
- package/dist/components/DropdownMenu.js +10 -10
- package/dist/components/Empty.js +4 -4
- package/dist/components/Field.js +8 -8
- package/dist/components/List.js +23 -23
- package/dist/components/MediaPreview.js +5 -5
- package/dist/components/MultipleSelect.js +20 -20
- package/dist/components/NavRail.js +4 -4
- package/dist/components/NumberField.js +5 -5
- package/dist/components/Page.js +5 -5
- package/dist/components/Popover.js +2 -2
- package/dist/components/PreviewFrame.js +5 -5
- package/dist/components/RadioGroup.js +6 -6
- package/dist/components/Resizable.js +5 -5
- package/dist/components/SearchField.d.ts +6 -1
- package/dist/components/SearchField.js +7 -5
- package/dist/components/Select.js +14 -14
- package/dist/components/Sheet.d.ts +50 -0
- package/dist/components/Sheet.js +202 -0
- package/dist/components/Sidebar.js +4 -4
- package/dist/components/SortableList.d.ts +34 -30
- package/dist/components/SortableList.js +162 -265
- package/dist/components/Spinner.js +1 -1
- package/dist/components/Surface.js +2 -2
- package/dist/components/Switch.js +7 -7
- package/dist/components/Table.d.ts +3 -1
- package/dist/components/Table.js +53 -42
- package/dist/components/Tabs.js +5 -5
- package/dist/components/TagGroup.js +9 -9
- package/dist/components/TextField.js +10 -10
- package/dist/components/TimeField.js +8 -8
- package/dist/components/Timestamp.js +1 -1
- package/dist/components/ToggleGroup.js +2 -2
- package/dist/components/Toolbar.js +4 -4
- package/dist/components/Tooltip.js +5 -5
- package/dist/components/Tree.js +29 -29
- package/dist/components/internal/DateControl.js +10 -10
- package/dist/components/internal/ListBoxOption.js +13 -13
- package/dist/components/internal/Locale.js +2 -2
- package/dist/components/internal/PopoverSurface.js +2 -2
- package/dist/components/internal/SelectionCheckbox.js +6 -6
- package/dist/components/internal/Slot.js +1 -1
- package/dist/components/internal/ToggleButton.js +3 -3
- package/dist/components/internal/Trigger.js +2 -2
- package/dist/components/internal/sortableDrag.d.ts +19 -0
- package/dist/components/internal/sortableDrag.js +175 -0
- package/dist/components/internal/useDragDrop.js +2 -2
- package/dist/components.d.ts +1 -0
- package/dist/components.js +1 -0
- package/dist/core/Config.d.ts +6 -1
- package/dist/core/Document.d.ts +9 -1
- package/dist/core/Document.js +31 -6
- package/dist/core/Overview.d.ts +2 -4
- package/dist/core/TextDoc.d.ts +4 -0
- package/dist/core/Validation.d.ts +0 -1
- package/dist/core/Validation.js +0 -6
- package/dist/core/field/RichTextField.js +23 -4
- package/dist/core/media/MediaTypes.js +1 -1
- package/dist/core/source/GithubSource.d.ts +4 -0
- package/dist/core/source/GithubSource.js +127 -25
- package/dist/core/source/GithubUsage.d.ts +21 -0
- package/dist/core/source/GithubUsage.js +47 -0
- package/dist/dashboard/App.d.ts +2 -2
- package/dist/dashboard/App.js +5 -3
- package/dist/dashboard/ViewKeys.d.ts +1 -0
- package/dist/dashboard/ViewKeys.js +1 -0
- package/dist/dashboard/app/ActivityStatus.js +11 -11
- package/dist/dashboard/app/AuthView.js +5 -5
- package/dist/dashboard/app/BlockSheet.d.ts +50 -0
- package/dist/dashboard/app/BlockSheet.js +207 -0
- package/dist/dashboard/app/BlockSheetStoryFrame.d.ts +6 -0
- package/dist/dashboard/app/BlockSheetStoryFrame.js +29 -0
- package/dist/dashboard/app/CompactField.js +15 -15
- package/dist/dashboard/app/CroppedImage.js +2 -2
- package/dist/dashboard/app/DashboardErrorBoundary.js +3 -3
- package/dist/dashboard/app/DashboardLayout.js +3 -1
- package/dist/dashboard/app/EntryHeader.js +32 -33
- package/dist/dashboard/app/EntryReferences.js +5 -5
- package/dist/dashboard/app/EntrySidebar.js +8 -8
- package/dist/dashboard/app/EntrySidebarPreview.js +4 -4
- package/dist/dashboard/app/EntryStatusIcon.d.ts +23 -0
- package/dist/dashboard/app/EntryStatusIcon.js +58 -0
- package/dist/dashboard/app/EntryValidationModal.d.ts +6 -5
- package/dist/dashboard/app/EntryValidationModal.js +18 -18
- package/dist/dashboard/app/Explorer.d.ts +3 -1
- package/dist/dashboard/app/Explorer.js +51 -47
- package/dist/dashboard/app/ExplorerBatchActions.d.ts +3 -1
- package/dist/dashboard/app/ExplorerBatchActions.js +68 -43
- package/dist/dashboard/app/ExplorerCards.js +7 -1
- package/dist/dashboard/app/ExplorerControls.js +6 -6
- package/dist/dashboard/app/ExplorerList.js +5 -5
- package/dist/dashboard/app/ExplorerModal.js +1 -1
- package/dist/dashboard/app/ExplorerTable.js +14 -11
- package/dist/dashboard/app/ImageEditor.js +25 -25
- package/dist/dashboard/app/ImagePicker.js +3 -13
- package/dist/dashboard/app/LinkPicker.js +29 -27
- package/dist/dashboard/app/LocaleMenu.js +7 -7
- package/dist/dashboard/app/MediaPreviewCell.js +2 -2
- package/dist/dashboard/app/MoveConfirmDialog.d.ts +5 -0
- package/dist/dashboard/app/MoveConfirmDialog.js +79 -0
- package/dist/dashboard/app/OverviewCell.js +8 -13
- package/dist/dashboard/app/ReadOnlyBadge.d.ts +1 -1
- package/dist/dashboard/app/RemoveDialog.d.ts +17 -0
- package/dist/dashboard/app/{DeleteDialog.js → RemoveDialog.js} +67 -27
- package/dist/dashboard/app/RemoveRedirect.d.ts +7 -0
- package/dist/dashboard/app/RemoveRedirect.js +123 -0
- package/dist/dashboard/app/SearchBar.d.ts +9 -0
- package/dist/dashboard/app/SearchBar.js +31 -0
- package/dist/dashboard/app/SidebarTree.js +29 -74
- package/dist/dashboard/app/WorkspaceMenu.js +8 -8
- package/dist/dashboard/app/WorkspaceRoots.js +11 -11
- package/dist/dashboard/app/editor/FileEditor.js +16 -16
- package/dist/dashboard/app/modals/CreateEntry.js +5 -5
- package/dist/dashboard/app/pages/EntryPage.d.ts +2 -1
- package/dist/dashboard/app/pages/EntryPage.js +35 -16
- package/dist/dashboard/app/pages/SplashPage.js +35 -35
- package/dist/dashboard/app/pages/UsersPage.js +14 -14
- package/dist/dashboard/app/ui/DashboardModal.js +17 -16
- package/dist/dashboard/atoms/dashboard.js +1 -1
- package/dist/dashboard/atoms/entry.js +1 -14
- package/dist/dashboard/atoms/entryTable.js +1 -0
- package/dist/dashboard/atoms/explorer.d.ts +4 -0
- package/dist/dashboard/atoms/explorer.js +19 -7
- package/dist/dashboard/atoms/graph.js +1 -1
- package/dist/dashboard/atoms/link.js +5 -2
- package/dist/dashboard/atoms/move.d.ts +5 -0
- package/dist/dashboard/atoms/move.js +29 -3
- package/dist/dashboard/atoms/moveConfirmation.d.ts +34 -0
- package/dist/dashboard/atoms/moveConfirmation.js +95 -0
- package/dist/dashboard/atoms/nav.d.ts +9 -5
- package/dist/dashboard/atoms/nav.js +120 -45
- package/dist/dashboard/atoms/overview.d.ts +6 -5
- package/dist/dashboard/atoms/overview.js +2 -16
- package/dist/dashboard/atoms/remove.d.ts +112 -0
- package/dist/dashboard/atoms/remove.js +268 -0
- package/dist/dashboard/atoms/root.d.ts +2 -2
- package/dist/dashboard/atoms/root.js +41 -26
- package/dist/dashboard/atoms/user.js +1 -1
- package/dist/dashboard/atoms/utils.js +1 -1
- package/dist/dashboard/boot/Boot.js +25 -17
- package/dist/dashboard/boot/BootProd.d.ts +6 -1
- package/dist/dashboard/boot/BootProd.js +2 -2
- package/dist/dashboard/boot/DashboardWorker.d.ts +1 -0
- package/dist/dashboard/boot/DashboardWorker.js +18 -18
- package/dist/dashboard/boot/LoadWorker.js +17 -10
- package/dist/dashboard/cms/EntryTable.js +6 -3
- package/dist/database/BrowserEntryStore.d.ts +17 -29
- package/dist/database/BrowserEntryStore.js +116 -144
- package/dist/database/DatabaseTables.js +2 -2
- package/dist/database/EntryDatabase.js +21 -1
- package/dist/database/EntryTransaction.js +0 -35
- package/dist/database/EntryUrlAliases.d.ts +4 -0
- package/dist/database/EntryUrlAliases.js +16 -10
- package/dist/database/driver/RuntimeDatabase.js +3 -3
- package/dist/database/driver/WasmDatabase.d.ts +5 -18
- package/dist/database/driver/WasmDatabase.js +15 -16
- package/dist/database/entry/EntryTable.js +2 -2
- package/dist/database/query/EntryQuery.js +1 -1
- package/dist/database/query/Relation.js +1 -1
- package/dist/database/query/Search.js +2 -2
- package/dist/field/check/CheckField.view.js +2 -2
- package/dist/field/code/CodeField.view.js +14 -14
- package/dist/field/link/EntryLink.d.ts +4 -4
- package/dist/field/link/FileLink.d.ts +4 -4
- package/dist/field/link/ImageLink.d.ts +4 -4
- package/dist/field/link/Link.d.ts +1 -1
- package/dist/field/link/LinkField.d.ts +5 -0
- package/dist/field/link/LinkField.view.js +246 -372
- package/dist/field/link/UrlLink.d.ts +4 -4
- package/dist/field/list/ListField.d.ts +2 -0
- package/dist/field/list/ListField.view.d.ts +15 -0
- package/dist/field/list/ListField.view.js +343 -301
- package/dist/field/metadata/MetadataField.d.ts +17 -7
- package/dist/field/metadata/MetadataField.js +14 -3
- package/dist/field/metadata/MetadataField.view.d.ts +1 -0
- package/dist/field/metadata/MetadataField.view.js +27 -23
- package/dist/field/richtext/RichTextBlock.d.ts +3 -1
- package/dist/field/richtext/RichTextBlock.js +178 -75
- package/dist/field/richtext/RichTextBlockHost.js +1 -1
- package/dist/field/richtext/RichTextExtensions.js +35 -35
- package/dist/field/richtext/RichTextField.view.js +14 -8
- package/dist/field/richtext/RichTextInsertMenu.js +43 -27
- package/dist/field/views.js +2 -0
- package/dist/index.css +490 -309
- package/dist/picker/url/UrlPicker.js +1 -0
- package/docs/components/badge.md +1 -0
- package/docs/components/button.md +1 -0
- package/docs/components/content-card.md +1 -0
- package/docs/components/search-field.md +1 -0
- package/docs/components/sortable-list.md +5 -20
- package/docs/components/table.md +1 -0
- package/docs/configuration.md +1 -1
- package/docs/deploy/self-host.md +1 -1
- package/docs/deploy.md +5 -4
- package/docs/fields.md +1 -1
- package/docs/index.md +1 -1
- package/docs/instant-publishing.md +7 -22
- package/docs/overviews.md +3 -4
- package/docs/upgrading.md +3 -2
- package/llms-full.txt +31 -55
- package/package.json +2 -3
- package/dist/core/db/EntryValidationError.d.ts +0 -13
- package/dist/core/db/EntryValidationError.js +0 -23
- package/dist/dashboard/app/DeleteDialog.d.ts +0 -11
- package/dist/dashboard/atoms/delete.d.ts +0 -68
- package/dist/dashboard/atoms/delete.js +0 -143
- package/dist/chunks/{chunk-MOWR65LM.js → chunk-PYDOMKJZ.js} +71 -71
|
@@ -9,13 +9,16 @@ import { getScope } from "alinea/core/Scope";
|
|
|
9
9
|
import { trigger } from "alinea/core/Trigger";
|
|
10
10
|
import { IndexEvent } from "alinea/core/db/IndexEvent";
|
|
11
11
|
import { EntryUrlConflictError } from "alinea/core/db/EntryUrlConflictError";
|
|
12
|
-
import {
|
|
13
|
-
|
|
12
|
+
import {
|
|
13
|
+
BrowserEntryStore,
|
|
14
|
+
isCorruptDatabaseError
|
|
15
|
+
} from "alinea/database/BrowserEntryStore";
|
|
14
16
|
import { EntryStore } from "alinea/database/EntryStore";
|
|
15
17
|
import {
|
|
16
18
|
ActivityEvent
|
|
17
19
|
} from "./ActivityEvent.js";
|
|
18
20
|
var remote = pLimit(1);
|
|
21
|
+
var cacheName = "alinea-entry-database";
|
|
19
22
|
var syncInterval = 12e4;
|
|
20
23
|
var activityHistoryLimit = 100;
|
|
21
24
|
var DashboardWorker = class extends EventTarget {
|
|
@@ -24,14 +27,13 @@ var DashboardWorker = class extends EventTarget {
|
|
|
24
27
|
#localClient;
|
|
25
28
|
#nextLoad = trigger();
|
|
26
29
|
#defer;
|
|
27
|
-
/** The store kept in IndexedDB, which a replacement takes over from. */
|
|
28
|
-
#stored;
|
|
29
30
|
#currentRevision;
|
|
30
31
|
#mutations = [];
|
|
31
32
|
#activities = [];
|
|
32
33
|
#local = pLimit(1);
|
|
33
34
|
#blocked = false;
|
|
34
35
|
#syncInterval;
|
|
36
|
+
/** Keep the content in memory with `source`, instead of in the browser. */
|
|
35
37
|
constructor(source) {
|
|
36
38
|
super();
|
|
37
39
|
this.#source = source;
|
|
@@ -114,7 +116,7 @@ Remote updates: ${remote2}`
|
|
|
114
116
|
void this.#flush(item);
|
|
115
117
|
return item.sha;
|
|
116
118
|
} catch (error) {
|
|
117
|
-
if (error instanceof EntryUrlConflictError
|
|
119
|
+
if (error instanceof EntryUrlConflictError) {
|
|
118
120
|
this.#cancelMutation(item, error);
|
|
119
121
|
throw error;
|
|
120
122
|
}
|
|
@@ -278,17 +280,17 @@ Remote updates: ${remote2}`
|
|
|
278
280
|
this.#localDB = void 0;
|
|
279
281
|
this.#localClient = void 0;
|
|
280
282
|
try {
|
|
281
|
-
|
|
282
|
-
name: "alinea-entry-database",
|
|
283
|
-
revision,
|
|
284
|
-
replaces: this.#stored
|
|
285
|
-
}) : await EntryStore.memory(config, this.#fallbackSource());
|
|
286
|
-
if (db instanceof BrowserEntryStore) this.#stored = db;
|
|
283
|
+
let db = await this.#open(config, revision, false);
|
|
287
284
|
if (this.#defer)
|
|
288
285
|
void this.#defer().catch(() => {
|
|
289
286
|
});
|
|
290
287
|
this.#defer = void 0;
|
|
291
|
-
|
|
288
|
+
let cacheFailure = await this.#syncLocalIndex(db);
|
|
289
|
+
if (cacheFailure && isCorruptDatabaseError(cacheFailure.error)) {
|
|
290
|
+
await db.close();
|
|
291
|
+
db = await this.#open(config, revision, true);
|
|
292
|
+
cacheFailure = await this.#syncLocalIndex(db);
|
|
293
|
+
}
|
|
292
294
|
if (hadPrevious && (await db.source.getTree()).isEmpty)
|
|
293
295
|
await this.#syncWithClient(db, client).catch(() => {
|
|
294
296
|
});
|
|
@@ -306,8 +308,7 @@ Remote updates: ${remote2}`
|
|
|
306
308
|
});
|
|
307
309
|
this.#defer = async () => {
|
|
308
310
|
unsubscribe();
|
|
309
|
-
|
|
310
|
-
else await db.close();
|
|
311
|
+
await db.close();
|
|
311
312
|
};
|
|
312
313
|
} catch (cause) {
|
|
313
314
|
this.#currentRevision = void 0;
|
|
@@ -316,10 +317,9 @@ Remote updates: ${remote2}`
|
|
|
316
317
|
throw cause;
|
|
317
318
|
}
|
|
318
319
|
}
|
|
319
|
-
#
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
return this.#source;
|
|
320
|
+
#open(config, fingerprint, reset) {
|
|
321
|
+
if (this.#source) return EntryStore.memory(config, this.#source);
|
|
322
|
+
return BrowserEntryStore.open(config, { name: cacheName, fingerprint, reset });
|
|
323
323
|
}
|
|
324
324
|
async #syncLocalIndex(db) {
|
|
325
325
|
const sourceTree = await db.source.getTree();
|
|
@@ -5,19 +5,14 @@ import "../../chunks/chunk-CQ52GEHY.js";
|
|
|
5
5
|
|
|
6
6
|
// src/dashboard/boot/LoadWorker.ts
|
|
7
7
|
import { IndexEvent } from "alinea/core/db/IndexEvent";
|
|
8
|
-
import { MemorySource } from "alinea/core/source/MemorySource";
|
|
9
8
|
import { ActivityEvent } from "./ActivityEvent.js";
|
|
10
9
|
import { DashboardWorker } from "./DashboardWorker.js";
|
|
11
10
|
async function loadWorker(gen) {
|
|
12
|
-
const worker = new DashboardWorker(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
console.info("Worker connected");
|
|
16
|
-
const port = event.ports[0];
|
|
17
|
-
expose(worker, port);
|
|
18
|
-
const listen = (event2) => {
|
|
11
|
+
const worker = new DashboardWorker();
|
|
12
|
+
function forward(target) {
|
|
13
|
+
const listen = (event) => {
|
|
19
14
|
try {
|
|
20
|
-
|
|
15
|
+
target.postMessage({ ...event, type: event.type });
|
|
21
16
|
} catch {
|
|
22
17
|
worker.removeEventListener(IndexEvent.type, listen);
|
|
23
18
|
worker.removeEventListener(ActivityEvent.type, listen);
|
|
@@ -25,7 +20,19 @@ async function loadWorker(gen) {
|
|
|
25
20
|
};
|
|
26
21
|
worker.addEventListener(IndexEvent.type, listen);
|
|
27
22
|
worker.addEventListener(ActivityEvent.type, listen);
|
|
28
|
-
}
|
|
23
|
+
}
|
|
24
|
+
if ("onconnect" in globalThis) {
|
|
25
|
+
addEventListener("connect", (event) => {
|
|
26
|
+
if (!(event instanceof MessageEvent)) return;
|
|
27
|
+
console.info("Worker connected");
|
|
28
|
+
const port = event.ports[0];
|
|
29
|
+
expose(worker, port);
|
|
30
|
+
forward(port);
|
|
31
|
+
});
|
|
32
|
+
} else {
|
|
33
|
+
expose(worker, globalThis);
|
|
34
|
+
forward(globalThis);
|
|
35
|
+
}
|
|
29
36
|
for await (const batch of gen) {
|
|
30
37
|
await worker.load(batch.configFingerprint, batch.config, batch.client);
|
|
31
38
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
unwrap
|
|
3
|
-
} from "../../chunks/chunk-
|
|
3
|
+
} from "../../chunks/chunk-G43W7AME.js";
|
|
4
4
|
import {
|
|
5
5
|
useAtomValueRaw,
|
|
6
6
|
useAtomValueRawSync,
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
import { Schema } from "alinea/core/Schema";
|
|
38
38
|
import { getScope } from "alinea/core/Scope";
|
|
39
39
|
import { Type } from "alinea/core/Type";
|
|
40
|
+
import { EntryStatusIcon, entryStatus } from "../app/EntryStatusIcon.js";
|
|
40
41
|
import {
|
|
41
42
|
OverviewCell,
|
|
42
43
|
overviewCellText,
|
|
@@ -234,17 +235,19 @@ function EntryTableRow({ config, overview, row }) {
|
|
|
234
235
|
const texts = overview.columns.map(
|
|
235
236
|
(column) => overviewCellText(config, column, row, links)
|
|
236
237
|
);
|
|
238
|
+
const status = entryStatus(row);
|
|
237
239
|
return /* @__PURE__ */ jsxs(
|
|
238
240
|
TableRow,
|
|
239
241
|
{
|
|
240
242
|
id: row.id,
|
|
241
|
-
textValue: [row.title, ...texts].filter(Boolean).join(" "),
|
|
243
|
+
textValue: [row.title, status?.label, ...texts].filter(Boolean).join(" "),
|
|
242
244
|
children: [
|
|
243
245
|
/* @__PURE__ */ jsx(
|
|
244
246
|
TableTitle,
|
|
245
247
|
{
|
|
246
248
|
icon: type && getType(type).icon || LucideFile,
|
|
247
|
-
title: row.title
|
|
249
|
+
title: row.title,
|
|
250
|
+
suffix: status && /* @__PURE__ */ jsx(EntryStatusIcon, { status })
|
|
248
251
|
}
|
|
249
252
|
),
|
|
250
253
|
overview.columns.map((column, index) => /* @__PURE__ */ jsx(
|
|
@@ -1,47 +1,35 @@
|
|
|
1
1
|
import type { Config } from 'alinea/core/Config';
|
|
2
|
-
import type { Mutation } from 'alinea/core/db/Mutation';
|
|
3
|
-
import type { CommitRequest } from 'alinea/core/db/CommitRequest';
|
|
4
2
|
import type { SyncOptions } from 'alinea/core/db/LocalStore';
|
|
5
3
|
import type { RemoteSource } from 'alinea/core/source/Source';
|
|
4
|
+
import { type SnapshotStorage } from '@alinea/sqlite-wasm/snapshots';
|
|
6
5
|
import { EntryStore } from './EntryStore.js';
|
|
7
6
|
export interface BrowserEntryStoreOptions {
|
|
8
7
|
name: string;
|
|
9
|
-
|
|
8
|
+
/** Stores of one config fingerprint open the bases it wrote. */
|
|
9
|
+
fingerprint: string;
|
|
10
|
+
/** Where bases are kept, Blobs in IndexedDB by default. */
|
|
11
|
+
storage?: SnapshotStorage;
|
|
10
12
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* stops storing without waiting for its work in flight.
|
|
13
|
+
* Start over from an empty database instead of a stored base, such as
|
|
14
|
+
* when it turned out to be corrupt.
|
|
14
15
|
*/
|
|
15
|
-
|
|
16
|
-
/** The IndexedDB implementation, the global one by default. */
|
|
17
|
-
indexedDB?: IDBFactory;
|
|
18
|
-
IDBKeyRange?: typeof IDBKeyRange;
|
|
16
|
+
reset?: boolean;
|
|
19
17
|
}
|
|
20
18
|
/**
|
|
21
|
-
* WASM entry store
|
|
22
|
-
*
|
|
19
|
+
* WASM entry store on a copy-on-write overlay over the newest stored base:
|
|
20
|
+
* it reads pages from the base as queries need them, and keeps its changes
|
|
21
|
+
* in memory. Every sync stores them as a new base in the background, which
|
|
22
|
+
* the next store opens; the stored bases never change, so stores of any
|
|
23
|
+
* number of workers and dashboard builds can use them at once.
|
|
23
24
|
*/
|
|
24
25
|
export declare class BrowserEntryStore extends EntryStore {
|
|
25
26
|
#private;
|
|
26
|
-
static open(config: Config, options: BrowserEntryStoreOptions
|
|
27
|
+
static open(config: Config, options: BrowserEntryStoreOptions): Promise<BrowserEntryStore>;
|
|
27
28
|
private constructor();
|
|
28
|
-
/**
|
|
29
|
-
* Opening, and syncing, resolve once the content is in memory: storing it
|
|
30
|
-
* is a cache that finishes in the background, which takes seconds for a
|
|
31
|
-
* first sync or a rebuild of a large project.
|
|
32
|
-
*/
|
|
33
29
|
sync(): Promise<string>;
|
|
34
30
|
syncWith(remote: RemoteSource, options?: SyncOptions): Promise<string>;
|
|
35
|
-
|
|
36
|
-
sha: string;
|
|
37
|
-
}>;
|
|
38
|
-
write(request: CommitRequest): Promise<{
|
|
39
|
-
sha: string;
|
|
40
|
-
}>;
|
|
31
|
+
/** Close once the last checkpoint is stored. */
|
|
41
32
|
close(): Promise<void>;
|
|
42
|
-
/**
|
|
43
|
-
* Close a store that a replacement took over from: its work in flight
|
|
44
|
-
* changes only its memory copy, which is not stored.
|
|
45
|
-
*/
|
|
46
|
-
abandon(): Promise<void>;
|
|
47
33
|
}
|
|
34
|
+
/** Whether an error, or one it holds, reports a damaged SQLite database. */
|
|
35
|
+
export declare function isCorruptDatabaseError(error: unknown): boolean;
|
|
@@ -5,177 +5,148 @@ import "../chunks/chunk-CQ52GEHY.js";
|
|
|
5
5
|
|
|
6
6
|
// src/database/BrowserEntryStore.ts
|
|
7
7
|
import { ReadonlyTree } from "alinea/core/source/Tree";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
8
|
+
import { isRecord } from "alinea/core/util/Objects";
|
|
9
|
+
import {
|
|
10
|
+
indexedDBSnapshots
|
|
11
|
+
} from "@alinea/sqlite-wasm/snapshots";
|
|
12
|
+
import { databaseVersion, versionedCacheName } from "./Version.js";
|
|
11
13
|
import { EntryDatabase } from "./EntryDatabase.js";
|
|
12
14
|
import { EntryStore } from "./EntryStore.js";
|
|
13
15
|
import { DatabaseSource } from "./DatabaseSource.js";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
var buildTable = sql.identifier("alinea_dashboard_build");
|
|
16
|
+
import { wasmHandle, wasmSqlite } from "./driver/WasmDatabase.js";
|
|
17
|
+
var cacheSize = -65536;
|
|
18
|
+
var keepBranches = 2;
|
|
18
19
|
var BrowserEntryStore = class _BrowserEntryStore extends EntryStore {
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
await EntryDatabase.createSchema(db, config, ReadonlyTree.EMPTY.sha);
|
|
40
|
-
const database = new EntryDatabase(config, db, { fork: handle.fork });
|
|
41
|
-
if (stored !== void 0 && stored !== options.revision)
|
|
42
|
-
await database.reindex(config);
|
|
43
|
-
if (stored !== options.revision)
|
|
44
|
-
await db.run(
|
|
45
|
-
sql`insert or replace into ${buildTable} (id, revision)
|
|
46
|
-
values (1, ${options.revision})`
|
|
47
|
-
);
|
|
48
|
-
return new _BrowserEntryStore(
|
|
20
|
+
#session;
|
|
21
|
+
#storage;
|
|
22
|
+
#stored;
|
|
23
|
+
#written = Promise.resolve();
|
|
24
|
+
#cleanup = Promise.resolve();
|
|
25
|
+
static async open(config, options) {
|
|
26
|
+
const { name, fingerprint } = options;
|
|
27
|
+
const storage = options.storage ?? indexedDBSnapshots(`${versionedCacheName(name)}-snapshots`);
|
|
28
|
+
const cleanup = !options.storage && globalThis.indexedDB ? cleanupOldCaches(indexedDB, name).catch(() => {
|
|
29
|
+
}) : Promise.resolve();
|
|
30
|
+
const Database = await wasmSqlite();
|
|
31
|
+
const session = options.reset ? storage.session(new Database(), { branch: fingerprint }) : await openBase(storage, Database, fingerprint);
|
|
32
|
+
const store = await _BrowserEntryStore.#on(
|
|
33
|
+
config,
|
|
34
|
+
session,
|
|
35
|
+
storage,
|
|
36
|
+
fingerprint
|
|
37
|
+
).catch((error) => {
|
|
38
|
+
if (!session.snapshot) throw error;
|
|
39
|
+
return _BrowserEntryStore.#on(
|
|
49
40
|
config,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
options.name,
|
|
54
|
-
storageName
|
|
41
|
+
storage.session(new Database(), { branch: fingerprint }),
|
|
42
|
+
storage,
|
|
43
|
+
fingerprint
|
|
55
44
|
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
await storage.delete();
|
|
60
|
-
return _BrowserEntryStore.open(
|
|
61
|
-
config,
|
|
62
|
-
{ ...options, replaces: void 0 },
|
|
63
|
-
true
|
|
64
|
-
);
|
|
65
|
-
}
|
|
45
|
+
});
|
|
46
|
+
store.#cleanup = cleanup;
|
|
47
|
+
return store;
|
|
66
48
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
await copy.attach(storage);
|
|
49
|
+
static async #on(config, session, storage, fingerprint) {
|
|
50
|
+
const sqlite = session.db;
|
|
51
|
+
const branch = session.snapshot?.branch;
|
|
52
|
+
sqlite.run(`pragma cache_size = ${cacheSize}`);
|
|
53
|
+
const { database: db, fork } = wasmHandle(sqlite);
|
|
54
|
+
async function preview() {
|
|
55
|
+
const copy = await fork();
|
|
56
|
+
await copy.database.run(sql`pragma cache_size = -8192`);
|
|
77
57
|
return copy;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
await db.run(sql`pragma page_size = 16384`);
|
|
61
|
+
await EntryDatabase.createSchema(db, config, ReadonlyTree.EMPTY.sha);
|
|
62
|
+
const database = new EntryDatabase(config, db, { fork: preview });
|
|
63
|
+
if (branch !== void 0 && branch !== fingerprint)
|
|
64
|
+
await withoutJournal(sqlite, () => database.reindex(config));
|
|
65
|
+
return new _BrowserEntryStore(config, database, session, storage);
|
|
78
66
|
} catch (error) {
|
|
79
|
-
await
|
|
67
|
+
await db.close();
|
|
80
68
|
throw error;
|
|
81
69
|
}
|
|
82
70
|
}
|
|
83
|
-
|
|
84
|
-
if (this.#detached) return;
|
|
85
|
-
this.#detached = true;
|
|
86
|
-
this.#handle.detach();
|
|
87
|
-
}
|
|
88
|
-
constructor(config, database, handle, factory, baseName, storageName) {
|
|
71
|
+
constructor(config, database, session, storage) {
|
|
89
72
|
super(config, database, new DatabaseSource(database), {
|
|
90
73
|
ownsDatabase: true,
|
|
91
74
|
sourceFollowsDatabase: true
|
|
92
75
|
});
|
|
93
|
-
this.#
|
|
94
|
-
this.#
|
|
95
|
-
this.#baseName = baseName;
|
|
96
|
-
this.#storageName = storageName;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Opening, and syncing, resolve once the content is in memory: storing it
|
|
100
|
-
* is a cache that finishes in the background, which takes seconds for a
|
|
101
|
-
* first sync or a rebuild of a large project.
|
|
102
|
-
*/
|
|
103
|
-
sync() {
|
|
104
|
-
return this.#run(() => super.sync());
|
|
105
|
-
}
|
|
106
|
-
syncWith(remote, options) {
|
|
107
|
-
return this.#run(() => super.syncWith(remote, options));
|
|
108
|
-
}
|
|
109
|
-
mutate(mutations) {
|
|
110
|
-
return this.#persistAfter(() => super.mutate(mutations));
|
|
111
|
-
}
|
|
112
|
-
write(request) {
|
|
113
|
-
return this.#persistAfter(() => super.write(request));
|
|
76
|
+
this.#session = session;
|
|
77
|
+
this.#storage = storage;
|
|
114
78
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return this.#run(async () => {
|
|
118
|
-
const result = await task();
|
|
119
|
-
await this.#handle.flush();
|
|
120
|
-
return result;
|
|
121
|
-
});
|
|
79
|
+
async sync() {
|
|
80
|
+
return this.#checkpoint(await super.sync());
|
|
122
81
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return Promise.reject(new Error("BrowserEntryStore is closed"));
|
|
126
|
-
return this.#persistQueue.run(task);
|
|
82
|
+
async syncWith(remote, options) {
|
|
83
|
+
return this.#checkpoint(await super.syncWith(remote, options));
|
|
127
84
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.#
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
85
|
+
/** Store the content at `revision` as a base, in the background. */
|
|
86
|
+
#checkpoint(revision) {
|
|
87
|
+
if (!this.#storage.supported() || this.#stored === revision) return revision;
|
|
88
|
+
this.#stored = revision;
|
|
89
|
+
const session = this.#session;
|
|
90
|
+
const storage = this.#storage;
|
|
91
|
+
const key = `${revision}-${session.branch}`;
|
|
92
|
+
const save = (key2) => this.database.whileIdle(async () => ({
|
|
93
|
+
saved: session.held ? session.save({ key: key2, meta: { tree: revision } }) : void 0
|
|
94
|
+
})).then(({ saved }) => saved);
|
|
95
|
+
const written = save(key).then(
|
|
96
|
+
(result) => result?.status === "mismatch" ? save(`${key}-${crypto.randomUUID()}`) : result
|
|
97
|
+
).then(() => storage.retain({ branches: keepBranches })).catch(() => {
|
|
98
|
+
if (this.#stored === revision) this.#stored = void 0;
|
|
141
99
|
});
|
|
100
|
+
this.#written = Promise.all([this.#written, written]);
|
|
101
|
+
return revision;
|
|
142
102
|
}
|
|
143
|
-
/**
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
abandon() {
|
|
148
|
-
this.#detach();
|
|
149
|
-
if (this.#closed) return this.#persistQueue.drain();
|
|
150
|
-
this.#closed = true;
|
|
151
|
-
return this.#persistQueue.run(() => super.close());
|
|
103
|
+
/** Close once the last checkpoint is stored. */
|
|
104
|
+
async close() {
|
|
105
|
+
await Promise.all([this.#cleanup, this.#written]);
|
|
106
|
+
await super.close();
|
|
152
107
|
}
|
|
153
108
|
};
|
|
154
|
-
|
|
155
|
-
|
|
109
|
+
var corruptCodes = /* @__PURE__ */ new Set(["SQLITE_CORRUPT", "SQLITE_NOTADB"]);
|
|
110
|
+
var corruptMessage = /database disk image is malformed|file is not a database/;
|
|
111
|
+
function isCorruptDatabaseError(error) {
|
|
112
|
+
if (!isRecord(error)) return false;
|
|
113
|
+
if (typeof error.code === "string" && corruptCodes.has(error.code))
|
|
114
|
+
return true;
|
|
115
|
+
if (typeof error.message === "string" && corruptMessage.test(error.message))
|
|
116
|
+
return true;
|
|
117
|
+
const errors = Array.isArray(error.errors) ? error.errors : [];
|
|
118
|
+
return isCorruptDatabaseError(error.cause) || errors.some(isCorruptDatabaseError);
|
|
156
119
|
}
|
|
157
|
-
async function
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
120
|
+
async function withoutJournal(sqlite, task) {
|
|
121
|
+
const [[mode]] = sqlite.exec("pragma journal_mode")[0].values;
|
|
122
|
+
sqlite.run("pragma journal_mode = off");
|
|
123
|
+
try {
|
|
124
|
+
return await task();
|
|
125
|
+
} finally {
|
|
126
|
+
sqlite.run(`pragma journal_mode = ${mode}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function openBase(storage, Database, fingerprint) {
|
|
130
|
+
const empty = () => storage.session(new Database(), { branch: fingerprint });
|
|
131
|
+
if (!storage.supported()) return empty();
|
|
132
|
+
return storage.open(Database, {
|
|
133
|
+
branch: fingerprint,
|
|
134
|
+
choose: (bases) => bases.find((base) => base.branch === fingerprint) ?? bases[0]
|
|
135
|
+
}).catch(empty);
|
|
171
136
|
}
|
|
172
|
-
async function cleanupOldCaches(factory,
|
|
137
|
+
async function cleanupOldCaches(factory, name) {
|
|
173
138
|
if (!factory.databases) return;
|
|
174
139
|
const databases = await factory.databases().catch(() => []);
|
|
175
|
-
const
|
|
176
|
-
(database) => database.name &&
|
|
140
|
+
const stale = databases.flatMap(
|
|
141
|
+
(database) => database.name && isStale(database.name, name) ? [database.name] : []
|
|
177
142
|
);
|
|
178
|
-
await Promise.all(
|
|
143
|
+
await Promise.all(stale.map((cache) => deleteCache(factory, cache)));
|
|
144
|
+
}
|
|
145
|
+
function isStale(cache, name) {
|
|
146
|
+
if (cache === name || cache === `${versionedCacheName(name)}-pages`)
|
|
147
|
+
return true;
|
|
148
|
+
if (!cache.startsWith(`${name}-v`)) return false;
|
|
149
|
+
return Number.parseInt(cache.slice(name.length + 2)) < databaseVersion;
|
|
179
150
|
}
|
|
180
151
|
function deleteCache(factory, name) {
|
|
181
152
|
return new Promise((resolve) => {
|
|
@@ -186,5 +157,6 @@ function deleteCache(factory, name) {
|
|
|
186
157
|
});
|
|
187
158
|
}
|
|
188
159
|
export {
|
|
189
|
-
BrowserEntryStore
|
|
160
|
+
BrowserEntryStore,
|
|
161
|
+
isCorruptDatabaseError
|
|
190
162
|
};
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
number,
|
|
5
5
|
text,
|
|
6
6
|
varchar
|
|
7
|
-
} from "../chunks/chunk-
|
|
7
|
+
} from "../chunks/chunk-5H4D5JQL.js";
|
|
8
8
|
import {
|
|
9
9
|
table
|
|
10
|
-
} from "../chunks/chunk-
|
|
10
|
+
} from "../chunks/chunk-PYDOMKJZ.js";
|
|
11
11
|
import "../chunks/chunk-76VMZTLN.js";
|
|
12
12
|
import "../chunks/chunk-2PIFHEYR.js";
|
|
13
13
|
import "../chunks/chunk-K62JP6HR.js";
|
|
@@ -11,6 +11,7 @@ import "../chunks/chunk-2PIFHEYR.js";
|
|
|
11
11
|
import "../chunks/chunk-K62JP6HR.js";
|
|
12
12
|
import "../chunks/chunk-ATF42T2B.js";
|
|
13
13
|
import {
|
|
14
|
+
getTable,
|
|
14
15
|
sql
|
|
15
16
|
} from "../chunks/chunk-ETBQTP2S.js";
|
|
16
17
|
import "../chunks/chunk-CQ52GEHY.js";
|
|
@@ -171,6 +172,7 @@ var EntryDatabase = class _EntryDatabase extends Graph {
|
|
|
171
172
|
tree: revision === ReadonlyTree.EMPTY.sha ? ReadonlyTree.EMPTY : null
|
|
172
173
|
});
|
|
173
174
|
await syncFieldIndexes(db, config);
|
|
175
|
+
await analyze(db);
|
|
174
176
|
}
|
|
175
177
|
/**
|
|
176
178
|
* Synchronize a source through this database's single prepared syncer,
|
|
@@ -194,6 +196,7 @@ var EntryDatabase = class _EntryDatabase extends Graph {
|
|
|
194
196
|
recordsTree: this.#recordsTree
|
|
195
197
|
});
|
|
196
198
|
this.#tree = tree;
|
|
199
|
+
if (changed.length > 0) await this.#optimize();
|
|
197
200
|
return changed;
|
|
198
201
|
});
|
|
199
202
|
const change = { revision: tree.sha, changedEntryIds };
|
|
@@ -222,7 +225,7 @@ var EntryDatabase = class _EntryDatabase extends Graph {
|
|
|
222
225
|
const { tree } = await this.#readTreeState();
|
|
223
226
|
if (!tree)
|
|
224
227
|
throw new Error("Cannot reindex a database without a source tree");
|
|
225
|
-
|
|
228
|
+
const reindexed = await this.#db.transaction(
|
|
226
229
|
async (tx) => {
|
|
227
230
|
await tx.run(sql`drop table if exists temp.${blobs}`);
|
|
228
231
|
await tx.run(sql`create temp table ${blobs} as
|
|
@@ -273,6 +276,8 @@ var EntryDatabase = class _EntryDatabase extends Graph {
|
|
|
273
276
|
},
|
|
274
277
|
{ async: true }
|
|
275
278
|
);
|
|
279
|
+
await this.#optimize();
|
|
280
|
+
return reindexed;
|
|
276
281
|
});
|
|
277
282
|
this.#tree = result.tree;
|
|
278
283
|
this.#vocabulary = new SearchVocabulary();
|
|
@@ -386,6 +391,9 @@ var EntryDatabase = class _EntryDatabase extends Graph {
|
|
|
386
391
|
[Symbol.asyncDispose]() {
|
|
387
392
|
return this.close();
|
|
388
393
|
}
|
|
394
|
+
async #optimize() {
|
|
395
|
+
if (!this.#transactional) await analyze(this.#db);
|
|
396
|
+
}
|
|
389
397
|
getRevision() {
|
|
390
398
|
return this.#queue.run(() => this.#getRevision(this.#db));
|
|
391
399
|
}
|
|
@@ -527,6 +535,18 @@ var EntryDatabase = class _EntryDatabase extends Graph {
|
|
|
527
535
|
});
|
|
528
536
|
}
|
|
529
537
|
};
|
|
538
|
+
async function analyze(db) {
|
|
539
|
+
try {
|
|
540
|
+
await db.run(sql`pragma analysis_limit = 400`);
|
|
541
|
+
const entries = getTable(EntryIndexTable).name;
|
|
542
|
+
const stats = await db.get(
|
|
543
|
+
sql`select 1 from sqlite_master where name = 'sqlite_stat1'`
|
|
544
|
+
);
|
|
545
|
+
const analyzed = stats && await db.get(sql`select 1 from sqlite_stat1 where tbl = ${entries}`);
|
|
546
|
+
await db.run(analyzed ? sql`pragma optimize = 0x10002` : sql`analyze`);
|
|
547
|
+
} catch {
|
|
548
|
+
}
|
|
549
|
+
}
|
|
530
550
|
export {
|
|
531
551
|
EntryDatabase
|
|
532
552
|
};
|