@geekity/cms 0.3.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/LICENSE +21 -0
- package/README.md +870 -0
- package/admin/layouts/_flash.njk +5 -0
- package/admin/layouts/base.njk +27 -0
- package/admin/layouts/dashboard.njk +78 -0
- package/admin/layouts/document-conflict.njk +49 -0
- package/admin/layouts/document-editor.njk +167 -0
- package/admin/layouts/document-list.njk +92 -0
- package/admin/layouts/federation.njk +145 -0
- package/admin/layouts/login.njk +23 -0
- package/admin/layouts/placeholder.njk +10 -0
- package/admin/layouts/settings.njk +116 -0
- package/admin/layouts/setup.njk +27 -0
- package/admin/layouts/shell.njk +37 -0
- package/admin/layouts/users.njk +91 -0
- package/admin/static/admin.css +726 -0
- package/admin/static/editor.js +30 -0
- package/dist/admin/assets.d.ts +26 -0
- package/dist/admin/assets.d.ts.map +1 -0
- package/dist/admin/assets.js +38 -0
- package/dist/admin/assets.js.map +1 -0
- package/dist/admin/credentials.d.ts +28 -0
- package/dist/admin/credentials.d.ts.map +1 -0
- package/dist/admin/credentials.js +39 -0
- package/dist/admin/credentials.js.map +1 -0
- package/dist/admin/documents.d.ts +134 -0
- package/dist/admin/documents.d.ts.map +1 -0
- package/dist/admin/documents.js +613 -0
- package/dist/admin/documents.js.map +1 -0
- package/dist/admin/federation.d.ts +194 -0
- package/dist/admin/federation.d.ts.map +1 -0
- package/dist/admin/federation.js +299 -0
- package/dist/admin/federation.js.map +1 -0
- package/dist/admin/flash.d.ts +24 -0
- package/dist/admin/flash.d.ts.map +1 -0
- package/dist/admin/flash.js +31 -0
- package/dist/admin/flash.js.map +1 -0
- package/dist/admin/index.d.ts +23 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +15 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/passwords.d.ts +49 -0
- package/dist/admin/passwords.d.ts.map +1 -0
- package/dist/admin/passwords.js +122 -0
- package/dist/admin/passwords.js.map +1 -0
- package/dist/admin/preview.d.ts +18 -0
- package/dist/admin/preview.d.ts.map +1 -0
- package/dist/admin/preview.js +83 -0
- package/dist/admin/preview.js.map +1 -0
- package/dist/admin/routes.d.ts +54 -0
- package/dist/admin/routes.d.ts.map +1 -0
- package/dist/admin/routes.js +383 -0
- package/dist/admin/routes.js.map +1 -0
- package/dist/admin/session.d.ts +44 -0
- package/dist/admin/session.d.ts.map +1 -0
- package/dist/admin/session.js +69 -0
- package/dist/admin/session.js.map +1 -0
- package/dist/admin/settings.d.ts +194 -0
- package/dist/admin/settings.d.ts.map +1 -0
- package/dist/admin/settings.js +470 -0
- package/dist/admin/settings.js.map +1 -0
- package/dist/admin/store.d.ts +407 -0
- package/dist/admin/store.d.ts.map +1 -0
- package/dist/admin/store.js +704 -0
- package/dist/admin/store.js.map +1 -0
- package/dist/admin/templates.d.ts +36 -0
- package/dist/admin/templates.d.ts.map +1 -0
- package/dist/admin/templates.js +43 -0
- package/dist/admin/templates.js.map +1 -0
- package/dist/admin/uploads.d.ts +96 -0
- package/dist/admin/uploads.d.ts.map +1 -0
- package/dist/admin/uploads.js +179 -0
- package/dist/admin/uploads.js.map +1 -0
- package/dist/admin/users.d.ts +95 -0
- package/dist/admin/users.d.ts.map +1 -0
- package/dist/admin/users.js +233 -0
- package/dist/admin/users.js.map +1 -0
- package/dist/cli.d.ts +85 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +424 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +172 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +184 -0
- package/dist/config.js.map +1 -0
- package/dist/content/document.d.ts +66 -0
- package/dist/content/document.d.ts.map +1 -0
- package/dist/content/document.js +13 -0
- package/dist/content/document.js.map +1 -0
- package/dist/content/index.d.ts +17 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/index.js +10 -0
- package/dist/content/index.js.map +1 -0
- package/dist/content/markdown.d.ts +3 -0
- package/dist/content/markdown.d.ts.map +1 -0
- package/dist/content/markdown.js +39 -0
- package/dist/content/markdown.js.map +1 -0
- package/dist/content/media.d.ts +65 -0
- package/dist/content/media.d.ts.map +1 -0
- package/dist/content/media.js +143 -0
- package/dist/content/media.js.map +1 -0
- package/dist/content/parser.d.ts +24 -0
- package/dist/content/parser.d.ts.map +1 -0
- package/dist/content/parser.js +165 -0
- package/dist/content/parser.js.map +1 -0
- package/dist/content/save.d.ts +60 -0
- package/dist/content/save.d.ts.map +1 -0
- package/dist/content/save.js +103 -0
- package/dist/content/save.js.map +1 -0
- package/dist/content/slug.d.ts +25 -0
- package/dist/content/slug.d.ts.map +1 -0
- package/dist/content/slug.js +75 -0
- package/dist/content/slug.js.map +1 -0
- package/dist/content/store.d.ts +133 -0
- package/dist/content/store.d.ts.map +1 -0
- package/dist/content/store.js +411 -0
- package/dist/content/store.js.map +1 -0
- package/dist/content/sync.d.ts +146 -0
- package/dist/content/sync.d.ts.map +1 -0
- package/dist/content/sync.js +421 -0
- package/dist/content/sync.js.map +1 -0
- package/dist/content/writer.d.ts +37 -0
- package/dist/content/writer.d.ts.map +1 -0
- package/dist/content/writer.js +97 -0
- package/dist/content/writer.js.map +1 -0
- package/dist/env.d.ts +48 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +2 -0
- package/dist/env.js.map +1 -0
- package/dist/federation/actor.d.ts +55 -0
- package/dist/federation/actor.d.ts.map +1 -0
- package/dist/federation/actor.js +101 -0
- package/dist/federation/actor.js.map +1 -0
- package/dist/federation/article.d.ts +83 -0
- package/dist/federation/article.d.ts.map +1 -0
- package/dist/federation/article.js +169 -0
- package/dist/federation/article.js.map +1 -0
- package/dist/federation/delivery.d.ts +90 -0
- package/dist/federation/delivery.d.ts.map +1 -0
- package/dist/federation/delivery.js +289 -0
- package/dist/federation/delivery.js.map +1 -0
- package/dist/federation/federation.d.ts +75 -0
- package/dist/federation/federation.d.ts.map +1 -0
- package/dist/federation/federation.js +190 -0
- package/dist/federation/federation.js.map +1 -0
- package/dist/federation/followers.d.ts +43 -0
- package/dist/federation/followers.d.ts.map +1 -0
- package/dist/federation/followers.js +69 -0
- package/dist/federation/followers.js.map +1 -0
- package/dist/federation/inbox.d.ts +68 -0
- package/dist/federation/inbox.d.ts.map +1 -0
- package/dist/federation/inbox.js +171 -0
- package/dist/federation/inbox.js.map +1 -0
- package/dist/federation/index.d.ts +14 -0
- package/dist/federation/index.d.ts.map +1 -0
- package/dist/federation/index.js +10 -0
- package/dist/federation/index.js.map +1 -0
- package/dist/federation/keys.d.ts +27 -0
- package/dist/federation/keys.d.ts.map +1 -0
- package/dist/federation/keys.js +60 -0
- package/dist/federation/keys.js.map +1 -0
- package/dist/federation/mount.d.ts +23 -0
- package/dist/federation/mount.d.ts.map +1 -0
- package/dist/federation/mount.js +71 -0
- package/dist/federation/mount.js.map +1 -0
- package/dist/federation/paths.d.ts +85 -0
- package/dist/federation/paths.d.ts.map +1 -0
- package/dist/federation/paths.js +97 -0
- package/dist/federation/paths.js.map +1 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +148 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +71 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +125 -0
- package/dist/init.js.map +1 -0
- package/dist/web/assets.d.ts +65 -0
- package/dist/web/assets.d.ts.map +1 -0
- package/dist/web/assets.js +152 -0
- package/dist/web/assets.js.map +1 -0
- package/dist/web/context.d.ts +121 -0
- package/dist/web/context.d.ts.map +1 -0
- package/dist/web/context.js +112 -0
- package/dist/web/context.js.map +1 -0
- package/dist/web/documents.d.ts +28 -0
- package/dist/web/documents.d.ts.map +1 -0
- package/dist/web/documents.js +39 -0
- package/dist/web/documents.js.map +1 -0
- package/dist/web/feeds.d.ts +122 -0
- package/dist/web/feeds.d.ts.map +1 -0
- package/dist/web/feeds.js +229 -0
- package/dist/web/feeds.js.map +1 -0
- package/dist/web/index.d.ts +17 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +10 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/negotiate.d.ts +219 -0
- package/dist/web/negotiate.d.ts.map +1 -0
- package/dist/web/negotiate.js +409 -0
- package/dist/web/negotiate.js.map +1 -0
- package/dist/web/pagination.d.ts +48 -0
- package/dist/web/pagination.d.ts.map +1 -0
- package/dist/web/pagination.js +30 -0
- package/dist/web/pagination.js.map +1 -0
- package/dist/web/render.d.ts +72 -0
- package/dist/web/render.d.ts.map +1 -0
- package/dist/web/render.js +73 -0
- package/dist/web/render.js.map +1 -0
- package/dist/web/routes.d.ts +31 -0
- package/dist/web/routes.d.ts.map +1 -0
- package/dist/web/routes.js +366 -0
- package/dist/web/routes.js.map +1 -0
- package/dist/web/templates.d.ts +34 -0
- package/dist/web/templates.d.ts.map +1 -0
- package/dist/web/templates.js +106 -0
- package/dist/web/templates.js.map +1 -0
- package/package.json +68 -0
- package/templates/site/content/_data/site.json +8 -0
- package/templates/site/content/pages/about.md +11 -0
- package/templates/site/content/pages/pages.json +3 -0
- package/templates/site/content/posts/2026-01-01-hello-world.md +34 -0
- package/templates/site/content/posts/posts.json +4 -0
- package/templates/site/geekity.config.ts +11 -0
- package/templates/site/gitignore +3 -0
- package/templates/site/server.ts +20 -0
- package/templates/site/tsconfig.json +18 -0
- package/themes/default/README.md +148 -0
- package/themes/default/layouts/404.njk +9 -0
- package/themes/default/layouts/base.njk +59 -0
- package/themes/default/layouts/home.njk +9 -0
- package/themes/default/layouts/page.njk +13 -0
- package/themes/default/layouts/post.njk +30 -0
- package/themes/default/layouts/tag.njk +19 -0
- package/themes/default/partials/pagination.njk +14 -0
- package/themes/default/partials/post-list.njk +24 -0
- package/themes/default/partials/tags.njk +12 -0
- package/themes/default/static/style.css +327 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { watch as watchPaths } from 'chokidar';
|
|
4
|
+
import { parseDocument } from './parser.js';
|
|
5
|
+
import { DuplicatePermalinkError, isTrashedPath, TRASH_DIRECTORY } from './store.js';
|
|
6
|
+
/** File extensions the sync treats as documents. */
|
|
7
|
+
const MARKDOWN_EXTENSIONS = new Set(['.md', '.markdown']);
|
|
8
|
+
/** How long the watcher waits for a path to stop changing before re-reading it. */
|
|
9
|
+
export const DEFAULT_DEBOUNCE_MS = 100;
|
|
10
|
+
/** Directories that hold documents. Everything else in `content/` is not indexed. */
|
|
11
|
+
const DOCUMENT_DIRECTORIES = new Map([
|
|
12
|
+
['posts', 'post'],
|
|
13
|
+
['pages', 'page'],
|
|
14
|
+
]);
|
|
15
|
+
/**
|
|
16
|
+
* Build the sync for one content directory.
|
|
17
|
+
*
|
|
18
|
+
* Files are the source of truth (decision-1). A scan parses every document
|
|
19
|
+
* under `content/`, writes the ones whose hash differs from the indexed row,
|
|
20
|
+
* and drops rows whose file has gone. Nothing else in the directory is
|
|
21
|
+
* touched: uploads, directory data files and every underscore-prefixed
|
|
22
|
+
* directory but `_trash` are skipped.
|
|
23
|
+
*/
|
|
24
|
+
export function createContentSync(options) {
|
|
25
|
+
const { store, contentDir } = options;
|
|
26
|
+
const logger = options.logger ?? console;
|
|
27
|
+
const events = createEmitter(logger);
|
|
28
|
+
/**
|
|
29
|
+
* Write a document, giving way to a file that has already gone.
|
|
30
|
+
*
|
|
31
|
+
* Renaming a file — which is what trashing and restoring are — briefly
|
|
32
|
+
* leaves two rows claiming one permalink, and the watcher may well see the
|
|
33
|
+
* new name before the old one disappears. When the conflicting row's file is
|
|
34
|
+
* no longer on disk the row is stale, so it is dropped (and reported) and
|
|
35
|
+
* the write retried. A conflict between two files that both exist is a
|
|
36
|
+
* content mistake and is left to the caller to report.
|
|
37
|
+
*/
|
|
38
|
+
async function index(document, origin) {
|
|
39
|
+
try {
|
|
40
|
+
store.upsert(document);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (!(error instanceof DuplicatePermalinkError))
|
|
45
|
+
throw error;
|
|
46
|
+
const conflicting = error.conflictingPath;
|
|
47
|
+
if (conflicting === undefined)
|
|
48
|
+
throw error;
|
|
49
|
+
if (await exists(path.join(contentDir, conflicting)))
|
|
50
|
+
throw error;
|
|
51
|
+
const stale = store.getByPath(conflicting);
|
|
52
|
+
store.remove(conflicting);
|
|
53
|
+
if (stale !== undefined) {
|
|
54
|
+
await emitChange(events, {
|
|
55
|
+
type: 'deleted',
|
|
56
|
+
path: conflicting,
|
|
57
|
+
previous: stale,
|
|
58
|
+
next: undefined,
|
|
59
|
+
origin,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
store.upsert(document);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function reconcile(relativePath, origin) {
|
|
66
|
+
const previous = store.getByPath(relativePath);
|
|
67
|
+
const source = await readSource(path.join(contentDir, relativePath));
|
|
68
|
+
if (source === undefined) {
|
|
69
|
+
if (previous === undefined)
|
|
70
|
+
return false;
|
|
71
|
+
store.remove(relativePath);
|
|
72
|
+
await emitChange(events, {
|
|
73
|
+
type: 'deleted',
|
|
74
|
+
path: relativePath,
|
|
75
|
+
previous,
|
|
76
|
+
next: undefined,
|
|
77
|
+
origin,
|
|
78
|
+
});
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
let document;
|
|
82
|
+
try {
|
|
83
|
+
document = parseDocument(source, { path: relativePath });
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
logger.warn(`Skipping ${relativePath}: ${messageOf(error)}`);
|
|
87
|
+
throw new SkippedFile();
|
|
88
|
+
}
|
|
89
|
+
// The hash covers the canonical file text, so a rewrite that changes
|
|
90
|
+
// nothing — an admin save, a touch, the watcher event that follows an
|
|
91
|
+
// admin write — costs no index write and emits no event.
|
|
92
|
+
if (previous !== undefined && previous.hash === document.hash)
|
|
93
|
+
return false;
|
|
94
|
+
try {
|
|
95
|
+
await index(document, origin);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
logger.warn(`Could not index ${relativePath}: ${messageOf(error)}`);
|
|
99
|
+
throw new SkippedFile();
|
|
100
|
+
}
|
|
101
|
+
await emitChange(events, {
|
|
102
|
+
type: previous === undefined ? 'created' : 'updated',
|
|
103
|
+
path: relativePath,
|
|
104
|
+
previous,
|
|
105
|
+
next: document,
|
|
106
|
+
origin,
|
|
107
|
+
});
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
async function scan() {
|
|
111
|
+
const result = {
|
|
112
|
+
scanned: 0,
|
|
113
|
+
created: 0,
|
|
114
|
+
updated: 0,
|
|
115
|
+
removed: 0,
|
|
116
|
+
unchanged: 0,
|
|
117
|
+
failed: 0,
|
|
118
|
+
};
|
|
119
|
+
const onDisk = await walk(contentDir, logger);
|
|
120
|
+
const seen = new Set(onDisk);
|
|
121
|
+
// Rows whose file has gone go first, so a document that was renamed —
|
|
122
|
+
// moving into or out of `_trash/` is a rename — does not collide with its
|
|
123
|
+
// own old row over the permalink they share.
|
|
124
|
+
for (const indexed of store.listPaths()) {
|
|
125
|
+
if (seen.has(indexed))
|
|
126
|
+
continue;
|
|
127
|
+
try {
|
|
128
|
+
if (await reconcile(indexed, 'scan'))
|
|
129
|
+
result.removed += 1;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (!(error instanceof SkippedFile))
|
|
133
|
+
throw error;
|
|
134
|
+
result.failed += 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (const relativePath of onDisk) {
|
|
138
|
+
result.scanned += 1;
|
|
139
|
+
const existed = store.getByPath(relativePath) !== undefined;
|
|
140
|
+
try {
|
|
141
|
+
const wrote = await reconcile(relativePath, 'scan');
|
|
142
|
+
if (!wrote)
|
|
143
|
+
result.unchanged += 1;
|
|
144
|
+
else if (existed)
|
|
145
|
+
result.updated += 1;
|
|
146
|
+
else
|
|
147
|
+
result.created += 1;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (!(error instanceof SkippedFile))
|
|
151
|
+
throw error;
|
|
152
|
+
result.failed += 1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
// Watcher events are debounced per path and then handled one at a time, so
|
|
158
|
+
// a burst of writes to one file costs a single re-parse and two files that
|
|
159
|
+
// change together never interleave their index writes.
|
|
160
|
+
const pending = new Map();
|
|
161
|
+
let queue = Promise.resolve();
|
|
162
|
+
let watcher;
|
|
163
|
+
function handle(absolutePath) {
|
|
164
|
+
const relativePath = toRelative(contentDir, absolutePath);
|
|
165
|
+
if (relativePath === undefined || !isDocumentPath(relativePath))
|
|
166
|
+
return;
|
|
167
|
+
clearTimeout(pending.get(relativePath));
|
|
168
|
+
pending.set(relativePath, setTimeout(() => {
|
|
169
|
+
pending.delete(relativePath);
|
|
170
|
+
queue = queue.then(async () => {
|
|
171
|
+
try {
|
|
172
|
+
await reconcile(relativePath, 'watch');
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (error instanceof SkippedFile)
|
|
176
|
+
return;
|
|
177
|
+
logger.warn(`Could not sync ${relativePath}: ${messageOf(error)}`);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}, options.debounceMs ?? DEFAULT_DEBOUNCE_MS));
|
|
181
|
+
}
|
|
182
|
+
async function startWatching() {
|
|
183
|
+
if (watcher !== undefined)
|
|
184
|
+
return;
|
|
185
|
+
const started = watchPaths(contentDir, {
|
|
186
|
+
ignored: (candidate, stats) => isIgnored(contentDir, candidate, stats),
|
|
187
|
+
ignoreInitial: true,
|
|
188
|
+
persistent: true,
|
|
189
|
+
});
|
|
190
|
+
watcher = started;
|
|
191
|
+
started.on('add', handle);
|
|
192
|
+
started.on('change', handle);
|
|
193
|
+
started.on('unlink', handle);
|
|
194
|
+
started.on('error', (error) => {
|
|
195
|
+
logger.warn(`Content watcher error: ${messageOf(error)}`);
|
|
196
|
+
});
|
|
197
|
+
await new Promise((resolve) => {
|
|
198
|
+
started.once('ready', () => resolve());
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
events,
|
|
203
|
+
announce(change) {
|
|
204
|
+
return emitChange(events, change);
|
|
205
|
+
},
|
|
206
|
+
sync() {
|
|
207
|
+
return scan();
|
|
208
|
+
},
|
|
209
|
+
async start() {
|
|
210
|
+
const result = await scan();
|
|
211
|
+
if (options.watch !== false)
|
|
212
|
+
await startWatching();
|
|
213
|
+
return result;
|
|
214
|
+
},
|
|
215
|
+
async stop() {
|
|
216
|
+
for (const timer of pending.values())
|
|
217
|
+
clearTimeout(timer);
|
|
218
|
+
pending.clear();
|
|
219
|
+
const running = watcher;
|
|
220
|
+
watcher = undefined;
|
|
221
|
+
if (running !== undefined)
|
|
222
|
+
await running.close();
|
|
223
|
+
// Anything already past its debounce is allowed to finish, so stopping
|
|
224
|
+
// never leaves a half-applied write behind.
|
|
225
|
+
await queue;
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Whether chokidar should skip a path: anything inside a directory the walk
|
|
231
|
+
* would not descend into, and any file that is not a document.
|
|
232
|
+
*
|
|
233
|
+
* chokidar calls this without stats before it knows what a path is, so a name
|
|
234
|
+
* that could be a directory is kept and filtered again when its event arrives.
|
|
235
|
+
*/
|
|
236
|
+
function isIgnored(contentDir, absolutePath, stats) {
|
|
237
|
+
const relativePath = toRelative(contentDir, absolutePath);
|
|
238
|
+
if (relativePath === undefined)
|
|
239
|
+
return false;
|
|
240
|
+
if (relativePath === '')
|
|
241
|
+
return false;
|
|
242
|
+
const segments = relativePath.split('/');
|
|
243
|
+
const name = segments.at(-1);
|
|
244
|
+
if (segments.slice(0, -1).some((segment) => !isWalkableDirectory(segment)))
|
|
245
|
+
return true;
|
|
246
|
+
if (stats?.isFile() === true)
|
|
247
|
+
return !isDocumentPath(relativePath);
|
|
248
|
+
return !isWalkableDirectory(name);
|
|
249
|
+
}
|
|
250
|
+
/** A watched absolute path as a content-relative one, or `undefined` if it is outside. */
|
|
251
|
+
function toRelative(contentDir, absolutePath) {
|
|
252
|
+
const relativePath = path.relative(contentDir, absolutePath).replace(/\\/g, '/');
|
|
253
|
+
if (relativePath.startsWith('../') || path.isAbsolute(relativePath))
|
|
254
|
+
return undefined;
|
|
255
|
+
return relativePath;
|
|
256
|
+
}
|
|
257
|
+
/** Thrown inside a reconcile that logged and gave up on one file. */
|
|
258
|
+
class SkippedFile extends Error {
|
|
259
|
+
name = 'SkippedFile';
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Emit the primary change, then the visibility change it implies, and resolve
|
|
263
|
+
* once every listener has finished with all of them.
|
|
264
|
+
*
|
|
265
|
+
* The events go out in order rather than at once, so a subscriber that listens
|
|
266
|
+
* for both `created` and `published` sees them the way the names read.
|
|
267
|
+
*/
|
|
268
|
+
async function emitChange(events, change) {
|
|
269
|
+
await events.emit(change.type, change);
|
|
270
|
+
await events.emit('change', change);
|
|
271
|
+
const wasPublic = isPublic(change.previous);
|
|
272
|
+
const isNowPublic = isPublic(change.next);
|
|
273
|
+
if (isNowPublic && !wasPublic)
|
|
274
|
+
await events.emit('published', change);
|
|
275
|
+
else if (wasPublic && !isNowPublic)
|
|
276
|
+
await events.emit('unpublished', change);
|
|
277
|
+
}
|
|
278
|
+
/** A document is public when it exists, is not a draft and is not in the trash. */
|
|
279
|
+
function isPublic(document) {
|
|
280
|
+
if (document === undefined)
|
|
281
|
+
return false;
|
|
282
|
+
return !document.draft && !isTrashedPath(document.path);
|
|
283
|
+
}
|
|
284
|
+
/** The file's text, or `undefined` when it is not there any more. */
|
|
285
|
+
async function readSource(file) {
|
|
286
|
+
try {
|
|
287
|
+
return await readFile(file, 'utf8');
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
if (isNotFound(error))
|
|
291
|
+
return undefined;
|
|
292
|
+
throw error;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/** Whether a file is still on disk. */
|
|
296
|
+
async function exists(file) {
|
|
297
|
+
try {
|
|
298
|
+
await stat(file);
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
if (isNotFound(error))
|
|
303
|
+
return false;
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function isNotFound(error) {
|
|
308
|
+
const code = error?.code;
|
|
309
|
+
return code === 'ENOENT' || code === 'ENOTDIR' || code === 'EISDIR';
|
|
310
|
+
}
|
|
311
|
+
function messageOf(error) {
|
|
312
|
+
return error instanceof Error ? error.message : String(error);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Every document file under the content directory, content-relative and
|
|
316
|
+
* sorted. A directory that cannot be read is reported and skipped rather than
|
|
317
|
+
* failing the whole walk.
|
|
318
|
+
*/
|
|
319
|
+
async function walk(contentDir, logger) {
|
|
320
|
+
const found = [];
|
|
321
|
+
async function visit(directory, prefix) {
|
|
322
|
+
let entries;
|
|
323
|
+
try {
|
|
324
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
if (!isNotFound(error))
|
|
328
|
+
logger.warn(`Could not read ${directory}: ${messageOf(error)}`);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
for (const entry of entries) {
|
|
332
|
+
const relativePath = prefix === '' ? entry.name : `${prefix}/${entry.name}`;
|
|
333
|
+
if (entry.isDirectory()) {
|
|
334
|
+
if (!isWalkableDirectory(entry.name))
|
|
335
|
+
continue;
|
|
336
|
+
await visit(path.join(directory, entry.name), relativePath);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (!entry.isFile())
|
|
340
|
+
continue;
|
|
341
|
+
if (isDocumentPath(relativePath))
|
|
342
|
+
found.push(relativePath);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
await visit(contentDir, '');
|
|
346
|
+
return found.sort();
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Whether the walk descends into a directory. Eleventy ignores directories
|
|
350
|
+
* whose name starts with an underscore and so does the CMS, with one
|
|
351
|
+
* exception: the trash still holds documents, which stay indexed so the admin
|
|
352
|
+
* can restore them.
|
|
353
|
+
*/
|
|
354
|
+
function isWalkableDirectory(name) {
|
|
355
|
+
if (name === TRASH_DIRECTORY)
|
|
356
|
+
return true;
|
|
357
|
+
if (name.startsWith('_') || name.startsWith('.'))
|
|
358
|
+
return false;
|
|
359
|
+
return name !== 'node_modules';
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Whether a content-relative path is a document: a Markdown file under a
|
|
363
|
+
* `posts/` or `pages/` directory. Uploads, directory data files and anything
|
|
364
|
+
* the CMS does not model are skipped without a word.
|
|
365
|
+
*/
|
|
366
|
+
function isDocumentPath(relativePath) {
|
|
367
|
+
if (!MARKDOWN_EXTENSIONS.has(path.extname(relativePath).toLowerCase()))
|
|
368
|
+
return false;
|
|
369
|
+
const segments = relativePath.split('/').slice(0, -1);
|
|
370
|
+
return segments.some((segment) => DOCUMENT_DIRECTORIES.has(segment));
|
|
371
|
+
}
|
|
372
|
+
function createEmitter(logger) {
|
|
373
|
+
const listeners = new Map();
|
|
374
|
+
function setFor(event) {
|
|
375
|
+
const existing = listeners.get(event);
|
|
376
|
+
if (existing !== undefined)
|
|
377
|
+
return existing;
|
|
378
|
+
const created = new Set();
|
|
379
|
+
listeners.set(event, created);
|
|
380
|
+
return created;
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
on(event, listener) {
|
|
384
|
+
setFor(event).add(listener);
|
|
385
|
+
return () => {
|
|
386
|
+
listeners.get(event)?.delete(listener);
|
|
387
|
+
};
|
|
388
|
+
},
|
|
389
|
+
once(event, listener) {
|
|
390
|
+
const wrapped = (change) => {
|
|
391
|
+
listeners.get(event)?.delete(wrapped);
|
|
392
|
+
listener(change);
|
|
393
|
+
};
|
|
394
|
+
setFor(event).add(wrapped);
|
|
395
|
+
return () => {
|
|
396
|
+
listeners.get(event)?.delete(wrapped);
|
|
397
|
+
};
|
|
398
|
+
},
|
|
399
|
+
off(event, listener) {
|
|
400
|
+
listeners.get(event)?.delete(listener);
|
|
401
|
+
},
|
|
402
|
+
async emit(event, change) {
|
|
403
|
+
const registered = listeners.get(event);
|
|
404
|
+
if (registered === undefined)
|
|
405
|
+
return;
|
|
406
|
+
for (const listener of [...registered]) {
|
|
407
|
+
try {
|
|
408
|
+
// A listener's return is ignored, but an `async` one hands back a
|
|
409
|
+
// promise: awaiting it is what lets a subscriber that writes to disk
|
|
410
|
+
// finish before the caller carries on, and what keeps a rejection
|
|
411
|
+
// from escaping as an unhandled one.
|
|
412
|
+
await listener(change);
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
logger.warn(`A ${event} listener threw: ${messageOf(error)}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/content/sync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,UAAU,CAAC;AAI/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGrF,oDAAoD;AACpD,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;AAE1D,mFAAmF;AACnF,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEvC,qFAAqF;AACrF,MAAM,oBAAoB,GAAsC,IAAI,GAAG,CAAC;IACtE,CAAC,OAAO,EAAE,MAAM,CAAC;IACjB,CAAC,OAAO,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AA+IH;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAiC;IACjE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC;IACzC,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAErC;;;;;;;;;OASG;IACH,KAAK,UAAU,KAAK,CAAC,QAAkB,EAAE,MAAoB;QAC3D,IAAI,CAAC;YACH,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,CAAC,KAAK,YAAY,uBAAuB,CAAC;gBAAE,MAAM,KAAK,CAAC;YAC7D,MAAM,WAAW,GAAG,KAAK,CAAC,eAAe,CAAC;YAC1C,IAAI,WAAW,KAAK,SAAS;gBAAE,MAAM,KAAK,CAAC;YAC3C,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;gBAAE,MAAM,KAAK,CAAC;YAElE,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YAC3C,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,UAAU,CAAC,MAAM,EAAE;oBACvB,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,WAAW;oBACjB,QAAQ,EAAE,KAAK;oBACf,IAAI,EAAE,SAAS;oBACf,MAAM;iBACP,CAAC,CAAC;YACL,CAAC;YACD,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,KAAK,UAAU,SAAS,CAAC,YAAoB,EAAE,MAAoB;QACjE,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;QAErE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;YACzC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAC3B,MAAM,UAAU,CAAC,MAAM,EAAE;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,YAAY;gBAClB,QAAQ;gBACR,IAAI,EAAE,SAAS;gBACf,MAAM;aACP,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,aAAa,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,YAAY,YAAY,KAAK,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC7D,MAAM,IAAI,WAAW,EAAE,CAAC;QAC1B,CAAC;QAED,qEAAqE;QACrE,sEAAsE;QACtE,yDAAyD;QACzD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAE5E,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,mBAAmB,YAAY,KAAK,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACpE,MAAM,IAAI,WAAW,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,UAAU,CAAC,MAAM,EAAE;YACvB,IAAI,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YACpD,IAAI,EAAE,YAAY;YAClB,QAAQ;YACR,IAAI,EAAE,QAAQ;YACd,MAAM;SACP,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,UAAU,IAAI;QACjB,MAAM,MAAM,GAAe;YACzB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC;SACV,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAE7B,sEAAsE;QACtE,0EAA0E;QAC1E,6CAA6C;QAC7C,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS;YAChC,IAAI,CAAC;gBACH,IAAI,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;oBAAE,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;YAC5D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,CAAC,KAAK,YAAY,WAAW,CAAC;oBAAE,MAAM,KAAK,CAAC;gBACjD,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,KAAK,MAAM,YAAY,IAAI,MAAM,EAAE,CAAC;YAClC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;YACpB,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,SAAS,CAAC;YAC5D,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;gBACpD,IAAI,CAAC,KAAK;oBAAE,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;qBAC7B,IAAI,OAAO;oBAAE,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;;oBACjC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;YAC3B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,CAAC,KAAK,YAAY,WAAW,CAAC;oBAAE,MAAM,KAAK,CAAC;gBACjD,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,2EAA2E;IAC3E,2EAA2E;IAC3E,uDAAuD;IACvD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAClD,IAAI,KAAK,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7C,IAAI,OAA8B,CAAC;IAEnC,SAAS,MAAM,CAAC,YAAoB;QAClC,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QAC1D,IAAI,YAAY,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC;YAAE,OAAO;QAExE,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CACT,YAAY,EACZ,UAAU,CAAC,GAAG,EAAE;YACd,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAC7B,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;gBAC5B,IAAI,CAAC;oBACH,MAAM,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBACzC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,KAAK,YAAY,WAAW;wBAAE,OAAO;oBACzC,MAAM,CAAC,IAAI,CAAC,kBAAkB,YAAY,KAAK,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACrE,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAC,CAC9C,CAAC;IACJ,CAAC;IAED,KAAK,UAAU,aAAa;QAC1B,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO;QAElC,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,EAAE;YACrC,OAAO,EAAE,CAAC,SAAiB,EAAE,KAAa,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC;YACtF,aAAa,EAAE,IAAI;YACnB,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QACH,OAAO,GAAG,OAAO,CAAC;QAElB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC7B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC7B,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAc,EAAE,EAAE;YACrC,MAAM,CAAC,IAAI,CAAC,0BAA0B,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,MAAM;QAEN,QAAQ,CAAC,MAAM;YACb,OAAO,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC;QAED,IAAI;YACF,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,KAAK,CAAC,KAAK;YACT,MAAM,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC;YAC5B,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK;gBAAE,MAAM,aAAa,EAAE,CAAC;YACnD,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,KAAK,CAAC,IAAI;YACR,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC1D,OAAO,CAAC,KAAK,EAAE,CAAC;YAEhB,MAAM,OAAO,GAAG,OAAO,CAAC;YACxB,OAAO,GAAG,SAAS,CAAC;YACpB,IAAI,OAAO,KAAK,SAAS;gBAAE,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YAEjD,uEAAuE;YACvE,4CAA4C;YAC5C,MAAM,KAAK,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,UAAkB,EAAE,YAAoB,EAAE,KAAa;IACxE,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC1D,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC7C,IAAI,YAAY,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAW,CAAC;IACvC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACxF,IAAI,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI;QAAE,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IACnE,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,0FAA0F;AAC1F,SAAS,UAAU,CAAC,UAAkB,EAAE,YAAoB;IAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACjF,IAAI,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,SAAS,CAAC;IACtF,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,qEAAqE;AACrE,MAAM,WAAY,SAAQ,KAAK;IACX,IAAI,GAAG,aAAa,CAAC;CACxC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,UAAU,CAAC,MAAe,EAAE,MAAsB;IAC/D,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEpC,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,WAAW,IAAI,CAAC,SAAS;QAAE,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;SACjE,IAAI,SAAS,IAAI,CAAC,WAAW;QAAE,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;AAC/E,CAAC;AAED,mFAAmF;AACnF,SAAS,QAAQ,CAAC,QAA8B;IAC9C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC1D,CAAC;AAED,qEAAqE;AACrE,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,UAAU,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QACxC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,uCAAuC;AACvC,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,UAAU,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACpC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,MAAM,IAAI,GAAI,KAAmC,EAAE,IAAI,CAAC;IACxD,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,QAAQ,CAAC;AACtE,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,IAAI,CAAC,UAAkB,EAAE,MAAkB;IACxD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,UAAU,KAAK,CAAC,SAAiB,EAAE,MAAc;QACpD,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,kBAAkB,SAAS,KAAK,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACxF,OAAO;QACT,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,YAAY,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YAC5E,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAC/C,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC;gBAC5D,SAAS;YACX,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;gBAAE,SAAS;YAC9B,IAAI,cAAc,CAAC,YAAY,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC5B,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,IAAY;IACvC,IAAI,IAAI,KAAK,eAAe;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/D,OAAO,IAAI,KAAK,cAAc,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,YAAoB;IAC1C,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IACrF,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACtD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AACvE,CAAC;AAQD,SAAS,aAAa,CAAC,MAAkB;IACvC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoD,CAAC;IAE9E,SAAS,MAAM,CAAC,KAA4B;QAC1C,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,QAAQ,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;QAChD,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,EAAE,CAAC,KAAK,EAAE,QAAQ;YAChB,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5B,OAAO,GAAG,EAAE;gBACV,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YACzC,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,QAAQ;YAClB,MAAM,OAAO,GAAyB,CAAC,MAAM,EAAE,EAAE;gBAC/C,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;gBACtC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACnB,CAAC,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC3B,OAAO,GAAG,EAAE;gBACV,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YACxC,CAAC,CAAC;QACJ,CAAC;QAED,GAAG,CAAC,KAAK,EAAE,QAAQ;YACjB,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM;YACtB,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,UAAU,KAAK,SAAS;gBAAE,OAAO;YACrC,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC;gBACvC,IAAI,CAAC;oBACH,kEAAkE;oBAClE,qEAAqE;oBACrE,kEAAkE;oBAClE,qCAAqC;oBACrC,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACzB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,oBAAoB,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAChE,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DocumentContent } from './document.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Turn a Document back into the text of its Markdown file.
|
|
4
|
+
*
|
|
5
|
+
* Front matter keys are emitted in the order of
|
|
6
|
+
* {@link KNOWN_FRONT_MATTER_KEYS}, followed by the unmodelled keys in the order
|
|
7
|
+
* they were read, so an unchanged document always writes the same bytes and a
|
|
8
|
+
* real edit produces a small diff. Keys that carry no information — an empty
|
|
9
|
+
* tag list, `draft: false` — are left out.
|
|
10
|
+
*/
|
|
11
|
+
export declare function serializeDocument(document: DocumentContent): string;
|
|
12
|
+
/**
|
|
13
|
+
* The writable half of a parsed document: what it would be written back from.
|
|
14
|
+
*
|
|
15
|
+
* A rewrite that means to change one thing has to carry everything else
|
|
16
|
+
* through untouched, and an optional field has to come back absent rather than
|
|
17
|
+
* `undefined`, or the front matter grows keys with no values. This is the one
|
|
18
|
+
* place that spelling lives, so a caller that only wants to add a key — the
|
|
19
|
+
* federation stamping `activitypub` into a post it has just announced — cannot
|
|
20
|
+
* quietly drop another.
|
|
21
|
+
*/
|
|
22
|
+
export declare function documentContent(document: DocumentContent): DocumentContent;
|
|
23
|
+
/**
|
|
24
|
+
* Strip the whitespace a Markdown body does not need, so that files differing
|
|
25
|
+
* only in blank lines at the edges are the same document.
|
|
26
|
+
*/
|
|
27
|
+
export declare function normalizeBody(body: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* The front matter block a document would be written with: the keys the CMS
|
|
30
|
+
* models, in {@link KNOWN_FRONT_MATTER_KEYS} order, then the unmodelled ones.
|
|
31
|
+
*
|
|
32
|
+
* This is the same object {@link serializeDocument} dumps to YAML, so the JSON
|
|
33
|
+
* representation of a document and the Markdown file cannot disagree about
|
|
34
|
+
* what its front matter is.
|
|
35
|
+
*/
|
|
36
|
+
export declare function documentFrontMatter(document: DocumentContent): Record<string, unknown>;
|
|
37
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/content/writer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIrD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAMnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,GAAG,eAAe,CAc1E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqBtF"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { dump } from 'js-yaml';
|
|
2
|
+
import { KNOWN_FRONT_MATTER_KEYS } from './document.js';
|
|
3
|
+
const KNOWN_KEYS = new Set(KNOWN_FRONT_MATTER_KEYS);
|
|
4
|
+
/**
|
|
5
|
+
* Turn a Document back into the text of its Markdown file.
|
|
6
|
+
*
|
|
7
|
+
* Front matter keys are emitted in the order of
|
|
8
|
+
* {@link KNOWN_FRONT_MATTER_KEYS}, followed by the unmodelled keys in the order
|
|
9
|
+
* they were read, so an unchanged document always writes the same bytes and a
|
|
10
|
+
* real edit produces a small diff. Keys that carry no information — an empty
|
|
11
|
+
* tag list, `draft: false` — are left out.
|
|
12
|
+
*/
|
|
13
|
+
export function serializeDocument(document) {
|
|
14
|
+
const frontMatter = documentFrontMatter(document);
|
|
15
|
+
const yaml = dump(frontMatter, { lineWidth: -1, noRefs: true });
|
|
16
|
+
const body = normalizeBody(document.body);
|
|
17
|
+
return body === '' ? `---\n${yaml}---\n` : `---\n${yaml}---\n\n${body}\n`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The writable half of a parsed document: what it would be written back from.
|
|
21
|
+
*
|
|
22
|
+
* A rewrite that means to change one thing has to carry everything else
|
|
23
|
+
* through untouched, and an optional field has to come back absent rather than
|
|
24
|
+
* `undefined`, or the front matter grows keys with no values. This is the one
|
|
25
|
+
* place that spelling lives, so a caller that only wants to add a key — the
|
|
26
|
+
* federation stamping `activitypub` into a post it has just announced — cannot
|
|
27
|
+
* quietly drop another.
|
|
28
|
+
*/
|
|
29
|
+
export function documentContent(document) {
|
|
30
|
+
return {
|
|
31
|
+
title: document.title,
|
|
32
|
+
...(document.date === undefined ? {} : { date: document.date }),
|
|
33
|
+
...(document.updated === undefined ? {} : { updated: document.updated }),
|
|
34
|
+
permalink: document.permalink,
|
|
35
|
+
tags: [...document.tags],
|
|
36
|
+
draft: document.draft,
|
|
37
|
+
...(document.description === undefined ? {} : { description: document.description }),
|
|
38
|
+
...(document.author === undefined ? {} : { author: document.author }),
|
|
39
|
+
...(document.activitypub === undefined ? {} : { activitypub: { ...document.activitypub } }),
|
|
40
|
+
extra: { ...document.extra },
|
|
41
|
+
body: document.body,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Strip the whitespace a Markdown body does not need, so that files differing
|
|
46
|
+
* only in blank lines at the edges are the same document.
|
|
47
|
+
*/
|
|
48
|
+
export function normalizeBody(body) {
|
|
49
|
+
return body.replace(/\r\n?/g, '\n').trim();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The front matter block a document would be written with: the keys the CMS
|
|
53
|
+
* models, in {@link KNOWN_FRONT_MATTER_KEYS} order, then the unmodelled ones.
|
|
54
|
+
*
|
|
55
|
+
* This is the same object {@link serializeDocument} dumps to YAML, so the JSON
|
|
56
|
+
* representation of a document and the Markdown file cannot disagree about
|
|
57
|
+
* what its front matter is.
|
|
58
|
+
*/
|
|
59
|
+
export function documentFrontMatter(document) {
|
|
60
|
+
const data = { title: document.title };
|
|
61
|
+
if (document.date !== undefined)
|
|
62
|
+
data['date'] = document.date;
|
|
63
|
+
if (document.updated !== undefined)
|
|
64
|
+
data['updated'] = document.updated;
|
|
65
|
+
data['permalink'] = document.permalink;
|
|
66
|
+
if (document.tags.length > 0)
|
|
67
|
+
data['tags'] = [...document.tags];
|
|
68
|
+
if (document.draft)
|
|
69
|
+
data['draft'] = true;
|
|
70
|
+
if (document.description !== undefined)
|
|
71
|
+
data['description'] = document.description;
|
|
72
|
+
if (document.author !== undefined)
|
|
73
|
+
data['author'] = document.author;
|
|
74
|
+
const activitypub = activityPubOf(document);
|
|
75
|
+
if (activitypub !== undefined)
|
|
76
|
+
data['activitypub'] = activitypub;
|
|
77
|
+
for (const [key, value] of Object.entries(document.extra)) {
|
|
78
|
+
if (KNOWN_KEYS.has(key))
|
|
79
|
+
continue;
|
|
80
|
+
if (value === undefined)
|
|
81
|
+
continue;
|
|
82
|
+
data[key] = value;
|
|
83
|
+
}
|
|
84
|
+
return data;
|
|
85
|
+
}
|
|
86
|
+
function activityPubOf(document) {
|
|
87
|
+
const block = document.activitypub;
|
|
88
|
+
if (block === undefined)
|
|
89
|
+
return undefined;
|
|
90
|
+
const out = {};
|
|
91
|
+
if (block.id !== undefined)
|
|
92
|
+
out['id'] = block.id;
|
|
93
|
+
if (block.published !== undefined)
|
|
94
|
+
out['published'] = block.published;
|
|
95
|
+
return Object.keys(out).length === 0 ? undefined : out;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/content/writer.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AdminStore } from './admin/store.ts';
|
|
2
|
+
import type { Session } from './admin/store.ts';
|
|
3
|
+
import type { ResolvedConfig } from './config.ts';
|
|
4
|
+
import type { ContentStore } from './content/store.ts';
|
|
5
|
+
import type { DocumentChange } from './content/sync.ts';
|
|
6
|
+
import type { DeliveryService } from './federation/delivery.ts';
|
|
7
|
+
import type { Renderer } from './web/render.ts';
|
|
8
|
+
/**
|
|
9
|
+
* What every Hono handler in the CMS can read off the context, so a route
|
|
10
|
+
* never has to be handed the store, the config or the theme by hand.
|
|
11
|
+
*/
|
|
12
|
+
export interface GeekityEnv {
|
|
13
|
+
Variables: {
|
|
14
|
+
/** The derived content index this CMS booted. */
|
|
15
|
+
store: ContentStore;
|
|
16
|
+
/** Users and sessions, the part of the database that is not derived. */
|
|
17
|
+
admin: AdminStore;
|
|
18
|
+
/** Config after defaults and environment overrides. */
|
|
19
|
+
config: ResolvedConfig;
|
|
20
|
+
/** The theme, for handlers that answer with HTML. */
|
|
21
|
+
renderer: Renderer;
|
|
22
|
+
/**
|
|
23
|
+
* Report a write this request made to the content directory.
|
|
24
|
+
*
|
|
25
|
+
* The admin corrects the index as soon as the bytes land rather than
|
|
26
|
+
* waiting for the watcher (doc-1), which means the watcher's later re-read
|
|
27
|
+
* of that file finds a matching hash and emits nothing. A handler that
|
|
28
|
+
* writes therefore has to say so, or no subscriber — a site's
|
|
29
|
+
* `onPublish` hook, the federation's delivery — ever hears about an admin
|
|
30
|
+
* save. The promise resolves once every listener has finished.
|
|
31
|
+
*/
|
|
32
|
+
announce: (change: DocumentChange) => Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Outbound ActivityPub delivery, so a handler can send a recorded activity
|
|
35
|
+
* again. The federation screen's Redeliver button is the whole reason it is
|
|
36
|
+
* here: everything else about delivery happens off the index, away from any
|
|
37
|
+
* request.
|
|
38
|
+
*/
|
|
39
|
+
delivery: DeliveryService;
|
|
40
|
+
/**
|
|
41
|
+
* The session this request carries, set by the admin guard: a login, the
|
|
42
|
+
* anonymous session that holds a CSRF token before login, or `undefined`
|
|
43
|
+
* outside `/admin` and for a request whose session has expired.
|
|
44
|
+
*/
|
|
45
|
+
session: Session | undefined;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE;QACT,iDAAiD;QACjD,KAAK,EAAE,YAAY,CAAC;QACpB,wEAAwE;QACxE,KAAK,EAAE,UAAU,CAAC;QAClB,uDAAuD;QACvD,MAAM,EAAE,cAAc,CAAC;QACvB,qDAAqD;QACrD,QAAQ,EAAE,QAAQ,CAAC;QACnB;;;;;;;;;WASG;QACH,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACpD;;;;;WAKG;QACH,QAAQ,EAAE,eAAe,CAAC;QAC1B;;;;WAIG;QACH,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;KAC9B,CAAC;CACH"}
|
package/dist/env.js
ADDED
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":""}
|