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.
Files changed (144) hide show
  1. package/CHANGELOG.md +96 -1
  2. package/README.md +259 -188
  3. package/dist/bin/emit.d.ts.map +1 -1
  4. package/dist/bin/emit.js +2 -0
  5. package/dist/bin/emit.js.map +1 -1
  6. package/dist/cli/commands/doctor.d.ts.map +1 -1
  7. package/dist/cli/commands/doctor.js +6 -0
  8. package/dist/cli/commands/doctor.js.map +1 -1
  9. package/dist/cli/commands/media.d.ts +4 -0
  10. package/dist/cli/commands/media.d.ts.map +1 -0
  11. package/dist/cli/commands/media.js +128 -0
  12. package/dist/cli/commands/media.js.map +1 -0
  13. package/dist/cli/commands/pull.d.ts +32 -0
  14. package/dist/cli/commands/pull.d.ts.map +1 -1
  15. package/dist/cli/commands/pull.js +136 -9
  16. package/dist/cli/commands/pull.js.map +1 -1
  17. package/dist/cli/commands/push.d.ts.map +1 -1
  18. package/dist/cli/commands/push.js +18 -0
  19. package/dist/cli/commands/push.js.map +1 -1
  20. package/dist/cli/commands/status.d.ts.map +1 -1
  21. package/dist/cli/commands/status.js +16 -5
  22. package/dist/cli/commands/status.js.map +1 -1
  23. package/dist/client/media.d.ts.map +1 -1
  24. package/dist/client/media.js +16 -5
  25. package/dist/client/media.js.map +1 -1
  26. package/dist/db/cache.d.ts +19 -4
  27. package/dist/db/cache.d.ts.map +1 -1
  28. package/dist/db/cache.js +127 -16
  29. package/dist/db/cache.js.map +1 -1
  30. package/dist/mcp/server.d.ts.map +1 -1
  31. package/dist/mcp/server.js +7 -3
  32. package/dist/mcp/server.js.map +1 -1
  33. package/dist/mcp/tools/sync-doctor.d.ts.map +1 -1
  34. package/dist/mcp/tools/sync-doctor.js +12 -0
  35. package/dist/mcp/tools/sync-doctor.js.map +1 -1
  36. package/dist/mcp/tools/sync-media-search.d.ts +4 -0
  37. package/dist/mcp/tools/sync-media-search.d.ts.map +1 -0
  38. package/dist/mcp/tools/sync-media-search.js +102 -0
  39. package/dist/mcp/tools/sync-media-search.js.map +1 -0
  40. package/dist/mcp/tools/sync-pull.d.ts.map +1 -1
  41. package/dist/mcp/tools/sync-pull.js +85 -13
  42. package/dist/mcp/tools/sync-pull.js.map +1 -1
  43. package/dist/mcp/tools/sync-push.d.ts.map +1 -1
  44. package/dist/mcp/tools/sync-push.js +5 -0
  45. package/dist/mcp/tools/sync-push.js.map +1 -1
  46. package/dist/mcp/tools/sync-status.d.ts.map +1 -1
  47. package/dist/mcp/tools/sync-status.js +6 -2
  48. package/dist/mcp/tools/sync-status.js.map +1 -1
  49. package/dist/sync/delete.d.ts +2 -1
  50. package/dist/sync/delete.d.ts.map +1 -1
  51. package/dist/sync/delete.js +6 -19
  52. package/dist/sync/delete.js.map +1 -1
  53. package/dist/sync/diff.d.ts.map +1 -1
  54. package/dist/sync/diff.js +18 -2
  55. package/dist/sync/diff.js.map +1 -1
  56. package/dist/sync/doctor.d.ts +27 -1
  57. package/dist/sync/doctor.d.ts.map +1 -1
  58. package/dist/sync/doctor.js +309 -26
  59. package/dist/sync/doctor.js.map +1 -1
  60. package/dist/sync/guards.d.ts +45 -0
  61. package/dist/sync/guards.d.ts.map +1 -0
  62. package/dist/sync/guards.js +236 -0
  63. package/dist/sync/guards.js.map +1 -0
  64. package/dist/sync/media/body_scan.d.ts +15 -0
  65. package/dist/sync/media/body_scan.d.ts.map +1 -0
  66. package/dist/sync/media/body_scan.js +132 -0
  67. package/dist/sync/media/body_scan.js.map +1 -0
  68. package/dist/sync/media/companions.d.ts +32 -0
  69. package/dist/sync/media/companions.d.ts.map +1 -0
  70. package/dist/sync/media/companions.js +260 -0
  71. package/dist/sync/media/companions.js.map +1 -0
  72. package/dist/sync/media/index.d.ts +9 -0
  73. package/dist/sync/media/index.d.ts.map +1 -0
  74. package/dist/sync/media/index.js +9 -0
  75. package/dist/sync/media/index.js.map +1 -0
  76. package/dist/sync/media/mirror_item.d.ts +27 -0
  77. package/dist/sync/media/mirror_item.d.ts.map +1 -0
  78. package/dist/sync/media/mirror_item.js +207 -0
  79. package/dist/sync/media/mirror_item.js.map +1 -0
  80. package/dist/sync/media/naming_mirror.d.ts +36 -0
  81. package/dist/sync/media/naming_mirror.d.ts.map +1 -0
  82. package/dist/sync/media/naming_mirror.js +143 -0
  83. package/dist/sync/media/naming_mirror.js.map +1 -0
  84. package/dist/sync/media/pull_article.d.ts +37 -0
  85. package/dist/sync/media/pull_article.d.ts.map +1 -0
  86. package/dist/sync/media/pull_article.js +273 -0
  87. package/dist/sync/media/pull_article.js.map +1 -0
  88. package/dist/sync/media/pull_library.d.ts +12 -0
  89. package/dist/sync/media/pull_library.d.ts.map +1 -0
  90. package/dist/sync/media/pull_library.js +255 -0
  91. package/dist/sync/media/pull_library.js.map +1 -0
  92. package/dist/sync/media/remote_index.d.ts +49 -0
  93. package/dist/sync/media/remote_index.d.ts.map +1 -0
  94. package/dist/sync/media/remote_index.js +241 -0
  95. package/dist/sync/media/remote_index.js.map +1 -0
  96. package/dist/sync/media/types.d.ts +237 -0
  97. package/dist/sync/media/types.d.ts.map +1 -0
  98. package/dist/sync/media/types.js +11 -0
  99. package/dist/sync/media/types.js.map +1 -0
  100. package/dist/sync/media.d.ts +1 -74
  101. package/dist/sync/media.d.ts.map +1 -1
  102. package/dist/sync/media.js +1 -592
  103. package/dist/sync/media.js.map +1 -1
  104. package/dist/sync/orchestrator.d.ts +23 -0
  105. package/dist/sync/orchestrator.d.ts.map +1 -1
  106. package/dist/sync/orchestrator.js +85 -1
  107. package/dist/sync/orchestrator.js.map +1 -1
  108. package/dist/sync/preflight.d.ts +1 -1
  109. package/dist/sync/preflight.d.ts.map +1 -1
  110. package/dist/sync/preflight.js +129 -17
  111. package/dist/sync/preflight.js.map +1 -1
  112. package/dist/sync/pull.d.ts +19 -0
  113. package/dist/sync/pull.d.ts.map +1 -1
  114. package/dist/sync/pull.js +169 -15
  115. package/dist/sync/pull.js.map +1 -1
  116. package/dist/sync/push.d.ts +7 -0
  117. package/dist/sync/push.d.ts.map +1 -1
  118. package/dist/sync/push.js +37 -10
  119. package/dist/sync/push.js.map +1 -1
  120. package/dist/sync/status.d.ts +4 -0
  121. package/dist/sync/status.d.ts.map +1 -1
  122. package/dist/sync/status.js +68 -4
  123. package/dist/sync/status.js.map +1 -1
  124. package/dist/utils/config.d.ts +25 -0
  125. package/dist/utils/config.d.ts.map +1 -1
  126. package/dist/utils/config.js +28 -2
  127. package/dist/utils/config.js.map +1 -1
  128. package/dist/utils/frontmatter.d.ts +1 -1
  129. package/dist/utils/frontmatter.d.ts.map +1 -1
  130. package/dist/utils/frontmatter.js +15 -4
  131. package/dist/utils/frontmatter.js.map +1 -1
  132. package/dist/utils/media-body-refs.d.ts +81 -0
  133. package/dist/utils/media-body-refs.d.ts.map +1 -0
  134. package/dist/utils/media-body-refs.js +240 -0
  135. package/dist/utils/media-body-refs.js.map +1 -0
  136. package/dist/utils/media-refs.d.ts +44 -0
  137. package/dist/utils/media-refs.d.ts.map +1 -0
  138. package/dist/utils/media-refs.js +101 -0
  139. package/dist/utils/media-refs.js.map +1 -0
  140. package/dist/utils/naming.d.ts +31 -0
  141. package/dist/utils/naming.d.ts.map +1 -1
  142. package/dist/utils/naming.js +58 -0
  143. package/dist/utils/naming.js.map +1 -1
  144. package/package.json +1 -1
@@ -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
@@ -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
  /**