alinea 2.0.0-preview.0 → 2.0.0-preview.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.init/content/pages/welcome.json +1 -1
- package/dist/LICENSES.md +134 -80
- package/dist/adapter/next/DevRemote.d.ts +3 -0
- package/dist/adapter/next/DevRemote.js +37 -0
- package/dist/adapter/next/ForwardCredentials.d.ts +1 -0
- package/dist/adapter/next/ForwardCredentials.js +17 -0
- package/dist/adapter/next/cms.js +86 -38
- package/dist/adapter/next/context.d.ts +1 -1
- package/dist/adapter/next/context.js +11 -3
- package/dist/adapter/next/handler.d.ts +2 -0
- package/dist/adapter/next/handler.js +23 -16
- package/dist/adapter/next/with-alinea.js +18 -16
- package/dist/backend/Handler.d.ts +14 -13
- package/dist/backend/Handler.js +70 -36
- package/dist/backend/resolver/ParsePreview.d.ts +8 -4
- package/dist/backend/resolver/ParsePreview.js +40 -43
- package/dist/backend/router/Router.d.ts +1 -0
- package/dist/backend/router/Router.js +21 -15
- package/dist/bundled.d.ts +369 -99
- package/dist/chunks/chunk-6UT4N4CO.js +919 -0
- package/dist/chunks/{chunk-LUBOGJCG.js → chunk-6V4TAD2N.js} +1 -1
- package/dist/chunks/{chunk-TL7ZW6BX.js → chunk-A3XXZBOQ.js} +2535 -2999
- package/dist/chunks/chunk-AC5ATYI3.js +1434 -0
- package/dist/chunks/{chunk-7ORQ7BYK.js → chunk-KMLLLZ6X.js} +202 -269
- package/dist/chunks/{chunk-IWN3T3FL.js → chunk-O7XWTMCB.js} +1 -1
- package/dist/chunks/{chunk-53DZYORR.js → chunk-PAYSVIYI.js} +76 -176
- package/dist/chunks/{chunk-YK3OSMDM.js → chunk-S4AU6SRS.js} +188 -158
- package/dist/chunks/{chunk-EQ3TDHYD.js → chunk-UVOEM4AH.js} +6 -3
- package/dist/chunks/{chunk-I7X64JTZ.js → chunk-VXZM6V4P.js} +4 -4
- package/dist/cli/Generate.js +3 -13
- package/dist/cli/Serve.js +7 -3
- package/dist/cli/bin.js +8 -5
- package/dist/cli/generate/CompileConfig.js +3 -2
- package/dist/cli/generate/CopyStaticFiles.js +2 -3
- package/dist/cli/generate/DevDB.d.ts +1 -1
- package/dist/cli/generate/DevDB.js +3 -5
- package/dist/cli/serve/CreateLocalServer.d.ts +1 -1
- package/dist/cli/serve/CreateLocalServer.js +3 -2
- package/dist/cli/serve/DevServer.d.ts +3 -2
- package/dist/cli/serve/DevServer.js +60 -3
- package/dist/cli/serve/ServeContext.d.ts +1 -0
- package/dist/cli/serve/StartServer.d.ts +1 -0
- package/dist/cli/serve/StartServer.js +6 -1
- package/dist/cli/util/EnsureLibs.js +2 -2
- package/dist/cli/util/EnsureNode.js +2 -2
- package/dist/cloud/CloudRemote.d.ts +2 -1
- package/dist/cloud/CloudRemote.js +3 -2
- package/dist/components/Breadcrumbs.js +8 -8
- package/dist/components/Button.js +6 -6
- package/dist/components/Calendar.js +11 -11
- package/dist/components/Checkbox.js +7 -7
- package/dist/components/CheckboxGroup.js +6 -6
- package/dist/components/ColorSwatch.js +6 -6
- package/dist/components/ColorSwatchPicker.js +6 -6
- package/dist/components/ComboBox.js +17 -17
- package/dist/components/DateField.js +9 -9
- package/dist/components/DatePicker.js +10 -10
- package/dist/components/DateRangePicker.js +14 -14
- package/dist/components/Dialog.js +6 -6
- package/dist/components/Disclosure.js +13 -13
- package/dist/components/DropZone.js +6 -6
- package/dist/components/Label.js +16 -16
- package/dist/components/Link.js +6 -6
- package/dist/components/List.js +34 -34
- package/dist/components/Menu.js +10 -10
- package/dist/components/Modal.js +8 -8
- package/dist/components/MultipleSelect.js +33 -33
- package/dist/components/NumberField.d.ts +2 -1
- package/dist/components/NumberField.js +21 -11
- package/dist/components/Popover.js +6 -6
- package/dist/components/ProgressCircle.js +10 -10
- package/dist/components/RadioGroup.js +6 -6
- package/dist/components/SearchField.js +11 -11
- package/dist/components/Select.js +13 -13
- package/dist/components/Surface.js +3 -3
- package/dist/components/Switch.js +6 -6
- package/dist/components/Table.js +13 -13
- package/dist/components/Tabs.js +8 -8
- package/dist/components/TagGroup.js +7 -7
- package/dist/components/TextField.js +10 -10
- package/dist/components/TimeField.js +6 -6
- package/dist/components/Toggle.js +6 -6
- package/dist/components/Toolbar.js +7 -7
- package/dist/components/Tooltip.js +10 -10
- package/dist/components/Tree.js +9 -9
- package/dist/core/BlobTransport.d.ts +5 -0
- package/dist/core/BlobTransport.js +79 -0
- package/dist/core/Client.d.ts +2 -1
- package/dist/core/Client.js +17 -12
- package/dist/core/Config.d.ts +4 -0
- package/dist/core/Config.js +6 -0
- package/dist/core/Connection.d.ts +4 -3
- package/dist/core/Connection.js +7 -0
- package/dist/core/Graph.d.ts +3 -4
- package/dist/core/ListRow.d.ts +2 -0
- package/dist/core/OrderBy.d.ts +7 -3
- package/dist/core/TextDoc.d.ts +11 -0
- package/dist/core/Trace.d.ts +8 -0
- package/dist/core/Trace.js +32 -0
- package/dist/core/Type.d.ts +7 -1
- package/dist/core/db/CommitRequest.d.ts +0 -3
- package/dist/core/db/CommitRequest.js +0 -9
- package/dist/core/db/EntryDB.js +1 -1
- package/dist/core/db/EntryIndex.d.ts +12 -2
- package/dist/core/db/EntryIndex.js +131 -22
- package/dist/core/db/EntryResolver.js +104 -29
- package/dist/core/db/EntryTransaction.d.ts +1 -2
- package/dist/core/db/EntryTransaction.js +29 -22
- package/dist/core/db/LocalDB.d.ts +5 -5
- package/dist/core/db/LocalDB.js +27 -12
- package/dist/core/field/RichTextField.d.ts +30 -3
- package/dist/core/field/RichTextField.js +124 -56
- package/dist/core/media/MediaAltField.d.ts +1 -0
- package/dist/core/media/MediaAltField.js +9 -1
- package/dist/core/media/MediaLocation.d.ts +5 -2
- package/dist/core/media/MediaLocation.js +6 -7
- package/dist/core/media/MediaTypes.js +11 -0
- package/dist/core/source/CombinedSource.d.ts +2 -2
- package/dist/core/source/CombinedSource.js +6 -3
- package/dist/core/source/FSSource.d.ts +4 -3
- package/dist/core/source/FSSource.js +59 -27
- package/dist/core/source/GithubSource.d.ts +2 -2
- package/dist/core/source/GithubSource.js +21 -9
- package/dist/core/source/IndexedDBSource.d.ts +2 -2
- package/dist/core/source/IndexedDBSource.js +3 -1
- package/dist/core/source/MemorySource.d.ts +2 -2
- package/dist/core/source/MemorySource.js +3 -1
- package/dist/core/source/OverlaySource.d.ts +12 -0
- package/dist/core/source/OverlaySource.js +50 -0
- package/dist/core/source/Source.d.ts +5 -2
- package/dist/core/source/Source.js +3 -3
- package/dist/core/util/Async.d.ts +8 -2
- package/dist/core/util/Async.js +67 -0
- package/dist/core/util/EntryFilenames.d.ts +2 -2
- package/dist/core/util/EntryFilenames.js +3 -3
- package/dist/dashboard/App.css +158 -0
- package/dist/dashboard/App.js +2 -2
- package/dist/dashboard/app/AccessDenied.js +3 -3
- package/dist/dashboard/app/ActivityStatus.js +15 -15
- package/dist/dashboard/app/AppShell.js +1 -1
- package/dist/dashboard/app/AuthView.js +11 -11
- package/dist/dashboard/app/CompactField.js +10 -10
- package/dist/dashboard/app/DashboardErrorBoundary.js +5 -5
- package/dist/dashboard/app/DashboardLayout.js +22 -19
- package/dist/dashboard/app/EntryHeader.js +12 -12
- package/dist/dashboard/app/EntryReferences.js +9 -9
- package/dist/dashboard/app/EntrySidebar.d.ts +1 -1
- package/dist/dashboard/app/EntrySidebar.js +17 -16
- package/dist/dashboard/app/EntrySidebarPreview.d.ts +1 -1
- package/dist/dashboard/app/EntrySidebarPreview.js +19 -14
- package/dist/dashboard/app/EntryTranslationBanner.js +7 -7
- package/dist/dashboard/app/Explorer.js +51 -43
- package/dist/dashboard/app/ExplorerCards.js +34 -34
- package/dist/dashboard/app/ExplorerFileCard.js +18 -18
- package/dist/dashboard/app/ExplorerList.js +13 -13
- package/dist/dashboard/app/ExplorerModal.js +3 -3
- package/dist/dashboard/app/ExplorerTable.js +76 -61
- package/dist/dashboard/app/ExternalLinkPicker.js +15 -4
- package/dist/dashboard/app/LinkPicker.js +8 -8
- package/dist/dashboard/app/LocaleMenu.js +12 -12
- package/dist/dashboard/app/SidebarLayout.d.ts +8 -0
- package/dist/dashboard/app/SidebarLayout.js +1169 -0
- package/dist/dashboard/app/SidebarTree.js +46 -46
- package/dist/dashboard/app/WorkspaceMenu.js +17 -17
- package/dist/dashboard/app/WorkspaceRoots.js +23 -23
- package/dist/dashboard/app/editor/FileEditor.d.ts +2 -1
- package/dist/dashboard/app/editor/FileEditor.js +41 -32
- package/dist/dashboard/app/editor/FilePreview.js +4 -4
- package/dist/dashboard/app/editor/MediaAltField.view.d.ts +1 -1
- package/dist/dashboard/app/editor/MediaAltField.view.js +6 -9
- package/dist/dashboard/app/modals/CreateEntry.js +4 -4
- package/dist/dashboard/app/pages/EntryPage.js +57 -31
- package/dist/dashboard/app/pages/UsersPage.js +33 -33
- package/dist/dashboard/app/ui/DashboardModal.js +23 -23
- package/dist/dashboard/app/ui/Rail.js +3 -3
- package/dist/dashboard/app/ui/Sidebar.js +2 -2
- package/dist/dashboard/atoms/auth.js +2 -0
- package/dist/dashboard/atoms/dashboard.d.ts +9 -0
- package/dist/dashboard/atoms/dashboard.js +17 -0
- package/dist/dashboard/atoms/editor.d.ts +7 -1
- package/dist/dashboard/atoms/editor.js +4 -1
- package/dist/dashboard/atoms/entry.d.ts +48 -2
- package/dist/dashboard/atoms/entry.js +222 -17
- package/dist/dashboard/atoms/explorer.js +4 -9
- package/dist/dashboard/atoms/preview.d.ts +3 -0
- package/dist/dashboard/atoms/preview.js +18 -1
- package/dist/dashboard/atoms/root.d.ts +4 -1
- package/dist/dashboard/atoms/root.js +96 -157
- package/dist/dashboard/hooks.d.ts +4 -2
- package/dist/dashboard/hooks.js +9 -5
- package/dist/dashboard/icons.d.ts +1 -0
- package/dist/dashboard/icons.js +10 -0
- package/dist/field/check/CheckField.view.js +2 -2
- package/dist/field/code/CodeField.view.js +12 -12
- package/dist/field/date/DateField.view.js +12 -2
- package/dist/field/link/FileLink.d.ts +2 -2
- package/dist/field/link/FileLink.js +5 -3
- package/dist/field/link/ImageLink.d.ts +1 -1
- package/dist/field/link/ImageLink.js +1 -1
- package/dist/field/link/Link.js +2 -2
- package/dist/field/link/LinkField.view.js +155 -128
- package/dist/field/list/ListField.view.js +22 -33
- package/dist/field/metadata/MetadataField.view.js +19 -19
- package/dist/field/number/NumberField.d.ts +2 -0
- package/dist/field/number/NumberField.view.js +4 -2
- package/dist/field/richtext/PickTextLink.d.ts +7 -0
- package/dist/field/richtext/PickTextLink.js +104 -2
- package/dist/field/richtext/ReferenceLink.d.ts +4 -1
- package/dist/field/richtext/ReferenceLink.js +18 -4
- package/dist/field/richtext/RichTextDocument.d.ts +7 -2
- package/dist/field/richtext/RichTextDocument.js +34 -5
- package/dist/field/richtext/RichTextExtensions.d.ts +3 -1
- package/dist/field/richtext/RichTextExtensions.js +2704 -7467
- package/dist/field/richtext/RichTextField.d.ts +4 -0
- package/dist/field/richtext/RichTextField.story.d.ts +4 -0
- package/dist/field/richtext/RichTextField.view.js +43 -20
- package/dist/field/richtext/RichTextInsertMenu.js +281 -495
- package/dist/field/richtext/RichTextToolbar.d.ts +5 -2
- package/dist/field/richtext/RichTextToolbar.js +38 -3
- package/dist/field/richtext/Toolbar.d.ts +19 -1
- package/dist/field/richtext/Toolbar.js +18 -13
- package/dist/field/richtext/extensions/Anchor.js +1 -1
- package/dist/field/richtext/extensions/Link.js +1 -1
- package/dist/field/richtext/extensions/Small.js +1 -1
- package/dist/field/select/SelectField.view.js +8 -6
- package/dist/index.css +227 -16
- package/dist/next.cjs +18 -16
- package/dist/next.d.ts +2 -1
- package/dist/next.edge.d.ts +2 -1
- package/dist/picker/entry/EntryPicker.js +9 -35
- package/dist/preview/PreviewPayload.js +35 -250
- package/dist/ui/RichText.d.ts +1 -0
- package/dist/ui/RichText.js +29 -2
- package/package.json +6 -3
- package/dist/cli/util/ExternalPlugin.d.ts +0 -2
- package/dist/cli/util/ExternalPlugin.js +0 -919
- package/dist/chunks/{chunk-JFROOUG6.js → chunk-NIVGVRDS.js} +17 -17
|
@@ -1774,8 +1774,8 @@ import {
|
|
|
1774
1774
|
Field
|
|
1775
1775
|
} from "../Field.js";
|
|
1776
1776
|
import { createId } from "../Id.js";
|
|
1777
|
+
import { mediaAltText } from "../media/MediaAltField.js";
|
|
1777
1778
|
import { MediaFile } from "../media/MediaTypes.js";
|
|
1778
|
-
import { MediaLocation } from "../media/MediaLocation.js";
|
|
1779
1779
|
import { Schema } from "../Schema.js";
|
|
1780
1780
|
import {
|
|
1781
1781
|
LinkMark,
|
|
@@ -1787,14 +1787,9 @@ import { applyUrlSuffix, createUniqueAnchor } from "../util/Anchors.js";
|
|
|
1787
1787
|
import { entries } from "../util/Objects.js";
|
|
1788
1788
|
import { slugify } from "../util/Slugs.js";
|
|
1789
1789
|
var linkInfoFields = {
|
|
1790
|
-
entryUrl: Entry.url,
|
|
1791
|
-
extension: MediaFile.extension,
|
|
1792
1790
|
id: Entry.id,
|
|
1793
|
-
location: MediaFile.location,
|
|
1794
|
-
path: Entry.path,
|
|
1795
|
-
root: Entry.root,
|
|
1796
1791
|
url: Entry.url,
|
|
1797
|
-
|
|
1792
|
+
alt: MediaFile.alt
|
|
1798
1793
|
};
|
|
1799
1794
|
var RichTextField = class extends Field {
|
|
1800
1795
|
constructor(schema, meta) {
|
|
@@ -2014,6 +2009,18 @@ function richTextReferences(schema, doc, path, label) {
|
|
|
2014
2009
|
linkType
|
|
2015
2010
|
});
|
|
2016
2011
|
});
|
|
2012
|
+
iterImageNodes(doc, (node, index) => {
|
|
2013
|
+
if (typeof node._entry !== "string") return;
|
|
2014
|
+
result.push({
|
|
2015
|
+
targetId: node._entry,
|
|
2016
|
+
fieldPath: referenceFieldPath(
|
|
2017
|
+
typeof node._id === "string" ? [...path, node._id] : [...path, String(index)]
|
|
2018
|
+
),
|
|
2019
|
+
fieldLabel: label,
|
|
2020
|
+
linkId: node._id,
|
|
2021
|
+
linkType: "image"
|
|
2022
|
+
});
|
|
2023
|
+
});
|
|
2017
2024
|
doc.forEach((row, index) => {
|
|
2018
2025
|
if (!schema || !Node.isBlock(row)) return;
|
|
2019
2026
|
const type = schema[row[Node.type]];
|
|
@@ -2039,27 +2046,33 @@ async function applyLinkMarks(doc, loader) {
|
|
|
2039
2046
|
const entryId = mark[LinkMark.entry];
|
|
2040
2047
|
if (typeof entryId === "string") links.set(mark, entryId);
|
|
2041
2048
|
});
|
|
2042
|
-
const
|
|
2049
|
+
const images = /* @__PURE__ */ new Map();
|
|
2050
|
+
iterImageNodes(doc, (node) => {
|
|
2051
|
+
if (node._link === "image" && typeof node._entry === "string") {
|
|
2052
|
+
delete node.src;
|
|
2053
|
+
delete node.alt;
|
|
2054
|
+
images.set(node, node._entry);
|
|
2055
|
+
}
|
|
2056
|
+
});
|
|
2057
|
+
const linkIds = Array.from(/* @__PURE__ */ new Set([...links.values(), ...images.values()]));
|
|
2043
2058
|
const entries2 = await loader.resolveLinks(linkInfoFields, linkIds);
|
|
2044
2059
|
const info = new Map(entries2.map((entry) => [entry.id, entry]));
|
|
2045
2060
|
for (const [mark, entryId] of links) {
|
|
2046
|
-
const type = mark[LinkMark.link];
|
|
2047
2061
|
const data = info.get(entryId);
|
|
2048
2062
|
if (!data) continue;
|
|
2049
|
-
const href =
|
|
2050
|
-
entryUrl: data.entryUrl,
|
|
2051
|
-
extension: data.extension,
|
|
2052
|
-
location: data.location,
|
|
2053
|
-
path: data.path,
|
|
2054
|
-
root: data.root,
|
|
2055
|
-
workspace: data.workspace
|
|
2056
|
-
}) : data.url;
|
|
2063
|
+
const href = data.url;
|
|
2057
2064
|
mark.href = applyUrlSuffix(
|
|
2058
2065
|
href,
|
|
2059
2066
|
mark[LinkMark.suffix],
|
|
2060
2067
|
mark[LinkMark.anchor]
|
|
2061
2068
|
);
|
|
2062
2069
|
}
|
|
2070
|
+
for (const [node, entryId] of images) {
|
|
2071
|
+
const data = info.get(entryId);
|
|
2072
|
+
if (!data) continue;
|
|
2073
|
+
node.src = data.url;
|
|
2074
|
+
node.alt = mediaAltText(data.alt, loader.locale ?? void 0);
|
|
2075
|
+
}
|
|
2063
2076
|
}
|
|
2064
2077
|
function richTextSearchableText(schema, value) {
|
|
2065
2078
|
if (!Array.isArray(value)) return "";
|
|
@@ -2089,6 +2102,13 @@ function iterMarks(doc, fn) {
|
|
|
2089
2102
|
else if (Node.isElement(row) && row.content) iterMarks(row.content, fn);
|
|
2090
2103
|
}
|
|
2091
2104
|
}
|
|
2105
|
+
function iterImageNodes(doc, fn) {
|
|
2106
|
+
doc.forEach((node, index) => {
|
|
2107
|
+
if (!Node.isElement(node)) return;
|
|
2108
|
+
if (node._type === "image") fn(node, index);
|
|
2109
|
+
if (node.content) iterImageNodes(node.content, fn);
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2092
2112
|
function iterNodes(doc, fn, path = []) {
|
|
2093
2113
|
doc.forEach((row, index) => {
|
|
2094
2114
|
const rowPath = [...path, String(index)];
|
|
@@ -2107,8 +2127,12 @@ var RichTextEditor = class {
|
|
|
2107
2127
|
this.doc.push({ _id: createId(), _type: type, ...block });
|
|
2108
2128
|
return this;
|
|
2109
2129
|
}
|
|
2110
|
-
addHtml(html) {
|
|
2111
|
-
this.doc.push(...parseHTML(html.trim()));
|
|
2130
|
+
addHtml(html, options) {
|
|
2131
|
+
this.doc.push(...parseHTML(html.trim(), options));
|
|
2132
|
+
return this;
|
|
2133
|
+
}
|
|
2134
|
+
async addHtmlAsync(html, options) {
|
|
2135
|
+
this.doc.push(...await parseHTMLAsync(html.trim(), options));
|
|
2112
2136
|
return this;
|
|
2113
2137
|
}
|
|
2114
2138
|
value() {
|
|
@@ -2170,51 +2194,94 @@ function mapMark(name, attributes) {
|
|
|
2170
2194
|
return { _type: "link", ...attributes };
|
|
2171
2195
|
}
|
|
2172
2196
|
}
|
|
2173
|
-
function
|
|
2174
|
-
const
|
|
2175
|
-
if (typeof html !== "string") return doc;
|
|
2176
|
-
const
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2197
|
+
async function parseHTMLAsync(html, options = {}) {
|
|
2198
|
+
const state = createParseHTMLState();
|
|
2199
|
+
if (typeof html !== "string") return state.doc;
|
|
2200
|
+
for (const token of tokenizeHTML(html)) {
|
|
2201
|
+
if (token.type === "text") {
|
|
2202
|
+
processText(state, token.text);
|
|
2203
|
+
} else if (token.type === "closeTag") {
|
|
2204
|
+
processCloseTag(state, token.name);
|
|
2205
|
+
} else {
|
|
2206
|
+
const tagHandler = options.tags?.[token.name];
|
|
2207
|
+
const markHandler = options.marks?.[token.name];
|
|
2208
|
+
const node = tagHandler ? await tagHandler(token.attributes) : mapNode(token.name, token.attributes);
|
|
2209
|
+
const mark = markHandler ? await markHandler(token.attributes) : mapMark(token.name, token.attributes);
|
|
2210
|
+
processOpenTag(state, token.name, node, mark);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
concatTextNodes(state.doc);
|
|
2214
|
+
return state.doc;
|
|
2215
|
+
}
|
|
2216
|
+
function parseHTML(html, options = {}) {
|
|
2217
|
+
const state = createParseHTMLState();
|
|
2218
|
+
if (typeof html !== "string") return state.doc;
|
|
2219
|
+
for (const token of tokenizeHTML(html)) {
|
|
2220
|
+
if (token.type === "text") {
|
|
2221
|
+
processText(state, token.text);
|
|
2222
|
+
} else if (token.type === "closeTag") {
|
|
2223
|
+
processCloseTag(state, token.name);
|
|
2224
|
+
} else {
|
|
2225
|
+
const tagHandler = options.tags?.[token.name];
|
|
2226
|
+
const markHandler = options.marks?.[token.name];
|
|
2227
|
+
const node = tagHandler ? tagHandler(token.attributes) : mapNode(token.name, token.attributes);
|
|
2228
|
+
const mark = markHandler ? markHandler(token.attributes) : mapMark(token.name, token.attributes);
|
|
2229
|
+
processOpenTag(state, token.name, node, mark);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
concatTextNodes(state.doc);
|
|
2233
|
+
return state.doc;
|
|
2234
|
+
}
|
|
2235
|
+
function tokenizeHTML(html) {
|
|
2236
|
+
const tokens = [];
|
|
2180
2237
|
const parser = new Parser({
|
|
2181
2238
|
onopentag(name, attributes) {
|
|
2182
|
-
|
|
2183
|
-
const mark = mapMark(name, attributes);
|
|
2184
|
-
const parent = parents.at(-1);
|
|
2185
|
-
if (node) {
|
|
2186
|
-
parent?.doc?.push(node);
|
|
2187
|
-
parents.push({ tag: name, doc: node?.content });
|
|
2188
|
-
} else if (mark) {
|
|
2189
|
-
const target = parent?.doc;
|
|
2190
|
-
if (!target) return;
|
|
2191
|
-
markStack.push({
|
|
2192
|
-
tag: name,
|
|
2193
|
-
mark,
|
|
2194
|
-
doc: target,
|
|
2195
|
-
start: target.length
|
|
2196
|
-
});
|
|
2197
|
-
}
|
|
2239
|
+
tokens.push({ type: "openTag", name, attributes });
|
|
2198
2240
|
},
|
|
2199
2241
|
ontext(text) {
|
|
2200
|
-
|
|
2201
|
-
if (parent?.doc === doc && text.trim().length === 0) return;
|
|
2202
|
-
parent?.doc?.push({ _type: "text", text });
|
|
2242
|
+
tokens.push({ type: "text", text });
|
|
2203
2243
|
},
|
|
2204
2244
|
onclosetag(name) {
|
|
2205
|
-
|
|
2206
|
-
if (parent?.tag === name) parents.pop();
|
|
2207
|
-
const match = findMark(name, markStack);
|
|
2208
|
-
if (match < 0) return;
|
|
2209
|
-
const { mark, doc: doc2, start } = markStack[match];
|
|
2210
|
-
for (let i = start; i < doc2.length; i++) applyMark(doc2[i], mark);
|
|
2211
|
-
markStack.splice(match);
|
|
2245
|
+
tokens.push({ type: "closeTag", name });
|
|
2212
2246
|
}
|
|
2213
2247
|
});
|
|
2214
2248
|
parser.write(html);
|
|
2215
2249
|
parser.end();
|
|
2216
|
-
|
|
2217
|
-
|
|
2250
|
+
return tokens;
|
|
2251
|
+
}
|
|
2252
|
+
function createParseHTMLState() {
|
|
2253
|
+
const doc = [];
|
|
2254
|
+
return { doc, parents: [{ doc }], markStack: [] };
|
|
2255
|
+
}
|
|
2256
|
+
function processOpenTag(state, name, node, mark) {
|
|
2257
|
+
const parent = state.parents.at(-1);
|
|
2258
|
+
if (node) {
|
|
2259
|
+
parent?.doc?.push(node);
|
|
2260
|
+
state.parents.push({ tag: name, doc: node.content });
|
|
2261
|
+
} else if (mark) {
|
|
2262
|
+
const target = parent?.doc;
|
|
2263
|
+
if (!target) return;
|
|
2264
|
+
state.markStack.push({
|
|
2265
|
+
tag: name,
|
|
2266
|
+
mark,
|
|
2267
|
+
doc: target,
|
|
2268
|
+
start: target.length
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
function processText(state, text) {
|
|
2273
|
+
const parent = state.parents.at(-1);
|
|
2274
|
+
if (parent?.doc === state.doc && text.trim().length === 0) return;
|
|
2275
|
+
parent?.doc?.push({ _type: "text", text });
|
|
2276
|
+
}
|
|
2277
|
+
function processCloseTag(state, name) {
|
|
2278
|
+
const parent = state.parents.at(-1);
|
|
2279
|
+
if (parent?.tag === name) state.parents.pop();
|
|
2280
|
+
const match = findMark(name, state.markStack);
|
|
2281
|
+
if (match < 0) return;
|
|
2282
|
+
const { mark, doc, start } = state.markStack[match];
|
|
2283
|
+
for (let i = start; i < doc.length; i++) applyMark(doc[i], mark);
|
|
2284
|
+
state.markStack.splice(match);
|
|
2218
2285
|
}
|
|
2219
2286
|
function findMark(tag, marks) {
|
|
2220
2287
|
for (let i = marks.length - 1; i >= 0; i--) {
|
|
@@ -2223,7 +2290,7 @@ function findMark(tag, marks) {
|
|
|
2223
2290
|
return -1;
|
|
2224
2291
|
}
|
|
2225
2292
|
function applyMark(node, mark) {
|
|
2226
|
-
if (node
|
|
2293
|
+
if (Node.isText(node)) {
|
|
2227
2294
|
const marks = node.marks || (node.marks = []);
|
|
2228
2295
|
if (!marks.some((current) => sameMark(current, mark))) marks.unshift(mark);
|
|
2229
2296
|
return;
|
|
@@ -2269,5 +2336,6 @@ function concatTextNodes(doc) {
|
|
|
2269
2336
|
export {
|
|
2270
2337
|
RichTextEditor,
|
|
2271
2338
|
RichTextField,
|
|
2272
|
-
parseHTML
|
|
2339
|
+
parseHTML,
|
|
2340
|
+
parseHTMLAsync
|
|
2273
2341
|
};
|
|
@@ -7,3 +7,4 @@ export interface MediaAltOptions extends Omit<TextOptions, 'initialValue' | 'val
|
|
|
7
7
|
export declare class MediaAltField extends ScalarField<MediaAltValue, MediaAltOptions> {
|
|
8
8
|
}
|
|
9
9
|
export declare function mediaAlt(label: string, options?: WithoutLabel<MediaAltOptions>): MediaAltField;
|
|
10
|
+
export declare function mediaAltText(value: MediaAltValue, locale?: string): string;
|
|
@@ -3,6 +3,7 @@ import "../../chunks/chunk-CQ52GEHY.js";
|
|
|
3
3
|
// src/core/media/MediaAltField.ts
|
|
4
4
|
import { ScalarField } from "alinea/core/field/ScalarField";
|
|
5
5
|
import { viewKeys } from "alinea/dashboard/ViewKeys";
|
|
6
|
+
import { isRecord } from "../util/Objects.js";
|
|
6
7
|
var MediaAltField = class extends ScalarField {
|
|
7
8
|
};
|
|
8
9
|
function mediaAlt(label, options = {}) {
|
|
@@ -11,7 +12,14 @@ function mediaAlt(label, options = {}) {
|
|
|
11
12
|
view: viewKeys.MediaAltInput
|
|
12
13
|
});
|
|
13
14
|
}
|
|
15
|
+
function mediaAltText(value, locale) {
|
|
16
|
+
if (typeof value === "string") return value;
|
|
17
|
+
if (!isRecord(value)) return "";
|
|
18
|
+
if (locale && typeof value[locale] === "string") return value[locale];
|
|
19
|
+
return Object.values(value).find((value2) => typeof value2 === "string") ?? "";
|
|
20
|
+
}
|
|
14
21
|
export {
|
|
15
22
|
MediaAltField,
|
|
16
|
-
mediaAlt
|
|
23
|
+
mediaAlt,
|
|
24
|
+
mediaAltText
|
|
17
25
|
};
|
|
@@ -16,10 +16,13 @@ export interface MediaUrlResolver {
|
|
|
16
16
|
(meta: MediaUrlMeta): string;
|
|
17
17
|
}
|
|
18
18
|
export interface MediaPublicUrlMeta extends Omit<MediaUrlMeta, 'parentPaths'> {
|
|
19
|
-
|
|
19
|
+
/** @deprecated Pass parentPaths directly when available. */
|
|
20
|
+
entryUrl?: string;
|
|
21
|
+
parentPaths?: Array<string>;
|
|
20
22
|
}
|
|
21
23
|
export interface MediaEntryUrlMeta {
|
|
22
|
-
|
|
24
|
+
defaultUrl: string;
|
|
25
|
+
parentPaths: Array<string>;
|
|
23
26
|
path: string;
|
|
24
27
|
workspace: string;
|
|
25
28
|
root: string;
|
|
@@ -24,29 +24,28 @@ var MediaLocation;
|
|
|
24
24
|
}
|
|
25
25
|
MediaLocation2.entryLocation = entryLocation;
|
|
26
26
|
function publicUrl(config, meta) {
|
|
27
|
-
const { entryUrl: entryUrl2, ...media } = meta;
|
|
28
|
-
const { location, workspace } =
|
|
27
|
+
const { entryUrl: entryUrl2, parentPaths, ...media } = meta;
|
|
28
|
+
const { location, workspace } = meta;
|
|
29
29
|
const { mediaUrl } = Workspace.data(config.workspaces[workspace]);
|
|
30
30
|
if (!mediaUrl) return location;
|
|
31
31
|
if (typeof mediaUrl === "function") {
|
|
32
|
-
const segments = entryUrl2.split("/").filter(Boolean);
|
|
33
32
|
return mediaUrl({
|
|
34
33
|
...media,
|
|
35
|
-
parentPaths:
|
|
34
|
+
parentPaths: parentPaths ?? entryUrl2?.split("/").filter(Boolean).slice(0, -1) ?? []
|
|
36
35
|
});
|
|
37
36
|
}
|
|
38
37
|
return joinPaths(mediaUrl, location);
|
|
39
38
|
}
|
|
40
39
|
MediaLocation2.publicUrl = publicUrl;
|
|
41
40
|
function entryUrl(config, meta) {
|
|
42
|
-
const { data,
|
|
41
|
+
const { data, defaultUrl, parentPaths, path, root, workspace } = meta;
|
|
43
42
|
const { extension, location } = data;
|
|
44
43
|
if (typeof extension !== "string" || typeof location !== "string")
|
|
45
|
-
return
|
|
44
|
+
return defaultUrl;
|
|
46
45
|
return publicUrl(config, {
|
|
47
|
-
entryUrl: entryUrl2,
|
|
48
46
|
extension,
|
|
49
47
|
location,
|
|
48
|
+
parentPaths,
|
|
50
49
|
path,
|
|
51
50
|
root,
|
|
52
51
|
workspace
|
|
@@ -9,6 +9,7 @@ import { path } from "alinea/field/path/PathField";
|
|
|
9
9
|
import { text } from "alinea/field/text/TextField";
|
|
10
10
|
import { type } from "../Type.js";
|
|
11
11
|
import { mediaAlt } from "./MediaAltField.js";
|
|
12
|
+
import { MediaLocation } from "./MediaLocation.js";
|
|
12
13
|
var MediaLibrary = type("Media directory", {
|
|
13
14
|
icon: IcRoundPermMedia,
|
|
14
15
|
contains: ["MediaLibrary", "MediaFile"],
|
|
@@ -20,6 +21,16 @@ var MediaLibrary = type("Media directory", {
|
|
|
20
21
|
});
|
|
21
22
|
var MediaFile = type("Media file", {
|
|
22
23
|
hidden: true,
|
|
24
|
+
entryUrl({ config, data, defaultUrl, parentPaths, path: path2, root, workspace }) {
|
|
25
|
+
return MediaLocation.entryUrl(config, {
|
|
26
|
+
data,
|
|
27
|
+
defaultUrl,
|
|
28
|
+
parentPaths,
|
|
29
|
+
path: path2,
|
|
30
|
+
root,
|
|
31
|
+
workspace
|
|
32
|
+
});
|
|
33
|
+
},
|
|
23
34
|
fields: {
|
|
24
35
|
title: text("Title"),
|
|
25
36
|
path: path("Path"),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ChangesBatch } from './Change.js';
|
|
2
|
-
import type { Source } from './Source.js';
|
|
2
|
+
import type { GetBlobsOptions, Source } from './Source.js';
|
|
3
3
|
import { ReadonlyTree } from './Tree.js';
|
|
4
4
|
export declare class CombinedSource implements Source {
|
|
5
5
|
#private;
|
|
6
6
|
constructor(sources: Record<string, Source>);
|
|
7
7
|
getTree(): Promise<ReadonlyTree>;
|
|
8
8
|
getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
|
|
9
|
-
getBlobs(shas:
|
|
9
|
+
getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
|
|
10
10
|
applyChanges(batch: ChangesBatch): Promise<void>;
|
|
11
11
|
}
|
|
@@ -32,8 +32,11 @@ var CombinedSource = class {
|
|
|
32
32
|
if (tree.sha === sha) return void 0;
|
|
33
33
|
return tree;
|
|
34
34
|
}
|
|
35
|
-
async *getBlobs(shas) {
|
|
36
|
-
if (this.#only)
|
|
35
|
+
async *getBlobs(shas, options = {}) {
|
|
36
|
+
if (this.#only) {
|
|
37
|
+
yield* this.#only.getBlobs(shas, options);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
37
40
|
const tree = await this.getTree();
|
|
38
41
|
const perSource = /* @__PURE__ */ new Map();
|
|
39
42
|
for (const [name, source] of entries(this.#sources)) {
|
|
@@ -47,7 +50,7 @@ var CombinedSource = class {
|
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
for (const [source, shas2] of perSource) {
|
|
50
|
-
yield* source.getBlobs(shas2);
|
|
53
|
+
yield* source.getBlobs(shas2, options);
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
async applyChanges(batch) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChangesBatch } from './Change.js';
|
|
2
|
-
import type { Source } from './Source.js';
|
|
2
|
+
import type { GetBlobsOptions, Source } from './Source.js';
|
|
3
3
|
import { ReadonlyTree, WriteableTree } from './Tree.js';
|
|
4
4
|
export declare class FSSource implements Source {
|
|
5
5
|
#private;
|
|
@@ -7,7 +7,8 @@ export declare class FSSource implements Source {
|
|
|
7
7
|
getTree(): Promise<ReadonlyTree>;
|
|
8
8
|
getFile(current: ReadonlyTree, builder: WriteableTree, file: string): Promise<readonly [string, Uint8Array<ArrayBufferLike>] | undefined>;
|
|
9
9
|
getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
|
|
10
|
-
getBlobs(shas:
|
|
10
|
+
getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
|
|
11
|
+
readBlob(sha: string, file: string, signal?: AbortSignal): Promise<[sha: string, blob: Uint8Array]>;
|
|
11
12
|
applyChanges(batch: ChangesBatch): Promise<void>;
|
|
12
13
|
}
|
|
13
14
|
export declare class CachedFSSource extends FSSource {
|
|
@@ -17,5 +18,5 @@ export declare class CachedFSSource extends FSSource {
|
|
|
17
18
|
getTree(): Promise<ReadonlyTree>;
|
|
18
19
|
applyChanges(batch: ChangesBatch): Promise<void>;
|
|
19
20
|
getFile(current: ReadonlyTree, builder: WriteableTree, file: string): Promise<readonly [string, Uint8Array<ArrayBufferLike>] | undefined>;
|
|
20
|
-
getBlobs(shas:
|
|
21
|
+
getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
|
|
21
22
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
import "../../chunks/chunk-CQ52GEHY.js";
|
|
5
5
|
|
|
6
6
|
// src/core/source/FSSource.ts
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
7
8
|
import fs from "node:fs/promises";
|
|
8
9
|
import path from "node:path/posix";
|
|
9
10
|
|
|
@@ -54,12 +55,17 @@ var p_debounce_default = pDebounce;
|
|
|
54
55
|
|
|
55
56
|
// src/core/source/FSSource.ts
|
|
56
57
|
import { assert } from "../util/Assert.js";
|
|
57
|
-
import {
|
|
58
|
+
import { mapConcurrent } from "../util/Async.js";
|
|
58
59
|
import { isRecord } from "../util/Objects.js";
|
|
59
|
-
import { hashBlob } from "./GitUtils.js";
|
|
60
60
|
import { ReadonlyTree, WriteableTree } from "./Tree.js";
|
|
61
61
|
var limit = pLimit(1);
|
|
62
62
|
var fileConcurrency = 64;
|
|
63
|
+
var blobReadConcurrency = 32;
|
|
64
|
+
var encoder = new TextEncoder();
|
|
65
|
+
function hashFileBlob(contents) {
|
|
66
|
+
const header = encoder.encode(`blob ${contents.byteLength}\0`);
|
|
67
|
+
return createHash("sha1").update(header).update(contents).digest("hex");
|
|
68
|
+
}
|
|
63
69
|
var FSSource = class {
|
|
64
70
|
#current = ReadonlyTree.EMPTY;
|
|
65
71
|
#cwd;
|
|
@@ -75,11 +81,12 @@ var FSSource = class {
|
|
|
75
81
|
const files = await fs.readdir(this.#cwd, {
|
|
76
82
|
recursive: true
|
|
77
83
|
});
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
(file) =>
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
for await (const result of mapConcurrent(
|
|
85
|
+
files,
|
|
86
|
+
(file) => this.getFile(current, builder, file),
|
|
87
|
+
{ concurrency: fileConcurrency }
|
|
88
|
+
))
|
|
89
|
+
void result;
|
|
83
90
|
const tree = await builder.compile(current);
|
|
84
91
|
this.#current = tree;
|
|
85
92
|
return tree;
|
|
@@ -111,7 +118,7 @@ var FSSource = class {
|
|
|
111
118
|
if (isRecord(error) && error.code === "ENOENT") return;
|
|
112
119
|
throw error;
|
|
113
120
|
}
|
|
114
|
-
const sha =
|
|
121
|
+
const sha = hashFileBlob(contents);
|
|
115
122
|
this.#locations.set(sha, filePath);
|
|
116
123
|
this.#lastModified.set(filePath, stat.mtimeMs);
|
|
117
124
|
builder.add(filePath, sha);
|
|
@@ -121,12 +128,20 @@ var FSSource = class {
|
|
|
121
128
|
const current = await this.getTree();
|
|
122
129
|
return current.sha === sha ? void 0 : current;
|
|
123
130
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
131
|
+
getBlobs(shas, options = {}) {
|
|
132
|
+
return mapConcurrent(
|
|
133
|
+
shas,
|
|
134
|
+
(sha, signal) => {
|
|
135
|
+
const file = this.#locations.get(sha);
|
|
136
|
+
assert(file, `Missing path for blob ${sha}`);
|
|
137
|
+
return this.readBlob(sha, file, signal);
|
|
138
|
+
},
|
|
139
|
+
{ concurrency: blobReadConcurrency, signal: options.signal }
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
async readBlob(sha, file, signal) {
|
|
143
|
+
const blob = await fs.readFile(`${this.#cwd}/${file}`, { signal });
|
|
144
|
+
return [sha, blob];
|
|
130
145
|
}
|
|
131
146
|
async applyChanges(batch) {
|
|
132
147
|
return limit(async () => {
|
|
@@ -157,9 +172,23 @@ var CachedFSSource = class extends FSSource {
|
|
|
157
172
|
constructor(cwd) {
|
|
158
173
|
super(cwd);
|
|
159
174
|
}
|
|
160
|
-
refresh = p_debounce_default(
|
|
161
|
-
|
|
162
|
-
|
|
175
|
+
refresh = p_debounce_default(() => {
|
|
176
|
+
let refresh;
|
|
177
|
+
refresh = super.getTree().then(
|
|
178
|
+
(tree) => {
|
|
179
|
+
const currentShas = new Set(tree.index().values());
|
|
180
|
+
for (const sha of this.#blobs.keys()) {
|
|
181
|
+
if (!currentShas.has(sha)) this.#blobs.delete(sha);
|
|
182
|
+
}
|
|
183
|
+
return tree;
|
|
184
|
+
},
|
|
185
|
+
(error) => {
|
|
186
|
+
if (this.#tree === refresh) this.#tree = void 0;
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
this.#tree = refresh;
|
|
191
|
+
return refresh;
|
|
163
192
|
}, 50);
|
|
164
193
|
getTree() {
|
|
165
194
|
if (!this.#tree) return this.refresh();
|
|
@@ -174,16 +203,19 @@ var CachedFSSource = class extends FSSource {
|
|
|
174
203
|
if (result) this.#blobs?.set(result[0], result[1]);
|
|
175
204
|
return result;
|
|
176
205
|
}
|
|
177
|
-
async *getBlobs(shas) {
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
206
|
+
async *getBlobs(shas, options = {}) {
|
|
207
|
+
const fromRemote = [];
|
|
208
|
+
for (const sha of shas) {
|
|
209
|
+
if (options.signal?.aborted)
|
|
210
|
+
throw options.signal.reason ?? new Error("Blob transfer aborted");
|
|
211
|
+
const blob = this.#blobs.get(sha);
|
|
212
|
+
if (blob) yield [sha, blob];
|
|
213
|
+
else fromRemote.push(sha);
|
|
214
|
+
}
|
|
215
|
+
for await (const [sha, blob] of super.getBlobs(fromRemote, options)) {
|
|
216
|
+
this.#blobs.set(sha, blob);
|
|
217
|
+
yield [sha, blob];
|
|
218
|
+
}
|
|
187
219
|
}
|
|
188
220
|
};
|
|
189
221
|
export {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChangesBatch } from './Change.js';
|
|
2
|
-
import type { Source } from './Source.js';
|
|
2
|
+
import type { GetBlobsOptions, Source } from './Source.js';
|
|
3
3
|
import { ReadonlyTree } from './Tree.js';
|
|
4
4
|
export interface GithubSourceOptions {
|
|
5
5
|
authToken: string;
|
|
@@ -17,6 +17,6 @@ export declare class GithubSource implements Source {
|
|
|
17
17
|
getTree(): Promise<ReadonlyTree>;
|
|
18
18
|
shaAt(ref: string): Promise<string>;
|
|
19
19
|
getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
|
|
20
|
-
getBlobs(shas:
|
|
20
|
+
getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
|
|
21
21
|
applyChanges(batch: ChangesBatch): Promise<void>;
|
|
22
22
|
}
|
|
@@ -19,6 +19,7 @@ var GithubSource = class {
|
|
|
19
19
|
#current = ReadonlyTree.EMPTY;
|
|
20
20
|
#options;
|
|
21
21
|
#limit = pLimit(8);
|
|
22
|
+
#shaCache = /* @__PURE__ */ new Map();
|
|
22
23
|
constructor(options) {
|
|
23
24
|
this.#options = normalizeGithubSourceOptions(options);
|
|
24
25
|
}
|
|
@@ -35,17 +36,25 @@ var GithubSource = class {
|
|
|
35
36
|
async shaAt(ref) {
|
|
36
37
|
const { owner, repo, authToken } = this.#options;
|
|
37
38
|
const parentDir = this.contentLocation.split("/").slice(0, -1).join("/");
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
39
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${parentDir}?ref=${ref}`;
|
|
40
|
+
const cached = this.#shaCache.get(url);
|
|
41
|
+
const headers = new Headers({ Authorization: `Bearer ${authToken}` });
|
|
42
|
+
if (cached) headers.set("If-None-Match", cached.etag);
|
|
43
|
+
const parentInfo = await fetch(url, { headers });
|
|
44
|
+
if (parentInfo.status === 304) {
|
|
45
|
+
assert(cached, "Received 304 without a cached GitHub response");
|
|
46
|
+
return cached.sha;
|
|
47
|
+
}
|
|
42
48
|
assert(parentInfo.ok, `Failed to get parent: ${parentInfo.statusText}`);
|
|
43
49
|
const parents = await parentInfo.json();
|
|
44
50
|
assert(Array.isArray(parents));
|
|
45
51
|
const parent = parents.find((entry) => entry.path === this.contentLocation);
|
|
46
|
-
|
|
47
|
-
assert(typeof
|
|
48
|
-
|
|
52
|
+
const sha = parent ? parent.sha : ReadonlyTree.EMPTY.sha;
|
|
53
|
+
assert(typeof sha === "string");
|
|
54
|
+
const etag = parentInfo.headers.get("etag");
|
|
55
|
+
if (etag) this.#shaCache.set(url, { etag, sha });
|
|
56
|
+
else this.#shaCache.delete(url);
|
|
57
|
+
return sha;
|
|
49
58
|
}
|
|
50
59
|
async getTreeIfDifferent(sha) {
|
|
51
60
|
const { branch, owner, repo, authToken } = this.#options;
|
|
@@ -61,13 +70,16 @@ var GithubSource = class {
|
|
|
61
70
|
const tree = ReadonlyTree.fromFlat(treeData);
|
|
62
71
|
return tree;
|
|
63
72
|
}
|
|
64
|
-
async *getBlobs(shas) {
|
|
73
|
+
async *getBlobs(shas, options = {}) {
|
|
65
74
|
const { owner, repo, authToken } = this.#options;
|
|
66
75
|
const responses = shas.map((sha) => {
|
|
67
76
|
const promise = this.#limit(
|
|
68
77
|
() => fetch(
|
|
69
78
|
`https://api.github.com/repos/${owner}/${repo}/git/blobs/${sha}`,
|
|
70
|
-
{
|
|
79
|
+
{
|
|
80
|
+
headers: { Authorization: `Bearer ${authToken}` },
|
|
81
|
+
signal: options.signal
|
|
82
|
+
}
|
|
71
83
|
)
|
|
72
84
|
);
|
|
73
85
|
return [sha, promise];
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ChangesBatch } from './Change.js';
|
|
2
|
-
import type { Source } from './Source.js';
|
|
2
|
+
import type { GetBlobsOptions, Source } from './Source.js';
|
|
3
3
|
import { ReadonlyTree } from './Tree.js';
|
|
4
4
|
export declare class IndexedDBSource implements Source {
|
|
5
5
|
#private;
|
|
6
6
|
constructor(indexedDB: IDBFactory, name: string);
|
|
7
7
|
getTree(): Promise<ReadonlyTree>;
|
|
8
8
|
getTreeIfDifferent(sha: string): Promise<ReadonlyTree | undefined>;
|
|
9
|
-
getBlobs(shas:
|
|
9
|
+
getBlobs(shas: ReadonlyArray<string>, options?: GetBlobsOptions): AsyncGenerator<[sha: string, blob: Uint8Array]>;
|
|
10
10
|
applyChanges(batch: ChangesBatch): Promise<void>;
|
|
11
11
|
}
|