alinea 2.0.0-preview.7 → 2.0.0-preview.9

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.
Files changed (301) hide show
  1. package/dist/.init/content/pages/welcome.json +1 -1
  2. package/dist/LICENSES.md +103 -103
  3. package/dist/adapter/next/cms.d.ts +18 -4
  4. package/dist/adapter/next/cms.js +141 -36
  5. package/dist/adapter/next/handler.d.ts +5 -1
  6. package/dist/adapter/next/handler.js +77 -17
  7. package/dist/adapter/next/node.d.ts +5 -0
  8. package/dist/adapter/next/node.js +16 -0
  9. package/dist/adapter/next/previews.d.ts +4 -1
  10. package/dist/adapter/next/previews.js +13 -1
  11. package/dist/adapter/next/renderStats.d.ts +45 -0
  12. package/dist/adapter/next/renderStats.js +142 -0
  13. package/dist/adapter/next/syncCheck.d.ts +8 -2
  14. package/dist/adapter/next/syncCheck.js +5 -11
  15. package/dist/adapter/next/with-alinea.js +6 -20
  16. package/dist/backend/HandleAction.d.ts +1 -1
  17. package/dist/backend/HandleAction.js +1 -1
  18. package/dist/backend/Handler.d.ts +2 -2
  19. package/dist/backend/Handler.js +45 -47
  20. package/dist/backend/api/CreateBackend.js +15 -3
  21. package/dist/backend/api/DatabaseApi.js +22 -135
  22. package/dist/backend/api/ProxyMedia.d.ts +2 -3
  23. package/dist/backend/api/ProxyMedia.js +7 -22
  24. package/dist/backend/api/database.js +15 -3
  25. package/dist/backend/resolver/ParsePreview.d.ts +2 -2
  26. package/dist/backend/router/NodeHandler.js +2 -0
  27. package/dist/backend/store/GeneratedDatabase.d.ts +8 -0
  28. package/dist/backend/store/GeneratedDatabase.js +33 -0
  29. package/dist/backend/store/GeneratedDatabaseNode.d.ts +4 -0
  30. package/dist/backend/store/GeneratedDatabaseNode.js +35 -0
  31. package/dist/backend/util/ORM.js +4 -2
  32. package/dist/bundled.d.ts +1565 -468
  33. package/dist/chunks/bun-sqlite-5SHXN3AT.js +18 -0
  34. package/dist/chunks/chunk-2BJ2IFQM.js +1085 -0
  35. package/dist/chunks/chunk-2PIFHEYR.js +364 -0
  36. package/dist/chunks/chunk-66YZ47TY.js +94 -0
  37. package/dist/chunks/chunk-76VMZTLN.js +55 -0
  38. package/dist/chunks/chunk-AIU6CMVT.js +495 -0
  39. package/dist/chunks/chunk-ASYKC6IE.js +103 -0
  40. package/dist/chunks/chunk-ATF42T2B.js +35 -0
  41. package/dist/chunks/{chunk-6P4UVRPH.js → chunk-DWR5A5KL.js} +6 -1
  42. package/dist/chunks/{chunk-NWQXN4SB.js → chunk-ETBQTP2S.js} +40 -29
  43. package/dist/chunks/chunk-ETWOY4AL.js +100 -0
  44. package/dist/chunks/chunk-K62JP6HR.js +22 -0
  45. package/dist/chunks/chunk-MOWR65LM.js +610 -0
  46. package/dist/chunks/chunk-N47Y62CI.js +396 -0
  47. package/dist/chunks/chunk-QBPYWU6C.js +24 -0
  48. package/dist/chunks/{chunk-X47OVDF3.js → chunk-QJGGYF6E.js} +356 -1000
  49. package/dist/chunks/chunk-QSN6RH6X.js +94 -0
  50. package/dist/chunks/{chunk-I4GC3E65.js → chunk-UPY2RUZF.js} +0 -1
  51. package/dist/chunks/chunk-XCZXR3C2.js +112 -0
  52. package/dist/chunks/chunk-XTWYBWP2.js +81 -0
  53. package/dist/chunks/node-sqlite-XVNTNMCY.js +18 -0
  54. package/dist/cli/Generate.js +74 -64
  55. package/dist/cli/Serve.js +1 -1
  56. package/dist/cli/bin.js +6 -1
  57. package/dist/cli/generate/CopyStaticFiles.js +17 -14
  58. package/dist/cli/generate/DevDB.d.ts +22 -5
  59. package/dist/cli/generate/DevDB.js +138 -24
  60. package/dist/cli/serve/CreateLocalServer.js +22 -4
  61. package/dist/cli/serve/DevServer.d.ts +2 -0
  62. package/dist/cli/serve/DevServer.js +7 -2
  63. package/dist/cli/serve/LiveReload.d.ts +1 -1
  64. package/dist/cli/serve/LiveReload.js +3 -0
  65. package/dist/cloud/CloudRemote.js +2 -1
  66. package/dist/components/Breadcrumbs.js +2 -2
  67. package/dist/components/Calendar.js +7 -7
  68. package/dist/components/Checkbox.js +1 -1
  69. package/dist/components/ColorSwatchPicker.js +2 -2
  70. package/dist/components/ComboBox.js +14 -14
  71. package/dist/components/DateField.js +1 -1
  72. package/dist/components/DatePicker.js +6 -6
  73. package/dist/components/DateRangePicker.js +4 -4
  74. package/dist/components/Disclosure.js +8 -8
  75. package/dist/components/Label.js +6 -6
  76. package/dist/components/List.js +33 -33
  77. package/dist/components/Menu.js +2 -2
  78. package/dist/components/Modal.js +2 -2
  79. package/dist/components/MultipleSelect.js +23 -23
  80. package/dist/components/NumberField.js +6 -6
  81. package/dist/components/ProgressCircle.js +3 -3
  82. package/dist/components/SearchField.js +8 -8
  83. package/dist/components/Select.js +8 -8
  84. package/dist/components/Surface.js +3 -3
  85. package/dist/components/Switch.js +2 -2
  86. package/dist/components/Table.js +7 -7
  87. package/dist/components/Tabs.js +2 -2
  88. package/dist/components/TagGroup.js +2 -2
  89. package/dist/components/TextField.js +2 -2
  90. package/dist/components/TimeField.js +3 -3
  91. package/dist/components/Toolbar.js +2 -2
  92. package/dist/components/Tooltip.js +4 -4
  93. package/dist/components/Tree.d.ts +2 -1
  94. package/dist/components/Tree.js +6 -6
  95. package/dist/core/Client.d.ts +1 -4
  96. package/dist/core/Client.js +5 -7
  97. package/dist/core/Connection.d.ts +4 -1
  98. package/dist/core/Connection.js +3 -1
  99. package/dist/core/Document.js +15 -3
  100. package/dist/core/Entry.d.ts +3 -0
  101. package/dist/core/Entry.js +4 -0
  102. package/dist/core/EntrySeed.d.ts +19 -0
  103. package/dist/core/EntrySeed.js +136 -0
  104. package/dist/core/Field.d.ts +7 -0
  105. package/dist/core/Field.js +4 -0
  106. package/dist/core/Filter.d.ts +40 -2
  107. package/dist/core/Filter.js +145 -0
  108. package/dist/core/Graph.d.ts +9 -0
  109. package/dist/core/ListRow.d.ts +1 -0
  110. package/dist/core/ListRow.js +1 -0
  111. package/dist/core/Reference.d.ts +1 -0
  112. package/dist/core/Root.js +1 -1
  113. package/dist/core/Scope.d.ts +2 -0
  114. package/dist/core/Scope.js +16 -1
  115. package/dist/core/Type.d.ts +2 -1
  116. package/dist/core/Type.js +13 -1
  117. package/dist/core/db/EntryAliases.js +1 -11
  118. package/dist/core/db/EntryReference.d.ts +0 -6
  119. package/dist/core/db/IndexEvent.d.ts +2 -1
  120. package/dist/core/db/IndexEvent.js +11 -3
  121. package/dist/core/db/LinkResolver.d.ts +6 -6
  122. package/dist/core/db/LinkResolver.js +0 -52
  123. package/dist/core/db/LocalStore.d.ts +27 -0
  124. package/dist/core/field/ListField.js +19 -0
  125. package/dist/core/field/RecordField.js +8 -0
  126. package/dist/core/field/RichTextField.js +42 -0
  127. package/dist/core/field/UnionField.js +8 -0
  128. package/dist/core/source/FSSource.d.ts +14 -2
  129. package/dist/core/source/FSSource.js +58 -13
  130. package/dist/core/source/GitUtils.d.ts +4 -0
  131. package/dist/core/source/GitUtils.js +9 -10
  132. package/dist/core/source/GithubSource.js +60 -21
  133. package/dist/core/source/IndexedDBSource.d.ts +2 -1
  134. package/dist/core/source/IndexedDBSource.js +67 -53
  135. package/dist/core/source/MemorySource.js +5 -3
  136. package/dist/core/source/OverlaySource.d.ts +5 -2
  137. package/dist/core/source/OverlaySource.js +31 -3
  138. package/dist/core/source/Source.d.ts +3 -0
  139. package/dist/core/source/Source.js +15 -2
  140. package/dist/core/source/Tree.d.ts +10 -7
  141. package/dist/core/source/Tree.js +118 -70
  142. package/dist/core/source/Utils.js +6 -3
  143. package/dist/core/util/Arrays.d.ts +1 -0
  144. package/dist/core/util/Arrays.js +10 -0
  145. package/dist/core/util/Async.d.ts +7 -0
  146. package/dist/core/util/Async.js +15 -0
  147. package/dist/core/util/Checks.js +1 -1
  148. package/dist/core/util/EntryFilenames.d.ts +22 -1
  149. package/dist/core/util/EntryFilenames.js +56 -2
  150. package/dist/core/util/IndexedDB.d.ts +4 -0
  151. package/dist/core/util/IndexedDB.js +20 -0
  152. package/dist/core/util/Paths.js +5 -1
  153. package/dist/dashboard/App.js +3 -3
  154. package/dist/dashboard/ViewKeys.d.ts +1 -0
  155. package/dist/dashboard/ViewKeys.js +1 -0
  156. package/dist/dashboard/app/AccessDenied.js +2 -2
  157. package/dist/dashboard/app/ActivityStatus.js +14 -14
  158. package/dist/dashboard/app/AppShell.js +2 -2
  159. package/dist/dashboard/app/AuthView.js +12 -12
  160. package/dist/dashboard/app/CompactField.js +11 -11
  161. package/dist/dashboard/app/DashboardErrorBoundary.js +6 -6
  162. package/dist/dashboard/app/DashboardLayout.js +3 -3
  163. package/dist/dashboard/app/EntryHeader.js +8 -8
  164. package/dist/dashboard/app/EntryReferences.js +8 -8
  165. package/dist/dashboard/app/EntrySidebar.js +15 -15
  166. package/dist/dashboard/app/EntrySidebarPreview.js +7 -7
  167. package/dist/dashboard/app/EntryTranslationBanner.js +5 -5
  168. package/dist/dashboard/app/Explorer.js +39 -39
  169. package/dist/dashboard/app/ExplorerCards.js +31 -31
  170. package/dist/dashboard/app/ExplorerFileCard.js +19 -19
  171. package/dist/dashboard/app/ExplorerList.js +10 -10
  172. package/dist/dashboard/app/ExplorerModal.js +5 -5
  173. package/dist/dashboard/app/ExplorerTable.js +47 -47
  174. package/dist/dashboard/app/LinkPicker.js +5 -5
  175. package/dist/dashboard/app/LocaleMenu.js +4 -4
  176. package/dist/dashboard/app/SidebarTree.js +76 -40
  177. package/dist/dashboard/app/WorkspaceMenu.js +9 -9
  178. package/dist/dashboard/app/WorkspaceRoots.js +22 -22
  179. package/dist/dashboard/app/editor/FileEditor.js +28 -28
  180. package/dist/dashboard/app/editor/FilePreview.js +6 -6
  181. package/dist/dashboard/app/modals/CreateEntry.js +3 -3
  182. package/dist/dashboard/app/pages/EntryPage.js +18 -18
  183. package/dist/dashboard/app/pages/RootPage.js +3 -3
  184. package/dist/dashboard/app/pages/SplashPage.js +45 -45
  185. package/dist/dashboard/app/pages/UsersPage.js +34 -34
  186. package/dist/dashboard/app/ui/DashboardModal.js +18 -18
  187. package/dist/dashboard/app/ui/Rail.js +5 -5
  188. package/dist/dashboard/app/ui/Sidebar.js +2 -2
  189. package/dist/dashboard/atoms/config.d.ts +4 -4
  190. package/dist/dashboard/atoms/entry.d.ts +8 -9
  191. package/dist/dashboard/atoms/entry.js +34 -4
  192. package/dist/dashboard/atoms/explorer.d.ts +2 -0
  193. package/dist/dashboard/atoms/explorer.js +7 -2
  194. package/dist/dashboard/boot/Boot.js +2 -3
  195. package/dist/dashboard/boot/DashboardWorker.d.ts +3 -3
  196. package/dist/dashboard/boot/DashboardWorker.js +82 -27
  197. package/dist/dashboard/boot/LoadWorker.js +2 -3
  198. package/dist/dashboard/boot/WorkerDB.d.ts +2 -2
  199. package/dist/dashboard/icons.d.ts +2 -0
  200. package/dist/dashboard/icons.js +40 -0
  201. package/dist/dashboard/plugins/alineaFixturePlugin.js +14 -3
  202. package/dist/database/BrowserEntryStore.d.ts +42 -0
  203. package/dist/database/BrowserEntryStore.js +182 -0
  204. package/dist/database/DatabaseSource.d.ts +13 -0
  205. package/dist/database/DatabaseSource.js +25 -0
  206. package/dist/database/DatabaseTables.d.ts +38 -0
  207. package/dist/database/DatabaseTables.js +53 -0
  208. package/dist/database/EntryDatabase.d.ts +97 -0
  209. package/dist/database/EntryDatabase.js +528 -0
  210. package/dist/database/EntryStore.d.ts +58 -0
  211. package/dist/database/EntryStore.js +230 -0
  212. package/dist/database/EntryTransaction.d.ts +33 -0
  213. package/dist/database/EntryTransaction.js +907 -0
  214. package/dist/database/EntryUrlAliases.d.ts +2 -0
  215. package/dist/database/EntryUrlAliases.js +69 -0
  216. package/dist/database/LocalDB.d.ts +39 -0
  217. package/dist/database/LocalDB.js +79 -0
  218. package/dist/database/Version.d.ts +9 -0
  219. package/dist/database/Version.js +13 -0
  220. package/dist/database/driver/DatabaseHandle.d.ts +17 -0
  221. package/dist/database/driver/DatabaseHandle.js +0 -0
  222. package/dist/database/driver/OverlayExtension.browser.d.ts +2 -0
  223. package/dist/database/driver/OverlayExtension.browser.js +9 -0
  224. package/dist/database/driver/OverlayExtension.d.ts +1 -0
  225. package/dist/database/driver/OverlayExtension.js +7 -0
  226. package/dist/database/driver/RuntimeDatabase.d.ts +13 -0
  227. package/dist/database/driver/RuntimeDatabase.js +77 -0
  228. package/dist/database/driver/WasmDatabase.d.ts +29 -0
  229. package/dist/database/driver/WasmDatabase.js +46 -0
  230. package/dist/database/entry/EntryData.d.ts +13 -0
  231. package/dist/database/entry/EntryData.js +51 -0
  232. package/dist/database/entry/EntryTable.d.ts +189 -0
  233. package/dist/database/entry/EntryTable.js +186 -0
  234. package/dist/database/query/Condition.d.ts +8 -0
  235. package/dist/database/query/Condition.js +117 -0
  236. package/dist/database/query/EntryQuery.d.ts +44 -0
  237. package/dist/database/query/EntryQuery.js +412 -0
  238. package/dist/database/query/EntryReferences.d.ts +5 -0
  239. package/dist/database/query/EntryReferences.js +70 -0
  240. package/dist/database/query/Relation.d.ts +11 -0
  241. package/dist/database/query/Relation.js +113 -0
  242. package/dist/database/query/ResolveQuery.d.ts +12 -0
  243. package/dist/database/query/ResolveQuery.js +189 -0
  244. package/dist/database/query/Search.d.ts +38 -0
  245. package/dist/database/query/Search.js +149 -0
  246. package/dist/database/sync/Derive.d.ts +8 -0
  247. package/dist/database/sync/Derive.js +270 -0
  248. package/dist/database/sync/EntryParser.d.ts +8 -0
  249. package/dist/database/sync/EntryParser.js +90 -0
  250. package/dist/database/sync/EntrySyncer.d.ts +25 -0
  251. package/dist/database/sync/EntrySyncer.js +89 -0
  252. package/dist/database/sync/Ingest.d.ts +21 -0
  253. package/dist/database/sync/Ingest.js +145 -0
  254. package/dist/database/sync/SyncQueries.d.ts +160 -0
  255. package/dist/database/sync/SyncQueries.js +216 -0
  256. package/dist/field/check/CheckField.view.js +2 -2
  257. package/dist/field/code/CodeField.view.js +10 -10
  258. package/dist/field/link/LinkField.js +23 -0
  259. package/dist/field/link/LinkField.view.js +42 -41
  260. package/dist/field/list/ListField.view.js +172 -150
  261. package/dist/field/metadata/MetadataField.d.ts +28 -3
  262. package/dist/field/metadata/MetadataField.js +44 -7
  263. package/dist/field/metadata/MetadataField.view.d.ts +5 -0
  264. package/dist/field/metadata/MetadataField.view.js +31 -16
  265. package/dist/field/richtext/RichTextDocument.js +4 -3
  266. package/dist/field/richtext/RichTextExtensions.d.ts +1 -1
  267. package/dist/field/richtext/RichTextExtensions.js +33 -29
  268. package/dist/field/richtext/RichTextField.view.js +17 -8
  269. package/dist/field/richtext/RichTextInsertMenu.js +2 -2
  270. package/dist/field/views.js +2 -0
  271. package/dist/next.cjs +6 -20
  272. package/dist/next.d.ts +4 -3
  273. package/dist/next.edge.d.ts +1 -1
  274. package/dist/next.js +1 -2
  275. package/dist/picker/entry/EntryPicker.js +2 -1
  276. package/dist/picker/url/UrlPicker.js +1 -0
  277. package/dist/preview/widget.d.ts +45 -0
  278. package/dist/preview/widget.js +96 -1
  279. package/dist/query.d.ts +28 -0
  280. package/package.json +6 -1
  281. package/dist/adapter/next/DevRemote.d.ts +0 -3
  282. package/dist/adapter/next/DevRemote.js +0 -45
  283. package/dist/backend/store/GeneratedSource.d.ts +0 -2
  284. package/dist/backend/store/GeneratedSource.js +0 -21
  285. package/dist/chunks/chunk-G6E35DMJ.js +0 -1997
  286. package/dist/core/db/EntryDB.d.ts +0 -19
  287. package/dist/core/db/EntryDB.js +0 -48
  288. package/dist/core/db/EntryIndex.d.ts +0 -143
  289. package/dist/core/db/EntryIndex.js +0 -2773
  290. package/dist/core/db/EntryReferenceIndex.d.ts +0 -21
  291. package/dist/core/db/EntryReferenceIndex.js +0 -131
  292. package/dist/core/db/EntryResolver.d.ts +0 -56
  293. package/dist/core/db/EntryResolver.js +0 -699
  294. package/dist/core/db/EntryTarget.d.ts +0 -5
  295. package/dist/core/db/EntryTransaction.d.ts +0 -31
  296. package/dist/core/db/EntryTransaction.js +0 -956
  297. package/dist/core/db/LocalDB.d.ts +0 -42
  298. package/dist/core/db/LocalDB.js +0 -127
  299. package/dist/core/db/TestDB.d.ts +0 -19
  300. package/dist/core/db/TestDB.js +0 -50
  301. /package/dist/core/db/{EntryTarget.js → LocalStore.js} +0 -0
package/dist/bundled.d.ts CHANGED
@@ -44,28 +44,42 @@ declare module 'alinea/adapter/next/cms' {
44
44
  import { CMS } from 'alinea/core/CMS';
45
45
  import { Config } from 'alinea/core/Config';
46
46
  import type { UploadResponse } from 'alinea/core/Connection';
47
- import { LocalDB } from 'alinea/core/db/LocalDB';
47
+ import type { LocalStore } from 'alinea/core/db/LocalStore';
48
48
  import type { Mutation } from 'alinea/core/db/Mutation';
49
49
  import type { GraphQuery } from 'alinea/core/Graph';
50
50
  import type { User } from 'alinea/core/User';
51
51
  import PLazy from 'p-lazy';
52
+ import type { DatabaseOptions } from 'rado';
52
53
  export interface PreviewProps {
53
54
  widget?: boolean;
55
+ /** Show the queries and syncs of each draft render in the widget */
56
+ stats?: boolean;
54
57
  workspace?: string;
55
58
  root?: string;
56
59
  }
60
+ export type OpenBundledDatabase = (config: Config, options?: DatabaseOptions) => Promise<LocalStore>;
61
+ export interface SyncStatus {
62
+ /** Whether queries are answered from the bundled database or the handler. */
63
+ source: 'database' | 'handler';
64
+ /** The content revision the answering side is at. */
65
+ sha: string | undefined;
66
+ /** When this isolate last synced its bundled database with the handler. */
67
+ syncedAt: Date | undefined;
68
+ }
57
69
  export class NextCMS<Definition extends Config = Config> extends CMS<Definition> {
58
70
  #private;
59
- constructor(config: Definition);
71
+ bundledDb: PLazy<LocalStore>;
72
+ constructor(config: Definition, openBundledDatabase?: OpenBundledDatabase);
60
73
  throttle: (sync: () => Promise<unknown>, interval?: number) => Promise<void>;
61
- bundledDb: PLazy<LocalDB>;
74
+ /** Where queries are answered from and how fresh that side is. */
75
+ status(): Promise<SyncStatus>;
62
76
  resolve<Query extends GraphQuery>(query: Query): Promise<any>;
63
77
  user(): Promise<User | undefined>;
64
78
  mutate(mutations: Array<Mutation>): Promise<{
65
79
  sha: string;
66
80
  }>;
67
81
  prepareUpload(file: string): Promise<UploadResponse>;
68
- previews: ({ widget, workspace, root }: PreviewProps) => Promise<import("react").JSX.Element | null>;
82
+ previews: ({ widget, stats: showStats, workspace, root }: PreviewProps) => Promise<import("react").JSX.Element | null>;
69
83
  }
70
84
  export function createCMS<Definition extends Config>(config: Definition): NextCMS<Definition>;
71
85
 
@@ -79,14 +93,6 @@ declare module 'alinea/adapter/next/context' {
79
93
 
80
94
  }
81
95
 
82
- declare module 'alinea/adapter/next/DevRemote' {
83
-
84
- import type { RemoteConnection, RequestContext } from 'alinea/core/Connection';
85
- import type { Config } from 'alinea/core/Config';
86
- export function createDevRemote(context: RequestContext, config: Config): RemoteConnection;
87
-
88
- }
89
-
90
96
  declare module 'alinea/adapter/next/ForwardCredentials' {
91
97
 
92
98
  export function forwardDevelopmentCredentials(request: Request | undefined, apiKey: string, init?: RequestInit): RequestInit;
@@ -98,27 +104,44 @@ declare module 'alinea/adapter/next/handler' {
98
104
  import { type BackendFactory, type BackendOptions } from 'alinea/backend/api/CreateBackend';
99
105
  import { type HandlerHooks } from 'alinea/backend/Handler';
100
106
  import { Config } from 'alinea/core/Config';
107
+ import type { LocalStore } from 'alinea/core/db/LocalStore';
101
108
  import { NextCMS } from 'alinea/adapter/next/cms';
102
109
  type Handler = (request: Request) => Promise<Response>;
103
110
  export interface NextHandlerOptions extends HandlerHooks {
104
111
  cms: NextCMS;
105
112
  backend?: BackendFactory | BackendOptions;
106
113
  }
107
- export function createHandler(input: NextCMS | NextHandlerOptions): Handler;
114
+ export type OpenGeneratedDatabase = (config: Config) => Promise<LocalStore>;
115
+ export function createHandlerWithDatabase(input: NextCMS | NextHandlerOptions, openGeneratedDatabase?: OpenGeneratedDatabase): Handler;
108
116
  export function handlerPathname(config: Config, requestUrl: URL): string;
117
+ /** A handler without a generated database, as used in the Edge runtime. */
118
+ export function createHandler(input: NextCMS | NextHandlerOptions): Handler;
109
119
  export {};
110
120
 
111
121
  }
112
122
 
123
+ declare module 'alinea/adapter/next/node' {
124
+
125
+ import type { Config } from 'alinea/core/Config';
126
+ import { NextCMS } from 'alinea/adapter/next/cms';
127
+ import { type NextHandlerOptions } from 'alinea/adapter/next/handler';
128
+ export function createCMS<Definition extends Config>(config: Definition): NextCMS<Definition>;
129
+ export function createHandler(input: NextCMS | NextHandlerOptions): (request: Request) => Promise<Response>;
130
+
131
+ }
132
+
113
133
  declare module 'alinea/adapter/next/previews' {
114
134
 
135
+ import { type PreviewStats } from 'alinea/preview/widget';
115
136
  export interface NextPreviewsProps {
116
137
  dashboardUrl: string;
117
138
  widget?: boolean;
139
+ /** Resolves once the render's CMS queries settled. */
140
+ stats?: Promise<PreviewStats>;
118
141
  root?: string;
119
142
  workspace?: string;
120
143
  }
121
- export default function NextPreviews({ dashboardUrl, widget, root, workspace }: NextPreviewsProps): import("react").JSX.Element | null;
144
+ export default function NextPreviews({ dashboardUrl, widget, stats, root, workspace }: NextPreviewsProps): import("react").JSX.Element | null;
122
145
  /**
123
146
  * Wrapper around `router.refresh()` from `next/navigation` `useRouter()` to return Promise, and resolve after refresh completed
124
147
  * @returns Refresh function
@@ -133,10 +156,65 @@ declare module 'alinea/adapter/next/previews.spec' {
133
156
 
134
157
  }
135
158
 
159
+ declare module 'alinea/adapter/next/renderStats' {
160
+
161
+ import type { GraphQuery } from 'alinea/core/Graph';
162
+ import type { PreviewDatabase, PreviewStat, PreviewStatement, PreviewStats } from 'alinea/preview/widget';
163
+ /** Collects the CMS queries and syncs of one draft render. */
164
+ export class RenderStats {
165
+ #private;
166
+ rows: Array<PreviewStat>;
167
+ statements: number;
168
+ sqlMs: number;
169
+ slowest: Array<PreviewStatement>;
170
+ /** The bundled database that answered, once a query reached it. */
171
+ database?: PreviewDatabase;
172
+ readonly startedAt: number;
173
+ /** Add a row and count it as pending until `run` settles; see `timed`. */
174
+ track<T>(stat: Omit<PreviewStat, 'durationMs'>, run: (row: PreviewStat) => Promise<T>): Promise<T>;
175
+ /**
176
+ * Time a database query without the time it waited behind the others:
177
+ * queries of a render run one at a time in the order they were called, so
178
+ * one starts executing once the previous one finished, or when it was
179
+ * called if that is later.
180
+ */
181
+ executed<T>(row: PreviewStat, run: () => Promise<T>): Promise<T>;
182
+ /**
183
+ * Count a statement towards the render, and towards the row that ran it:
184
+ * a sync in progress, or else the query executing, which is the earliest
185
+ * one called that has not finished (see `executed`).
186
+ */
187
+ statement(durationMs: number, sql?: string): void;
188
+ /**
189
+ * Resolves once nothing ran for `quietMs`, so queries of server components
190
+ * that render after the caller are counted, or after `maxMs` regardless.
191
+ */
192
+ settled(quietMs?: number, maxMs?: number): Promise<PreviewStats>;
193
+ }
194
+ /**
195
+ * A statement short enough to read in a table, such as
196
+ * `select … from alinea_entry_index where (visible = ? and id in (?))`.
197
+ */
198
+ export function summarizeSql(sql: string, maxLength?: number): string;
199
+ /**
200
+ * Time the work a row stands for from call to answer, such as a sync or a
201
+ * query the handler answers, without the sync it waited for.
202
+ */
203
+ export function timed<T>(row: PreviewStat | undefined, run: () => Promise<T>): Promise<T>;
204
+ /** A short description such as `first(type, url=/about)`. */
205
+ export function summarizeQuery(query: GraphQuery): string;
206
+
207
+ }
208
+
136
209
  declare module 'alinea/adapter/next/syncCheck' {
137
210
 
138
211
  import type { Client } from 'alinea/core/Client';
139
- import type { LocalDB } from 'alinea/core/db/LocalDB';
212
+ import type { SyncOptions } from 'alinea/core/db/LocalStore';
213
+ import type { RemoteSource } from 'alinea/core/source/Source';
214
+ interface SyncableDB {
215
+ readonly sha: string | Promise<string>;
216
+ syncWith(source: RemoteSource, options?: SyncOptions): Promise<string>;
217
+ }
140
218
  export const CONTENT_SHA_TAG = "alinea-content-sha";
141
219
  export function revalidateContentSha(): Promise<void>;
142
220
  /**
@@ -146,7 +224,8 @@ declare module 'alinea/adapter/next/syncCheck' {
146
224
  * Returns false when the sha could not be determined, so the caller falls
147
225
  * back to its existing throttle behavior.
148
226
  */
149
- export function syncIfStale(db: LocalDB, client: Client, syncInterval?: number): Promise<boolean>;
227
+ export function syncIfStale(db: SyncableDB, client: Client, syncInterval?: number, options?: SyncOptions): Promise<boolean>;
228
+ export {};
150
229
 
151
230
  }
152
231
 
@@ -356,9 +435,8 @@ declare module 'alinea/backend/api/OAuth2' {
356
435
 
357
436
  declare module 'alinea/backend/api/ProxyMedia' {
358
437
 
359
- import { type Request, Response } from '@alinea/iso';
360
- export function proxyMediaUrl(request: Request, source: URL, isAllowed?: (url: URL) => boolean): Promise<Response>;
361
- export function isRedirectStatus(status: number): boolean;
438
+ import { type Request } from '@alinea/iso';
439
+ export function proxyMediaUrl(request: Request, source: URL): Promise<Response>;
362
440
 
363
441
  }
364
442
 
@@ -496,7 +574,7 @@ declare module 'alinea/backend/HandleAction' {
496
574
  Mutate = "mutate",
497
575
  Upload = "upload",
498
576
  Tree = "tree",
499
- Commit = "commit",
577
+ Sha = "sha",
500
578
  Blob = "blob"
501
579
  }
502
580
 
@@ -506,7 +584,7 @@ declare module 'alinea/backend/Handler' {
506
584
 
507
585
  import type { CMS } from 'alinea/core/CMS';
508
586
  import type { AuthedContext, RemoteConnection, RequestContext } from 'alinea/core/Connection';
509
- import { LocalDB } from 'alinea/core/db/LocalDB';
587
+ import type { LocalStore } from 'alinea/core/db/LocalStore';
510
588
  import type { Mutation } from 'alinea/core/db/Mutation';
511
589
  export interface Handler {
512
590
  (request: Request, context: RequestContext): Promise<Response>;
@@ -524,7 +602,7 @@ declare module 'alinea/backend/Handler' {
524
602
  }
525
603
  export interface HandlerOptions extends HandlerHooks {
526
604
  cms: CMS;
527
- db: LocalDB | Promise<LocalDB>;
605
+ db: LocalStore | Promise<LocalStore>;
528
606
  remote?: (context: RequestContext) => RemoteConnection;
529
607
  forwardMutations?(request: Request, context: AuthedContext): Promise<Response | undefined>;
530
608
  }
@@ -562,15 +640,15 @@ declare module 'alinea/backend/Previews' {
562
640
 
563
641
  declare module 'alinea/backend/resolver/ParsePreview' {
564
642
 
565
- import type { LocalDB } from 'alinea/core/db/LocalDB';
566
643
  import { Entry } from 'alinea/core/Entry';
567
644
  import type { PreviewRequest, PreviewUpdate } from 'alinea/core/Preview';
645
+ import type { Graph } from 'alinea/core/Graph';
568
646
  export interface DecodedEntryPreview {
569
647
  entry: Entry;
570
648
  }
571
649
  export type DecodedPreviewRequest = PreviewUpdate | DecodedEntryPreview;
572
650
  export function decodePreviewRequest(preview: PreviewRequest): Promise<DecodedPreviewRequest>;
573
- export function applyPreview(local: LocalDB, preview: DecodedPreviewRequest): Promise<PreviewRequest | undefined>;
651
+ export function applyPreview(local: Graph, preview: DecodedPreviewRequest): Promise<PreviewRequest | undefined>;
574
652
 
575
653
  }
576
654
 
@@ -737,16 +815,31 @@ declare module 'alinea/backend/router/Router' {
737
815
 
738
816
  }
739
817
 
740
- declare module 'alinea/backend/store/GeneratedRelease' {
818
+ declare module 'alinea/backend/store/GeneratedDatabase' {
741
819
 
742
- export const generatedRelease: Promise<string>;
820
+ import type { Config } from 'alinea/core/Config';
821
+ import type { DatabaseHandle } from 'alinea/database/driver/DatabaseHandle';
822
+ import { EntryStore } from 'alinea/database/EntryStore';
823
+ /**
824
+ * Serve a generated database from a connection that keeps its writes in
825
+ * memory, so syncs and commits never reach the generated file.
826
+ */
827
+ export function createGeneratedDatabase(config: Config, { database: db, fork, driver }: DatabaseHandle): Promise<EntryStore>;
743
828
 
744
829
  }
745
830
 
746
- declare module 'alinea/backend/store/GeneratedSource' {
831
+ declare module 'alinea/backend/store/GeneratedDatabaseNode' {
747
832
 
748
- import { MemorySource } from 'alinea/core/source/MemorySource';
749
- export const generatedSource: Promise<MemorySource>;
833
+ import type { Config } from 'alinea/core/Config';
834
+ import type { DatabaseOptions } from 'rado';
835
+ /** Open the traced generated file as an in-memory overlay. */
836
+ export function generatedDatabase(config: Config, options?: DatabaseOptions): Promise<import("alinea/database/EntryStore").EntryStore>;
837
+
838
+ }
839
+
840
+ declare module 'alinea/backend/store/GeneratedRelease' {
841
+
842
+ export const generatedRelease: Promise<string>;
750
843
 
751
844
  }
752
845
 
@@ -872,23 +965,40 @@ declare module 'alinea/cli/generate/DevDB' {
872
965
 
873
966
  import { Config } from 'alinea/core/Config';
874
967
  import type { UploadResponse } from 'alinea/core/Connection';
875
- import type { CommitRequest } from 'alinea/core/db/CommitRequest';
876
- import { LocalDB } from 'alinea/core/db/LocalDB';
968
+ import { type CommitRequest } from 'alinea/core/db/CommitRequest';
877
969
  import { CachedFSSource } from 'alinea/core/source/FSSource';
970
+ import { EntryDatabase } from 'alinea/database/EntryDatabase';
971
+ import { EntryStore } from 'alinea/database/EntryStore';
878
972
  export interface DevDBOptions {
879
973
  config: Config;
880
974
  rootDir: string;
975
+ databasePath: string;
976
+ configFingerprint?: string;
881
977
  dashboardUrl: string | undefined;
882
978
  }
883
979
  export interface WatchFiles {
884
980
  files: Array<string>;
885
981
  dirs: Array<string>;
886
982
  }
887
- export class DevDB extends LocalDB {
983
+ /** The persistent generated database used by dev, build and the local handler. */
984
+ export class DevDB extends EntryStore {
888
985
  #private;
889
- source: CachedFSSource;
890
- constructor(options: DevDBOptions);
986
+ readonly source: CachedFSSource;
987
+ readonly database: EntryDatabase;
988
+ private constructor();
989
+ /** Whether the source was restored from a previously built database. */
990
+ get hydrated(): boolean;
991
+ /** How many entries the last sync changed; zero when everything was reused. */
992
+ get lastSyncChanges(): number;
993
+ static create(options: DevDBOptions): Promise<DevDB>;
994
+ /**
995
+ * Adopt a changed config in place: every entry is derived again from the
996
+ * content files while the database stays open, so the dev server keeps
997
+ * serving through the rebuild and the hydrated file stats stay valid.
998
+ */
999
+ reconfigure(options: Pick<DevDBOptions, 'config' | 'configFingerprint' | 'dashboardUrl'>): Promise<void>;
891
1000
  sync(): Promise<string>;
1001
+ finalize(): Promise<number>;
892
1002
  fix(): Promise<void>;
893
1003
  watchFiles(): Promise<WatchFiles>;
894
1004
  isInMediaLocation(file: string): boolean;
@@ -985,6 +1095,7 @@ declare module 'alinea/cli/serve/CreateLocalServer' {
985
1095
 
986
1096
  declare module 'alinea/cli/serve/DevServer' {
987
1097
 
1098
+ import type { CMS } from 'alinea/core/CMS';
988
1099
  import { Config } from 'alinea/core/Config';
989
1100
  import { Request, type Response } from '@alinea/iso';
990
1101
  import type { BuildOptions } from 'esbuild';
@@ -1005,6 +1116,7 @@ declare module 'alinea/cli/serve/DevServer' {
1005
1116
  handle(input: Request): Promise<Response>;
1006
1117
  }
1007
1118
  export function createDevServer(dir: string, options: CreateDevServerOptions): Promise<DevServer>;
1119
+ export function forwardMutation(request: Request, cms: CMS, apiKey: string): Promise<Response | undefined>;
1008
1120
 
1009
1121
  }
1010
1122
 
@@ -1032,7 +1144,7 @@ declare module 'alinea/cli/serve/LiveReload' {
1032
1144
  export class LiveReload {
1033
1145
  clients: Array<Client>;
1034
1146
  reload(type: 'refetch' | 'refresh' | 'reload'): void;
1035
- register(client: Client): void;
1147
+ register(client: Client): () => void;
1036
1148
  }
1037
1149
  export {};
1038
1150
 
@@ -2027,11 +2139,12 @@ declare module 'alinea/components/Tooltip' {
2027
2139
 
2028
2140
  declare module 'alinea/components/Tree' {
2029
2141
 
2030
- import { type ReactNode } from 'react';
2142
+ import { type ReactNode, type Ref } from 'react';
2031
2143
  import { type TreeItemContentProps as AriaTreeItemContentProps, type TreeItemProps as AriaTreeItemProps, type TreeProps as AriaTreeProps } from 'react-aria-components';
2032
2144
  import { type IconProps } from 'alinea/components/Icon';
2033
2145
  export interface TreeProps<T extends object> extends Omit<AriaTreeProps<T>, 'className'> {
2034
2146
  className?: string;
2147
+ ref?: Ref<HTMLDivElement>;
2035
2148
  }
2036
2149
  export function Tree<T extends object>(props: TreeProps<T>): import("react").JSX.Element;
2037
2150
  export interface TreeItemContentProps extends Omit<AriaTreeItemContentProps, 'children'> {
@@ -2113,7 +2226,6 @@ declare module 'alinea/core/Client' {
2113
2226
  import { type AuthResult } from 'alinea/cloud/AuthResult';
2114
2227
  import type { Config } from 'alinea/core/Config';
2115
2228
  import type { BackendCapabilities, LocalConnection, Revision, UploadMetadata, UploadResponse } from 'alinea/core/Connection';
2116
- import type { CommitRequest } from 'alinea/core/db/CommitRequest';
2117
2229
  import type { Mutation } from 'alinea/core/db/Mutation';
2118
2230
  import type { Draft, DraftKey } from 'alinea/core/Draft';
2119
2231
  import type { EntryRecord } from 'alinea/core/EntryRecord';
@@ -2150,10 +2262,8 @@ declare module 'alinea/core/Client' {
2150
2262
  revisions(file: string): Promise<Array<Revision>>;
2151
2263
  revisionData(file: string, revisionId: string): Promise<EntryRecord | undefined>;
2152
2264
  getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
2265
+ getSha(): Promise<string>;
2153
2266
  getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
2154
- write(request: CommitRequest): Promise<{
2155
- sha: string;
2156
- }>;
2157
2267
  getDraft(key: DraftKey): Promise<Draft | undefined>;
2158
2268
  storeDraft(draft: Draft): Promise<void>;
2159
2269
  }
@@ -2287,7 +2397,8 @@ declare module 'alinea/core/Connection' {
2287
2397
  export interface BrowserConnection extends Connection {
2288
2398
  logout?(): Promise<void>;
2289
2399
  }
2290
- export interface LocalConnection extends Connection, CapabilitiesApi {
2400
+ /** A handler seen from the dashboard or an app: it commits by mutating. */
2401
+ export interface LocalConnection extends SyncApi, HistoryApi, DraftsApi, UploadsApi, UserApi, CapabilitiesApi {
2291
2402
  mutate(mutations: Array<Mutation>): Promise<{
2292
2403
  sha: string;
2293
2404
  }>;
@@ -2326,6 +2437,8 @@ declare module 'alinea/core/Connection' {
2326
2437
  applyAuth?(init?: RequestInit): RequestInit;
2327
2438
  }
2328
2439
  export const developmentKeyHeader = "x-alinea-dev-key";
2440
+ /** Marks a mutation an app sends back to the dev server after its hooks ran. */
2441
+ export const forwardedMutationHeader = "x-alinea-forwarded";
2329
2442
  export interface AuthedContext extends RequestContext {
2330
2443
  user: User;
2331
2444
  token: string;
@@ -2394,178 +2507,6 @@ declare module 'alinea/core/db/EntryAliases' {
2394
2507
 
2395
2508
  }
2396
2509
 
2397
- declare module 'alinea/core/db/EntryDB' {
2398
-
2399
- import type { Config } from 'alinea/core/Config';
2400
- import type { LocalConnection, UploadMetadata, UploadResponse } from 'alinea/core/Connection';
2401
- import type { Source } from 'alinea/core/source/Source';
2402
- import { type CommitRequest } from 'alinea/core/db/CommitRequest';
2403
- import { LocalDB } from 'alinea/core/db/LocalDB';
2404
- import type { Mutation } from 'alinea/core/db/Mutation';
2405
- export class EntryDB extends LocalDB {
2406
- connect: () => Promise<LocalConnection>;
2407
- constructor(config: Config, source: Source, connect: () => Promise<LocalConnection>);
2408
- mutate(mutations: Array<Mutation>): Promise<{
2409
- sha: string;
2410
- remote: Promise<string>;
2411
- }>;
2412
- write(request: CommitRequest): Promise<{
2413
- sha: string;
2414
- }>;
2415
- prepareUpload(file: string, metadata?: UploadMetadata): Promise<UploadResponse>;
2416
- syncWithRemote(): Promise<string>;
2417
- }
2418
-
2419
- }
2420
-
2421
- declare module 'alinea/core/db/EntryIndex' {
2422
-
2423
- import { Config } from 'alinea/core/Config';
2424
- import type { Entry, EntryStatus } from 'alinea/core/Entry';
2425
- import type { ChangesBatch } from 'alinea/core/source/Change';
2426
- import { type Source } from 'alinea/core/source/Source';
2427
- import { ReadonlyTree } from 'alinea/core/source/Tree';
2428
- import { Type } from 'alinea/core/Type';
2429
- import type { EntryReferenceQuery, EntryReferenceResult } from 'alinea/core/db/EntryReference';
2430
- import { EntryReferenceIndex } from 'alinea/core/db/EntryReferenceIndex';
2431
- import { EntryTransaction } from 'alinea/core/db/EntryTransaction';
2432
- export interface EntryFilter {
2433
- ids?: ReadonlyArray<string>;
2434
- search?: string;
2435
- condition?(entry: Entry): boolean;
2436
- }
2437
- export interface EntryCondition {
2438
- search?: string;
2439
- nodes?: Iterable<EntryNode>;
2440
- node?(node: EntryNode): boolean;
2441
- language?(language: EntryLanguageNode): boolean;
2442
- entry?(entry: Entry): boolean;
2443
- }
2444
- interface EntryNodeQuery {
2445
- ids?: ReadonlyArray<string>;
2446
- parentIds?: ReadonlyArray<string | null>;
2447
- urls?: ReadonlyArray<string>;
2448
- workspaces?: ReadonlyArray<string>;
2449
- roots?: ReadonlyArray<string>;
2450
- types?: ReadonlyArray<string>;
2451
- }
2452
- export function combineConditions(a: EntryCondition, b: EntryCondition): EntryCondition;
2453
- interface EntryVersionData {
2454
- id: string;
2455
- type: string;
2456
- index: string;
2457
- searchableText?: string;
2458
- title: string;
2459
- data: Record<string, unknown>;
2460
- seeded: string | null;
2461
- rowHash: string;
2462
- fileHash: string;
2463
- }
2464
- interface EntryVersion extends EntryVersionData {
2465
- locale: string | null;
2466
- workspace: string;
2467
- root: string;
2468
- path: string;
2469
- status: EntryStatus;
2470
- parentDir: string;
2471
- childrenDir: string;
2472
- filePath: string;
2473
- level: number;
2474
- }
2475
- class EntryLanguage extends Map<EntryStatus, EntryVersion> {
2476
- readonly locale: string | null;
2477
- readonly parentDir: string;
2478
- readonly selfDir: string;
2479
- constructor(versions: Array<EntryVersion>);
2480
- }
2481
- class EntryCollection extends Map<string | null, EntryLanguage> {
2482
- versions: Array<EntryVersion>;
2483
- readonly type: string;
2484
- constructor(versions: Array<EntryVersion>);
2485
- }
2486
- class EntryLanguageNode {
2487
- #private;
2488
- private node;
2489
- private language;
2490
- inheritedStatus: EntryStatus | undefined;
2491
- main: EntryVersion;
2492
- active: EntryVersion;
2493
- url: string;
2494
- locale: string | null;
2495
- path: string;
2496
- readonly seeded: string | null;
2497
- constructor(node: EntryNode, language: EntryLanguage);
2498
- [Symbol.iterator](): MapIterator<[EntryStatus, EntryVersion]>;
2499
- has(status: EntryStatus): boolean;
2500
- get parentPaths(): string[];
2501
- get entries(): Entry<Record<string, unknown>>[];
2502
- filter(filter: EntryCondition): Generator<Entry>;
2503
- }
2504
- export class EntryNode extends Map<string | null, EntryLanguageNode> {
2505
- graph: EntryGraph;
2506
- entryType: Type;
2507
- parent: EntryNode | null;
2508
- children: () => Iterable<EntryNode>;
2509
- readonly id: string;
2510
- readonly index: string;
2511
- readonly parentId: string | null;
2512
- readonly parents: Array<string>;
2513
- readonly workspace: string;
2514
- readonly root: string;
2515
- readonly type: string;
2516
- readonly level: number;
2517
- constructor(graph: EntryGraph, entryType: Type, parent: EntryNode | null, children: () => Iterable<EntryNode>, collection: EntryCollection);
2518
- filter(filter: EntryCondition): Generator<Entry>;
2519
- }
2520
- export class EntryGraph {
2521
- #private;
2522
- nodes: Array<EntryNode>;
2523
- constructor(config: Config, versionData: Map<string, EntryVersionData>, seeds: Map<string, Seed>);
2524
- byId(id: string): EntryNode | undefined;
2525
- candidateNodes(query: EntryNodeQuery): Array<EntryNode> | undefined;
2526
- byUrl(url: string): Iterable<Entry>;
2527
- byAlias(alias: string): Iterable<Entry>;
2528
- get config(): Config;
2529
- byDir(dir: string): EntryNode | undefined;
2530
- entryByFilePath(filePath: string): Entry | undefined;
2531
- withChanges(batch: ChangesBatch): EntryGraph;
2532
- filter({ search, ...filter }: EntryCondition): Generator<Entry>;
2533
- }
2534
- export class EntryIndex extends EventTarget {
2535
- #private;
2536
- tree: ReadonlyTree;
2537
- initialSync: ReadonlyTree | undefined;
2538
- graph: EntryGraph;
2539
- constructor(config: Config);
2540
- clone(): EntryIndex;
2541
- get sha(): string;
2542
- filter(filter: EntryCondition): Iterable<Entry>;
2543
- findFirst<T extends Record<string, unknown>>(filter: (entry: Entry) => boolean): Entry<T> | undefined;
2544
- findMany(filter: (entry: Entry) => boolean): Iterable<Entry>;
2545
- findByUrl(url: string, filter: (entry: Entry) => boolean): Entry | undefined;
2546
- referencesTo(query: EntryReferenceQuery): Promise<EntryReferenceResult>;
2547
- referencesFrom(sourceId: string): Promise<import("alinea/core/db/EntryReference").EntryReference[]>;
2548
- get references(): Promise<EntryReferenceIndex>;
2549
- sync(source: Source): Promise<string>;
2550
- syncWith(source: Source): Promise<string>;
2551
- indexChanges(batch: ChangesBatch, targetTree?: ReadonlyTree): Promise<string>;
2552
- seed(source: Source): Promise<void>;
2553
- byId(id: string): EntryNode | undefined;
2554
- fix(source: Source): Promise<void>;
2555
- transaction(source: Source): Promise<EntryTransaction>;
2556
- }
2557
- interface Seed {
2558
- seedId: string;
2559
- type: string;
2560
- workspace: string;
2561
- root: string;
2562
- locale: string | null;
2563
- data: Record<string, any>;
2564
- }
2565
- export {};
2566
-
2567
- }
2568
-
2569
2510
  declare module 'alinea/core/db/EntryReference' {
2570
2511
 
2571
2512
  import type { EntryStatus } from 'alinea/core/Entry';
@@ -2600,151 +2541,12 @@ declare module 'alinea/core/db/EntryReference' {
2600
2541
  export interface EntryReferenceResult {
2601
2542
  references: Array<EntryReference>;
2602
2543
  total: number;
2603
- scan: EntryReferenceScan;
2604
2544
  }
2605
2545
  export interface FieldReferenceContext {
2606
2546
  path: Array<string>;
2607
2547
  label?: string;
2608
2548
  }
2609
2549
  export function referenceFieldPath(path: Array<string>): string;
2610
- export interface EntryReferenceScan {
2611
- scanned: number;
2612
- total: number;
2613
- complete: boolean;
2614
- }
2615
-
2616
- }
2617
-
2618
- declare module 'alinea/core/db/EntryReferenceIndex' {
2619
-
2620
- import type { Config } from 'alinea/core/Config';
2621
- import type { EntryCondition } from 'alinea/core/db/EntryIndex';
2622
- import { type EntryReference, type EntryReferenceQuery, type EntryReferenceResult, type EntryReferenceScan } from 'alinea/core/db/EntryReference';
2623
- import type { Entry } from 'alinea/core/Entry';
2624
- export interface EntryReferenceGraph {
2625
- config: Config;
2626
- filter(filter: EntryCondition): Iterable<Entry>;
2627
- }
2628
- export interface EntryReferenceBuildOptions {
2629
- onProgress?: (scan: EntryReferenceScan) => void;
2630
- }
2631
- export class EntryReferenceIndex {
2632
- #private;
2633
- static build(graph: EntryReferenceGraph, options?: EntryReferenceBuildOptions): Promise<EntryReferenceIndex>;
2634
- constructor(config: Config);
2635
- referencesTo(query: EntryReferenceQuery): EntryReferenceResult;
2636
- referencesFrom(sourceId: string): Array<EntryReference>;
2637
- replaceEntry(entry: Entry): Set<string>;
2638
- removeFile(filePath: string): Set<string>;
2639
- replaceFile(filePath: string, references: Array<EntryReference>): Set<string>;
2640
- }
2641
-
2642
- }
2643
-
2644
- declare module 'alinea/core/db/EntryResolver' {
2645
-
2646
- import type { Config } from 'alinea/core/Config';
2647
- import { Entry as EntryExprs, type Entry } from 'alinea/core/Entry';
2648
- import type { Expr } from 'alinea/core/Expr';
2649
- import { Field } from 'alinea/core/Field';
2650
- import type { Filter } from 'alinea/core/Filter';
2651
- import { type AnyQueryResult, type Edge, type EdgeQuery, type GraphQuery, type Projection, type Status } from 'alinea/core/Graph';
2652
- import { type HasExpr } from 'alinea/core/Internal';
2653
- import type { Resolver } from 'alinea/core/Resolver';
2654
- import type { Type } from 'alinea';
2655
- import { type EntryCondition, type EntryFilter, type EntryGraph, type EntryIndex } from 'alinea/core/db/EntryIndex';
2656
- import { LinkResolver } from 'alinea/core/db/LinkResolver';
2657
- type Interim = any;
2658
- export interface PostContext {
2659
- linkResolver: LinkResolver;
2660
- }
2661
- export class EntryResolver implements Resolver {
2662
- #private;
2663
- config: Config;
2664
- index: EntryIndex;
2665
- constructor(config: Config, index: EntryIndex);
2666
- call(ctx: ResolveContext, entry: Entry, internal: {
2667
- method: string;
2668
- args: Array<Expr>;
2669
- }): unknown;
2670
- field(entry: Entry, field: Expr): unknown;
2671
- expr(ctx: ResolveContext, entry: Entry, expr: Expr): unknown;
2672
- projectTypes(types: Array<Type>): Array<[string, Expr]>;
2673
- projection(query: GraphQuery<Projection>): Projection;
2674
- sourceFilter(ctx: ResolveContext, entry: Entry, query: EdgeQuery): EntryCondition;
2675
- selectProjection(ctx: ResolveContext, entry: Entry, value: Projection): unknown;
2676
- select(ctx: ResolveContext, entry: Entry | null, query: GraphQuery<Projection>): unknown;
2677
- condition(ctx: ResolveContext, query: EdgeQuery): EntryFilter;
2678
- isSingleResult(query: GraphQuery & Partial<Edge>): boolean;
2679
- query(ctx: ResolveContext, query: GraphQuery<Projection>, preFilter?: EntryCondition): {
2680
- entries: EntryExprs<Record<string, unknown>>[];
2681
- getUnprocessed: () => unknown;
2682
- getProcessed: () => Promise<any>;
2683
- };
2684
- postField(ctx: PostContext, interim: Interim, field: Field): Promise<unknown>;
2685
- postExpr(ctx: PostContext, interim: Interim, expr: HasExpr): Promise<unknown>;
2686
- postRow(ctx: PostContext, interim: Interim, query: GraphQuery<Projection>): Promise<unknown>;
2687
- post(ctx: PostContext, interim: Interim, input: EdgeQuery<Projection>): Promise<unknown>;
2688
- resolve<Query extends GraphQuery>(query: Query): Promise<AnyQueryResult<Query>>;
2689
- }
2690
- export interface ResolveContext {
2691
- status: Status;
2692
- locale?: string | null;
2693
- graph: EntryGraph;
2694
- searchTerms?: string;
2695
- }
2696
- export function statusChecker(status: Status): Check;
2697
- interface Check {
2698
- (input: Entry): boolean;
2699
- }
2700
- export function filterChecker(filter: Filter, getField?: (input: any, name: string) => any): Check;
2701
- export {};
2702
-
2703
- }
2704
-
2705
- declare module 'alinea/core/db/EntryTarget' {
2706
-
2707
- import type { RemoteSource } from 'alinea/core/source/Source';
2708
- import type { CommitRequest } from 'alinea/core/db/CommitRequest';
2709
- export interface EntryTarget extends RemoteSource {
2710
- commit(request: CommitRequest): Promise<string>;
2711
- }
2712
-
2713
- }
2714
-
2715
- declare module 'alinea/core/db/EntryTransaction' {
2716
-
2717
- import { Config } from 'alinea/core/Config';
2718
- import { Policy } from 'alinea/core/Role';
2719
- import type { Source } from 'alinea/core/source/Source';
2720
- import type { ReadonlyTree } from 'alinea/core/source/Tree';
2721
- import { type CommitChange } from 'alinea/core/db/CommitRequest';
2722
- import type { EntryIndex } from 'alinea/core/db/EntryIndex';
2723
- import type { ArchiveMutation, CreateMutation, MoveMutation, Mutation, PublishMutation, RemoveFileMutation, RemoveMutation, UnpublishMutation, UpdateMutation, UploadFileMutation } from 'alinea/core/db/Mutation';
2724
- type Op<T> = Omit<T, 'op'>;
2725
- export class EntryTransaction {
2726
- #private;
2727
- constructor(config: Config, index: EntryIndex, source: Source, from: ReadonlyTree, policy?: Policy);
2728
- get empty(): boolean;
2729
- create({ locale, type, data, root, workspace, fromSeed, parentId, id, insertOrder, status, overwrite }: Op<CreateMutation>): this;
2730
- update({ id, locale, status, set }: Op<UpdateMutation>): this;
2731
- publish({ id, locale, status }: Op<PublishMutation>): this;
2732
- unpublish({ id, locale }: Op<UnpublishMutation>): this;
2733
- archive({ id, locale }: Op<ArchiveMutation>): this;
2734
- move({ id, target, dropPosition, targetType }: Op<MoveMutation>): this;
2735
- remove({ id, locale, status }: Op<RemoveMutation>): this;
2736
- removeFile(mutation: Op<RemoveFileMutation>): this;
2737
- uploadFile(mutation: Op<UploadFileMutation>): this;
2738
- description(): string;
2739
- apply(mutations: ReadonlyArray<Mutation>): Promise<void>;
2740
- toRequest(): Promise<{
2741
- fromSha: string;
2742
- intoSha: string;
2743
- description: string;
2744
- changes: CommitChange[];
2745
- }>;
2746
- }
2747
- export {};
2748
2550
 
2749
2551
  }
2750
2552
 
@@ -2767,8 +2569,9 @@ declare module 'alinea/core/db/EntryUrlConflictError' {
2767
2569
  declare module 'alinea/core/db/IndexEvent' {
2768
2570
 
2769
2571
  export class IndexEvent extends Event {
2770
- data: IndexOp;
2771
2572
  static readonly type = "index";
2573
+ static [Symbol.hasInstance](value: unknown): boolean;
2574
+ data: IndexOp;
2772
2575
  constructor(data: IndexOp);
2773
2576
  }
2774
2577
  export type IndexOp = {
@@ -2792,17 +2595,17 @@ declare module 'alinea/core/db/IndexEvent' {
2792
2595
  declare module 'alinea/core/db/LinkResolver' {
2793
2596
 
2794
2597
  import type { InferProjection, Projection } from 'alinea/core/Graph';
2795
- import type { EntryResolver, ResolveContext } from 'alinea/core/db/EntryResolver';
2598
+ import type { Config } from 'alinea/core/Config';
2796
2599
  export interface LinkTarget {
2797
2600
  entryId: string;
2798
2601
  locale?: string;
2799
2602
  }
2800
- export class LinkResolver {
2801
- resolver: EntryResolver;
2802
- private ctx;
2603
+ /** Field postprocessors depend on query capabilities, not an index backend. */
2604
+ export interface LinkResolver {
2605
+ config: Config;
2803
2606
  locale: string | null;
2804
- constructor(resolver: EntryResolver, ctx: ResolveContext, locale: string | null);
2805
- resolveLinks<P extends Projection>(projection: P, entryIds: ReadonlyArray<string>, locale?: string | null | undefined): Promise<Array<InferProjection<P>>>;
2607
+ includedAtBuild(filePath: string): boolean | Promise<boolean>;
2608
+ resolveLinks<P extends Projection>(projection: P, entryIds: ReadonlyArray<string>, locale?: string | null): Promise<Array<InferProjection<P>>>;
2806
2609
  resolveTargets<P extends Projection & {
2807
2610
  id: unknown;
2808
2611
  }>(projection: P, targets: ReadonlyArray<LinkTarget>): Promise<Array<InferProjection<P> | undefined>>;
@@ -2810,49 +2613,34 @@ declare module 'alinea/core/db/LinkResolver' {
2810
2613
 
2811
2614
  }
2812
2615
 
2813
- declare module 'alinea/core/db/LocalDB' {
2616
+ declare module 'alinea/core/db/LocalStore' {
2814
2617
 
2815
- import type { Config } from 'alinea/core/Config';
2816
- import type { SyncApi, UploadMetadata, UploadResponse } from 'alinea/core/Connection';
2817
- import type { AnyQueryResult, GraphQuery } from 'alinea/core/Graph';
2818
2618
  import type { Policy } from 'alinea/core/Role';
2819
- import type { ChangesBatch } from 'alinea/core/source/Change';
2820
- import type { GetBlobsOptions } from 'alinea/core/source/Source';
2821
- import { type Source } from 'alinea/core/source/Source';
2822
- import { type CommitRequest } from 'alinea/core/db/CommitRequest';
2823
- import { EntryIndex } from 'alinea/core/db/EntryIndex';
2824
- import type { EntryReferenceQuery, EntryReferenceResult } from 'alinea/core/db/EntryReference';
2619
+ import type { RemoteSource, Source } from 'alinea/core/source/Source';
2620
+ import type { CommitRequest } from 'alinea/core/db/CommitRequest';
2825
2621
  import type { Mutation } from 'alinea/core/db/Mutation';
2826
- import { WriteableGraph } from 'alinea/core/db/WriteableGraph';
2827
- export class LocalDB extends WriteableGraph {
2828
- #private;
2829
- config: Config;
2830
- index: EntryIndex;
2622
+ import type { WriteableGraph } from 'alinea/core/db/WriteableGraph';
2623
+ export interface SyncOptions {
2624
+ /** Skip entry validation for a remote whose entries were already validated. */
2625
+ validate?: boolean;
2626
+ }
2627
+ /**
2628
+ * A locally available entry store: a writeable graph backed by a source that
2629
+ * can be synced against a remote and committed to. Implemented by the SQLite
2630
+ * engine (`EntryStore`) and the `LocalDB` convenience facade.
2631
+ */
2632
+ export interface LocalStore extends WriteableGraph, RemoteSource {
2831
2633
  source: Source;
2832
- constructor(config: Config, source?: Source, index?: EntryIndex);
2833
- resolve<Query extends GraphQuery>(query: Query): Promise<AnyQueryResult<Query>>;
2834
- referencesTo(query: EntryReferenceQuery): Promise<EntryReferenceResult>;
2835
- get sha(): string;
2836
- indexChanges(batch: ChangesBatch): Promise<string>;
2837
- applyChanges(batch: ChangesBatch): Promise<void>;
2838
- getTreeIfDifferent(sha: string): Promise<import("alinea/core/source/Tree").ReadonlyTree | undefined>;
2839
- getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncIterable<[sha: string, blob: Uint8Array<ArrayBufferLike>]>;
2634
+ /** How the store reads its database, when it is a SQLite connection. */
2635
+ driver?: 'native' | 'overlay' | 'wasm';
2636
+ sha: string | Promise<string>;
2840
2637
  sync(): Promise<string>;
2841
- syncWith(remote: SyncApi): Promise<string>;
2842
- logEntries(): Promise<void>;
2843
- request(mutations: ReadonlyArray<Mutation>, policy?: Policy): Promise<{
2844
- fromSha: string;
2845
- intoSha: string;
2846
- description: string;
2847
- changes: import("alinea/core/db/CommitRequest").CommitChange[];
2848
- }>;
2849
- mutate(mutations: Array<Mutation>): Promise<{
2850
- sha: string;
2851
- }>;
2638
+ syncWith(remote: RemoteSource, options?: SyncOptions): Promise<string>;
2639
+ includedAtBuild(filePath: string): boolean | Promise<boolean>;
2640
+ request(mutations: ReadonlyArray<Mutation>, policy?: Policy): Promise<CommitRequest>;
2852
2641
  write(request: CommitRequest): Promise<{
2853
2642
  sha: string;
2854
2643
  }>;
2855
- prepareUpload(file: string, _metadata?: UploadMetadata): Promise<UploadResponse>;
2856
2644
  }
2857
2645
 
2858
2646
  }
@@ -3034,30 +2822,6 @@ declare module 'alinea/core/db/Operation' {
3034
2822
 
3035
2823
  }
3036
2824
 
3037
- declare module 'alinea/core/db/TestDB' {
3038
-
3039
- import type { LocalConnection } from 'alinea/core/Connection';
3040
- import { type User, type UserInput } from 'alinea/core/User';
3041
- import { LocalDB } from 'alinea/core/db/LocalDB';
3042
- export class TestDB extends LocalDB implements LocalConnection {
3043
- capabilities(): Promise<{
3044
- users: boolean;
3045
- }>;
3046
- previewToken(): Promise<string>;
3047
- user(): Promise<User>;
3048
- enrichUser(user: User): Promise<User>;
3049
- listUsers(): Promise<Array<User>>;
3050
- createUser(user: UserInput): Promise<User>;
3051
- updateUser(user: UserInput): Promise<User>;
3052
- removeUser(): Promise<void>;
3053
- revisions(): Promise<never[]>;
3054
- revisionData(): Promise<undefined>;
3055
- getDraft(): Promise<undefined>;
3056
- storeDraft(): Promise<void>;
3057
- }
3058
-
3059
- }
3060
-
3061
2825
  declare module 'alinea/core/db/WriteableGraph' {
3062
2826
 
3063
2827
  import type { Infer } from 'alinea';
@@ -3174,6 +2938,8 @@ declare module 'alinea/core/Entry' {
3174
2938
  export const ALT_STATUS: Array<EntryStatus>;
3175
2939
  export interface Entry<Data extends object = Record<string, unknown>> {
3176
2940
  id: string;
2941
+ /** Physical authored version before status inheritance is applied. */
2942
+ versionStatus?: EntryStatus;
3177
2943
  status: EntryStatus;
3178
2944
  title: string;
3179
2945
  type: string;
@@ -3206,6 +2972,7 @@ declare module 'alinea/core/Entry' {
3206
2972
  }
3207
2973
  export const Entry: {
3208
2974
  id: Expr<string>;
2975
+ versionStatus: Expr<EntryStatus>;
3209
2976
  status: Expr<EntryStatus>;
3210
2977
  title: Expr<string>;
3211
2978
  type: Expr<string>;
@@ -3328,6 +3095,30 @@ declare module 'alinea/core/EntryRecord' {
3328
3095
 
3329
3096
  }
3330
3097
 
3098
+ declare module 'alinea/core/EntrySeed' {
3099
+
3100
+ import { type Config as ConfigType } from 'alinea/core/Config';
3101
+ import type { Mutation } from 'alinea/core/db/Mutation';
3102
+ import type { Graph } from 'alinea/core/Graph';
3103
+ export interface EntrySeed {
3104
+ id: string;
3105
+ type: string;
3106
+ workspace: string;
3107
+ root: string;
3108
+ locale: string | null;
3109
+ filePath: string;
3110
+ nodePath: string;
3111
+ parentNodePath: string | null;
3112
+ seedPath: string;
3113
+ data: Record<string, unknown>;
3114
+ }
3115
+ export function entrySeeds(config: ConfigType): ReadonlyArray<EntrySeed>;
3116
+ /** Plan the creations needed to materialize every configured seed. */
3117
+ export function seedMutations(graph: Graph, config: ConfigType): Promise<Array<Mutation>>;
3118
+ export function seedData(config: ConfigType, seedPath: string | null, data: Record<string, unknown>, location: Pick<EntrySeed, 'workspace' | 'root' | 'locale'>): Record<string, unknown>;
3119
+
3120
+ }
3121
+
3331
3122
  declare module 'alinea/core/Expr' {
3332
3123
 
3333
3124
  import { type HasExpr, internalExpr } from 'alinea/core/Internal';
@@ -3390,6 +3181,10 @@ declare module 'alinea/core/Field' {
3390
3181
  export interface FieldAnchorContext {
3391
3182
  anchors: Set<string>;
3392
3183
  }
3184
+ export interface FieldLocalizeContext {
3185
+ locale: string;
3186
+ entryIds: Set<string>;
3187
+ }
3393
3188
  export type WithoutLabel<Options extends FieldOptions<any>> = Omit<Options, 'label'>;
3394
3189
  export interface FieldMeta<StoredValue, QueryValue, Mutator, Options> {
3395
3190
  options: Options & FieldOptions<StoredValue>;
@@ -3404,6 +3199,8 @@ declare module 'alinea/core/Field' {
3404
3199
  references?: (value: StoredValue, context: FieldReferenceContext) => Array<EntryReferenceTarget>;
3405
3200
  anchors?: (value: StoredValue, context: FieldReferenceContext) => Array<EntryAnchorTarget>;
3406
3201
  normalizeAnchors?: (value: StoredValue, context: FieldAnchorContext) => StoredValue;
3202
+ /** Point entry links to entryIds at the given locale */
3203
+ localizeLinks?: (value: StoredValue, context: FieldLocalizeContext) => StoredValue;
3407
3204
  beforeSave?: (context: FieldBeforeSaveContext<StoredValue>) => StoredValue;
3408
3205
  }
3409
3206
  export type FieldBeforeSaveAction = 'create' | 'update' | 'publish' | 'translate';
@@ -3450,6 +3247,7 @@ declare module 'alinea/core/Field' {
3450
3247
  function references<StoredValue, QueryValue, Mutator, Options>(field: Field<StoredValue, QueryValue, Mutator, Options>, value: StoredValue, context: FieldReferenceContext): Array<EntryReferenceTarget>;
3451
3248
  function anchors<StoredValue, QueryValue, Mutator, Options>(field: Field<StoredValue, QueryValue, Mutator, Options>, value: StoredValue, context: FieldReferenceContext): Array<EntryAnchorTarget>;
3452
3249
  function normalizeAnchors<StoredValue>(field: HasField, value: StoredValue, context: FieldAnchorContext): StoredValue;
3250
+ function localizeLinks<StoredValue>(field: HasField, value: StoredValue, context: FieldLocalizeContext): StoredValue;
3453
3251
  function isField(value: any): value is Field;
3454
3252
  }
3455
3253
  export {};
@@ -3619,8 +3417,6 @@ declare module 'alinea/core/Filter' {
3619
3417
  type FieldOps<Fields> = {
3620
3418
  [K in keyof Fields]?: Condition<Fields[K]>;
3621
3419
  };
3622
- export interface AnyCondition<Value> extends Ops<Value>, ArrayOps<Value>, ObjectOps<Value> {
3623
- }
3624
3420
  export type Condition<Value> = [Value] extends [Primitive] ? Ops<Value> | Value : [Value] extends [Array<any>] ? ArrayOps<Value[0]> : ObjectOps<Value>;
3625
3421
  type AndCondition<Fields> = {
3626
3422
  and: Array<Filter<Fields> | undefined>;
@@ -3629,14 +3425,55 @@ declare module 'alinea/core/Filter' {
3629
3425
  or: Array<Filter<Fields> | undefined>;
3630
3426
  };
3631
3427
  export type Filter<Fields = unknown> = AndCondition<Fields> | OrCondition<Fields> | FieldOps<Fields>;
3632
- export {};
3633
-
3634
- }
3635
-
3636
- declare module 'alinea/core/Graph' {
3637
-
3638
- import type { Root, Workspace } from 'alinea/types';
3639
- import type { Config } from 'alinea/core/Config';
3428
+ /** A validated filter over named fields, shared by every filter backend. */
3429
+ export type FilterNode = {
3430
+ op: 'and';
3431
+ nodes: Array<FilterNode>;
3432
+ } | {
3433
+ op: 'or';
3434
+ nodes: Array<FilterNode>;
3435
+ } | {
3436
+ op: 'field';
3437
+ name: string;
3438
+ condition: ConditionNode;
3439
+ };
3440
+ /** A validated condition on one value. */
3441
+ export type ConditionNode = {
3442
+ op: 'and';
3443
+ nodes: Array<ConditionNode>;
3444
+ } | {
3445
+ op: 'or';
3446
+ nodes: Array<ConditionNode>;
3447
+ } | {
3448
+ op: 'is' | 'isNot' | 'gt' | 'gte' | 'lt' | 'lte';
3449
+ value: unknown;
3450
+ } | {
3451
+ op: 'in' | 'notIn';
3452
+ values: Array<unknown>;
3453
+ } | {
3454
+ op: 'startsWith';
3455
+ value: string;
3456
+ } | {
3457
+ op: 'has';
3458
+ filter: FilterNode;
3459
+ } | {
3460
+ op: 'includes';
3461
+ item: ConditionNode;
3462
+ };
3463
+ export function parseFilter(filter: unknown): FilterNode;
3464
+ export function parseCondition(condition: unknown): ConditionNode;
3465
+ type FilterCheck<Input> = (input: Input) => boolean;
3466
+ type FieldAccessor<Input> = (input: Input, name: string) => unknown;
3467
+ export function filterChecker<Input = unknown>(filter: Filter, getField?: FieldAccessor<Input>): FilterCheck<Input>;
3468
+ export {};
3469
+
3470
+ }
3471
+
3472
+ declare module 'alinea/core/Graph' {
3473
+
3474
+ import type { Root, Workspace } from 'alinea/types';
3475
+ import type { Config } from 'alinea/core/Config';
3476
+ import type { EntryStatus } from 'alinea/core/Entry';
3640
3477
  import type { EntryFields } from 'alinea/core/EntryFields';
3641
3478
  import type { Expr } from 'alinea/core/Expr';
3642
3479
  import type { Condition, Filter } from 'alinea/core/Filter';
@@ -3738,8 +3575,16 @@ declare module 'alinea/core/Graph' {
3738
3575
  id?: Condition<string>;
3739
3576
  /** Filter by parentId */
3740
3577
  parentId?: Condition<string | null>;
3578
+ /** Filter by the physical authored status before inheritance. */
3579
+ versionStatus?: Condition<EntryStatus>;
3580
+ /** Filter by whether this is the preferred version for its locale. */
3581
+ main?: Condition<boolean>;
3741
3582
  /** Filter by path */
3742
3583
  path?: Condition<string>;
3584
+ /** Filter by the full source file path. */
3585
+ filePath?: Condition<string>;
3586
+ /** Filter by the configured seed identity. */
3587
+ seeded?: Condition<string | null>;
3743
3588
  /** Filter by url */
3744
3589
  url?: Condition<string>;
3745
3590
  /** Filter by a metadata URL alias */
@@ -3969,6 +3814,7 @@ declare module 'alinea/core/ListRow' {
3969
3814
  const id = "_id";
3970
3815
  const index = "_index";
3971
3816
  const type = "_type";
3817
+ const label = "_label";
3972
3818
  }
3973
3819
 
3974
3820
  }
@@ -4329,6 +4175,7 @@ declare module 'alinea/core/Reference' {
4329
4175
  export interface Reference {
4330
4176
  _id: string;
4331
4177
  _type: string;
4178
+ _label?: string;
4332
4179
  }
4333
4180
  export namespace Reference {
4334
4181
  const id = "_id";
@@ -4592,6 +4439,8 @@ declare module 'alinea/core/Scope' {
4592
4439
  keyOf(entity: Entity): string;
4593
4440
  locationOf(entity: Entity): string[] | undefined;
4594
4441
  nameOf(entity: Entity): string | undefined;
4442
+ /** Configured spellings of a locale, matched case-insensitively. */
4443
+ locales(locale: string): Array<string>;
4595
4444
  stringify(input: any): string;
4596
4445
  parse<Result>(input: string): Result;
4597
4446
  }
@@ -4719,11 +4568,23 @@ declare module 'alinea/core/source/FSSource' {
4719
4568
  import type { ChangesBatch } from 'alinea/core/source/Change';
4720
4569
  import type { GetBlobsOptions, Source } from 'alinea/core/source/Source';
4721
4570
  import { ReadonlyTree, WriteableTree } from 'alinea/core/source/Tree';
4571
+ /** The filesystem metadata used to detect that a file did not change. */
4572
+ export interface FileStat {
4573
+ mtimeMs: number;
4574
+ size: number;
4575
+ }
4722
4576
  export class FSSource implements Source {
4723
4577
  #private;
4724
4578
  constructor(cwd: string);
4579
+ /**
4580
+ * Restore a previously persisted tree and the file stats it was built from,
4581
+ * so unchanged files are not read again.
4582
+ */
4583
+ hydrate(tree: ReadonlyTree, stats: ReadonlyMap<string, FileStat>): void;
4584
+ /** The file stats of every file in the current tree. */
4585
+ fileStats(): ReadonlyMap<string, FileStat>;
4725
4586
  getTree(): Promise<ReadonlyTree>;
4726
- getFile(current: ReadonlyTree, builder: WriteableTree, file: string): Promise<readonly [string, Uint8Array<ArrayBufferLike>] | undefined>;
4587
+ getFile(current: ReadonlyTree, builder: WriteableTree, filePath: string): Promise<readonly [string, Uint8Array<ArrayBufferLike>] | undefined>;
4727
4588
  getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
4728
4589
  getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
4729
4590
  readBlob(sha: string, file: string, signal?: AbortSignal): Promise<[sha: string, blob: Uint8Array]>;
@@ -4732,7 +4593,7 @@ declare module 'alinea/core/source/FSSource' {
4732
4593
  export class CachedFSSource extends FSSource {
4733
4594
  #private;
4734
4595
  constructor(cwd: string);
4735
- refresh: () => Promise<ReadonlyTree>;
4596
+ refresh(): Promise<ReadonlyTree>;
4736
4597
  getTree(): Promise<ReadonlyTree>;
4737
4598
  applyChanges(batch: ChangesBatch): Promise<void>;
4738
4599
  getFile(current: ReadonlyTree, builder: WriteableTree, file: string): Promise<readonly [string, Uint8Array<ArrayBufferLike>] | undefined>;
@@ -4790,6 +4651,10 @@ declare module 'alinea/core/source/GitUtils' {
4790
4651
  * Serializes a TreeData object into a Git tree object as a Uint8Array.
4791
4652
  */
4792
4653
  export function serializeTreeEntries(entries: Array<Entry>): Uint8Array;
4654
+ /**
4655
+ * Compares two TreeEntry objects for sorting.
4656
+ */
4657
+ export function compareTreeEntries(a: Entry, b: Entry): number;
4793
4658
  /**
4794
4659
  * Parses a Git tree object from a Uint8Array into a TreeEntry object.
4795
4660
  */
@@ -4812,7 +4677,7 @@ declare module 'alinea/core/source/GitUtils' {
4812
4677
  declare module 'alinea/core/source/IndexedDBSource' {
4813
4678
 
4814
4679
  import type { ChangesBatch } from 'alinea/core/source/Change';
4815
- import type { GetBlobsOptions, Source } from 'alinea/core/source/Source';
4680
+ import type { GetBlobsOptions, RemoteSource, Source } from 'alinea/core/source/Source';
4816
4681
  import { ReadonlyTree } from 'alinea/core/source/Tree';
4817
4682
  export class IndexedDBSource implements Source {
4818
4683
  #private;
@@ -4821,6 +4686,7 @@ declare module 'alinea/core/source/IndexedDBSource' {
4821
4686
  getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
4822
4687
  getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
4823
4688
  applyChanges(batch: ChangesBatch): Promise<void>;
4689
+ applyChangesFrom(remote: RemoteSource, batch: ChangesBatch, tree: ReadonlyTree): Promise<void>;
4824
4690
  }
4825
4691
 
4826
4692
  }
@@ -4845,8 +4711,8 @@ declare module 'alinea/core/source/MemorySource' {
4845
4711
  declare module 'alinea/core/source/OverlaySource' {
4846
4712
 
4847
4713
  import type { ChangesBatch } from 'alinea/core/source/Change';
4848
- import type { GetBlobsOptions, Source } from 'alinea/core/source/Source';
4849
- import type { ReadonlyTree } from 'alinea/core/source/Tree';
4714
+ import type { GetBlobsOptions, RemoteSource, Source } from 'alinea/core/source/Source';
4715
+ import { type ReadonlyTree } from 'alinea/core/source/Tree';
4850
4716
  export class OverlaySource implements Source {
4851
4717
  #private;
4852
4718
  constructor(source: Source, tree: ReadonlyTree);
@@ -4855,6 +4721,9 @@ declare module 'alinea/core/source/OverlaySource' {
4855
4721
  getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
4856
4722
  getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
4857
4723
  applyChanges(batch: ChangesBatch): Promise<void>;
4724
+ applyChangesFrom(remote: RemoteSource, batch: ChangesBatch, tree: ReadonlyTree): Promise<void>;
4725
+ /** Apply a batch while reusing an already received or compiled target tree. */
4726
+ applyChangesTo(batch: ChangesBatch, tree?: ReadonlyTree): Promise<void>;
4858
4727
  }
4859
4728
 
4860
4729
  }
@@ -4884,7 +4753,10 @@ declare module 'alinea/core/source/Source' {
4884
4753
  export interface Source extends RemoteSource {
4885
4754
  getTree(): Promise<ReadonlyTree>;
4886
4755
  applyChanges(batch: ChangesBatch): Promise<void>;
4756
+ /** Consume remote blobs incrementally instead of materializing one bundle. */
4757
+ applyChangesFrom?(remote: RemoteSource, batch: ChangesBatch, tree: ReadonlyTree): Promise<void>;
4887
4758
  }
4759
+ export function applyChangesFrom(source: Source, remote: RemoteSource, batch: ChangesBatch, tree: ReadonlyTree): Promise<void>;
4888
4760
  export function bundleContents(source: RemoteSource, batch: ChangesBatch): Promise<ChangesBatch>;
4889
4761
  export function diff(source: Source, remote: RemoteSource): Promise<ChangesBatch>;
4890
4762
  export function syncWith(source: Source, remote: RemoteSource): Promise<ChangesBatch>;
@@ -4951,7 +4823,6 @@ declare module 'alinea/core/source/Tree' {
4951
4823
  readonly sha: string;
4952
4824
  readonly mode: string;
4953
4825
  constructor({ sha, mode }: BaseEntry);
4954
- clone(): Leaf;
4955
4826
  toJSON(): BaseEntry;
4956
4827
  }
4957
4828
  class TreeBase<Node extends TreeBase<Node>> {
@@ -4975,10 +4846,14 @@ declare module 'alinea/core/source/Tree' {
4975
4846
  readonly sha: string;
4976
4847
  static readonly EMPTY: ReadonlyTree;
4977
4848
  constructor({ sha, entries }: Tree);
4849
+ /** A tree over built nodes, which it shares instead of copying. */
4850
+ static fromNodes(nodes: Map<string, ReadonlyTree | Leaf>, sha?: string): Promise<ReadonlyTree>;
4978
4851
  get isEmpty(): boolean;
4979
4852
  get entries(): Array<Entry>;
4980
- get shas(): ReadonlySet<string>;
4853
+ /** A path holding the blob, if this tree has it. */
4854
+ pathOf(sha: string): string | undefined;
4981
4855
  hasSha(sha: string): boolean;
4856
+ /** A writable tree sharing these nodes until they change. */
4982
4857
  clone(): WriteableTree;
4983
4858
  toJSON(): {
4984
4859
  sha: string;
@@ -4991,18 +4866,18 @@ declare module 'alinea/core/source/Tree' {
4991
4866
  };
4992
4867
  withChanges(batch: ChangesBatch): Promise<ReadonlyTree>;
4993
4868
  static fromFlat(tree: FlatTree): ReadonlyTree;
4994
- diff(that: TreeBase<any>): ChangesBatch;
4869
+ diff(that: ReadonlyTree | WriteableTree): ChangesBatch;
4995
4870
  }
4996
- export class WriteableTree extends TreeBase<WriteableTree> {
4871
+ /** A mutable tree, which copies shared readonly subtrees once they change. */
4872
+ export class WriteableTree extends TreeBase<WriteableTree | ReadonlyTree> {
4997
4873
  #private;
4998
4874
  constructor({ sha, entries }?: Tree);
4999
- add(path: string, input: {
5000
- clone(): WriteableTree | Leaf;
5001
- } | string): void;
4875
+ add(path: string, input: WriteableTree | ReadonlyTree | Leaf | string): void;
5002
4876
  remove(path: string): boolean;
5003
4877
  rename(from: string, to: string): void;
5004
4878
  applyChanges(batch: ChangesBatch): void;
5005
4879
  getSha(): Promise<string>;
4880
+ /** Compile, reusing the nodes of a previous tree wherever they are equal. */
5006
4881
  compile(previous?: ReadonlyTree): Promise<ReadonlyTree>;
5007
4882
  clone(): WriteableTree;
5008
4883
  }
@@ -5159,7 +5034,7 @@ declare module 'alinea/core/Type' {
5159
5034
  import type { Config } from 'alinea/core/Config';
5160
5035
  import type { EntryStatus } from 'alinea/core/Entry';
5161
5036
  import type { Expr } from 'alinea/core/Expr';
5162
- import { Field, type EntryAnchorTarget, type FieldAnchorContext, type FieldBeforeSaveContext } from 'alinea/core/Field';
5037
+ import { Field, type EntryAnchorTarget, type FieldAnchorContext, type FieldLocalizeContext, type FieldBeforeSaveContext } from 'alinea/core/Field';
5163
5038
  import { type HasType } from 'alinea/core/Internal';
5164
5039
  import type { Label } from 'alinea/core/Label';
5165
5040
  import type { OrderBy } from 'alinea/core/OrderBy';
@@ -5205,6 +5080,7 @@ declare module 'alinea/core/Type' {
5205
5080
  function initialValue(type: Type): Record<string, unknown>;
5206
5081
  function withInitialValue(type: Type, value: Record<string, unknown>): Record<string, unknown>;
5207
5082
  function normalizeAnchors(type: Type, value: Record<string, unknown>, context?: FieldAnchorContext): Record<string, unknown>;
5083
+ function localizeLinks(type: Type, value: Record<string, unknown>, context: FieldLocalizeContext): Record<string, unknown>;
5208
5084
  function beforeSave(type: Type, value: Record<string, unknown>, context: Omit<FieldBeforeSaveContext<unknown>, 'value'>): Record<string, unknown>;
5209
5085
  function applyLinks(type: Type, value: Record<string, unknown>, loader: import('./db/LinkResolver.js').LinkResolver): Promise<void>;
5210
5086
  function preview(type: Type): Preview | undefined;
@@ -5306,6 +5182,12 @@ declare module 'alinea/core/util/ArrayBuffers' {
5306
5182
 
5307
5183
  }
5308
5184
 
5185
+ declare module 'alinea/core/util/Arrays' {
5186
+
5187
+ export function chunks<T>(items: ReadonlyArray<T>, size: number): Generator<Array<T>>;
5188
+
5189
+ }
5190
+
5309
5191
  declare module 'alinea/core/util/Assert' {
5310
5192
 
5311
5193
  export function assert(value: unknown, message?: string): asserts value;
@@ -5324,6 +5206,13 @@ declare module 'alinea/core/util/Async' {
5324
5206
  /** Map concurrently while yielding results as they complete. */
5325
5207
  export function mapConcurrent<T, TResult>(iterable: Iterable<T>, mapper: (item: T, signal?: AbortSignal) => Promise<TResult>, options: MapConcurrentOptions): AsyncGenerator<TResult>;
5326
5208
  export function genEffect<T, TReturn>(gen: AsyncIterable<T, TReturn>, effect: (result: T) => void): AsyncIterable<T>;
5209
+ /** Run tasks one after another; a failed task does not block the next one. */
5210
+ export class TaskQueue {
5211
+ #private;
5212
+ run<T>(task: () => Promise<T>): Promise<T>;
5213
+ /** Resolve once every task queued so far has settled. */
5214
+ drain(): Promise<void>;
5215
+ }
5327
5216
 
5328
5217
  }
5329
5218
 
@@ -5483,10 +5372,29 @@ declare module 'alinea/core/util/Encoding' {
5483
5372
 
5484
5373
  declare module 'alinea/core/util/EntryFilenames' {
5485
5374
 
5486
- import type { Config } from 'alinea/core/Config';
5375
+ import { Config } from 'alinea/core/Config';
5487
5376
  import { type Entry, type EntryStatus } from 'alinea/core/Entry';
5488
5377
  import type { EntryUrlInput, Type } from 'alinea/core/Type';
5489
5378
  export function entryInfo(fileName: string): [name: string, status: EntryStatus];
5379
+ /** The workspace/root/locale layout encoded in a source file path. */
5380
+ export interface EntryFileLocation {
5381
+ workspace: string;
5382
+ root: string;
5383
+ locale: string | null;
5384
+ path: string;
5385
+ versionStatus: EntryStatus;
5386
+ parentDir: string;
5387
+ childrenDir: string;
5388
+ /** Segments taken up by the workspace, root and locale. */
5389
+ levelOffset: number;
5390
+ level: number;
5391
+ parentPaths: Array<string>;
5392
+ }
5393
+ /**
5394
+ * Read back the layout `Config.filePath` and `entryChildrenDir` write:
5395
+ * `[workspace/]root/[locale/]...parents/path[.status].json`.
5396
+ */
5397
+ export function parseEntryFilePath(config: Config, filePath: string): EntryFileLocation;
5490
5398
  export function entryChildrenDir(config: Config, entry: {
5491
5399
  workspace: string;
5492
5400
  root: string;
@@ -5494,6 +5402,8 @@ declare module 'alinea/core/util/EntryFilenames' {
5494
5402
  path: string;
5495
5403
  status: EntryStatus;
5496
5404
  }, parentPaths: Array<string>): string;
5405
+ /** The `<childrenDir>[.status].json` file holding a single entry version. */
5406
+ export function entryVersionFile(childrenDir: string, status: EntryStatus): string;
5497
5407
  export function entryFilepath(config: Config, entry: {
5498
5408
  workspace: string;
5499
5409
  root: string;
@@ -5562,6 +5472,15 @@ declare module 'alinea/core/util/Identifiers' {
5562
5472
 
5563
5473
  }
5564
5474
 
5475
+ declare module 'alinea/core/util/IndexedDB' {
5476
+
5477
+ /** Resolve once an IndexedDB transaction has committed. */
5478
+ export function transactionComplete(tx: IDBTransaction): Promise<void>;
5479
+ /** Resolve with the result of an IndexedDB request. */
5480
+ export function requestResult<T>(request: IDBRequest<T>): Promise<T>;
5481
+
5482
+ }
5483
+
5565
5484
  declare module 'alinea/core/util/JWT' {
5566
5485
 
5567
5486
  const algorithms: {
@@ -7000,10 +6919,6 @@ declare module 'alinea/dashboard/atoms/config' {
7000
6919
  export const workspaceAtom: (workspaceKey: string) => import("jotai").Atom<import("alinea/core/Workspace").WorkspaceInternal>;
7001
6920
  export const viewAtoms: (key: string) => import("jotai").Atom<ComponentType | undefined>;
7002
6921
  export const typeAtoms: (typeName: string) => import("jotai").Atom<{
7003
- type: import("alinea/types").Type;
7004
- customView: ((props: {
7005
- type: import("alinea/types").Type;
7006
- }) => import("react").ReactNode) | ComponentType | undefined;
7007
6922
  fields: import("alinea/core/Type").FieldsDefinition;
7008
6923
  contains?: Array<string | import("alinea/types").Type>;
7009
6924
  orderChildrenBy?: import("alinea/core/OrderBy").OrderBy | Array<import("alinea/core/OrderBy").OrderBy>;
@@ -7021,6 +6936,10 @@ declare module 'alinea/dashboard/atoms/config' {
7021
6936
  label: string;
7022
6937
  allFields: Record<string, import("alinea/core").Field>;
7023
6938
  sections: Array<import("alinea/core/Section").Section>;
6939
+ type: import("alinea/types").Type;
6940
+ customView: ((props: {
6941
+ type: import("alinea/types").Type;
6942
+ }) => import("react").ReactNode) | ComponentType | undefined;
7024
6943
  }>;
7025
6944
 
7026
6945
  }
@@ -7183,7 +7102,7 @@ declare module 'alinea/dashboard/atoms/editor' {
7183
7102
 
7184
7103
  declare module 'alinea/dashboard/atoms/entry' {
7185
7104
 
7186
- import type { EntryReference, EntryReferenceScan } from 'alinea/core/db/EntryReference';
7105
+ import type { EntryReference } from 'alinea/core/db/EntryReference';
7187
7106
  import { Entry, EntryStatus } from 'alinea/core/Entry';
7188
7107
  import type { Order } from 'alinea/core/Graph';
7189
7108
  import { type EntryDefaultView } from 'alinea/core/Type';
@@ -7209,7 +7128,6 @@ declare module 'alinea/dashboard/atoms/entry' {
7209
7128
  export interface EntryReferences {
7210
7129
  references: Array<EntryReferenceWithSource>;
7211
7130
  total: number;
7212
- scan: EntryReferenceScan;
7213
7131
  }
7214
7132
  export interface EntryReferenceWithSource {
7215
7133
  reference: EntryReference;
@@ -7262,10 +7180,8 @@ declare module 'alinea/dashboard/atoms/entry' {
7262
7180
  init: null;
7263
7181
  };
7264
7182
  previewEntryReady: Atom<Promise<{
7265
- title: string;
7266
- path: string;
7267
- data: Record<string, unknown>;
7268
7183
  id: string;
7184
+ versionStatus?: EntryStatus;
7269
7185
  status: EntryStatus;
7270
7186
  type: string;
7271
7187
  seeded: string | null;
@@ -7285,12 +7201,13 @@ declare module 'alinea/dashboard/atoms/entry' {
7285
7201
  fileHash: string;
7286
7202
  url: string;
7287
7203
  searchableText: string;
7288
- }>>;
7289
- previewEntry: Atom<{
7290
7204
  title: string;
7291
7205
  path: string;
7292
7206
  data: Record<string, unknown>;
7207
+ }>>;
7208
+ previewEntry: Atom<{
7293
7209
  id: string;
7210
+ versionStatus?: EntryStatus;
7294
7211
  status: EntryStatus;
7295
7212
  type: string;
7296
7213
  seeded: string | null;
@@ -7310,6 +7227,9 @@ declare module 'alinea/dashboard/atoms/entry' {
7310
7227
  fileHash: string;
7311
7228
  url: string;
7312
7229
  searchableText: string;
7230
+ title: string;
7231
+ path: string;
7232
+ data: Record<string, unknown>;
7313
7233
  } | undefined>;
7314
7234
  previewUrlReady: Atom<Promise<string | undefined>>;
7315
7235
  previewUrlState: Atom<readonly [false, string | undefined] | readonly [true, string | undefined]>;
@@ -7370,7 +7290,6 @@ declare module 'alinea/dashboard/atoms/entry' {
7370
7290
  };
7371
7291
  }[];
7372
7292
  total: number;
7373
- scan: EntryReferenceScan;
7374
7293
  }>>;
7375
7294
  incomingReferences: Atom<{
7376
7295
  references: {
@@ -7388,7 +7307,6 @@ declare module 'alinea/dashboard/atoms/entry' {
7388
7307
  };
7389
7308
  }[];
7390
7309
  total: number;
7391
- scan: EntryReferenceScan;
7392
7310
  } | undefined>;
7393
7311
  type: Atom<string>;
7394
7312
  parentId: Atom<string | null>;
@@ -7469,6 +7387,8 @@ declare module 'alinea/dashboard/atoms/explorer' {
7469
7387
  import type { DragItem, DragTypes, DropOperation, DropTarget } from '@react-types/shared';
7470
7388
  import type { DroppableCollectionOnItemDropEvent, Key } from 'react-aria-components';
7471
7389
  export const dashboardEntryOverviewColumnCount = 5;
7390
+ /** The best ranked matches a search loads into the explorer. */
7391
+ export const searchResultLimit = 100;
7472
7392
  export type ExplorerView = 'card' | 'row';
7473
7393
  export type ExplorerSortBy = 'title' | 'path' | 'size' | 'id' | 'index';
7474
7394
  export type ExplorerSortDirections = 'asc' | 'desc';
@@ -8106,14 +8026,14 @@ declare module 'alinea/dashboard/boot/DashboardWorker' {
8106
8026
  import type { Config } from 'alinea/core/Config';
8107
8027
  import type { LocalConnection } from 'alinea/core/Connection';
8108
8028
  import type { EntryReferenceQuery, EntryReferenceResult } from 'alinea/core/db/EntryReference';
8109
- import { LocalDB } from 'alinea/core/db/LocalDB';
8110
8029
  import type { Mutation } from 'alinea/core/db/Mutation';
8111
8030
  import type { Source } from 'alinea/core/source/Source';
8031
+ import { EntryStore } from 'alinea/database/EntryStore';
8112
8032
  import { type Activity } from 'alinea/dashboard/boot/ActivityEvent';
8113
8033
  export class DashboardWorker extends EventTarget {
8114
8034
  #private;
8115
- constructor(source: Source);
8116
- get db(): LocalDB | Promise<LocalDB>;
8035
+ constructor(source?: Source);
8036
+ get db(): EntryStore | Promise<EntryStore>;
8117
8037
  sync(): Promise<string>;
8118
8038
  sha(): Promise<string>;
8119
8039
  queue(id: string, mutations: Array<Mutation>): Promise<string>;
@@ -8137,7 +8057,7 @@ declare module 'alinea/dashboard/boot/LoadWorker' {
8137
8057
  declare module 'alinea/dashboard/boot/WorkerDB' {
8138
8058
 
8139
8059
  import type { Config } from 'alinea/core/Config';
8140
- import type { Connection, UploadMetadata, UploadResponse } from 'alinea/core/Connection';
8060
+ import type { LocalConnection, UploadMetadata, UploadResponse } from 'alinea/core/Connection';
8141
8061
  import type { AnyQueryResult, GraphQuery } from 'alinea/core/Graph';
8142
8062
  import type { EntryReferenceQuery, EntryReferenceResult } from 'alinea/core/db/EntryReference';
8143
8063
  import type { Mutation } from 'alinea/core/db/Mutation';
@@ -8148,7 +8068,7 @@ declare module 'alinea/dashboard/boot/WorkerDB' {
8148
8068
  #private;
8149
8069
  config: Config;
8150
8070
  events: EventTarget;
8151
- constructor(config: Config, worker: DashboardWorker, client: Connection, events: EventTarget);
8071
+ constructor(config: Config, worker: DashboardWorker, client: LocalConnection, events: EventTarget);
8152
8072
  mutate(mutations: Array<Mutation>): Promise<{
8153
8073
  id: string;
8154
8074
  sha: string;
@@ -8596,6 +8516,8 @@ declare module 'alinea/dashboard/icons' {
8596
8516
  export function IcOutlineTableRows(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
8597
8517
  export function IcOutlineViewList(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
8598
8518
  export function IcRoundDescription(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
8519
+ export function IcRoundBolt(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
8520
+ export function IcRoundInfo(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
8599
8521
  export function IcTwotoneDescription(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
8600
8522
  export function IcTwotoneFolder(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
8601
8523
  export function IcRoundInsertDriveFile(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
@@ -8800,6 +8722,7 @@ declare module 'alinea/dashboard/ViewKeys' {
8800
8722
  MetadataTimestampInput: string;
8801
8723
  MetadataUserInput: string;
8802
8724
  MetadataInput: string;
8725
+ MetadataDetailsView: string;
8803
8726
  NumberInput: string;
8804
8727
  ObjectInput: string;
8805
8728
  PathInput: string;
@@ -8814,6 +8737,1076 @@ declare module 'alinea/dashboard/ViewKeys' {
8814
8737
 
8815
8738
  }
8816
8739
 
8740
+ declare module 'alinea/database/BrowserEntryStore' {
8741
+
8742
+ import type { Config } from 'alinea/core/Config';
8743
+ import type { Mutation } from 'alinea/core/db/Mutation';
8744
+ import type { CommitRequest } from 'alinea/core/db/CommitRequest';
8745
+ import type { SyncOptions } from 'alinea/core/db/LocalStore';
8746
+ import type { RemoteSource } from 'alinea/core/source/Source';
8747
+ import { EntryStore } from 'alinea/database/EntryStore';
8748
+ export interface BrowserEntryStoreOptions {
8749
+ name: string;
8750
+ revision: string;
8751
+ /**
8752
+ * The store this one replaces, such as one of a previous dashboard build:
8753
+ * its content carries over from memory instead of loading it again, and it
8754
+ * stops storing without waiting for its work in flight.
8755
+ */
8756
+ replaces?: BrowserEntryStore;
8757
+ /** The IndexedDB implementation, the global one by default. */
8758
+ indexedDB?: IDBFactory;
8759
+ IDBKeyRange?: typeof IDBKeyRange;
8760
+ }
8761
+ /**
8762
+ * WASM entry store kept in IndexedDB: every commit stores the pages it
8763
+ * changed.
8764
+ */
8765
+ export class BrowserEntryStore extends EntryStore {
8766
+ #private;
8767
+ static open(config: Config, options: BrowserEntryStoreOptions, retried?: boolean): Promise<BrowserEntryStore>;
8768
+ private constructor();
8769
+ sync(): Promise<string>;
8770
+ syncWith(remote: RemoteSource, options?: SyncOptions): Promise<string>;
8771
+ mutate(mutations: Array<Mutation>): Promise<{
8772
+ sha: string;
8773
+ }>;
8774
+ write(request: CommitRequest): Promise<{
8775
+ sha: string;
8776
+ }>;
8777
+ close(): Promise<void>;
8778
+ /**
8779
+ * Close a store that a replacement took over from: its work in flight
8780
+ * changes only its memory copy, which is not stored.
8781
+ */
8782
+ abandon(): Promise<void>;
8783
+ }
8784
+
8785
+ }
8786
+
8787
+ declare module 'alinea/database/DatabaseSource' {
8788
+
8789
+ import type { ChangesBatch } from 'alinea/core/source/Change';
8790
+ import type { GetBlobsOptions, Source } from 'alinea/core/source/Source';
8791
+ import type { ReadonlyTree } from 'alinea/core/source/Tree';
8792
+ import type { EntryDatabase } from 'alinea/database/EntryDatabase';
8793
+ /** Read-only Source view backed by exact payload text in an entry database. */
8794
+ export class DatabaseSource implements Source {
8795
+ #private;
8796
+ constructor(database: EntryDatabase);
8797
+ getTree(): Promise<ReadonlyTree>;
8798
+ getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
8799
+ getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array<ArrayBufferLike>], any, any>;
8800
+ applyChanges(_batch: ChangesBatch): Promise<void>;
8801
+ }
8802
+
8803
+ }
8804
+
8805
+ declare module 'alinea/database/DatabaseTables' {
8806
+
8807
+ import type { Tree } from 'alinea/core/source/Tree';
8808
+ export const DatabaseStateColumns: {
8809
+ id: import("rado").Column<number, [false, false]>;
8810
+ revision: import("rado").Column<string, [false, boolean]>;
8811
+ /** Merkle tree matching the indexed source revision. */
8812
+ tree: import("rado").JsonColumn<Tree, import("rado").Nullability>;
8813
+ };
8814
+ export const DatabaseStateTable: import("rado").Table<{
8815
+ id: import("rado").Column<number, [false, false]>;
8816
+ revision: import("rado").Column<string, [false, boolean]>;
8817
+ /** Merkle tree matching the indexed source revision. */
8818
+ tree: import("rado").JsonColumn<Tree, import("rado").Nullability>;
8819
+ }, "alinea_database_state">;
8820
+ export const DatabaseMetadataColumns: {
8821
+ id: import("rado").Column<number, [false, false]>;
8822
+ /** The database version whose layout the tables have. */
8823
+ version: import("rado").Column<number, [false, boolean]>;
8824
+ configFingerprint: import("rado").Column<string, [false, boolean]>;
8825
+ };
8826
+ export const DatabaseMetadataTable: import("rado").Table<{
8827
+ id: import("rado").Column<number, [false, false]>;
8828
+ /** The database version whose layout the tables have. */
8829
+ version: import("rado").Column<number, [false, boolean]>;
8830
+ configFingerprint: import("rado").Column<string, [false, boolean]>;
8831
+ }, "alinea_database_metadata">;
8832
+ /** Filesystem metadata of the source files indexed by this database. */
8833
+ export const SourceFileColumns: {
8834
+ path: import("rado").Column<string, [false, false]>;
8835
+ /** Last modification time in milliseconds. */
8836
+ mtime: import("rado").Column<number, [false, boolean]>;
8837
+ size: import("rado").Column<number, [false, boolean]>;
8838
+ };
8839
+ export const SourceFileTable: import("rado").Table<{
8840
+ path: import("rado").Column<string, [false, false]>;
8841
+ /** Last modification time in milliseconds. */
8842
+ mtime: import("rado").Column<number, [false, boolean]>;
8843
+ size: import("rado").Column<number, [false, boolean]>;
8844
+ }, "alinea_source_file">;
8845
+
8846
+ }
8847
+
8848
+ declare module 'alinea/database/driver/DatabaseHandle' {
8849
+
8850
+ import type { Database } from 'rado';
8851
+ /**
8852
+ * How a connection reads its data: a native file, a native in-memory overlay
8853
+ * of a file, or a copy in WASM memory.
8854
+ */
8855
+ export type DatabaseDriver = 'native' | 'overlay' | 'wasm';
8856
+ /** A SQLite connection, which may copy itself without copying its data. */
8857
+ export interface DatabaseHandle {
8858
+ database: Database;
8859
+ driver?: DatabaseDriver;
8860
+ /**
8861
+ * An independent connection to the last committed state. The copy shares
8862
+ * every page with this one until either side writes it. Connections that
8863
+ * write a file in place cannot fork.
8864
+ */
8865
+ fork?(): Promise<DatabaseHandle>;
8866
+ }
8867
+
8868
+ }
8869
+
8870
+ declare module 'alinea/database/driver/OverlayExtension.browser' {
8871
+
8872
+ /** Browser bundles reach the database driver without ever running it. */
8873
+ export function overlayExtension(): string;
8874
+
8875
+ }
8876
+
8877
+ declare module 'alinea/database/driver/OverlayExtension' {
8878
+
8879
+ export { overlayExtension } from '@alinea/sqlite-wasm/native';
8880
+
8881
+ }
8882
+
8883
+ declare module 'alinea/database/driver/RuntimeDatabase' {
8884
+
8885
+ import type { DatabaseOptions } from 'rado';
8886
+ import type { DatabaseHandle } from 'alinea/database/driver/DatabaseHandle';
8887
+ export interface RuntimeDatabaseOptions extends DatabaseOptions {
8888
+ path: string;
8889
+ /** Keep every write in memory: the file is never written. */
8890
+ overlay?: boolean;
8891
+ }
8892
+ /**
8893
+ * Open a SQLite file with the native Node/Bun driver. Overlays of the file
8894
+ * keep their writes in memory and fork cheaply, through the native overlay
8895
+ * VFS or else a WASM copy; a file opened for writing cannot fork.
8896
+ */
8897
+ export function runtimeDatabase(options: RuntimeDatabaseOptions): Promise<DatabaseHandle>;
8898
+
8899
+ }
8900
+
8901
+ declare module 'alinea/database/driver/WasmDatabase' {
8902
+
8903
+ import type { Storage } from '@alinea/sqlite-wasm/Database.js';
8904
+ import type { DatabaseOptions } from 'rado';
8905
+ import { connect } from 'rado/driver/sql.js';
8906
+ import type { DatabaseHandle } from 'alinea/database/driver/DatabaseHandle';
8907
+ export interface WasmDatabaseHandle extends DatabaseHandle {
8908
+ database: ReturnType<typeof connect>;
8909
+ fork(): Promise<WasmDatabaseHandle>;
8910
+ export(): Uint8Array;
8911
+ /** Resolves once every commit so far is stored; at once in memory. */
8912
+ flush(): Promise<void>;
8913
+ /**
8914
+ * Store this database from now on, replacing what the storage held, once
8915
+ * a database detached from it wrote its last commits.
8916
+ */
8917
+ attach(storage: Storage): Promise<void>;
8918
+ /**
8919
+ * Stop storing commits once the ones so far are written; later commits
8920
+ * change only the memory copy.
8921
+ */
8922
+ detach(): void;
8923
+ }
8924
+ /**
8925
+ * Open a WASM connection from the database kept in storage, or an empty one,
8926
+ * that stores every commit there.
8927
+ */
8928
+ export function syncWasmDatabase(storage: Storage, options?: DatabaseOptions): Promise<WasmDatabaseHandle>;
8929
+ /** Open an in-memory WASM connection, optionally from a complete SQLite file. */
8930
+ export function openWasmDatabase(data?: Uint8Array, options?: DatabaseOptions): Promise<WasmDatabaseHandle>;
8931
+ export function wasmDatabase(data?: Uint8Array): Promise<import("rado").SyncDatabase<"sqlite">>;
8932
+
8933
+ }
8934
+
8935
+ declare module 'alinea/database/entry/EntryData' {
8936
+
8937
+ import { type Database, type Sql } from 'rado';
8938
+ import { type EntryIndexTarget } from 'alinea/database/entry/EntryTable';
8939
+ /**
8940
+ * Whether this SQLite stores entry data as JSONB, which reads paths of large
8941
+ * documents without parsing them. Older versions store JSON text.
8942
+ */
8943
+ export function supportsJsonb(db: Database): Promise<boolean>;
8944
+ /** Whether the entry index holds rows stored as JSONB. */
8945
+ export function hasJsonbRows(db: Database): Promise<boolean>;
8946
+ /** Fail clearly when this SQLite cannot read the JSONB rows of a database. */
8947
+ export function assertReadableData(db: Database): Promise<void>;
8948
+ /** The data as JSON text, whether stored as text or JSONB. */
8949
+ export function entryDataText(entry: Pick<EntryIndexTarget, 'data'>): Sql<string>;
8950
+
8951
+ }
8952
+
8953
+ declare module 'alinea/database/entry/EntryTable' {
8954
+
8955
+ import type { Config } from 'alinea/core/Config';
8956
+ import type { Entry, EntryStatus } from 'alinea/core/Entry';
8957
+ import { type Database, type Table } from 'rado';
8958
+ /** One complete authored entry version. Only arrays and authored data are JSON. */
8959
+ export const EntryIndexColumns: {
8960
+ /**
8961
+ * Also the rowid of the version's full-text search row. Declared, so VACUUM
8962
+ * keeps it.
8963
+ */
8964
+ rowid: import("rado").Column<number, [false, false]>;
8965
+ versionId: import("rado").Column<string, [false, boolean]>;
8966
+ id: import("rado").Column<string, [false, boolean]>;
8967
+ locale: import("rado").Column<string, import("rado").Nullability>;
8968
+ versionStatus: import("rado").Column<EntryStatus, [false, boolean]>;
8969
+ status: import("rado").Column<EntryStatus, [false, boolean]>;
8970
+ type: import("rado").Column<string, [false, boolean]>;
8971
+ title: import("rado").Column<string, [false, boolean]>;
8972
+ workspace: import("rado").Column<string, [false, boolean]>;
8973
+ root: import("rado").Column<string, [false, boolean]>;
8974
+ sourceRoot: import("rado").Column<string, import("rado").Nullability>;
8975
+ parentId: import("rado").Column<string, import("rado").Nullability>;
8976
+ parents: import("rado").Column<string[], [false, boolean]>;
8977
+ level: import("rado").Column<number, [false, boolean]>;
8978
+ index: import("rado").Column<string, [false, boolean]>;
8979
+ path: import("rado").Column<string, [false, boolean]>;
8980
+ /** Full source path of this authored version. */
8981
+ filePath: import("rado").Column<string, [false, boolean]>;
8982
+ fileHash: import("rado").Column<string, [false, boolean]>;
8983
+ parentDir: import("rado").Column<string, [false, boolean]>;
8984
+ childrenDir: import("rado").Column<string, [false, boolean]>;
8985
+ url: import("rado").Column<string, [false, boolean]>;
8986
+ active: import("rado").Column<boolean, [false, boolean]>;
8987
+ main: import("rado").Column<boolean, [false, boolean]>;
8988
+ visible: import("rado").Column<boolean, [false, boolean]>;
8989
+ seeded: import("rado").Column<string, import("rado").Nullability>;
8990
+ rowHash: import("rado").Column<string, [false, boolean]>;
8991
+ /** Hash of this entry's child directory in the synced source tree. */
8992
+ childrenSha: import("rado").Column<string, import("rado").Nullability>;
8993
+ /** Exact source blob for seeded rows whose expanded data differs. */
8994
+ payload: import("rado").Column<string, import("rado").Nullability>;
8995
+ /**
8996
+ * Exact source JSON, or expanded JSON for seeded rows. Stored as JSONB where
8997
+ * SQLite supports it; read it as text with `entryDataText`.
8998
+ */
8999
+ data: import("rado").Column<string, [false, boolean]>;
9000
+ };
9001
+ export function entryIndexTable(name: string): Table<{
9002
+ /**
9003
+ * Also the rowid of the version's full-text search row. Declared, so VACUUM
9004
+ * keeps it.
9005
+ */
9006
+ rowid: import("rado").Column<number, [false, false]>;
9007
+ versionId: import("rado").Column<string, [false, boolean]>;
9008
+ id: import("rado").Column<string, [false, boolean]>;
9009
+ locale: import("rado").Column<string, import("rado").Nullability>;
9010
+ versionStatus: import("rado").Column<EntryStatus, [false, boolean]>;
9011
+ status: import("rado").Column<EntryStatus, [false, boolean]>;
9012
+ type: import("rado").Column<string, [false, boolean]>;
9013
+ title: import("rado").Column<string, [false, boolean]>;
9014
+ workspace: import("rado").Column<string, [false, boolean]>;
9015
+ root: import("rado").Column<string, [false, boolean]>;
9016
+ sourceRoot: import("rado").Column<string, import("rado").Nullability>;
9017
+ parentId: import("rado").Column<string, import("rado").Nullability>;
9018
+ parents: import("rado").Column<string[], [false, boolean]>;
9019
+ level: import("rado").Column<number, [false, boolean]>;
9020
+ index: import("rado").Column<string, [false, boolean]>;
9021
+ path: import("rado").Column<string, [false, boolean]>;
9022
+ /** Full source path of this authored version. */
9023
+ filePath: import("rado").Column<string, [false, boolean]>;
9024
+ fileHash: import("rado").Column<string, [false, boolean]>;
9025
+ parentDir: import("rado").Column<string, [false, boolean]>;
9026
+ childrenDir: import("rado").Column<string, [false, boolean]>;
9027
+ url: import("rado").Column<string, [false, boolean]>;
9028
+ active: import("rado").Column<boolean, [false, boolean]>;
9029
+ main: import("rado").Column<boolean, [false, boolean]>;
9030
+ visible: import("rado").Column<boolean, [false, boolean]>;
9031
+ seeded: import("rado").Column<string, import("rado").Nullability>;
9032
+ rowHash: import("rado").Column<string, [false, boolean]>;
9033
+ /** Hash of this entry's child directory in the synced source tree. */
9034
+ childrenSha: import("rado").Column<string, import("rado").Nullability>;
9035
+ /** Exact source blob for seeded rows whose expanded data differs. */
9036
+ payload: import("rado").Column<string, import("rado").Nullability>;
9037
+ /**
9038
+ * Exact source JSON, or expanded JSON for seeded rows. Stored as JSONB where
9039
+ * SQLite supports it; read it as text with `entryDataText`.
9040
+ */
9041
+ data: import("rado").Column<string, [false, boolean]>;
9042
+ }, string>;
9043
+ export type EntryIndexTarget = Table<typeof EntryIndexColumns>;
9044
+ export const EntryIndexTable: Table<{
9045
+ /**
9046
+ * Also the rowid of the version's full-text search row. Declared, so VACUUM
9047
+ * keeps it.
9048
+ */
9049
+ rowid: import("rado").Column<number, [false, false]>;
9050
+ versionId: import("rado").Column<string, [false, boolean]>;
9051
+ id: import("rado").Column<string, [false, boolean]>;
9052
+ locale: import("rado").Column<string, import("rado").Nullability>;
9053
+ versionStatus: import("rado").Column<EntryStatus, [false, boolean]>;
9054
+ status: import("rado").Column<EntryStatus, [false, boolean]>;
9055
+ type: import("rado").Column<string, [false, boolean]>;
9056
+ title: import("rado").Column<string, [false, boolean]>;
9057
+ workspace: import("rado").Column<string, [false, boolean]>;
9058
+ root: import("rado").Column<string, [false, boolean]>;
9059
+ sourceRoot: import("rado").Column<string, import("rado").Nullability>;
9060
+ parentId: import("rado").Column<string, import("rado").Nullability>;
9061
+ parents: import("rado").Column<string[], [false, boolean]>;
9062
+ level: import("rado").Column<number, [false, boolean]>;
9063
+ index: import("rado").Column<string, [false, boolean]>;
9064
+ path: import("rado").Column<string, [false, boolean]>;
9065
+ /** Full source path of this authored version. */
9066
+ filePath: import("rado").Column<string, [false, boolean]>;
9067
+ fileHash: import("rado").Column<string, [false, boolean]>;
9068
+ parentDir: import("rado").Column<string, [false, boolean]>;
9069
+ childrenDir: import("rado").Column<string, [false, boolean]>;
9070
+ url: import("rado").Column<string, [false, boolean]>;
9071
+ active: import("rado").Column<boolean, [false, boolean]>;
9072
+ main: import("rado").Column<boolean, [false, boolean]>;
9073
+ visible: import("rado").Column<boolean, [false, boolean]>;
9074
+ seeded: import("rado").Column<string, import("rado").Nullability>;
9075
+ rowHash: import("rado").Column<string, [false, boolean]>;
9076
+ /** Hash of this entry's child directory in the synced source tree. */
9077
+ childrenSha: import("rado").Column<string, import("rado").Nullability>;
9078
+ /** Exact source blob for seeded rows whose expanded data differs. */
9079
+ payload: import("rado").Column<string, import("rado").Nullability>;
9080
+ /**
9081
+ * Exact source JSON, or expanded JSON for seeded rows. Stored as JSONB where
9082
+ * SQLite supports it; read it as text with `entryDataText`.
9083
+ */
9084
+ data: import("rado").Column<string, [false, boolean]>;
9085
+ }, string>;
9086
+ /** The entry ids each entry version references, under the version's rowid. */
9087
+ export const EntryReferenceTable: Table<{
9088
+ targetId: import("rado").Column<string, [false, boolean]>;
9089
+ source: import("rado").Column<number, [false, boolean]>;
9090
+ }, "alinea_entry_reference">;
9091
+ /** Fields whose queries order by their stored value, through a field index. */
9092
+ export function isOrderedField(field: unknown): boolean;
9093
+ /** Metadata fields whose queries order by their stored value. */
9094
+ export const orderedMetadata: Set<string>;
9095
+ /**
9096
+ * Index the stored value of every ordered field in the config, per type, and
9097
+ * of the ordered metadata. Field names are identifiers, so the dotted metadata
9098
+ * names cannot collide with them.
9099
+ */
9100
+ export function syncFieldIndexes(db: Database, config: Config): Promise<void>;
9101
+ /** An Entry plus the physical-version and local-index fields. */
9102
+ export interface IndexedEntry extends Entry {
9103
+ versionStatus: EntryStatus;
9104
+ /** Exact source text matching fileHash. */
9105
+ payload?: string;
9106
+ /** False for authored versions suppressed by inherited status in normal queries. */
9107
+ visible?: boolean;
9108
+ /** First source-directory segment below the content root (not the URL slug). */
9109
+ sourceRoot?: string | null;
9110
+ /** Hash of this entry's child directory in the synced source tree. */
9111
+ childrenSha?: string | null;
9112
+ }
9113
+ export function entryIndexRow(entry: IndexedEntry): {
9114
+ versionId: string;
9115
+ id: string;
9116
+ locale: string | null;
9117
+ versionStatus: EntryStatus;
9118
+ status: EntryStatus;
9119
+ type: string;
9120
+ title: string;
9121
+ workspace: string;
9122
+ root: string;
9123
+ sourceRoot: string | null;
9124
+ parentId: string | null;
9125
+ parents: string[];
9126
+ level: number;
9127
+ index: string;
9128
+ path: string;
9129
+ filePath: string;
9130
+ fileHash: string;
9131
+ parentDir: string;
9132
+ childrenDir: string;
9133
+ url: string;
9134
+ active: boolean;
9135
+ main: boolean;
9136
+ visible: boolean;
9137
+ seeded: string | null;
9138
+ rowHash: string;
9139
+ childrenSha: string | null;
9140
+ payload: string | null;
9141
+ data: string;
9142
+ };
9143
+ export function storedEntryData(value: unknown, path: string): Record<string, unknown>;
9144
+
9145
+ }
9146
+
9147
+ declare module 'alinea/database/EntryDatabase' {
9148
+
9149
+ import type { Config } from 'alinea/core/Config';
9150
+ import type { CommitRequest } from 'alinea/core/db/CommitRequest';
9151
+ import type { EntryReferenceQuery, EntryReferenceResult } from 'alinea/core/db/EntryReference';
9152
+ import type { SyncOptions } from 'alinea/core/db/LocalStore';
9153
+ import type { Mutation } from 'alinea/core/db/Mutation';
9154
+ import { Graph, type AnyQueryResult, type GraphQuery } from 'alinea/core/Graph';
9155
+ import { Policy } from 'alinea/core/Role';
9156
+ import type { FileStat } from 'alinea/core/source/FSSource';
9157
+ import { type GetBlobsOptions, type RemoteSource, type Source } from 'alinea/core/source/Source';
9158
+ import { ReadonlyTree } from 'alinea/core/source/Tree';
9159
+ import { type Database } from 'rado';
9160
+ import type { DatabaseHandle } from 'alinea/database/driver/DatabaseHandle';
9161
+ export interface EntryDatabaseOptions {
9162
+ includedAtBuild?(filePath: string): boolean | Promise<boolean>;
9163
+ /** Copy the connection for an overlay; without it there are none. */
9164
+ fork?(): Promise<DatabaseHandle>;
9165
+ /**
9166
+ * Whether syncs record the source tree in the state, so the database can be
9167
+ * reopened and synced from it. An overlay keeps its tree in memory.
9168
+ */
9169
+ recordsTree?: boolean;
9170
+ }
9171
+ export interface EntryApplyOptions {
9172
+ source: Source;
9173
+ policy?: Policy;
9174
+ }
9175
+ export type EntryChangeListener = (change: EntrySyncResult) => void;
9176
+ export interface EntrySyncResult {
9177
+ revision: string;
9178
+ /** Includes source changes, deletions, and entries changed by inheritance. */
9179
+ changedEntryIds: ReadonlyArray<string>;
9180
+ }
9181
+ export interface EntryApplyResult extends EntrySyncResult {
9182
+ request: CommitRequest;
9183
+ }
9184
+ /**
9185
+ * A queryable entry index owning its SQLite connection. Mutations are planned
9186
+ * on a working copy inside a write transaction of that connection.
9187
+ */
9188
+ export class EntryDatabase extends Graph implements AsyncDisposable {
9189
+ #private;
9190
+ constructor(config: Config, db: Database, options?: EntryDatabaseOptions);
9191
+ get config(): Config;
9192
+ /** Whether this database can create overlays. */
9193
+ get forkable(): boolean;
9194
+ includedAtBuild(filePath: string): boolean | Promise<boolean>;
9195
+ /** Whether this database was closed, and answers only from a replacement. */
9196
+ get closed(): boolean;
9197
+ /**
9198
+ * Run a task while no other task uses the connection, so no transaction
9199
+ * is open: a fork of the connection then copies committed state.
9200
+ */
9201
+ whileIdle<T>(task: () => Promise<T>): Promise<T>;
9202
+ /**
9203
+ * Fork the connection and synchronize the copy with a source. The overlay
9204
+ * shares every unchanged page with this database and is independent of it:
9205
+ * either can change or close without affecting the other.
9206
+ */
9207
+ overlay(source: RemoteSource): Promise<EntryDatabase>;
9208
+ static createSchema(db: Database, config: Config, revision: string, configFingerprint?: string): Promise<void>;
9209
+ /**
9210
+ * Synchronize a source through this database's single prepared syncer,
9211
+ * without keeping an in-memory copy of its entries.
9212
+ */
9213
+ syncWith(source: RemoteSource, options?: SyncOptions): Promise<EntrySyncResult>;
9214
+ /**
9215
+ * Adopt another config and derive every entry again from the payloads this
9216
+ * database stores, recording the fingerprint so a later open recognizes the
9217
+ * database as written by that config. The rows of the previous config are
9218
+ * replaced within one transaction, so reads keep answering from them until
9219
+ * the replacement is committed.
9220
+ */
9221
+ reindex(config: Config, configFingerprint?: string): Promise<EntrySyncResult>;
9222
+ /** Atomically plan and apply mutations through a private working copy. */
9223
+ apply(mutations: ReadonlyArray<Mutation>, options: EntryApplyOptions): Promise<EntryApplyResult>;
9224
+ /** Plan mutations like apply, then roll them back. */
9225
+ plan(mutations: ReadonlyArray<Mutation>, options: EntryApplyOptions): Promise<CommitRequest>;
9226
+ /**
9227
+ * Resolve a query with a source synced into this database, within a write
9228
+ * transaction that is rolled back afterwards.
9229
+ */
9230
+ resolveWith<const Query extends GraphQuery>(source: RemoteSource, query: Query): Promise<AnyQueryResult<Query>>;
9231
+ close(): Promise<void>;
9232
+ [Symbol.asyncDispose](): Promise<void>;
9233
+ getRevision(): Promise<string>;
9234
+ getTree(): Promise<ReadonlyTree>;
9235
+ getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
9236
+ resolve<const Query extends GraphQuery>(query: Query): Promise<AnyQueryResult<Query>>;
9237
+ /** Scan references in bounded pages without retaining an entry index. */
9238
+ referencesTo(query: EntryReferenceQuery): Promise<EntryReferenceResult>;
9239
+ onChange(listener: EntryChangeListener): () => void;
9240
+ /** File stats recorded by the last filesystem sync of this database. */
9241
+ getSourceFileStats(): Promise<Map<string, FileStat>>;
9242
+ /** Replace the recorded file stats after syncing from a filesystem source. */
9243
+ setSourceFileStats(stats: ReadonlyMap<string, FileStat>): Promise<void>;
9244
+ compact(): Promise<void>;
9245
+ }
9246
+
9247
+ }
9248
+
9249
+ declare module 'alinea/database/EntryStore' {
9250
+
9251
+ import type { Config } from 'alinea/core/Config';
9252
+ import type { GetBlobsOptions, RemoteSource, Source } from 'alinea/core/source/Source';
9253
+ import { ReadonlyTree } from 'alinea/core/source/Tree';
9254
+ import type { AnyQueryResult, GraphQuery } from 'alinea/core/Graph';
9255
+ import type { Mutation } from 'alinea/core/db/Mutation';
9256
+ import type { Policy } from 'alinea/core/Role';
9257
+ import type { EntryReferenceQuery, EntryReferenceResult } from 'alinea/core/db/EntryReference';
9258
+ import { type CommitRequest } from 'alinea/core/db/CommitRequest';
9259
+ import type { LocalStore, SyncOptions } from 'alinea/core/db/LocalStore';
9260
+ import { WriteableGraph } from 'alinea/core/db/WriteableGraph';
9261
+ import type { UploadMetadata, UploadResponse } from 'alinea/core/Connection';
9262
+ import { EntryDatabase, type EntryChangeListener } from 'alinea/database/EntryDatabase';
9263
+ import type { DatabaseDriver } from 'alinea/database/driver/DatabaseHandle';
9264
+ export interface EntryStoreOptions {
9265
+ ownsDatabase?: boolean;
9266
+ sourceFollowsDatabase?: boolean;
9267
+ driver?: DatabaseDriver;
9268
+ }
9269
+ /** Source and commit lifecycle around the transport-neutral SQLite database. */
9270
+ export class EntryStore extends WriteableGraph implements LocalStore, AsyncDisposable {
9271
+ #private;
9272
+ /** Replaced only by a reindex, which derives every entry again. */
9273
+ config: Config;
9274
+ readonly database: EntryDatabase;
9275
+ readonly source: Source;
9276
+ readonly driver?: DatabaseDriver;
9277
+ constructor(config: Config, database: EntryDatabase, source: Source, options?: EntryStoreOptions);
9278
+ static memory(config: Config, source: Source): Promise<EntryStore>;
9279
+ get sha(): Promise<string>;
9280
+ includedAtBuild(filePath: string): boolean | Promise<boolean>;
9281
+ /**
9282
+ * Preview queries resolve over the store with the previewed entry synced
9283
+ * in. The last payload keeps its fork, so repeated queries of one preview
9284
+ * sync once; another payload or store revision forks afresh. A database
9285
+ * that cannot fork syncs each preview in a transaction it rolls back.
9286
+ */
9287
+ resolve<Query extends GraphQuery>(query: Query): Promise<AnyQueryResult<Query>>;
9288
+ referencesTo(query: EntryReferenceQuery): Promise<EntryReferenceResult>;
9289
+ onChange(listener: EntryChangeListener): () => void;
9290
+ sync(): Promise<string>;
9291
+ /** Keep the writable source and its query database at one remote revision. */
9292
+ syncWith(remote: RemoteSource, options?: SyncOptions): Promise<string>;
9293
+ /** Plan a commit without changing this store. */
9294
+ request(mutations: ReadonlyArray<Mutation>, policy?: Policy): Promise<CommitRequest>;
9295
+ mutate(mutations: Array<Mutation>): Promise<{
9296
+ sha: string;
9297
+ }>;
9298
+ write(request: CommitRequest): Promise<{
9299
+ sha: string;
9300
+ }>;
9301
+ getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
9302
+ getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncIterable<[sha: string, blob: Uint8Array<ArrayBufferLike>]>;
9303
+ prepareUpload(_file: string, _metadata?: UploadMetadata): Promise<UploadResponse>;
9304
+ /** Whether the underlying database was closed. */
9305
+ get closed(): boolean;
9306
+ close(): Promise<void>;
9307
+ [Symbol.asyncDispose](): Promise<void>;
9308
+ }
9309
+
9310
+ }
9311
+
9312
+ declare module 'alinea/database/EntryTransaction' {
9313
+
9314
+ import { type Policy } from 'alinea/core/Role';
9315
+ import { OverlaySource } from 'alinea/core/source/OverlaySource';
9316
+ import { SourceTransaction } from 'alinea/core/source/Source';
9317
+ import type { ReadonlyTree } from 'alinea/core/source/Tree';
9318
+ import { type CommitRequest } from 'alinea/core/db/CommitRequest';
9319
+ import type { ArchiveMutation, CreateMutation, MoveMutation, Mutation, PublishMutation, RemoveFileMutation, RemoveMutation, UnpublishMutation, UpdateMutation, UploadFileMutation } from 'alinea/core/db/Mutation';
9320
+ import type { EntryDatabase } from 'alinea/database/EntryDatabase';
9321
+ type Op<T> = Omit<T, 'op'>;
9322
+ /**
9323
+ * Plans mutations inside the receiver's write transaction. Each mutation is
9324
+ * flushed so subsequent mutations query its result without retaining an
9325
+ * in-memory entry index. SQLite rolls the full batch back on failure.
9326
+ */
9327
+ export class EntryTransaction implements AsyncDisposable {
9328
+ #private;
9329
+ /** @internal Constructed by EntryDatabase.apply. */
9330
+ constructor(workingDatabase: EntryDatabase, workingSource: OverlaySource, sourceTransaction: SourceTransaction, from: ReadonlyTree, policy: Policy);
9331
+ get changedEntryIds(): Array<string>;
9332
+ apply(mutations: ReadonlyArray<Mutation>): Promise<void>;
9333
+ create({ locale, type, data, root, workspace, fromSeed, parentId, id, insertOrder, status, overwrite }: Op<CreateMutation>): Promise<void>;
9334
+ update({ id, locale, status, set }: Op<UpdateMutation>): Promise<void>;
9335
+ publish({ id, locale, status }: Op<PublishMutation>): Promise<void>;
9336
+ unpublish({ id, locale }: Op<UnpublishMutation>): Promise<void>;
9337
+ archive({ id, locale }: Op<ArchiveMutation>): Promise<void>;
9338
+ move({ id, target, dropPosition, targetType }: Op<MoveMutation>): Promise<void>;
9339
+ remove({ id, locale, status }: Op<RemoveMutation>): Promise<void>;
9340
+ removeFile(mutation: Op<RemoveFileMutation>): void;
9341
+ uploadFile(mutation: Op<UploadFileMutation>): void;
9342
+ toRequest(): Promise<CommitRequest>;
9343
+ close(): Promise<void>;
9344
+ [Symbol.asyncDispose](): Promise<void>;
9345
+ }
9346
+ export {};
9347
+
9348
+ }
9349
+
9350
+ declare module 'alinea/database/EntryUrlAliases' {
9351
+
9352
+ import { Type } from 'alinea/core/Type';
9353
+ export function dataWithUrlAlias(type: Type, data: Record<string, unknown>, previousUrl: string, currentUrl: string): Record<string, unknown>;
9354
+
9355
+ }
9356
+
9357
+ declare module 'alinea/database/LocalDB' {
9358
+
9359
+ import type { AnyQueryResult, GraphQuery } from 'alinea/core/Graph';
9360
+ import type { GetBlobsOptions, RemoteSource, Source } from 'alinea/core/source/Source';
9361
+ import type { Config } from 'alinea/core/Config';
9362
+ import type { UploadMetadata, UploadResponse } from 'alinea/core/Connection';
9363
+ import type { CommitRequest } from 'alinea/core/db/CommitRequest';
9364
+ import type { EntryReferenceQuery, EntryReferenceResult } from 'alinea/core/db/EntryReference';
9365
+ import type { LocalStore, SyncOptions } from 'alinea/core/db/LocalStore';
9366
+ import type { Mutation } from 'alinea/core/db/Mutation';
9367
+ import { WriteableGraph } from 'alinea/core/db/WriteableGraph';
9368
+ import type { Policy } from 'alinea/core/Role';
9369
+ /**
9370
+ * Sync-constructor convenience over `EntryStore.memory()`.
9371
+ * This facade is backed by the SQLite engine.
9372
+ */
9373
+ export class LocalDB extends WriteableGraph implements LocalStore, AsyncDisposable {
9374
+ #private;
9375
+ readonly config: Config;
9376
+ readonly source: Source;
9377
+ readonly events: EventTarget;
9378
+ constructor(config: Config, source?: Source);
9379
+ get sha(): Promise<string>;
9380
+ includedAtBuild(filePath: string): Promise<boolean>;
9381
+ resolve<Query extends GraphQuery>(query: Query): Promise<AnyQueryResult<Query>>;
9382
+ referencesTo(query: EntryReferenceQuery): Promise<EntryReferenceResult>;
9383
+ getTreeIfDifferent(sha: string): Promise<import("alinea/core/source/Tree").ReadonlyTree | undefined>;
9384
+ getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncIterable<[sha: string, blob: Uint8Array<ArrayBufferLike>]>;
9385
+ sync(): Promise<string>;
9386
+ syncWith(remote: RemoteSource, options?: SyncOptions): Promise<string>;
9387
+ request(mutations: ReadonlyArray<Mutation>, policy?: Policy): Promise<CommitRequest>;
9388
+ mutate(mutations: Array<Mutation>): Promise<{
9389
+ sha: string;
9390
+ }>;
9391
+ write(request: CommitRequest): Promise<{
9392
+ sha: string;
9393
+ }>;
9394
+ prepareUpload(_file: string, _metadata?: UploadMetadata): Promise<UploadResponse>;
9395
+ close(): Promise<void>;
9396
+ [Symbol.asyncDispose](): Promise<void>;
9397
+ }
9398
+
9399
+ }
9400
+
9401
+ declare module 'alinea/database/query/Condition' {
9402
+
9403
+ import { type HasSql, type Sql } from 'rado';
9404
+ type FieldSql = (name: string) => HasSql;
9405
+ export function jsonField(target: HasSql, segments: Array<string>): HasSql<unknown>;
9406
+ /** Compile a condition; `depth` names the array items it iterates. */
9407
+ export function compileCondition(field: HasSql, condition: unknown, depth?: number): Sql<boolean>;
9408
+ export function compileFilter(filter: unknown, field: FieldSql): Sql<boolean>;
9409
+ export function arrayIncludes(field: HasSql, predicate: (item: HasSql) => Sql<boolean>, depth?: number): Sql<boolean>;
9410
+ export {};
9411
+
9412
+ }
9413
+
9414
+ declare module 'alinea/database/query/EntryQuery' {
9415
+
9416
+ import type { Config } from 'alinea/core/Config';
9417
+ import type { Field } from 'alinea/core/Field';
9418
+ import type { GraphQuery, Status } from 'alinea/core/Graph';
9419
+ import { type Scope } from 'alinea/core/Scope';
9420
+ import { type HasSql, type SelectionInput, type Sql } from 'rado';
9421
+ import { type EntryIndexTarget } from 'alinea/database/entry/EntryTable';
9422
+ import { searchQuery } from 'alinea/database/query/Search';
9423
+ interface RelationProjection {
9424
+ path: Array<string>;
9425
+ plan: ProjectionPlan;
9426
+ }
9427
+ interface FieldProjection {
9428
+ path: Array<string>;
9429
+ field: Field;
9430
+ }
9431
+ export interface ProjectionPlan {
9432
+ count: boolean;
9433
+ single: boolean;
9434
+ /** Rows carry the selection as `value`, next to the columns they need. */
9435
+ wrapped: boolean;
9436
+ relations: Array<RelationProjection>;
9437
+ fields: Array<FieldProjection>;
9438
+ }
9439
+ /** Rows visible under a query status; the default addresses published rows. */
9440
+ export function statusCondition(entry: EntryIndexTarget, status?: Status): Sql<boolean>;
9441
+ /**
9442
+ * Rows in one locale; null is unlocalized. Stored locales use the configured
9443
+ * spelling, so a requested locale matches any case of it.
9444
+ */
9445
+ export function localeCondition(scope: Scope, entry: EntryIndexTarget, locale: string | null | HasSql<string | null>): Sql<boolean>;
9446
+ interface EntryQueryOptions {
9447
+ source?: EntryIndexTarget;
9448
+ search?: ReturnType<typeof searchQuery>;
9449
+ entry?: EntryIndexTarget;
9450
+ depth?: number;
9451
+ baseEntry?: EntryIndexTarget;
9452
+ /** Wrap every row and carry its entry id next to the selection. */
9453
+ withId?: boolean;
9454
+ }
9455
+ export function compileEntryQuery(config: Config, query: GraphQuery, options?: EntryQueryOptions): {
9456
+ rows: import("rado").Select<SelectionInput, import("rado/core/MetaData").QueryMeta>;
9457
+ plan: ProjectionPlan;
9458
+ };
9459
+ export {};
9460
+
9461
+ }
9462
+
9463
+ declare module 'alinea/database/query/EntryReferences' {
9464
+
9465
+ import type { Config } from 'alinea/core/Config';
9466
+ import type { EntryReferenceQuery, EntryReferenceResult } from 'alinea/core/db/EntryReference';
9467
+ import { type Database } from 'rado';
9468
+ /** Read the versions indexed as referencing the target and walk their data. */
9469
+ export function queryEntryReferences(config: Config, db: Database, query: EntryReferenceQuery): Promise<EntryReferenceResult>;
9470
+
9471
+ }
9472
+
9473
+ declare module 'alinea/database/query/Relation' {
9474
+
9475
+ import type { EdgeQuery } from 'alinea/core/Graph';
9476
+ import { type Sql } from 'rado';
9477
+ import type { EntryIndexTarget } from 'alinea/database/entry/EntryTable';
9478
+ /** Expand the stored references as SQL rows, retaining list order and duplicates. */
9479
+ export function linkRelation(source: EntryIndexTarget, field: string, multiple: boolean): {
9480
+ target: Sql<unknown>;
9481
+ id: Sql<string>;
9482
+ ordinal: Sql<number>;
9483
+ };
9484
+ /** Restrict related identities in SQL before the query's own filters/paging. */
9485
+ export function relationCondition(entry: EntryIndexTarget, query: EdgeQuery, source: EntryIndexTarget): Sql<boolean>;
9486
+
9487
+ }
9488
+
9489
+ declare module 'alinea/database/query/ResolveQuery' {
9490
+
9491
+ import type { Config } from 'alinea/core/Config';
9492
+ import type { GraphQuery } from 'alinea/core/Graph';
9493
+ import { type Database } from 'rado';
9494
+ import type { SearchQuery } from 'alinea/database/query/Search';
9495
+ /** Query dependencies bound to one connection and its current transaction. */
9496
+ export interface EntryQueryContext {
9497
+ config: Config;
9498
+ database: Database;
9499
+ search(input: GraphQuery['search']): Promise<SearchQuery | undefined>;
9500
+ includedAtBuild(filePath: string): boolean | Promise<boolean>;
9501
+ }
9502
+ export function resolveEntryQuery(query: GraphQuery, context: EntryQueryContext): Promise<unknown>;
9503
+
9504
+ }
9505
+
9506
+ declare module 'alinea/database/query/Search' {
9507
+
9508
+ import { type Database, type HasSql, type Sql } from 'rado';
9509
+ import type { EntryIndexTarget } from 'alinea/database/entry/EntryTable';
9510
+ export const EntrySearchTable: import("rado").Table<{
9511
+ rowid: import("rado").Column<number, [false, false]>;
9512
+ title: import("rado").Column<string, [false, boolean]>;
9513
+ body: import("rado").Column<string, [false, boolean]>;
9514
+ }, "alinea_entry_search">;
9515
+ export interface SearchQuery {
9516
+ target: Sql;
9517
+ identity: Sql<boolean>;
9518
+ condition: Sql<boolean>;
9519
+ rank: Sql<number>;
9520
+ snippet(start: HasSql, end: HasSql, cutOff: HasSql, limit: HasSql): Sql<string>;
9521
+ }
9522
+ export function createSearch(db: Database): Promise<void>;
9523
+ /** The searchable text of an entry row, read from its search row. */
9524
+ export function searchableText(entry: EntryIndexTarget): Sql<string>;
9525
+ export function searchTokens(input: string | Array<string> | undefined): RegExpMatchArray | [] | undefined;
9526
+ export interface SearchQueryOptions {
9527
+ /** Indexed spellings a token may also match, besides its prefix. */
9528
+ alternatives?(token: string): ReadonlyArray<string>;
9529
+ }
9530
+ export function searchQuery(input: string | Array<string> | undefined, entry: EntryIndexTarget, options?: SearchQueryOptions): SearchQuery | undefined;
9531
+ /** The edits a token may be away from an indexed term: none below five
9532
+ * characters, one up to fourteen, then one more per ten. */
9533
+ export function fuzzyDistance(token: string): number;
9534
+ /**
9535
+ * The terms of the search index, loaded once per database revision. Query tokens
9536
+ * expand to indexed terms within a small edit distance, so a typo still
9537
+ * finds the entry.
9538
+ */
9539
+ export class SearchVocabulary {
9540
+ #private;
9541
+ load(db: Database, revision: string): Promise<void>;
9542
+ /** Indexed terms close to a token, most frequent first; prefixes of the
9543
+ * token are left to the prefix match. */
9544
+ alternatives(token: string): Array<string>;
9545
+ }
9546
+
9547
+ }
9548
+
9549
+ declare module 'alinea/database/sync/Derive' {
9550
+
9551
+ import type { Config } from 'alinea/core/Config';
9552
+ import { type SyncChanges } from 'alinea/database/sync/Ingest';
9553
+ import type { SyncQueries } from 'alinea/database/sync/SyncQueries';
9554
+ /**
9555
+ * Derive parents, statuses and urls for what a merge changed, and for what
9556
+ * inherits from it. Resolves to the sorted ids of every entry that changed.
9557
+ */
9558
+ export function deriveEntries(config: Config, queries: SyncQueries, changes: SyncChanges, validate: boolean): Promise<Array<string>>;
9559
+
9560
+ }
9561
+
9562
+ declare module 'alinea/database/sync/EntryParser' {
9563
+
9564
+ import type { Config } from 'alinea/core/Config';
9565
+ import type { IndexedEntry } from 'alinea/database/entry/EntryTable';
9566
+ /** A parsed source entry and the ids of the entries it references. */
9567
+ export interface ParsedEntry extends IndexedEntry {
9568
+ references: Array<string>;
9569
+ }
9570
+ /** Parse one source blob into the entry fields that do not depend on its tree. */
9571
+ export function parseSourceEntry(config: Config, filePath: string, fileHash: string, blob: Uint8Array): ParsedEntry;
9572
+
9573
+ }
9574
+
9575
+ declare module 'alinea/database/sync/EntrySyncer' {
9576
+
9577
+ import type { Config } from 'alinea/core/Config';
9578
+ import type { RemoteSource } from 'alinea/core/source/Source';
9579
+ import { ReadonlyTree } from 'alinea/core/source/Tree';
9580
+ import type { Database } from 'rado';
9581
+ export interface EntrySyncOptions {
9582
+ previousTree?: ReadonlyTree;
9583
+ withinTransaction?: boolean;
9584
+ /** Skip entry validation for a source whose entries were already validated. */
9585
+ validate?: boolean;
9586
+ /**
9587
+ * Record the synced source tree in the state, so the database can be
9588
+ * reopened and synced from it. Defaults to true.
9589
+ */
9590
+ recordsTree?: boolean;
9591
+ }
9592
+ /** Prepared, serialized source synchronization for one database connection. */
9593
+ export class EntrySyncer {
9594
+ #private;
9595
+ constructor(config: Config, db: Database);
9596
+ /** Derive later syncs with another config; prepared statements are shared. */
9597
+ reconfigure(config: Config): Promise<void>;
9598
+ /** Stream a source/tree diff directly into the canonical SQLite table. */
9599
+ sync(source: RemoteSource, tree: ReadonlyTree, fromRevision: string, options?: EntrySyncOptions): Promise<Array<string>>;
9600
+ close(): Promise<void>;
9601
+ }
9602
+
9603
+ }
9604
+
9605
+ declare module 'alinea/database/sync/Ingest' {
9606
+
9607
+ import type { Config } from 'alinea/core/Config';
9608
+ import type { RemoteSource } from 'alinea/core/source/Source';
9609
+ import { ReadonlyTree } from 'alinea/core/source/Tree';
9610
+ import { type SyncQueries } from 'alinea/database/sync/SyncQueries';
9611
+ /** What merging a source tree into the entry table changed. */
9612
+ export interface SyncChanges {
9613
+ /** Entries with a version that was added, replaced or removed. */
9614
+ touched: Set<string>;
9615
+ /** Versions written from their source file, with the url parsed from it. */
9616
+ inserted: Set<string>;
9617
+ /** Entries with a touched version that has children: those inherit from it. */
9618
+ parents: Set<string>;
9619
+ /** Child directories of removed or replaced versions that had children. */
9620
+ childDirs: Set<string>;
9621
+ /** Entries whose child directory changed in the source tree. */
9622
+ containers: Set<string>;
9623
+ }
9624
+ /** Whether a directory hash stands for a directory with files. */
9625
+ export function hasChildren(childrenSha: string | null): boolean;
9626
+ /** Write the files that differ between two source trees to the entry table. */
9627
+ export function mergeTrees(config: Config, source: RemoteSource, previousTree: ReadonlyTree, tree: ReadonlyTree, queries: SyncQueries): Promise<SyncChanges>;
9628
+
9629
+ }
9630
+
9631
+ declare module 'alinea/database/sync/SyncQueries' {
9632
+
9633
+ import type { EntryStatus } from 'alinea/core/Entry';
9634
+ import type { Tree } from 'alinea/core/source/Tree';
9635
+ import { type Database } from 'rado';
9636
+ import { type entryIndexRow } from 'alinea/database/entry/EntryTable';
9637
+ export const sqliteBatchSize = 5000;
9638
+ /**
9639
+ * Named parameters bypass column encoders, so bind SQLite values explicitly for
9640
+ * the placeholders of {@link insertEntryQuery}.
9641
+ */
9642
+ export function insertEntryValues(row: ReturnType<typeof entryIndexRow>): {
9643
+ versionId: string;
9644
+ id: string;
9645
+ locale: string | null;
9646
+ versionStatus: EntryStatus;
9647
+ status: EntryStatus;
9648
+ type: string;
9649
+ title: string;
9650
+ workspace: string;
9651
+ root: string;
9652
+ sourceRoot: string | null;
9653
+ parentId: string | null;
9654
+ level: number;
9655
+ index: string;
9656
+ path: string;
9657
+ filePath: string;
9658
+ fileHash: string;
9659
+ parentDir: string;
9660
+ childrenDir: string;
9661
+ url: string;
9662
+ seeded: string | null;
9663
+ rowHash: string;
9664
+ childrenSha: string | null;
9665
+ payload: string | null;
9666
+ data: string;
9667
+ parents: string;
9668
+ active: number;
9669
+ main: number;
9670
+ visible: number;
9671
+ };
9672
+ export function prepareSyncQueries(db: Database,
9673
+ /** Store entry data as JSONB, on a SQLite that reads it. */
9674
+ jsonb: boolean): {
9675
+ revision: import("rado").PreparedQuery<{
9676
+ revision: string;
9677
+ }, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9678
+ tree: import("rado").PreparedQuery<{
9679
+ tree: Tree;
9680
+ }, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9681
+ setRevision: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9682
+ entryCount: import("rado").PreparedQuery<{
9683
+ value: number;
9684
+ }, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9685
+ insertEntry: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9686
+ /** Index the entry row inserted last, under its rowid. */
9687
+ insertSearch: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9688
+ /** Record the entry ids a version references, under its rowid. */
9689
+ insertReferences: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9690
+ /** Versions stored at these file paths or under these version ids. */
9691
+ storedFiles: import("rado").PreparedQuery<{
9692
+ id: string;
9693
+ filePath: string;
9694
+ childrenDir: string;
9695
+ childrenSha: string | null;
9696
+ }[], Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9697
+ /** Delete the versions stored at these file paths or version ids. */
9698
+ deleteFiles: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9699
+ /** Delete the search rows of those versions, before the versions. */
9700
+ deleteSearch: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9701
+ /** Delete the reference rows of those versions, before the versions. */
9702
+ deleteReferences: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9703
+ directories: import("rado").PreparedQuery<{
9704
+ id: string;
9705
+ childrenDir: string;
9706
+ childrenSha: string | null;
9707
+ }[], Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9708
+ updateChildrenSha: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9709
+ /** Every version of these entries. */
9710
+ versionsOf: import("rado").PreparedQuery<{
9711
+ versionId: string;
9712
+ id: string;
9713
+ locale: string | null;
9714
+ versionStatus: EntryStatus;
9715
+ type: string;
9716
+ index: string;
9717
+ workspace: string;
9718
+ root: string;
9719
+ path: string;
9720
+ filePath: string;
9721
+ level: number;
9722
+ parentDir: string;
9723
+ childrenDir: string;
9724
+ childrenSha: string | null;
9725
+ parentId: string | null;
9726
+ parents: string[];
9727
+ status: EntryStatus;
9728
+ active: boolean;
9729
+ main: boolean;
9730
+ visible: boolean;
9731
+ url: string;
9732
+ }[], Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9733
+ /** Every version stored below one directory. */
9734
+ versionsBelow: import("rado").PreparedQuery<{
9735
+ versionId: string;
9736
+ id: string;
9737
+ locale: string | null;
9738
+ versionStatus: EntryStatus;
9739
+ type: string;
9740
+ index: string;
9741
+ workspace: string;
9742
+ root: string;
9743
+ path: string;
9744
+ filePath: string;
9745
+ level: number;
9746
+ parentDir: string;
9747
+ childrenDir: string;
9748
+ childrenSha: string | null;
9749
+ parentId: string | null;
9750
+ parents: string[];
9751
+ status: EntryStatus;
9752
+ active: boolean;
9753
+ main: boolean;
9754
+ visible: boolean;
9755
+ url: string;
9756
+ }[], Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9757
+ /** The entry owning each directory: children stored there have it as parent. */
9758
+ owners: import("rado").PreparedQuery<{
9759
+ childrenDir: string;
9760
+ id: string;
9761
+ }[], Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9762
+ statusesOf: import("rado").PreparedQuery<{
9763
+ id: string;
9764
+ locale: string | null;
9765
+ status: EntryStatus;
9766
+ }[], Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9767
+ dataOf: import("rado").PreparedQuery<{
9768
+ versionId: string;
9769
+ data: string;
9770
+ }[], Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9771
+ updateVersion: import("rado").PreparedQuery<import("rado/core/MetaData").MutationResultBase, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9772
+ /** An entry whose versions disagree on what all of them must share. */
9773
+ mismatchedEntry: import("rado").PreparedQuery<{
9774
+ id: string;
9775
+ }, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9776
+ /** A language whose versions disagree on their location. */
9777
+ mismatchedLanguage: import("rado").PreparedQuery<{
9778
+ id: string;
9779
+ locale: string | null;
9780
+ }, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9781
+ /** A language without exactly one active and one main version. */
9782
+ invalidStatus: import("rado").PreparedQuery<{
9783
+ id: string;
9784
+ locale: string | null;
9785
+ }, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9786
+ /** A version listed among its own parents. */
9787
+ cyclicVersion: import("rado").PreparedQuery<{
9788
+ filePath: string;
9789
+ }, Record<string, unknown>, import("rado/core/MetaData").QueryMeta>;
9790
+ free(): void;
9791
+ };
9792
+ export type SyncQueries = ReturnType<typeof prepareSyncQueries>;
9793
+
9794
+ }
9795
+
9796
+ declare module 'alinea/database/Version' {
9797
+
9798
+ /**
9799
+ * Bump when the SQLite schema or the data derived into generated databases
9800
+ * changes incompatibly. Generated database files and browser caches are keyed
9801
+ * by this version rather than the package version, so releases that keep the
9802
+ * schema reuse the databases that are already there.
9803
+ */
9804
+ export const databaseVersion = 8;
9805
+ export const generatedDatabaseFile = "database-v8.sqlite";
9806
+ export function versionedCacheName(name: string): string;
9807
+
9808
+ }
9809
+
8817
9810
  declare module 'alinea/edit' {
8818
9811
 
8819
9812
  import type { Reference } from 'alinea/core/Reference';
@@ -9608,6 +10601,7 @@ declare module 'alinea/field/metadata/MetadataField' {
9608
10601
  import type { FieldOptions } from 'alinea/core/Field';
9609
10602
  import { RecordField } from 'alinea/core/field/RecordField';
9610
10603
  import { ScalarField } from 'alinea/core/field/ScalarField';
10604
+ import { type Section, type SectionData } from 'alinea/core/Section';
9611
10605
  import { Type } from 'alinea/core/Type';
9612
10606
  import { type ImageField, type ImageLink } from 'alinea/field/link';
9613
10607
  import { type ObjectField } from 'alinea/field/object';
@@ -9620,19 +10614,23 @@ declare module 'alinea/field/metadata/MetadataField' {
9620
10614
  export interface MetadataUserOptions extends FieldOptions<MetadataAuditUser> {
9621
10615
  width?: number;
9622
10616
  }
9623
- export interface MetadataFields {
10617
+ export interface MetadataSeoFields {
9624
10618
  title: TextField;
9625
10619
  description: TextField;
9626
- aliases: AliasesField;
9627
10620
  openGraph: ObjectField<{
9628
10621
  image: ImageField;
9629
10622
  title: TextField;
9630
10623
  description: TextField;
9631
10624
  }>;
10625
+ }
10626
+ export interface MetadataDetailsFields {
9632
10627
  createdAt: MetadataTimestampField;
9633
10628
  createdBy: MetadataUserField;
9634
10629
  updatedAt: MetadataTimestampField;
9635
10630
  updatedBy: MetadataUserField;
10631
+ aliases: AliasesField;
10632
+ }
10633
+ export interface MetadataFields extends MetadataSeoFields, MetadataDetailsFields {
9636
10634
  }
9637
10635
  export interface MetadataAuditUser {
9638
10636
  name: string;
@@ -9654,6 +10652,15 @@ declare module 'alinea/field/metadata/MetadataField' {
9654
10652
  }
9655
10653
  export interface MetadataOptions extends FieldOptions<Metadata> {
9656
10654
  fields: Type<MetadataFields>;
10655
+ seo: Type<MetadataSeoFields>;
10656
+ details: Type<MetadataDetailsFields>;
10657
+ /** The details are rendered by a separate `metadataDetails` section */
10658
+ detailsSection?: boolean;
10659
+ }
10660
+ export interface MetadataConfig {
10661
+ /** Leave the details out of the field view, render them with
10662
+ * `metadataDetails(field)` instead */
10663
+ detailsSection?: boolean;
9657
10664
  }
9658
10665
  export class MetadataField extends RecordField<Metadata, MetadataOptions> {
9659
10666
  }
@@ -9663,12 +10670,24 @@ declare module 'alinea/field/metadata/MetadataField' {
9663
10670
  }
9664
10671
  export class MetadataUserField extends ScalarField<MetadataAuditUser, MetadataUserOptions> {
9665
10672
  }
9666
- export function metadata(label?: string): MetadataField;
10673
+ export function metadata(label?: string, { detailsSection }?: MetadataConfig): MetadataField;
10674
+ export class MetadataDetailsSection implements SectionData {
10675
+ field: MetadataField;
10676
+ view: string;
10677
+ definition: {};
10678
+ fields: {};
10679
+ sections: never[];
10680
+ constructor(field: MetadataField);
10681
+ }
10682
+ /** Renders the created/updated details and aliases of a metadata field
10683
+ * created with `detailsSection: true` */
10684
+ export function metadataDetails(field: MetadataField): Section;
9667
10685
 
9668
10686
  }
9669
10687
 
9670
10688
  declare module 'alinea/field/metadata/MetadataField.view' {
9671
10689
 
10690
+ import { Section } from 'alinea/core/Section';
9672
10691
  import { MetadataField, MetadataTimestampField, MetadataUserField } from 'alinea/field/metadata';
9673
10692
  export interface MetadataFieldViewProps {
9674
10693
  field: MetadataField;
@@ -9682,6 +10701,10 @@ declare module 'alinea/field/metadata/MetadataField.view' {
9682
10701
  }
9683
10702
  export function MetadataUserFieldView({ field }: MetadataUserFieldViewProps): import("react").JSX.Element;
9684
10703
  export function MetadataFieldView({ field }: MetadataFieldViewProps): import("react").JSX.Element;
10704
+ export interface MetadataDetailsViewProps {
10705
+ section: Section;
10706
+ }
10707
+ export function MetadataDetailsView({ section }: MetadataDetailsViewProps): import("react").JSX.Element;
9685
10708
 
9686
10709
  }
9687
10710
 
@@ -10112,7 +11135,7 @@ declare module 'alinea/field/richtext/RichTextExtensions' {
10112
11135
  Highlight: import("@tiptap/core").Mark<import("@tiptap/extension-highlight").HighlightOptions, any>;
10113
11136
  UndoRedo: Extension<import("@tiptap/extensions").UndoRedoOptions, any>;
10114
11137
  };
10115
- export function defaultExtensionConfig(getEntryAnchors?: () => Iterable<string>, enableImageResize?: boolean): {
11138
+ export function defaultExtensionConfig(getEntryAnchors?: () => Iterable<string>, enableImageResize?: boolean, enableTables?: boolean): {
10116
11139
  Document: TipTapNode<any, any>;
10117
11140
  Text: TipTapNode<any, any>;
10118
11141
  Paragraph: TipTapNode<import("@tiptap/extension-paragraph").ParagraphOptions, any>;
@@ -10756,16 +11779,17 @@ declare module 'alinea' {
10756
11779
 
10757
11780
  declare module 'alinea/next' {
10758
11781
 
10759
- export { createCMS } from 'alinea/adapter/next/cms';
10760
- export { createHandler, type NextHandlerOptions } from 'alinea/adapter/next/handler';
10761
- export type { AfterCommitContext, BeforeCommitContext } from 'alinea/backend/Handler';
11782
+ export type { SyncStatus } from 'alinea/adapter/next/cms';
11783
+ export type { NextHandlerOptions } from 'alinea/adapter/next/handler';
11784
+ export { createCMS, createHandler } from 'alinea/adapter/next/node';
10762
11785
  export { withAlinea } from 'alinea/adapter/next/with-alinea';
11786
+ export type { AfterCommitContext, BeforeCommitContext } from 'alinea/backend/Handler';
10763
11787
 
10764
11788
  }
10765
11789
 
10766
11790
  declare module 'alinea/next.edge' {
10767
11791
 
10768
- export { createCMS } from 'alinea/adapter/next/cms';
11792
+ export { createCMS, type SyncStatus } from 'alinea/adapter/next/cms';
10769
11793
  export { createHandler, type NextHandlerOptions } from 'alinea/adapter/next/handler';
10770
11794
  export type { AfterCommitContext, BeforeCommitContext } from 'alinea/backend/Handler';
10771
11795
 
@@ -10978,6 +12002,49 @@ declare module 'alinea/preview/RegisterPreview' {
10978
12002
  declare module 'alinea/preview/widget' {
10979
12003
 
10980
12004
  import type { DOMAttributes } from 'react';
12005
+ export interface PreviewStat {
12006
+ kind: 'query' | 'sync';
12007
+ summary: string;
12008
+ /** Whether the query was answered by the bundled database or the handler. */
12009
+ source?: 'database' | 'handler';
12010
+ /**
12011
+ * Execution time for queries the bundled database answers, without the
12012
+ * wait behind the render's other queries; time from call to answer for
12013
+ * syncs and queries the handler answers.
12014
+ */
12015
+ durationMs: number;
12016
+ /** SQL statements this row's work ran, such as a preview's sync. */
12017
+ statements?: number;
12018
+ sqlMs?: number;
12019
+ }
12020
+ /** One of the slowest SQL statements of a render. */
12021
+ export interface PreviewStatement {
12022
+ /** The statement, shortened */
12023
+ sql: string;
12024
+ durationMs: number;
12025
+ /** Summary of the query or sync that ran it */
12026
+ query?: string;
12027
+ }
12028
+ /** The bundled database that answered the render's queries. */
12029
+ export interface PreviewDatabase {
12030
+ /** The native overlay, the native file, or the WASM copy */
12031
+ driver?: string;
12032
+ /** Time this process took to open it */
12033
+ openMs: number;
12034
+ /** Whether this render waited for it to open */
12035
+ cold: boolean;
12036
+ }
12037
+ /** The CMS work of one render, shown in the widget. */
12038
+ export interface PreviewStats {
12039
+ rows: Array<PreviewStat>;
12040
+ /** SQL statements run in this process for the render. */
12041
+ statements: number;
12042
+ sqlMs: number;
12043
+ /** Time from the first query or sync of the render until the last settled. */
12044
+ renderMs: number;
12045
+ slowest?: Array<PreviewStatement>;
12046
+ database?: PreviewDatabase;
12047
+ }
10981
12048
  export function registerPreviewWidget(): void;
10982
12049
  global {
10983
12050
  namespace JSX {
@@ -10986,6 +12053,8 @@ declare module 'alinea/preview/widget' {
10986
12053
  adminUrl: string;
10987
12054
  editUrl: string;
10988
12055
  livePreview?: 'connected' | 'warning' | 'loading';
12056
+ /** JSON encoded PreviewStats */
12057
+ stats?: string;
10989
12058
  };
10990
12059
  }
10991
12060
  }
@@ -11019,7 +12088,11 @@ declare module 'alinea/query' {
11019
12088
  count?: true;
11020
12089
  id?: import("alinea/core/Filter").Condition<string>;
11021
12090
  parentId?: import("alinea/core/Filter").Condition<string | null>;
12091
+ versionStatus?: import("alinea/core/Filter").Condition<import("alinea/core/Entry").EntryStatus>;
12092
+ main?: import("alinea/core/Filter").Condition<boolean>;
11022
12093
  path?: import("alinea/core/Filter").Condition<string>;
12094
+ filePath?: import("alinea/core/Filter").Condition<string>;
12095
+ seeded?: import("alinea/core/Filter").Condition<string | null>;
11023
12096
  url?: import("alinea/core/Filter").Condition<string>;
11024
12097
  alias?: import("alinea/core/Filter").Condition<string>;
11025
12098
  createdAt?: import("alinea/core/Filter").Condition<number | null>;
@@ -11054,7 +12127,11 @@ declare module 'alinea/query' {
11054
12127
  count?: true;
11055
12128
  id?: import("alinea/core/Filter").Condition<string>;
11056
12129
  parentId?: import("alinea/core/Filter").Condition<string | null>;
12130
+ versionStatus?: import("alinea/core/Filter").Condition<import("alinea/core/Entry").EntryStatus>;
12131
+ main?: import("alinea/core/Filter").Condition<boolean>;
11057
12132
  path?: import("alinea/core/Filter").Condition<string>;
12133
+ filePath?: import("alinea/core/Filter").Condition<string>;
12134
+ seeded?: import("alinea/core/Filter").Condition<string | null>;
11058
12135
  url?: import("alinea/core/Filter").Condition<string>;
11059
12136
  alias?: import("alinea/core/Filter").Condition<string>;
11060
12137
  createdAt?: import("alinea/core/Filter").Condition<number | null>;
@@ -11089,7 +12166,11 @@ declare module 'alinea/query' {
11089
12166
  count?: true;
11090
12167
  id?: import("alinea/core/Filter").Condition<string>;
11091
12168
  parentId?: import("alinea/core/Filter").Condition<string | null>;
12169
+ versionStatus?: import("alinea/core/Filter").Condition<import("alinea/core/Entry").EntryStatus>;
12170
+ main?: import("alinea/core/Filter").Condition<boolean>;
11092
12171
  path?: import("alinea/core/Filter").Condition<string>;
12172
+ filePath?: import("alinea/core/Filter").Condition<string>;
12173
+ seeded?: import("alinea/core/Filter").Condition<string | null>;
11093
12174
  url?: import("alinea/core/Filter").Condition<string>;
11094
12175
  alias?: import("alinea/core/Filter").Condition<string>;
11095
12176
  createdAt?: import("alinea/core/Filter").Condition<number | null>;
@@ -11124,7 +12205,11 @@ declare module 'alinea/query' {
11124
12205
  count?: true;
11125
12206
  id?: import("alinea/core/Filter").Condition<string>;
11126
12207
  parentId?: import("alinea/core/Filter").Condition<string | null>;
12208
+ versionStatus?: import("alinea/core/Filter").Condition<import("alinea/core/Entry").EntryStatus>;
12209
+ main?: import("alinea/core/Filter").Condition<boolean>;
11127
12210
  path?: import("alinea/core/Filter").Condition<string>;
12211
+ filePath?: import("alinea/core/Filter").Condition<string>;
12212
+ seeded?: import("alinea/core/Filter").Condition<string | null>;
11128
12213
  url?: import("alinea/core/Filter").Condition<string>;
11129
12214
  alias?: import("alinea/core/Filter").Condition<string>;
11130
12215
  createdAt?: import("alinea/core/Filter").Condition<number | null>;
@@ -11157,7 +12242,11 @@ declare module 'alinea/query' {
11157
12242
  count?: true;
11158
12243
  id?: import("alinea/core/Filter").Condition<string>;
11159
12244
  parentId?: import("alinea/core/Filter").Condition<string | null>;
12245
+ versionStatus?: import("alinea/core/Filter").Condition<import("alinea/core/Entry").EntryStatus>;
12246
+ main?: import("alinea/core/Filter").Condition<boolean>;
11160
12247
  path?: import("alinea/core/Filter").Condition<string>;
12248
+ filePath?: import("alinea/core/Filter").Condition<string>;
12249
+ seeded?: import("alinea/core/Filter").Condition<string | null>;
11161
12250
  url?: import("alinea/core/Filter").Condition<string>;
11162
12251
  alias?: import("alinea/core/Filter").Condition<string>;
11163
12252
  createdAt?: import("alinea/core/Filter").Condition<number | null>;
@@ -11189,7 +12278,11 @@ declare module 'alinea/query' {
11189
12278
  count?: true;
11190
12279
  id?: import("alinea/core/Filter").Condition<string>;
11191
12280
  parentId?: import("alinea/core/Filter").Condition<string | null>;
12281
+ versionStatus?: import("alinea/core/Filter").Condition<import("alinea/core/Entry").EntryStatus>;
12282
+ main?: import("alinea/core/Filter").Condition<boolean>;
11192
12283
  path?: import("alinea/core/Filter").Condition<string>;
12284
+ filePath?: import("alinea/core/Filter").Condition<string>;
12285
+ seeded?: import("alinea/core/Filter").Condition<string | null>;
11193
12286
  url?: import("alinea/core/Filter").Condition<string>;
11194
12287
  alias?: import("alinea/core/Filter").Condition<string>;
11195
12288
  createdAt?: import("alinea/core/Filter").Condition<number | null>;
@@ -11221,7 +12314,11 @@ declare module 'alinea/query' {
11221
12314
  count?: true;
11222
12315
  id?: import("alinea/core/Filter").Condition<string>;
11223
12316
  parentId?: import("alinea/core/Filter").Condition<string | null>;
12317
+ versionStatus?: import("alinea/core/Filter").Condition<import("alinea/core/Entry").EntryStatus>;
12318
+ main?: import("alinea/core/Filter").Condition<boolean>;
11224
12319
  path?: import("alinea/core/Filter").Condition<string>;
12320
+ filePath?: import("alinea/core/Filter").Condition<string>;
12321
+ seeded?: import("alinea/core/Filter").Condition<string | null>;
11225
12322
  url?: import("alinea/core/Filter").Condition<string>;
11226
12323
  alias?: import("alinea/core/Filter").Condition<string>;
11227
12324
  createdAt?: import("alinea/core/Filter").Condition<number | null>;