alinea 2.0.0-preview.6 → 2.0.0-preview.8

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 (298) hide show
  1. package/dist/.init/content/pages/welcome.json +1 -1
  2. package/dist/LICENSES.md +109 -109
  3. package/dist/adapter/next/cms.d.ts +18 -4
  4. package/dist/adapter/next/cms.js +125 -36
  5. package/dist/adapter/next/handler.d.ts +5 -1
  6. package/dist/adapter/next/handler.js +14 -7
  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 -3
  11. package/dist/adapter/next/renderStats.d.ts +24 -0
  12. package/dist/adapter/next/renderStats.js +74 -0
  13. package/dist/adapter/next/syncCheck.d.ts +8 -2
  14. package/dist/adapter/next/syncCheck.js +3 -3
  15. package/dist/adapter/next/with-alinea.js +0 -18
  16. package/dist/backend/Handler.d.ts +2 -2
  17. package/dist/backend/Handler.js +33 -12
  18. package/dist/backend/api/CreateBackend.js +15 -3
  19. package/dist/backend/api/DatabaseApi.js +22 -135
  20. package/dist/backend/api/database.js +15 -3
  21. package/dist/backend/resolver/ParsePreview.d.ts +2 -2
  22. package/dist/backend/router/NodeHandler.js +2 -0
  23. package/dist/backend/store/GeneratedDatabase.d.ts +5 -0
  24. package/dist/backend/store/GeneratedDatabase.js +31 -0
  25. package/dist/backend/store/GeneratedDatabaseNode.d.ts +4 -0
  26. package/dist/backend/store/GeneratedDatabaseNode.js +35 -0
  27. package/dist/backend/util/ORM.js +4 -2
  28. package/dist/bundled.d.ts +1485 -446
  29. package/dist/chunks/bun-sqlite-ZZDB7YQQ.js +18 -0
  30. package/dist/chunks/chunk-2BJ2IFQM.js +1085 -0
  31. package/dist/chunks/chunk-2PIFHEYR.js +364 -0
  32. package/dist/chunks/{chunk-X47OVDF3.js → chunk-2U43BB6P.js} +356 -1000
  33. package/dist/chunks/chunk-76VMZTLN.js +55 -0
  34. package/dist/chunks/chunk-A42DP5T7.js +94 -0
  35. package/dist/chunks/chunk-ATF42T2B.js +35 -0
  36. package/dist/chunks/{chunk-NWQXN4SB.js → chunk-ETBQTP2S.js} +40 -29
  37. package/dist/chunks/chunk-IL7FJQAY.js +94 -0
  38. package/dist/chunks/chunk-K62JP6HR.js +22 -0
  39. package/dist/chunks/chunk-K7LHQXI4.js +103 -0
  40. package/dist/chunks/chunk-M7KDJEGH.js +495 -0
  41. package/dist/chunks/chunk-N47Y62CI.js +396 -0
  42. package/dist/chunks/chunk-NLZLRQ5U.js +100 -0
  43. package/dist/chunks/chunk-QBPYWU6C.js +24 -0
  44. package/dist/chunks/{chunk-7IOKMUKO.js → chunk-RWWYUNVX.js} +2 -1
  45. package/dist/chunks/chunk-TFMUSWGG.js +605 -0
  46. package/dist/chunks/{chunk-I4GC3E65.js → chunk-UPY2RUZF.js} +0 -1
  47. package/dist/chunks/chunk-XCZXR3C2.js +112 -0
  48. package/dist/chunks/chunk-XTWYBWP2.js +81 -0
  49. package/dist/chunks/node-sqlite-7CSGL27V.js +18 -0
  50. package/dist/cli/Generate.js +74 -64
  51. package/dist/cli/Serve.js +1 -1
  52. package/dist/cli/bin.js +2 -1
  53. package/dist/cli/generate/CopyStaticFiles.js +17 -14
  54. package/dist/cli/generate/DevDB.d.ts +22 -5
  55. package/dist/cli/generate/DevDB.js +136 -24
  56. package/dist/cli/serve/CreateLocalServer.js +22 -4
  57. package/dist/cli/serve/LiveReload.d.ts +1 -1
  58. package/dist/cli/serve/LiveReload.js +3 -0
  59. package/dist/cloud/CloudRemote.js +2 -1
  60. package/dist/components/Calendar.js +5 -5
  61. package/dist/components/Checkbox.js +2 -2
  62. package/dist/components/ComboBox.js +13 -13
  63. package/dist/components/DateField.js +3 -3
  64. package/dist/components/DatePicker.js +5 -5
  65. package/dist/components/DateRangePicker.js +6 -6
  66. package/dist/components/Disclosure.js +7 -7
  67. package/dist/components/Label.js +4 -4
  68. package/dist/components/List.js +51 -49
  69. package/dist/components/Menu.js +4 -4
  70. package/dist/components/Modal.js +2 -2
  71. package/dist/components/MultipleSelect.js +25 -25
  72. package/dist/components/NumberField.js +3 -3
  73. package/dist/components/ProgressCircle.js +2 -2
  74. package/dist/components/RadioGroup.js +2 -2
  75. package/dist/components/SearchField.js +8 -8
  76. package/dist/components/Select.js +8 -8
  77. package/dist/components/Surface.js +3 -3
  78. package/dist/components/Table.js +7 -7
  79. package/dist/components/Tabs.js +4 -4
  80. package/dist/components/TagGroup.js +3 -3
  81. package/dist/components/TextField.js +3 -3
  82. package/dist/components/TimeField.js +3 -3
  83. package/dist/components/Toggle.js +2 -2
  84. package/dist/components/Toolbar.js +2 -2
  85. package/dist/components/Tooltip.js +3 -3
  86. package/dist/components/Tree.d.ts +2 -1
  87. package/dist/components/Tree.js +9 -9
  88. package/dist/core/Document.js +15 -3
  89. package/dist/core/Entry.d.ts +3 -0
  90. package/dist/core/Entry.js +4 -0
  91. package/dist/core/EntrySeed.d.ts +19 -0
  92. package/dist/core/EntrySeed.js +136 -0
  93. package/dist/core/Field.d.ts +7 -0
  94. package/dist/core/Field.js +4 -0
  95. package/dist/core/Filter.d.ts +40 -2
  96. package/dist/core/Filter.js +145 -0
  97. package/dist/core/Graph.d.ts +9 -0
  98. package/dist/core/ListRow.d.ts +1 -0
  99. package/dist/core/ListRow.js +1 -0
  100. package/dist/core/Reference.d.ts +1 -0
  101. package/dist/core/Root.js +1 -1
  102. package/dist/core/Scope.d.ts +2 -0
  103. package/dist/core/Scope.js +16 -1
  104. package/dist/core/TextDoc.d.ts +1 -0
  105. package/dist/core/Type.d.ts +2 -1
  106. package/dist/core/Type.js +13 -1
  107. package/dist/core/db/EntryAliases.js +1 -11
  108. package/dist/core/db/EntryReference.d.ts +0 -6
  109. package/dist/core/db/IndexEvent.d.ts +2 -1
  110. package/dist/core/db/IndexEvent.js +11 -3
  111. package/dist/core/db/LinkResolver.d.ts +6 -6
  112. package/dist/core/db/LinkResolver.js +0 -52
  113. package/dist/core/db/LocalStore.d.ts +25 -0
  114. package/dist/core/field/ListField.js +19 -0
  115. package/dist/core/field/RecordField.js +8 -0
  116. package/dist/core/field/RichTextField.js +45 -3
  117. package/dist/core/field/UnionField.js +8 -0
  118. package/dist/core/source/FSSource.d.ts +14 -2
  119. package/dist/core/source/FSSource.js +58 -13
  120. package/dist/core/source/GitUtils.d.ts +4 -0
  121. package/dist/core/source/GitUtils.js +9 -10
  122. package/dist/core/source/GithubSource.js +22 -11
  123. package/dist/core/source/IndexedDBSource.d.ts +2 -1
  124. package/dist/core/source/IndexedDBSource.js +67 -53
  125. package/dist/core/source/MemorySource.js +5 -3
  126. package/dist/core/source/OverlaySource.d.ts +5 -2
  127. package/dist/core/source/OverlaySource.js +31 -3
  128. package/dist/core/source/Source.d.ts +3 -0
  129. package/dist/core/source/Source.js +15 -2
  130. package/dist/core/source/Tree.d.ts +10 -7
  131. package/dist/core/source/Tree.js +118 -70
  132. package/dist/core/source/Utils.js +6 -3
  133. package/dist/core/util/Arrays.d.ts +1 -0
  134. package/dist/core/util/Arrays.js +10 -0
  135. package/dist/core/util/Async.d.ts +7 -0
  136. package/dist/core/util/Async.js +15 -0
  137. package/dist/core/util/Checks.js +1 -1
  138. package/dist/core/util/EntryFilenames.d.ts +22 -1
  139. package/dist/core/util/EntryFilenames.js +56 -2
  140. package/dist/core/util/IndexedDB.d.ts +4 -0
  141. package/dist/core/util/IndexedDB.js +20 -0
  142. package/dist/core/util/Paths.js +5 -1
  143. package/dist/dashboard/App.js +5 -3
  144. package/dist/dashboard/ViewKeys.d.ts +1 -0
  145. package/dist/dashboard/ViewKeys.js +1 -0
  146. package/dist/dashboard/app/AccessDenied.js +3 -3
  147. package/dist/dashboard/app/ActivityStatus.js +17 -17
  148. package/dist/dashboard/app/AppShell.js +2 -2
  149. package/dist/dashboard/app/AuthView.js +11 -11
  150. package/dist/dashboard/app/CompactField.js +12 -12
  151. package/dist/dashboard/app/DashboardErrorBoundary.js +6 -6
  152. package/dist/dashboard/app/DashboardLayout.js +6 -5
  153. package/dist/dashboard/app/EntryHeader.js +8 -8
  154. package/dist/dashboard/app/EntryReferences.js +12 -17
  155. package/dist/dashboard/app/EntrySidebar.js +27 -13
  156. package/dist/dashboard/app/EntrySidebarPreview.js +12 -12
  157. package/dist/dashboard/app/EntryTranslationBanner.js +3 -3
  158. package/dist/dashboard/app/Explorer.js +41 -41
  159. package/dist/dashboard/app/ExplorerCards.js +33 -33
  160. package/dist/dashboard/app/ExplorerFileCard.js +18 -18
  161. package/dist/dashboard/app/ExplorerList.js +13 -13
  162. package/dist/dashboard/app/ExplorerModal.js +5 -5
  163. package/dist/dashboard/app/ExplorerTable.js +48 -48
  164. package/dist/dashboard/app/LinkPicker.js +3 -3
  165. package/dist/dashboard/app/LocaleMenu.js +7 -7
  166. package/dist/dashboard/app/SidebarTree.js +81 -45
  167. package/dist/dashboard/app/WorkspaceMenu.js +9 -9
  168. package/dist/dashboard/app/WorkspaceRoots.js +21 -21
  169. package/dist/dashboard/app/editor/FileEditor.js +26 -26
  170. package/dist/dashboard/app/editor/FilePreview.js +6 -6
  171. package/dist/dashboard/app/modals/CreateEntry.js +5 -5
  172. package/dist/dashboard/app/pages/EntryPage.js +15 -15
  173. package/dist/dashboard/app/pages/RootPage.js +3 -3
  174. package/dist/dashboard/app/pages/SplashPage.js +43 -43
  175. package/dist/dashboard/app/pages/UsersPage.js +34 -34
  176. package/dist/dashboard/app/ui/DashboardModal.js +17 -17
  177. package/dist/dashboard/app/ui/Rail.js +3 -3
  178. package/dist/dashboard/app/ui/Sidebar.js +2 -2
  179. package/dist/dashboard/atoms/config.d.ts +4 -4
  180. package/dist/dashboard/atoms/dashboard.js +2 -1
  181. package/dist/dashboard/atoms/editor.js +7 -0
  182. package/dist/dashboard/atoms/entry.d.ts +10 -13
  183. package/dist/dashboard/atoms/entry.js +42 -7
  184. package/dist/dashboard/atoms/explorer.d.ts +2 -0
  185. package/dist/dashboard/atoms/explorer.js +7 -2
  186. package/dist/dashboard/atoms/root.d.ts +1 -0
  187. package/dist/dashboard/atoms/root.js +61 -35
  188. package/dist/dashboard/boot/Boot.js +9 -8
  189. package/dist/dashboard/boot/DashboardWorker.d.ts +3 -3
  190. package/dist/dashboard/boot/DashboardWorker.js +78 -27
  191. package/dist/dashboard/boot/LoadWorker.js +2 -3
  192. package/dist/dashboard/icons.d.ts +2 -0
  193. package/dist/dashboard/icons.js +40 -0
  194. package/dist/dashboard/plugins/alineaFixturePlugin.js +14 -3
  195. package/dist/database/BrowserEntryStore.d.ts +30 -0
  196. package/dist/database/BrowserEntryStore.js +168 -0
  197. package/dist/database/DatabaseSource.d.ts +13 -0
  198. package/dist/database/DatabaseSource.js +25 -0
  199. package/dist/database/DatabaseTables.d.ts +38 -0
  200. package/dist/database/DatabaseTables.js +53 -0
  201. package/dist/database/EntryDatabase.d.ts +21 -0
  202. package/dist/database/EntryDatabase.js +138 -0
  203. package/dist/database/EntryLayer.d.ts +93 -0
  204. package/dist/database/EntryLayer.js +459 -0
  205. package/dist/database/EntryStore.d.ts +60 -0
  206. package/dist/database/EntryStore.js +269 -0
  207. package/dist/database/EntryTransaction.d.ts +33 -0
  208. package/dist/database/EntryTransaction.js +889 -0
  209. package/dist/database/EntryUrlAliases.d.ts +2 -0
  210. package/dist/database/EntryUrlAliases.js +69 -0
  211. package/dist/database/LocalDB.d.ts +39 -0
  212. package/dist/database/LocalDB.js +79 -0
  213. package/dist/database/Version.d.ts +9 -0
  214. package/dist/database/Version.js +13 -0
  215. package/dist/database/driver/RuntimeDatabase.d.ts +8 -0
  216. package/dist/database/driver/RuntimeDatabase.js +33 -0
  217. package/dist/database/driver/WasmDatabase.d.ts +8 -0
  218. package/dist/database/driver/WasmDatabase.js +33 -0
  219. package/dist/database/entry/EntryData.d.ts +13 -0
  220. package/dist/database/entry/EntryData.js +51 -0
  221. package/dist/database/entry/EntryTable.d.ts +173 -0
  222. package/dist/database/entry/EntryTable.js +137 -0
  223. package/dist/database/entry/EntryView.d.ts +22 -0
  224. package/dist/database/entry/EntryView.js +106 -0
  225. package/dist/database/query/Condition.d.ts +8 -0
  226. package/dist/database/query/Condition.js +117 -0
  227. package/dist/database/query/EntryQuery.d.ts +43 -0
  228. package/dist/database/query/EntryQuery.js +414 -0
  229. package/dist/database/query/EntryReferences.d.ts +6 -0
  230. package/dist/database/query/EntryReferences.js +68 -0
  231. package/dist/database/query/Relation.d.ts +11 -0
  232. package/dist/database/query/Relation.js +113 -0
  233. package/dist/database/query/ResolveQuery.d.ts +15 -0
  234. package/dist/database/query/ResolveQuery.js +154 -0
  235. package/dist/database/query/Search.d.ts +47 -0
  236. package/dist/database/query/Search.js +169 -0
  237. package/dist/database/sync/Derive.d.ts +8 -0
  238. package/dist/database/sync/Derive.js +270 -0
  239. package/dist/database/sync/EntryParser.d.ts +4 -0
  240. package/dist/database/sync/EntryParser.js +87 -0
  241. package/dist/database/sync/EntrySyncer.d.ts +37 -0
  242. package/dist/database/sync/EntrySyncer.js +117 -0
  243. package/dist/database/sync/Ingest.d.ts +21 -0
  244. package/dist/database/sync/Ingest.js +136 -0
  245. package/dist/database/sync/SyncQueries.d.ts +157 -0
  246. package/dist/database/sync/SyncQueries.js +192 -0
  247. package/dist/field/check/CheckField.view.js +2 -2
  248. package/dist/field/code/CodeField.view.js +7 -7
  249. package/dist/field/link/FileLink.js +1 -7
  250. package/dist/field/link/LinkField.js +23 -0
  251. package/dist/field/link/LinkField.view.js +44 -43
  252. package/dist/field/list/ListField.d.ts +5 -0
  253. package/dist/field/list/ListField.stories.d.ts +1 -0
  254. package/dist/field/list/ListField.view.js +190 -156
  255. package/dist/field/metadata/MetadataField.d.ts +28 -3
  256. package/dist/field/metadata/MetadataField.js +44 -7
  257. package/dist/field/metadata/MetadataField.view.d.ts +5 -0
  258. package/dist/field/metadata/MetadataField.view.js +37 -22
  259. package/dist/field/richtext/PickTextLink.d.ts +3 -1
  260. package/dist/field/richtext/PickTextLink.js +7 -6
  261. package/dist/field/richtext/RichTextDocument.js +12 -4
  262. package/dist/field/richtext/RichTextExtensions.d.ts +1 -1
  263. package/dist/field/richtext/RichTextExtensions.js +34 -30
  264. package/dist/field/richtext/RichTextField.d.ts +3 -0
  265. package/dist/field/richtext/RichTextField.view.js +20 -11
  266. package/dist/field/richtext/RichTextInsertMenu.js +3 -3
  267. package/dist/field/views.js +2 -0
  268. package/dist/index.css +17 -6
  269. package/dist/next.cjs +0 -18
  270. package/dist/next.d.ts +4 -3
  271. package/dist/next.edge.d.ts +1 -1
  272. package/dist/next.js +1 -2
  273. package/dist/picker/entry/EntryPicker.js +2 -1
  274. package/dist/picker/url/UrlPicker.js +1 -0
  275. package/dist/preview/widget.d.ts +16 -0
  276. package/dist/preview/widget.js +70 -1
  277. package/dist/query.d.ts +28 -0
  278. package/dist/ui/RichText.js +33 -18
  279. package/package.json +2 -1
  280. package/dist/backend/store/GeneratedSource.d.ts +0 -2
  281. package/dist/backend/store/GeneratedSource.js +0 -21
  282. package/dist/chunks/chunk-G6E35DMJ.js +0 -1997
  283. package/dist/core/db/EntryDB.d.ts +0 -19
  284. package/dist/core/db/EntryDB.js +0 -48
  285. package/dist/core/db/EntryIndex.d.ts +0 -143
  286. package/dist/core/db/EntryIndex.js +0 -2773
  287. package/dist/core/db/EntryReferenceIndex.d.ts +0 -21
  288. package/dist/core/db/EntryReferenceIndex.js +0 -131
  289. package/dist/core/db/EntryResolver.d.ts +0 -56
  290. package/dist/core/db/EntryResolver.js +0 -699
  291. package/dist/core/db/EntryTarget.d.ts +0 -5
  292. package/dist/core/db/EntryTransaction.d.ts +0 -31
  293. package/dist/core/db/EntryTransaction.js +0 -956
  294. package/dist/core/db/LocalDB.d.ts +0 -42
  295. package/dist/core/db/LocalDB.js +0 -127
  296. package/dist/core/db/TestDB.d.ts +0 -19
  297. package/dist/core/db/TestDB.js +0 -50
  298. /package/dist/core/db/{EntryTarget.js → LocalStore.js} +0 -0
@@ -0,0 +1,16 @@
1
+ import "../../chunks/chunk-CQ52GEHY.js";
2
+
3
+ // src/adapter/next/node.ts
4
+ import { generatedDatabase } from "alinea/backend/store/GeneratedDatabaseNode";
5
+ import { NextCMS } from "./cms.js";
6
+ import { createHandlerWithDatabase } from "./handler.js";
7
+ function createCMS(config) {
8
+ return new NextCMS(config, generatedDatabase);
9
+ }
10
+ function createHandler(input) {
11
+ return createHandlerWithDatabase(input, generatedDatabase);
12
+ }
13
+ export {
14
+ createCMS,
15
+ createHandler
16
+ };
@@ -1,10 +1,13 @@
1
+ import { type PreviewStats } from 'alinea/preview/widget';
1
2
  export interface NextPreviewsProps {
2
3
  dashboardUrl: string;
3
4
  widget?: boolean;
5
+ /** Resolves once the render's CMS queries settled. */
6
+ stats?: Promise<PreviewStats>;
4
7
  root?: string;
5
8
  workspace?: string;
6
9
  }
7
- export default function NextPreviews({ dashboardUrl, widget, root, workspace }: NextPreviewsProps): import("react").JSX.Element | null;
10
+ export default function NextPreviews({ dashboardUrl, widget, stats, root, workspace }: NextPreviewsProps): import("react").JSX.Element | null;
8
11
  /**
9
12
  * Wrapper around `router.refresh()` from `next/navigation` `useRouter()` to return Promise, and resolve after refresh completed
10
13
  * @returns Refresh function
@@ -11,12 +11,14 @@ import { jsx } from "react/jsx-runtime";
11
11
  function NextPreviews({
12
12
  dashboardUrl,
13
13
  widget,
14
+ stats,
14
15
  root,
15
16
  workspace
16
17
  }) {
17
18
  const refresh = useRouterRefresh();
18
19
  const [isLoading, setIsLoading] = useState(false);
19
20
  const [previewDisabled, setPreviewDisabled] = useState(false);
21
+ const [renderStats, setRenderStats] = useState();
20
22
  const pathname = usePathname();
21
23
  const adminUrl = new URL(dashboardUrl, location.origin);
22
24
  const host = window.parent !== window ? window.parent : window.opener;
@@ -43,15 +45,23 @@ function NextPreviews({
43
45
  useEffect(() => {
44
46
  if (widget) registerPreviewWidget();
45
47
  }, [widget]);
48
+ useEffect(() => {
49
+ let current = true;
50
+ stats?.then((value) => {
51
+ if (current) setRenderStats(JSON.stringify(value));
52
+ });
53
+ return () => {
54
+ current = false;
55
+ };
56
+ }, [stats]);
46
57
  if (!widget) return null;
47
- const isFullPage = window.parent === window;
48
- if (isFullPage && isPreviewing && !previewDisabled) return null;
49
58
  return /* @__PURE__ */ jsx(
50
59
  "alinea-preview",
51
60
  {
52
61
  adminUrl: String(adminUrl),
53
62
  editUrl: String(editUrl),
54
- livePreview: isPreviewing ? isLoading ? "loading" : previewDisabled ? "warning" : "connected" : void 0
63
+ livePreview: isPreviewing ? isLoading ? "loading" : previewDisabled ? "warning" : "connected" : void 0,
64
+ stats: renderStats
55
65
  }
56
66
  );
57
67
  }
@@ -0,0 +1,24 @@
1
+ import type { GraphQuery } from 'alinea/core/Graph';
2
+ import type { PreviewStat, PreviewStats } from 'alinea/preview/widget';
3
+ /** Collects the CMS queries and syncs of one draft render. */
4
+ export declare class RenderStats {
5
+ #private;
6
+ rows: Array<PreviewStat>;
7
+ statements: number;
8
+ sqlMs: number;
9
+ /** Add a row and count it as pending until `run` settles; see `timed`. */
10
+ track<T>(stat: Omit<PreviewStat, 'durationMs'>, run: (row: PreviewStat) => Promise<T>): Promise<T>;
11
+ statement(durationMs: number): void;
12
+ /**
13
+ * Resolves once nothing ran for `quietMs`, so queries of server components
14
+ * that render after the caller are counted, or after `maxMs` regardless.
15
+ */
16
+ settled(quietMs?: number, maxMs?: number): Promise<PreviewStats>;
17
+ }
18
+ /**
19
+ * Time the work a row stands for, such as answering a query without the sync
20
+ * it waited for.
21
+ */
22
+ export declare function timed<T>(row: PreviewStat | undefined, run: () => Promise<T>): Promise<T>;
23
+ /** A short description such as `first(type, url=/about)`. */
24
+ export declare function summarizeQuery(query: GraphQuery): string;
@@ -0,0 +1,74 @@
1
+ import "../../chunks/chunk-CQ52GEHY.js";
2
+
3
+ // src/adapter/next/renderStats.ts
4
+ var RenderStats = class {
5
+ rows = [];
6
+ statements = 0;
7
+ sqlMs = 0;
8
+ #pending = 0;
9
+ #idleSince = Date.now();
10
+ /** Add a row and count it as pending until `run` settles; see `timed`. */
11
+ async track(stat, run) {
12
+ const row = { ...stat, durationMs: 0 };
13
+ this.rows.push(row);
14
+ this.#pending++;
15
+ try {
16
+ return await run(row);
17
+ } finally {
18
+ this.#pending--;
19
+ this.#idleSince = Date.now();
20
+ }
21
+ }
22
+ statement(durationMs) {
23
+ this.statements++;
24
+ this.sqlMs += durationMs;
25
+ }
26
+ /**
27
+ * Resolves once nothing ran for `quietMs`, so queries of server components
28
+ * that render after the caller are counted, or after `maxMs` regardless.
29
+ */
30
+ async settled(quietMs = 50, maxMs = 5e3) {
31
+ const deadline = Date.now() + maxMs;
32
+ for (let now = Date.now(); now < deadline; now = Date.now()) {
33
+ const wait = this.#pending > 0 ? quietMs : this.#idleSince + quietMs - now;
34
+ if (wait <= 0) break;
35
+ await new Promise(
36
+ (resolve) => setTimeout(resolve, Math.min(wait, deadline - now))
37
+ );
38
+ }
39
+ const { rows, statements, sqlMs } = this;
40
+ return { rows: [...rows], statements, sqlMs };
41
+ }
42
+ };
43
+ async function timed(row, run) {
44
+ if (!row) return run();
45
+ const start = performance.now();
46
+ try {
47
+ return await run();
48
+ } finally {
49
+ row.durationMs += performance.now() - start;
50
+ }
51
+ }
52
+ var unlisted = /* @__PURE__ */ new Set([
53
+ "first",
54
+ "get",
55
+ "count",
56
+ "select",
57
+ "include",
58
+ "status",
59
+ "preview",
60
+ "syncInterval",
61
+ "disableSync"
62
+ ]);
63
+ function summarizeQuery(query) {
64
+ const mode = query.count ? "count" : query.get ? "get" : query.first ? "first" : "find";
65
+ const parts = Object.entries(query).filter(([key, value]) => !unlisted.has(key) && value !== void 0).map(
66
+ ([key, value]) => typeof value === "string" || typeof value === "number" ? `${key}=${value}` : key
67
+ );
68
+ return `${mode}(${parts.join(", ")})`;
69
+ }
70
+ export {
71
+ RenderStats,
72
+ summarizeQuery,
73
+ timed
74
+ };
@@ -1,5 +1,10 @@
1
1
  import type { Client } from 'alinea/core/Client';
2
- import type { LocalDB } from 'alinea/core/db/LocalDB';
2
+ import type { SyncOptions } from 'alinea/core/db/LocalStore';
3
+ import type { RemoteSource } from 'alinea/core/source/Source';
4
+ interface SyncableDB {
5
+ readonly sha: string | Promise<string>;
6
+ syncWith(source: RemoteSource, options?: SyncOptions): Promise<string>;
7
+ }
3
8
  export declare const CONTENT_SHA_TAG = "alinea-content-sha";
4
9
  export declare function revalidateContentSha(): Promise<void>;
5
10
  /**
@@ -9,4 +14,5 @@ export declare function revalidateContentSha(): Promise<void>;
9
14
  * Returns false when the sha could not be determined, so the caller falls
10
15
  * back to its existing throttle behavior.
11
16
  */
12
- export declare function syncIfStale(db: LocalDB, client: Client, syncInterval?: number): Promise<boolean>;
17
+ export declare function syncIfStale(db: SyncableDB, client: Client, syncInterval?: number, options?: SyncOptions): Promise<boolean>;
18
+ export {};
@@ -41,15 +41,15 @@ async function revalidateContentSha() {
41
41
  } catch {
42
42
  }
43
43
  }
44
- async function syncIfStale(db, client, syncInterval) {
44
+ async function syncIfStale(db, client, syncInterval, options) {
45
45
  if (syncInterval === Number.POSITIVE_INFINITY) return true;
46
46
  if (syncInterval === 0) {
47
- await db.syncWith(client);
47
+ await db.syncWith(client, options);
48
48
  return true;
49
49
  }
50
50
  const expected = await latestSha(client);
51
51
  if (!expected) return false;
52
- if (expected !== db.sha) await db.syncWith(client);
52
+ if (expected !== await db.sha) await db.syncWith(client, options);
53
53
  return true;
54
54
  }
55
55
  export {
@@ -27,7 +27,6 @@ function withAlinea(config = {}) {
27
27
  } catch {
28
28
  console.warn("Alinea could not determine Next.js version, assuming 15+");
29
29
  }
30
- const redirects = adminPath ? createRedirects(config, adminPath) : config.redirects;
31
30
  const rewrites = adminPath ? createRewrites(config, adminPath, settings.handlerUrl) : config.rewrites;
32
31
  const images = adminPath ? createImages(config, adminPath) : config.images;
33
32
  const env = settings ? {
@@ -45,7 +44,6 @@ function withAlinea(config = {}) {
45
44
  "@alinea/generated"
46
45
  ]
47
46
  },
48
- redirects,
49
47
  rewrites,
50
48
  images,
51
49
  env
@@ -56,7 +54,6 @@ function withAlinea(config = {}) {
56
54
  ...config.serverExternalPackages ?? [],
57
55
  "@alinea/generated"
58
56
  ],
59
- redirects,
60
57
  rewrites,
61
58
  images,
62
59
  env
@@ -82,21 +79,6 @@ function createImages(config, adminPath) {
82
79
  ]
83
80
  };
84
81
  }
85
- function createRedirects(config, adminPath) {
86
- const dev = process.env.ALINEA_DEV_SERVER;
87
- if (!dev) return config.redirects;
88
- return async () => {
89
- const existing = config.redirects ? await config.redirects() : [];
90
- return [
91
- ...existing,
92
- {
93
- permanent: true,
94
- source: `${adminPath}/~dev`,
95
- destination: `${dev}/~dev`
96
- }
97
- ];
98
- };
99
- }
100
82
  var emptyRewrites = {
101
83
  beforeFiles: [],
102
84
  afterFiles: [],
@@ -1,6 +1,6 @@
1
1
  import type { CMS } from 'alinea/core/CMS';
2
2
  import type { AuthedContext, RemoteConnection, RequestContext } from 'alinea/core/Connection';
3
- import { LocalDB } from 'alinea/core/db/LocalDB';
3
+ import type { LocalStore } from 'alinea/core/db/LocalStore';
4
4
  import type { Mutation } from 'alinea/core/db/Mutation';
5
5
  export interface Handler {
6
6
  (request: Request, context: RequestContext): Promise<Response>;
@@ -18,7 +18,7 @@ export interface HandlerHooks {
18
18
  }
19
19
  export interface HandlerOptions extends HandlerHooks {
20
20
  cms: CMS;
21
- db: LocalDB | Promise<LocalDB>;
21
+ db: LocalStore | Promise<LocalStore>;
22
22
  remote?: (context: RequestContext) => RemoteConnection;
23
23
  forwardMutations?(request: Request, context: AuthedContext): Promise<Response | undefined>;
24
24
  }
@@ -4,7 +4,7 @@ import {
4
4
  object,
5
5
  optional,
6
6
  string
7
- } from "../chunks/chunk-I4GC3E65.js";
7
+ } from "../chunks/chunk-UPY2RUZF.js";
8
8
  import {
9
9
  PLazy
10
10
  } from "../chunks/chunk-IKINPSS5.js";
@@ -19,8 +19,10 @@ import {
19
19
  } from "alinea/core/BlobTransport";
20
20
  import { Config } from "alinea/core/Config";
21
21
  import { developmentKeyHeader } from "alinea/core/Connection";
22
+ import { Entry } from "alinea/core/Entry";
22
23
  import { ErrorCode, HttpError } from "alinea/core/HttpError";
23
24
  import { MediaLocation } from "alinea/core/media/MediaLocation";
25
+ import { MediaFile } from "alinea/core/media/MediaTypes";
24
26
  import { assertUploadSize } from "alinea/core/media/UploadLimits";
25
27
  import { Permission, Policy } from "alinea/core/Role";
26
28
  import { getScope } from "alinea/core/Scope";
@@ -51,9 +53,18 @@ function createHandler({
51
53
  const local = await db;
52
54
  const simulateLatency = process.env.ALINEA_LATENCY;
53
55
  if (simulateLatency) await new Promise((resolve) => setTimeout(resolve, 2e3));
56
+ async function syncForRead(cnx) {
57
+ try {
58
+ await local.syncWith(cnx);
59
+ } catch (error) {
60
+ console.warn(
61
+ `Alinea could not sync with the remote, serving current content: ${error instanceof Error ? error.message : String(error)}`
62
+ );
63
+ }
64
+ }
54
65
  async function periodicSync(cnx, syncInterval) {
55
66
  if (dev) return;
56
- return throttle(() => local.syncWith(cnx), syncInterval);
67
+ return throttle(() => syncForRead(cnx), syncInterval);
57
68
  }
58
69
  try {
59
70
  const previews = new JWTPreviews(context.apiKey);
@@ -87,19 +98,29 @@ function createHandler({
87
98
  throw new HttpError(400, "Invalid file path");
88
99
  await periodicSync(cnx);
89
100
  const requestedUrl = Config.filePathname(cms.config, normalized);
90
- const entry = local.index.findByUrl(
91
- requestedUrl,
92
- (entry2) => entry2.type === "MediaFile" && entry2.status === "published" && entry2.main
93
- );
101
+ const select = {
102
+ url: Entry.url,
103
+ filePath: Entry.filePath,
104
+ workspace: Entry.workspace,
105
+ location: MediaFile.location,
106
+ previewUrl: MediaFile.previewUrl
107
+ };
108
+ const query = {
109
+ type: MediaFile,
110
+ status: "published",
111
+ main: true,
112
+ select
113
+ };
114
+ const entry = await local.first({ ...query, url: requestedUrl }) ?? await local.first({ ...query, alias: requestedUrl });
94
115
  if (!entry) return new Response("Not found", { status: 404 });
95
116
  if (entry.url !== requestedUrl && !proxy)
96
117
  return new Response(null, {
97
118
  status: 308,
98
119
  headers: { location: entry.url }
99
120
  });
100
- const wasBuilt = local.index.initialSync?.has(entry.filePath) ?? false;
101
- const previewUrl = entry.data.previewUrl;
102
- const location = entry.data.location;
121
+ const wasBuilt = await local.includedAtBuild(entry.filePath);
122
+ const previewUrl = entry.previewUrl;
123
+ const location = entry.location;
103
124
  if (typeof location !== "string")
104
125
  return new Response("Not found", { status: 404 });
105
126
  const previewSource = typeof previewUrl === "string" && previewUrl ? new URL(previewUrl, request.url).href : void 0;
@@ -245,8 +266,8 @@ function createHandler({
245
266
  );
246
267
  } else {
247
268
  const preview = await decodePreviewRequest(query.preview);
248
- if ("contentHash" in preview && local.sha !== preview.contentHash)
249
- await local.syncWith(cnx);
269
+ if ("contentHash" in preview && await local.sha !== preview.contentHash)
270
+ await syncForRead(cnx);
250
271
  query.preview = await applyPreview(local, preview);
251
272
  }
252
273
  return Response.json(await local.resolve(query) ?? null);
@@ -322,7 +343,7 @@ function createHandler({
322
343
  if (action === HandleAction.Tree && request.method === "GET") {
323
344
  expectJson();
324
345
  const sha = string(url.searchParams.get("sha"));
325
- await local.syncWith(cnx);
346
+ await syncForRead(cnx);
326
347
  const tree = await local.getTreeIfDifferent(sha);
327
348
  return compressResponse(request, Response.json(tree ?? null));
328
349
  }
@@ -1,8 +1,20 @@
1
1
  import {
2
2
  driver_exports
3
- } from "../../chunks/chunk-X47OVDF3.js";
4
- import "../../chunks/chunk-G6E35DMJ.js";
5
- import "../../chunks/chunk-NWQXN4SB.js";
3
+ } from "../../chunks/chunk-2U43BB6P.js";
4
+ import "../../chunks/chunk-A42DP5T7.js";
5
+ import "../../chunks/chunk-NLZLRQ5U.js";
6
+ import "../../chunks/chunk-IL7FJQAY.js";
7
+ import "../../chunks/chunk-M7KDJEGH.js";
8
+ import "../../chunks/chunk-N47Y62CI.js";
9
+ import "../../chunks/chunk-QBPYWU6C.js";
10
+ import "../../chunks/chunk-2BJ2IFQM.js";
11
+ import "../../chunks/chunk-XCZXR3C2.js";
12
+ import "../../chunks/chunk-TFMUSWGG.js";
13
+ import "../../chunks/chunk-76VMZTLN.js";
14
+ import "../../chunks/chunk-2PIFHEYR.js";
15
+ import "../../chunks/chunk-K62JP6HR.js";
16
+ import "../../chunks/chunk-ATF42T2B.js";
17
+ import "../../chunks/chunk-ETBQTP2S.js";
6
18
  import "../../chunks/chunk-CQ52GEHY.js";
7
19
 
8
20
  // src/backend/api/CreateBackend.ts
@@ -1,21 +1,29 @@
1
1
  import {
2
- Builder,
3
- Column,
4
- ColumnType,
5
- column,
6
- eq,
7
- jsonAggregateArray,
8
- jsonArray,
9
- querySelection,
10
- selectQuery,
2
+ include
3
+ } from "../../chunks/chunk-XTWYBWP2.js";
4
+ import {
5
+ blob,
6
+ id,
7
+ integer,
8
+ text,
9
+ varchar
10
+ } from "../../chunks/chunk-K7LHQXI4.js";
11
+ import {
12
+ Builder
13
+ } from "../../chunks/chunk-2BJ2IFQM.js";
14
+ import {
15
+ eq
16
+ } from "../../chunks/chunk-XCZXR3C2.js";
17
+ import {
11
18
  table
12
- } from "../../chunks/chunk-G6E35DMJ.js";
19
+ } from "../../chunks/chunk-TFMUSWGG.js";
20
+ import "../../chunks/chunk-76VMZTLN.js";
21
+ import "../../chunks/chunk-2PIFHEYR.js";
22
+ import "../../chunks/chunk-K62JP6HR.js";
23
+ import "../../chunks/chunk-ATF42T2B.js";
13
24
  import {
14
- getData,
15
- internalData,
16
- internalSql,
17
25
  sql
18
- } from "../../chunks/chunk-NWQXN4SB.js";
26
+ } from "../../chunks/chunk-ETBQTP2S.js";
19
27
  import {
20
28
  PLazy
21
29
  } from "../../chunks/chunk-IKINPSS5.js";
@@ -26,127 +34,6 @@ import { createId } from "alinea/core/Id";
26
34
  import { assert } from "alinea/core/util/Assert";
27
35
  import { basename, extname } from "alinea/core/util/Paths";
28
36
  import { slugify } from "alinea/core/util/Slugs";
29
-
30
- // node_modules/rado/dist/universal/columns.js
31
- var idType = new ColumnType(
32
- "id",
33
- [],
34
- sql.universal({
35
- sqlite: sql`integer`,
36
- postgres: sql`integer generated always as identity`,
37
- mysql: sql`int not null auto_increment`
38
- })
39
- );
40
- var blobType = new ColumnType(
41
- "blob",
42
- [],
43
- sql.universal({
44
- postgres: sql`bytea`,
45
- default: sql`blob`
46
- })
47
- );
48
- var numberType = new ColumnType(
49
- "number",
50
- [],
51
- sql.universal({
52
- mysql: sql`double`,
53
- default: sql`numeric`
54
- })
55
- );
56
- var jsonbType = new ColumnType(
57
- "json",
58
- [],
59
- sql.universal({
60
- mysql: sql`json`,
61
- default: sql`jsonb`
62
- })
63
- );
64
- function id(name) {
65
- return new Column({
66
- name,
67
- type: idType,
68
- primary: true,
69
- notNull: true
70
- });
71
- }
72
- function text(name) {
73
- return new Column({ name, type: column.text() });
74
- }
75
- function varchar(name, options) {
76
- return new Column({ name, type: column.varchar(options?.length) });
77
- }
78
- function integer(name) {
79
- return new Column({ name, type: column.integer() });
80
- }
81
- function blob(name) {
82
- return new Column({
83
- name,
84
- type: blobType,
85
- mapFromDriverValue(value) {
86
- return new Uint8Array(value);
87
- }
88
- });
89
- }
90
-
91
- // node_modules/rado/dist/core/expr/Include.js
92
- var Include = class {
93
- [internalData];
94
- constructor(data) {
95
- this[internalData] = data;
96
- }
97
- #mapFromDriverValue = (value, specs) => {
98
- const query = getData(this);
99
- const parsed = specs.parsesJson ? value : JSON.parse(value);
100
- const selected = querySelection(query);
101
- if (query.first) {
102
- const result = parsed ? selected.mapRow({ values: parsed, index: 0, specs }) : null;
103
- return result;
104
- }
105
- if (!parsed) return [];
106
- const rows = parsed;
107
- const ctx = {
108
- values: void 0,
109
- index: 0,
110
- specs
111
- };
112
- for (let i = 0; i < rows.length; i++) {
113
- ctx.values = rows[i];
114
- ctx.index = 0;
115
- rows[i] = selected.mapRow(ctx);
116
- }
117
- return rows ?? [];
118
- };
119
- get [internalSql]() {
120
- return includeQuery(getData(this)).mapWith({
121
- mapFromDriverValue: this.#mapFromDriverValue
122
- });
123
- }
124
- };
125
- function include(select) {
126
- return new Include({ ...getData(select), first: false });
127
- }
128
- ((include2) => {
129
- function one(select) {
130
- return new Include({
131
- ...getData(select),
132
- first: true
133
- });
134
- }
135
- include2.one = one;
136
- })(include || (include = {}));
137
- function includeQuery(query) {
138
- const { first, limit, offset, orderBy } = query;
139
- const wrapQuery = Boolean(limit || offset || orderBy);
140
- const innerQuery = selectQuery(query);
141
- const inner = wrapQuery ? sql`select * from (${innerQuery}) as __` : innerQuery;
142
- const fields = querySelection(query).fieldNames();
143
- const subject = jsonArray(
144
- ...fields.map((name) => sql`_.${sql.identifier(name)}`)
145
- );
146
- return sql`(select ${first ? subject : jsonAggregateArray(subject)} from (${inner}) as _)`;
147
- }
148
-
149
- // src/backend/api/DatabaseApi.ts
150
37
  import { HandleAction } from "../HandleAction.js";
151
38
  var UploadTable = table("alinea_upload", {
152
39
  entryId: varchar(void 0, { length: 27 }).primaryKey(),
@@ -1,8 +1,20 @@
1
1
  import {
2
2
  driver_exports
3
- } from "../../chunks/chunk-X47OVDF3.js";
4
- import "../../chunks/chunk-G6E35DMJ.js";
5
- import "../../chunks/chunk-NWQXN4SB.js";
3
+ } from "../../chunks/chunk-2U43BB6P.js";
4
+ import "../../chunks/chunk-A42DP5T7.js";
5
+ import "../../chunks/chunk-NLZLRQ5U.js";
6
+ import "../../chunks/chunk-IL7FJQAY.js";
7
+ import "../../chunks/chunk-M7KDJEGH.js";
8
+ import "../../chunks/chunk-N47Y62CI.js";
9
+ import "../../chunks/chunk-QBPYWU6C.js";
10
+ import "../../chunks/chunk-2BJ2IFQM.js";
11
+ import "../../chunks/chunk-XCZXR3C2.js";
12
+ import "../../chunks/chunk-TFMUSWGG.js";
13
+ import "../../chunks/chunk-76VMZTLN.js";
14
+ import "../../chunks/chunk-2PIFHEYR.js";
15
+ import "../../chunks/chunk-K62JP6HR.js";
16
+ import "../../chunks/chunk-ATF42T2B.js";
17
+ import "../../chunks/chunk-ETBQTP2S.js";
6
18
  import "../../chunks/chunk-CQ52GEHY.js";
7
19
 
8
20
  // src/backend/api/database.ts
@@ -1,9 +1,9 @@
1
- import type { LocalDB } from 'alinea/core/db/LocalDB';
2
1
  import { Entry } from 'alinea/core/Entry';
3
2
  import type { PreviewRequest, PreviewUpdate } from 'alinea/core/Preview';
3
+ import type { Graph } from 'alinea/core/Graph';
4
4
  export interface DecodedEntryPreview {
5
5
  entry: Entry;
6
6
  }
7
7
  export type DecodedPreviewRequest = PreviewUpdate | DecodedEntryPreview;
8
8
  export declare function decodePreviewRequest(preview: PreviewRequest): Promise<DecodedPreviewRequest>;
9
- export declare function applyPreview(local: LocalDB, preview: DecodedPreviewRequest): Promise<PreviewRequest | undefined>;
9
+ export declare function applyPreview(local: Graph, preview: DecodedPreviewRequest): Promise<PreviewRequest | undefined>;
@@ -5,6 +5,8 @@ import { Headers, Request } from "@alinea/iso";
5
5
  import { TLSSocket } from "node:tls";
6
6
  async function writeReadableStreamToWritable(stream, writable) {
7
7
  const reader = stream.getReader();
8
+ writable.once("close", () => reader.cancel().catch(() => {
9
+ }));
8
10
  async function read() {
9
11
  const { done, value } = await reader.read();
10
12
  if (done) return writable.end();
@@ -0,0 +1,5 @@
1
+ import type { Config } from 'alinea/core/Config';
2
+ import { EntryStore } from 'alinea/database/EntryStore';
3
+ import type { Database } from 'rado';
4
+ /** Add one writable, connection-local layer over a generated database. */
5
+ export declare function createGeneratedDatabase(config: Config, db: Database): Promise<EntryStore>;
@@ -0,0 +1,31 @@
1
+ import "../../chunks/chunk-CQ52GEHY.js";
2
+
3
+ // src/backend/store/GeneratedDatabase.ts
4
+ import { assertReadableData } from "alinea/database/entry/EntryData";
5
+ import { EntryDatabase } from "alinea/database/EntryDatabase";
6
+ import { EntryStore } from "alinea/database/EntryStore";
7
+ async function createGeneratedDatabase(config, db) {
8
+ let initialTree;
9
+ const base = new EntryDatabase(config, db, {
10
+ includedAtBuild(filePath) {
11
+ return initialTree?.has(filePath) ?? false;
12
+ }
13
+ });
14
+ try {
15
+ await assertReadableData(db);
16
+ initialTree = await base.getTree();
17
+ const overlay = await base.createOverlay();
18
+ return new EntryStore(config, overlay.database, overlay.source, {
19
+ close: async () => {
20
+ await overlay.close();
21
+ await base.close();
22
+ }
23
+ });
24
+ } catch (error) {
25
+ await base.close();
26
+ throw error;
27
+ }
28
+ }
29
+ export {
30
+ createGeneratedDatabase
31
+ };
@@ -0,0 +1,4 @@
1
+ import type { Config } from 'alinea/core/Config';
2
+ import type { DatabaseOptions } from 'rado';
3
+ /** Open the traced generated file through the native SQLite driver. */
4
+ export declare function generatedDatabase(config: Config, options?: DatabaseOptions): Promise<import("../../database/EntryStore.js").EntryStore>;