emdash-emit 0.1.17 → 0.1.25
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 +152 -0
- package/README.md +22 -11
- package/dist/cli/commands/new.d.ts.map +1 -1
- package/dist/cli/commands/new.js +30 -0
- package/dist/cli/commands/new.js.map +1 -1
- package/dist/cli/commands/pull.d.ts +2 -10
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/pull.js +12 -30
- package/dist/cli/commands/pull.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +7 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/client/api.d.ts +20 -0
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +89 -0
- package/dist/client/api.js.map +1 -1
- package/dist/client/auth.d.ts.map +1 -1
- package/dist/client/auth.js +2 -1
- package/dist/client/auth.js.map +1 -1
- package/dist/client/endpoints.d.ts +19 -0
- package/dist/client/endpoints.d.ts.map +1 -0
- package/dist/client/endpoints.js +69 -0
- package/dist/client/endpoints.js.map +1 -0
- package/dist/client/http.d.ts +4 -2
- package/dist/client/http.d.ts.map +1 -1
- package/dist/client/http.js.map +1 -1
- package/dist/client/lock.d.ts.map +1 -1
- package/dist/client/lock.js +4 -3
- package/dist/client/lock.js.map +1 -1
- package/dist/client/mapper.d.ts.map +1 -1
- package/dist/client/mapper.js +5 -3
- package/dist/client/mapper.js.map +1 -1
- package/dist/client/media-id.d.ts +2 -0
- package/dist/client/media-id.d.ts.map +1 -0
- package/dist/client/media-id.js +23 -0
- package/dist/client/media-id.js.map +1 -0
- package/dist/client/media.d.ts +8 -7
- package/dist/client/media.d.ts.map +1 -1
- package/dist/client/media.js +58 -17
- package/dist/client/media.js.map +1 -1
- package/dist/db/baseline.d.ts +38 -0
- package/dist/db/baseline.d.ts.map +1 -0
- package/dist/db/baseline.js +74 -0
- package/dist/db/baseline.js.map +1 -0
- package/dist/db/cache.d.ts +8 -2
- package/dist/db/cache.d.ts.map +1 -1
- package/dist/db/cache.js +24 -2
- package/dist/db/cache.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/tools/sync-new.d.ts.map +1 -1
- package/dist/mcp/tools/sync-new.js +42 -1
- package/dist/mcp/tools/sync-new.js.map +1 -1
- package/dist/mcp/tools/sync-pull.d.ts.map +1 -1
- package/dist/mcp/tools/sync-pull.js +15 -2
- package/dist/mcp/tools/sync-pull.js.map +1 -1
- package/dist/mcp/tools/sync-status.d.ts.map +1 -1
- package/dist/mcp/tools/sync-status.js +1 -0
- package/dist/mcp/tools/sync-status.js.map +1 -1
- package/dist/presentation/article_report.d.ts +40 -0
- package/dist/presentation/article_report.d.ts.map +1 -0
- package/dist/presentation/article_report.js +80 -0
- package/dist/presentation/article_report.js.map +1 -0
- package/dist/sync/bylines.d.ts.map +1 -1
- package/dist/sync/bylines.js +2 -1
- package/dist/sync/bylines.js.map +1 -1
- package/dist/sync/conflicts.js +1 -1
- package/dist/sync/conflicts.js.map +1 -1
- package/dist/sync/delete.d.ts +0 -5
- package/dist/sync/delete.d.ts.map +1 -1
- package/dist/sync/delete.js +5 -11
- package/dist/sync/delete.js.map +1 -1
- package/dist/sync/diff.d.ts.map +1 -1
- package/dist/sync/diff.js +13 -9
- package/dist/sync/diff.js.map +1 -1
- package/dist/sync/doctor.d.ts.map +1 -1
- package/dist/sync/doctor.js +11 -14
- package/dist/sync/doctor.js.map +1 -1
- package/dist/sync/guards.d.ts +5 -0
- package/dist/sync/guards.d.ts.map +1 -1
- package/dist/sync/guards.js +62 -1
- package/dist/sync/guards.js.map +1 -1
- package/dist/sync/media/body_scan.d.ts.map +1 -1
- package/dist/sync/media/body_scan.js +9 -3
- package/dist/sync/media/body_scan.js.map +1 -1
- package/dist/sync/media/companions.d.ts +2 -9
- package/dist/sync/media/companions.d.ts.map +1 -1
- package/dist/sync/media/companions.js +5 -23
- package/dist/sync/media/companions.js.map +1 -1
- package/dist/sync/media/mirror_item.d.ts.map +1 -1
- package/dist/sync/media/mirror_item.js +33 -21
- package/dist/sync/media/mirror_item.js.map +1 -1
- package/dist/sync/media/pull_article.d.ts.map +1 -1
- package/dist/sync/media/pull_article.js +3 -2
- package/dist/sync/media/pull_article.js.map +1 -1
- package/dist/sync/media/pull_library.d.ts.map +1 -1
- package/dist/sync/media/pull_library.js +16 -11
- package/dist/sync/media/pull_library.js.map +1 -1
- package/dist/sync/media/remote_index.d.ts.map +1 -1
- package/dist/sync/media/remote_index.js +2 -1
- package/dist/sync/media/remote_index.js.map +1 -1
- package/dist/sync/media/types.d.ts +4 -3
- package/dist/sync/media/types.d.ts.map +1 -1
- package/dist/sync/media/types.js.map +1 -1
- package/dist/sync/merge.d.ts +1 -1
- package/dist/sync/merge.d.ts.map +1 -1
- package/dist/sync/merge.js +50 -17
- package/dist/sync/merge.js.map +1 -1
- package/dist/sync/new.d.ts +11 -0
- package/dist/sync/new.d.ts.map +1 -1
- package/dist/sync/new.js +81 -4
- package/dist/sync/new.js.map +1 -1
- package/dist/sync/preflight.d.ts +10 -2
- package/dist/sync/preflight.d.ts.map +1 -1
- package/dist/sync/preflight.js +119 -17
- package/dist/sync/preflight.js.map +1 -1
- package/dist/sync/pull.d.ts +6 -44
- package/dist/sync/pull.d.ts.map +1 -1
- package/dist/sync/pull.js +154 -207
- package/dist/sync/pull.js.map +1 -1
- package/dist/sync/push/commit.d.ts +61 -0
- package/dist/sync/push/commit.d.ts.map +1 -0
- package/dist/sync/push/commit.js +258 -0
- package/dist/sync/push/commit.js.map +1 -0
- package/dist/sync/push/guards.d.ts +33 -0
- package/dist/sync/push/guards.d.ts.map +1 -0
- package/dist/sync/push/guards.js +110 -0
- package/dist/sync/push/guards.js.map +1 -0
- package/dist/sync/push/index.d.ts +9 -0
- package/dist/sync/push/index.d.ts.map +1 -0
- package/dist/sync/push/index.js +372 -0
- package/dist/sync/push/index.js.map +1 -0
- package/dist/sync/push/media_stage.d.ts +56 -0
- package/dist/sync/push/media_stage.d.ts.map +1 -0
- package/dist/sync/push/media_stage.js +338 -0
- package/dist/sync/push/media_stage.js.map +1 -0
- package/dist/sync/push/merge_stage.d.ts +37 -0
- package/dist/sync/push/merge_stage.d.ts.map +1 -0
- package/dist/sync/push/merge_stage.js +257 -0
- package/dist/sync/push/merge_stage.js.map +1 -0
- package/dist/sync/push/preflight_stage.d.ts +6 -0
- package/dist/sync/push/preflight_stage.d.ts.map +1 -0
- package/dist/sync/push/preflight_stage.js +40 -0
- package/dist/sync/push/preflight_stage.js.map +1 -0
- package/dist/sync/push/tax_audit.d.ts +24 -0
- package/dist/sync/push/tax_audit.d.ts.map +1 -0
- package/dist/sync/push/tax_audit.js +70 -0
- package/dist/sync/push/tax_audit.js.map +1 -0
- package/dist/sync/push/taxonomy_plan.d.ts +36 -0
- package/dist/sync/push/taxonomy_plan.d.ts.map +1 -0
- package/dist/sync/push/taxonomy_plan.js +136 -0
- package/dist/sync/push/taxonomy_plan.js.map +1 -0
- package/dist/sync/push/transport.d.ts +14 -0
- package/dist/sync/push/transport.d.ts.map +1 -0
- package/dist/sync/push/transport.js +74 -0
- package/dist/sync/push/transport.js.map +1 -0
- package/dist/sync/push/types.d.ts +62 -0
- package/dist/sync/push/types.d.ts.map +1 -0
- package/dist/sync/push/types.js +23 -0
- package/dist/sync/push/types.js.map +1 -0
- package/dist/sync/push.d.ts +2 -57
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +2 -1184
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/status.d.ts +3 -0
- package/dist/sync/status.d.ts.map +1 -1
- package/dist/sync/status.js +18 -8
- package/dist/sync/status.js.map +1 -1
- package/dist/sync/taxonomies.d.ts.map +1 -1
- package/dist/sync/taxonomies.js +21 -9
- package/dist/sync/taxonomies.js.map +1 -1
- package/dist/sync/terms.d.ts.map +1 -1
- package/dist/sync/terms.js +2 -1
- package/dist/sync/terms.js.map +1 -1
- package/dist/sync/workspace/commit.d.ts +46 -0
- package/dist/sync/workspace/commit.d.ts.map +1 -0
- package/dist/sync/workspace/commit.js +85 -0
- package/dist/sync/workspace/commit.js.map +1 -0
- package/dist/sync/workspace/index.d.ts +42 -0
- package/dist/sync/workspace/index.d.ts.map +1 -0
- package/dist/sync/workspace/index.js +125 -0
- package/dist/sync/workspace/index.js.map +1 -0
- package/dist/utils/disk-spelling.d.ts +26 -0
- package/dist/utils/disk-spelling.d.ts.map +1 -0
- package/dist/utils/disk-spelling.js +51 -0
- package/dist/utils/disk-spelling.js.map +1 -0
- package/dist/utils/draft-revision.d.ts +15 -0
- package/dist/utils/draft-revision.d.ts.map +1 -0
- package/dist/utils/draft-revision.js +36 -0
- package/dist/utils/draft-revision.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +21 -2
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +71 -10
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/media-body-refs.d.ts +24 -0
- package/dist/utils/media-body-refs.d.ts.map +1 -1
- package/dist/utils/media-body-refs.js +51 -0
- package/dist/utils/media-body-refs.js.map +1 -1
- package/dist/utils/media-companion.d.ts +13 -0
- package/dist/utils/media-companion.d.ts.map +1 -0
- package/dist/utils/media-companion.js +42 -0
- package/dist/utils/media-companion.js.map +1 -0
- package/dist/utils/media-id.d.ts +46 -0
- package/dist/utils/media-id.d.ts.map +1 -0
- package/dist/utils/media-id.js +84 -0
- package/dist/utils/media-id.js.map +1 -0
- package/dist/utils/naming.d.ts.map +1 -1
- package/dist/utils/naming.js +3 -2
- package/dist/utils/naming.js.map +1 -1
- package/dist/utils/ulid.d.ts +31 -0
- package/dist/utils/ulid.d.ts.map +1 -0
- package/dist/utils/ulid.js +65 -0
- package/dist/utils/ulid.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,372 @@
|
|
|
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 { extractRev, unwrapItem } from '../../client/api.js';
|
|
25
|
+
import { ApiError } from '../../client/error.js';
|
|
26
|
+
import { createAuthedFetch } from '../../client/http.js';
|
|
27
|
+
import { withEntryLock } from '../../client/lock.js';
|
|
28
|
+
import { localToApiPayload } from '../../client/mapper.js';
|
|
29
|
+
import { articleContentEndpoint } from '../../client/endpoints.js';
|
|
30
|
+
import { parseMarkdown } from '../../utils/frontmatter.js';
|
|
31
|
+
import { syncRemoteBylines } from '../bylines.js';
|
|
32
|
+
import { loadLocalTaxonomyCandidates, loadLocalTaxonomyMaps } from '../taxonomies.js';
|
|
33
|
+
import { PushValidationError, assertNotQuarantinedCopy, evaluatePrePreflightGuards, evaluatePostPreflightGuards, } from './guards.js';
|
|
34
|
+
import { executePreflightStage } from './preflight_stage.js';
|
|
35
|
+
import { canonicalizeFrontmatterTaxonomies, syncArticleTaxonomies } from './taxonomy_plan.js';
|
|
36
|
+
import { preserveOrResolveFeaturedImage, resolveFeaturedImageMediaId, uploadAndRewriteDraftImages, } from './media_stage.js';
|
|
37
|
+
import { auditRemoteTaxonomies } from './tax_audit.js';
|
|
38
|
+
import { resolveConflictAndMerge } from './merge_stage.js';
|
|
39
|
+
import { commitPostPush } from './commit.js';
|
|
40
|
+
import { throwRemoteArticleDeleted } from './transport.js';
|
|
41
|
+
export { PushValidationError, };
|
|
42
|
+
/**
|
|
43
|
+
* Pushes a local markdown article to remote EmDash with full preflight guards,
|
|
44
|
+
* two-tier lock lease protection, and automatic 3-way merge on conflict.
|
|
45
|
+
*/
|
|
46
|
+
export async function pushArticle(targetFilePath, options) {
|
|
47
|
+
const fetchFn = createAuthedFetch(options);
|
|
48
|
+
const fullPath = path.isAbsolute(targetFilePath)
|
|
49
|
+
? targetFilePath
|
|
50
|
+
: path.join(options.workspaceRoot, targetFilePath);
|
|
51
|
+
if (!fs.existsSync(fullPath)) {
|
|
52
|
+
throw new Error(`Target file not found: ${targetFilePath}`);
|
|
53
|
+
}
|
|
54
|
+
const originalRelPath = path.relative(options.workspaceRoot, fullPath);
|
|
55
|
+
// Rescue copies under "<collection>/conflicts/" are deliberately unpushable.
|
|
56
|
+
assertNotQuarantinedCopy(originalRelPath);
|
|
57
|
+
const rawContent = fs.readFileSync(fullPath, 'utf8');
|
|
58
|
+
const parsed = parseMarkdown(rawContent, targetFilePath);
|
|
59
|
+
const id = parsed.frontmatter.id;
|
|
60
|
+
const collection = parsed.frontmatter.collection;
|
|
61
|
+
// Retrieve sync state and base snapshot
|
|
62
|
+
const syncState = options.cache.getSyncState(id);
|
|
63
|
+
const baseSnapshot = options.cache.getBaseSnapshot(id);
|
|
64
|
+
// Pre-load local taxonomy maps once for canonicalization, G4 guard, and remote sync
|
|
65
|
+
const taxonomyMaps = loadLocalTaxonomyMaps(options.workspaceRoot);
|
|
66
|
+
// Canonicalize frontmatter taxonomy terms in-place before preflight and payload creation
|
|
67
|
+
const { resolvedTaxonomies } = canonicalizeFrontmatterTaxonomies(parsed, taxonomyMaps);
|
|
68
|
+
// Pre-build taxonomy candidates with slugToName for frontmatter serialization with inline '# <Name>' comments
|
|
69
|
+
const candidates = options.candidates || loadLocalTaxonomyCandidates(options.workspaceRoot);
|
|
70
|
+
// If knownTaxonomies is not explicitly passed, populate from local categories/ and tags/ (if present)
|
|
71
|
+
let knownTaxonomies = options.knownTaxonomies;
|
|
72
|
+
if (!knownTaxonomies) {
|
|
73
|
+
const knownCats = Object.keys(taxonomyMaps.slugToId.category);
|
|
74
|
+
const knownTags = Object.keys(taxonomyMaps.slugToId.tag);
|
|
75
|
+
if (knownCats.length > 0 || knownTags.length > 0) {
|
|
76
|
+
knownTaxonomies = {
|
|
77
|
+
...(knownCats.length > 0 ? { categories: knownCats } : {}),
|
|
78
|
+
...(knownTags.length > 0 ? { tags: knownTags } : {}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// 1. Guard against blind re-push when article is marked delete_pending (G15)
|
|
83
|
+
evaluatePrePreflightGuards(syncState, options, collection, id, targetFilePath);
|
|
84
|
+
// 2. Preflight Guards (including G6: UNRESOLVED_CONFLICT_MARKERS - T2-1 invariant)
|
|
85
|
+
const preflight = executePreflightStage(targetFilePath, parsed, options, syncState, baseSnapshot, knownTaxonomies);
|
|
86
|
+
// 3 & 4. Post-preflight guards (G16: taxonomy conflict pending, G17: taxonomy apply pending)
|
|
87
|
+
evaluatePostPreflightGuards(syncState, options, collection, id, targetFilePath);
|
|
88
|
+
// Track 1 (Transport Token): baseSnapshot holds the raw token from server. Prioritize it to prevent 409 conflicts.
|
|
89
|
+
const currentRev = baseSnapshot?.rev || syncState?.remoteRev || '';
|
|
90
|
+
const warnings = [...preflight.warnings];
|
|
91
|
+
// Load local bylines map for converting frontmatter byline slugs to ULIDs
|
|
92
|
+
let bylineSlugToId = options.bylineSlugToId;
|
|
93
|
+
if (!bylineSlugToId) {
|
|
94
|
+
const cachedMaps = options.cache.getBylineMaps();
|
|
95
|
+
if (Object.keys(cachedMaps.slugToId).length > 0) {
|
|
96
|
+
bylineSlugToId = cachedMaps.slugToId;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const freshMaps = await syncRemoteBylines({
|
|
100
|
+
origin: options.origin,
|
|
101
|
+
token: options.token,
|
|
102
|
+
refreshToken: options.refreshToken,
|
|
103
|
+
cache: options.cache,
|
|
104
|
+
fetchFn: options.fetchFn,
|
|
105
|
+
}).catch(() => ({ slugToId: {}, idToSlug: {} }));
|
|
106
|
+
bylineSlugToId = freshMaps.slugToId;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const effectiveOptions = {
|
|
110
|
+
...options,
|
|
111
|
+
bylineSlugToId,
|
|
112
|
+
};
|
|
113
|
+
const isNewArticle = !syncState;
|
|
114
|
+
if (isNewArticle) {
|
|
115
|
+
// Upload/resolve standalone draft images and rewrite body
|
|
116
|
+
const { body: rewrittenBody, uploadedByAbsPath } = await uploadAndRewriteDraftImages(parsed.body, preflight.draftImages, options, fetchFn);
|
|
117
|
+
parsed.body = rewrittenBody;
|
|
118
|
+
const fiResolution = resolveFeaturedImageMediaId(parsed.frontmatter.featuredImage, uploadedByAbsPath, targetFilePath, options.workspaceRoot);
|
|
119
|
+
if (fiResolution) {
|
|
120
|
+
parsed.frontmatter.featuredImage = fiResolution.mediaId;
|
|
121
|
+
}
|
|
122
|
+
else if (parsed.frontmatter.featuredImage) {
|
|
123
|
+
// Defensive guard (W1): preflight guarantees resolution, but fail-fast if an unresolved value reaches push
|
|
124
|
+
throw new Error(`Failed to resolve featuredImage '${parsed.frontmatter.featuredImage}' to a media record ID during push.`);
|
|
125
|
+
}
|
|
126
|
+
const payload = localToApiPayload(parsed, '', effectiveOptions);
|
|
127
|
+
warnings.push(...preserveOrResolveFeaturedImage(payload, parsed.frontmatter.featuredImage, options.cache, id, options.workspaceRoot, { skipCompanionCheck: fiResolution?.autoUploaded }));
|
|
128
|
+
const postUrl = articleContentEndpoint(options.origin, collection);
|
|
129
|
+
const res = await fetchFn(postUrl, {
|
|
130
|
+
method: 'POST',
|
|
131
|
+
headers: {
|
|
132
|
+
Authorization: `Bearer ${options.token}`,
|
|
133
|
+
'Content-Type': 'application/json',
|
|
134
|
+
},
|
|
135
|
+
body: JSON.stringify(payload),
|
|
136
|
+
});
|
|
137
|
+
if (!res.ok) {
|
|
138
|
+
const errBody = await res.text().catch(() => '');
|
|
139
|
+
const slugConflictDetail = 'slug-conflict-detail';
|
|
140
|
+
let remoteSlug;
|
|
141
|
+
let conflictSignal = false;
|
|
142
|
+
try {
|
|
143
|
+
const parsedJson = JSON.parse(errBody);
|
|
144
|
+
const errObj = parsedJson?.error || parsedJson;
|
|
145
|
+
remoteSlug = errObj?.details?.slug;
|
|
146
|
+
if (errObj?.code === 'SLUG_CONFLICT') {
|
|
147
|
+
conflictSignal = true;
|
|
148
|
+
}
|
|
149
|
+
else if (remoteSlug !== undefined) {
|
|
150
|
+
conflictSignal = slugConflictDetail;
|
|
151
|
+
}
|
|
152
|
+
else if (!errObj?.code && (res.status === 409 || res.status === 422)) {
|
|
153
|
+
conflictSignal = /slug/i.test(errObj?.message || '');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
conflictSignal =
|
|
158
|
+
(res.status === 409 || res.status === 422 ? /slug/i.test(errBody) : false) ||
|
|
159
|
+
/slug.*(?:already exists|conflict)|unique constraint.*slug/i.test(errBody);
|
|
160
|
+
}
|
|
161
|
+
const isSlugConflict = conflictSignal === true || conflictSignal === slugConflictDetail;
|
|
162
|
+
const suggestion = isSlugConflict
|
|
163
|
+
? [
|
|
164
|
+
`An article with slug "${remoteSlug || parsed.frontmatter.slug}" already exists on remote.`,
|
|
165
|
+
'Change the "slug" field in frontmatter and re-run',
|
|
166
|
+
`"emit push ${targetFilePath}" (Emit will automatically update the filename and cache).`,
|
|
167
|
+
'Note: EmDash keeps slugs reserved for trashed entries too, so a slug freed by deletion may still be taken.',
|
|
168
|
+
].join(' ')
|
|
169
|
+
: 'Check if an article with this slug already exists or if token has create permissions.';
|
|
170
|
+
throw new ApiError({
|
|
171
|
+
message: `Create push failed: ${res.statusText} - ${errBody}`,
|
|
172
|
+
code: 'PUSH_CREATE_FAILED',
|
|
173
|
+
status: res.status,
|
|
174
|
+
endpoint: postUrl,
|
|
175
|
+
suggestion,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
const createdJson = await res.json();
|
|
179
|
+
const createdItem = unwrapItem(createdJson);
|
|
180
|
+
const actualId = String(createdItem.id || id);
|
|
181
|
+
const newRev = extractRev(createdJson, '1');
|
|
182
|
+
parsed.frontmatter.id = actualId;
|
|
183
|
+
const taxFailures = await syncArticleTaxonomies({
|
|
184
|
+
articleId: actualId,
|
|
185
|
+
collection,
|
|
186
|
+
parsed,
|
|
187
|
+
taxonomyMaps,
|
|
188
|
+
resolvedTaxonomies,
|
|
189
|
+
baseSnapshot,
|
|
190
|
+
options,
|
|
191
|
+
fetchFn,
|
|
192
|
+
warnings,
|
|
193
|
+
});
|
|
194
|
+
return await commitPostPush({
|
|
195
|
+
mode: 'create',
|
|
196
|
+
actualId,
|
|
197
|
+
originalId: id,
|
|
198
|
+
originalRelPath,
|
|
199
|
+
fullPath,
|
|
200
|
+
newRev,
|
|
201
|
+
parsed,
|
|
202
|
+
rawContent,
|
|
203
|
+
draftImages: preflight.draftImages,
|
|
204
|
+
uploadedByAbsPath,
|
|
205
|
+
candidates,
|
|
206
|
+
taxFailures,
|
|
207
|
+
resolvedTaxonomies,
|
|
208
|
+
options,
|
|
209
|
+
fetchFn,
|
|
210
|
+
warnings,
|
|
211
|
+
createdItemCreatedAt: createdItem.createdAt || null,
|
|
212
|
+
updatedRawItem: createdJson,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
// Existing article: execute within full 7-minute entry lock lease
|
|
216
|
+
return await withEntryLock(collection, id, options, async () => {
|
|
217
|
+
const { body: rewrittenBody, uploadedByAbsPath } = await uploadAndRewriteDraftImages(parsed.body, preflight.draftImages, options, fetchFn);
|
|
218
|
+
parsed.body = rewrittenBody;
|
|
219
|
+
const fiResolution = resolveFeaturedImageMediaId(parsed.frontmatter.featuredImage, uploadedByAbsPath, targetFilePath, options.workspaceRoot);
|
|
220
|
+
if (fiResolution) {
|
|
221
|
+
parsed.frontmatter.featuredImage = fiResolution.mediaId;
|
|
222
|
+
}
|
|
223
|
+
else if (parsed.frontmatter.featuredImage) {
|
|
224
|
+
// Defensive guard (W1): preflight guarantees resolution, but fail-fast if an unresolved value reaches push
|
|
225
|
+
throw new Error(`Failed to resolve featuredImage '${parsed.frontmatter.featuredImage}' to a media record ID during push.`);
|
|
226
|
+
}
|
|
227
|
+
let payload = localToApiPayload(parsed, currentRev, effectiveOptions);
|
|
228
|
+
warnings.push(...preserveOrResolveFeaturedImage(payload, parsed.frontmatter.featuredImage, options.cache, id, options.workspaceRoot, { skipCompanionCheck: fiResolution?.autoUploaded }));
|
|
229
|
+
const putUrl = articleContentEndpoint(options.origin, collection, id);
|
|
230
|
+
// Pre-PUT Taxonomy Audit
|
|
231
|
+
const { remoteTaxAudit, taxonomyDivergenceDetected } = await auditRemoteTaxonomies({
|
|
232
|
+
collection,
|
|
233
|
+
id,
|
|
234
|
+
parsed,
|
|
235
|
+
syncState,
|
|
236
|
+
baseSnapshot,
|
|
237
|
+
options,
|
|
238
|
+
fetchFn,
|
|
239
|
+
warnings,
|
|
240
|
+
});
|
|
241
|
+
let res = null;
|
|
242
|
+
if (!taxonomyDivergenceDetected) {
|
|
243
|
+
res = await fetchFn(putUrl, {
|
|
244
|
+
method: 'PUT',
|
|
245
|
+
headers: {
|
|
246
|
+
Authorization: `Bearer ${options.token}`,
|
|
247
|
+
'Content-Type': 'application/json',
|
|
248
|
+
},
|
|
249
|
+
body: JSON.stringify(payload),
|
|
250
|
+
});
|
|
251
|
+
if (res.status === 404 || res.status === 410) {
|
|
252
|
+
throwRemoteArticleDeleted(collection, id, targetFilePath, putUrl);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// Handle 409 Conflict or detected taxonomy divergence
|
|
256
|
+
if (taxonomyDivergenceDetected || res?.status === 409) {
|
|
257
|
+
const conflictOutcome = await resolveConflictAndMerge({
|
|
258
|
+
collection,
|
|
259
|
+
id,
|
|
260
|
+
targetFilePath,
|
|
261
|
+
fullPath,
|
|
262
|
+
putUrl,
|
|
263
|
+
res,
|
|
264
|
+
taxonomyDivergenceDetected,
|
|
265
|
+
parsed,
|
|
266
|
+
syncState,
|
|
267
|
+
baseSnapshot,
|
|
268
|
+
remoteTaxAudit,
|
|
269
|
+
candidates,
|
|
270
|
+
options,
|
|
271
|
+
fetchFn,
|
|
272
|
+
warnings,
|
|
273
|
+
});
|
|
274
|
+
if (conflictOutcome.handled && conflictOutcome.pushResult) {
|
|
275
|
+
return conflictOutcome.pushResult;
|
|
276
|
+
}
|
|
277
|
+
if (conflictOutcome.mergedParsed && conflictOutcome.remoteParsedRev) {
|
|
278
|
+
parsed.frontmatter = conflictOutcome.mergedParsed.frontmatter;
|
|
279
|
+
parsed.body = conflictOutcome.mergedParsed.body;
|
|
280
|
+
payload = localToApiPayload(parsed, conflictOutcome.remoteParsedRev, effectiveOptions);
|
|
281
|
+
warnings.push(...preserveOrResolveFeaturedImage(payload, parsed.frontmatter.featuredImage, options.cache, id, options.workspaceRoot, {
|
|
282
|
+
skipCompanionCheck: fiResolution?.mediaId === parsed.frontmatter.featuredImage &&
|
|
283
|
+
fiResolution?.autoUploaded,
|
|
284
|
+
}));
|
|
285
|
+
res = await fetchFn(putUrl, {
|
|
286
|
+
method: 'PUT',
|
|
287
|
+
headers: {
|
|
288
|
+
Authorization: `Bearer ${options.token}`,
|
|
289
|
+
'Content-Type': 'application/json',
|
|
290
|
+
},
|
|
291
|
+
body: JSON.stringify(payload),
|
|
292
|
+
});
|
|
293
|
+
if (!res.ok) {
|
|
294
|
+
if (res.status === 404 || res.status === 410) {
|
|
295
|
+
throwRemoteArticleDeleted(collection, id, targetFilePath, putUrl);
|
|
296
|
+
}
|
|
297
|
+
const errText = await res.text().catch(() => '');
|
|
298
|
+
const mergeResult = conflictOutcome.mergeResult;
|
|
299
|
+
if ((res.status === 400 || res.status === 422) &&
|
|
300
|
+
((mergeResult?.autoMergedTaxonomies && mergeResult.autoMergedTaxonomies.length > 0) ||
|
|
301
|
+
(mergeResult?.strategyAdoptions && mergeResult.strategyAdoptions.length > 0))) {
|
|
302
|
+
const wasStrategy = mergeResult.strategyAdoptions && mergeResult.strategyAdoptions.length > 0;
|
|
303
|
+
throw new ApiError({
|
|
304
|
+
message: `Remote server rejected the merged taxonomy union (HTTP ${res.status}): ${errText || res.statusText}`,
|
|
305
|
+
code: 'TAXONOMY_UNION_REJECTED',
|
|
306
|
+
status: res.status,
|
|
307
|
+
endpoint: putUrl,
|
|
308
|
+
suggestion: wasStrategy
|
|
309
|
+
? 'The remote server rejected the taxonomy adopted by your strategy (e.g. single-category constraint). Switch strategy with "--resolve-taxonomy=remote" or edit the frontmatter manually before pushing.'
|
|
310
|
+
: 'The remote server enforces constraints that reject combining local and remote taxonomy terms (e.g. single-category constraint). Resolve by explicitly choosing a side: "emit push <file> --resolve-taxonomy=local" (or remote), or edit the frontmatter manually.',
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
throw new ApiError({
|
|
314
|
+
message: `Retry push after auto-merge failed: ${res.statusText}${errText ? ` - ${errText}` : ''}`,
|
|
315
|
+
code: 'PUSH_RETRY_FAILED',
|
|
316
|
+
status: res.status,
|
|
317
|
+
endpoint: putUrl,
|
|
318
|
+
suggestion: 'Another change might have been committed in the meantime. Try pulling again.',
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (!res || !res.ok) {
|
|
324
|
+
if (res && (res.status === 404 || res.status === 410)) {
|
|
325
|
+
throwRemoteArticleDeleted(collection, id, targetFilePath, putUrl);
|
|
326
|
+
}
|
|
327
|
+
const errText = res ? await res.text().catch(() => '') : '';
|
|
328
|
+
throw new ApiError({
|
|
329
|
+
message: `Push failed: ${res ? res.statusText : 'Request failed'}${errText ? ` - ${errText}` : ''}`,
|
|
330
|
+
code: 'PUSH_FAILED',
|
|
331
|
+
status: res ? res.status : 500,
|
|
332
|
+
endpoint: putUrl,
|
|
333
|
+
suggestion: 'Verify network connectivity, token permissions, and article status.',
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
const updatedJson = await res.json().catch(() => ({}));
|
|
337
|
+
const newRev = extractRev(updatedJson, currentRev);
|
|
338
|
+
const taxFailures = await syncArticleTaxonomies({
|
|
339
|
+
articleId: id,
|
|
340
|
+
collection,
|
|
341
|
+
parsed,
|
|
342
|
+
taxonomyMaps,
|
|
343
|
+
resolvedTaxonomies,
|
|
344
|
+
baseSnapshot,
|
|
345
|
+
options,
|
|
346
|
+
fetchFn,
|
|
347
|
+
warnings,
|
|
348
|
+
});
|
|
349
|
+
return await commitPostPush({
|
|
350
|
+
mode: 'update',
|
|
351
|
+
actualId: id,
|
|
352
|
+
originalId: id,
|
|
353
|
+
originalRelPath,
|
|
354
|
+
fullPath,
|
|
355
|
+
newRev,
|
|
356
|
+
parsed,
|
|
357
|
+
rawContent,
|
|
358
|
+
draftImages: preflight.draftImages,
|
|
359
|
+
uploadedByAbsPath,
|
|
360
|
+
candidates,
|
|
361
|
+
taxFailures,
|
|
362
|
+
resolvedTaxonomies,
|
|
363
|
+
options,
|
|
364
|
+
fetchFn,
|
|
365
|
+
warnings,
|
|
366
|
+
syncState,
|
|
367
|
+
baseSnapshot,
|
|
368
|
+
updatedRawItem: updatedJson,
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sync/push/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type localToApiPayload } from '../../client/mapper.js';
|
|
2
|
+
import { type UploadMediaResult } from '../../client/media.js';
|
|
3
|
+
import type { CacheDatabase } from '../../db/cache.js';
|
|
4
|
+
import { type DraftImageReference } from '../preflight.js';
|
|
5
|
+
import type { PushOptions } from './types.js';
|
|
6
|
+
export interface FeaturedImageResolveOptions {
|
|
7
|
+
skipCompanionCheck?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolves the canonical media record ULID for frontmatter featuredImage.
|
|
11
|
+
*
|
|
12
|
+
* If featuredImage is a local path (draft or promoted), it resolves the mediaId from
|
|
13
|
+
* the shared uploadedByAbsPath map. Returns autoUploaded: true when resolved from
|
|
14
|
+
* a newly uploaded or reused draft image reference so that advisory verification
|
|
15
|
+
* warnings can be suppressed.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveFeaturedImageMediaId(featuredImage: string | null | undefined, uploadedByAbsPath: Map<string, UploadMediaResult>, filePath: string, workspaceRoot?: string): {
|
|
18
|
+
mediaId: string;
|
|
19
|
+
autoUploaded: boolean;
|
|
20
|
+
} | null;
|
|
21
|
+
/**
|
|
22
|
+
* Featured-image preservation / resolution helper.
|
|
23
|
+
*
|
|
24
|
+
* EmDash stores `featured_image: { id: "<ULID>" }`.
|
|
25
|
+
* When pushing an article whose frontmatter sets `featuredImage: <ULID>`, Emit cross-checks that the
|
|
26
|
+
* referenced media exists locally (or was mirrored), and preserves the exact remote object structure
|
|
27
|
+
* from the cache when unchanged.
|
|
28
|
+
*/
|
|
29
|
+
export declare function preserveOrResolveFeaturedImage(payload: ReturnType<typeof localToApiPayload>, featuredImage: string | null | undefined, cache: CacheDatabase | undefined, id: string, workspaceRoot?: string, options?: FeaturedImageResolveOptions): string[];
|
|
30
|
+
/**
|
|
31
|
+
* Rewrites standalone local draft image lines in Markdown body to their confirmed
|
|
32
|
+
* canonical root-relative URLs (`/_emdash/api/media/file/<storageKey>`), skipping
|
|
33
|
+
* fenced code blocks and opaque block fences.
|
|
34
|
+
*/
|
|
35
|
+
export declare function rewriteDraftImagesInBody(body: string, draftImages: DraftImageReference[], uploadedByAbsPath: Map<string, UploadMediaResult>): string;
|
|
36
|
+
/**
|
|
37
|
+
* Promotes uploaded draft images from `media/drafts/<filename>` into
|
|
38
|
+
* `media/<markdownRef>.<ext>` along with companion `.yaml` metadata, where markdownRef is derived from the
|
|
39
|
+
* and commits `status = 'ready'` in `media_state`.
|
|
40
|
+
*
|
|
41
|
+
* Protected by try/catch per asset (C-2) so that any local filesystem failure
|
|
42
|
+
* after a successful remote article PUT/POST is downgraded to a warning rather than
|
|
43
|
+
* aborting `saveBaseSnapshot` / `saveSyncState`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function finalizePromotedDraftImages(draftImages: DraftImageReference[], uploadedByAbsPath: Map<string, UploadMediaResult>, options: PushOptions, warnings: string[]): void;
|
|
46
|
+
/**
|
|
47
|
+
* Executes P2–P4 (upload/resolve draft images and rewrite Markdown body in-memory).
|
|
48
|
+
* Already-promoted assets are verified against the remote before their canonical URL is
|
|
49
|
+
* baked into the body, so a media record deleted on the EmDash side can never produce an
|
|
50
|
+
* article that renders HTTP 404 images in production.
|
|
51
|
+
*/
|
|
52
|
+
export declare function uploadAndRewriteDraftImages(body: string, draftImages: DraftImageReference[], options: PushOptions, fetchFn: typeof fetch): Promise<{
|
|
53
|
+
body: string;
|
|
54
|
+
uploadedByAbsPath: Map<string, UploadMediaResult>;
|
|
55
|
+
}>;
|
|
56
|
+
//# sourceMappingURL=media_stage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media_stage.d.ts","sourceRoot":"","sources":["../../../src/sync/push/media_stage.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAyB,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAElF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,2BAA2B;IAC1C,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,EACjD,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GACrB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAkBnD;AAED;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,EAC7C,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,KAAK,EAAE,aAAa,GAAG,SAAS,EAChC,EAAE,EAAE,MAAM,EACV,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,2BAA2B,GACpC,MAAM,EAAE,CA0FV;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,mBAAmB,EAAE,EAClC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAChD,MAAM,CA8CR;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,mBAAmB,EAAE,EAClC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,EACjD,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAAE,GACjB,IAAI,CA4FN;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,mBAAmB,EAAE,EAClC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,OAAO,KAAK,GACpB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CAAE,CAAC,CAwE9E"}
|