emdash-emit 0.1.25 → 0.1.30

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 (203) hide show
  1. package/CHANGELOG.md +132 -4
  2. package/dist/cli/commands/conflicts.d.ts.map +1 -1
  3. package/dist/cli/commands/conflicts.js +2 -22
  4. package/dist/cli/commands/conflicts.js.map +1 -1
  5. package/dist/cli/commands/delete.d.ts.map +1 -1
  6. package/dist/cli/commands/delete.js +1 -13
  7. package/dist/cli/commands/delete.js.map +1 -1
  8. package/dist/cli/commands/doctor.d.ts.map +1 -1
  9. package/dist/cli/commands/doctor.js +1 -13
  10. package/dist/cli/commands/doctor.js.map +1 -1
  11. package/dist/cli/commands/media.d.ts.map +1 -1
  12. package/dist/cli/commands/media.js +1 -13
  13. package/dist/cli/commands/media.js.map +1 -1
  14. package/dist/cli/commands/new.d.ts.map +1 -1
  15. package/dist/cli/commands/new.js +1 -13
  16. package/dist/cli/commands/new.js.map +1 -1
  17. package/dist/cli/commands/pull.d.ts +1 -1
  18. package/dist/cli/commands/pull.d.ts.map +1 -1
  19. package/dist/cli/commands/pull.js +110 -79
  20. package/dist/cli/commands/pull.js.map +1 -1
  21. package/dist/cli/commands/push.d.ts +1 -1
  22. package/dist/cli/commands/push.d.ts.map +1 -1
  23. package/dist/cli/commands/push.js +32 -90
  24. package/dist/cli/commands/push.js.map +1 -1
  25. package/dist/cli/context.d.ts +12 -0
  26. package/dist/cli/context.d.ts.map +1 -1
  27. package/dist/cli/context.js +27 -1
  28. package/dist/cli/context.js.map +1 -1
  29. package/dist/cli/report-failure.d.ts +6 -0
  30. package/dist/cli/report-failure.d.ts.map +1 -0
  31. package/dist/cli/report-failure.js +71 -0
  32. package/dist/cli/report-failure.js.map +1 -0
  33. package/dist/client/api.d.ts.map +1 -1
  34. package/dist/client/api.js +1 -1
  35. package/dist/client/api.js.map +1 -1
  36. package/dist/client/lock.js.map +1 -1
  37. package/dist/client/mapper.js.map +1 -1
  38. package/dist/client/media.d.ts.map +1 -1
  39. package/dist/client/media.js.map +1 -1
  40. package/dist/db/baseline.d.ts +16 -1
  41. package/dist/db/baseline.d.ts.map +1 -1
  42. package/dist/db/baseline.js +25 -0
  43. package/dist/db/baseline.js.map +1 -1
  44. package/dist/db/cache.d.ts +2 -3
  45. package/dist/db/cache.d.ts.map +1 -1
  46. package/dist/db/cache.js +3 -295
  47. package/dist/db/cache.js.map +1 -1
  48. package/dist/db/migrations.d.ts +7 -0
  49. package/dist/db/migrations.d.ts.map +1 -0
  50. package/dist/db/migrations.js +320 -0
  51. package/dist/db/migrations.js.map +1 -0
  52. package/dist/mcp/heartbeat.d.ts +1 -34
  53. package/dist/mcp/heartbeat.d.ts.map +1 -1
  54. package/dist/mcp/heartbeat.js +1 -113
  55. package/dist/mcp/heartbeat.js.map +1 -1
  56. package/dist/mcp/tool-errors.d.ts +12 -1
  57. package/dist/mcp/tool-errors.d.ts.map +1 -1
  58. package/dist/mcp/tool-errors.js +29 -0
  59. package/dist/mcp/tool-errors.js.map +1 -1
  60. package/dist/mcp/tools/sync-conflicts.d.ts.map +1 -1
  61. package/dist/mcp/tools/sync-conflicts.js +46 -58
  62. package/dist/mcp/tools/sync-conflicts.js.map +1 -1
  63. package/dist/mcp/tools/sync-delete.d.ts.map +1 -1
  64. package/dist/mcp/tools/sync-delete.js +18 -30
  65. package/dist/mcp/tools/sync-delete.js.map +1 -1
  66. package/dist/mcp/tools/sync-diff.d.ts.map +1 -1
  67. package/dist/mcp/tools/sync-diff.js +10 -31
  68. package/dist/mcp/tools/sync-diff.js.map +1 -1
  69. package/dist/mcp/tools/sync-doctor.d.ts.map +1 -1
  70. package/dist/mcp/tools/sync-doctor.js +18 -30
  71. package/dist/mcp/tools/sync-doctor.js.map +1 -1
  72. package/dist/mcp/tools/sync-media-search.d.ts.map +1 -1
  73. package/dist/mcp/tools/sync-media-search.js +40 -52
  74. package/dist/mcp/tools/sync-media-search.js.map +1 -1
  75. package/dist/mcp/tools/sync-new.d.ts.map +1 -1
  76. package/dist/mcp/tools/sync-new.js +34 -55
  77. package/dist/mcp/tools/sync-new.js.map +1 -1
  78. package/dist/mcp/tools/sync-pull.d.ts.map +1 -1
  79. package/dist/mcp/tools/sync-pull.js +194 -220
  80. package/dist/mcp/tools/sync-pull.js.map +1 -1
  81. package/dist/mcp/tools/sync-push.d.ts.map +1 -1
  82. package/dist/mcp/tools/sync-push.js +64 -84
  83. package/dist/mcp/tools/sync-push.js.map +1 -1
  84. package/dist/mcp/tools/sync-status.d.ts.map +1 -1
  85. package/dist/mcp/tools/sync-status.js +3 -13
  86. package/dist/mcp/tools/sync-status.js.map +1 -1
  87. package/dist/sync/baseline-reconstruction.d.ts +43 -0
  88. package/dist/sync/baseline-reconstruction.d.ts.map +1 -0
  89. package/dist/sync/baseline-reconstruction.js +103 -0
  90. package/dist/sync/baseline-reconstruction.js.map +1 -0
  91. package/dist/sync/bylines.d.ts +5 -0
  92. package/dist/sync/bylines.d.ts.map +1 -1
  93. package/dist/sync/bylines.js +29 -0
  94. package/dist/sync/bylines.js.map +1 -1
  95. package/dist/sync/conflicts.d.ts.map +1 -1
  96. package/dist/sync/conflicts.js +21 -4
  97. package/dist/sync/conflicts.js.map +1 -1
  98. package/dist/sync/delete.d.ts.map +1 -1
  99. package/dist/sync/delete.js +12 -1
  100. package/dist/sync/delete.js.map +1 -1
  101. package/dist/sync/diff.d.ts.map +1 -1
  102. package/dist/sync/diff.js +58 -27
  103. package/dist/sync/diff.js.map +1 -1
  104. package/dist/sync/doctor.d.ts.map +1 -1
  105. package/dist/sync/doctor.js +13 -3
  106. package/dist/sync/doctor.js.map +1 -1
  107. package/dist/sync/guards.d.ts +1 -1
  108. package/dist/sync/guards.d.ts.map +1 -1
  109. package/dist/sync/guards.js +1 -0
  110. package/dist/sync/guards.js.map +1 -1
  111. package/dist/sync/media/companions.d.ts.map +1 -1
  112. package/dist/sync/media/companions.js.map +1 -1
  113. package/dist/sync/media/naming_mirror.d.ts.map +1 -1
  114. package/dist/sync/media/naming_mirror.js +11 -2
  115. package/dist/sync/media/naming_mirror.js.map +1 -1
  116. package/dist/sync/media/pull_article.d.ts +2 -0
  117. package/dist/sync/media/pull_article.d.ts.map +1 -1
  118. package/dist/sync/media/pull_article.js +74 -25
  119. package/dist/sync/media/pull_article.js.map +1 -1
  120. package/dist/sync/media/pull_library.d.ts.map +1 -1
  121. package/dist/sync/media/pull_library.js +34 -61
  122. package/dist/sync/media/pull_library.js.map +1 -1
  123. package/dist/sync/media/remote_index.d.ts +16 -1
  124. package/dist/sync/media/remote_index.d.ts.map +1 -1
  125. package/dist/sync/media/remote_index.js +2 -2
  126. package/dist/sync/media/remote_index.js.map +1 -1
  127. package/dist/sync/merge.d.ts.map +1 -1
  128. package/dist/sync/merge.js +5 -5
  129. package/dist/sync/merge.js.map +1 -1
  130. package/dist/sync/new.d.ts.map +1 -1
  131. package/dist/sync/new.js +5 -4
  132. package/dist/sync/new.js.map +1 -1
  133. package/dist/sync/orchestrator.d.ts +34 -0
  134. package/dist/sync/orchestrator.d.ts.map +1 -1
  135. package/dist/sync/orchestrator.js +89 -80
  136. package/dist/sync/orchestrator.js.map +1 -1
  137. package/dist/sync/preflight/image_probe.d.ts +28 -0
  138. package/dist/sync/preflight/image_probe.d.ts.map +1 -0
  139. package/dist/sync/preflight/image_probe.js +70 -0
  140. package/dist/sync/preflight/image_probe.js.map +1 -0
  141. package/dist/sync/preflight.d.ts.map +1 -1
  142. package/dist/sync/preflight.js +48 -45
  143. package/dist/sync/preflight.js.map +1 -1
  144. package/dist/sync/pull/fast_path.d.ts +9 -0
  145. package/dist/sync/pull/fast_path.d.ts.map +1 -0
  146. package/dist/sync/pull/fast_path.js +341 -0
  147. package/dist/sync/pull/fast_path.js.map +1 -0
  148. package/dist/sync/pull/index.d.ts +15 -0
  149. package/dist/sync/pull/index.d.ts.map +1 -0
  150. package/dist/sync/pull/index.js +363 -0
  151. package/dist/sync/pull/index.js.map +1 -0
  152. package/dist/sync/pull/list.d.ts +22 -0
  153. package/dist/sync/pull/list.d.ts.map +1 -0
  154. package/dist/sync/pull/list.js +175 -0
  155. package/dist/sync/pull/list.js.map +1 -0
  156. package/dist/sync/pull/media_stage.d.ts +67 -0
  157. package/dist/sync/pull/media_stage.d.ts.map +1 -0
  158. package/dist/sync/pull/media_stage.js +599 -0
  159. package/dist/sync/pull/media_stage.js.map +1 -0
  160. package/dist/sync/pull/quarantine.d.ts +22 -0
  161. package/dist/sync/pull/quarantine.d.ts.map +1 -0
  162. package/dist/sync/pull/quarantine.js +174 -0
  163. package/dist/sync/pull/quarantine.js.map +1 -0
  164. package/dist/sync/pull/types.d.ts +125 -0
  165. package/dist/sync/pull/types.d.ts.map +1 -0
  166. package/dist/sync/pull/types.js +23 -0
  167. package/dist/sync/pull/types.js.map +1 -0
  168. package/dist/sync/pull.d.ts +1 -114
  169. package/dist/sync/pull.d.ts.map +1 -1
  170. package/dist/sync/pull.js +1 -861
  171. package/dist/sync/pull.js.map +1 -1
  172. package/dist/sync/push/commit.d.ts.map +1 -1
  173. package/dist/sync/push/commit.js +1 -2
  174. package/dist/sync/push/commit.js.map +1 -1
  175. package/dist/sync/push/index.js +3 -3
  176. package/dist/sync/push/index.js.map +1 -1
  177. package/dist/sync/push/merge_stage.js +1 -1
  178. package/dist/sync/push/merge_stage.js.map +1 -1
  179. package/dist/sync/push/transport.d.ts +1 -1
  180. package/dist/sync/push/transport.d.ts.map +1 -1
  181. package/dist/sync/push/transport.js +1 -1
  182. package/dist/sync/push/transport.js.map +1 -1
  183. package/dist/sync/status.d.ts.map +1 -1
  184. package/dist/sync/status.js +11 -57
  185. package/dist/sync/status.js.map +1 -1
  186. package/dist/sync/taxonomies.d.ts +25 -0
  187. package/dist/sync/taxonomies.d.ts.map +1 -1
  188. package/dist/sync/taxonomies.js +161 -119
  189. package/dist/sync/taxonomies.js.map +1 -1
  190. package/dist/utils/frontmatter.d.ts.map +1 -1
  191. package/dist/utils/frontmatter.js.map +1 -1
  192. package/dist/utils/mcp-heartbeat.d.ts +36 -0
  193. package/dist/utils/mcp-heartbeat.d.ts.map +1 -0
  194. package/dist/utils/mcp-heartbeat.js +126 -0
  195. package/dist/utils/mcp-heartbeat.js.map +1 -0
  196. package/dist/utils/media-body-refs.d.ts.map +1 -1
  197. package/dist/utils/media-body-refs.js +2 -2
  198. package/dist/utils/media-body-refs.js.map +1 -1
  199. package/dist/utils/taxonomy-key.d.ts +25 -0
  200. package/dist/utils/taxonomy-key.d.ts.map +1 -0
  201. package/dist/utils/taxonomy-key.js +51 -0
  202. package/dist/utils/taxonomy-key.js.map +1 -0
  203. package/package.json +1 -1
@@ -0,0 +1,363 @@
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 { apiResponseToLocal } from '../../client/mapper.js';
25
+ import { ApiError } from '../../client/error.js';
26
+ import { createAuthedFetch } from '../../client/http.js';
27
+ import { extractRev, extractComparisonRev, isSameRev } from '../../client/api.js';
28
+ import { articleContentEndpoint } from '../../client/endpoints.js';
29
+ import { extractDatePrefixFromPath, serializeMarkdown, } from '../../utils/frontmatter.js';
30
+ import { hasUncommittedDraftRevision } from '../../utils/draft-revision.js';
31
+ import { localizeArticleMediaRefs, carriesDepthFreeMediaRef, shouldPreferLegacyRef, } from '../../utils/media-body-refs.js';
32
+ import { CONFLICTS_SUBDIR, calculateHash, commitArticleSnapshot, findLocalFilesByUlid, isQuarantinedRelativePath, quarantineLocalCopy, resolveCanonicalArticlePath, } from '../workspace/index.js';
33
+ import { loadLocalTaxonomyCandidates } from '../taxonomies.js';
34
+ import { syncRemoteBylines, extractRemoteBylineIds } from '../bylines.js';
35
+ import { updateConfigSyncedVersion } from '../../utils/config.js';
36
+ import { fetchAssignedTerms as fetchAssignedTermsShared, computeTaxonomyHash } from '../terms.js';
37
+ import { extractCanonicalRemoteTitle, getRemoteMaxBatchLimit, listRemoteArticles } from './list.js';
38
+ import { formatQuarantineNotice, handleRemoteDeletedArticle, quarantineDivergentLocalCopies, } from './quarantine.js';
39
+ import { tryFastPathOrHeal } from './fast_path.js';
40
+ import { mirrorArticleReferencedMedia, createMediaMirrorSession } from './media_stage.js';
41
+ export { CONFLICTS_SUBDIR, calculateHash, findLocalFilesByUlid, isQuarantinedRelativePath, quarantineLocalCopy, resolveCanonicalArticlePath, carriesDepthFreeMediaRef, shouldPreferLegacyRef, extractCanonicalRemoteTitle, getRemoteMaxBatchLimit, listRemoteArticles, formatQuarantineNotice, mirrorArticleReferencedMedia, createMediaMirrorSession, };
42
+ /**
43
+ * Pulls a content item from EmDash and updates local files and cache.
44
+ * Implements Differential Skip: if remote _rev matches cached rev and local file is untouched,
45
+ * skips disk write and AST conversion.
46
+ */
47
+ export async function pullArticle(collection, id, options) {
48
+ const fetchFn = createAuthedFetch(options);
49
+ let rawItem = options.rawItem;
50
+ // Helper to fetch assigned terms for a taxonomy ('category' | 'tag')
51
+ const fetchAssignedTerms = (taxonomy) => fetchAssignedTermsShared({
52
+ origin: options.origin,
53
+ token: options.token,
54
+ collection,
55
+ id,
56
+ taxonomy,
57
+ fetchFn,
58
+ });
59
+ // Helper to resolve byline ID-to-slug mapping
60
+ let bylineIdToSlug = options.bylineIdToSlug;
61
+ const getBylineIdToSlug = async () => {
62
+ if (bylineIdToSlug)
63
+ return bylineIdToSlug;
64
+ const cachedMaps = options.cache.getBylineMaps();
65
+ const remoteBylineIds = rawItem ? extractRemoteBylineIds(rawItem) : [];
66
+ const hasUnknownByline = Object.keys(cachedMaps.idToSlug).length === 0 ||
67
+ remoteBylineIds.some((ref) => !cachedMaps.idToSlug[ref] && !cachedMaps.slugToId[ref]);
68
+ if (!hasUnknownByline) {
69
+ bylineIdToSlug = cachedMaps.idToSlug;
70
+ return bylineIdToSlug;
71
+ }
72
+ const freshMaps = await syncRemoteBylines({
73
+ origin: options.origin,
74
+ token: options.token,
75
+ refreshToken: options.refreshToken,
76
+ cache: options.cache,
77
+ fetchFn: options.fetchFn,
78
+ }).catch(() => ({ slugToId: {}, idToSlug: {} }));
79
+ bylineIdToSlug = freshMaps.idToSlug;
80
+ return bylineIdToSlug;
81
+ };
82
+ // Helper to resolve taxonomy candidates for frontmatter inline comments
83
+ let candidates = options.candidates;
84
+ const getTaxonomyCandidates = () => {
85
+ if (candidates)
86
+ return candidates;
87
+ candidates = loadLocalTaxonomyCandidates(options.workspaceRoot);
88
+ return candidates;
89
+ };
90
+ /** The path a tracked article currently sits at, used when the caller has not resolved a new one yet. */
91
+ const existingFilePathForDepth = () => {
92
+ const tracked = options.cache.getSyncState(id)?.localFilePath;
93
+ if (tracked)
94
+ return tracked;
95
+ const onDisk = findLocalFilesByUlid(options.workspaceRoot, collection, id)[0];
96
+ return onDisk ?? `${collection}/draft/${id}.md`;
97
+ };
98
+ /**
99
+ * Applies the workspace's local-media-ref spelling to a serialized document. `sync_state.local_hash` always
100
+ * records the exact bytes on disk, so every comparison against a tracked file must run through this same
101
+ * transform: reconstructing the canonical form from a remote response and then localizing it keeps the
102
+ * fast-path skip honest whether or not `localMediaRefs` is enabled.
103
+ */
104
+ const localizeDiskMarkdown = (canonicalContent, articleRelPath, preferLegacyRef) => options.localMediaRefs
105
+ ? localizeArticleMediaRefs(canonicalContent, {
106
+ workspaceRoot: options.workspaceRoot,
107
+ articleRelPath: articleRelPath ?? existingFilePathForDepth(),
108
+ fs,
109
+ preferLegacyRef,
110
+ })
111
+ : canonicalContent;
112
+ const fastPathCtx = {
113
+ collection,
114
+ id,
115
+ options,
116
+ fetchAssignedTerms,
117
+ getBylineIdToSlug,
118
+ getTaxonomyCandidates,
119
+ localizeDiskMarkdown,
120
+ };
121
+ // 1. Fast-path check: If rawItem is provided in options, test fast-path / heal
122
+ if (rawItem) {
123
+ const fastResult = await tryFastPathOrHeal(fastPathCtx, rawItem);
124
+ if (fastResult) {
125
+ updateConfigSyncedVersion(options.workspaceRoot);
126
+ return fastResult;
127
+ }
128
+ // Fast-path missed: remote content changed or local repair required.
129
+ // EmDash list API returns stale creation-time posts.data for drafts, and liveData for published articles.
130
+ // When a published article has unpublished draft changes (draftRevisionId exists), list API does NOT expand
131
+ // the draft body (it returns only liveData).
132
+ // Therefore, if this is an existing tracked article whose remote draft revision has advanced, we must discard
133
+ // the stale list rawItem so Step 2 fetches the full canonical item via single GET!
134
+ const rawObj = rawItem;
135
+ const hasDraftRevision = Boolean(rawObj.draftRevisionId);
136
+ const isDraft = String(rawObj.status || 'draft') !== 'published';
137
+ const needsFullDraftFetch = isDraft || hasDraftRevision;
138
+ const existingSync = options.cache.getSyncState(id);
139
+ const rawRevCandidate = String(rawItem._rev || rawItem.rev || rawItem.version || rawObj._rev || '');
140
+ const remoteRev = extractRev(rawObj, rawRevCandidate);
141
+ const remoteComparisonRev = extractComparisonRev(rawObj, remoteRev);
142
+ const remoteChanged = !existingSync || !isSameRev(existingSync.remoteRev, remoteComparisonRev);
143
+ if (needsFullDraftFetch && existingSync && remoteChanged) {
144
+ rawItem = undefined;
145
+ }
146
+ }
147
+ // 2. Fetch raw item if not passed in options (or discarded above for draft updates)
148
+ if (!rawItem) {
149
+ const url = articleContentEndpoint(options.origin, collection, id);
150
+ const res = await fetchFn(url, {
151
+ method: 'GET',
152
+ headers: {
153
+ Authorization: `Bearer ${options.token}`,
154
+ Accept: 'application/json',
155
+ },
156
+ });
157
+ if (!res.ok) {
158
+ if (res.status === 404 || res.status === 410) {
159
+ const deletedResult = handleRemoteDeletedArticle(collection, id, options, getTaxonomyCandidates());
160
+ if (deletedResult)
161
+ return deletedResult;
162
+ }
163
+ throw new ApiError({
164
+ message: `Failed to pull article ${collection}/${id}: ${res.statusText}`,
165
+ code: 'ARTICLE_PULL_FAILED',
166
+ status: res.status,
167
+ endpoint: url,
168
+ suggestion: `Verify that article '${id}' exists in collection '${collection}'.`,
169
+ });
170
+ }
171
+ rawItem = (await res.json());
172
+ // Step 2b (D5): Test fast-path / non-destructive heal for single-article pull as well!
173
+ const singleHealResult = await tryFastPathOrHeal(fastPathCtx, rawItem);
174
+ if (singleHealResult) {
175
+ updateConfigSyncedVersion(options.workspaceRoot);
176
+ return singleHealResult;
177
+ }
178
+ }
179
+ // Ensure byline ID-to-slug mapping is loaded
180
+ const resolvedBylineMap = await getBylineIdToSlug();
181
+ const effectiveOptions = {
182
+ ...options,
183
+ bylineIdToSlug: resolvedBylineMap,
184
+ };
185
+ const { frontmatter, body, rev } = apiResponseToLocal(rawItem, effectiveOptions);
186
+ const [categoriesTerms, tagsTerms] = await Promise.all([
187
+ fetchAssignedTerms('category'),
188
+ fetchAssignedTerms('tag'),
189
+ ]);
190
+ if (categoriesTerms !== null || tagsTerms !== null) {
191
+ if (!frontmatter.taxonomies) {
192
+ frontmatter.taxonomies = {};
193
+ }
194
+ if (categoriesTerms !== null) {
195
+ frontmatter.taxonomies.categories = categoriesTerms;
196
+ }
197
+ if (tagsTerms !== null) {
198
+ frontmatter.taxonomies.tags = tagsTerms;
199
+ }
200
+ }
201
+ // Format full Markdown. `canonicalMarkdown` is the remote form and is what every cache hash and every
202
+ // base snapshot records; `markdownContent` is what lands on disk, which may spell mirrored images as local
203
+ // references when `localMediaRefs` is enabled.
204
+ const comparisonRev = extractComparisonRev(rawItem, rev);
205
+ const hasDraft = hasUncommittedDraftRevision({
206
+ status: frontmatter.status,
207
+ remoteRev: comparisonRev,
208
+ });
209
+ const canonicalMarkdown = serializeMarkdown(frontmatter, body, getTaxonomyCandidates(), {
210
+ hasDraftRevision: hasDraft,
211
+ });
212
+ // Determine standard relative file path: <collection>/<status>/<yyyyMMdd>_<ulid>-<title>.md
213
+ const existingSync = options.cache.getSyncState(frontmatter.id);
214
+ const existingDiskMatches = findLocalFilesByUlid(options.workspaceRoot, frontmatter.collection, frontmatter.id);
215
+ const preferredDiskMatch = existingDiskMatches.find((p) => p.startsWith(`${frontmatter.collection}/${frontmatter.status}/`)) ?? existingDiskMatches[0];
216
+ const existingPrefix = existingSync?.localFilePath
217
+ ? extractDatePrefixFromPath(existingSync.localFilePath)
218
+ : preferredDiskMatch
219
+ ? extractDatePrefixFromPath(preferredDiskMatch)
220
+ : null;
221
+ const canonicalTitle = rawItem
222
+ ? extractCanonicalRemoteTitle(rawItem, frontmatter.slug)
223
+ : frontmatter.title || frontmatter.slug;
224
+ const relPath = resolveCanonicalArticlePath(frontmatter.collection, frontmatter.status, frontmatter.id, canonicalTitle, {
225
+ publishedAt: frontmatter.publishedAt || rawItem?.publishedAt || null,
226
+ createdAt: rawItem?.createdAt || null,
227
+ updatedAt: rawItem?.updatedAt || null,
228
+ }, existingPrefix);
229
+ let mediaSummary = undefined;
230
+ if (options.mediaSync !== false) {
231
+ mediaSummary = await mirrorArticleReferencedMedia(options, canonicalMarkdown, frontmatter.featuredImage);
232
+ }
233
+ const markdownContent = localizeDiskMarkdown(canonicalMarkdown, relPath, shouldPreferLegacyRef(options.workspaceRoot, existingDiskMatches));
234
+ const fullFilePath = path.join(options.workspaceRoot, relPath);
235
+ // Path tracking: Remove any previous file(s) for this ULID at a different path
236
+ // BEFORE writing fullFilePath so case-insensitive filesystems (e.g. macOS APFS)
237
+ // do not unlink the newly written file when only casing differs.
238
+ const staleRelPaths = new Set(existingDiskMatches);
239
+ if (existingSync?.localFilePath) {
240
+ staleRelPaths.add(existingSync.localFilePath);
241
+ }
242
+ const canonicalResolved = path.resolve(fullFilePath);
243
+ // Data safety: preserve every local copy whose content diverges from the last synced
244
+ // baseline (or has no cache baseline at all) before it is overwritten or unlinked.
245
+ const quarantined = quarantineDivergentLocalCopies(options, frontmatter.collection, staleRelPaths, existingSync?.localHash, markdownContent, existingSync?.conflictCopyHash, existingSync, getTaxonomyCandidates());
246
+ for (const staleRel of staleRelPaths) {
247
+ const staleFull = path.resolve(options.workspaceRoot, staleRel);
248
+ if (staleFull !== canonicalResolved && fs.existsSync(staleFull)) {
249
+ try {
250
+ fs.unlinkSync(staleFull);
251
+ }
252
+ catch {
253
+ // Ignore removal failure
254
+ }
255
+ }
256
+ }
257
+ // Update sync state with explicit conflict pending preservation
258
+ let conflictInfo = {};
259
+ const divergedQuarantines = !options.force
260
+ ? (quarantined ?? []).filter((q) => q.reason === 'diverged-from-baseline')
261
+ : [];
262
+ const divergedQuarantine = divergedQuarantines[divergedQuarantines.length - 1];
263
+ if (divergedQuarantine) {
264
+ const qFull = path.join(options.workspaceRoot, divergedQuarantine.quarantineFilePath);
265
+ let qHash = null;
266
+ if (fs.existsSync(qFull)) {
267
+ qHash = calculateHash(fs.readFileSync(qFull, 'utf8'));
268
+ }
269
+ conflictInfo = {
270
+ conflictPending: 1,
271
+ bodyConflictPending: 1,
272
+ taxonomyConflictPending: existingSync?.taxonomyConflictPending ?? 0,
273
+ conflictCopyPath: divergedQuarantine.quarantineFilePath,
274
+ conflictCopyHash: qHash,
275
+ conflictAt: Math.floor(Date.now() / 1000),
276
+ };
277
+ }
278
+ else if (!options.force && existingSync?.conflictCopyPath) {
279
+ const existingFull = path.join(options.workspaceRoot, existingSync.conflictCopyPath);
280
+ if (fs.existsSync(existingFull)) {
281
+ conflictInfo = {
282
+ conflictPending: existingSync.conflictPending,
283
+ bodyConflictPending: existingSync.bodyConflictPending,
284
+ taxonomyConflictPending: existingSync.taxonomyConflictPending,
285
+ conflictCopyPath: existingSync.conflictCopyPath,
286
+ conflictCopyHash: existingSync.conflictCopyHash,
287
+ conflictAt: existingSync.conflictAt,
288
+ };
289
+ }
290
+ else {
291
+ const taxPending = existingSync.taxonomyConflictPending ?? 0;
292
+ conflictInfo = {
293
+ conflictPending: taxPending,
294
+ bodyConflictPending: 0,
295
+ taxonomyConflictPending: taxPending,
296
+ conflictCopyPath: null,
297
+ conflictCopyHash: null,
298
+ conflictAt: null,
299
+ };
300
+ }
301
+ }
302
+ else if (options.force) {
303
+ conflictInfo = {
304
+ conflictPending: 0,
305
+ bodyConflictPending: 0,
306
+ taxonomyConflictPending: 0,
307
+ conflictCopyPath: null,
308
+ conflictCopyHash: null,
309
+ conflictAt: null,
310
+ };
311
+ }
312
+ else {
313
+ const taxPending = existingSync?.taxonomyConflictPending ?? 0;
314
+ conflictInfo = {
315
+ conflictPending: taxPending,
316
+ bodyConflictPending: 0,
317
+ taxonomyConflictPending: taxPending,
318
+ conflictCopyPath: null,
319
+ conflictCopyHash: null,
320
+ conflictAt: null,
321
+ };
322
+ }
323
+ // Commit canonical Markdown and sync state via commitArticleSnapshot
324
+ commitArticleSnapshot(options.cache, options.workspaceRoot, {
325
+ id: frontmatter.id,
326
+ relPath,
327
+ diskContent: markdownContent,
328
+ canonicalContent: canonicalMarkdown,
329
+ frontmatter,
330
+ bodyMarkdown: body,
331
+ revForTransport: rev,
332
+ revForComparison: comparisonRev,
333
+ flags: {
334
+ remoteTaxonomyHash: computeTaxonomyHash(frontmatter.taxonomies?.categories, frontmatter.taxonomies?.tags),
335
+ taxonomyApplyPending: 0,
336
+ ...conflictInfo,
337
+ },
338
+ });
339
+ // Update entries cache
340
+ options.cache.saveEntry({
341
+ id: frontmatter.id,
342
+ collection: frontmatter.collection,
343
+ slug: frontmatter.slug,
344
+ status: frontmatter.status,
345
+ title: frontmatter.title,
346
+ rev,
347
+ publishedAt: frontmatter.publishedAt,
348
+ rawJson: JSON.stringify(rawItem),
349
+ updatedAt: Math.floor(Date.now() / 1000),
350
+ });
351
+ updateConfigSyncedVersion(options.workspaceRoot);
352
+ return {
353
+ id: frontmatter.id,
354
+ slug: frontmatter.slug,
355
+ status: frontmatter.status,
356
+ filePath: relPath,
357
+ updated: true,
358
+ title: frontmatter.title,
359
+ quarantined: quarantined.length > 0 ? quarantined : undefined,
360
+ media: mediaSummary,
361
+ };
362
+ }
363
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sync/pull/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EACL,yBAAyB,EACzB,iBAAiB,GAElB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,kBAAkB,IAAI,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClG,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpG,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,4BAA4B,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAY1F,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,2BAA2B,EAC3B,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,4BAA4B,EAC5B,wBAAwB,GACzB,CAAC;AAaF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAAkB,EAClB,EAAU,EACV,OAAoB;IAEpB,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAE9B,qEAAqE;IACrE,MAAM,kBAAkB,GAAG,CAAC,QAA4B,EAA4B,EAAE,CACpF,wBAAwB,CAAC;QACvB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,UAAU;QACV,EAAE;QACF,QAAQ;QACR,OAAO;KACR,CAAC,CAAC;IAEL,8CAA8C;IAC9C,IAAI,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IAC5C,MAAM,iBAAiB,GAAG,KAAK,IAAqC,EAAE;QACpE,IAAI,cAAc;YAAE,OAAO,cAAc,CAAC;QAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QACjD,MAAM,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,gBAAgB,GACpB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC;YAC7C,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QACxF,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC;YACrC,OAAO,cAAc,CAAC;QACxB,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC;YACxC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QACjD,cAAc,GAAG,SAAS,CAAC,QAAQ,CAAC;QACpC,OAAO,cAAc,CAAC;IACxB,CAAC,CAAC;IAEF,wEAAwE;IACxE,IAAI,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACpC,MAAM,qBAAqB,GAAG,GAAmC,EAAE;QACjE,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC;QAClC,UAAU,GAAG,2BAA2B,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAChE,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;IAEF,yGAAyG;IACzG,MAAM,wBAAwB,GAAG,GAAW,EAAE;QAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC;QAC9D,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAC5B,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9E,OAAO,MAAM,IAAI,GAAG,UAAU,UAAU,EAAE,KAAK,CAAC;IAClD,CAAC,CAAC;IAEF;;;;;OAKG;IACH,MAAM,oBAAoB,GAAG,CAC3B,gBAAwB,EACxB,cAAuB,EACvB,eAAyB,EACjB,EAAE,CACV,OAAO,CAAC,cAAc;QACpB,CAAC,CAAC,wBAAwB,CAAC,gBAAgB,EAAE;YACzC,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,cAAc,EAAE,cAAc,IAAI,wBAAwB,EAAE;YAC5D,EAAE;YACF,eAAe;SAChB,CAAC;QACJ,CAAC,CAAC,gBAAgB,CAAC;IAEvB,MAAM,WAAW,GAAoB;QACnC,UAAU;QACV,EAAE;QACF,OAAO;QACP,kBAAkB;QAClB,iBAAiB;QACjB,qBAAqB;QACrB,oBAAoB;KACrB,CAAC;IAEF,+EAA+E;IAC/E,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACjE,IAAI,UAAU,EAAE,CAAC;YACf,yBAAyB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACjD,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,qEAAqE;QACrE,0GAA0G;QAC1G,4GAA4G;QAC5G,6CAA6C;QAC7C,8GAA8G;QAC9G,mFAAmF;QACnF,MAAM,MAAM,GAAG,OAAkC,CAAC;QAClD,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,WAAW,CAAC;QACjE,MAAM,mBAAmB,GAAG,OAAO,IAAI,gBAAgB,CAAC;QAExD,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,eAAe,GAAG,MAAM,CAC5B,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,CACpE,CAAC;QACF,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QACtD,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACpE,MAAM,aAAa,GAAG,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;QAE/F,IAAI,mBAAmB,IAAI,YAAY,IAAI,aAAa,EAAE,CAAC;YACzD,OAAO,GAAG,SAAS,CAAC;QACtB,CAAC;IACH,CAAC;IAED,oFAAoF;IACpF,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,sBAAsB,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE;YAC7B,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;gBACxC,MAAM,EAAE,kBAAkB;aAC3B;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC7C,MAAM,aAAa,GAAG,0BAA0B,CAC9C,UAAU,EACV,EAAE,EACF,OAAO,EACP,qBAAqB,EAAE,CACxB,CAAC;gBACF,IAAI,aAAa;oBAAE,OAAO,aAAa,CAAC;YAC1C,CAAC;YAED,MAAM,IAAI,QAAQ,CAAC;gBACjB,OAAO,EAAE,0BAA0B,UAAU,IAAI,EAAE,KAAK,GAAG,CAAC,UAAU,EAAE;gBACxE,IAAI,EAAE,qBAAqB;gBAC3B,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,QAAQ,EAAE,GAAG;gBACb,UAAU,EAAE,wBAAwB,EAAE,2BAA2B,UAAU,IAAI;aAChF,CAAC,CAAC;QACL,CAAC;QAED,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;QAExD,uFAAuF;QACvF,MAAM,gBAAgB,GAAG,MAAM,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACvE,IAAI,gBAAgB,EAAE,CAAC;YACrB,yBAAyB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACjD,OAAO,gBAAgB,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,MAAM,iBAAiB,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACpD,MAAM,gBAAgB,GAAgB;QACpC,GAAG,OAAO;QACV,cAAc,EAAE,iBAAiB;KAClC,CAAC;IAEF,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAEjF,MAAM,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACrD,kBAAkB,CAAC,UAAU,CAAC;QAC9B,kBAAkB,CAAC,KAAK,CAAC;KAC1B,CAAC,CAAC;IAEH,IAAI,eAAe,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACnD,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC;YAC5B,WAAW,CAAC,UAAU,GAAG,EAAE,CAAC;QAC9B,CAAC;QACD,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;YAC7B,WAAW,CAAC,UAAU,CAAC,UAAU,GAAG,eAAe,CAAC;QACtD,CAAC;QACD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,WAAW,CAAC,UAAU,CAAC,IAAI,GAAG,SAAS,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,sGAAsG;IACtG,2GAA2G;IAC3G,+CAA+C;IAC/C,MAAM,aAAa,GAAG,oBAAoB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,2BAA2B,CAAC;QAC3C,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,SAAS,EAAE,aAAa;KACzB,CAAC,CAAC;IACH,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,WAAW,EAAE,IAAI,EAAE,qBAAqB,EAAE,EAAE;QACtF,gBAAgB,EAAE,QAAQ;KAC3B,CAAC,CAAC;IAEH,4FAA4F;IAC5F,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAChE,MAAM,mBAAmB,GAAG,oBAAoB,CAC9C,OAAO,CAAC,aAAa,EACrB,WAAW,CAAC,UAAU,EACtB,WAAW,CAAC,EAAE,CACf,CAAC;IACF,MAAM,kBAAkB,GACtB,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC7B,CAAC,CAAC,UAAU,CAAC,GAAG,WAAW,CAAC,UAAU,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,CACjE,IAAI,mBAAmB,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,cAAc,GAAG,YAAY,EAAE,aAAa;QAChD,CAAC,CAAC,yBAAyB,CAAC,YAAY,CAAC,aAAa,CAAC;QACvD,CAAC,CAAC,kBAAkB;YAClB,CAAC,CAAC,yBAAyB,CAAC,kBAAkB,CAAC;YAC/C,CAAC,CAAC,IAAI,CAAC;IAEX,MAAM,cAAc,GAAG,OAAO;QAC5B,CAAC,CAAC,2BAA2B,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC;QACxD,CAAC,CAAC,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,IAAI,CAAC;IAE1C,MAAM,OAAO,GAAG,2BAA2B,CACzC,WAAW,CAAC,UAAU,EACtB,WAAW,CAAC,MAAM,EAClB,WAAW,CAAC,EAAE,EACd,cAAc,EACd;QACE,WAAW,EAAG,WAAW,CAAC,WAAsB,IAAK,OAAO,EAAE,WAAsB,IAAI,IAAI;QAC5F,SAAS,EAAG,OAAO,EAAE,SAAoB,IAAI,IAAI;QACjD,SAAS,EAAG,OAAO,EAAE,SAAoB,IAAI,IAAI;KAClD,EACD,cAAc,CACf,CAAC;IAEF,IAAI,YAAY,GAAwC,SAAS,CAAC;IAClE,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;QAChC,YAAY,GAAG,MAAM,4BAA4B,CAC/C,OAAO,EACP,iBAAiB,EACjB,WAAW,CAAC,aAAa,CAC1B,CAAC;IACJ,CAAC;IAED,MAAM,eAAe,GAAG,oBAAoB,CAC1C,iBAAiB,EACjB,OAAO,EACP,qBAAqB,CAAC,OAAO,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAClE,CAAC;IAEF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAE/D,+EAA+E;IAC/E,gFAAgF;IAChF,iEAAiE;IACjE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAS,mBAAmB,CAAC,CAAC;IAC3D,IAAI,YAAY,EAAE,aAAa,EAAE,CAAC;QAChC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAErD,qFAAqF;IACrF,mFAAmF;IACnF,MAAM,WAAW,GAAG,8BAA8B,CAChD,OAAO,EACP,WAAW,CAAC,UAAU,EACtB,aAAa,EACb,YAAY,EAAE,SAAS,EACvB,eAAe,EACf,YAAY,EAAE,gBAAgB,EAC9B,YAAY,EACZ,qBAAqB,EAAE,CACxB,CAAC;IAEF,KAAK,MAAM,QAAQ,IAAI,aAAa,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAChE,IAAI,SAAS,KAAK,iBAAiB,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAChE,IAAI,CAAC;gBACH,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,yBAAyB;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,IAAI,YAAY,GAAuB,EAAE,CAAC;IAC1C,MAAM,mBAAmB,GAAG,CAAC,OAAO,CAAC,KAAK;QACxC,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,wBAAwB,CAAC;QAC1E,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,kBAAkB,GAAG,mBAAmB,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE/E,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;QACtF,IAAI,KAAK,GAAkB,IAAI,CAAC;QAChC,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,GAAG,aAAa,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,YAAY,GAAG;YACb,eAAe,EAAE,CAAC;YAClB,mBAAmB,EAAE,CAAC;YACtB,uBAAuB,EAAE,YAAY,EAAE,uBAAuB,IAAI,CAAC;YACnE,gBAAgB,EAAE,kBAAkB,CAAC,kBAAkB;YACvD,gBAAgB,EAAE,KAAK;YACvB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;SAC1C,CAAC;IACJ,CAAC;SAAM,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,YAAY,EAAE,gBAAgB,EAAE,CAAC;QAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;QACrF,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAChC,YAAY,GAAG;gBACb,eAAe,EAAE,YAAY,CAAC,eAAe;gBAC7C,mBAAmB,EAAE,YAAY,CAAC,mBAAmB;gBACrD,uBAAuB,EAAE,YAAY,CAAC,uBAAuB;gBAC7D,gBAAgB,EAAE,YAAY,CAAC,gBAAgB;gBAC/C,gBAAgB,EAAE,YAAY,CAAC,gBAAgB;gBAC/C,UAAU,EAAE,YAAY,CAAC,UAAU;aACpC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,UAAU,GAAG,YAAY,CAAC,uBAAuB,IAAI,CAAC,CAAC;YAC7D,YAAY,GAAG;gBACb,eAAe,EAAE,UAAU;gBAC3B,mBAAmB,EAAE,CAAC;gBACtB,uBAAuB,EAAE,UAAU;gBACnC,gBAAgB,EAAE,IAAI;gBACtB,gBAAgB,EAAE,IAAI;gBACtB,UAAU,EAAE,IAAI;aACjB,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACzB,YAAY,GAAG;YACb,eAAe,EAAE,CAAC;YAClB,mBAAmB,EAAE,CAAC;YACtB,uBAAuB,EAAE,CAAC;YAC1B,gBAAgB,EAAE,IAAI;YACtB,gBAAgB,EAAE,IAAI;YACtB,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,UAAU,GAAG,YAAY,EAAE,uBAAuB,IAAI,CAAC,CAAC;QAC9D,YAAY,GAAG;YACb,eAAe,EAAE,UAAU;YAC3B,mBAAmB,EAAE,CAAC;YACtB,uBAAuB,EAAE,UAAU;YACnC,gBAAgB,EAAE,IAAI;YACtB,gBAAgB,EAAE,IAAI;YACtB,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,qBAAqB,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE;QAC1D,EAAE,EAAE,WAAW,CAAC,EAAE;QAClB,OAAO;QACP,WAAW,EAAE,eAAe;QAC5B,gBAAgB,EAAE,iBAAiB;QACnC,WAAW;QACX,YAAY,EAAE,IAAI;QAClB,eAAe,EAAE,GAAG;QACpB,gBAAgB,EAAE,aAAa;QAC/B,KAAK,EAAE;YACL,kBAAkB,EAAE,mBAAmB,CACrC,WAAW,CAAC,UAAU,EAAE,UAAU,EAClC,WAAW,CAAC,UAAU,EAAE,IAAI,CAC7B;YACD,oBAAoB,EAAE,CAAC;YACvB,GAAG,YAAY;SAChB;KACF,CAAC,CAAC;IAEH,uBAAuB;IACvB,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QACtB,EAAE,EAAE,WAAW,CAAC,EAAE;QAClB,UAAU,EAAE,WAAW,CAAC,UAAU;QAClC,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,GAAG;QACH,WAAW,EAAE,WAAW,CAAC,WAAW;QACpC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QAChC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;KACzC,CAAC,CAAC;IAEH,yBAAyB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAEjD,OAAO;QACL,EAAE,EAAE,WAAW,CAAC,EAAE;QAClB,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,WAAW,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;QAC7D,KAAK,EAAE,YAAY;KACpB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { ListRemoteArticlesOptions, RemoteArticleItem } from './types.js';
2
+ /**
3
+ * Resolves the canonical article title from remote data symmetrically across
4
+ * fast-path and full-pull (EMIT-005 / v0.1.14 backlog §1).
5
+ */
6
+ export declare function extractCanonicalRemoteTitle(rawObj: Record<string, unknown>, fallbackSlug?: string): string;
7
+ /**
8
+ * Discovers the server's maximum allowed limit for content list queries from /_emdash/api/openapi.json.
9
+ * Defaults to 100 if openapi.json cannot be fetched or parsed.
10
+ */
11
+ export declare function getRemoteMaxBatchLimit(options: {
12
+ origin: string;
13
+ token?: string;
14
+ fetchFn?: typeof fetch;
15
+ }): Promise<number>;
16
+ /**
17
+ * Lists articles from EmDash API with cursor pagination and dynamic batch size detection.
18
+ * When status is not specified or 'all', fetches up to `limit` published articles AND
19
+ * up to `limit` draft articles in parallel, ensuring drafts and published posts are both covered.
20
+ */
21
+ export declare function listRemoteArticles(collection: string, options: ListRemoteArticlesOptions): Promise<RemoteArticleItem[]>;
22
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/sync/pull/list.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/E;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAQR;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BlB;AAyGD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAe9B"}
@@ -0,0 +1,175 @@
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 { ApiError } from '../../client/error.js';
23
+ import { createAuthedFetch } from '../../client/http.js';
24
+ import { unwrapEnvelope, unwrapItem, extractRev } from '../../client/api.js';
25
+ import { articleContentEndpoint, openApiEndpoint } from '../../client/endpoints.js';
26
+ /**
27
+ * Resolves the canonical article title from remote data symmetrically across
28
+ * fast-path and full-pull (EMIT-005 / v0.1.14 backlog §1).
29
+ */
30
+ export function extractCanonicalRemoteTitle(rawObj, fallbackSlug) {
31
+ const item = unwrapItem(rawObj);
32
+ const data = (item.data || {}) || {};
33
+ const rawTitle = String(data.title || item.title || '').trim();
34
+ if (rawTitle)
35
+ return rawTitle;
36
+ const rawSlug = String(item.slug || fallbackSlug || '').trim();
37
+ if (rawSlug)
38
+ return rawSlug;
39
+ return 'Untitled';
40
+ }
41
+ /**
42
+ * Discovers the server's maximum allowed limit for content list queries from /_emdash/api/openapi.json.
43
+ * Defaults to 100 if openapi.json cannot be fetched or parsed.
44
+ */
45
+ export async function getRemoteMaxBatchLimit(options) {
46
+ const fetchFn = options.fetchFn || fetch;
47
+ try {
48
+ const url = openApiEndpoint(options.origin);
49
+ const headers = { Accept: 'application/json' };
50
+ if (options.token) {
51
+ headers.Authorization = `Bearer ${options.token}`;
52
+ }
53
+ const res = await fetchFn(url, { headers });
54
+ if (!res.ok)
55
+ return 100;
56
+ const json = (await res.json());
57
+ const paths = (json.paths || {});
58
+ const getEndpoint = paths['/_emdash/api/content/{collection}']?.get || paths['/content/{collection}']?.get;
59
+ if (getEndpoint && Array.isArray(getEndpoint.parameters)) {
60
+ const params = getEndpoint.parameters;
61
+ const limitParam = params.find((p) => p.name === 'limit');
62
+ const schema = (limitParam?.schema || {});
63
+ if (typeof schema.maximum === 'number' && schema.maximum > 0) {
64
+ return schema.maximum;
65
+ }
66
+ }
67
+ }
68
+ catch {
69
+ // Ignore network or parse error, fallback to safe 100
70
+ }
71
+ return 100;
72
+ }
73
+ /**
74
+ * Fetches articles for a specific status ('draft' or 'published') using cursor pagination.
75
+ */
76
+ async function fetchStatusArticles(collection, status, options, serverMaxLimit) {
77
+ const fetchFn = createAuthedFetch(options);
78
+ const targetTotal = options.all ? Infinity : (options.limit ?? 100);
79
+ const items = [];
80
+ let cursor = undefined;
81
+ let batchLimit = serverMaxLimit;
82
+ while (items.length < targetTotal) {
83
+ const remaining = targetTotal - items.length;
84
+ const currentBatch = Math.min(remaining, batchLimit);
85
+ const url = new URL(articleContentEndpoint(options.origin, collection));
86
+ url.searchParams.set('status', status);
87
+ url.searchParams.set('limit', String(currentBatch));
88
+ if (cursor) {
89
+ url.searchParams.set('cursor', cursor);
90
+ }
91
+ let res = await fetchFn(url.toString(), {
92
+ method: 'GET',
93
+ headers: {
94
+ Authorization: `Bearer ${options.token}`,
95
+ Accept: 'application/json',
96
+ },
97
+ });
98
+ // Adaptive fallback if server responds with validation error on limit
99
+ if (!res.ok && res.status === 400) {
100
+ try {
101
+ const errJson = (await res.clone().json());
102
+ const errMsg = JSON.stringify(errJson);
103
+ const match = errMsg.match(/expected number to be <=(\d+)/);
104
+ if (match && Number(match[1]) < batchLimit) {
105
+ batchLimit = Number(match[1]);
106
+ url.searchParams.set('limit', String(Math.min(remaining, batchLimit)));
107
+ res = await fetchFn(url.toString(), {
108
+ method: 'GET',
109
+ headers: {
110
+ Authorization: `Bearer ${options.token}`,
111
+ Accept: 'application/json',
112
+ },
113
+ });
114
+ }
115
+ }
116
+ catch {
117
+ // Continue to normal error handling below
118
+ }
119
+ }
120
+ if (!res.ok) {
121
+ throw new ApiError({
122
+ message: `Failed to list remote articles (${status}): ${res.statusText}`,
123
+ code: 'ARTICLE_LIST_FAILED',
124
+ status: res.status,
125
+ endpoint: url.toString(),
126
+ suggestion: 'Verify network connection, permissions, or try lowering the limit.',
127
+ });
128
+ }
129
+ const json = await res.json();
130
+ const data = unwrapEnvelope(json);
131
+ const rawItems = (Array.isArray(data.items) ? data.items : Array.isArray(data) ? data : []);
132
+ if (rawItems.length === 0) {
133
+ break;
134
+ }
135
+ for (const raw of rawItems) {
136
+ const rawData = (raw.data || {});
137
+ const rev = extractRev(raw, '1');
138
+ items.push({
139
+ id: String(raw.id),
140
+ slug: String(raw.slug || ''),
141
+ status: String(raw.status || status),
142
+ title: String(rawData.title || raw.title || 'Untitled'),
143
+ _rev: rev,
144
+ rawItem: raw,
145
+ });
146
+ if (items.length >= targetTotal) {
147
+ break;
148
+ }
149
+ }
150
+ if (!data.nextCursor || typeof data.nextCursor !== 'string') {
151
+ break;
152
+ }
153
+ cursor = data.nextCursor;
154
+ }
155
+ return items;
156
+ }
157
+ /**
158
+ * Lists articles from EmDash API with cursor pagination and dynamic batch size detection.
159
+ * When status is not specified or 'all', fetches up to `limit` published articles AND
160
+ * up to `limit` draft articles in parallel, ensuring drafts and published posts are both covered.
161
+ */
162
+ export async function listRemoteArticles(collection, options) {
163
+ const serverMaxLimit = options.batchSize || (await getRemoteMaxBatchLimit(options));
164
+ // If a specific status is explicitly requested
165
+ if (options.status === 'draft' || options.status === 'published') {
166
+ return fetchStatusArticles(collection, options.status, options, serverMaxLimit);
167
+ }
168
+ // Default: Fetch both published (up to limit) and draft (up to limit) in parallel
169
+ const [draftItems, publishedItems] = await Promise.all([
170
+ fetchStatusArticles(collection, 'draft', options, serverMaxLimit),
171
+ fetchStatusArticles(collection, 'published', options, serverMaxLimit),
172
+ ]);
173
+ return [...draftItems, ...publishedItems];
174
+ }
175
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/sync/pull/list.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGpF;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CACzC,MAA+B,EAC/B,YAAqB;IAErB,MAAM,IAAI,GAAG,UAAU,CAA0B,MAAM,CAAC,CAAC;IACzD,MAAM,IAAI,GAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAA6B,IAAI,EAAE,CAAC;IAClE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAI5C;IACC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,OAAO,GAA2B,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;QACvE,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,CAAC,aAAa,GAAG,UAAU,OAAO,CAAC,KAAK,EAAE,CAAC;QACpD,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,GAAG,CAAC;QAExB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;QAC3D,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAA4C,CAAC;QAC5E,MAAM,WAAW,GACf,KAAK,CAAC,mCAAmC,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC,uBAAuB,CAAC,EAAE,GAAG,CAAC;QAEzF,IAAI,WAAW,IAAI,KAAK,CAAC,OAAO,CAAE,WAAuC,CAAC,UAAU,CAAC,EAAE,CAAC;YACtF,MAAM,MAAM,GAAI,WAAuC,CAAC,UAEvD,CAAC;YACF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;YAC1D,MAAM,MAAM,GAAG,CAAC,UAAU,EAAE,MAAM,IAAI,EAAE,CAA4B,CAAC;YACrE,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;gBAC7D,OAAO,MAAM,CAAC,OAAO,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;IACxD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,mBAAmB,CAChC,UAAkB,EAClB,MAA6B,EAC7B,OAAkC,EAClC,cAAsB;IAEtB,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC;IAEpE,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,IAAI,MAAM,GAAuB,SAAS,CAAC;IAC3C,IAAI,UAAU,GAAG,cAAc,CAAC;IAEhC,OAAO,KAAK,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC;QAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAErD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,sBAAsB,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QACxE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACvC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QACpD,IAAI,MAAM,EAAE,CAAC;YACX,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QAED,IAAI,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACtC,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;gBACxC,MAAM,EAAE,kBAAkB;aAC3B;SACF,CAAC,CAAC;QAEH,sEAAsE;QACtE,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAA4B,CAAC;gBACtE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBACvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBAC5D,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,EAAE,CAAC;oBAC3C,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC9B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;oBACvE,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;wBAClC,MAAM,EAAE,KAAK;wBACb,OAAO,EAAE;4BACP,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;4BACxC,MAAM,EAAE,kBAAkB;yBAC3B;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,0CAA0C;YAC5C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,QAAQ,CAAC;gBACjB,OAAO,EAAE,mCAAmC,MAAM,MAAM,GAAG,CAAC,UAAU,EAAE;gBACxE,IAAI,EAAE,qBAAqB;gBAC3B,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE;gBACxB,UAAU,EAAE,oEAAoE;aACjF,CAAC,CAAC;QACL,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,cAAc,CAA0B,IAAI,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,CACf,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACvC,CAAC;QAEpC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM;QACR,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC;YAC5D,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC5B,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC;gBACpC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,IAAI,UAAU,CAAC;gBACvD,IAAI,EAAE,GAAG;gBACT,OAAO,EAAE,GAAG;aACb,CAAC,CAAC;YAEH,IAAI,KAAK,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;gBAChC,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YAC5D,MAAM;QACR,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,UAAkB,EAClB,OAAkC;IAElC,MAAM,cAAc,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,MAAM,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpF,+CAA+C;IAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QACjE,OAAO,mBAAmB,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IAClF,CAAC;IAED,kFAAkF;IAClF,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACrD,mBAAmB,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC;QACjE,mBAAmB,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,CAAC;KACtE,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,UAAU,EAAE,GAAG,cAAc,CAAC,CAAC;AAC5C,CAAC"}