alinea 2.0.0-preview.4 → 2.0.0-preview.6

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 (187) hide show
  1. package/dist/.init/content/pages/welcome.json +1 -1
  2. package/dist/.init/src/cms.ts +1 -4
  3. package/dist/LICENSES.md +137 -137
  4. package/dist/adapter/next/cms.js +5 -1
  5. package/dist/adapter/next/handler.js +35 -6
  6. package/dist/adapter/next/previews.js +7 -1
  7. package/dist/adapter/next/syncCheck.d.ts +12 -0
  8. package/dist/adapter/next/syncCheck.js +59 -0
  9. package/dist/adapter/next/with-alinea.d.ts +0 -8
  10. package/dist/adapter/next/with-alinea.js +43 -19
  11. package/dist/adapter/vite/plugin.js +9 -4
  12. package/dist/backend/Handler.js +106 -0
  13. package/dist/backend/api/GithubApi.js +16 -7
  14. package/dist/backend/api/ProxyMedia.d.ts +3 -0
  15. package/dist/backend/api/ProxyMedia.js +39 -0
  16. package/dist/backend/api/S3Uploads.d.ts +1 -1
  17. package/dist/backend/router/Router.js +2 -0
  18. package/dist/backend/util/Syncable.js +1 -1
  19. package/dist/bundled.d.ts +166 -73
  20. package/dist/chunks/{chunk-XMOVGDFI.js → chunk-7IOKMUKO.js} +1 -1
  21. package/dist/chunks/{chunk-O7XWTMCB.js → chunk-D6RGFNUW.js} +73 -72
  22. package/dist/chunks/{chunk-VXZM6V4P.js → chunk-OFEKTDRF.js} +41 -41
  23. package/dist/cli/Generate.js +3 -4
  24. package/dist/cli/Serve.js +3 -2
  25. package/dist/cli/bin.js +1 -1
  26. package/dist/cli/generate/FillCache.d.ts +1 -1
  27. package/dist/cli/generate/FillCache.js +20 -9
  28. package/dist/cli/generate/GenerateDashboard.js +1 -0
  29. package/dist/cli/serve/CreateLocalServer.d.ts +1 -1
  30. package/dist/cli/serve/CreateLocalServer.js +42 -34
  31. package/dist/cli/serve/DevServer.js +1 -0
  32. package/dist/cli/static/init/cms.js +1 -4
  33. package/dist/cli/util/ContentType.d.ts +1 -0
  34. package/dist/cli/util/ContentType.js +36 -0
  35. package/dist/cli/util/Emitter.js +1 -1
  36. package/dist/cloud/CloudHandshake.d.ts +6 -0
  37. package/dist/cloud/CloudHandshake.js +67 -10
  38. package/dist/cloud/CloudRemote.js +24 -11
  39. package/dist/components/Breadcrumbs.js +7 -7
  40. package/dist/components/Button.js +5 -5
  41. package/dist/components/Calendar.js +7 -7
  42. package/dist/components/Checkbox.js +8 -8
  43. package/dist/components/CheckboxGroup.js +5 -5
  44. package/dist/components/ColorSwatch.js +5 -5
  45. package/dist/components/ColorSwatchPicker.js +7 -7
  46. package/dist/components/ComboBox.js +14 -14
  47. package/dist/components/DateField.js +8 -8
  48. package/dist/components/DatePicker.js +10 -10
  49. package/dist/components/DateRangePicker.js +11 -11
  50. package/dist/components/Dialog.js +5 -5
  51. package/dist/components/Disclosure.js +11 -11
  52. package/dist/components/DropZone.js +5 -5
  53. package/dist/components/Label.js +9 -9
  54. package/dist/components/Link.js +5 -5
  55. package/dist/components/List.d.ts +1 -1
  56. package/dist/components/List.js +37 -36
  57. package/dist/components/Menu.js +9 -9
  58. package/dist/components/Modal.js +8 -8
  59. package/dist/components/MultipleSelect.js +33 -33
  60. package/dist/components/NumberField.js +11 -11
  61. package/dist/components/Popover.js +5 -5
  62. package/dist/components/ProgressCircle.js +8 -8
  63. package/dist/components/RadioGroup.js +7 -7
  64. package/dist/components/SearchField.js +10 -10
  65. package/dist/components/Select.js +12 -12
  66. package/dist/components/Surface.js +3 -3
  67. package/dist/components/Switch.js +7 -7
  68. package/dist/components/Table.js +11 -11
  69. package/dist/components/Tabs.js +9 -9
  70. package/dist/components/TagGroup.js +7 -7
  71. package/dist/components/TextField.js +10 -10
  72. package/dist/components/TimeField.js +5 -5
  73. package/dist/components/Toggle.js +5 -5
  74. package/dist/components/Toolbar.js +6 -6
  75. package/dist/components/Tooltip.js +8 -8
  76. package/dist/components/Tree.js +13 -13
  77. package/dist/core/Config.d.ts +10 -3
  78. package/dist/core/Config.js +16 -1
  79. package/dist/core/Graph.d.ts +2 -2
  80. package/dist/core/Role.js +16 -14
  81. package/dist/core/TextDoc.d.ts +2 -0
  82. package/dist/core/TextDoc.js +1 -0
  83. package/dist/core/Workspace.d.ts +6 -5
  84. package/dist/core/db/EntryIndex.d.ts +3 -0
  85. package/dist/core/db/EntryIndex.js +55 -0
  86. package/dist/core/db/EntryTransaction.js +34 -32
  87. package/dist/core/db/EntryUrlConflictError.js +1 -1
  88. package/dist/core/db/LinkResolver.d.ts +8 -2
  89. package/dist/core/db/LinkResolver.js +27 -5
  90. package/dist/core/field/RichTextField.js +16 -10
  91. package/dist/core/media/MediaLocation.d.ts +9 -15
  92. package/dist/core/media/MediaLocation.js +29 -19
  93. package/dist/core/media/MediaTypes.js +1 -2
  94. package/dist/dashboard/App.js +4 -4
  95. package/dist/dashboard/app/ActivityStatus.js +31 -37
  96. package/dist/dashboard/app/AppShell.js +2 -2
  97. package/dist/dashboard/app/AuthView.js +12 -12
  98. package/dist/dashboard/app/Badge.js +2 -2
  99. package/dist/dashboard/app/CompactField.js +9 -9
  100. package/dist/dashboard/app/DashboardErrorBoundary.js +6 -6
  101. package/dist/dashboard/app/EntryFields.d.ts +3 -1
  102. package/dist/dashboard/app/EntryFields.js +11 -8
  103. package/dist/dashboard/app/EntryHeader.js +116 -84
  104. package/dist/dashboard/app/EntryHeaderActions.d.ts +21 -4
  105. package/dist/dashboard/app/EntryHeaderActions.js +48 -27
  106. package/dist/dashboard/app/EntryReferences.js +6 -6
  107. package/dist/dashboard/app/EntrySidebar.js +15 -15
  108. package/dist/dashboard/app/EntrySidebarPreview.js +4 -4
  109. package/dist/dashboard/app/EntryTranslationBanner.d.ts +3 -1
  110. package/dist/dashboard/app/EntryTranslationBanner.js +23 -20
  111. package/dist/dashboard/app/Explorer.d.ts +4 -2
  112. package/dist/dashboard/app/Explorer.js +53 -49
  113. package/dist/dashboard/app/ExplorerCards.js +31 -31
  114. package/dist/dashboard/app/ExplorerFileCard.js +16 -16
  115. package/dist/dashboard/app/ExplorerList.js +14 -15
  116. package/dist/dashboard/app/ExplorerModal.js +4 -4
  117. package/dist/dashboard/app/ExplorerTable.js +54 -54
  118. package/dist/dashboard/app/LinkPicker.js +5 -5
  119. package/dist/dashboard/app/LocaleMenu.d.ts +7 -0
  120. package/dist/dashboard/app/LocaleMenu.js +34 -18
  121. package/dist/dashboard/app/ReadOnlyBadge.d.ts +4 -0
  122. package/dist/dashboard/app/ReadOnlyBadge.js +33 -0
  123. package/dist/dashboard/app/SidebarTree.d.ts +3 -6
  124. package/dist/dashboard/app/SidebarTree.js +62 -57
  125. package/dist/dashboard/app/WorkspaceMenu.js +16 -16
  126. package/dist/dashboard/app/WorkspaceRoots.js +21 -21
  127. package/dist/dashboard/app/editor/FileEditor.d.ts +2 -3
  128. package/dist/dashboard/app/editor/FileEditor.js +24 -27
  129. package/dist/dashboard/app/editor/FilePreview.js +4 -4
  130. package/dist/dashboard/app/modals/CreateEntry.js +5 -5
  131. package/dist/dashboard/app/pages/EntryPage.js +72 -29
  132. package/dist/dashboard/app/pages/RootPage.js +3 -3
  133. package/dist/dashboard/app/pages/SplashPage.js +45 -45
  134. package/dist/dashboard/app/pages/UsersPage.js +36 -36
  135. package/dist/dashboard/app/ui/DashboardModal.js +21 -21
  136. package/dist/dashboard/app/ui/Rail.js +5 -5
  137. package/dist/dashboard/app/ui/Sidebar.js +2 -2
  138. package/dist/dashboard/atoms/activity.d.ts +0 -2
  139. package/dist/dashboard/atoms/activity.js +4 -10
  140. package/dist/dashboard/atoms/editor.d.ts +2 -1
  141. package/dist/dashboard/atoms/editor.js +4 -2
  142. package/dist/dashboard/atoms/entry.d.ts +2 -0
  143. package/dist/dashboard/atoms/entry.js +32 -14
  144. package/dist/dashboard/atoms/explorer.d.ts +4 -3
  145. package/dist/dashboard/atoms/explorer.js +61 -22
  146. package/dist/dashboard/atoms/link.d.ts +1 -1
  147. package/dist/dashboard/atoms/link.js +39 -55
  148. package/dist/dashboard/atoms/root.d.ts +7 -2
  149. package/dist/dashboard/atoms/root.js +51 -16
  150. package/dist/dashboard/atoms/upload.d.ts +1 -0
  151. package/dist/dashboard/atoms/upload.js +2 -1
  152. package/dist/dashboard/boot/ActivityEvent.d.ts +1 -1
  153. package/dist/dashboard/boot/DashboardWorker.js +2 -28
  154. package/dist/dashboard/fixture/cms.js +1 -4
  155. package/dist/dashboard/hook/UseSaveShortcut.d.ts +1 -0
  156. package/dist/dashboard/hook/UseSaveShortcut.js +24 -0
  157. package/dist/dashboard/hooks.d.ts +1 -1
  158. package/dist/dashboard/hooks.js +12 -3
  159. package/dist/field/check/CheckField.view.js +2 -2
  160. package/dist/field/code/CodeField.view.js +11 -11
  161. package/dist/field/date/DateField.view.js +5 -5
  162. package/dist/field/link/ImageLink.js +1 -3
  163. package/dist/field/link/LinkField.view.js +88 -62
  164. package/dist/field/list/ListField.view.js +25 -25
  165. package/dist/field/metadata/MetadataField.d.ts +3 -3
  166. package/dist/field/metadata/MetadataField.view.js +27 -20
  167. package/dist/field/object/ObjectField.view.js +11 -4
  168. package/dist/field/richtext/PickTextLink.js +5 -2
  169. package/dist/field/richtext/ReferenceLink.d.ts +2 -0
  170. package/dist/field/richtext/ReferenceLink.js +5 -0
  171. package/dist/field/richtext/RichTextBlock.js +2 -2
  172. package/dist/field/richtext/RichTextExtensions.js +24 -24
  173. package/dist/field/richtext/RichTextField.view.js +2 -2
  174. package/dist/field/richtext/RichTextInsertMenu.js +3 -3
  175. package/dist/field/richtext/extensions/Link.d.ts +1 -0
  176. package/dist/field/richtext/extensions/Link.js +1 -0
  177. package/dist/field/select/SelectField.view.js +1 -1
  178. package/dist/field/time/TimeField.d.ts +0 -2
  179. package/dist/field/time/TimeField.view.js +1 -1
  180. package/dist/index.css +44 -38
  181. package/dist/next.cjs +96 -19
  182. package/dist/picker/entry/EntryPicker.js +10 -12
  183. package/dist/picker/entry/EntryReference.d.ts +2 -0
  184. package/dist/picker/entry/EntryReference.js +1 -0
  185. package/dist/types.d.ts +0 -1
  186. package/package.json +1 -1
  187. package/dist/chunks/{chunk-6V4TAD2N.js → chunk-DNJX6CRV.js} +4 -4
@@ -312,31 +312,31 @@ var EntryTransaction = class {
312
312
  }
313
313
  #assertUniqueUrls(candidate) {
314
314
  const claims = this.#getUrlClaims();
315
- const urls = this.#candidateUrls(candidate);
316
- for (const url of urls) {
317
- const key = this.#urlClaimKey(candidate.workspace, candidate.root, url);
318
- const existing = claims.get(key);
319
- if (existing && existing.id !== candidate.id) {
320
- throw new EntryUrlConflictError({
321
- url,
322
- entryId: existing.id,
323
- workspace: candidate.workspace,
324
- root: candidate.root
325
- });
326
- }
327
- }
328
- for (const [key, claim] of claims) {
329
- if (claim.id === candidate.id) claims.delete(key);
330
- }
331
- for (const url of urls) {
332
- claims.set(this.#urlClaimKey(candidate.workspace, candidate.root, url), {
333
- id: candidate.id,
334
- url
315
+ const url = this.#resolvedUrl(candidate);
316
+ const key = this.#urlClaimKey(
317
+ candidate.workspace,
318
+ candidate.root,
319
+ candidate.type,
320
+ url
321
+ );
322
+ const existing = claims.get(key);
323
+ if (existing && existing.id !== candidate.id) {
324
+ throw new EntryUrlConflictError({
325
+ url,
326
+ entryId: existing.id,
327
+ workspace: existing.workspace,
328
+ root: existing.root
335
329
  });
336
330
  }
337
- }
338
- #candidateUrls(candidate) {
339
- return [this.#resolvedUrl(candidate), ...aliasUrlsFromData(candidate.data)];
331
+ for (const [claimedKey, claim] of claims) {
332
+ if (claim.id === candidate.id) claims.delete(claimedKey);
333
+ }
334
+ claims.set(key, {
335
+ id: candidate.id,
336
+ url,
337
+ workspace: candidate.workspace,
338
+ root: candidate.root
339
+ });
340
340
  }
341
341
  #resolvedUrl(candidate) {
342
342
  const type = this.#config.schema[candidate.type];
@@ -384,20 +384,22 @@ var EntryTransaction = class {
384
384
  for (const entry of this.#index.findMany((entry2) => {
385
385
  return entry2.status === "published";
386
386
  })) {
387
- for (const url of [
388
- this.#resolvedUrl(entry),
389
- ...aliasUrlsFromData(entry.data)
390
- ]) {
391
- claims.set(this.#urlClaimKey(entry.workspace, entry.root, url), {
387
+ const url = this.#resolvedUrl(entry);
388
+ claims.set(
389
+ this.#urlClaimKey(entry.workspace, entry.root, entry.type, url),
390
+ {
392
391
  id: entry.id,
393
- url
394
- });
395
- }
392
+ url,
393
+ workspace: entry.workspace,
394
+ root: entry.root
395
+ }
396
+ );
396
397
  }
397
398
  this.#urlClaims = claims;
398
399
  return claims;
399
400
  }
400
- #urlClaimKey(workspace, root, url) {
401
+ #urlClaimKey(workspace, root, type, url) {
402
+ if (type === "MediaFile") return `MediaFile\0${url}`;
401
403
  return `${workspace}\0${root}\0${url}`;
402
404
  }
403
405
  #persistSharedFields(id, locale, type, data) {
@@ -4,7 +4,7 @@ import "../../chunks/chunk-CQ52GEHY.js";
4
4
  var EntryUrlConflictError = class extends Error {
5
5
  constructor(info) {
6
6
  super(
7
- `URL "${info.url}" is already defined by entry ${info.entryId}. Remove or change this URL alias before publishing.`
7
+ `URL "${info.url}" is already defined by entry ${info.entryId} in workspace "${info.workspace}", root "${info.root}". Change the entry path or remove this URL alias before publishing.`
8
8
  );
9
9
  this.info = info;
10
10
  }
@@ -1,10 +1,16 @@
1
1
  import type { InferProjection, Projection } from 'alinea/core/Graph';
2
2
  import type { EntryResolver, ResolveContext } from './EntryResolver.js';
3
+ export interface LinkTarget {
4
+ entryId: string;
5
+ locale?: string;
6
+ }
3
7
  export declare class LinkResolver {
4
8
  resolver: EntryResolver;
5
9
  private ctx;
6
10
  locale: string | null;
7
11
  constructor(resolver: EntryResolver, ctx: ResolveContext, locale: string | null);
8
- includedAtBuild(filePath: string): boolean;
9
- resolveLinks<P extends Projection>(projection: P, entryIds: ReadonlyArray<string>): Promise<Array<InferProjection<P>>>;
12
+ resolveLinks<P extends Projection>(projection: P, entryIds: ReadonlyArray<string>, locale?: string | null | undefined): Promise<Array<InferProjection<P>>>;
13
+ resolveTargets<P extends Projection & {
14
+ id: unknown;
15
+ }>(projection: P, targets: ReadonlyArray<LinkTarget>): Promise<Array<InferProjection<P> | undefined>>;
10
16
  }
@@ -10,20 +10,42 @@ var LinkResolver = class {
10
10
  resolver;
11
11
  ctx;
12
12
  locale;
13
- includedAtBuild(filePath) {
14
- return this.resolver.index.initialSync?.has(filePath) ?? false;
15
- }
16
- async resolveLinks(projection, entryIds) {
13
+ async resolveLinks(projection, entryIds, locale = this.locale) {
17
14
  const { status, graph } = this.ctx;
18
15
  const results = await this.resolver.resolve({
19
16
  graph,
20
- preferredLocale: this.locale ?? void 0,
17
+ preferredLocale: locale ?? void 0,
21
18
  status,
22
19
  select: projection,
23
20
  id: { in: entryIds }
24
21
  });
25
22
  return results;
26
23
  }
24
+ async resolveTargets(projection, targets) {
25
+ const targetsByLocale = /* @__PURE__ */ new Map();
26
+ for (const { entryId, locale } of targets) {
27
+ const entryIds = targetsByLocale.get(locale) ?? /* @__PURE__ */ new Set();
28
+ entryIds.add(entryId);
29
+ targetsByLocale.set(locale, entryIds);
30
+ }
31
+ const resultsByLocale = /* @__PURE__ */ new Map();
32
+ await Promise.all(
33
+ Array.from(targetsByLocale, async ([locale, entryIds]) => {
34
+ const results = await this.resolveLinks(
35
+ projection,
36
+ [...entryIds],
37
+ locale
38
+ );
39
+ resultsByLocale.set(
40
+ locale,
41
+ new Map(results.map((result) => [String(result.id), result]))
42
+ );
43
+ })
44
+ );
45
+ return targets.map(
46
+ ({ entryId, locale }) => resultsByLocale.get(locale)?.get(entryId)
47
+ );
48
+ }
27
49
  };
28
50
  export {
29
51
  LinkResolver
@@ -1775,6 +1775,7 @@ import {
1775
1775
  } from "../Field.js";
1776
1776
  import { createId } from "../Id.js";
1777
1777
  import { mediaAltText } from "../media/MediaAltField.js";
1778
+ import { MediaLocation } from "../media/MediaLocation.js";
1778
1779
  import { MediaFile } from "../media/MediaTypes.js";
1779
1780
  import { Schema } from "../Schema.js";
1780
1781
  import {
@@ -1789,7 +1790,8 @@ import { slugify } from "../util/Slugs.js";
1789
1790
  var linkInfoFields = {
1790
1791
  id: Entry.id,
1791
1792
  url: Entry.url,
1792
- alt: MediaFile.alt
1793
+ alt: MediaFile.alt,
1794
+ hash: MediaFile.hash
1793
1795
  };
1794
1796
  var RichTextField = class extends Field {
1795
1797
  constructor(schema, meta) {
@@ -2044,7 +2046,8 @@ async function applyLinkMarks(doc, loader) {
2044
2046
  iterMarks(doc, (mark) => {
2045
2047
  if (mark[Mark.type] !== "link") return;
2046
2048
  const entryId = mark[LinkMark.entry];
2047
- if (typeof entryId === "string") links.set(mark, entryId);
2049
+ if (typeof entryId === "string")
2050
+ links.set(mark, { entryId, locale: mark[LinkMark.locale] });
2048
2051
  });
2049
2052
  const images = /* @__PURE__ */ new Map();
2050
2053
  iterImageNodes(doc, (node) => {
@@ -2054,11 +2057,14 @@ async function applyLinkMarks(doc, loader) {
2054
2057
  images.set(node, node._entry);
2055
2058
  }
2056
2059
  });
2057
- const linkIds = Array.from(/* @__PURE__ */ new Set([...links.values(), ...images.values()]));
2058
- const entries2 = await loader.resolveLinks(linkInfoFields, linkIds);
2059
- const info = new Map(entries2.map((entry) => [entry.id, entry]));
2060
- for (const [mark, entryId] of links) {
2061
- const data = info.get(entryId);
2060
+ const targets = [
2061
+ ...links.values(),
2062
+ ...Array.from(images.values(), (entryId) => ({ entryId }))
2063
+ ];
2064
+ const resolved = await loader.resolveTargets(linkInfoFields, targets);
2065
+ let index = 0;
2066
+ for (const [mark] of links) {
2067
+ const data = resolved[index++];
2062
2068
  if (!data) continue;
2063
2069
  const href = data.url;
2064
2070
  mark.href = applyUrlSuffix(
@@ -2067,10 +2073,10 @@ async function applyLinkMarks(doc, loader) {
2067
2073
  mark[LinkMark.anchor]
2068
2074
  );
2069
2075
  }
2070
- for (const [node, entryId] of images) {
2071
- const data = info.get(entryId);
2076
+ for (const [node] of images) {
2077
+ const data = resolved[index++];
2072
2078
  if (!data) continue;
2073
- node.src = data.url;
2079
+ node.src = MediaLocation.versionedUrl(data.url, data.hash);
2074
2080
  node.alt = mediaAltText(data.alt, loader.locale ?? void 0);
2075
2081
  }
2076
2082
  }
@@ -1,32 +1,22 @@
1
- import type { Config } from '../Config.js';
1
+ import { Config } from '../Config.js';
2
2
  export declare const MEDIA_LOCATION = "@alinea.location";
3
- export interface MediaUrlMeta {
3
+ export interface MediaPublicUrlMeta {
4
4
  /** The media entry path without its extension. */
5
5
  path: string;
6
6
  /** The paths of parent media directories. */
7
7
  parentPaths: Array<string>;
8
8
  /** The file extension, including its leading dot. */
9
9
  extension: string;
10
- /** The location stored in the media entry, excluding mediaDir. */
11
- location: string;
10
+ /** The workspace holding the media entry. */
12
11
  workspace: string;
13
- root: string;
14
- }
15
- export interface MediaUrlResolver {
16
- (meta: MediaUrlMeta): string;
17
- }
18
- export interface MediaPublicUrlMeta extends Omit<MediaUrlMeta, 'parentPaths'> {
19
- /** @deprecated Pass parentPaths directly when available. */
20
- entryUrl?: string;
21
- parentPaths?: Array<string>;
22
12
  }
23
13
  export interface MediaEntryUrlMeta {
24
14
  defaultUrl: string;
25
15
  parentPaths: Array<string>;
26
16
  path: string;
27
- workspace: string;
28
- root: string;
29
17
  data: Record<string, unknown>;
18
+ /** The workspace holding the media entry. */
19
+ workspace: string;
30
20
  }
31
21
  /** Maps media entry locations between storage and public URLs. */
32
22
  export declare namespace MediaLocation {
@@ -36,8 +26,12 @@ export declare namespace MediaLocation {
36
26
  function storagePath(config: Config, workspace: string, location: string): string;
37
27
  /** Remove the workspace storage directory from a prepared upload location. */
38
28
  function entryLocation(config: Config, workspace: string, location: string): string;
29
+ /** Resolve the deployed public location of a stored media file. */
30
+ function sourceUrl(config: Config, workspace: string, location: string): string | undefined;
39
31
  /** Resolve the public URL used to serve a media entry. */
40
32
  function publicUrl(config: Config, meta: MediaPublicUrlMeta): string;
33
+ /** Add an immutable media version without changing its canonical path. */
34
+ function versionedUrl(url: string, version: string | undefined): string;
41
35
  /** Resolve a media entry URL, falling back to its regular entry URL. */
42
36
  function entryUrl(config: Config, meta: MediaEntryUrlMeta): string;
43
37
  }
@@ -1,9 +1,9 @@
1
1
  import "../../chunks/chunk-CQ52GEHY.js";
2
2
 
3
3
  // src/core/media/MediaLocation.ts
4
+ import { Config } from "../Config.js";
4
5
  import { Workspace } from "../Workspace.js";
5
- import { join, normalize } from "../util/Paths.js";
6
- import { joinPaths } from "../util/Urls.js";
6
+ import { contains, join, normalize, relative } from "../util/Paths.js";
7
7
  var MEDIA_LOCATION = "@alinea.location";
8
8
  var MediaLocation;
9
9
  ((MediaLocation2) => {
@@ -18,36 +18,46 @@ var MediaLocation;
18
18
  function entryLocation(config, workspace, location) {
19
19
  const mediaDir = directory(config, workspace);
20
20
  if (!mediaDir) return location;
21
- const prefix = normalize(mediaDir).replace(/\/$/, "");
22
- if (location === prefix) return "";
23
- return location.startsWith(`${prefix}/`) ? location.slice(prefix.length) : location;
21
+ const normalizedDir = join("/", normalize(mediaDir));
22
+ const normalizedLocation = join("/", normalize(location));
23
+ if (normalizedLocation === normalizedDir) return "";
24
+ if (!contains(normalizedDir, normalizedLocation)) return location;
25
+ return join("/", relative(normalizedDir, normalizedLocation));
24
26
  }
25
27
  MediaLocation2.entryLocation = entryLocation;
28
+ function sourceUrl(config, workspace, location) {
29
+ if (/^https?:\/\//.test(location)) return;
30
+ if (!directory(config, workspace)) return join("/", location);
31
+ const publicDir = join("/", config.publicDir ?? "/public");
32
+ const storage = join("/", storagePath(config, workspace, location));
33
+ if (!contains(publicDir, storage)) return;
34
+ return join("/", relative(publicDir, storage));
35
+ }
36
+ MediaLocation2.sourceUrl = sourceUrl;
26
37
  function publicUrl(config, meta) {
27
- const { entryUrl: entryUrl2, parentPaths, ...media } = meta;
28
- const { location, workspace } = meta;
29
- const { mediaUrl } = Workspace.data(config.workspaces[workspace]);
30
- if (!mediaUrl) return location;
31
- if (typeof mediaUrl === "function") {
32
- return mediaUrl({
33
- ...media,
34
- parentPaths: parentPaths ?? entryUrl2?.split("/").filter(Boolean).slice(0, -1) ?? []
35
- });
36
- }
37
- return joinPaths(mediaUrl, location);
38
+ const file = join(...meta.parentPaths, `${meta.path}${meta.extension}`);
39
+ const mediaUrl = Workspace.data(config.workspaces[meta.workspace]).mediaUrl;
40
+ return Config.filePathname(config, join(mediaUrl, file));
38
41
  }
39
42
  MediaLocation2.publicUrl = publicUrl;
43
+ function versionedUrl(url, version) {
44
+ if (!version) return url;
45
+ const fragmentAt = url.indexOf("#");
46
+ const base = fragmentAt === -1 ? url : url.slice(0, fragmentAt);
47
+ const fragment = fragmentAt === -1 ? "" : url.slice(fragmentAt);
48
+ const separator = base.includes("?") ? "&" : "?";
49
+ return `${base}${separator}v=${encodeURIComponent(version)}${fragment}`;
50
+ }
51
+ MediaLocation2.versionedUrl = versionedUrl;
40
52
  function entryUrl(config, meta) {
41
- const { data, defaultUrl, parentPaths, path, root, workspace } = meta;
53
+ const { data, defaultUrl, parentPaths, path, workspace } = meta;
42
54
  const { extension, location } = data;
43
55
  if (typeof extension !== "string" || typeof location !== "string")
44
56
  return defaultUrl;
45
57
  return publicUrl(config, {
46
58
  extension,
47
- location,
48
59
  parentPaths,
49
60
  path,
50
- root,
51
61
  workspace
52
62
  });
53
63
  }
@@ -21,13 +21,12 @@ var MediaLibrary = type("Media directory", {
21
21
  });
22
22
  var MediaFile = type("Media file", {
23
23
  hidden: true,
24
- entryUrl({ config, data, defaultUrl, parentPaths, path: path2, root, workspace }) {
24
+ entryUrl({ config, data, defaultUrl, parentPaths, path: path2, workspace }) {
25
25
  return MediaLocation.entryUrl(config, {
26
26
  data,
27
27
  defaultUrl,
28
28
  parentPaths,
29
29
  path: path2,
30
- root,
31
30
  workspace
32
31
  });
33
32
  },
@@ -22,11 +22,11 @@ import {
22
22
 
23
23
  // src/dashboard/App.module.css
24
24
  var App_default = {
25
- "AppLoading": "alinea-AppLoading",
25
+ "AppLoading-progress-fade-in": "alinea-AppLoading-progress-fade-in",
26
+ "AppLoadingProgressFadeIn": "alinea-AppLoading-progress-fade-in",
26
27
  "AppLoading-progress": "alinea-AppLoading-progress",
27
28
  "AppLoadingProgress": "alinea-AppLoading-progress",
28
- "AppLoading-progress-fade-in": "alinea-AppLoading-progress-fade-in",
29
- "AppLoadingProgressFadeIn": "alinea-AppLoading-progress-fade-in"
29
+ "AppLoading": "alinea-AppLoading"
30
30
  };
31
31
 
32
32
  // src/dashboard/App.tsx
@@ -196,7 +196,7 @@ function DashboardApp(props) {
196
196
  const [appPending, app] = useAtomValueRaw(appAtom);
197
197
  const activity = useAtomValueRaw(activityAtom);
198
198
  const [, setActivityPending] = useAtom(activityPendingAtom);
199
- const pending = appPending || activity.isFetchingUpdates || activity.isMutating;
199
+ const pending = appPending || activity.isMutating;
200
200
  useEffect(() => {
201
201
  setActivityPending(pending);
202
202
  }, [pending, setActivityPending]);
@@ -1,8 +1,15 @@
1
+ import "../../chunks/chunk-NUFRM6SI.js";
1
2
  import {
2
3
  useAtomValueRaw,
3
4
  useSetAtom
4
5
  } from "../../chunks/chunk-D6UJHBJJ.js";
5
6
  import "../../chunks/chunk-CFNRVI3Y.js";
7
+ import {
8
+ $e260d131964da0f9$export$872b660ac5a1ff98
9
+ } from "../../chunks/chunk-D6RGFNUW.js";
10
+ import "../../chunks/chunk-RKDPDEF7.js";
11
+ import "../../chunks/chunk-SJBZFMQ2.js";
12
+ import "../../chunks/chunk-S4AU6SRS.js";
6
13
  import {
7
14
  dist_default
8
15
  } from "../../chunks/chunk-I4OYYAX5.js";
@@ -42,29 +49,29 @@ import { IcRoundCheck, IcRoundHistory, IcRoundWarning } from "../icons.js";
42
49
 
43
50
  // src/dashboard/app/ActivityStatus.module.css
44
51
  var ActivityStatus_default = {
52
+ "ActivityStatus-icon": "alinea-ActivityStatus-icon",
53
+ "ActivityStatusIcon": "alinea-ActivityStatus-icon",
54
+ "ActivityStatus-popover-title": "alinea-ActivityStatus-popover-title",
55
+ "ActivityStatusPopoverTitle": "alinea-ActivityStatus-popover-title",
56
+ "ActivityStatus-popover-actions": "alinea-ActivityStatus-popover-actions",
57
+ "ActivityStatusPopoverActions": "alinea-ActivityStatus-popover-actions",
58
+ "ActivityStatus-popover-item-error": "alinea-ActivityStatus-popover-item-error",
59
+ "ActivityStatusPopoverItemError": "alinea-ActivityStatus-popover-item-error",
45
60
  "is-syncing": "alinea-is-syncing",
46
61
  "isSyncing": "alinea-is-syncing",
47
- "is-failed": "alinea-is-failed",
48
- "isFailed": "alinea-is-failed",
62
+ "ActivityStatus": "alinea-ActivityStatus",
49
63
  "ActivityStatus-label": "alinea-ActivityStatus-label",
50
64
  "ActivityStatusLabel": "alinea-ActivityStatus-label",
51
65
  "ActivityStatus-popover": "alinea-ActivityStatus-popover",
52
66
  "ActivityStatusPopover": "alinea-ActivityStatus-popover",
53
67
  "ActivityStatus-popover-header": "alinea-ActivityStatus-popover-header",
54
68
  "ActivityStatusPopoverHeader": "alinea-ActivityStatus-popover-header",
55
- "ActivityStatus": "alinea-ActivityStatus",
56
- "ActivityStatus-popover-surface": "alinea-ActivityStatus-popover-surface",
57
- "ActivityStatusPopoverSurface": "alinea-ActivityStatus-popover-surface",
58
69
  "ActivityStatus-popover-list": "alinea-ActivityStatus-popover-list",
59
70
  "ActivityStatusPopoverList": "alinea-ActivityStatus-popover-list",
60
- "ActivityStatus-popover-item-error": "alinea-ActivityStatus-popover-item-error",
61
- "ActivityStatusPopoverItemError": "alinea-ActivityStatus-popover-item-error",
62
- "ActivityStatus-icon": "alinea-ActivityStatus-icon",
63
- "ActivityStatusIcon": "alinea-ActivityStatus-icon",
64
- "ActivityStatus-popover-title": "alinea-ActivityStatus-popover-title",
65
- "ActivityStatusPopoverTitle": "alinea-ActivityStatus-popover-title",
66
- "ActivityStatus-popover-actions": "alinea-ActivityStatus-popover-actions",
67
- "ActivityStatusPopoverActions": "alinea-ActivityStatus-popover-actions"
71
+ "is-failed": "alinea-is-failed",
72
+ "isFailed": "alinea-is-failed",
73
+ "ActivityStatus-popover-surface": "alinea-ActivityStatus-popover-surface",
74
+ "ActivityStatusPopoverSurface": "alinea-ActivityStatus-popover-surface"
68
75
  };
69
76
 
70
77
  // src/dashboard/app/ActivityStatus.tsx
@@ -100,6 +107,12 @@ function ActivityStatus({
100
107
  const retry = useSetAtom(retryActivityAtom);
101
108
  const discard = useSetAtom(discardActivityAtom);
102
109
  const [isOpen, setIsOpen] = useState(false);
110
+ const panelRef = useRef(null);
111
+ $e260d131964da0f9$export$872b660ac5a1ff98({
112
+ ref: panelRef,
113
+ onInteractOutside: () => setIsOpen(false),
114
+ isDisabled: !isOpen
115
+ });
103
116
  const isMobile = useSyncExternalStore(
104
117
  mobilePlacement ? subscribeToMobileActivity : ignoreActivityBreakpoint,
105
118
  mobilePlacement ? mobileActivitySnapshot : desktopActivitySnapshot,
@@ -107,11 +120,7 @@ function ActivityStatus({
107
120
  );
108
121
  const wasFailed = useRef(false);
109
122
  const lastActivityLabel = useRef("Finishing up");
110
- const activityLabel = getActivityLabel(
111
- activity.isFetchingUpdates,
112
- appPending,
113
- activity.isMutating
114
- );
123
+ const activityLabel = getActivityLabel(appPending, activity.isMutating);
115
124
  const showSpinner = useAtomValueRaw(activityPendingAtom);
116
125
  if (activityLabel !== void 0) lastActivityLabel.current = activityLabel;
117
126
  const visibleActivityLabel = activityLabel ?? (showSpinner ? lastActivityLabel.current : void 0);
@@ -191,13 +200,14 @@ function ActivityStatus({
191
200
  Popover,
192
201
  {
193
202
  className: styles.ActivityStatus.popover.surface(),
203
+ isNonModal: true,
194
204
  placement: isMobile ? mobilePlacement : placement,
195
205
  offset: 16,
196
206
  style: {
197
207
  padding: "0",
198
208
  boxShadow: "0 8px 20px rgba(0, 0, 0, 0.12)"
199
209
  },
200
- children: /* @__PURE__ */ jsxs("div", { className: styles.ActivityStatus.popover(), children: [
210
+ children: /* @__PURE__ */ jsxs("div", { ref: panelRef, className: styles.ActivityStatus.popover(), children: [
201
211
  /* @__PURE__ */ jsxs("div", { className: styles.ActivityStatus.popover.header(), children: [
202
212
  /* @__PURE__ */ jsx("h2", { className: styles.ActivityStatus.popover.title(), children: "Activity" }),
203
213
  activity.hasFailed && /* @__PURE__ */ jsxs("div", { className: styles.ActivityStatus.popover.actions(), children: [
@@ -274,8 +284,7 @@ function ActivityItem({ activity }) {
274
284
  }
275
285
  );
276
286
  }
277
- function getActivityLabel(isFetchingUpdates, isNavigating, isMutating) {
278
- if (isFetchingUpdates) return "Fetching updates";
287
+ function getActivityLabel(isNavigating, isMutating) {
279
288
  if (isNavigating) return "Loading page";
280
289
  if (isMutating) return "Syncing changes";
281
290
  }
@@ -292,12 +301,10 @@ function formatActivityStatus(activity) {
292
301
  case "pending":
293
302
  return "Pending";
294
303
  case "running":
295
- if (activity.type === "fetch") return "Fetching";
296
304
  if (activity.type === "upload") return "Uploading";
297
305
  if (isFileActivity(activity)) return "Saving";
298
306
  return "Syncing";
299
307
  case "succeeded":
300
- if (activity.type === "fetch") return "Up to date";
301
308
  if (isFileActivity(activity)) return "Uploaded";
302
309
  return "Synced";
303
310
  case "failed":
@@ -337,11 +344,6 @@ function activityStatusTone(status) {
337
344
  }
338
345
  }
339
346
  function formatActivityTitle(activity) {
340
- if (activity.type === "fetch") {
341
- if (activity.status === "running") return "Fetching updates";
342
- if (activity.status === "failed") return "Fetching updates failed";
343
- return "Checked for updates";
344
- }
345
347
  const uploadTitle = formatUploadTitle(activity);
346
348
  if (uploadTitle) return uploadTitle;
347
349
  const titles = [
@@ -355,9 +357,7 @@ function formatActivityTitle(activity) {
355
357
  return "Content changes";
356
358
  }
357
359
  function formatActivityDescription(activity) {
358
- const details = activity.type === "fetch" ? fetchDescription(activity.status) : activity.type === "mutation" && isFileActivity(activity) ? fileMutationDescription(activity.status) : activity.operations.map(
359
- (operation) => formatActivityOperation(operation, activity.status)
360
- ).join(" \xB7 ");
360
+ const details = activity.type === "mutation" && isFileActivity(activity) ? fileMutationDescription(activity.status) : activity.operations.map((operation) => formatActivityOperation(operation, activity.status)).join(" \xB7 ");
361
361
  const timestamp = activity.finishedAt ?? activity.startedAt;
362
362
  const time = new Date(timestamp).toLocaleTimeString([], {
363
363
  hour: "2-digit",
@@ -390,12 +390,6 @@ function fileMutationDescription(status) {
390
390
  if (status === "discarded") return "Upload discarded.";
391
391
  return "Upload cancelled.";
392
392
  }
393
- function fetchDescription(status) {
394
- if (status === "running") return "Checking for content changes.";
395
- if (status === "succeeded") return "Content is up to date.";
396
- if (status === "failed") return "Could not check for content changes.";
397
- return "Content update check.";
398
- }
399
393
  function formatActivityOperation(operation, activityStatus) {
400
394
  const progress = operation.progress ? ` ${formatProgress(operation.progress)}` : "";
401
395
  const status = operation.status ? ` ${formatEntryStatus(operation.status)}` : "";
@@ -5,9 +5,9 @@ import "../../chunks/chunk-CQ52GEHY.js";
5
5
 
6
6
  // src/dashboard/app/AppShell.module.css
7
7
  var AppShell_default = {
8
- "AppShellContent": "alinea-AppShellContent",
8
+ "AppShell": "alinea-AppShell",
9
9
  "AppShellInner": "alinea-AppShellInner",
10
- "AppShell": "alinea-AppShell"
10
+ "AppShellContent": "alinea-AppShellContent"
11
11
  };
12
12
 
13
13
  // src/dashboard/app/AppShell.tsx
@@ -16,25 +16,25 @@ import { IcRoundArrowForward, IcRoundPublish } from "../icons.js";
16
16
 
17
17
  // src/dashboard/app/AuthView.module.css
18
18
  var AuthView_default = {
19
- "AuthView-surface": "alinea-AuthView-surface",
20
- "AuthViewSurface": "alinea-AuthView-surface",
21
- "AuthView": "alinea-AuthView",
22
- "AuthView-link": "alinea-AuthView-link",
23
- "AuthViewLink": "alinea-AuthView-link",
24
- "AuthView-actionRow": "alinea-AuthView-actionRow",
25
- "AuthViewActionRow": "alinea-AuthView-actionRow",
26
- "AuthView-loader": "alinea-AuthView-loader",
27
- "AuthViewLoader": "alinea-AuthView-loader",
28
- "AuthView-panel": "alinea-AuthView-panel",
29
- "AuthViewPanel": "alinea-AuthView-panel",
30
19
  "AuthView-heading": "alinea-AuthView-heading",
31
20
  "AuthViewHeading": "alinea-AuthView-heading",
32
21
  "AuthView-mark": "alinea-AuthView-mark",
33
22
  "AuthViewMark": "alinea-AuthView-mark",
23
+ "AuthView-link": "alinea-AuthView-link",
24
+ "AuthViewLink": "alinea-AuthView-link",
34
25
  "AuthView-text": "alinea-AuthView-text",
35
26
  "AuthViewText": "alinea-AuthView-text",
27
+ "AuthView-panel": "alinea-AuthView-panel",
28
+ "AuthViewPanel": "alinea-AuthView-panel",
36
29
  "AuthView-title": "alinea-AuthView-title",
37
- "AuthViewTitle": "alinea-AuthView-title"
30
+ "AuthViewTitle": "alinea-AuthView-title",
31
+ "AuthView-actionRow": "alinea-AuthView-actionRow",
32
+ "AuthViewActionRow": "alinea-AuthView-actionRow",
33
+ "AuthView-surface": "alinea-AuthView-surface",
34
+ "AuthViewSurface": "alinea-AuthView-surface",
35
+ "AuthView-loader": "alinea-AuthView-loader",
36
+ "AuthViewLoader": "alinea-AuthView-loader",
37
+ "AuthView": "alinea-AuthView"
38
38
  };
39
39
 
40
40
  // src/dashboard/app/AuthView.tsx
@@ -8,9 +8,9 @@ import { Icon } from "../../components/Icon.js";
8
8
 
9
9
  // src/dashboard/app/Badge.module.css
10
10
  var Badge_default = {
11
+ "Badge": "alinea-Badge",
11
12
  "Badge-label": "alinea-Badge-label",
12
- "BadgeLabel": "alinea-Badge-label",
13
- "Badge": "alinea-Badge"
13
+ "BadgeLabel": "alinea-Badge-label"
14
14
  };
15
15
 
16
16
  // src/dashboard/app/Badge.tsx
@@ -19,25 +19,25 @@ import { Badge } from "./Badge.js";
19
19
 
20
20
  // src/dashboard/app/CompactField.module.css
21
21
  var CompactField_default = {
22
+ "CompactField-muted": "alinea-CompactField-muted",
23
+ "CompactFieldMuted": "alinea-CompactField-muted",
22
24
  "CompactField-json": "alinea-CompactField-json",
23
25
  "CompactFieldJson": "alinea-CompactField-json",
24
- "CompactField-record": "alinea-CompactField-record",
25
- "CompactFieldRecord": "alinea-CompactField-record",
26
- "CompactField": "alinea-CompactField",
27
26
  "CompactField-record-value": "alinea-CompactField-record-value",
28
27
  "CompactFieldRecordValue": "alinea-CompactField-record-value",
28
+ "CompactField-record-field": "alinea-CompactField-record-field",
29
+ "CompactFieldRecordField": "alinea-CompactField-record-field",
30
+ "CompactField": "alinea-CompactField",
29
31
  "CompactField-record-label": "alinea-CompactField-record-label",
30
32
  "CompactFieldRecordLabel": "alinea-CompactField-record-label",
31
- "CompactField-items": "alinea-CompactField-items",
32
- "CompactFieldItems": "alinea-CompactField-items",
33
- "CompactField-muted": "alinea-CompactField-muted",
34
- "CompactFieldMuted": "alinea-CompactField-muted",
35
33
  "CompactField-list-count": "alinea-CompactField-list-count",
36
34
  "CompactFieldListCount": "alinea-CompactField-list-count",
37
35
  "CompactField-text": "alinea-CompactField-text",
38
36
  "CompactFieldText": "alinea-CompactField-text",
39
- "CompactField-record-field": "alinea-CompactField-record-field",
40
- "CompactFieldRecordField": "alinea-CompactField-record-field"
37
+ "CompactField-items": "alinea-CompactField-items",
38
+ "CompactFieldItems": "alinea-CompactField-items",
39
+ "CompactField-record": "alinea-CompactField-record",
40
+ "CompactFieldRecord": "alinea-CompactField-record"
41
41
  };
42
42
 
43
43
  // src/dashboard/app/CompactField.tsx