@krantho/server 0.0.0-stage → 1.0.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/dist/cdn/cloudfront.d.ts +9 -0
- package/dist/cdn/cloudfront.d.ts.map +1 -0
- package/dist/cdn/cloudfront.js +35 -0
- package/dist/cdn/cloudfront.js.map +1 -0
- package/dist/cdn/gcp.d.ts +15 -0
- package/dist/cdn/gcp.d.ts.map +1 -0
- package/dist/cdn/gcp.js +60 -0
- package/dist/cdn/gcp.js.map +1 -0
- package/dist/cdn/index.d.ts +9 -0
- package/dist/cdn/index.d.ts.map +1 -0
- package/dist/cdn/index.js +30 -0
- package/dist/cdn/index.js.map +1 -0
- package/dist/cdn/listener.d.ts +14 -0
- package/dist/cdn/listener.d.ts.map +1 -0
- package/dist/cdn/listener.js +53 -0
- package/dist/cdn/listener.js.map +1 -0
- package/dist/cdn/retry.d.ts +3 -0
- package/dist/cdn/retry.d.ts.map +1 -0
- package/dist/cdn/retry.js +17 -0
- package/dist/cdn/retry.js.map +1 -0
- package/dist/cdn/types.d.ts +12 -0
- package/dist/cdn/types.d.ts.map +1 -0
- package/dist/cdn/types.js +2 -0
- package/dist/cdn/types.js.map +1 -0
- package/dist/cdn/vercel.d.ts +9 -0
- package/dist/cdn/vercel.d.ts.map +1 -0
- package/dist/cdn/vercel.js +31 -0
- package/dist/cdn/vercel.js.map +1 -0
- package/dist/content-conflicts.d.ts +18 -0
- package/dist/content-conflicts.d.ts.map +1 -0
- package/dist/content-conflicts.js +22 -0
- package/dist/content-conflicts.js.map +1 -0
- package/dist/content-dates.d.ts +35 -0
- package/dist/content-dates.d.ts.map +1 -0
- package/dist/content-dates.js +85 -0
- package/dist/content-dates.js.map +1 -0
- package/dist/content-loader.d.ts +37 -0
- package/dist/content-loader.d.ts.map +1 -0
- package/dist/content-loader.js +223 -0
- package/dist/content-loader.js.map +1 -0
- package/dist/content-migration.d.ts +101 -0
- package/dist/content-migration.d.ts.map +1 -0
- package/dist/content-migration.js +291 -0
- package/dist/content-migration.js.map +1 -0
- package/dist/convert.d.ts +18 -0
- package/dist/convert.d.ts.map +1 -0
- package/dist/convert.js +152 -0
- package/dist/convert.js.map +1 -0
- package/dist/file-store.d.ts +11 -0
- package/dist/file-store.d.ts.map +1 -0
- package/dist/file-store.js +39 -0
- package/dist/file-store.js.map +1 -0
- package/dist/file-watcher.d.ts +19 -0
- package/dist/file-watcher.d.ts.map +1 -0
- package/dist/file-watcher.js +99 -0
- package/dist/file-watcher.js.map +1 -0
- package/dist/handler.d.ts +61 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +197 -0
- package/dist/handler.js.map +1 -0
- package/dist/import.d.ts +25 -0
- package/dist/import.d.ts.map +1 -0
- package/dist/import.js +71 -0
- package/dist/import.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/indexnow.d.ts +38 -0
- package/dist/indexnow.d.ts.map +1 -0
- package/dist/indexnow.js +89 -0
- package/dist/indexnow.js.map +1 -0
- package/dist/lazy-handler.d.ts +7 -0
- package/dist/lazy-handler.d.ts.map +1 -0
- package/dist/lazy-handler.js +16 -0
- package/dist/lazy-handler.js.map +1 -0
- package/dist/llm-seed.d.ts +25 -0
- package/dist/llm-seed.d.ts.map +1 -0
- package/dist/llm-seed.js +42 -0
- package/dist/llm-seed.js.map +1 -0
- package/dist/lock-adapters.d.ts +21 -0
- package/dist/lock-adapters.d.ts.map +1 -0
- package/dist/lock-adapters.js +69 -0
- package/dist/lock-adapters.js.map +1 -0
- package/dist/manifest.d.ts +15 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +39 -0
- package/dist/manifest.js.map +1 -0
- package/dist/mime-types.d.ts +3 -0
- package/dist/mime-types.d.ts.map +1 -0
- package/dist/mime-types.js +15 -0
- package/dist/mime-types.js.map +1 -0
- package/dist/page-cache-rules.d.ts +41 -0
- package/dist/page-cache-rules.d.ts.map +1 -0
- package/dist/page-cache-rules.js +94 -0
- package/dist/page-cache-rules.js.map +1 -0
- package/dist/page-cache-store.d.ts +11 -0
- package/dist/page-cache-store.d.ts.map +1 -0
- package/dist/page-cache-store.js +46 -0
- package/dist/page-cache-store.js.map +1 -0
- package/dist/page-request.d.ts +26 -0
- package/dist/page-request.d.ts.map +1 -0
- package/dist/page-request.js +29 -0
- package/dist/page-request.js.map +1 -0
- package/dist/persistence.d.ts +36 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/persistence.js +108 -0
- package/dist/persistence.js.map +1 -0
- package/dist/preview-token.d.ts +9 -0
- package/dist/preview-token.d.ts.map +1 -0
- package/dist/preview-token.js +14 -0
- package/dist/preview-token.js.map +1 -0
- package/dist/read-cache.d.ts +17 -0
- package/dist/read-cache.d.ts.map +1 -0
- package/dist/read-cache.js +33 -0
- package/dist/read-cache.js.map +1 -0
- package/dist/route-matcher.d.ts +21 -0
- package/dist/route-matcher.d.ts.map +1 -0
- package/dist/route-matcher.js +75 -0
- package/dist/route-matcher.js.map +1 -0
- package/dist/secret-vault.d.ts +20 -0
- package/dist/secret-vault.d.ts.map +1 -0
- package/dist/secret-vault.js +60 -0
- package/dist/secret-vault.js.map +1 -0
- package/dist/seo-config-io.d.ts +51 -0
- package/dist/seo-config-io.d.ts.map +1 -0
- package/dist/seo-config-io.js +151 -0
- package/dist/seo-config-io.js.map +1 -0
- package/dist/seo-seed.d.ts +12 -0
- package/dist/seo-seed.d.ts.map +1 -0
- package/dist/seo-seed.js +100 -0
- package/dist/seo-seed.js.map +1 -0
- package/dist/studio-gate.d.ts +25 -0
- package/dist/studio-gate.d.ts.map +1 -0
- package/dist/studio-gate.js +70 -0
- package/dist/studio-gate.js.map +1 -0
- package/dist/studio.d.ts +17 -0
- package/dist/studio.d.ts.map +1 -0
- package/dist/studio.js +107 -0
- package/dist/studio.js.map +1 -0
- package/dist/webhook-sweep.d.ts +22 -0
- package/dist/webhook-sweep.d.ts.map +1 -0
- package/dist/webhook-sweep.js +33 -0
- package/dist/webhook-sweep.js.map +1 -0
- package/package.json +87 -3
- package/README.md +0 -3
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { renderContent } from '@krantho/core';
|
|
5
|
+
import { canGetContent, publicationOfFile, } from '@krantho/persistence';
|
|
6
|
+
import { documentChecksum, parseRepositoryContent, resolveCollectionContract, } from '@krantho/schema';
|
|
7
|
+
import matter from 'gray-matter';
|
|
8
|
+
import { recordNewConflict, resolveConflictsOf } from './content-conflicts.js';
|
|
9
|
+
import { contentDateKey, contentDateLookup } from './content-dates.js';
|
|
10
|
+
import { autoImport } from './import.js';
|
|
11
|
+
import { CONTENT_MANIFEST_FILE } from './manifest.js';
|
|
12
|
+
/**
|
|
13
|
+
* Bring the database up to date with the repository's content on startup.
|
|
14
|
+
*
|
|
15
|
+
* Without `<contentDir>/manifest.json` (or a migration adapter) the content is
|
|
16
|
+
* imported into an empty database only. With one, every deployment whose
|
|
17
|
+
* manifest is newer than the database's compares each file with its document:
|
|
18
|
+
* a new or changed file is imported, unless an editor changed the document in
|
|
19
|
+
* Studio since — then the editor's version stands and a changed file is
|
|
20
|
+
* recorded as a conflict. A document deleted in Studio stays deleted.
|
|
21
|
+
*/
|
|
22
|
+
export async function runContentMigration(adapter, contentConfig, migrationAdapter, checkpointAdapter, contentDir, defaultStatus = 'published') {
|
|
23
|
+
const manifest = await loadManifest(contentDir);
|
|
24
|
+
const dateOf = await contentDateLookup(contentDir);
|
|
25
|
+
if (!manifest || !migrationAdapter) {
|
|
26
|
+
const imported = await autoImport(adapter, contentConfig, dateOf, defaultStatus);
|
|
27
|
+
return {
|
|
28
|
+
action: imported > 0 ? 'full-import' : 'skip',
|
|
29
|
+
imported,
|
|
30
|
+
conflicts: 0,
|
|
31
|
+
rejected: 0,
|
|
32
|
+
checkpointVersion: null,
|
|
33
|
+
reason: !manifest ? `No ${CONTENT_MANIFEST_FILE} found` : 'Migration adapter not configured',
|
|
34
|
+
details: [],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const dbVersion = await migrationAdapter.getContentManifestVersion();
|
|
38
|
+
if (dbVersion !== null && dbVersion >= manifest.version) {
|
|
39
|
+
return {
|
|
40
|
+
action: 'skip',
|
|
41
|
+
imported: 0,
|
|
42
|
+
conflicts: 0,
|
|
43
|
+
rejected: 0,
|
|
44
|
+
checkpointVersion: null,
|
|
45
|
+
reason: `DB version ${dbVersion} >= repo version ${manifest.version}`,
|
|
46
|
+
details: [],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const previous = (await migrationAdapter.getContentManifest())?.fileChecksums ?? {};
|
|
50
|
+
const files = await readRepositoryFiles(adapter, contentConfig, contentDir);
|
|
51
|
+
const planned = await planFiles(adapter, files, previous);
|
|
52
|
+
const checkpointVersion = await checkpointBeforeImport(adapter, checkpointAdapter, planned, manifest.version);
|
|
53
|
+
await applyPlan(adapter, migrationAdapter, planned, dateOf, defaultStatus);
|
|
54
|
+
await migrationAdapter.saveContentManifest({
|
|
55
|
+
id: 0,
|
|
56
|
+
repoVersion: manifest.version,
|
|
57
|
+
repoCommit: manifest.commit ?? null,
|
|
58
|
+
importedAt: new Date().toISOString(),
|
|
59
|
+
fileChecksums: knownFiles(planned),
|
|
60
|
+
});
|
|
61
|
+
const count = (outcome) => planned.filter((p) => p.outcome === outcome).length;
|
|
62
|
+
return {
|
|
63
|
+
action: dbVersion === null ? 'full-import' : 'migrate',
|
|
64
|
+
imported: count('imported'),
|
|
65
|
+
conflicts: count('conflict'),
|
|
66
|
+
rejected: count('rejected'),
|
|
67
|
+
checkpointVersion,
|
|
68
|
+
details: planned.map(({ file, outcome }) => ({
|
|
69
|
+
collection: file.collection,
|
|
70
|
+
slug: file.slug,
|
|
71
|
+
outcome,
|
|
72
|
+
})),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function planFiles(adapter, files, previous) {
|
|
76
|
+
const planned = [];
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
const read = await adapter.getContent(file.collection, file.slug, file.document?.locale);
|
|
79
|
+
const current = file.document?.locale !== undefined && read?.meta.locale !== file.document.locale
|
|
80
|
+
? null
|
|
81
|
+
: read;
|
|
82
|
+
planned.push({ file, current, outcome: decideFile(file, current, previous[file.key]) });
|
|
83
|
+
}
|
|
84
|
+
return planned;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* What to do with one repository file, given its document's current version
|
|
88
|
+
* and the file's checksum when the database last took the repository's
|
|
89
|
+
* content (undefined: the database never saw this file).
|
|
90
|
+
*
|
|
91
|
+
* Content equal to a state the repository held (the document's basis, or what
|
|
92
|
+
* the last deployment took) is not an edit: a document that carries the
|
|
93
|
+
* repository's previous file, as one does after a pull of production's edits was
|
|
94
|
+
* merged, is not reported as edited, and a file at that state is not reported as changed.
|
|
95
|
+
*
|
|
96
|
+
* A version an import wrote is not an edit either, whatever its checksum: nobody changed it since,
|
|
97
|
+
* even when it predates the document's basis and contract. A restore copies the restored version's
|
|
98
|
+
* source but always names who restored it, so only a version with no `changedBy` is an import's.
|
|
99
|
+
*/
|
|
100
|
+
export function decideFile(file, current, previousChecksum) {
|
|
101
|
+
if (!file.fields)
|
|
102
|
+
return 'rejected';
|
|
103
|
+
if (!current)
|
|
104
|
+
return previousChecksum === undefined ? 'imported' : 'deleted';
|
|
105
|
+
const repo = documentChecksum({ ...file.document, fields: file.fields, body: file.body });
|
|
106
|
+
const database = documentChecksum(current);
|
|
107
|
+
if (repo === database)
|
|
108
|
+
return 'unchanged';
|
|
109
|
+
if (current.meta.source === 'filesystem' && current.meta.changedBy === null)
|
|
110
|
+
return 'imported';
|
|
111
|
+
const basis = current.repositoryBasis?.checksum ?? previousChecksum;
|
|
112
|
+
if (basis === undefined)
|
|
113
|
+
return 'conflict';
|
|
114
|
+
const heldByRepository = (checksum) => checksum === basis || checksum === previousChecksum;
|
|
115
|
+
const repositoryChanged = !heldByRepository(repo);
|
|
116
|
+
const databaseChanged = !heldByRepository(database);
|
|
117
|
+
if (repositoryChanged && databaseChanged)
|
|
118
|
+
return 'conflict';
|
|
119
|
+
return repositoryChanged ? 'imported' : 'kept';
|
|
120
|
+
}
|
|
121
|
+
/** A checkpoint before the first import into a database that already holds content */
|
|
122
|
+
async function checkpointBeforeImport(adapter, checkpointAdapter, planned, version) {
|
|
123
|
+
if (!checkpointAdapter)
|
|
124
|
+
return null;
|
|
125
|
+
if (!planned.some((p) => p.outcome === 'imported'))
|
|
126
|
+
return null;
|
|
127
|
+
if ((await adapter.listSlugs()).length === 0)
|
|
128
|
+
return null;
|
|
129
|
+
const checkpoint = await checkpointAdapter.createCheckpoint(`pre-content-migration-v${version}`, 'pre-migration');
|
|
130
|
+
return checkpoint.version;
|
|
131
|
+
}
|
|
132
|
+
async function applyPlan(adapter, migrationAdapter, planned, dateOf, defaultStatus) {
|
|
133
|
+
const migrationId = (await migrationAdapter.getContentManifest())?.id ?? 0;
|
|
134
|
+
// Read once: each document is planned once, so no conflict this run touches is read again
|
|
135
|
+
const open = await migrationAdapter.listConflicts();
|
|
136
|
+
for (const plan of planned) {
|
|
137
|
+
const { file, current } = plan;
|
|
138
|
+
if (plan.outcome === 'imported' && file.fields) {
|
|
139
|
+
try {
|
|
140
|
+
await importFile(adapter, file, file.fields, dateOf, defaultStatus, current?.meta.version ?? 0);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
console.warn(`[content-migration] Failed to import ${file.key}:`, err);
|
|
144
|
+
plan.outcome = 'rejected';
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
await resolveConflictsOf(migrationAdapter, open, {
|
|
148
|
+
collection: file.collection,
|
|
149
|
+
slug: file.slug,
|
|
150
|
+
locale: file.document?.locale ?? current?.meta.locale,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
else if (plan.outcome === 'conflict' && file.fields && current) {
|
|
154
|
+
await recordNewConflict(migrationAdapter, open, {
|
|
155
|
+
migrationId,
|
|
156
|
+
collection: file.collection,
|
|
157
|
+
slug: file.slug,
|
|
158
|
+
locale: current.meta.locale,
|
|
159
|
+
repoChecksum: documentChecksum({ ...file.document, fields: file.fields, body: file.body }),
|
|
160
|
+
dbChecksum: documentChecksum(current),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
else if (plan.outcome === 'rejected') {
|
|
164
|
+
console.warn(`[import] Skipping ${file.key}: schema validation failed`);
|
|
165
|
+
for (const issue of file.issues)
|
|
166
|
+
console.warn(` - ${issue}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async function importFile(adapter, file, fields, dateOf, defaultStatus, expectedVersion) {
|
|
171
|
+
const { html, sections } = await renderContent(fields, file.body, { atNotation: false });
|
|
172
|
+
await adapter.upsertFromFile(file.collection, file.slug, fields, file.body, html, sections, file.filePath, file.document?.locale, dateOf(file.filePath), {
|
|
173
|
+
...file.document,
|
|
174
|
+
publication: publicationOfFile(file.status ?? defaultStatus),
|
|
175
|
+
expectedVersion,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/** The files the database now knows, by key: every file it holds or chose not to */
|
|
179
|
+
function knownFiles(planned) {
|
|
180
|
+
return Object.fromEntries(planned
|
|
181
|
+
.filter((p) => p.outcome !== 'rejected')
|
|
182
|
+
.map((p) => [
|
|
183
|
+
p.file.key,
|
|
184
|
+
p.outcome === 'conflict' || p.outcome === 'kept'
|
|
185
|
+
? (p.current?.repositoryBasis?.checksum ?? p.file.fileChecksum)
|
|
186
|
+
: p.file.fileChecksum,
|
|
187
|
+
]));
|
|
188
|
+
}
|
|
189
|
+
/** Every markdown file in each collection's directory, parsed and validated */
|
|
190
|
+
async function readRepositoryFiles(adapter, contentConfig, contentDir) {
|
|
191
|
+
const files = [];
|
|
192
|
+
for (const [, collection] of contentConfig.collections) {
|
|
193
|
+
if (!collection.directory)
|
|
194
|
+
continue;
|
|
195
|
+
let entries;
|
|
196
|
+
try {
|
|
197
|
+
entries = await readdir(collection.directory);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const contract = resolveCollectionContract(collection, (await adapter.getRuntimeSchema?.(collection.name)) ?? null);
|
|
203
|
+
for (const name of entries.filter((e) => e.endsWith('.md'))) {
|
|
204
|
+
const filePath = join(collection.directory, name);
|
|
205
|
+
const raw = await readFile(filePath, 'utf-8');
|
|
206
|
+
const parsed = matter(raw);
|
|
207
|
+
const result = parseRepositoryContent(collection, name.slice(0, -3), parsed.data, parsed.content, collection.schema, contract);
|
|
208
|
+
files.push({
|
|
209
|
+
key: contentDateKey(contentDir, filePath),
|
|
210
|
+
collection: collection.name,
|
|
211
|
+
slug: name.slice(0, -3),
|
|
212
|
+
filePath,
|
|
213
|
+
fileChecksum: result.success
|
|
214
|
+
? documentChecksum(result.data)
|
|
215
|
+
: createHash('sha256').update(raw).digest('hex'),
|
|
216
|
+
document: result.success ? result.data : undefined,
|
|
217
|
+
status: typeof parsed.data['status'] === 'string' ? parsed.data['status'] : undefined,
|
|
218
|
+
fields: result.success ? result.data.fields : null,
|
|
219
|
+
issues: result.success
|
|
220
|
+
? []
|
|
221
|
+
: result.error.issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`),
|
|
222
|
+
body: parsed.content,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return files;
|
|
227
|
+
}
|
|
228
|
+
/** Read `<contentDir>/manifest.json`, or null when the build wrote none */
|
|
229
|
+
export async function loadManifest(contentDir) {
|
|
230
|
+
try {
|
|
231
|
+
const raw = await readFile(join(contentDir, CONTENT_MANIFEST_FILE), 'utf-8');
|
|
232
|
+
const parsed = JSON.parse(raw);
|
|
233
|
+
if (typeof parsed !== 'object' ||
|
|
234
|
+
parsed === null ||
|
|
235
|
+
typeof parsed['version'] !== 'number' ||
|
|
236
|
+
typeof parsed['files'] !== 'object') {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
return parsed;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/** Canonical authored content checksum, independent of YAML spelling and key order. */
|
|
246
|
+
export function contentChecksum(fields, body) {
|
|
247
|
+
return documentChecksum({ fields, body });
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Import the repository's content into the database when it needs it (an
|
|
251
|
+
* empty database, or a newer content manifest), logging what happened. Both
|
|
252
|
+
* the API handler and the page loader run it on first use, so whichever a
|
|
253
|
+
* fresh deployment serves first finds the content in place.
|
|
254
|
+
*
|
|
255
|
+
* @returns how many documents were imported
|
|
256
|
+
*/
|
|
257
|
+
export async function importRepositoryContent(adapter, contentConfig, migrationAdapter, checkpointAdapter, contentDir, defaultStatus = 'published') {
|
|
258
|
+
if (!('upsertFromFile' in adapter && 'listSlugs' in adapter && canGetContent(adapter)))
|
|
259
|
+
return 0;
|
|
260
|
+
const result = await runContentMigration(adapter, contentConfig, migrationAdapter, checkpointAdapter, contentDir, defaultStatus);
|
|
261
|
+
if (result.imported > 0 || result.conflicts > 0 || result.rejected > 0) {
|
|
262
|
+
const parts = [`[krantho] Content migration: ${result.action}`];
|
|
263
|
+
parts.push(`${result.imported} imported`);
|
|
264
|
+
if (result.conflicts > 0)
|
|
265
|
+
parts.push(`${result.conflicts} conflicts`);
|
|
266
|
+
if (result.rejected > 0)
|
|
267
|
+
parts.push(`${result.rejected} rejected`);
|
|
268
|
+
console.log(parts.join(', '));
|
|
269
|
+
}
|
|
270
|
+
return result.imported;
|
|
271
|
+
}
|
|
272
|
+
/** The site setting that holds the last content version the site announced */
|
|
273
|
+
const ANNOUNCED_CONTENT_VERSION = 'content.announcedVersion';
|
|
274
|
+
/**
|
|
275
|
+
* Whether the database holds a content version the site has not announced
|
|
276
|
+
* yet, recording it as announced. The page loader can import a deployment's
|
|
277
|
+
* content before the API handler starts, and only the handler can announce a
|
|
278
|
+
* change, so it announces each new content version once, whoever imported it.
|
|
279
|
+
*/
|
|
280
|
+
export async function claimContentAnnouncement(migrationAdapter, settings) {
|
|
281
|
+
if (!migrationAdapter || !settings)
|
|
282
|
+
return false;
|
|
283
|
+
const version = await migrationAdapter.getContentManifestVersion();
|
|
284
|
+
if (version === null)
|
|
285
|
+
return false;
|
|
286
|
+
if ((await settings.getSetting(ANNOUNCED_CONTENT_VERSION)) === String(version))
|
|
287
|
+
return false;
|
|
288
|
+
await settings.setSetting(ANNOUNCED_CONTENT_VERSION, String(version));
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=content-migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-migration.js","sourceRoot":"","sources":["../src/content-migration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ApiRequest, ApiResponse } from '@krantho/api';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a Web Request to a framework-agnostic ApiRequest.
|
|
4
|
+
*
|
|
5
|
+
* Extracts method, path, query parameters, headers, and body.
|
|
6
|
+
* Supports both JSON and multipart/form-data content types.
|
|
7
|
+
* The `/api` prefix is preserved — the API router expects it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function toApiRequest(request: Request): Promise<ApiRequest>;
|
|
10
|
+
/**
|
|
11
|
+
* Convert a framework-agnostic ApiResponse to a Web Response.
|
|
12
|
+
*
|
|
13
|
+
* Handles JSON bodies (default), binary bodies (Buffer/Uint8Array for image
|
|
14
|
+
* serving) and stream bodies (a `ReadableStream`, passed through unread). Content-Type is set from response headers if present,
|
|
15
|
+
* otherwise defaults to application/json.
|
|
16
|
+
*/
|
|
17
|
+
export declare function toResponse(apiResponse: ApiResponse): Response;
|
|
18
|
+
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAyC3D;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CA2CxE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,WAAW,GAAG,QAAQ,CAyE7D"}
|
package/dist/convert.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const METHODS_WITH_BODY = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
|
2
|
+
/**
|
|
3
|
+
* Check whether the content-type header indicates multipart form data.
|
|
4
|
+
*/
|
|
5
|
+
function isMultipart(headers) {
|
|
6
|
+
const ct = headers['content-type'] ?? '';
|
|
7
|
+
return ct.startsWith('multipart/form-data');
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Parse multipart form data from a Request into the files array format
|
|
11
|
+
* expected by ApiRequest.
|
|
12
|
+
*/
|
|
13
|
+
async function parseMultipartFiles(request) {
|
|
14
|
+
const formData = await request.formData();
|
|
15
|
+
const files = [];
|
|
16
|
+
const body = {};
|
|
17
|
+
for (const [key, value] of formData) {
|
|
18
|
+
if (value instanceof File) {
|
|
19
|
+
const buffer = await value.arrayBuffer();
|
|
20
|
+
files.push({
|
|
21
|
+
name: key,
|
|
22
|
+
data: new Uint8Array(buffer),
|
|
23
|
+
filename: value.name,
|
|
24
|
+
mimeType: value.type || 'application/octet-stream',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
body[key] = value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { files, body };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Convert a Web Request to a framework-agnostic ApiRequest.
|
|
35
|
+
*
|
|
36
|
+
* Extracts method, path, query parameters, headers, and body.
|
|
37
|
+
* Supports both JSON and multipart/form-data content types.
|
|
38
|
+
* The `/api` prefix is preserved — the API router expects it.
|
|
39
|
+
*/
|
|
40
|
+
export async function toApiRequest(request) {
|
|
41
|
+
const url = new URL(request.url);
|
|
42
|
+
const method = request.method.toUpperCase();
|
|
43
|
+
const query = {};
|
|
44
|
+
for (const [key, value] of url.searchParams) {
|
|
45
|
+
query[key] = value;
|
|
46
|
+
}
|
|
47
|
+
const headers = {};
|
|
48
|
+
for (const [key, value] of request.headers) {
|
|
49
|
+
headers[key.toLowerCase()] = value;
|
|
50
|
+
}
|
|
51
|
+
let body;
|
|
52
|
+
let files;
|
|
53
|
+
if (METHODS_WITH_BODY.has(method) && request.body) {
|
|
54
|
+
if (isMultipart(headers)) {
|
|
55
|
+
const parsed = await parseMultipartFiles(request);
|
|
56
|
+
files = parsed.files;
|
|
57
|
+
body = parsed.body;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
try {
|
|
61
|
+
body = await request.json();
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Non-JSON body or empty — leave undefined
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
method,
|
|
70
|
+
path: url.pathname,
|
|
71
|
+
params: {},
|
|
72
|
+
query,
|
|
73
|
+
body,
|
|
74
|
+
headers,
|
|
75
|
+
rawRequest: request,
|
|
76
|
+
files,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convert a framework-agnostic ApiResponse to a Web Response.
|
|
81
|
+
*
|
|
82
|
+
* Handles JSON bodies (default), binary bodies (Buffer/Uint8Array for image
|
|
83
|
+
* serving) and stream bodies (a `ReadableStream`, passed through unread). Content-Type is set from response headers if present,
|
|
84
|
+
* otherwise defaults to application/json.
|
|
85
|
+
*/
|
|
86
|
+
export function toResponse(apiResponse) {
|
|
87
|
+
const responseHeaders = new Headers();
|
|
88
|
+
if (apiResponse.headers) {
|
|
89
|
+
for (const [key, value] of Object.entries(apiResponse.headers)) {
|
|
90
|
+
responseHeaders.set(key, value);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Emit each cookie as its own Set-Cookie header line (RFC 6265). Headers.append
|
|
94
|
+
// accumulates, and the resulting Response exposes them via headers.getSetCookie().
|
|
95
|
+
if (apiResponse.cookies) {
|
|
96
|
+
for (const cookie of apiResponse.cookies) {
|
|
97
|
+
responseHeaders.append('set-cookie', cookie);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Stream body (e.g. server-sent events) — passed through unread
|
|
101
|
+
if (apiResponse.body instanceof ReadableStream) {
|
|
102
|
+
if (!responseHeaders.has('content-type')) {
|
|
103
|
+
responseHeaders.set('content-type', 'application/octet-stream');
|
|
104
|
+
}
|
|
105
|
+
return new Response(apiResponse.body, {
|
|
106
|
+
status: apiResponse.status,
|
|
107
|
+
headers: responseHeaders,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
// Binary body (Buffer or Uint8Array) — pass raw bytes
|
|
111
|
+
if (apiResponse.body instanceof Uint8Array || Buffer.isBuffer(apiResponse.body)) {
|
|
112
|
+
if (!responseHeaders.has('content-type')) {
|
|
113
|
+
responseHeaders.set('content-type', 'application/octet-stream');
|
|
114
|
+
}
|
|
115
|
+
const raw = Buffer.isBuffer(apiResponse.body)
|
|
116
|
+
? apiResponse.body
|
|
117
|
+
: Buffer.from(apiResponse.body);
|
|
118
|
+
// Copy to a new ArrayBuffer to satisfy BodyInit type (avoids SharedArrayBuffer issue)
|
|
119
|
+
const ab = new ArrayBuffer(raw.byteLength);
|
|
120
|
+
new Uint8Array(ab).set(raw);
|
|
121
|
+
return new Response(ab, {
|
|
122
|
+
status: apiResponse.status,
|
|
123
|
+
headers: responseHeaders,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Null body (e.g., 304 Not Modified)
|
|
127
|
+
if (apiResponse.body === null || apiResponse.body === undefined) {
|
|
128
|
+
return new Response(null, {
|
|
129
|
+
status: apiResponse.status,
|
|
130
|
+
headers: responseHeaders,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// String body with explicit Content-Type (e.g., text/html)
|
|
134
|
+
if (typeof apiResponse.body === 'string') {
|
|
135
|
+
if (!responseHeaders.has('content-type')) {
|
|
136
|
+
responseHeaders.set('content-type', 'text/plain');
|
|
137
|
+
}
|
|
138
|
+
return new Response(apiResponse.body, {
|
|
139
|
+
status: apiResponse.status,
|
|
140
|
+
headers: responseHeaders,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Default: JSON
|
|
144
|
+
if (!responseHeaders.has('content-type')) {
|
|
145
|
+
responseHeaders.set('content-type', 'application/json');
|
|
146
|
+
}
|
|
147
|
+
return new Response(JSON.stringify(apiResponse.body), {
|
|
148
|
+
status: apiResponse.status,
|
|
149
|
+
headers: responseHeaders,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=convert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.js","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MediaSection } from '@krantho/config';
|
|
2
|
+
import type { IFileStore } from '@krantho/persistence';
|
|
3
|
+
/**
|
|
4
|
+
* Build the file store `media.provider` selects.
|
|
5
|
+
*
|
|
6
|
+
* Each store is its own optional peer, loaded by a literal dynamic import so
|
|
7
|
+
* bundlers and Next/Vercel file tracing can follow it; an app installs only
|
|
8
|
+
* the store it uses.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createFileStore(media: MediaSection): Promise<IFileStore>;
|
|
11
|
+
//# sourceMappingURL=file-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEtD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAyB9E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the file store `media.provider` selects.
|
|
3
|
+
*
|
|
4
|
+
* Each store is its own optional peer, loaded by a literal dynamic import so
|
|
5
|
+
* bundlers and Next/Vercel file tracing can follow it; an app installs only
|
|
6
|
+
* the store it uses.
|
|
7
|
+
*/
|
|
8
|
+
export async function createFileStore(media) {
|
|
9
|
+
switch (media.provider) {
|
|
10
|
+
case 'local': {
|
|
11
|
+
const mod = await load('local', '@krantho/media-local', () => import('@krantho/media-local'));
|
|
12
|
+
return mod.createLocalFileStore(media.local);
|
|
13
|
+
}
|
|
14
|
+
case 'vercel-blob': {
|
|
15
|
+
const mod = await load('vercel-blob', '@krantho/media-vercel-blob', () => import('@krantho/media-vercel-blob'));
|
|
16
|
+
return mod.createVercelBlobFileStore(media.vercelBlob);
|
|
17
|
+
}
|
|
18
|
+
case 's3': {
|
|
19
|
+
const mod = await load('s3', '@krantho/media-s3', () => import('@krantho/media-s3'));
|
|
20
|
+
return mod.createS3FileStore(media.s3);
|
|
21
|
+
}
|
|
22
|
+
case 'gcs': {
|
|
23
|
+
const mod = await load('gcs', '@krantho/media-gcs', () => import('@krantho/media-gcs'));
|
|
24
|
+
return mod.createGcsFileStore(media.gcs);
|
|
25
|
+
}
|
|
26
|
+
case undefined:
|
|
27
|
+
throw new Error('media.provider is not set');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function load(provider, pkg, importer) {
|
|
31
|
+
try {
|
|
32
|
+
return await importer();
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
throw new Error(`media.provider is "${provider}", but ${pkg} could not be loaded. ` +
|
|
36
|
+
'Add it to the dependencies of the app that runs krantho.', { cause: err });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=file-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAmB;IACvD,QAAQ,KAAK,CAAC,QAAQ,EAAE,CAAC;QACvB,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,sBAAsB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAA;YAC7F,OAAO,GAAG,CAAC,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,GAAG,GAAG,MAAM,IAAI,CACpB,aAAa,EACb,4BAA4B,EAC5B,GAAG,EAAE,CAAC,MAAM,CAAC,4BAA4B,CAAC,CAC3C,CAAA;YACD,OAAO,GAAG,CAAC,yBAAyB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;QACxD,CAAC;QACD,KAAK,IAAI,CAAC,CAAC,CAAC;YACV,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAA;YACpF,OAAO,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACxC,CAAC;QACD,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,oBAAoB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAA;YACvF,OAAO,GAAG,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC1C,CAAC;QACD,KAAK,SAAS;YACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;IAChD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI,CACjB,QAAuB,EACvB,GAAW,EACX,QAA0B;IAE1B,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,EAAE,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,sBAAsB,QAAQ,UAAU,GAAG,wBAAwB;YACjE,0DAA0D,EAC5D,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAA;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ApiHandlers } from '@krantho/api';
|
|
2
|
+
import { type ContentConfig } from '@krantho/schema';
|
|
3
|
+
import type { ImportableAdapter } from './import.js';
|
|
4
|
+
export interface FileWatcherOptions {
|
|
5
|
+
contentConfig: ContentConfig;
|
|
6
|
+
adapter: ImportableAdapter;
|
|
7
|
+
saveDocument: ApiHandlers['saveRepositoryDocument'];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Start watching filesystem collection directories for changes.
|
|
11
|
+
*
|
|
12
|
+
* When a `.md` file is added or modified, it is parsed, validated against
|
|
13
|
+
* the collection contract, and saved as a draft through the common document write
|
|
14
|
+
* path. When a file is deleted, the document stays in the database until explicitly archived.
|
|
15
|
+
*
|
|
16
|
+
* Returns a cleanup function to stop watching.
|
|
17
|
+
*/
|
|
18
|
+
export declare function startFileWatcher(options: FileWatcherOptions): Promise<() => void>;
|
|
19
|
+
//# sourceMappingURL=file-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-watcher.d.ts","sourceRoot":"","sources":["../src/file-watcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAEL,KAAK,aAAa,EAInB,MAAM,iBAAiB,CAAA;AAGxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAkEpD,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,aAAa,CAAA;IAC5B,OAAO,EAAE,iBAAiB,CAAA;IAC1B,YAAY,EAAE,WAAW,CAAC,wBAAwB,CAAC,CAAA;CACpD;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAoDvF"}
|