emdash-emit 0.1.14 → 0.1.15
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 +77 -1
- package/README.md +235 -187
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +6 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/pull.d.ts +32 -0
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/pull.js +108 -9
- package/dist/cli/commands/pull.js.map +1 -1
- package/dist/cli/commands/push.d.ts.map +1 -1
- package/dist/cli/commands/push.js +18 -0
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +15 -5
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/client/media.d.ts.map +1 -1
- package/dist/client/media.js +16 -5
- package/dist/client/media.js.map +1 -1
- package/dist/db/cache.d.ts +19 -4
- package/dist/db/cache.d.ts.map +1 -1
- package/dist/db/cache.js +127 -16
- package/dist/db/cache.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +5 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/sync-doctor.d.ts.map +1 -1
- package/dist/mcp/tools/sync-doctor.js +12 -0
- package/dist/mcp/tools/sync-doctor.js.map +1 -1
- package/dist/mcp/tools/sync-pull.d.ts.map +1 -1
- package/dist/mcp/tools/sync-pull.js +49 -12
- package/dist/mcp/tools/sync-pull.js.map +1 -1
- package/dist/mcp/tools/sync-push.d.ts.map +1 -1
- package/dist/mcp/tools/sync-push.js +5 -0
- package/dist/mcp/tools/sync-push.js.map +1 -1
- package/dist/mcp/tools/sync-status.d.ts.map +1 -1
- package/dist/mcp/tools/sync-status.js +6 -2
- package/dist/mcp/tools/sync-status.js.map +1 -1
- package/dist/sync/delete.d.ts +2 -1
- package/dist/sync/delete.d.ts.map +1 -1
- package/dist/sync/delete.js +6 -19
- package/dist/sync/delete.js.map +1 -1
- package/dist/sync/diff.d.ts.map +1 -1
- package/dist/sync/diff.js +18 -2
- package/dist/sync/diff.js.map +1 -1
- package/dist/sync/doctor.d.ts +27 -1
- package/dist/sync/doctor.d.ts.map +1 -1
- package/dist/sync/doctor.js +309 -26
- package/dist/sync/doctor.js.map +1 -1
- package/dist/sync/guards.d.ts +45 -0
- package/dist/sync/guards.d.ts.map +1 -0
- package/dist/sync/guards.js +235 -0
- package/dist/sync/guards.js.map +1 -0
- package/dist/sync/media/body_scan.d.ts +15 -0
- package/dist/sync/media/body_scan.d.ts.map +1 -0
- package/dist/sync/media/body_scan.js +132 -0
- package/dist/sync/media/body_scan.js.map +1 -0
- package/dist/sync/media/companions.d.ts +20 -0
- package/dist/sync/media/companions.d.ts.map +1 -0
- package/dist/sync/media/companions.js +111 -0
- package/dist/sync/media/companions.js.map +1 -0
- package/dist/sync/media/index.d.ts +9 -0
- package/dist/sync/media/index.d.ts.map +1 -0
- package/dist/sync/media/index.js +9 -0
- package/dist/sync/media/index.js.map +1 -0
- package/dist/sync/media/mirror_item.d.ts +27 -0
- package/dist/sync/media/mirror_item.d.ts.map +1 -0
- package/dist/sync/media/mirror_item.js +207 -0
- package/dist/sync/media/mirror_item.js.map +1 -0
- package/dist/sync/media/naming_mirror.d.ts +36 -0
- package/dist/sync/media/naming_mirror.d.ts.map +1 -0
- package/dist/sync/media/naming_mirror.js +143 -0
- package/dist/sync/media/naming_mirror.js.map +1 -0
- package/dist/sync/media/pull_article.d.ts +37 -0
- package/dist/sync/media/pull_article.d.ts.map +1 -0
- package/dist/sync/media/pull_article.js +273 -0
- package/dist/sync/media/pull_article.js.map +1 -0
- package/dist/sync/media/pull_library.d.ts +12 -0
- package/dist/sync/media/pull_library.d.ts.map +1 -0
- package/dist/sync/media/pull_library.js +207 -0
- package/dist/sync/media/pull_library.js.map +1 -0
- package/dist/sync/media/remote_index.d.ts +18 -0
- package/dist/sync/media/remote_index.d.ts.map +1 -0
- package/dist/sync/media/remote_index.js +94 -0
- package/dist/sync/media/remote_index.js.map +1 -0
- package/dist/sync/media/types.d.ts +191 -0
- package/dist/sync/media/types.d.ts.map +1 -0
- package/dist/sync/media/types.js +11 -0
- package/dist/sync/media/types.js.map +1 -0
- package/dist/sync/media.d.ts +1 -74
- package/dist/sync/media.d.ts.map +1 -1
- package/dist/sync/media.js +1 -592
- package/dist/sync/media.js.map +1 -1
- package/dist/sync/orchestrator.d.ts +23 -0
- package/dist/sync/orchestrator.d.ts.map +1 -1
- package/dist/sync/orchestrator.js +85 -1
- package/dist/sync/orchestrator.js.map +1 -1
- package/dist/sync/preflight.d.ts +1 -1
- package/dist/sync/preflight.d.ts.map +1 -1
- package/dist/sync/preflight.js +127 -15
- package/dist/sync/preflight.js.map +1 -1
- package/dist/sync/pull.d.ts +19 -0
- package/dist/sync/pull.d.ts.map +1 -1
- package/dist/sync/pull.js +169 -15
- package/dist/sync/pull.js.map +1 -1
- package/dist/sync/push.d.ts +7 -0
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +37 -10
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/status.d.ts +4 -0
- package/dist/sync/status.d.ts.map +1 -1
- package/dist/sync/status.js +68 -4
- package/dist/sync/status.js.map +1 -1
- package/dist/utils/config.d.ts +25 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +28 -2
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +15 -4
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/media-body-refs.d.ts +81 -0
- package/dist/utils/media-body-refs.d.ts.map +1 -0
- package/dist/utils/media-body-refs.js +240 -0
- package/dist/utils/media-body-refs.js.map +1 -0
- package/dist/utils/media-refs.d.ts +44 -0
- package/dist/utils/media-refs.d.ts.map +1 -0
- package/dist/utils/media-refs.js +101 -0
- package/dist/utils/media-refs.js.map +1 -0
- package/dist/utils/naming.d.ts +31 -0
- package/dist/utils/naming.d.ts.map +1 -1
- package/dist/utils/naming.js +58 -0
- package/dist/utils/naming.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical registry of preflight guards, authoring safety checks, and known error codes.
|
|
3
|
+
*
|
|
4
|
+
* This file is the single source of truth for:
|
|
5
|
+
* 1. Numbered safety guards (G1 through G19).
|
|
6
|
+
* 2. Operational ApiErrors emitted by network/push/media transport layers.
|
|
7
|
+
* 3. Standing protection errors raised by dedicated error classes.
|
|
8
|
+
*
|
|
9
|
+
* Verified against src/ via tests/guards.test.ts to guarantee zero drift.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Operational ApiErrors (network, lock, HTTP transport, server reject).
|
|
13
|
+
* They report a failed system operation rather than a rejected authoring intent.
|
|
14
|
+
* Exhaustively enumerated against src/ to ensure the rogue-code check in tests/guards.test.ts is total.
|
|
15
|
+
*/
|
|
16
|
+
export const OPERATIONAL_ERROR_CODES = [
|
|
17
|
+
// push / publish transport
|
|
18
|
+
'PUSH_CREATE_FAILED',
|
|
19
|
+
'PUSH_FAILED',
|
|
20
|
+
'PUSH_RETRY_FAILED',
|
|
21
|
+
'PUBLISH_FAILED',
|
|
22
|
+
'UNPUBLISH_FAILED',
|
|
23
|
+
'REMOTE_ARTICLE_DELETED',
|
|
24
|
+
'CONFLICT_REMOTE_FETCH_FAILED',
|
|
25
|
+
// taxonomy transport (push.ts / taxonomies.ts)
|
|
26
|
+
'TAXONOMY_UPDATE_FAILED',
|
|
27
|
+
'TAXONOMY_DIVERGENCE',
|
|
28
|
+
'TAXONOMY_UNION_REJECTED',
|
|
29
|
+
'TAXONOMY_FETCH_FAILED',
|
|
30
|
+
// lock lease (client/lock.ts, thrown as EntryLockError('ENTRY_LOCKED'))
|
|
31
|
+
'ENTRY_LOCKED',
|
|
32
|
+
// media upload transport (client/media.ts)
|
|
33
|
+
'MEDIA_UPLOAD_URL_FAILED',
|
|
34
|
+
'MEDIA_BINARY_UPLOAD_FAILED',
|
|
35
|
+
'MEDIA_CONFIRM_FAILED',
|
|
36
|
+
'MEDIA_NOT_READY',
|
|
37
|
+
// list / fetch failures
|
|
38
|
+
'ARTICLE_LIST_FAILED',
|
|
39
|
+
'ARTICLE_PULL_FAILED',
|
|
40
|
+
'ARTICLE_NOT_FOUND',
|
|
41
|
+
'MEDIA_LIST_FAILED',
|
|
42
|
+
'NETWORK_ERROR',
|
|
43
|
+
// delete transport (sync/delete.ts)
|
|
44
|
+
'REMOTE_DELETE_FAILED',
|
|
45
|
+
'REMOTE_DELETE_UNCONFIRMED',
|
|
46
|
+
];
|
|
47
|
+
/**
|
|
48
|
+
* Standing protection errors raised by dedicated error classes rather than ApiError.
|
|
49
|
+
* They guard destructive operations (e.g. deleting published or modified articles)
|
|
50
|
+
* or fundamental parsing, living outside GUARD_REGISTRY.
|
|
51
|
+
*/
|
|
52
|
+
export const PROTECTION_ERROR_CODES = [
|
|
53
|
+
'UNPUSHED_CHANGES_PROTECTION', // sync/delete.ts (UnpushedModificationsError)
|
|
54
|
+
'PUBLISHED_ARTICLE_PROTECTION', // sync/delete.ts (PublishedArticleDeletionForbiddenError)
|
|
55
|
+
'FRONTMATTER_PARSE_ERROR', // utils/frontmatter.ts (FrontmatterParseError)
|
|
56
|
+
];
|
|
57
|
+
export const GUARD_REGISTRY = [
|
|
58
|
+
{
|
|
59
|
+
id: 1,
|
|
60
|
+
name: 'SINGLE_TARGET_GUARD',
|
|
61
|
+
codes: [],
|
|
62
|
+
stage: 'cli-mcp',
|
|
63
|
+
severity: 'error',
|
|
64
|
+
source: 'src/sync/preflight.ts:358',
|
|
65
|
+
description: 'CLI / MCP 呼び出し層での単一ファイル指定強制(一括 Push の抑止)',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 2,
|
|
69
|
+
name: 'ID_MISMATCH_ERROR',
|
|
70
|
+
codes: ['ID_MISMATCH_ERROR'],
|
|
71
|
+
stage: 'preflight',
|
|
72
|
+
severity: 'error',
|
|
73
|
+
source: 'src/sync/preflight.ts:377',
|
|
74
|
+
description: 'ファイルパスと Frontmatter 内 ULID の整合性検証',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 3,
|
|
78
|
+
name: 'UNINTENDED_PUBLISH_GUARD',
|
|
79
|
+
codes: ['UNINTENDED_PUBLISH_GUARD'],
|
|
80
|
+
stage: 'preflight',
|
|
81
|
+
severity: 'error',
|
|
82
|
+
source: 'src/sync/preflight.ts:389',
|
|
83
|
+
description: '明示的な allowPublish 指定なしの公開昇格を防止',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 4,
|
|
87
|
+
name: 'INVALID_TAXONOMY_ERROR',
|
|
88
|
+
codes: ['INVALID_TAXONOMY_ERROR'],
|
|
89
|
+
stage: 'preflight',
|
|
90
|
+
severity: 'error',
|
|
91
|
+
source: 'src/sync/preflight.ts:440',
|
|
92
|
+
description: '未定義カテゴリ・タグの指定検知',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 5,
|
|
96
|
+
name: 'LOCAL_IMAGE_DETECTED',
|
|
97
|
+
codes: ['LOCAL_IMAGE_DETECTED', 'INLINE_LOCAL_IMAGE_NOT_SUPPORTED'],
|
|
98
|
+
stage: 'preflight',
|
|
99
|
+
severity: 'error',
|
|
100
|
+
source: 'src/sync/preflight.ts:515,608',
|
|
101
|
+
description: '本文内の未解決ローカル画像パスおよびインラインローカル画像検知',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: 6,
|
|
105
|
+
name: 'UNRESOLVED_CONFLICT_MARKERS',
|
|
106
|
+
codes: ['UNRESOLVED_CONFLICT_MARKERS'],
|
|
107
|
+
stage: 'preflight',
|
|
108
|
+
severity: 'error',
|
|
109
|
+
source: 'src/sync/preflight.ts:642',
|
|
110
|
+
description: '3-Way Merge コンフリクトマーカー(<<<<<<<, =======, >>>>>>>)の残存検知',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 7,
|
|
114
|
+
name: 'TITLE_DUPLICATION_AUTOTRIM',
|
|
115
|
+
codes: [],
|
|
116
|
+
stage: 'preflight',
|
|
117
|
+
severity: 'info',
|
|
118
|
+
source: 'src/sync/preflight.ts:651-663',
|
|
119
|
+
description: '本文冒頭の重複 # Title 自動除去(cleanedBody の mutation)',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: 8,
|
|
123
|
+
name: 'UNSUPPORTED_SYNTAX_WARNING',
|
|
124
|
+
codes: [],
|
|
125
|
+
stage: 'preflight',
|
|
126
|
+
severity: 'warning',
|
|
127
|
+
source: 'src/client/portable-text.ts:618',
|
|
128
|
+
description: 'Portable Text 非互換構文の警告(detectUnsupportedMarkdownSyntax)',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 9,
|
|
132
|
+
name: 'MODIFIED_OPAQUE_BLOCK',
|
|
133
|
+
codes: ['MODIFIED_OPAQUE_BLOCK'],
|
|
134
|
+
stage: 'preflight',
|
|
135
|
+
severity: 'error',
|
|
136
|
+
source: 'src/sync/preflight.ts:672',
|
|
137
|
+
description: '<!--ec:block--> 保護ブロック改ざん検知',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: 10,
|
|
141
|
+
name: 'INVALID_FEATURED_IMAGE',
|
|
142
|
+
codes: ['INVALID_FEATURED_IMAGE'],
|
|
143
|
+
stage: 'preflight',
|
|
144
|
+
severity: 'error',
|
|
145
|
+
source: 'src/sync/preflight.ts:630',
|
|
146
|
+
description: 'アイキャッチ画像 ID の形式検証(26 文字 ULID または null)',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: 11,
|
|
150
|
+
name: 'LOCAL_IMAGE_AUTO_UPLOAD',
|
|
151
|
+
codes: [
|
|
152
|
+
'MISSING_LOCAL_IMAGE_FILE',
|
|
153
|
+
'INVALID_LOCAL_IMAGE_TYPE',
|
|
154
|
+
'LOCAL_IMAGE_SIZE_EXCEEDED',
|
|
155
|
+
'PROMOTED_MEDIA_NOT_FOUND_REMOTE',
|
|
156
|
+
],
|
|
157
|
+
stage: 'preflight',
|
|
158
|
+
severity: 'error',
|
|
159
|
+
source: 'src/sync/preflight.ts:545,564',
|
|
160
|
+
description: 'media/drafts/ からのオフライン画像自動アップロード・置換処理([MEDIA_EXISTENCE_UNVERIFIED] 警告を含む)',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: 12,
|
|
164
|
+
name: 'QUARANTINED_COPY_NOT_PUSHABLE',
|
|
165
|
+
codes: ['QUARANTINED_COPY_NOT_PUSHABLE'],
|
|
166
|
+
stage: 'push',
|
|
167
|
+
severity: 'error',
|
|
168
|
+
source: 'src/sync/push.ts:581',
|
|
169
|
+
description: 'conflicts/ 配下の退避ファイル直接 Push 禁止',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: 13,
|
|
173
|
+
name: 'CANONICAL_HAS_UNPUSHED_EDITS',
|
|
174
|
+
codes: ['CANONICAL_HAS_UNPUSHED_EDITS'],
|
|
175
|
+
stage: 'conflicts',
|
|
176
|
+
severity: 'error',
|
|
177
|
+
source: 'src/sync/conflicts.ts:67',
|
|
178
|
+
description: 'コンフリクト解消時の未 Push ローカル編集上書き防止',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: 14,
|
|
182
|
+
name: 'QUARANTINED_PATH_REQUIRED',
|
|
183
|
+
codes: ['QUARANTINED_PATH_REQUIRED'],
|
|
184
|
+
stage: 'conflicts',
|
|
185
|
+
severity: 'error',
|
|
186
|
+
source: 'src/sync/conflicts.ts:86',
|
|
187
|
+
description: 'コンフリクト対象パスの検証',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: 15,
|
|
191
|
+
name: 'DELETE_PENDING_ARTICLE',
|
|
192
|
+
codes: ['DELETE_PENDING_ARTICLE'],
|
|
193
|
+
stage: 'push',
|
|
194
|
+
severity: 'error',
|
|
195
|
+
source: 'src/sync/push.ts:674',
|
|
196
|
+
description: '削除保留中記事の Push 抑止',
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: 16,
|
|
200
|
+
name: 'TAXONOMY_CONFLICT_PENDING',
|
|
201
|
+
codes: ['TAXONOMY_CONFLICT_PENDING'],
|
|
202
|
+
stage: 'push',
|
|
203
|
+
severity: 'error',
|
|
204
|
+
source: 'src/sync/push.ts:711',
|
|
205
|
+
description: 'タクソノミー未反映状態での Push 抑止',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
id: 17,
|
|
209
|
+
name: 'TAXONOMY_APPLY_PENDING',
|
|
210
|
+
codes: ['TAXONOMY_APPLY_PENDING'],
|
|
211
|
+
stage: 'push',
|
|
212
|
+
severity: 'error',
|
|
213
|
+
source: 'src/sync/push.ts:726',
|
|
214
|
+
description: 'タクソノミー同期保留中の Push 抑止',
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: 18,
|
|
218
|
+
name: 'DUPLICATE_SLUG_CONFLICT',
|
|
219
|
+
codes: ['DUPLICATE_SLUG_CONFLICT'],
|
|
220
|
+
stage: 'new',
|
|
221
|
+
severity: 'error',
|
|
222
|
+
source: 'src/sync/new.ts:45',
|
|
223
|
+
description: '記事作成時の重複スラッグ検証',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
id: 19,
|
|
227
|
+
name: 'DESTRUCTIVE_TAXONOMY_WIPE',
|
|
228
|
+
codes: ['DESTRUCTIVE_TAXONOMY_WIPE'],
|
|
229
|
+
stage: 'push',
|
|
230
|
+
severity: 'error',
|
|
231
|
+
source: 'src/sync/push.ts:803,1232',
|
|
232
|
+
description: 'タクソノミー全削除等の破壊的操作抑止',
|
|
233
|
+
},
|
|
234
|
+
];
|
|
235
|
+
//# sourceMappingURL=guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/sync/guards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OrphanMediaDescriptor } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts every media file storageKey referenced by an article (markdown images, HTML img tags,
|
|
4
|
+
* opaque custom-block fences, and legacy container lines such as `[dimage url="..." control=true]`).
|
|
5
|
+
* A storageKey must be ULID-segment based with a known image extension, so template placeholders
|
|
6
|
+
* (`<storageKey>`) and prose never produce descriptors. The media record id is deliberately NOT
|
|
7
|
+
* inferred from it: for migrated WordPress assets the file route serves `<storageKey>` while the
|
|
8
|
+
* record id returns 404, so only the storageKey can be reported to the user.
|
|
9
|
+
*/
|
|
10
|
+
export declare function collectArticleStorageKeys(content: string): OrphanMediaDescriptor[];
|
|
11
|
+
/**
|
|
12
|
+
* Collects all media ULIDs referenced by an article content (frontmatter featuredImage + body images).
|
|
13
|
+
*/
|
|
14
|
+
export declare function collectArticleReferencedMediaIds(content: string): string[];
|
|
15
|
+
//# sourceMappingURL=body_scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body_scan.d.ts","sourceRoot":"","sources":["../../../src/sync/media/body_scan.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAuBxD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,EAAE,CA+BlF;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAwE1E"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import yaml from 'js-yaml';
|
|
2
|
+
import { extractMediaUlid } from '../../client/mapper.js';
|
|
3
|
+
import { parseMarkdown, lenientRepairMarkdownFrontmatter } from '../../utils/frontmatter.js';
|
|
4
|
+
import { scanArticleMediaReferences } from '../delete.js';
|
|
5
|
+
/** Builds a descriptor from a ULID-segment storageKey, defaulting to `.jpg` when no extension is present. */
|
|
6
|
+
function descriptorFromStorageKey(storageKey) {
|
|
7
|
+
const extMatch = storageKey.match(/\.[a-z]+$/i);
|
|
8
|
+
return {
|
|
9
|
+
storageKey,
|
|
10
|
+
ext: extMatch ? extMatch[0].toLowerCase() : '.jpg',
|
|
11
|
+
ulids: Array.from(storageKey.matchAll(/[0-9A-HJ-NP-Z]{26}/gi), (m) => m[0].toUpperCase()),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Collapses descriptors that name the same storageKey, keeping one entry per key. */
|
|
15
|
+
function dedupeDescriptorsByStorageKey(descriptors) {
|
|
16
|
+
const byKey = new Map();
|
|
17
|
+
for (const descriptor of descriptors) {
|
|
18
|
+
if (!byKey.has(descriptor.storageKey))
|
|
19
|
+
byKey.set(descriptor.storageKey, descriptor);
|
|
20
|
+
}
|
|
21
|
+
return Array.from(byKey.values()).sort((a, b) => a.storageKey.localeCompare(b.storageKey));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Extracts every media file storageKey referenced by an article (markdown images, HTML img tags,
|
|
25
|
+
* opaque custom-block fences, and legacy container lines such as `[dimage url="..." control=true]`).
|
|
26
|
+
* A storageKey must be ULID-segment based with a known image extension, so template placeholders
|
|
27
|
+
* (`<storageKey>`) and prose never produce descriptors. The media record id is deliberately NOT
|
|
28
|
+
* inferred from it: for migrated WordPress assets the file route serves `<storageKey>` while the
|
|
29
|
+
* record id returns 404, so only the storageKey can be reported to the user.
|
|
30
|
+
*/
|
|
31
|
+
export function collectArticleStorageKeys(content) {
|
|
32
|
+
const keys = new Set();
|
|
33
|
+
const keyPattern = /(?:^|\/)media\/file\/([0-9A-HJ-NP-Z]{26}(?:\.[0-9A-HJ-NP-Z]{26})*\.(?:jpg|jpeg|png|gif|webp|avif|svg))/gi;
|
|
34
|
+
// A workspace that spells a mirrored image as `media/<storageKey>` names the key outright rather than
|
|
35
|
+
// through the file route, so the census must read that spelling too — otherwise an unmirrored local
|
|
36
|
+
// reference silently disappears from `referencedUnmirroredStorageKeys`.
|
|
37
|
+
const localRefPattern = /(?:^|\/)media\/([0-9A-HJ-NP-Z]{26}(?:\.[0-9A-HJ-NP-Z]{26})*\.(?:jpg|jpeg|png|gif|webp|avif|svg))/gi;
|
|
38
|
+
const harvest = (text, pattern) => {
|
|
39
|
+
let match;
|
|
40
|
+
pattern.lastIndex = 0;
|
|
41
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
42
|
+
keys.add(match[1]);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
// scanArticleMediaReferences covers markdown images and HTML img tags anywhere in the body,
|
|
46
|
+
// including inside opaque fences and legacy container lines where doctor stays quiet by design.
|
|
47
|
+
const scannedRefs = scanArticleMediaReferences(content).join('\n');
|
|
48
|
+
harvest(scannedRefs, keyPattern);
|
|
49
|
+
harvest(content, keyPattern);
|
|
50
|
+
harvest(scannedRefs, localRefPattern);
|
|
51
|
+
harvest(content, localRefPattern);
|
|
52
|
+
const descriptors = [];
|
|
53
|
+
for (const storageKey of keys) {
|
|
54
|
+
descriptors.push(descriptorFromStorageKey(storageKey));
|
|
55
|
+
}
|
|
56
|
+
return dedupeDescriptorsByStorageKey(descriptors);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Collects all media ULIDs referenced by an article content (frontmatter featuredImage + body images).
|
|
60
|
+
*/
|
|
61
|
+
export function collectArticleReferencedMediaIds(content) {
|
|
62
|
+
const ids = new Set();
|
|
63
|
+
let frontmatter = null;
|
|
64
|
+
let body = content;
|
|
65
|
+
// Try extracting YAML block directly if present
|
|
66
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
67
|
+
if (fmMatch) {
|
|
68
|
+
try {
|
|
69
|
+
frontmatter = yaml.load(fmMatch[1]) || null;
|
|
70
|
+
body = content.slice(fmMatch[0].length);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Keep going
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!frontmatter) {
|
|
77
|
+
try {
|
|
78
|
+
const parsed = parseMarkdown(content);
|
|
79
|
+
frontmatter = parsed.frontmatter;
|
|
80
|
+
body = parsed.body;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
try {
|
|
84
|
+
const healed = lenientRepairMarkdownFrontmatter(content);
|
|
85
|
+
if (healed) {
|
|
86
|
+
const parsed = parseMarkdown(healed);
|
|
87
|
+
frontmatter = parsed.frontmatter;
|
|
88
|
+
body = parsed.body;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Fallback: search raw content
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// 1. Frontmatter featuredImage
|
|
97
|
+
if (frontmatter && frontmatter.featuredImage) {
|
|
98
|
+
const ulid = extractMediaUlid(frontmatter.featuredImage);
|
|
99
|
+
if (ulid) {
|
|
100
|
+
ids.add(ulid);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// Regex fallback for featuredImage in raw text if YAML parsing failed
|
|
105
|
+
const rawFiMatch = content.match(/featuredImage:\s*["']?([0-9A-HJ-NP-Z]{26})["']?/i);
|
|
106
|
+
if (rawFiMatch) {
|
|
107
|
+
ids.add(rawFiMatch[1].toUpperCase());
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// 2. Body Markdown & HTML image references
|
|
111
|
+
const refs = scanArticleMediaReferences(body);
|
|
112
|
+
for (const ref of refs) {
|
|
113
|
+
const ulid = extractMediaUlid(ref);
|
|
114
|
+
if (ulid) {
|
|
115
|
+
ids.add(ulid);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const match = ref.match(/(?:^|\/)(?:\d{8}_)?([0-9A-HJ-NP-Z]{26})-/i);
|
|
119
|
+
if (match) {
|
|
120
|
+
ids.add(match[1].toUpperCase());
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// 3. URLs matching /_emdash/api/media/file/<ULID> or /media/<ULID>
|
|
125
|
+
const mediaUrlRegex = /(?:\/media\/file\/|\/media\/)([0-9A-HJ-NP-Z]{26})/gi;
|
|
126
|
+
let m;
|
|
127
|
+
while ((m = mediaUrlRegex.exec(body)) !== null) {
|
|
128
|
+
ids.add(m[1].toUpperCase());
|
|
129
|
+
}
|
|
130
|
+
return Array.from(ids).sort();
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=body_scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body_scan.js","sourceRoot":"","sources":["../../../src/sync/media/body_scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EmDashMediaItem, LocalMediaMirrorCandidate } from './types.js';
|
|
2
|
+
export declare function buildMediaMetaDoc(item: EmDashMediaItem, origin: string, existingMeta?: Record<string, unknown> | null): Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* Recovers the storageKey a companion YAML actually refers to. Older mirrors — most visibly the ones
|
|
5
|
+
* written before Emit persisted the field — carry no `storageKey:` key at all, yet their `url:` is the
|
|
6
|
+
* canonical `/_emdash/api/media/file/<storageKey>` route, which is confirmed metadata written from the
|
|
7
|
+
* server response and not an inference from a body reference. Absolute and root-relative forms are both
|
|
8
|
+
* accepted because either can appear depending on how the record was mirrored. `legacy_*` residue is
|
|
9
|
+
* never read here: it backs no real record, so it must not serve as verification evidence.
|
|
10
|
+
*/
|
|
11
|
+
export declare function storageKeyFromMediaMeta(doc: Record<string, unknown>): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Indexes every locally mirrored media asset (`media/<markdownRef>.yaml`, plus legacy companion names) so a body
|
|
14
|
+
* storageKey that the canonical id lookup failed to resolve can be re-checked against confirmed local
|
|
15
|
+
* metadata instead of being declared missing. Leftover `legacy_*` residue is skipped because it backs
|
|
16
|
+
* no real record. The result maps each ULID found in a mirror (record id or storageKey) to its entry,
|
|
17
|
+
* which is what lets Emit tell "the record exists under a different id" apart from "no record exists".
|
|
18
|
+
*/
|
|
19
|
+
export declare function collectLocalMediaMirrorCandidates(mediaDir: string): Map<string, LocalMediaMirrorCandidate>;
|
|
20
|
+
//# sourceMappingURL=companions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companions.d.ts","sourceRoot":"","sources":["../../../src/sync/media/companions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE7E,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAC5C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoDzB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAOxF;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAgCxC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
import { toRootRelativeMediaUrl } from '../../client/media.js';
|
|
5
|
+
import { MEDIA_FILE_ROUTE_PREFIX } from '../../utils/media-refs.js';
|
|
6
|
+
export function buildMediaMetaDoc(item, origin, existingMeta) {
|
|
7
|
+
const storageKey = (typeof item.storageKey === 'string' && item.storageKey ? item.storageKey : undefined) ??
|
|
8
|
+
(typeof existingMeta?.storageKey === 'string' && existingMeta.storageKey
|
|
9
|
+
? existingMeta.storageKey
|
|
10
|
+
: '');
|
|
11
|
+
const canonicalUrl = item.url ||
|
|
12
|
+
(storageKey
|
|
13
|
+
? `${MEDIA_FILE_ROUTE_PREFIX}${storageKey}`
|
|
14
|
+
: typeof existingMeta?.url === 'string'
|
|
15
|
+
? existingMeta.url
|
|
16
|
+
: '');
|
|
17
|
+
const rootRelativeUrl = canonicalUrl
|
|
18
|
+
? toRootRelativeMediaUrl(canonicalUrl, storageKey, origin)
|
|
19
|
+
: '';
|
|
20
|
+
const resolvedAlt = item.alt !== undefined && item.alt !== null && item.alt !== ''
|
|
21
|
+
? item.alt
|
|
22
|
+
: typeof existingMeta?.alt === 'string'
|
|
23
|
+
? existingMeta.alt
|
|
24
|
+
: '';
|
|
25
|
+
const resolvedCaption = item.caption !== undefined && item.caption !== null && item.caption !== ''
|
|
26
|
+
? item.caption
|
|
27
|
+
: typeof existingMeta?.caption === 'string'
|
|
28
|
+
? existingMeta.caption
|
|
29
|
+
: '';
|
|
30
|
+
const resolvedContentHash = typeof item.contentHash === 'string' && item.contentHash
|
|
31
|
+
? item.contentHash
|
|
32
|
+
: typeof existingMeta?.contentHash === 'string' && existingMeta.contentHash
|
|
33
|
+
? existingMeta.contentHash
|
|
34
|
+
: null;
|
|
35
|
+
return {
|
|
36
|
+
id: item.id,
|
|
37
|
+
filename: item.filename,
|
|
38
|
+
mimeType: item.mimeType,
|
|
39
|
+
size: item.size,
|
|
40
|
+
width: item.width ?? (typeof existingMeta?.width === 'number' ? existingMeta.width : null),
|
|
41
|
+
height: item.height ?? (typeof existingMeta?.height === 'number' ? existingMeta.height : null),
|
|
42
|
+
alt: resolvedAlt,
|
|
43
|
+
caption: resolvedCaption,
|
|
44
|
+
storageKey,
|
|
45
|
+
contentHash: resolvedContentHash,
|
|
46
|
+
status: item.status ?? (typeof existingMeta?.status === 'string' ? existingMeta.status : 'ready'),
|
|
47
|
+
url: rootRelativeUrl,
|
|
48
|
+
createdAt: item.createdAt || (typeof existingMeta?.createdAt === 'string' ? existingMeta.createdAt : ''),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Recovers the storageKey a companion YAML actually refers to. Older mirrors — most visibly the ones
|
|
53
|
+
* written before Emit persisted the field — carry no `storageKey:` key at all, yet their `url:` is the
|
|
54
|
+
* canonical `/_emdash/api/media/file/<storageKey>` route, which is confirmed metadata written from the
|
|
55
|
+
* server response and not an inference from a body reference. Absolute and root-relative forms are both
|
|
56
|
+
* accepted because either can appear depending on how the record was mirrored. `legacy_*` residue is
|
|
57
|
+
* never read here: it backs no real record, so it must not serve as verification evidence.
|
|
58
|
+
*/
|
|
59
|
+
export function storageKeyFromMediaMeta(doc) {
|
|
60
|
+
if (typeof doc.storageKey === 'string' && doc.storageKey.trim()) {
|
|
61
|
+
return doc.storageKey.trim();
|
|
62
|
+
}
|
|
63
|
+
if (typeof doc.url !== 'string' || !doc.url.trim())
|
|
64
|
+
return undefined;
|
|
65
|
+
const match = doc.url.match(/(?:^|\/)media\/file\/([^?#]+)/);
|
|
66
|
+
return match ? match[1] : undefined;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Indexes every locally mirrored media asset (`media/<markdownRef>.yaml`, plus legacy companion names) so a body
|
|
70
|
+
* storageKey that the canonical id lookup failed to resolve can be re-checked against confirmed local
|
|
71
|
+
* metadata instead of being declared missing. Leftover `legacy_*` residue is skipped because it backs
|
|
72
|
+
* no real record. The result maps each ULID found in a mirror (record id or storageKey) to its entry,
|
|
73
|
+
* which is what lets Emit tell "the record exists under a different id" apart from "no record exists".
|
|
74
|
+
*/
|
|
75
|
+
export function collectLocalMediaMirrorCandidates(mediaDir) {
|
|
76
|
+
const byUlid = new Map();
|
|
77
|
+
if (!fs.existsSync(mediaDir))
|
|
78
|
+
return byUlid;
|
|
79
|
+
for (const file of fs.readdirSync(mediaDir)) {
|
|
80
|
+
if (!file.endsWith('.yaml') || file.startsWith('legacy_'))
|
|
81
|
+
continue;
|
|
82
|
+
let doc = null;
|
|
83
|
+
try {
|
|
84
|
+
doc = yaml.load(fs.readFileSync(path.join(mediaDir, file), 'utf8'));
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!doc)
|
|
90
|
+
continue;
|
|
91
|
+
const storageKey = storageKeyFromMediaMeta(doc);
|
|
92
|
+
const stem = file.replace(/\.yaml$/, '');
|
|
93
|
+
const idMatch = stem.replace(/^\d{8}_/, '').match(/^([0-9A-HJ-NP-Z]{26})/i);
|
|
94
|
+
const docId = typeof doc.id === 'string' && /^[0-9A-HJ-NP-Z]{26}$/i.test(doc.id.trim())
|
|
95
|
+
? doc.id.trim().toUpperCase()
|
|
96
|
+
: undefined;
|
|
97
|
+
const mediaId = docId || (idMatch ? idMatch[1].toUpperCase() : '');
|
|
98
|
+
if (!mediaId)
|
|
99
|
+
continue;
|
|
100
|
+
const candidate = { mediaId, storageKey, metaFile: file };
|
|
101
|
+
if (!byUlid.has(mediaId))
|
|
102
|
+
byUlid.set(mediaId, candidate);
|
|
103
|
+
for (const ulid of storageKey?.matchAll(/[0-9A-HJ-NP-Z]{26}/gi) ?? []) {
|
|
104
|
+
const key = ulid[0].toUpperCase();
|
|
105
|
+
if (!byUlid.has(key))
|
|
106
|
+
byUlid.set(key, candidate);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return byUlid;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=companions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companions.js","sourceRoot":"","sources":["../../../src/sync/media/companions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './naming_mirror.js';
|
|
3
|
+
export * from './companions.js';
|
|
4
|
+
export * from './body_scan.js';
|
|
5
|
+
export * from './mirror_item.js';
|
|
6
|
+
export * from './pull_article.js';
|
|
7
|
+
export * from './pull_library.js';
|
|
8
|
+
export * from './remote_index.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sync/media/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './naming_mirror.js';
|
|
3
|
+
export * from './companions.js';
|
|
4
|
+
export * from './body_scan.js';
|
|
5
|
+
export * from './mirror_item.js';
|
|
6
|
+
export * from './pull_article.js';
|
|
7
|
+
export * from './pull_library.js';
|
|
8
|
+
export * from './remote_index.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sync/media/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CacheDatabase } from '../../db/cache.js';
|
|
2
|
+
import type { EmDashMediaItem, PromoteDraftMediaOptions, PromotedMediaFile } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Persists YAML companion metadata and downloads the binary file for a single media item.
|
|
5
|
+
*/
|
|
6
|
+
export declare function syncSingleMediaItem(options: {
|
|
7
|
+
item: EmDashMediaItem;
|
|
8
|
+
mediaDir: string;
|
|
9
|
+
origin: string;
|
|
10
|
+
token: string;
|
|
11
|
+
downloadFiles: boolean;
|
|
12
|
+
fetchFn: typeof fetch;
|
|
13
|
+
cache?: CacheDatabase;
|
|
14
|
+
}): Promise<{
|
|
15
|
+
downloaded: boolean;
|
|
16
|
+
skipped: boolean;
|
|
17
|
+
baseName: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Promotes a local draft image from media/drafts/<name> into the canonical
|
|
21
|
+
* media/<markdownRef>.<ext> location alongside its matching media/<markdownRef>.yaml companion, where
|
|
22
|
+
* markdownRef is derived from the storageKey the article body will reference. Returns both the workspace-relative
|
|
23
|
+
* path of the promoted binary and the shared `media/<markdownRef>` stem, so the caller can record the mirror in
|
|
24
|
+
* `media_state.markdown_ref`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function promoteDraftMediaFile(options: PromoteDraftMediaOptions): PromotedMediaFile;
|
|
27
|
+
//# sourceMappingURL=mirror_item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mirror_item.d.ts","sourceRoot":"","sources":["../../../src/sync/media/mirror_item.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQvD,OAAO,KAAK,EAAE,eAAe,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/F;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE;IACjD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,KAAK,CAAC;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,GAAG,OAAO,CAAC;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAmKvE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAyD1F"}
|