@micacms/runtime 0.4.0 → 0.5.0-rc.1
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/README.md +2 -2
- package/dist/app.d.ts +8 -37
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +7 -42
- package/dist/app.js.map +1 -1
- package/dist/config.d.ts +12 -82
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -82
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +37 -66
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +24 -75
- package/dist/context.js.map +1 -1
- package/dist/http.d.ts +8 -16
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +6 -13
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +13 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -14
- package/dist/index.js.map +1 -1
- package/dist/routes/admin-content.d.ts +4 -17
- package/dist/routes/admin-content.d.ts.map +1 -1
- package/dist/routes/admin-content.js +11 -51
- package/dist/routes/admin-content.js.map +1 -1
- package/dist/routes/admin-media.d.ts +3 -14
- package/dist/routes/admin-media.d.ts.map +1 -1
- package/dist/routes/admin-media.js +7 -29
- package/dist/routes/admin-media.js.map +1 -1
- package/dist/routes/admin-staging.d.ts +4 -9
- package/dist/routes/admin-staging.d.ts.map +1 -1
- package/dist/routes/admin-staging.js +31 -18
- package/dist/routes/admin-staging.js.map +1 -1
- package/dist/routes/admin-system.d.ts +2 -8
- package/dist/routes/admin-system.d.ts.map +1 -1
- package/dist/routes/admin-system.js +9 -44
- package/dist/routes/admin-system.js.map +1 -1
- package/dist/routes/health.d.ts +3 -10
- package/dist/routes/health.d.ts.map +1 -1
- package/dist/routes/health.js +9 -26
- package/dist/routes/health.js.map +1 -1
- package/dist/schema.d.ts +10 -38
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +14 -65
- package/dist/schema.js.map +1 -1
- package/dist/server.d.ts +2 -10
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +3 -9
- package/dist/server.js.map +1 -1
- package/dist/services/changes.d.ts +150 -0
- package/dist/services/changes.d.ts.map +1 -0
- package/dist/services/changes.js +339 -0
- package/dist/services/changes.js.map +1 -0
- package/dist/services/content-store.d.ts +61 -0
- package/dist/services/content-store.d.ts.map +1 -0
- package/dist/services/content-store.js +330 -0
- package/dist/services/content-store.js.map +1 -0
- package/dist/services/media.d.ts +9 -29
- package/dist/services/media.d.ts.map +1 -1
- package/dist/services/media.js +17 -57
- package/dist/services/media.js.map +1 -1
- package/dist/services/staging.d.ts +35 -167
- package/dist/services/staging.d.ts.map +1 -1
- package/dist/services/staging.js +195 -458
- package/dist/services/staging.js.map +1 -1
- package/dist/workspace/developer.d.ts +14 -0
- package/dist/workspace/developer.d.ts.map +1 -0
- package/dist/workspace/developer.js +31 -0
- package/dist/workspace/developer.js.map +1 -0
- package/dist/workspace/files.d.ts +70 -0
- package/dist/workspace/files.d.ts.map +1 -0
- package/dist/workspace/files.js +176 -0
- package/dist/workspace/files.js.map +1 -0
- package/dist/workspace/git.d.ts +45 -0
- package/dist/workspace/git.d.ts.map +1 -0
- package/dist/workspace/git.js +68 -0
- package/dist/workspace/git.js.map +1 -0
- package/dist/workspace/locks.d.ts +33 -0
- package/dist/workspace/locks.d.ts.map +1 -0
- package/dist/workspace/locks.js +76 -0
- package/dist/workspace/locks.js.map +1 -0
- package/dist/workspace/policy.d.ts +92 -0
- package/dist/workspace/policy.d.ts.map +1 -0
- package/dist/workspace/policy.js +7 -0
- package/dist/workspace/policy.js.map +1 -0
- package/dist/workspace/tree.d.ts +73 -0
- package/dist/workspace/tree.d.ts.map +1 -0
- package/dist/workspace/tree.js +229 -0
- package/dist/workspace/tree.js.map +1 -0
- package/package.json +2 -3
- package/dist/db/driver.d.ts +0 -35
- package/dist/db/driver.d.ts.map +0 -1
- package/dist/db/driver.js +0 -95
- package/dist/db/driver.js.map +0 -1
- package/dist/lib/git.d.ts +0 -29
- package/dist/lib/git.d.ts.map +0 -1
- package/dist/lib/git.js +0 -62
- package/dist/lib/git.js.map +0 -1
- package/dist/services/staging-local.d.ts +0 -58
- package/dist/services/staging-local.d.ts.map +0 -1
- package/dist/services/staging-local.js +0 -391
- package/dist/services/staging-local.js.map +0 -1
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collections and singletons over the working tree's files: validation, slugs,
|
|
3
|
+
* entry files and `_order.json`. An entry is its slug and path, Git keeps the
|
|
4
|
+
* history, a save is a draft, and only Publish makes a commit.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { ContentPathError, DOCUMENT_EXTENSION, INDEX_FILE, ORDER_FILE, collectionEntryPath, entryFiles, entryLayout, entryTitle, isValidSlug, readCollection, readSingleton, relativizeMedia, resolveSlugField, serializeEntry, singletonPath, slugify, uniqueSlug, validateFields, withDefaults, } from "@micacms/core";
|
|
8
|
+
import { ConflictError, FilesError } from "../workspace/files.js";
|
|
9
|
+
export class ContentError extends FilesError {
|
|
10
|
+
name = "ContentError";
|
|
11
|
+
}
|
|
12
|
+
export class ValidationError extends ContentError {
|
|
13
|
+
issues;
|
|
14
|
+
name = "ValidationError";
|
|
15
|
+
constructor(message, issues) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.issues = issues;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function createContentStore(site, workspace) {
|
|
21
|
+
const requireCollection = (name) => {
|
|
22
|
+
const def = site.collections[name];
|
|
23
|
+
if (!def)
|
|
24
|
+
throw new ContentError(`Unknown collection "${name}".`);
|
|
25
|
+
return def;
|
|
26
|
+
};
|
|
27
|
+
const requireSingleton = (name) => {
|
|
28
|
+
const def = site.singletons[name];
|
|
29
|
+
if (!def)
|
|
30
|
+
throw new ContentError(`Unknown singleton "${name}".`);
|
|
31
|
+
return def;
|
|
32
|
+
};
|
|
33
|
+
const validate = (def, data, what) => {
|
|
34
|
+
const result = validateFields(def.fields, data, "storage");
|
|
35
|
+
if (!result.ok) {
|
|
36
|
+
throw new ValidationError(`${what} cannot be saved until these fields are correct.`, result.issues);
|
|
37
|
+
}
|
|
38
|
+
return result.data;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Deletes for `.mdoc` files not in `keep`, so a cleared rich-text field does
|
|
42
|
+
* not come back on the next read. Media stays: an unreferenced upload is not
|
|
43
|
+
* garbage.
|
|
44
|
+
*/
|
|
45
|
+
const staleDocuments = async (base, keep) => {
|
|
46
|
+
const changes = [];
|
|
47
|
+
for (const item of await workspace.list(base)) {
|
|
48
|
+
if (item.type !== "file")
|
|
49
|
+
continue;
|
|
50
|
+
if (!item.name.endsWith(DOCUMENT_EXTENSION))
|
|
51
|
+
continue;
|
|
52
|
+
if (keep.has(item.name))
|
|
53
|
+
continue;
|
|
54
|
+
changes.push({ type: "delete", path: `${base}/${item.name}` });
|
|
55
|
+
}
|
|
56
|
+
return changes;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* The document's revision after a write. Throws when the file is absent,
|
|
60
|
+
* because an empty token could never match.
|
|
61
|
+
*/
|
|
62
|
+
const revisionAfterWrite = async (dataFile, folder) => {
|
|
63
|
+
const revision = await documentRevision(dataFile, folder);
|
|
64
|
+
if (revision === null) {
|
|
65
|
+
throw new ContentError(`Saved, but "${dataFile}" is not in the repository afterwards.`);
|
|
66
|
+
}
|
|
67
|
+
return revision;
|
|
68
|
+
};
|
|
69
|
+
/** The folder whose files make up one document, or null for a one-file document. */
|
|
70
|
+
const folderOf = (fields, base) => entryLayout(fields) === "directory" ? base : null;
|
|
71
|
+
/**
|
|
72
|
+
* The revision of a whole document: its data file and, in the folder layout,
|
|
73
|
+
* every file of its folder. A change to any one of them makes the next save a
|
|
74
|
+
* conflict, not an overwrite.
|
|
75
|
+
*/
|
|
76
|
+
const documentRevision = async (dataFile, folder) => {
|
|
77
|
+
const files = await documentFiles(dataFile, folder);
|
|
78
|
+
if (files === null)
|
|
79
|
+
return null;
|
|
80
|
+
if (folder === null)
|
|
81
|
+
return files.get(dataFile);
|
|
82
|
+
const parts = [...files].map(([path, revision]) => `${path}\u0000${revision}`);
|
|
83
|
+
return createHash("sha256").update(parts.sort().join("\n")).digest("hex").slice(0, 16);
|
|
84
|
+
};
|
|
85
|
+
/** Every file of a document with its revision, or null when its data file is absent. */
|
|
86
|
+
const documentFiles = async (dataFile, folder) => {
|
|
87
|
+
const data = await workspace.revision(dataFile);
|
|
88
|
+
if (data === null)
|
|
89
|
+
return null;
|
|
90
|
+
const files = new Map([[dataFile, data]]);
|
|
91
|
+
if (folder === null)
|
|
92
|
+
return files;
|
|
93
|
+
const walk = async (dir) => {
|
|
94
|
+
for (const item of await workspace.list(dir)) {
|
|
95
|
+
const child = `${dir}/${item.name}`;
|
|
96
|
+
if (item.type === "directory")
|
|
97
|
+
await walk(child);
|
|
98
|
+
else
|
|
99
|
+
files.set(child, (await workspace.revision(child)) ?? "");
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
await walk(folder);
|
|
103
|
+
return files;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Refuses when the document changed since the editor read `expected`, and
|
|
107
|
+
* returns every file's revision for `apply`, which checks them all again
|
|
108
|
+
* under the write lock.
|
|
109
|
+
*/
|
|
110
|
+
const expectDocument = async (expected, dataFile, folder) => {
|
|
111
|
+
if (expected === undefined)
|
|
112
|
+
return undefined;
|
|
113
|
+
const files = await documentFiles(dataFile, folder);
|
|
114
|
+
if ((await documentRevision(dataFile, folder)) !== expected) {
|
|
115
|
+
throw new ConflictError("This content changed after you opened it. Reload to see the current version.", [
|
|
116
|
+
dataFile,
|
|
117
|
+
]);
|
|
118
|
+
}
|
|
119
|
+
return files === null ? { [dataFile]: null } : Object.fromEntries(files);
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* The order file with a renamed slug in its old place, so the entry does not
|
|
123
|
+
* drop to the end of the list.
|
|
124
|
+
*/
|
|
125
|
+
const renameInOrder = async (name, from, to) => {
|
|
126
|
+
const path = `${name}/${ORDER_FILE}`;
|
|
127
|
+
const raw = await workspace.read(path);
|
|
128
|
+
if (raw === null)
|
|
129
|
+
return null;
|
|
130
|
+
let listed;
|
|
131
|
+
try {
|
|
132
|
+
listed = JSON.parse(raw);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Reading the collection reports a malformed order file; a save need not.
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
if (!Array.isArray(listed) || !listed.includes(from))
|
|
139
|
+
return null;
|
|
140
|
+
const order = listed.map((slug) => (slug === from ? to : slug));
|
|
141
|
+
return { type: "write", path, contents: `${JSON.stringify(order, null, 2)}\n` };
|
|
142
|
+
};
|
|
143
|
+
/** Slugs already taken in a collection, so a new one can be made unique. */
|
|
144
|
+
const takenSlugs = async (def, name, except) => {
|
|
145
|
+
const entries = await readCollection(workspace, def, name);
|
|
146
|
+
return entries.map((entry) => entry.slug).filter((slug) => slug !== except);
|
|
147
|
+
};
|
|
148
|
+
return {
|
|
149
|
+
async list(collectionName) {
|
|
150
|
+
return readCollection(workspace, requireCollection(collectionName), collectionName);
|
|
151
|
+
},
|
|
152
|
+
async get(collectionName, slug) {
|
|
153
|
+
const entries = await this.list(collectionName);
|
|
154
|
+
return entries.find((entry) => entry.slug === slug) ?? null;
|
|
155
|
+
},
|
|
156
|
+
/** The revision an editor must send back with a save of this entry. */
|
|
157
|
+
async revisionOf(collectionName, slug) {
|
|
158
|
+
const def = requireCollection(collectionName);
|
|
159
|
+
return documentRevision(dataPath(def, collectionName, slug), folderOf(def.fields, collectionEntryPath(def.fields, collectionName, slug)));
|
|
160
|
+
},
|
|
161
|
+
/** The revision an editor must send back with a save of this singleton. */
|
|
162
|
+
async revisionOfSingleton(name) {
|
|
163
|
+
const def = requireSingleton(name);
|
|
164
|
+
return documentRevision(singletonDataPath(def, name), folderOf(def.fields, singletonPath(def.fields, name)));
|
|
165
|
+
},
|
|
166
|
+
async getSingleton(name) {
|
|
167
|
+
const def = requireSingleton(name);
|
|
168
|
+
const data = await readSingleton(workspace, def, name);
|
|
169
|
+
// A singleton with no file yet opens as an empty form, not a 404.
|
|
170
|
+
return withDefaults(def.fields, data);
|
|
171
|
+
},
|
|
172
|
+
async save(collectionName, input) {
|
|
173
|
+
const def = requireCollection(collectionName);
|
|
174
|
+
const data = validate(def, input.data, "This entry");
|
|
175
|
+
const slugKey = resolveSlugField(def);
|
|
176
|
+
const requested = pickSlug(def, data, input.slug);
|
|
177
|
+
const slug = requested === input.slug
|
|
178
|
+
? requested
|
|
179
|
+
: uniqueSlug(requested, await takenSlugs(def, collectionName, input.slug));
|
|
180
|
+
data[slugKey] = slug;
|
|
181
|
+
const base = collectionEntryPath(def.fields, collectionName, slug);
|
|
182
|
+
const previousBase = input.slug && input.slug !== slug
|
|
183
|
+
? collectionEntryPath(def.fields, collectionName, input.slug)
|
|
184
|
+
: null;
|
|
185
|
+
// The editor uses root-relative media paths; store them relative to the
|
|
186
|
+
// entry (the old directory on a rename).
|
|
187
|
+
const serialized = serializeEntry(def.fields, mediaForDisk(def.fields, data, previousBase ?? base));
|
|
188
|
+
const files = entryFiles(def.fields, base, serialized);
|
|
189
|
+
const changes = Object.entries(files).map(([path, contents]) => ({
|
|
190
|
+
type: "write",
|
|
191
|
+
path,
|
|
192
|
+
contents,
|
|
193
|
+
}));
|
|
194
|
+
if (previousBase) {
|
|
195
|
+
changes.push(entryLayout(def.fields) === "directory"
|
|
196
|
+
? { type: "deleteTree", path: previousBase }
|
|
197
|
+
: { type: "delete", path: previousBase });
|
|
198
|
+
await moveMedia(workspace, previousBase, base, changes);
|
|
199
|
+
const order = await renameInOrder(collectionName, input.slug, slug);
|
|
200
|
+
if (order)
|
|
201
|
+
changes.push(order);
|
|
202
|
+
}
|
|
203
|
+
else if (entryLayout(def.fields) === "directory") {
|
|
204
|
+
changes.push(...(await staleDocuments(base, new Set(Object.keys(serialized.documents)))));
|
|
205
|
+
}
|
|
206
|
+
const title = entryTitle(def, data);
|
|
207
|
+
await workspace.apply({
|
|
208
|
+
changes,
|
|
209
|
+
expect: await expectDocument(input.expectedRevision, dataPath(def, collectionName, input.slug ?? slug), folderOf(def.fields, previousBase ?? base)),
|
|
210
|
+
});
|
|
211
|
+
const revision = await revisionAfterWrite(dataPath(def, collectionName, slug), folderOf(def.fields, base));
|
|
212
|
+
return { slug, title, revision, renamed: previousBase !== null };
|
|
213
|
+
},
|
|
214
|
+
async remove(collectionName, slug, options = {}) {
|
|
215
|
+
const def = requireCollection(collectionName);
|
|
216
|
+
// One path segment: an empty slug or `a/b` would delete more than one entry.
|
|
217
|
+
if (slug === "" || slug.includes("/") || slug === "." || slug === "..") {
|
|
218
|
+
throw new ContentPathError(`"${slug}" is not an entry of "${collectionName}".`);
|
|
219
|
+
}
|
|
220
|
+
const base = collectionEntryPath(def.fields, collectionName, slug);
|
|
221
|
+
await workspace.apply({
|
|
222
|
+
changes: [
|
|
223
|
+
entryLayout(def.fields) === "directory"
|
|
224
|
+
? { type: "deleteTree", path: base }
|
|
225
|
+
: { type: "delete", path: base },
|
|
226
|
+
],
|
|
227
|
+
expect: await expectDocument(options.expectedRevision, dataPath(def, collectionName, slug), folderOf(def.fields, base)),
|
|
228
|
+
});
|
|
229
|
+
},
|
|
230
|
+
async saveSingleton(name, payload, options = {}) {
|
|
231
|
+
const def = requireSingleton(name);
|
|
232
|
+
const data = validate(def, payload, `The "${def.label}" settings`);
|
|
233
|
+
const base = singletonPath(def.fields, name);
|
|
234
|
+
const serialized = serializeEntry(def.fields, mediaForDisk(def.fields, data, base));
|
|
235
|
+
const changes = Object.entries(entryFiles(def.fields, base, serialized)).map(([path, contents]) => ({ type: "write", path, contents }));
|
|
236
|
+
if (entryLayout(def.fields) === "directory") {
|
|
237
|
+
changes.push(...(await staleDocuments(base, new Set(Object.keys(serialized.documents)))));
|
|
238
|
+
}
|
|
239
|
+
await workspace.apply({
|
|
240
|
+
changes,
|
|
241
|
+
expect: await expectDocument(options.expectedRevision, singletonDataPath(def, name), folderOf(def.fields, base)),
|
|
242
|
+
});
|
|
243
|
+
return { revision: await revisionAfterWrite(singletonDataPath(def, name), folderOf(def.fields, base)) };
|
|
244
|
+
},
|
|
245
|
+
async reorder(collectionName, slugs) {
|
|
246
|
+
const def = requireCollection(collectionName);
|
|
247
|
+
if (!def.sortable) {
|
|
248
|
+
throw new ContentError(`The "${def.label}" collection is not manually sortable.`);
|
|
249
|
+
}
|
|
250
|
+
await workspace.apply({
|
|
251
|
+
changes: [
|
|
252
|
+
{
|
|
253
|
+
type: "write",
|
|
254
|
+
path: `${collectionName}/${ORDER_FILE}`,
|
|
255
|
+
contents: `${JSON.stringify(slugs, null, 2)}\n`,
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
});
|
|
259
|
+
},
|
|
260
|
+
requireCollection,
|
|
261
|
+
requireSingleton,
|
|
262
|
+
/** Slug the server would assign, so the editor's URL preview matches it. */
|
|
263
|
+
async suggestSlug(collectionName, source, except) {
|
|
264
|
+
const def = requireCollection(collectionName);
|
|
265
|
+
return uniqueSlug(slugify(source), await takenSlugs(def, collectionName, except));
|
|
266
|
+
},
|
|
267
|
+
/** Entries pointing at `slug`, so the editor can warn before a delete. */
|
|
268
|
+
async findReferences(collectionName, slug) {
|
|
269
|
+
const results = [];
|
|
270
|
+
for (const [name, def] of Object.entries(site.collections)) {
|
|
271
|
+
const keys = Object.entries(def.fields)
|
|
272
|
+
.filter(([, field]) => field.kind === "relation" && field.collection === collectionName)
|
|
273
|
+
.map(([key]) => key);
|
|
274
|
+
if (keys.length === 0)
|
|
275
|
+
continue;
|
|
276
|
+
for (const entry of await readCollection(workspace, def, name)) {
|
|
277
|
+
const points = keys.some((key) => {
|
|
278
|
+
const value = entry.data[key];
|
|
279
|
+
return Array.isArray(value) ? value.includes(slug) : value === slug;
|
|
280
|
+
});
|
|
281
|
+
if (points) {
|
|
282
|
+
results.push({ collection: name, slug: entry.slug, title: entryTitle(def, entry.data) });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return results;
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Media paths as the repository stores them. Only a directory entry has
|
|
292
|
+
* colocated media to relativize.
|
|
293
|
+
*/
|
|
294
|
+
function mediaForDisk(fields, data, base) {
|
|
295
|
+
return entryLayout(fields) === "directory" ? relativizeMedia(fields, data, base) : data;
|
|
296
|
+
}
|
|
297
|
+
function dataPath(def, collection, slug) {
|
|
298
|
+
const base = collectionEntryPath(def.fields, collection, slug);
|
|
299
|
+
return entryLayout(def.fields) === "directory" ? `${base}/${INDEX_FILE}` : base;
|
|
300
|
+
}
|
|
301
|
+
function singletonDataPath(def, name) {
|
|
302
|
+
const base = singletonPath(def.fields, name);
|
|
303
|
+
return entryLayout(def.fields) === "directory" ? `${base}/${INDEX_FILE}` : base;
|
|
304
|
+
}
|
|
305
|
+
/** The slug from the payload's slug field, or one derived from the title. */
|
|
306
|
+
function pickSlug(def, data, current) {
|
|
307
|
+
const slugKey = resolveSlugField(def);
|
|
308
|
+
const fromData = data[slugKey];
|
|
309
|
+
const candidate = (typeof fromData === "string" && fromData.trim()) || slugify(entryTitle(def, data));
|
|
310
|
+
if (!candidate) {
|
|
311
|
+
throw new ContentError("An entry needs a title or a URL before it can be saved.");
|
|
312
|
+
}
|
|
313
|
+
const normalised = isValidSlug(candidate) ? candidate : slugify(candidate);
|
|
314
|
+
if (!normalised) {
|
|
315
|
+
throw new ContentError(`"${candidate}" cannot be turned into a URL. Use letters and numbers.`);
|
|
316
|
+
}
|
|
317
|
+
return normalised === current ? current : normalised;
|
|
318
|
+
}
|
|
319
|
+
/** Copies colocated media to the renamed entry; the caller deletes the old directory. */
|
|
320
|
+
async function moveMedia(files, from, to, changes) {
|
|
321
|
+
for (const item of await files.list(`${from}/media`)) {
|
|
322
|
+
if (item.type !== "file")
|
|
323
|
+
continue;
|
|
324
|
+
const bytes = await files.readBinary(`${from}/media/${item.name}`);
|
|
325
|
+
if (bytes === null)
|
|
326
|
+
continue;
|
|
327
|
+
changes.push({ type: "write", path: `${to}/media/${item.name}`, contents: bytes });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=content-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-store.js","sourceRoot":"","sources":["../../src/services/content-store.ts"],"names":[],"mappings":"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"}
|
package/dist/services/media.d.ts
CHANGED
|
@@ -1,27 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Media uploads.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* size, and the real content type read from the bytes rather than from the
|
|
6
|
-
* browser's claim.
|
|
7
|
-
*
|
|
8
|
-
* An upload is a *file in the content repository*. There is no media table, no
|
|
9
|
-
* generated key and no object store — a media value is the path to a file a
|
|
10
|
-
* reviewer can see in the diff.
|
|
11
|
-
*
|
|
12
|
-
* The filename therefore matters. It is derived from what the editor uploaded,
|
|
13
|
-
* slugified so it is safe as a path segment, and made unique inside its own
|
|
14
|
-
* directory rather than globally.
|
|
2
|
+
* Media uploads. Every upload is checked here for size and for its real content
|
|
3
|
+
* type, read from the bytes. An upload is a file in the content repository; its
|
|
4
|
+
* name is slugified and unique in its own directory.
|
|
15
5
|
*/
|
|
16
|
-
import type {
|
|
6
|
+
import type { ContentFiles } from "../workspace/files.js";
|
|
17
7
|
/** Where uploads go when they are not attached to a particular entry. */
|
|
18
8
|
export declare const SHARED_MEDIA_DIR = "media";
|
|
19
9
|
export interface MediaServiceDeps {
|
|
20
|
-
|
|
10
|
+
files: ContentFiles;
|
|
21
11
|
maxBytes: number;
|
|
22
12
|
}
|
|
23
13
|
export interface MediaFile {
|
|
24
|
-
/** Path relative to the content root
|
|
14
|
+
/** Path relative to the content root: the value a `media()` field holds. */
|
|
25
15
|
path: string;
|
|
26
16
|
filename: string;
|
|
27
17
|
mimeType: string;
|
|
@@ -30,14 +20,7 @@ export interface MediaFile {
|
|
|
30
20
|
height: number | null;
|
|
31
21
|
}
|
|
32
22
|
export declare function createMediaService(deps: MediaServiceDeps): {
|
|
33
|
-
/**
|
|
34
|
-
* Reads and checks an upload, without writing it.
|
|
35
|
-
*
|
|
36
|
-
* Separate from the commit so that an entry and the media it references go
|
|
37
|
-
* into the repository in *one* change set. Uploading first and saving
|
|
38
|
-
* second would leave an orphaned file behind whenever the editor changed
|
|
39
|
-
* their mind.
|
|
40
|
-
*/
|
|
23
|
+
/** Reads and checks an upload, without writing it. */
|
|
41
24
|
prepare(input: {
|
|
42
25
|
file: File;
|
|
43
26
|
/** Directory to place the file in, relative to the content root. */
|
|
@@ -48,11 +31,8 @@ export declare function createMediaService(deps: MediaServiceDeps): {
|
|
|
48
31
|
contents: Uint8Array;
|
|
49
32
|
}>;
|
|
50
33
|
/**
|
|
51
|
-
* Every media file in the repository
|
|
52
|
-
*
|
|
53
|
-
* A walk of the content tree rather than a table scan. Content trees are
|
|
54
|
-
* small, and the alternative — an index Mica maintains — would be a second
|
|
55
|
-
* source of truth that could disagree with the repository.
|
|
34
|
+
* Every media file in the repository. A tree walk is sufficient because
|
|
35
|
+
* content trees are small.
|
|
56
36
|
*/
|
|
57
37
|
list(): Promise<MediaFile[]>;
|
|
58
38
|
read(mediaPath: string): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/services/media.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/services/media.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAM1D,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB;IAkBrD,sDAAsD;mBACjC;QACnB,IAAI,EAAE,IAAI,CAAC;QACX,oEAAoE;QACpE,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,KAAK,CAAC;KACvC,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,QAAQ,EAAE,UAAU,CAAA;KAAE,CAAC;IAyCtD;;;OAGG;YACW,OAAO,CAAC,SAAS,EAAE,CAAC;oBAkCZ,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;EASzF;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AA6EjE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
|
package/dist/services/media.js
CHANGED
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Media uploads.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* size, and the real content type read from the bytes rather than from the
|
|
6
|
-
* browser's claim.
|
|
7
|
-
*
|
|
8
|
-
* An upload is a *file in the content repository*. There is no media table, no
|
|
9
|
-
* generated key and no object store — a media value is the path to a file a
|
|
10
|
-
* reviewer can see in the diff.
|
|
11
|
-
*
|
|
12
|
-
* The filename therefore matters. It is derived from what the editor uploaded,
|
|
13
|
-
* slugified so it is safe as a path segment, and made unique inside its own
|
|
14
|
-
* directory rather than globally.
|
|
2
|
+
* Media uploads. Every upload is checked here for size and for its real content
|
|
3
|
+
* type, read from the bytes. An upload is a file in the content repository; its
|
|
4
|
+
* name is slugified and unique in its own directory.
|
|
15
5
|
*/
|
|
16
6
|
import path from "node:path";
|
|
17
7
|
import { contentPath, ContentPathError, MEDIA_DIR, slugify } from "@micacms/core";
|
|
@@ -21,17 +11,10 @@ import { detectFileType, isAccepted, isImageType, SVG_TYPE } from "../lib/file-t
|
|
|
21
11
|
/** Where uploads go when they are not attached to a particular entry. */
|
|
22
12
|
export const SHARED_MEDIA_DIR = "media";
|
|
23
13
|
export function createMediaService(deps) {
|
|
24
|
-
const {
|
|
25
|
-
/**
|
|
26
|
-
* A name that is unique in `directory`.
|
|
27
|
-
*
|
|
28
|
-
* Scoped to the directory rather than to the whole repository, because that
|
|
29
|
-
* is where a collision would actually overwrite something — and because
|
|
30
|
-
* `haus-a/media/exterior.jpg` and `haus-b/media/exterior.jpg` are two
|
|
31
|
-
* perfectly reasonable files with the same name.
|
|
32
|
-
*/
|
|
14
|
+
const { files, maxBytes } = deps;
|
|
15
|
+
/** A name that is unique in `directory`. Only there can a collision overwrite a file. */
|
|
33
16
|
const uniqueName = async (directory, filename) => {
|
|
34
|
-
const taken = new Set((await
|
|
17
|
+
const taken = new Set((await files.list(directory)).filter((item) => item.type === "file").map((item) => item.name));
|
|
35
18
|
const extension = path.extname(filename);
|
|
36
19
|
const stem = filename.slice(0, filename.length - extension.length);
|
|
37
20
|
let candidate = filename;
|
|
@@ -40,14 +23,7 @@ export function createMediaService(deps) {
|
|
|
40
23
|
return candidate;
|
|
41
24
|
};
|
|
42
25
|
return {
|
|
43
|
-
/**
|
|
44
|
-
* Reads and checks an upload, without writing it.
|
|
45
|
-
*
|
|
46
|
-
* Separate from the commit so that an entry and the media it references go
|
|
47
|
-
* into the repository in *one* change set. Uploading first and saving
|
|
48
|
-
* second would leave an orphaned file behind whenever the editor changed
|
|
49
|
-
* their mind.
|
|
50
|
-
*/
|
|
26
|
+
/** Reads and checks an upload, without writing it. */
|
|
51
27
|
async prepare(input) {
|
|
52
28
|
const { file } = input;
|
|
53
29
|
const directory = uploadDirectory(input.directory ?? SHARED_MEDIA_DIR);
|
|
@@ -57,7 +33,7 @@ export function createMediaService(deps) {
|
|
|
57
33
|
throw new ApiError("payload_too_large", `The file is ${formatBytes(file.size)}. The limit is ${formatBytes(maxBytes)}.`);
|
|
58
34
|
}
|
|
59
35
|
const contents = new Uint8Array(await file.arrayBuffer());
|
|
60
|
-
// From the bytes, never from the browser's claim
|
|
36
|
+
// From the bytes, never from the browser's claim.
|
|
61
37
|
const detected = detectFileType(contents);
|
|
62
38
|
if (!detected) {
|
|
63
39
|
throw new ApiError("unsupported_media_type", "This file type is not supported.");
|
|
@@ -80,16 +56,13 @@ export function createMediaService(deps) {
|
|
|
80
56
|
};
|
|
81
57
|
},
|
|
82
58
|
/**
|
|
83
|
-
* Every media file in the repository
|
|
84
|
-
*
|
|
85
|
-
* A walk of the content tree rather than a table scan. Content trees are
|
|
86
|
-
* small, and the alternative — an index Mica maintains — would be a second
|
|
87
|
-
* source of truth that could disagree with the repository.
|
|
59
|
+
* Every media file in the repository. A tree walk is sufficient because
|
|
60
|
+
* content trees are small.
|
|
88
61
|
*/
|
|
89
62
|
async list() {
|
|
90
63
|
const found = [];
|
|
91
64
|
const walk = async (directory) => {
|
|
92
|
-
for (const item of await
|
|
65
|
+
for (const item of await files.list(directory)) {
|
|
93
66
|
const child = directory === "" ? item.name : `${directory}/${item.name}`;
|
|
94
67
|
if (item.type === "directory") {
|
|
95
68
|
await walk(child);
|
|
@@ -97,7 +70,7 @@ export function createMediaService(deps) {
|
|
|
97
70
|
}
|
|
98
71
|
if (!isMediaName(item.name))
|
|
99
72
|
continue;
|
|
100
|
-
const bytes = await
|
|
73
|
+
const bytes = await files.readBinary(child);
|
|
101
74
|
if (!bytes)
|
|
102
75
|
continue;
|
|
103
76
|
const mimeType = typeOf(bytes, item.name);
|
|
@@ -116,7 +89,7 @@ export function createMediaService(deps) {
|
|
|
116
89
|
return found.sort((a, b) => a.path.localeCompare(b.path));
|
|
117
90
|
},
|
|
118
91
|
async read(mediaPath) {
|
|
119
|
-
const bytes = await
|
|
92
|
+
const bytes = await files.readBinary(contentPath(mediaPath));
|
|
120
93
|
if (!bytes)
|
|
121
94
|
return null;
|
|
122
95
|
const mimeType = typeOf(bytes, mediaPath);
|
|
@@ -142,24 +115,12 @@ function uploadDirectory(directory) {
|
|
|
142
115
|
}
|
|
143
116
|
return clean;
|
|
144
117
|
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* A filename that is safe as a path segment and still recognisable.
|
|
148
|
-
*
|
|
149
|
-
* Slugified rather than sanitised: the result is part of a URL in the built
|
|
150
|
-
* site and part of a path in a Git repository, and both are better off without
|
|
151
|
-
* spaces, accents or case.
|
|
152
|
-
*/
|
|
118
|
+
/** A slugified filename: safe as a path segment and as part of a URL. */
|
|
153
119
|
function safeName(original, extension) {
|
|
154
120
|
const stem = slugify(path.basename(original).replace(/\.[^.]*$/, "")).slice(0, 80);
|
|
155
121
|
return `${stem || "upload"}.${extension}`;
|
|
156
122
|
}
|
|
157
|
-
/**
|
|
158
|
-
* Extension to media type, for the formats byte-sniffing does not identify.
|
|
159
|
-
*
|
|
160
|
-
* A fallback, never the first answer: a file's own bytes are the only thing
|
|
161
|
-
* that cannot be renamed to lie.
|
|
162
|
-
*/
|
|
123
|
+
/** Extension to media type, only for formats that byte-sniffing does not identify. */
|
|
163
124
|
const BY_EXTENSION = {
|
|
164
125
|
svg: "image/svg+xml",
|
|
165
126
|
pdf: "application/pdf",
|
|
@@ -171,9 +132,8 @@ const BY_EXTENSION = {
|
|
|
171
132
|
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
172
133
|
};
|
|
173
134
|
/**
|
|
174
|
-
* The bytes
|
|
175
|
-
*
|
|
176
|
-
* like one, so that a leading comment cannot slip one past the refusal.
|
|
135
|
+
* The bytes win over the extension, except that an SVG name always counts, so a
|
|
136
|
+
* leading comment cannot hide an SVG.
|
|
177
137
|
*/
|
|
178
138
|
function typeOf(bytes, name) {
|
|
179
139
|
const byName = mimeFromName(name);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/services/media.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/services/media.ts"],"names":[],"mappings":"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"}
|