@geekity/cms 0.13.0 → 0.15.0
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 +181 -57
- package/admin/pages/documents/editor.njk +82 -0
- package/admin/pages/media/library.njk +4 -3
- package/admin/pages/settings/general.njk +51 -6
- package/admin/static/admin.css +33 -0
- package/dist/admin/documents.d.ts +5 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +63 -6
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/enclosure-field.d.ts +91 -0
- package/dist/admin/enclosure-field.d.ts.map +1 -0
- package/dist/admin/enclosure-field.js +282 -0
- package/dist/admin/enclosure-field.js.map +1 -0
- package/dist/admin/federation.js +2 -2
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/headers.d.ts +4 -1
- package/dist/admin/headers.d.ts.map +1 -1
- package/dist/admin/headers.js +9 -4
- package/dist/admin/headers.js.map +1 -1
- package/dist/admin/media.d.ts +7 -2
- package/dist/admin/media.d.ts.map +1 -1
- package/dist/admin/media.js +4 -2
- package/dist/admin/media.js.map +1 -1
- package/dist/admin/settings-general.d.ts.map +1 -1
- package/dist/admin/settings-general.js +63 -4
- package/dist/admin/settings-general.js.map +1 -1
- package/dist/admin/settings-page.d.ts.map +1 -1
- package/dist/admin/settings-page.js +1 -2
- package/dist/admin/settings-page.js.map +1 -1
- package/dist/admin/settings.d.ts +37 -9
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +93 -11
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/uploads.d.ts +7 -2
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +23 -5
- package/dist/admin/uploads.js.map +1 -1
- package/dist/config.d.ts +21 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -7
- package/dist/config.js.map +1 -1
- package/dist/content/enclosure.d.ts +69 -0
- package/dist/content/enclosure.d.ts.map +1 -0
- package/dist/content/enclosure.js +165 -0
- package/dist/content/enclosure.js.map +1 -0
- package/dist/content/index.d.ts +3 -1
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -0
- package/dist/content/index.js.map +1 -1
- package/dist/content/media.d.ts +15 -2
- package/dist/content/media.d.ts.map +1 -1
- package/dist/content/media.js +92 -9
- package/dist/content/media.js.map +1 -1
- package/dist/content/pinned.d.ts +26 -0
- package/dist/content/pinned.d.ts.map +1 -0
- package/dist/content/pinned.js +42 -0
- package/dist/content/pinned.js.map +1 -0
- package/dist/content/store.d.ts +7 -0
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +20 -0
- package/dist/content/store.js.map +1 -1
- package/dist/env.d.ts +7 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/actor.d.ts +15 -0
- package/dist/federation/actor.d.ts.map +1 -1
- package/dist/federation/actor.js +94 -3
- package/dist/federation/actor.js.map +1 -1
- package/dist/federation/article.d.ts +13 -1
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +62 -7
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +36 -4
- package/dist/federation/delivery.js.map +1 -1
- package/dist/federation/federation.d.ts.map +1 -1
- package/dist/federation/federation.js +24 -2
- package/dist/federation/federation.js.map +1 -1
- package/dist/federation/mount.js +2 -2
- package/dist/federation/mount.js.map +1 -1
- package/dist/federation/paths.d.ts +30 -0
- package/dist/federation/paths.d.ts.map +1 -1
- package/dist/federation/paths.js +36 -0
- package/dist/federation/paths.js.map +1 -1
- package/dist/images/icons.d.ts +5 -0
- package/dist/images/icons.d.ts.map +1 -1
- package/dist/images/icons.js +13 -8
- package/dist/images/icons.js.map +1 -1
- package/dist/images/paths.d.ts +1 -1
- package/dist/images/paths.d.ts.map +1 -1
- package/dist/images/paths.js.map +1 -1
- package/dist/images/variants.d.ts +11 -0
- package/dist/images/variants.d.ts.map +1 -1
- package/dist/images/variants.js +21 -0
- package/dist/images/variants.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/indieauth/identity.d.ts +3 -3
- package/dist/indieauth/identity.d.ts.map +1 -1
- package/dist/indieauth/identity.js +6 -7
- package/dist/indieauth/identity.js.map +1 -1
- package/dist/web/admin-bar.d.ts +3 -1
- package/dist/web/admin-bar.d.ts.map +1 -1
- package/dist/web/admin-bar.js +5 -1
- package/dist/web/admin-bar.js.map +1 -1
- package/dist/web/assets.d.ts +14 -0
- package/dist/web/assets.d.ts.map +1 -1
- package/dist/web/assets.js +56 -1
- package/dist/web/assets.js.map +1 -1
- package/dist/web/authors.d.ts +19 -0
- package/dist/web/authors.d.ts.map +1 -1
- package/dist/web/authors.js +25 -0
- package/dist/web/authors.js.map +1 -1
- package/dist/web/context.d.ts +26 -0
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +15 -0
- package/dist/web/context.js.map +1 -1
- package/dist/web/feed-atom.d.ts.map +1 -1
- package/dist/web/feed-atom.js +22 -1
- package/dist/web/feed-atom.js.map +1 -1
- package/dist/web/feed-item.d.ts +34 -6
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +31 -7
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/feed-json.d.ts +15 -2
- package/dist/web/feed-json.d.ts.map +1 -1
- package/dist/web/feed-json.js +17 -1
- package/dist/web/feed-json.js.map +1 -1
- package/dist/web/feed-rss.d.ts.map +1 -1
- package/dist/web/feed-rss.js +60 -3
- package/dist/web/feed-rss.js.map +1 -1
- package/dist/web/feed-source.d.ts +3 -0
- package/dist/web/feed-source.d.ts.map +1 -1
- package/dist/web/feed-source.js.map +1 -1
- package/dist/web/feed-xml.d.ts +7 -1
- package/dist/web/feed-xml.d.ts.map +1 -1
- package/dist/web/feed-xml.js +8 -2
- package/dist/web/feed-xml.js.map +1 -1
- package/dist/web/feeds.d.ts +1 -1
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +13 -2
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/index.d.ts +5 -2
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +3 -1
- package/dist/web/index.js.map +1 -1
- package/dist/web/license.d.ts +94 -0
- package/dist/web/license.d.ts.map +1 -0
- package/dist/web/license.js +116 -0
- package/dist/web/license.js.map +1 -0
- package/dist/web/oembed.d.ts +104 -0
- package/dist/web/oembed.d.ts.map +1 -0
- package/dist/web/oembed.js +289 -0
- package/dist/web/oembed.js.map +1 -0
- package/dist/web/opensearch.d.ts +35 -0
- package/dist/web/opensearch.d.ts.map +1 -0
- package/dist/web/opensearch.js +65 -0
- package/dist/web/opensearch.js.map +1 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +16 -8
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +82 -6
- package/dist/web/routes.js.map +1 -1
- package/dist/web/share-image.d.ts +7 -7
- package/dist/web/share-image.d.ts.map +1 -1
- package/dist/web/share-image.js +8 -7
- package/dist/web/share-image.js.map +1 -1
- package/dist/web/templates.d.ts.map +1 -1
- package/dist/web/templates.js +5 -0
- package/dist/web/templates.js.map +1 -1
- package/package.json +2 -1
- package/templates/site/content/_data/site.json +0 -1
- package/themes/default/README.md +142 -48
- package/themes/default/layouts/base.njk +25 -6
- package/themes/default/layouts/front-page.njk +1 -0
- package/themes/default/layouts/home.njk +1 -0
- package/themes/default/layouts/post.njk +4 -0
- package/themes/default/partials/bio.njk +7 -0
- package/themes/default/partials/jsonld.njk +30 -7
- package/themes/default/partials/recording.njk +41 -0
- package/themes/default/src/style.css +16 -0
- package/themes/default/static/style.css +29 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A post's recording: one main audio or video file, the other versions of it,
|
|
3
|
+
* and its transcript (TASK-213).
|
|
4
|
+
*
|
|
5
|
+
* The front matter spells it the way RSS does, so a person reading the file
|
|
6
|
+
* and a person reading the feed see the same names:
|
|
7
|
+
*
|
|
8
|
+
* ```yaml
|
|
9
|
+
* enclosure:
|
|
10
|
+
* url: /uploads/2026/10/episode-12.mp3
|
|
11
|
+
* type: audio/mpeg
|
|
12
|
+
* length: 23456789
|
|
13
|
+
* duration: 1834
|
|
14
|
+
* transcript:
|
|
15
|
+
* url: /uploads/2026/10/episode-12.vtt
|
|
16
|
+
* type: text/vtt
|
|
17
|
+
* alternates:
|
|
18
|
+
* - url: https://cdn.example.com/episode-12.mp4
|
|
19
|
+
* type: video/mp4
|
|
20
|
+
* title: Video
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* It is not a key the CMS models in {@link Document}: like `license`, it stays
|
|
24
|
+
* in {@link Document.extra}, so an admin save and an Eleventy build both see
|
|
25
|
+
* exactly what the file says. {@link enclosureOf} is the one reading of it,
|
|
26
|
+
* and the feeds, the theme and the federation read only what it returns.
|
|
27
|
+
*/
|
|
28
|
+
import { UPLOAD_ASSET_PREFIX } from '../web/assets.js';
|
|
29
|
+
/** The front matter key the recording is under. */
|
|
30
|
+
export const ENCLOSURE_FRONT_MATTER_KEY = 'enclosure';
|
|
31
|
+
/** The longest title an alternate version may have, as the Podcasting 2.0 namespace says. */
|
|
32
|
+
export const ALTERNATE_TITLE_MAX_LENGTH = 32;
|
|
33
|
+
/** The transcript formats the Podcasting 2.0 namespace names, and so the ones a feed can carry. */
|
|
34
|
+
export const TRANSCRIPT_TYPES = [
|
|
35
|
+
'text/vtt',
|
|
36
|
+
'application/x-subrip',
|
|
37
|
+
'text/html',
|
|
38
|
+
'text/plain',
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* The recording a post's front matter describes, or `undefined` when it has
|
|
42
|
+
* none worth printing.
|
|
43
|
+
*
|
|
44
|
+
* A main file without a URL under `/uploads/`, a media type, or a positive
|
|
45
|
+
* whole number of bytes is no enclosure at all: RSS requires all three, and a
|
|
46
|
+
* guessed one would send a podcast app the wrong file. Anything else that is
|
|
47
|
+
* wrong is dropped on its own — an alternate version with no media type, a
|
|
48
|
+
* transcript of a format nobody plays, a title too long to show — so one bad
|
|
49
|
+
* line in a hand-edited file costs that line and not the episode.
|
|
50
|
+
*/
|
|
51
|
+
export function enclosureOf(extra) {
|
|
52
|
+
const raw = record(extra[ENCLOSURE_FRONT_MATTER_KEY]);
|
|
53
|
+
if (raw === undefined)
|
|
54
|
+
return undefined;
|
|
55
|
+
const url = uploadUrl(raw['url']);
|
|
56
|
+
const type = mediaType(raw['type']);
|
|
57
|
+
const length = positiveInteger(raw['length']);
|
|
58
|
+
if (url === undefined || type === undefined || length === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
const duration = typeof raw['duration'] === 'number' ? raw['duration'] : undefined;
|
|
61
|
+
return {
|
|
62
|
+
url,
|
|
63
|
+
type,
|
|
64
|
+
length,
|
|
65
|
+
...(duration !== undefined && Number.isFinite(duration) && duration > 0 ? { duration } : {}),
|
|
66
|
+
...optional('transcript', transcriptOf(raw['transcript'])),
|
|
67
|
+
alternates: Array.isArray(raw['alternates'])
|
|
68
|
+
? raw['alternates'].flatMap((entry) => alternateOf(entry) ?? [])
|
|
69
|
+
: [],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Whether a media type is played by a `<video>` and federated as a `Video`,
|
|
74
|
+
* rather than by an `<audio>` as an `Audio`. One answer for both, so the page
|
|
75
|
+
* and the fediverse never disagree about what a file is.
|
|
76
|
+
*/
|
|
77
|
+
export function playsAsVideo(type) {
|
|
78
|
+
return type.toLowerCase().startsWith('video/');
|
|
79
|
+
}
|
|
80
|
+
/** Whether a transcript is timed captions, which a player can show over the recording. */
|
|
81
|
+
export function isCaptions(transcript) {
|
|
82
|
+
return transcript.type === 'text/vtt' || transcript.type === 'application/x-subrip';
|
|
83
|
+
}
|
|
84
|
+
/** Whether a value is an absolute `http` or `https` URL. */
|
|
85
|
+
export function isWebUrl(value) {
|
|
86
|
+
try {
|
|
87
|
+
const url = new URL(value);
|
|
88
|
+
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Whether a value is a site-relative URL under `/uploads/` that cannot climb out of it. */
|
|
95
|
+
export function isUploadUrl(value) {
|
|
96
|
+
return (value.startsWith(UPLOAD_ASSET_PREFIX) &&
|
|
97
|
+
value.length > UPLOAD_ASSET_PREFIX.length &&
|
|
98
|
+
!/[?#\\]/.test(value) &&
|
|
99
|
+
!value.split('/').includes('..'));
|
|
100
|
+
}
|
|
101
|
+
/** Whether a value is a media type, `type/subtype`, with no parameters. */
|
|
102
|
+
export function isMediaType(value) {
|
|
103
|
+
return /^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*$/i.test(value);
|
|
104
|
+
}
|
|
105
|
+
function alternateOf(value) {
|
|
106
|
+
const raw = record(value);
|
|
107
|
+
if (raw === undefined)
|
|
108
|
+
return undefined;
|
|
109
|
+
const url = fileUrl(raw['url']);
|
|
110
|
+
const type = mediaType(raw['type']);
|
|
111
|
+
if (url === undefined || type === undefined)
|
|
112
|
+
return undefined;
|
|
113
|
+
const title = trimmed(raw['title']);
|
|
114
|
+
return {
|
|
115
|
+
url,
|
|
116
|
+
type,
|
|
117
|
+
...optional('length', positiveInteger(raw['length'])),
|
|
118
|
+
...(title !== undefined && title.length <= ALTERNATE_TITLE_MAX_LENGTH ? { title } : {}),
|
|
119
|
+
...optional('height', positiveInteger(raw['height'])),
|
|
120
|
+
...optional('lang', trimmed(raw['lang'])),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function transcriptOf(value) {
|
|
124
|
+
const raw = record(value);
|
|
125
|
+
if (raw === undefined)
|
|
126
|
+
return undefined;
|
|
127
|
+
const url = fileUrl(raw['url']);
|
|
128
|
+
const type = trimmed(raw['type'])?.toLowerCase();
|
|
129
|
+
if (url === undefined || type === undefined || !isTranscriptType(type))
|
|
130
|
+
return undefined;
|
|
131
|
+
return { url, type };
|
|
132
|
+
}
|
|
133
|
+
function isTranscriptType(value) {
|
|
134
|
+
return TRANSCRIPT_TYPES.includes(value);
|
|
135
|
+
}
|
|
136
|
+
function uploadUrl(value) {
|
|
137
|
+
const url = trimmed(value);
|
|
138
|
+
return url !== undefined && isUploadUrl(url) ? url : undefined;
|
|
139
|
+
}
|
|
140
|
+
function fileUrl(value) {
|
|
141
|
+
const url = trimmed(value);
|
|
142
|
+
return url !== undefined && (isUploadUrl(url) || isWebUrl(url)) ? url : undefined;
|
|
143
|
+
}
|
|
144
|
+
function mediaType(value) {
|
|
145
|
+
const type = trimmed(value)?.toLowerCase();
|
|
146
|
+
return type !== undefined && isMediaType(type) ? type : undefined;
|
|
147
|
+
}
|
|
148
|
+
function positiveInteger(value) {
|
|
149
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
150
|
+
}
|
|
151
|
+
function trimmed(value) {
|
|
152
|
+
if (typeof value !== 'string')
|
|
153
|
+
return undefined;
|
|
154
|
+
const text = value.trim();
|
|
155
|
+
return text === '' ? undefined : text;
|
|
156
|
+
}
|
|
157
|
+
function record(value) {
|
|
158
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
159
|
+
? value
|
|
160
|
+
: undefined;
|
|
161
|
+
}
|
|
162
|
+
function optional(key, value) {
|
|
163
|
+
return value === undefined ? {} : { [key]: value };
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=enclosure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclosure.js","sourceRoot":"","sources":["../../src/content/enclosure.ts"],"names":[],"mappings":"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"}
|
package/dist/content/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { KNOWN_FRONT_MATTER_KEYS } from './document.ts';
|
|
2
2
|
export type { ActivityPubMetadata, Document, DocumentContent, DocumentType } from './document.ts';
|
|
3
|
+
export { ENCLOSURE_FRONT_MATTER_KEY, enclosureOf, isCaptions, playsAsVideo, TRANSCRIPT_TYPES, } from './enclosure.ts';
|
|
4
|
+
export type { AlternateEnclosure, Enclosure, Transcript, TranscriptType } from './enclosure.ts';
|
|
3
5
|
export { renderMarkdown } from './markdown.ts';
|
|
4
6
|
export { KNOWN_UPLOAD_TYPES, matchesSignature, normalizeUploadType, UPLOAD_MEDIA_TYPES, } from './media.ts';
|
|
5
|
-
export type { UploadMediaType, UploadSignature } from './media.ts';
|
|
7
|
+
export type { UploadKind, UploadMediaType, UploadSignature } from './media.ts';
|
|
6
8
|
export { hashDocument, parseDocument, typeForPath } from './parser.ts';
|
|
7
9
|
export type { ParseDocumentOptions } from './parser.ts';
|
|
8
10
|
export { discoverPostType, postLabel, postTypeOf } from './post-type.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,YAAY,EAAE,mBAAmB,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,YAAY,EAAE,mBAAmB,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,EACL,0BAA0B,EAC1B,WAAW,EACX,UAAU,EACV,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACzE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpE,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5F,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,sBAAsB,EACtB,cAAc,EACd,SAAS,EACT,cAAc,EACd,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACb,WAAW,EACX,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,aAAa,EACb,KAAK,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,uBAAuB,EACvB,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACnE,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,WAAW,EACX,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,UAAU,GACX,MAAM,WAAW,CAAC"}
|
package/dist/content/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { KNOWN_FRONT_MATTER_KEYS } from './document.js';
|
|
2
|
+
export { ENCLOSURE_FRONT_MATTER_KEY, enclosureOf, isCaptions, playsAsVideo, TRANSCRIPT_TYPES, } from './enclosure.js';
|
|
2
3
|
export { renderMarkdown } from './markdown.js';
|
|
3
4
|
export { KNOWN_UPLOAD_TYPES, matchesSignature, normalizeUploadType, UPLOAD_MEDIA_TYPES, } from './media.js';
|
|
4
5
|
export { hashDocument, parseDocument, typeForPath } from './parser.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEpE,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,GACb,MAAM,eAAe,CAAC;AAQvB,OAAO,EACL,aAAa,EACb,WAAW,EACX,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,eAAe,GAChB,MAAM,YAAY,CAAC;AAapB,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EACL,0BAA0B,EAC1B,WAAW,EACX,UAAU,EACV,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEpE,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,GACb,MAAM,eAAe,CAAC;AAQvB,OAAO,EACL,aAAa,EACb,WAAW,EACX,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,eAAe,GAChB,MAAM,YAAY,CAAC;AAapB,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/content/media.d.ts
CHANGED
|
@@ -18,6 +18,13 @@ export interface UploadSignature {
|
|
|
18
18
|
/** The bytes themselves. */
|
|
19
19
|
bytes: readonly number[];
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* What an upload is for, which decides what the CMS offers to do with it.
|
|
23
|
+
*
|
|
24
|
+
* An image is embedded and gets variants, audio and video can be a post's
|
|
25
|
+
* enclosure and are held to their own size limit, and a document is linked.
|
|
26
|
+
*/
|
|
27
|
+
export type UploadKind = 'image' | 'audio' | 'video' | 'document';
|
|
21
28
|
/** One kind of file the upload endpoint knows about. */
|
|
22
29
|
export interface UploadMediaType {
|
|
23
30
|
/**
|
|
@@ -26,8 +33,8 @@ export interface UploadMediaType {
|
|
|
26
33
|
* sends no type at all, and there is then nothing to disagree with.
|
|
27
34
|
*/
|
|
28
35
|
declared: readonly string[];
|
|
29
|
-
/**
|
|
30
|
-
|
|
36
|
+
/** What the file is for. */
|
|
37
|
+
kind: UploadKind;
|
|
31
38
|
/**
|
|
32
39
|
* Byte patterns that identify the format, as alternatives: a file matches
|
|
33
40
|
* when every part of any one of them matches. Absent for the text formats,
|
|
@@ -54,6 +61,12 @@ export declare const KNOWN_UPLOAD_TYPES: readonly string[];
|
|
|
54
61
|
* file, so they are the same thing here.
|
|
55
62
|
*/
|
|
56
63
|
export declare function normalizeUploadType(value: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* The media type a feed or an attachment announces for this kind of file: the
|
|
66
|
+
* first one {@link UploadMediaType.declared} lists, which is the registered
|
|
67
|
+
* name where a browser may also send an older one.
|
|
68
|
+
*/
|
|
69
|
+
export declare function canonicalType(media: UploadMediaType): string | undefined;
|
|
57
70
|
/**
|
|
58
71
|
* Whether the first bytes of a file are the ones its extension implies.
|
|
59
72
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/content/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,6DAA6D;AAC7D,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,
|
|
1
|
+
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/content/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,6DAA6D;AAC7D,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC;AAElE,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,4BAA4B;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,eAAe,EAAE,CAAC,EAAE,GAAG,SAAS,CAAC;CAClE;AAgBD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CA+JlE,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAA0C,CAAC;AAE3F;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAExE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CASnF"}
|
package/dist/content/media.js
CHANGED
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
function ascii(value) {
|
|
16
16
|
return [...value].map((character) => character.charCodeAt(0));
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* An ISO base media file — MP4, M4A, M4V — whatever its brand: a box length,
|
|
20
|
+
* then `ftyp`.
|
|
21
|
+
*/
|
|
22
|
+
const ISO_BASE_MEDIA = [{ offset: 4, bytes: ascii('ftyp') }];
|
|
23
|
+
/** An Ogg page, whatever codec is inside it. */
|
|
24
|
+
const OGG = [{ offset: 0, bytes: ascii('OggS') }];
|
|
18
25
|
/**
|
|
19
26
|
* Every extension the upload endpoint can accept, and what it takes to be one.
|
|
20
27
|
*
|
|
@@ -29,7 +36,7 @@ export const UPLOAD_MEDIA_TYPES = new Map([
|
|
|
29
36
|
'.png',
|
|
30
37
|
{
|
|
31
38
|
declared: ['image/png'],
|
|
32
|
-
|
|
39
|
+
kind: 'image',
|
|
33
40
|
signatures: [[{ offset: 0, bytes: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a] }]],
|
|
34
41
|
},
|
|
35
42
|
],
|
|
@@ -37,7 +44,7 @@ export const UPLOAD_MEDIA_TYPES = new Map([
|
|
|
37
44
|
'.jpg',
|
|
38
45
|
{
|
|
39
46
|
declared: ['image/jpeg', 'image/jpg'],
|
|
40
|
-
|
|
47
|
+
kind: 'image',
|
|
41
48
|
signatures: [[{ offset: 0, bytes: [0xff, 0xd8, 0xff] }]],
|
|
42
49
|
},
|
|
43
50
|
],
|
|
@@ -45,7 +52,7 @@ export const UPLOAD_MEDIA_TYPES = new Map([
|
|
|
45
52
|
'.jpeg',
|
|
46
53
|
{
|
|
47
54
|
declared: ['image/jpeg', 'image/jpg'],
|
|
48
|
-
|
|
55
|
+
kind: 'image',
|
|
49
56
|
signatures: [[{ offset: 0, bytes: [0xff, 0xd8, 0xff] }]],
|
|
50
57
|
},
|
|
51
58
|
],
|
|
@@ -53,7 +60,7 @@ export const UPLOAD_MEDIA_TYPES = new Map([
|
|
|
53
60
|
'.gif',
|
|
54
61
|
{
|
|
55
62
|
declared: ['image/gif'],
|
|
56
|
-
|
|
63
|
+
kind: 'image',
|
|
57
64
|
signatures: [
|
|
58
65
|
[{ offset: 0, bytes: ascii('GIF87a') }],
|
|
59
66
|
[{ offset: 0, bytes: ascii('GIF89a') }],
|
|
@@ -64,7 +71,7 @@ export const UPLOAD_MEDIA_TYPES = new Map([
|
|
|
64
71
|
'.webp',
|
|
65
72
|
{
|
|
66
73
|
declared: ['image/webp'],
|
|
67
|
-
|
|
74
|
+
kind: 'image',
|
|
68
75
|
// A WebP is a RIFF container whose form type is WEBP, so both halves of
|
|
69
76
|
// the header have to be there.
|
|
70
77
|
signatures: [
|
|
@@ -79,7 +86,7 @@ export const UPLOAD_MEDIA_TYPES = new Map([
|
|
|
79
86
|
'.avif',
|
|
80
87
|
{
|
|
81
88
|
declared: ['image/avif'],
|
|
82
|
-
|
|
89
|
+
kind: 'image',
|
|
83
90
|
// An ISO base media file: a length, then `ftyp`, then the brand.
|
|
84
91
|
signatures: [
|
|
85
92
|
[
|
|
@@ -97,19 +104,87 @@ export const UPLOAD_MEDIA_TYPES = new Map([
|
|
|
97
104
|
'.pdf',
|
|
98
105
|
{
|
|
99
106
|
declared: ['application/pdf'],
|
|
100
|
-
|
|
107
|
+
kind: 'document',
|
|
101
108
|
signatures: [[{ offset: 0, bytes: ascii('%PDF-') }]],
|
|
102
109
|
},
|
|
103
110
|
],
|
|
104
111
|
// The two text formats have no header. Nothing is sniffed, and nothing needs
|
|
105
112
|
// to be: they are served as text, and `application/octet-stream` is allowed
|
|
106
113
|
// because that is what a browser sends for a file type it does not know.
|
|
107
|
-
['.txt', { declared: ['text/plain', 'application/octet-stream'],
|
|
114
|
+
['.txt', { declared: ['text/plain', 'application/octet-stream'], kind: 'document' }],
|
|
108
115
|
[
|
|
109
116
|
'.md',
|
|
110
117
|
{
|
|
111
118
|
declared: ['text/markdown', 'text/x-markdown', 'text/plain', 'application/octet-stream'],
|
|
112
|
-
|
|
119
|
+
kind: 'document',
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
// WebVTT opens with its name, after a byte order mark when the editor that
|
|
123
|
+
// wrote it added one. SubRip has no header, so it is taken as text like the
|
|
124
|
+
// two formats above.
|
|
125
|
+
[
|
|
126
|
+
'.vtt',
|
|
127
|
+
{
|
|
128
|
+
declared: ['text/vtt', 'text/plain', 'application/octet-stream'],
|
|
129
|
+
kind: 'document',
|
|
130
|
+
signatures: [
|
|
131
|
+
[{ offset: 0, bytes: ascii('WEBVTT') }],
|
|
132
|
+
[{ offset: 0, bytes: [0xef, 0xbb, 0xbf, ...ascii('WEBVTT')] }],
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
[
|
|
137
|
+
'.srt',
|
|
138
|
+
{
|
|
139
|
+
declared: ['application/x-subrip', 'text/srt', 'text/plain', 'application/octet-stream'],
|
|
140
|
+
kind: 'document',
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
[
|
|
144
|
+
'.mp3',
|
|
145
|
+
{
|
|
146
|
+
declared: ['audio/mpeg', 'audio/mp3'],
|
|
147
|
+
kind: 'audio',
|
|
148
|
+
// An ID3 tag, or straight into an MPEG audio frame: eleven sync bits,
|
|
149
|
+
// then MPEG-1 or MPEG-2 layer III, with or without a CRC.
|
|
150
|
+
signatures: [
|
|
151
|
+
[{ offset: 0, bytes: ascii('ID3') }],
|
|
152
|
+
[{ offset: 0, bytes: [0xff, 0xfb] }],
|
|
153
|
+
[{ offset: 0, bytes: [0xff, 0xfa] }],
|
|
154
|
+
[{ offset: 0, bytes: [0xff, 0xf3] }],
|
|
155
|
+
[{ offset: 0, bytes: [0xff, 0xf2] }],
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
[
|
|
160
|
+
'.m4a',
|
|
161
|
+
{
|
|
162
|
+
declared: ['audio/mp4', 'audio/x-m4a', 'audio/m4a'],
|
|
163
|
+
kind: 'audio',
|
|
164
|
+
signatures: [ISO_BASE_MEDIA],
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
[
|
|
168
|
+
'.aac',
|
|
169
|
+
{
|
|
170
|
+
declared: ['audio/aac', 'audio/x-aac', 'audio/aacp'],
|
|
171
|
+
kind: 'audio',
|
|
172
|
+
// A raw ADTS stream: twelve sync bits, MPEG-4 or MPEG-2, no CRC.
|
|
173
|
+
signatures: [[{ offset: 0, bytes: [0xff, 0xf1] }], [{ offset: 0, bytes: [0xff, 0xf9] }]],
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
['.ogg', { declared: ['audio/ogg', 'application/ogg'], kind: 'audio', signatures: [OGG] }],
|
|
177
|
+
['.oga', { declared: ['audio/ogg', 'application/ogg'], kind: 'audio', signatures: [OGG] }],
|
|
178
|
+
['.opus', { declared: ['audio/ogg', 'audio/opus'], kind: 'audio', signatures: [OGG] }],
|
|
179
|
+
['.mp4', { declared: ['video/mp4'], kind: 'video', signatures: [ISO_BASE_MEDIA] }],
|
|
180
|
+
['.m4v', { declared: ['video/mp4', 'video/x-m4v'], kind: 'video', signatures: [ISO_BASE_MEDIA] }],
|
|
181
|
+
[
|
|
182
|
+
'.webm',
|
|
183
|
+
{
|
|
184
|
+
declared: ['video/webm', 'audio/webm'],
|
|
185
|
+
kind: 'video',
|
|
186
|
+
// The EBML header every Matroska file, WebM included, opens with.
|
|
187
|
+
signatures: [[{ offset: 0, bytes: [0x1a, 0x45, 0xdf, 0xa3] }]],
|
|
113
188
|
},
|
|
114
189
|
],
|
|
115
190
|
]);
|
|
@@ -127,6 +202,14 @@ export function normalizeUploadType(value) {
|
|
|
127
202
|
return '';
|
|
128
203
|
return trimmed.startsWith('.') ? trimmed : `.${trimmed}`;
|
|
129
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* The media type a feed or an attachment announces for this kind of file: the
|
|
207
|
+
* first one {@link UploadMediaType.declared} lists, which is the registered
|
|
208
|
+
* name where a browser may also send an older one.
|
|
209
|
+
*/
|
|
210
|
+
export function canonicalType(media) {
|
|
211
|
+
return media.declared[0];
|
|
212
|
+
}
|
|
130
213
|
/**
|
|
131
214
|
* Whether the first bytes of a file are the ones its extension implies.
|
|
132
215
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/content/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/content/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoCH,uEAAuE;AACvE,SAAS,KAAK,CAAC,KAAa;IAC1B,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;GAGG;AACH,MAAM,cAAc,GAA+B,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAEzF,gDAAgD;AAChD,MAAM,GAAG,GAA+B,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAE9E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAyC,IAAI,GAAG,CAG7E;IACA;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,WAAW,CAAC;YACvB,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;SACvF;KACF;IACD;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;YACrC,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;SACzD;KACF;IACD;QACE,OAAO;QACP;YACE,QAAQ,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;YACrC,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;SACzD;KACF;IACD;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,WAAW,CAAC;YACvB,IAAI,EAAE,OAAO;YACb,UAAU,EAAE;gBACV,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACvC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;aACxC;SACF;KACF;IACD;QACE,OAAO;QACP;YACE,QAAQ,EAAE,CAAC,YAAY,CAAC;YACxB,IAAI,EAAE,OAAO;YACb,wEAAwE;YACxE,+BAA+B;YAC/B,UAAU,EAAE;gBACV;oBACE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;oBACnC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;iBACpC;aACF;SACF;KACF;IACD;QACE,OAAO;QACP;YACE,QAAQ,EAAE,CAAC,YAAY,CAAC;YACxB,IAAI,EAAE,OAAO;YACb,iEAAiE;YACjE,UAAU,EAAE;gBACV;oBACE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;oBACnC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;iBACpC;gBACD;oBACE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;oBACnC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;iBACpC;aACF;SACF;KACF;IACD;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,iBAAiB,CAAC;YAC7B,IAAI,EAAE,UAAU;YAChB,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;SACrD;KACF;IACD,6EAA6E;IAC7E,4EAA4E;IAC5E,yEAAyE;IACzE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,YAAY,EAAE,0BAA0B,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IACpF;QACE,KAAK;QACL;YACE,QAAQ,EAAE,CAAC,eAAe,EAAE,iBAAiB,EAAE,YAAY,EAAE,0BAA0B,CAAC;YACxF,IAAI,EAAE,UAAU;SACjB;KACF;IACD,2EAA2E;IAC3E,4EAA4E;IAC5E,qBAAqB;IACrB;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,UAAU,EAAE,YAAY,EAAE,0BAA0B,CAAC;YAChE,IAAI,EAAE,UAAU;YAChB,UAAU,EAAE;gBACV,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACvC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;aAC/D;SACF;KACF;IACD;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,sBAAsB,EAAE,UAAU,EAAE,YAAY,EAAE,0BAA0B,CAAC;YACxF,IAAI,EAAE,UAAU;SACjB;KACF;IACD;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;YACrC,IAAI,EAAE,OAAO;YACb,sEAAsE;YACtE,0DAA0D;YAC1D,UAAU,EAAE;gBACV,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACpC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACpC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACpC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;aACrC;SACF;KACF;IACD;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC;YACnD,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,CAAC,cAAc,CAAC;SAC7B;KACF;IACD;QACE,MAAM;QACN;YACE,QAAQ,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,YAAY,CAAC;YACpD,IAAI,EAAE,OAAO;YACb,iEAAiE;YACjE,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;SACzF;KACF;IACD,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1F,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1F,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IACtF,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;IAClF,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;IACjG;QACE,OAAO;QACP;YACE,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;YACtC,IAAI,EAAE,OAAO;YACb,kEAAkE;YAClE,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;SAC/D;KACF;CACF,CAAC,CAAC;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,kBAAkB,GAAsB,CAAC,GAAG,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAE3F;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAC9B,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAsB;IAClD,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAsB,EAAE,KAAiB;IACxE,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC;IACtC,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5C,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CACrC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CACvB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,CACvE,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Document } from './document.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The front matter key that pins a post to the top of its author's profile
|
|
4
|
+
* (TASK-207): `pinned: <ISO instant>`, written when the author pinned it.
|
|
5
|
+
*
|
|
6
|
+
* An instant rather than `true`, so the order the fediverse shows pins in
|
|
7
|
+
* (most recently pinned first, as Mastodon does) lives in the file with the
|
|
8
|
+
* pin itself (decision-9) instead of in an index that a rebuild would lose.
|
|
9
|
+
*/
|
|
10
|
+
export declare const PINNED_FRONT_MATTER_KEY = "pinned";
|
|
11
|
+
/** How many posts one author can pin, which is Mastodon's own limit. */
|
|
12
|
+
export declare const PINNED_POST_LIMIT = 5;
|
|
13
|
+
/**
|
|
14
|
+
* When a post was pinned, as a UTC instant, or `undefined` for one that is not.
|
|
15
|
+
*
|
|
16
|
+
* YAML hands back an unquoted timestamp as a `Date` and a quoted one as a
|
|
17
|
+
* string; both are read. A hand-written `pinned: true` has no moment of its
|
|
18
|
+
* own, so it reads as the post's date and sorts among the others by that.
|
|
19
|
+
*/
|
|
20
|
+
export declare function pinnedAt(document: Document): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* The pinned ones among some posts, most recently pinned first and no more
|
|
23
|
+
* than {@link PINNED_POST_LIMIT} of them: an author's featured collection.
|
|
24
|
+
*/
|
|
25
|
+
export declare function featuredPosts(documents: readonly Document[]): Document[];
|
|
26
|
+
//# sourceMappingURL=pinned.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pinned.d.ts","sourceRoot":"","sources":["../../src/content/pinned.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG9C;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAK/D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,EAAE,CASxE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { toUtcInstant } from './time.js';
|
|
2
|
+
/**
|
|
3
|
+
* The front matter key that pins a post to the top of its author's profile
|
|
4
|
+
* (TASK-207): `pinned: <ISO instant>`, written when the author pinned it.
|
|
5
|
+
*
|
|
6
|
+
* An instant rather than `true`, so the order the fediverse shows pins in
|
|
7
|
+
* (most recently pinned first, as Mastodon does) lives in the file with the
|
|
8
|
+
* pin itself (decision-9) instead of in an index that a rebuild would lose.
|
|
9
|
+
*/
|
|
10
|
+
export const PINNED_FRONT_MATTER_KEY = 'pinned';
|
|
11
|
+
/** How many posts one author can pin, which is Mastodon's own limit. */
|
|
12
|
+
export const PINNED_POST_LIMIT = 5;
|
|
13
|
+
/**
|
|
14
|
+
* When a post was pinned, as a UTC instant, or `undefined` for one that is not.
|
|
15
|
+
*
|
|
16
|
+
* YAML hands back an unquoted timestamp as a `Date` and a quoted one as a
|
|
17
|
+
* string; both are read. A hand-written `pinned: true` has no moment of its
|
|
18
|
+
* own, so it reads as the post's date and sorts among the others by that.
|
|
19
|
+
*/
|
|
20
|
+
export function pinnedAt(document) {
|
|
21
|
+
const value = document.extra[PINNED_FRONT_MATTER_KEY];
|
|
22
|
+
if (value === true)
|
|
23
|
+
return document.date ?? '';
|
|
24
|
+
if (typeof value !== 'string' && !(value instanceof Date))
|
|
25
|
+
return undefined;
|
|
26
|
+
return toUtcInstant(value, 'UTC');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The pinned ones among some posts, most recently pinned first and no more
|
|
30
|
+
* than {@link PINNED_POST_LIMIT} of them: an author's featured collection.
|
|
31
|
+
*/
|
|
32
|
+
export function featuredPosts(documents) {
|
|
33
|
+
return documents
|
|
34
|
+
.flatMap((document) => {
|
|
35
|
+
const at = pinnedAt(document);
|
|
36
|
+
return at === undefined ? [] : [{ document, at }];
|
|
37
|
+
})
|
|
38
|
+
.sort((a, b) => (a.at < b.at ? 1 : a.at > b.at ? -1 : 0))
|
|
39
|
+
.slice(0, PINNED_POST_LIMIT)
|
|
40
|
+
.map(({ document }) => document);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=pinned.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pinned.js","sourceRoot":"","sources":["../../src/content/pinned.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAEhD,wEAAwE;AACxE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAkB;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACtD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5E,OAAO,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,SAA8B;IAC1D,OAAO,SAAS;SACb,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QACpB,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC9B,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACxD,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC;SAC3B,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC"}
|
package/dist/content/store.d.ts
CHANGED
|
@@ -166,6 +166,13 @@ export interface ContentStore {
|
|
|
166
166
|
* of the furniture of the site rather than of anybody's body of work.
|
|
167
167
|
*/
|
|
168
168
|
listByAuthor(names: readonly string[], options?: ListOptions): Document[];
|
|
169
|
+
/**
|
|
170
|
+
* The posts of one user's archive that carry a `pinned` key, most recently
|
|
171
|
+
* pinned first and capped at `PINNED_POST_LIMIT`: their featured collection
|
|
172
|
+
* (TASK-207). The same archive {@link ContentStore.listByAuthor} reads, so a
|
|
173
|
+
* draft, a trashed post or a scheduled one is never featured.
|
|
174
|
+
*/
|
|
175
|
+
listPinnedByAuthor(names: readonly string[]): Document[];
|
|
169
176
|
/** Everything the admin may see, trash and drafts included unless filtered. */
|
|
170
177
|
listAll(options?: ListAllOptions): Document[];
|
|
171
178
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/content/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAuB,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/content/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAuB,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAIjF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC;;;;;GAKG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC;AAE/B,wDAAwD;AACxD,eAAO,MAAM,WAAW,EAAE,KAAwB,CAAC;AAEnD,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;CACzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,GAAG,IAAI,IAAI,CAAC;IACZ;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IACjC,0EAA0E;IAC1E,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAC/C,+EAA+E;IAC/E,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,IAAI,IAAI,CAAC;IACd,+DAA+D;IAC/D,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC9C,6EAA6E;IAC7E,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxD;;;;;;;;;OASG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5D;;;;;;;;OAQG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC9D;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC9C,6DAA6D;IAC7D,SAAS,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,QAAQ,EAAE,CAAC;IAC7C;;;;;;;;;OASG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAC5C;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,kBAAkB,CAAC;IACnD;;;;;;OAMG;IACH,OAAO,IAAI,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;;;OAMG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IACxC,mEAAmE;IACnE,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,QAAQ,EAAE,CAAC;IAC/D,2EAA2E;IAC3E,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,QAAQ,EAAE,CAAC;IACzE;;;;;;;;;;;;;;OAcG;IACH,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,QAAQ,EAAE,CAAC;IAC1E;;;;;OAKG;IACH,kBAAkB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACzD,+EAA+E;IAC/E,OAAO,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,QAAQ,EAAE,CAAC;IAC9C;;;;;;;;;;OAUG;IACH,aAAa,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,QAAQ,EAAE,CAAC;IACjD,iFAAiF;IACjF,SAAS,IAAI,MAAM,EAAE,CAAC;IACtB,iDAAiD;IACjD,MAAM,IAAI,aAAa,CAAC;IACxB,2DAA2D;IAC3D,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IAC5D,0EAA0E;IAC1E,QAAQ,IAAI,QAAQ,EAAE,CAAC;IACvB,0EAA0E;IAC1E,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IACtE,gGAAgG;IAChG,aAAa,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC;IAChD,+EAA+E;IAC/E,cAAc,IAAI,aAAa,EAAE,CAAC;IAClC;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,CAAC;IACnD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,EAAE,CAAC;IAC1D,gFAAgF;IAChF,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,8CAA8C;IAC9C,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,kEAAkE;IAClE,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B;AAED,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACxB,oBAAoB;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,8DAA8D;AAC9D,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,oDAAoD;IACpD,IAAI,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACjC;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,oDAAoD;IACpD,IAAI,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAChC,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,yDAAyD;AACzD,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,UAAU,CAAC;AAE9C,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACxB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAkB,IAAI,6BAA6B;IACnD,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IAE7C,YAAY,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,SAAS,EAS/E;CACF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAInE;AA+DD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,YAAY,CAiiB/E"}
|
package/dist/content/store.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { databaseFile, openDatabase } from '../cache.js';
|
|
2
|
+
import { featuredPosts, PINNED_FRONT_MATTER_KEY } from './pinned.js';
|
|
2
3
|
import { searchExpression, searchText, SNIPPET_CLOSE, SNIPPET_OPEN } from './search.js';
|
|
3
4
|
export { DATABASE_FILE } from '../cache.js';
|
|
4
5
|
/** Directory name that marks a document as thrown away but not yet deleted. */
|
|
@@ -60,6 +61,13 @@ export function dateSortKey(date) {
|
|
|
60
61
|
const DUE_CLAUSE = '(date_sort IS NULL OR date_sort <= ?)';
|
|
61
62
|
/** The reverse: a document whose date is still ahead of the clock. */
|
|
62
63
|
const SCHEDULED_CLAUSE = '(date_sort IS NOT NULL AND date_sort > ?)';
|
|
64
|
+
/**
|
|
65
|
+
* A document whose front matter carries a `pinned` key that is not `false`.
|
|
66
|
+
* Which moment it was pinned at, and whether it is readable at all, is
|
|
67
|
+
* `content/pinned.ts`'s to decide; this only keeps the rest of an archive from
|
|
68
|
+
* being hydrated to find out.
|
|
69
|
+
*/
|
|
70
|
+
const PINNED_CLAUSE = `COALESCE(json_extract(extra, '$.${PINNED_FRONT_MATTER_KEY}'), 0) NOT IN (0, '')`;
|
|
63
71
|
/**
|
|
64
72
|
* The clause that picks out a document some follower holds a copy of: one
|
|
65
73
|
* whose `activitypub` block records when it was announced.
|
|
@@ -434,6 +442,18 @@ export function openContentStore(options) {
|
|
|
434
442
|
return [];
|
|
435
443
|
return select(["type = 'post'", 'draft = 0', 'trashed = 0', DUE_CLAUSE, authorClause(names)], [nowKey(), ...names], options);
|
|
436
444
|
},
|
|
445
|
+
listPinnedByAuthor(names) {
|
|
446
|
+
if (names.length === 0)
|
|
447
|
+
return [];
|
|
448
|
+
return featuredPosts(select([
|
|
449
|
+
"type = 'post'",
|
|
450
|
+
'draft = 0',
|
|
451
|
+
'trashed = 0',
|
|
452
|
+
DUE_CLAUSE,
|
|
453
|
+
authorClause(names),
|
|
454
|
+
PINNED_CLAUSE,
|
|
455
|
+
], [nowKey(), ...names], {}));
|
|
456
|
+
},
|
|
437
457
|
listAll(options = {}) {
|
|
438
458
|
const where = [];
|
|
439
459
|
const params = [];
|