emdash-emit 0.1.14 → 0.1.16
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/CHANGELOG.md +96 -1
- package/README.md +259 -188
- package/dist/bin/emit.d.ts.map +1 -1
- package/dist/bin/emit.js +2 -0
- package/dist/bin/emit.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +6 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/media.d.ts +4 -0
- package/dist/cli/commands/media.d.ts.map +1 -0
- package/dist/cli/commands/media.js +128 -0
- package/dist/cli/commands/media.js.map +1 -0
- package/dist/cli/commands/pull.d.ts +32 -0
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/pull.js +136 -9
- package/dist/cli/commands/pull.js.map +1 -1
- package/dist/cli/commands/push.d.ts.map +1 -1
- package/dist/cli/commands/push.js +18 -0
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +16 -5
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/client/media.d.ts.map +1 -1
- package/dist/client/media.js +16 -5
- package/dist/client/media.js.map +1 -1
- package/dist/db/cache.d.ts +19 -4
- package/dist/db/cache.d.ts.map +1 -1
- package/dist/db/cache.js +127 -16
- package/dist/db/cache.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +7 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/sync-doctor.d.ts.map +1 -1
- package/dist/mcp/tools/sync-doctor.js +12 -0
- package/dist/mcp/tools/sync-doctor.js.map +1 -1
- package/dist/mcp/tools/sync-media-search.d.ts +4 -0
- package/dist/mcp/tools/sync-media-search.d.ts.map +1 -0
- package/dist/mcp/tools/sync-media-search.js +102 -0
- package/dist/mcp/tools/sync-media-search.js.map +1 -0
- package/dist/mcp/tools/sync-pull.d.ts.map +1 -1
- package/dist/mcp/tools/sync-pull.js +85 -13
- package/dist/mcp/tools/sync-pull.js.map +1 -1
- package/dist/mcp/tools/sync-push.d.ts.map +1 -1
- package/dist/mcp/tools/sync-push.js +5 -0
- package/dist/mcp/tools/sync-push.js.map +1 -1
- package/dist/mcp/tools/sync-status.d.ts.map +1 -1
- package/dist/mcp/tools/sync-status.js +6 -2
- package/dist/mcp/tools/sync-status.js.map +1 -1
- package/dist/sync/delete.d.ts +2 -1
- package/dist/sync/delete.d.ts.map +1 -1
- package/dist/sync/delete.js +6 -19
- package/dist/sync/delete.js.map +1 -1
- package/dist/sync/diff.d.ts.map +1 -1
- package/dist/sync/diff.js +18 -2
- package/dist/sync/diff.js.map +1 -1
- package/dist/sync/doctor.d.ts +27 -1
- package/dist/sync/doctor.d.ts.map +1 -1
- package/dist/sync/doctor.js +309 -26
- package/dist/sync/doctor.js.map +1 -1
- package/dist/sync/guards.d.ts +45 -0
- package/dist/sync/guards.d.ts.map +1 -0
- package/dist/sync/guards.js +236 -0
- package/dist/sync/guards.js.map +1 -0
- package/dist/sync/media/body_scan.d.ts +15 -0
- package/dist/sync/media/body_scan.d.ts.map +1 -0
- package/dist/sync/media/body_scan.js +132 -0
- package/dist/sync/media/body_scan.js.map +1 -0
- package/dist/sync/media/companions.d.ts +32 -0
- package/dist/sync/media/companions.d.ts.map +1 -0
- package/dist/sync/media/companions.js +260 -0
- package/dist/sync/media/companions.js.map +1 -0
- package/dist/sync/media/index.d.ts +9 -0
- package/dist/sync/media/index.d.ts.map +1 -0
- package/dist/sync/media/index.js +9 -0
- package/dist/sync/media/index.js.map +1 -0
- package/dist/sync/media/mirror_item.d.ts +27 -0
- package/dist/sync/media/mirror_item.d.ts.map +1 -0
- package/dist/sync/media/mirror_item.js +207 -0
- package/dist/sync/media/mirror_item.js.map +1 -0
- package/dist/sync/media/naming_mirror.d.ts +36 -0
- package/dist/sync/media/naming_mirror.d.ts.map +1 -0
- package/dist/sync/media/naming_mirror.js +143 -0
- package/dist/sync/media/naming_mirror.js.map +1 -0
- package/dist/sync/media/pull_article.d.ts +37 -0
- package/dist/sync/media/pull_article.d.ts.map +1 -0
- package/dist/sync/media/pull_article.js +273 -0
- package/dist/sync/media/pull_article.js.map +1 -0
- package/dist/sync/media/pull_library.d.ts +12 -0
- package/dist/sync/media/pull_library.d.ts.map +1 -0
- package/dist/sync/media/pull_library.js +255 -0
- package/dist/sync/media/pull_library.js.map +1 -0
- package/dist/sync/media/remote_index.d.ts +49 -0
- package/dist/sync/media/remote_index.d.ts.map +1 -0
- package/dist/sync/media/remote_index.js +241 -0
- package/dist/sync/media/remote_index.js.map +1 -0
- package/dist/sync/media/types.d.ts +237 -0
- package/dist/sync/media/types.d.ts.map +1 -0
- package/dist/sync/media/types.js +11 -0
- package/dist/sync/media/types.js.map +1 -0
- package/dist/sync/media.d.ts +1 -74
- package/dist/sync/media.d.ts.map +1 -1
- package/dist/sync/media.js +1 -592
- package/dist/sync/media.js.map +1 -1
- package/dist/sync/orchestrator.d.ts +23 -0
- package/dist/sync/orchestrator.d.ts.map +1 -1
- package/dist/sync/orchestrator.js +85 -1
- package/dist/sync/orchestrator.js.map +1 -1
- package/dist/sync/preflight.d.ts +1 -1
- package/dist/sync/preflight.d.ts.map +1 -1
- package/dist/sync/preflight.js +129 -17
- package/dist/sync/preflight.js.map +1 -1
- package/dist/sync/pull.d.ts +19 -0
- package/dist/sync/pull.d.ts.map +1 -1
- package/dist/sync/pull.js +169 -15
- package/dist/sync/pull.js.map +1 -1
- package/dist/sync/push.d.ts +7 -0
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +37 -10
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/status.d.ts +4 -0
- package/dist/sync/status.d.ts.map +1 -1
- package/dist/sync/status.js +68 -4
- package/dist/sync/status.js.map +1 -1
- package/dist/utils/config.d.ts +25 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +28 -2
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +15 -4
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/media-body-refs.d.ts +81 -0
- package/dist/utils/media-body-refs.d.ts.map +1 -0
- package/dist/utils/media-body-refs.js +240 -0
- package/dist/utils/media-body-refs.js.map +1 -0
- package/dist/utils/media-refs.d.ts +44 -0
- package/dist/utils/media-refs.d.ts.map +1 -0
- package/dist/utils/media-refs.js +101 -0
- package/dist/utils/media-refs.js.map +1 -0
- package/dist/utils/naming.d.ts +31 -0
- package/dist/utils/naming.d.ts.map +1 -1
- package/dist/utils/naming.js +58 -0
- package/dist/utils/naming.js.map +1 -1
- package/package.json +1 -1
package/dist/sync/media.js
CHANGED
|
@@ -1,593 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Copyright (C) 2026 SPORT-SERVICE RS★R
|
|
3
|
-
*
|
|
4
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
-
* in the Software without restriction, including without limitation the rights
|
|
7
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
-
* furnished to do so, subject to the following conditions:
|
|
10
|
-
*
|
|
11
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
-
* copies or substantial portions of the Software.
|
|
13
|
-
*
|
|
14
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
-
* SOFTWARE.
|
|
21
|
-
*/
|
|
22
|
-
import fs from 'node:fs';
|
|
23
|
-
import path from 'node:path';
|
|
24
|
-
import yaml from 'js-yaml';
|
|
25
|
-
import { unwrapEnvelope } from '../client/api.js';
|
|
26
|
-
import { ApiError } from '../client/error.js';
|
|
27
|
-
import { createAuthedFetch } from '../client/http.js';
|
|
28
|
-
import { extractMediaUlid } from '../client/mapper.js';
|
|
29
|
-
import { toRootRelativeMediaUrl } from '../client/media.js';
|
|
30
|
-
import { formatDatePrefix, sanitizeTitleForFilename, parseMarkdown, lenientRepairMarkdownFrontmatter, } from '../utils/frontmatter.js';
|
|
31
|
-
import { scanArticleMediaReferences } from './delete.js';
|
|
32
|
-
export function buildMediaMetaDoc(item, origin, existingMeta) {
|
|
33
|
-
const storageKey = (typeof item.storageKey === 'string' && item.storageKey ? item.storageKey : undefined) ??
|
|
34
|
-
(typeof existingMeta?.storageKey === 'string' && existingMeta.storageKey
|
|
35
|
-
? existingMeta.storageKey
|
|
36
|
-
: '');
|
|
37
|
-
const canonicalUrl = item.url ||
|
|
38
|
-
(storageKey
|
|
39
|
-
? `/_emdash/api/media/file/${storageKey}`
|
|
40
|
-
: typeof existingMeta?.url === 'string'
|
|
41
|
-
? existingMeta.url
|
|
42
|
-
: '');
|
|
43
|
-
const rootRelativeUrl = canonicalUrl
|
|
44
|
-
? toRootRelativeMediaUrl(canonicalUrl, storageKey, origin)
|
|
45
|
-
: '';
|
|
46
|
-
const resolvedAlt = item.alt !== undefined && item.alt !== null && item.alt !== ''
|
|
47
|
-
? item.alt
|
|
48
|
-
: typeof existingMeta?.alt === 'string'
|
|
49
|
-
? existingMeta.alt
|
|
50
|
-
: '';
|
|
51
|
-
const resolvedCaption = item.caption !== undefined && item.caption !== null && item.caption !== ''
|
|
52
|
-
? item.caption
|
|
53
|
-
: typeof existingMeta?.caption === 'string'
|
|
54
|
-
? existingMeta.caption
|
|
55
|
-
: '';
|
|
56
|
-
const resolvedContentHash = typeof item.contentHash === 'string' && item.contentHash
|
|
57
|
-
? item.contentHash
|
|
58
|
-
: typeof existingMeta?.contentHash === 'string' && existingMeta.contentHash
|
|
59
|
-
? existingMeta.contentHash
|
|
60
|
-
: null;
|
|
61
|
-
return {
|
|
62
|
-
id: item.id,
|
|
63
|
-
filename: item.filename,
|
|
64
|
-
mimeType: item.mimeType,
|
|
65
|
-
size: item.size,
|
|
66
|
-
width: item.width ?? (typeof existingMeta?.width === 'number' ? existingMeta.width : null),
|
|
67
|
-
height: item.height ?? (typeof existingMeta?.height === 'number' ? existingMeta.height : null),
|
|
68
|
-
alt: resolvedAlt,
|
|
69
|
-
caption: resolvedCaption,
|
|
70
|
-
storageKey,
|
|
71
|
-
contentHash: resolvedContentHash,
|
|
72
|
-
status: item.status ?? (typeof existingMeta?.status === 'string' ? existingMeta.status : 'ready'),
|
|
73
|
-
url: rootRelativeUrl,
|
|
74
|
-
createdAt: item.createdAt || (typeof existingMeta?.createdAt === 'string' ? existingMeta.createdAt : ''),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Moves a file from src to dest, falling back to copy + unlink when src and dest
|
|
79
|
-
* reside on different filesystems (`EXDEV`).
|
|
80
|
-
*/
|
|
81
|
-
function moveFileSafe(src, dest) {
|
|
82
|
-
try {
|
|
83
|
-
fs.renameSync(src, dest);
|
|
84
|
-
}
|
|
85
|
-
catch (err) {
|
|
86
|
-
if (err?.code === 'EXDEV') {
|
|
87
|
-
fs.copyFileSync(src, dest);
|
|
88
|
-
fs.unlinkSync(src);
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
throw err;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Removes any stale duplicate files in `media/` that share the same 26-char `mediaId`
|
|
97
|
-
* but have a different baseName (e.g. a fabricated date prefix from an earlier local promotion).
|
|
98
|
-
*/
|
|
99
|
-
function cleanupDuplicateMediaFilesForId(mediaDir, mediaId, canonicalBaseName) {
|
|
100
|
-
if (!fs.existsSync(mediaDir))
|
|
101
|
-
return;
|
|
102
|
-
const entries = fs.readdirSync(mediaDir);
|
|
103
|
-
for (const entry of entries) {
|
|
104
|
-
const match = entry.replace(/^\d{8}_/, '').match(/^([0-9A-Z]{26})-/);
|
|
105
|
-
if (!match || match[1] !== mediaId)
|
|
106
|
-
continue;
|
|
107
|
-
const entryBase = entry.replace(/\.[^.]+$/, '');
|
|
108
|
-
if (entryBase !== canonicalBaseName) {
|
|
109
|
-
try {
|
|
110
|
-
fs.unlinkSync(path.join(mediaDir, entry));
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
// Ignore cleanup errors
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Promotes a local draft image from media/drafts/<name> into the canonical
|
|
120
|
-
* media/<yyyyMMdd>_<mediaId>-<sanitizedName>.<ext> location alongside its .yaml metadata.
|
|
121
|
-
* Returns the workspace-relative path of the promoted binary file.
|
|
122
|
-
*/
|
|
123
|
-
export function promoteDraftMediaFile(options) {
|
|
124
|
-
const { workspaceRoot, origin, draftAbsPath, item, removeDraft = true } = options;
|
|
125
|
-
const mediaDir = path.join(workspaceRoot, 'media');
|
|
126
|
-
fs.mkdirSync(mediaDir, { recursive: true });
|
|
127
|
-
const ext = path.extname(item.filename) ||
|
|
128
|
-
path.extname(draftAbsPath) ||
|
|
129
|
-
(item.mimeType.includes('png') ? '.png' : '.jpg');
|
|
130
|
-
const baseWithoutExt = path.basename(item.filename, path.extname(item.filename));
|
|
131
|
-
const sanitizedBase = sanitizeTitleForFilename(baseWithoutExt);
|
|
132
|
-
const datePrefix = formatDatePrefix(item.createdAt || new Date().toISOString());
|
|
133
|
-
const baseName = `${datePrefix}${item.id}-${sanitizedBase}`;
|
|
134
|
-
const yamlPath = path.join(mediaDir, `${baseName}.yaml`);
|
|
135
|
-
let existingMeta = null;
|
|
136
|
-
if (fs.existsSync(yamlPath)) {
|
|
137
|
-
try {
|
|
138
|
-
existingMeta = yaml.load(fs.readFileSync(yamlPath, 'utf8'));
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
existingMeta = null;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
const metaDoc = buildMediaMetaDoc(item, origin, existingMeta);
|
|
145
|
-
fs.writeFileSync(yamlPath, yaml.dump(metaDoc, { indent: 2, quotingType: '"', forceQuotes: false, lineWidth: -1 }), 'utf8');
|
|
146
|
-
const targetFilePath = path.join(mediaDir, `${baseName}${ext}`);
|
|
147
|
-
if (fs.existsSync(draftAbsPath)) {
|
|
148
|
-
if (removeDraft) {
|
|
149
|
-
moveFileSafe(draftAbsPath, targetFilePath);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
fs.copyFileSync(draftAbsPath, targetFilePath);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
cleanupDuplicateMediaFilesForId(mediaDir, item.id, baseName);
|
|
156
|
-
return path.posix.join('media', `${baseName}${ext}`);
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Collects all media ULIDs referenced by an article content (frontmatter featuredImage + body images).
|
|
160
|
-
*/
|
|
161
|
-
export function collectArticleReferencedMediaIds(content) {
|
|
162
|
-
const ids = new Set();
|
|
163
|
-
let frontmatter = null;
|
|
164
|
-
let body = content;
|
|
165
|
-
// Try extracting YAML block directly if present
|
|
166
|
-
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
167
|
-
if (fmMatch) {
|
|
168
|
-
try {
|
|
169
|
-
frontmatter = yaml.load(fmMatch[1]) || null;
|
|
170
|
-
body = content.slice(fmMatch[0].length);
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
// Keep going
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (!frontmatter) {
|
|
177
|
-
try {
|
|
178
|
-
const parsed = parseMarkdown(content);
|
|
179
|
-
frontmatter = parsed.frontmatter;
|
|
180
|
-
body = parsed.body;
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
try {
|
|
184
|
-
const healed = lenientRepairMarkdownFrontmatter(content);
|
|
185
|
-
if (healed) {
|
|
186
|
-
const parsed = parseMarkdown(healed);
|
|
187
|
-
frontmatter = parsed.frontmatter;
|
|
188
|
-
body = parsed.body;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
catch {
|
|
192
|
-
// Fallback: search raw content
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
// 1. Frontmatter featuredImage
|
|
197
|
-
if (frontmatter && frontmatter.featuredImage) {
|
|
198
|
-
const ulid = extractMediaUlid(frontmatter.featuredImage);
|
|
199
|
-
if (ulid) {
|
|
200
|
-
ids.add(ulid);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
// Regex fallback for featuredImage in raw text if YAML parsing failed
|
|
205
|
-
const rawFiMatch = content.match(/featuredImage:\s*["']?([0-9A-HJ-NP-Z]{26})["']?/i);
|
|
206
|
-
if (rawFiMatch) {
|
|
207
|
-
ids.add(rawFiMatch[1].toUpperCase());
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// 2. Body Markdown & HTML image references
|
|
211
|
-
const refs = scanArticleMediaReferences(body);
|
|
212
|
-
for (const ref of refs) {
|
|
213
|
-
const ulid = extractMediaUlid(ref);
|
|
214
|
-
if (ulid) {
|
|
215
|
-
ids.add(ulid);
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
const match = ref.match(/(?:^|\/)(?:\d{8}_)?([0-9A-HJ-NP-Z]{26})-/i);
|
|
219
|
-
if (match) {
|
|
220
|
-
ids.add(match[1].toUpperCase());
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
// 3. URLs matching /_emdash/api/media/file/<ULID> or /media/<ULID>
|
|
225
|
-
const mediaUrlRegex = /(?:\/media\/file\/|\/media\/)([0-9A-HJ-NP-Z]{26})/gi;
|
|
226
|
-
let m;
|
|
227
|
-
while ((m = mediaUrlRegex.exec(body)) !== null) {
|
|
228
|
-
ids.add(m[1].toUpperCase());
|
|
229
|
-
}
|
|
230
|
-
return Array.from(ids).sort();
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Persists YAML companion metadata and downloads the binary file for a single media item.
|
|
234
|
-
*/
|
|
235
|
-
async function syncSingleMediaItem(options) {
|
|
236
|
-
const { item, mediaDir, origin, token, downloadFiles, fetchFn } = options;
|
|
237
|
-
const ext = path.extname(item.filename);
|
|
238
|
-
const baseWithoutExt = path.basename(item.filename, ext);
|
|
239
|
-
const sanitizedBase = sanitizeTitleForFilename(baseWithoutExt);
|
|
240
|
-
const datePrefix = formatDatePrefix(item.createdAt);
|
|
241
|
-
const baseName = `${datePrefix}${item.id}-${sanitizedBase}`;
|
|
242
|
-
const oldBaseName = `${item.id}-${sanitizedBase}`;
|
|
243
|
-
// Clean up old un-prefixed YAML if migrating, and load any existing metadata for this media ID
|
|
244
|
-
const oldYamlPath = path.join(mediaDir, `${oldBaseName}.yaml`);
|
|
245
|
-
const yamlPath = path.join(mediaDir, `${baseName}.yaml`);
|
|
246
|
-
let existingMeta = null;
|
|
247
|
-
if (fs.existsSync(yamlPath)) {
|
|
248
|
-
try {
|
|
249
|
-
existingMeta = yaml.load(fs.readFileSync(yamlPath, 'utf8'));
|
|
250
|
-
}
|
|
251
|
-
catch {
|
|
252
|
-
existingMeta = null;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
// Check if an older or differently-dated YAML for the same item.id exists
|
|
257
|
-
const existingFiles = fs.readdirSync(mediaDir);
|
|
258
|
-
const matchingYaml = existingFiles.find((f) => f.endsWith('.yaml') && (f.includes(`_${item.id}-`) || f.startsWith(`${item.id}-`)));
|
|
259
|
-
if (matchingYaml) {
|
|
260
|
-
try {
|
|
261
|
-
existingMeta = yaml.load(fs.readFileSync(path.join(mediaDir, matchingYaml), 'utf8'));
|
|
262
|
-
}
|
|
263
|
-
catch {
|
|
264
|
-
existingMeta = null;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
if (oldYamlPath !== yamlPath && fs.existsSync(oldYamlPath)) {
|
|
269
|
-
try {
|
|
270
|
-
fs.unlinkSync(oldYamlPath);
|
|
271
|
-
}
|
|
272
|
-
catch { }
|
|
273
|
-
}
|
|
274
|
-
// 1. Write YAML metadata
|
|
275
|
-
const metaDoc = buildMediaMetaDoc(item, origin, existingMeta);
|
|
276
|
-
fs.writeFileSync(yamlPath, yaml.dump(metaDoc, { indent: 2, quotingType: '"', forceQuotes: false, lineWidth: -1 }), 'utf8');
|
|
277
|
-
let downloaded = false;
|
|
278
|
-
let skipped = false;
|
|
279
|
-
// 2. Download binary file if enabled and url is present
|
|
280
|
-
const canonicalDownloadPath = item.url || (item.storageKey ? `/_emdash/api/media/file/${item.storageKey}` : '');
|
|
281
|
-
if (downloadFiles && canonicalDownloadPath) {
|
|
282
|
-
const fileExt = ext || (item.mimeType.includes('png') ? '.png' : '.jpg');
|
|
283
|
-
const oldFilePath = path.join(mediaDir, `${oldBaseName}${fileExt}`);
|
|
284
|
-
const targetFilePath = path.join(mediaDir, `${baseName}${fileExt}`);
|
|
285
|
-
// Migrate/rename old or differently-dated file for the same media ID if already present
|
|
286
|
-
if (!fs.existsSync(targetFilePath)) {
|
|
287
|
-
const candidates = [
|
|
288
|
-
oldFilePath,
|
|
289
|
-
...fs
|
|
290
|
-
.readdirSync(mediaDir)
|
|
291
|
-
.filter((f) => !f.endsWith('.yaml') && (f.includes(`_${item.id}-`) || f.startsWith(`${item.id}-`)))
|
|
292
|
-
.map((f) => path.join(mediaDir, f)),
|
|
293
|
-
];
|
|
294
|
-
for (const candidate of candidates) {
|
|
295
|
-
if (candidate !== targetFilePath && fs.existsSync(candidate)) {
|
|
296
|
-
try {
|
|
297
|
-
const stat = fs.statSync(candidate);
|
|
298
|
-
if (stat.size === item.size) {
|
|
299
|
-
moveFileSafe(candidate, targetFilePath);
|
|
300
|
-
break;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
catch { }
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
// Avoid re-downloading if already present and matches size
|
|
308
|
-
let shouldDownload = true;
|
|
309
|
-
if (fs.existsSync(targetFilePath)) {
|
|
310
|
-
const stat = fs.statSync(targetFilePath);
|
|
311
|
-
if (stat.size === item.size) {
|
|
312
|
-
shouldDownload = false;
|
|
313
|
-
skipped = true;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
if (shouldDownload) {
|
|
317
|
-
try {
|
|
318
|
-
const downloadUrl = new URL(canonicalDownloadPath, origin).toString();
|
|
319
|
-
const fileRes = await fetchFn(downloadUrl, {
|
|
320
|
-
headers: {
|
|
321
|
-
Authorization: `Bearer ${token}`,
|
|
322
|
-
},
|
|
323
|
-
});
|
|
324
|
-
if (fileRes.ok) {
|
|
325
|
-
const buffer = Buffer.from(await fileRes.arrayBuffer());
|
|
326
|
-
fs.writeFileSync(targetFilePath, buffer);
|
|
327
|
-
downloaded = true;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
catch {
|
|
331
|
-
// Ignore individual download failures
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
// Clean up any duplicate files with the same media ID but a different datePrefix/baseName
|
|
336
|
-
cleanupDuplicateMediaFilesForId(mediaDir, item.id, baseName);
|
|
337
|
-
return { downloaded, skipped, baseName };
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Pulls media referenced by a specific article (by ULID or file path).
|
|
341
|
-
*/
|
|
342
|
-
export async function pullArticleMedia(options) {
|
|
343
|
-
const fetchFn = createAuthedFetch(options);
|
|
344
|
-
const collection = options.collection || 'posts';
|
|
345
|
-
const downloadFiles = options.downloadFiles !== false;
|
|
346
|
-
const mediaDir = path.join(options.workspaceRoot, 'media');
|
|
347
|
-
fs.mkdirSync(mediaDir, { recursive: true });
|
|
348
|
-
let articleId = options.article;
|
|
349
|
-
let articleContent = null;
|
|
350
|
-
// 1. Try resolving as direct file path
|
|
351
|
-
const directPath = path.isAbsolute(options.article)
|
|
352
|
-
? options.article
|
|
353
|
-
: path.resolve(options.workspaceRoot, options.article);
|
|
354
|
-
if (fs.existsSync(directPath) && fs.statSync(directPath).isFile()) {
|
|
355
|
-
articleContent = fs.readFileSync(directPath, 'utf8');
|
|
356
|
-
try {
|
|
357
|
-
const parsed = parseMarkdown(articleContent);
|
|
358
|
-
articleId = parsed.frontmatter.id || articleId;
|
|
359
|
-
}
|
|
360
|
-
catch {
|
|
361
|
-
// Keep articleId as fallback
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
// 2. Try finding file in draft/published
|
|
366
|
-
for (const status of ['draft', 'published']) {
|
|
367
|
-
const statusDir = path.join(options.workspaceRoot, collection, status);
|
|
368
|
-
if (!fs.existsSync(statusDir))
|
|
369
|
-
continue;
|
|
370
|
-
const found = fs
|
|
371
|
-
.readdirSync(statusDir)
|
|
372
|
-
.find((f) => f.endsWith('.md') && f.includes(options.article));
|
|
373
|
-
if (found) {
|
|
374
|
-
articleContent = fs.readFileSync(path.join(statusDir, found), 'utf8');
|
|
375
|
-
try {
|
|
376
|
-
const parsed = parseMarkdown(articleContent);
|
|
377
|
-
articleId = parsed.frontmatter.id || articleId;
|
|
378
|
-
}
|
|
379
|
-
catch {
|
|
380
|
-
// fallback
|
|
381
|
-
}
|
|
382
|
-
break;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
// 3. If still absent locally, fetch remote article content from EmDash API
|
|
387
|
-
if (!articleContent) {
|
|
388
|
-
const url = new URL(`/_emdash/api/content/${collection}/${options.article}`, options.origin);
|
|
389
|
-
const res = await fetchFn(url.toString(), {
|
|
390
|
-
headers: {
|
|
391
|
-
Authorization: `Bearer ${options.token}`,
|
|
392
|
-
Accept: 'application/json',
|
|
393
|
-
},
|
|
394
|
-
});
|
|
395
|
-
if (!res.ok) {
|
|
396
|
-
throw new ApiError({
|
|
397
|
-
message: `Failed to fetch remote article for media resolution: ${res.statusText}`,
|
|
398
|
-
code: 'ARTICLE_NOT_FOUND',
|
|
399
|
-
status: res.status,
|
|
400
|
-
endpoint: url.toString(),
|
|
401
|
-
suggestion: `Verify that article '${options.article}' exists in collection '${collection}' on remote.`,
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
const json = await res.json();
|
|
405
|
-
const data = unwrapEnvelope(json);
|
|
406
|
-
const item = (data.item || data);
|
|
407
|
-
articleId = item.id || options.article;
|
|
408
|
-
// Build synthesized content string from remote representation
|
|
409
|
-
const remoteFi = item.featured_image || item.featuredImage;
|
|
410
|
-
const fiId = extractMediaUlid(remoteFi);
|
|
411
|
-
const fiPart = fiId ? `featuredImage: ${fiId}\n` : '';
|
|
412
|
-
const bodyPart = typeof item.content === 'string'
|
|
413
|
-
? item.content
|
|
414
|
-
: JSON.stringify(item.content || item.body || '');
|
|
415
|
-
articleContent = `---\n${fiPart}---\n${bodyPart}`;
|
|
416
|
-
}
|
|
417
|
-
const mediaIds = collectArticleReferencedMediaIds(articleContent);
|
|
418
|
-
if (mediaIds.length === 0) {
|
|
419
|
-
return {
|
|
420
|
-
total: 0,
|
|
421
|
-
downloaded: 0,
|
|
422
|
-
skipped: 0,
|
|
423
|
-
failed: 0,
|
|
424
|
-
articleId,
|
|
425
|
-
mediaIds: [],
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
let downloadedCount = 0;
|
|
429
|
-
let skippedCount = 0;
|
|
430
|
-
let failedCount = 0;
|
|
431
|
-
for (const mId of mediaIds) {
|
|
432
|
-
try {
|
|
433
|
-
const mediaUrl = new URL(`/_emdash/api/media/${mId}`, options.origin);
|
|
434
|
-
const res = await fetchFn(mediaUrl.toString(), {
|
|
435
|
-
headers: {
|
|
436
|
-
Authorization: `Bearer ${options.token}`,
|
|
437
|
-
Accept: 'application/json',
|
|
438
|
-
},
|
|
439
|
-
});
|
|
440
|
-
if (!res.ok) {
|
|
441
|
-
failedCount++;
|
|
442
|
-
continue;
|
|
443
|
-
}
|
|
444
|
-
const json = await res.json();
|
|
445
|
-
const envelope = unwrapEnvelope(json);
|
|
446
|
-
const item = (envelope.item || envelope);
|
|
447
|
-
const result = await syncSingleMediaItem({
|
|
448
|
-
item,
|
|
449
|
-
mediaDir,
|
|
450
|
-
origin: options.origin,
|
|
451
|
-
token: options.token,
|
|
452
|
-
downloadFiles,
|
|
453
|
-
fetchFn,
|
|
454
|
-
});
|
|
455
|
-
if (result.downloaded)
|
|
456
|
-
downloadedCount++;
|
|
457
|
-
else if (result.skipped)
|
|
458
|
-
skippedCount++;
|
|
459
|
-
}
|
|
460
|
-
catch {
|
|
461
|
-
failedCount++;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
return {
|
|
465
|
-
total: mediaIds.length,
|
|
466
|
-
downloaded: downloadedCount,
|
|
467
|
-
skipped: skippedCount,
|
|
468
|
-
failed: failedCount,
|
|
469
|
-
articleId,
|
|
470
|
-
mediaIds,
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Pulls media metadata and files from EmDash API into media/ directory with cursor pagination.
|
|
475
|
-
* media/<id>-<filename>.yaml
|
|
476
|
-
* media/<id>-<filename>.<ext>
|
|
477
|
-
*/
|
|
478
|
-
export async function pullMedia(options) {
|
|
479
|
-
if (options.article) {
|
|
480
|
-
return pullArticleMedia({
|
|
481
|
-
workspaceRoot: options.workspaceRoot,
|
|
482
|
-
origin: options.origin,
|
|
483
|
-
token: options.token,
|
|
484
|
-
refreshToken: options.refreshToken,
|
|
485
|
-
article: options.article,
|
|
486
|
-
collection: options.collection,
|
|
487
|
-
downloadFiles: options.downloadFiles,
|
|
488
|
-
fetchFn: options.fetchFn,
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
const fetchFn = createAuthedFetch(options);
|
|
492
|
-
const targetTotal = options.all ? Infinity : (options.limit ?? 300);
|
|
493
|
-
const downloadFiles = options.downloadFiles !== false;
|
|
494
|
-
const batchSize = 100;
|
|
495
|
-
const mediaDir = path.join(options.workspaceRoot, 'media');
|
|
496
|
-
fs.mkdirSync(mediaDir, { recursive: true });
|
|
497
|
-
const activeMediaBaseNames = new Set();
|
|
498
|
-
const activeMediaIds = new Set();
|
|
499
|
-
let totalProcessed = 0;
|
|
500
|
-
let downloadedCount = 0;
|
|
501
|
-
let skippedCount = 0;
|
|
502
|
-
let cursor = undefined;
|
|
503
|
-
while (totalProcessed < targetTotal) {
|
|
504
|
-
const remaining = targetTotal - totalProcessed;
|
|
505
|
-
const currentBatch = Math.min(remaining, batchSize);
|
|
506
|
-
const url = new URL(`/_emdash/api/media`, options.origin);
|
|
507
|
-
url.searchParams.set('limit', String(currentBatch));
|
|
508
|
-
if (cursor) {
|
|
509
|
-
url.searchParams.set('cursor', cursor);
|
|
510
|
-
}
|
|
511
|
-
const res = await fetchFn(url.toString(), {
|
|
512
|
-
method: 'GET',
|
|
513
|
-
headers: {
|
|
514
|
-
Authorization: `Bearer ${options.token}`,
|
|
515
|
-
Accept: 'application/json',
|
|
516
|
-
},
|
|
517
|
-
});
|
|
518
|
-
if (!res.ok) {
|
|
519
|
-
throw new ApiError({
|
|
520
|
-
message: `Failed to list media: ${res.statusText}`,
|
|
521
|
-
code: 'MEDIA_LIST_FAILED',
|
|
522
|
-
status: res.status,
|
|
523
|
-
endpoint: url.toString(),
|
|
524
|
-
suggestion: 'Verify network connection and token permissions.',
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
const json = await res.json();
|
|
528
|
-
const data = unwrapEnvelope(json);
|
|
529
|
-
const rawItems = (Array.isArray(data.items) ? data.items : Array.isArray(data) ? data : []);
|
|
530
|
-
if (rawItems.length === 0) {
|
|
531
|
-
break;
|
|
532
|
-
}
|
|
533
|
-
for (const item of rawItems) {
|
|
534
|
-
const ext = path.extname(item.filename);
|
|
535
|
-
const baseWithoutExt = path.basename(item.filename, ext);
|
|
536
|
-
const sanitizedBase = sanitizeTitleForFilename(baseWithoutExt);
|
|
537
|
-
const datePrefix = formatDatePrefix(item.createdAt);
|
|
538
|
-
const baseName = `${datePrefix}${item.id}-${sanitizedBase}`;
|
|
539
|
-
const oldBaseName = `${item.id}-${sanitizedBase}`;
|
|
540
|
-
activeMediaBaseNames.add(baseName);
|
|
541
|
-
activeMediaBaseNames.add(oldBaseName);
|
|
542
|
-
activeMediaIds.add(item.id);
|
|
543
|
-
const result = await syncSingleMediaItem({
|
|
544
|
-
item,
|
|
545
|
-
mediaDir,
|
|
546
|
-
origin: options.origin,
|
|
547
|
-
token: options.token,
|
|
548
|
-
downloadFiles,
|
|
549
|
-
fetchFn,
|
|
550
|
-
});
|
|
551
|
-
if (result.downloaded)
|
|
552
|
-
downloadedCount++;
|
|
553
|
-
else if (result.skipped)
|
|
554
|
-
skippedCount++;
|
|
555
|
-
totalProcessed++;
|
|
556
|
-
if (totalProcessed >= targetTotal) {
|
|
557
|
-
break;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
if (!data.nextCursor || typeof data.nextCursor !== 'string') {
|
|
561
|
-
break;
|
|
562
|
-
}
|
|
563
|
-
cursor = data.nextCursor;
|
|
564
|
-
}
|
|
565
|
-
// Pruning logic for media: if --prune or --all is enabled, delete local media not present on remote
|
|
566
|
-
let deletedCount = 0;
|
|
567
|
-
if ((options.prune || options.all) && fs.existsSync(mediaDir)) {
|
|
568
|
-
const files = fs.readdirSync(mediaDir);
|
|
569
|
-
for (const file of files) {
|
|
570
|
-
// Check if file is related to any active media ID
|
|
571
|
-
const match = file.replace(/^\d{8}_/, '').match(/^([0-9A-Z]{26})/);
|
|
572
|
-
if (match) {
|
|
573
|
-
const id = match[1];
|
|
574
|
-
if (!activeMediaIds.has(id)) {
|
|
575
|
-
try {
|
|
576
|
-
fs.unlinkSync(path.join(mediaDir, file));
|
|
577
|
-
deletedCount++;
|
|
578
|
-
}
|
|
579
|
-
catch {
|
|
580
|
-
// Ignore unlink errors
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
return {
|
|
587
|
-
total: totalProcessed,
|
|
588
|
-
downloaded: downloadedCount,
|
|
589
|
-
skipped: skippedCount,
|
|
590
|
-
deleted: deletedCount,
|
|
591
|
-
};
|
|
592
|
-
}
|
|
1
|
+
export * from './media/index.js';
|
|
593
2
|
//# sourceMappingURL=media.js.map
|
package/dist/sync/media.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/sync/media.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/sync/media.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
|
|
@@ -18,6 +18,15 @@ export interface PullBatchOptions extends ListRemoteArticlesOptions {
|
|
|
18
18
|
force?: boolean;
|
|
19
19
|
concurrency?: number;
|
|
20
20
|
prune?: boolean;
|
|
21
|
+
/** Write mirrored body images as article-relative `../../media/<storageKey>` references. Passed to every article pull. */
|
|
22
|
+
localMediaRefs?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Local-first media mirroring is default-ON for a batch pull: after articles land on disk, Emit walks the
|
|
25
|
+
* remote media library once (JSON only), then downloads binaries for exactly the storageKeys those article
|
|
26
|
+
* bodies reference. Pass `false` to skip the walk and every binary download — this is what `--posts-only`
|
|
27
|
+
* uses. The full-library `emit pull-media --all` path stays a separate command, unaffected by this flag.
|
|
28
|
+
*/
|
|
29
|
+
mediaSync?: boolean;
|
|
21
30
|
onProgress?: (progress: {
|
|
22
31
|
current: number;
|
|
23
32
|
total: number;
|
|
@@ -33,6 +42,20 @@ export interface PullBatchResult {
|
|
|
33
42
|
preserved?: number;
|
|
34
43
|
/** Total number of divergent local copies preserved under `<collection>/conflicts/`. */
|
|
35
44
|
quarantined?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Local-first media mirror stage result: the lightweight library walk plus the binaries downloaded for
|
|
47
|
+
* exactly the storageKeys referenced by pulled article bodies. Absent when `mediaSync` was disabled.
|
|
48
|
+
*/
|
|
49
|
+
media?: {
|
|
50
|
+
walkedCount: number;
|
|
51
|
+
remoteTotalCount: number | null;
|
|
52
|
+
complete: boolean;
|
|
53
|
+
downloaded: number;
|
|
54
|
+
skipped: number;
|
|
55
|
+
mirroredStorageKeys: string[];
|
|
56
|
+
verifiedStorageKeys: string[];
|
|
57
|
+
orphanStorageKeys: string[];
|
|
58
|
+
};
|
|
36
59
|
items: PullResult[];
|
|
37
60
|
}
|
|
38
61
|
/**
|