emdash-emit 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +96 -1
  2. package/README.md +259 -188
  3. package/dist/bin/emit.d.ts.map +1 -1
  4. package/dist/bin/emit.js +2 -0
  5. package/dist/bin/emit.js.map +1 -1
  6. package/dist/cli/commands/doctor.d.ts.map +1 -1
  7. package/dist/cli/commands/doctor.js +6 -0
  8. package/dist/cli/commands/doctor.js.map +1 -1
  9. package/dist/cli/commands/media.d.ts +4 -0
  10. package/dist/cli/commands/media.d.ts.map +1 -0
  11. package/dist/cli/commands/media.js +128 -0
  12. package/dist/cli/commands/media.js.map +1 -0
  13. package/dist/cli/commands/pull.d.ts +32 -0
  14. package/dist/cli/commands/pull.d.ts.map +1 -1
  15. package/dist/cli/commands/pull.js +136 -9
  16. package/dist/cli/commands/pull.js.map +1 -1
  17. package/dist/cli/commands/push.d.ts.map +1 -1
  18. package/dist/cli/commands/push.js +18 -0
  19. package/dist/cli/commands/push.js.map +1 -1
  20. package/dist/cli/commands/status.d.ts.map +1 -1
  21. package/dist/cli/commands/status.js +16 -5
  22. package/dist/cli/commands/status.js.map +1 -1
  23. package/dist/client/media.d.ts.map +1 -1
  24. package/dist/client/media.js +16 -5
  25. package/dist/client/media.js.map +1 -1
  26. package/dist/db/cache.d.ts +19 -4
  27. package/dist/db/cache.d.ts.map +1 -1
  28. package/dist/db/cache.js +127 -16
  29. package/dist/db/cache.js.map +1 -1
  30. package/dist/mcp/server.d.ts.map +1 -1
  31. package/dist/mcp/server.js +7 -3
  32. package/dist/mcp/server.js.map +1 -1
  33. package/dist/mcp/tools/sync-doctor.d.ts.map +1 -1
  34. package/dist/mcp/tools/sync-doctor.js +12 -0
  35. package/dist/mcp/tools/sync-doctor.js.map +1 -1
  36. package/dist/mcp/tools/sync-media-search.d.ts +4 -0
  37. package/dist/mcp/tools/sync-media-search.d.ts.map +1 -0
  38. package/dist/mcp/tools/sync-media-search.js +102 -0
  39. package/dist/mcp/tools/sync-media-search.js.map +1 -0
  40. package/dist/mcp/tools/sync-pull.d.ts.map +1 -1
  41. package/dist/mcp/tools/sync-pull.js +85 -13
  42. package/dist/mcp/tools/sync-pull.js.map +1 -1
  43. package/dist/mcp/tools/sync-push.d.ts.map +1 -1
  44. package/dist/mcp/tools/sync-push.js +5 -0
  45. package/dist/mcp/tools/sync-push.js.map +1 -1
  46. package/dist/mcp/tools/sync-status.d.ts.map +1 -1
  47. package/dist/mcp/tools/sync-status.js +6 -2
  48. package/dist/mcp/tools/sync-status.js.map +1 -1
  49. package/dist/sync/delete.d.ts +2 -1
  50. package/dist/sync/delete.d.ts.map +1 -1
  51. package/dist/sync/delete.js +6 -19
  52. package/dist/sync/delete.js.map +1 -1
  53. package/dist/sync/diff.d.ts.map +1 -1
  54. package/dist/sync/diff.js +18 -2
  55. package/dist/sync/diff.js.map +1 -1
  56. package/dist/sync/doctor.d.ts +27 -1
  57. package/dist/sync/doctor.d.ts.map +1 -1
  58. package/dist/sync/doctor.js +309 -26
  59. package/dist/sync/doctor.js.map +1 -1
  60. package/dist/sync/guards.d.ts +45 -0
  61. package/dist/sync/guards.d.ts.map +1 -0
  62. package/dist/sync/guards.js +236 -0
  63. package/dist/sync/guards.js.map +1 -0
  64. package/dist/sync/media/body_scan.d.ts +15 -0
  65. package/dist/sync/media/body_scan.d.ts.map +1 -0
  66. package/dist/sync/media/body_scan.js +132 -0
  67. package/dist/sync/media/body_scan.js.map +1 -0
  68. package/dist/sync/media/companions.d.ts +32 -0
  69. package/dist/sync/media/companions.d.ts.map +1 -0
  70. package/dist/sync/media/companions.js +260 -0
  71. package/dist/sync/media/companions.js.map +1 -0
  72. package/dist/sync/media/index.d.ts +9 -0
  73. package/dist/sync/media/index.d.ts.map +1 -0
  74. package/dist/sync/media/index.js +9 -0
  75. package/dist/sync/media/index.js.map +1 -0
  76. package/dist/sync/media/mirror_item.d.ts +27 -0
  77. package/dist/sync/media/mirror_item.d.ts.map +1 -0
  78. package/dist/sync/media/mirror_item.js +207 -0
  79. package/dist/sync/media/mirror_item.js.map +1 -0
  80. package/dist/sync/media/naming_mirror.d.ts +36 -0
  81. package/dist/sync/media/naming_mirror.d.ts.map +1 -0
  82. package/dist/sync/media/naming_mirror.js +143 -0
  83. package/dist/sync/media/naming_mirror.js.map +1 -0
  84. package/dist/sync/media/pull_article.d.ts +37 -0
  85. package/dist/sync/media/pull_article.d.ts.map +1 -0
  86. package/dist/sync/media/pull_article.js +273 -0
  87. package/dist/sync/media/pull_article.js.map +1 -0
  88. package/dist/sync/media/pull_library.d.ts +12 -0
  89. package/dist/sync/media/pull_library.d.ts.map +1 -0
  90. package/dist/sync/media/pull_library.js +255 -0
  91. package/dist/sync/media/pull_library.js.map +1 -0
  92. package/dist/sync/media/remote_index.d.ts +49 -0
  93. package/dist/sync/media/remote_index.d.ts.map +1 -0
  94. package/dist/sync/media/remote_index.js +241 -0
  95. package/dist/sync/media/remote_index.js.map +1 -0
  96. package/dist/sync/media/types.d.ts +237 -0
  97. package/dist/sync/media/types.d.ts.map +1 -0
  98. package/dist/sync/media/types.js +11 -0
  99. package/dist/sync/media/types.js.map +1 -0
  100. package/dist/sync/media.d.ts +1 -74
  101. package/dist/sync/media.d.ts.map +1 -1
  102. package/dist/sync/media.js +1 -592
  103. package/dist/sync/media.js.map +1 -1
  104. package/dist/sync/orchestrator.d.ts +23 -0
  105. package/dist/sync/orchestrator.d.ts.map +1 -1
  106. package/dist/sync/orchestrator.js +85 -1
  107. package/dist/sync/orchestrator.js.map +1 -1
  108. package/dist/sync/preflight.d.ts +1 -1
  109. package/dist/sync/preflight.d.ts.map +1 -1
  110. package/dist/sync/preflight.js +129 -17
  111. package/dist/sync/preflight.js.map +1 -1
  112. package/dist/sync/pull.d.ts +19 -0
  113. package/dist/sync/pull.d.ts.map +1 -1
  114. package/dist/sync/pull.js +169 -15
  115. package/dist/sync/pull.js.map +1 -1
  116. package/dist/sync/push.d.ts +7 -0
  117. package/dist/sync/push.d.ts.map +1 -1
  118. package/dist/sync/push.js +37 -10
  119. package/dist/sync/push.js.map +1 -1
  120. package/dist/sync/status.d.ts +4 -0
  121. package/dist/sync/status.d.ts.map +1 -1
  122. package/dist/sync/status.js +68 -4
  123. package/dist/sync/status.js.map +1 -1
  124. package/dist/utils/config.d.ts +25 -0
  125. package/dist/utils/config.d.ts.map +1 -1
  126. package/dist/utils/config.js +28 -2
  127. package/dist/utils/config.js.map +1 -1
  128. package/dist/utils/frontmatter.d.ts +1 -1
  129. package/dist/utils/frontmatter.d.ts.map +1 -1
  130. package/dist/utils/frontmatter.js +15 -4
  131. package/dist/utils/frontmatter.js.map +1 -1
  132. package/dist/utils/media-body-refs.d.ts +81 -0
  133. package/dist/utils/media-body-refs.d.ts.map +1 -0
  134. package/dist/utils/media-body-refs.js +240 -0
  135. package/dist/utils/media-body-refs.js.map +1 -0
  136. package/dist/utils/media-refs.d.ts +44 -0
  137. package/dist/utils/media-refs.d.ts.map +1 -0
  138. package/dist/utils/media-refs.js +101 -0
  139. package/dist/utils/media-refs.js.map +1 -0
  140. package/dist/utils/naming.d.ts +31 -0
  141. package/dist/utils/naming.d.ts.map +1 -1
  142. package/dist/utils/naming.js +58 -0
  143. package/dist/utils/naming.js.map +1 -1
  144. package/package.json +1 -1
@@ -0,0 +1,237 @@
1
+ import type { CacheDatabase } from '../../db/cache.js';
2
+ export declare const MEDIA_BINARY_EXTENSIONS: readonly ['.jpg', '.jpeg', '.png', '.webp', '.gif', '.avif', '.svg'];
3
+ export declare const MEDIA_LIST_PAGE_SIZE = 100;
4
+ export interface EmDashMediaItem {
5
+ id: string;
6
+ filename: string;
7
+ mimeType: string;
8
+ size: number;
9
+ width?: number | null;
10
+ height?: number | null;
11
+ alt?: string | null;
12
+ caption?: string | null;
13
+ url?: string;
14
+ storageKey?: string;
15
+ contentHash?: string | null;
16
+ status?: 'pending' | 'ready' | 'failed';
17
+ createdAt?: string;
18
+ }
19
+ /** Result of promoting a local draft image into the canonical `media/` layout. */
20
+ export interface PromotedMediaFile {
21
+ /** Workspace-relative path of the promoted binary, e.g. `media/<markdownRef>.png`. */
22
+ filePath: string;
23
+ /**
24
+ * Workspace-relative path of the shared stem for the binary and its companion YAML, e.g.
25
+ * `media/<markdownRef>`. Recorded as `media_state.markdown_ref` so a body storageKey resolves to this
26
+ * mirror without parsing a filename.
27
+ */
28
+ markdownRef: string;
29
+ }
30
+ export interface PromoteDraftMediaOptions {
31
+ workspaceRoot: string;
32
+ origin: string;
33
+ draftAbsPath: string;
34
+ item: EmDashMediaItem;
35
+ removeDraft?: boolean;
36
+ }
37
+ /** A body image reference whose media record could not be resolved. */
38
+ export interface OrphanMediaDescriptor {
39
+ /** The storageKey taken from the article body URL `/_emdash/api/media/file/<storageKey>`. */
40
+ storageKey: string;
41
+ /** ULID segment(s) found inside the storageKey, uppercased, in document order. */
42
+ ulids: string[];
43
+ ext: string;
44
+ }
45
+ /**
46
+ * A locally mirrored asset that can be used to re-verify a body storageKey without inventing remote
47
+ * data: the media/ companion YAML already records both the record id and the confirmed storageKey.
48
+ */
49
+ export interface LocalMediaMirrorCandidate {
50
+ /** Media record id read from the companion YAML (`id:`) or the canonical filename stem. */
51
+ mediaId: string;
52
+ /** The storageKey recorded by the companion YAML, when present. */
53
+ storageKey?: string;
54
+ /** Companion YAML file name relative to `media/`. */
55
+ metaFile: string;
56
+ }
57
+ /**
58
+ * A media mirror's on-disk identity under the storageKey naming rule.
59
+ *
60
+ * `markdownRef` is the stem both the binary and its companion YAML share, derived from the storageKey the
61
+ * article body references. `legacyBaseNames` enumerates every older stem this asset may still occupy — the
62
+ * un-prefixed `<id>-<name>` form and any `<yyyyMMdd>_<id>-<name>` form written by earlier Emit versions or
63
+ * by a local promotion with a provisional date — so one pull can rename an existing workspace into the new
64
+ * layout without re-downloading a byte.
65
+ */
66
+ export interface MediaMirrorNames {
67
+ markdownRef: string;
68
+ ext: string;
69
+ legacyBaseNames: string[];
70
+ }
71
+ export interface PullMediaOptions {
72
+ workspaceRoot: string;
73
+ origin: string;
74
+ token: string;
75
+ refreshToken?: string;
76
+ article?: string;
77
+ collection?: string;
78
+ limit?: number;
79
+ all?: boolean;
80
+ /** Mirror exactly these storageKeys, resolved from the library walk. */
81
+ storageKeys?: string[];
82
+ downloadFiles?: boolean;
83
+ prune?: boolean;
84
+ fetchFn?: typeof fetch;
85
+ /**
86
+ * Workspace cache. When provided, every mirrored asset is registered in `media_state` with its storageKey
87
+ * and mirror path, which is what lets a body reference resolve by index instead of by filename — mirrors
88
+ * are named after the storageKey and no longer carry the record id.
89
+ */
90
+ cache?: CacheDatabase;
91
+ }
92
+ export interface PullMediaResult {
93
+ total: number;
94
+ downloaded: number;
95
+ skipped: number;
96
+ deleted?: number;
97
+ /**
98
+ * Media ids that Emit could not mirror in this run. An article-targeted pull collects every ULID a
99
+ * body mentions, but a migrated corpus bakes the R2 `storageKey` into the body URL, and those ULIDs
100
+ * are media ids only by coincidence — so most of them resolve to nothing. That is a known shape of a
101
+ * migrated corpus, not an unresolved reference: for an article-targeted pull this field counts only
102
+ * references that failed every id lookup AND every storageKey check, and `unresolvedIds` below holds
103
+ * the ids that merely resolved to no record.
104
+ */
105
+ failed?: number;
106
+ /**
107
+ * Article-targeted pulls only: how many collected media ULIDs returned no record. Expected for a
108
+ * migrated corpus, where the body URL carries an R2 storageKey rather than a media id, so these are
109
+ * reported separately from `failed` and never presented as unresolved references.
110
+ */
111
+ unresolvedIds?: number;
112
+ articleId?: string;
113
+ mediaIds?: string[];
114
+ /**
115
+ * Body storageKeys confirmed by evidence Emit actually holds: the canonical lookup resolved a record
116
+ * under that ULID (its own storageKey may differ), or a local mirror companion already names it. Such
117
+ * a key is healthy and must never be escalated as missing.
118
+ */
119
+ verifiedStorageKeys?: string[];
120
+ /**
121
+ * Body storageKeys that neither a resolved record nor confirmed local metadata could match.
122
+ * Populated only for an article-targeted pull, where body references are inspected one by one.
123
+ */
124
+ orphanStorageKeys?: string[];
125
+ /**
126
+ * Total media records reported by the server (`totalCount` of the list operation) for a library-wide
127
+ * pull. Lets a user tell "this run covered N of M" apart from "the library has N items".
128
+ */
129
+ remoteTotalCount?: number | null;
130
+ /**
131
+ * StorageKeys referenced by workspace articles that no local mirror names and that a complete remote
132
+ * library walk also did not report. Populated only for `--all` pulls, where the walk is exhaustive.
133
+ */
134
+ referencedUnmirroredStorageKeys?: string[];
135
+ }
136
+ /**
137
+ * Reads the media library once and returns its full storageKey index.
138
+ *
139
+ * `GET /_emdash/api/media` accepts only `cursor`, `limit`, `page`, `mimeType`, `folderId`, `q`, and
140
+ * `includeUsage`, so a specific body reference cannot be looked up by key: the list operation is the
141
+ * only handle that reaches migrated assets, whose storageKey differs from the record id that
142
+ * `GET /_emdash/api/media/{id}` keys on. Every item in the response carries its own `storageKey` and
143
+ * the listing is cursor-bounded by `totalCount`, so one walk indexes the whole library. The response's
144
+ * `totalCount` is reported alongside the index so callers can tell "the key is absent from a complete
145
+ * library" apart from "the walk stopped early".
146
+ */
147
+ export interface RemoteStorageKeyIndex {
148
+ /** Every storageKey present in the remote media library, as reported by the list endpoint. */
149
+ storageKeys: Set<string>;
150
+ /** ULIDs of the records those keys belong to, for reporting a match as a record id. */
151
+ mediaIdsByStorageKey: Map<string, string>;
152
+ /**
153
+ * The full `EmDashMediaItem` each storageKey resolves to, exactly as the list endpoint reported it.
154
+ * These carry `filename`, `mimeType`, and `size` — everything `mediaMirrorNames()` needs to derive a
155
+ * mirror stem, collision suffix, and extension — so an article-driven mirror can reuse a walked record
156
+ * instead of fetching `GET /_emdash/api/media/{id}` again per asset. A walk that only builds the key set
157
+ * (doctor's coverage check) still populates this; nothing reads it unless a mirror stage asks for it.
158
+ */
159
+ recordsByStorageKey: Map<string, EmDashMediaItem>;
160
+ /** The same records keyed by their record id, so an article body that references a media id resolves too. */
161
+ recordsById: Map<string, EmDashMediaItem>;
162
+ /** `totalCount` reported by the server, or null when the response did not include it. */
163
+ totalCount: number | null;
164
+ /** True only when the walk finished without hitting `maxItems`. */
165
+ complete: boolean;
166
+ /**
167
+ * Records actually read from the list endpoint. Live EmDash reports no `totalCount` at all, so this
168
+ * walked count is the only figure a coverage report can state; it equals `storageKeys.size` unless a
169
+ * record repeated a key or lacked one.
170
+ */
171
+ scannedCount: number;
172
+ }
173
+ /** The set of storageKeys a mirror stage actually resolved to a walked record and mirrored. */
174
+ export interface MirroredAssetResult {
175
+ /** StorageKeys matched to a walked record and written to `media/` (binary + companion). */
176
+ mirroredStorageKeys: Set<string>;
177
+ /** How many of those were freshly downloaded versus already up-to-date on disk. */
178
+ downloaded: number;
179
+ skipped: number;
180
+ /**
181
+ * Referenced storageKeys no walked record mirrors, but confirmed evidence proves healthy: the walk stored
182
+ * that exact key, or a walked record / local mirror companion names the ULID baked into the key. Such a key
183
+ * is healthy and must never be escalated as missing.
184
+ */
185
+ verifiedStorageKeys: string[];
186
+ /**
187
+ * Referenced storageKeys that no walked record owns and no confirmed local mirror metadata names. A key
188
+ * whose ULID matches a record the walk resolved under that id is downgraded to `verifiedStorageKeys`,
189
+ * never escalated here — Emit mirrors records and never repairs server data.
190
+ */
191
+ orphanStorageKeys: string[];
192
+ }
193
+ /** One media-search hit, decorated with the local mirror state Emit actually holds. */
194
+ export interface MediaSearchHit {
195
+ /** D1 media record id (uppercase ULID). NEVER usable in a body URL. */
196
+ mediaId: string;
197
+ /** R2 storage key — the only value valid in `/_emdash/api/media/file/<storageKey>`. */
198
+ storageKey: string | null;
199
+ filename: string | null;
200
+ mimeType: string | null;
201
+ size: number | null;
202
+ alt: string | null;
203
+ caption: string | null;
204
+ createdAt?: string;
205
+ /** True when Emit already mirrors this asset (media_state or companion YAML confirms it). */
206
+ mirrored: boolean;
207
+ /** Workspace-relative mirror path (`media/<markdownRef>.<ext>`), null when not mirrored. */
208
+ localPath: string | null;
209
+ /** Which field matched the query, so an agent can read why a row was returned. */
210
+ matchedOn: Array<'filename' | 'alt' | 'caption' | 'storageKey' | 'mirrorStem'>;
211
+ }
212
+ export interface MediaSearchResult {
213
+ hits: MediaSearchHit[];
214
+ /** Records actually read from the list endpoint. */
215
+ scannedCount: number;
216
+ /** True only when the walk finished without hitting `maxScan`. Absence claims require this. */
217
+ walkComplete: boolean;
218
+ /** Server-reported totalCount when present (live EmDash reports none). */
219
+ totalCount: number | null;
220
+ /** True when hits were cut at `limit`. */
221
+ truncated: boolean;
222
+ /** Query as normalized for matching (lowercased), echoed so agents can audit. */
223
+ normalizedQuery: string;
224
+ }
225
+ export interface LocalMirrorEntry {
226
+ mediaId: string;
227
+ storageKey: string;
228
+ /** Workspace-relative binary path, read from media_state.markdown_ref / workspace_path. */
229
+ localPath: string | null;
230
+ /** Companion YAML metadata only — never guessed from a filename. */
231
+ filename: string | null;
232
+ alt: string | null;
233
+ caption: string | null;
234
+ }
235
+ /** storageKey -> mirror entry. Built from confirmed metadata sources only. */
236
+ export type LocalMirrorIndex = Map<string, LocalMirrorEntry>;
237
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/sync/media/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export const MEDIA_BINARY_EXTENSIONS = [
2
+ '.jpg',
3
+ '.jpeg',
4
+ '.png',
5
+ '.webp',
6
+ '.gif',
7
+ '.avif',
8
+ '.svg',
9
+ ];
10
+ export const MEDIA_LIST_PAGE_SIZE = 100;
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/sync/media/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;CACE,CAAC;AAEX,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC"}
@@ -1,75 +1,2 @@
1
- export interface EmDashMediaItem {
2
- id: string;
3
- filename: string;
4
- mimeType: string;
5
- size: number;
6
- width?: number | null;
7
- height?: number | null;
8
- alt?: string | null;
9
- caption?: string | null;
10
- url?: string;
11
- storageKey?: string;
12
- contentHash?: string | null;
13
- status?: 'pending' | 'ready' | 'failed';
14
- createdAt?: string;
15
- }
16
- export declare function buildMediaMetaDoc(item: EmDashMediaItem, origin: string, existingMeta?: Record<string, unknown> | null): Record<string, unknown>;
17
- export interface PromoteDraftMediaOptions {
18
- workspaceRoot: string;
19
- origin: string;
20
- draftAbsPath: string;
21
- item: EmDashMediaItem;
22
- removeDraft?: boolean;
23
- }
24
- /**
25
- * Promotes a local draft image from media/drafts/<name> into the canonical
26
- * media/<yyyyMMdd>_<mediaId>-<sanitizedName>.<ext> location alongside its .yaml metadata.
27
- * Returns the workspace-relative path of the promoted binary file.
28
- */
29
- export declare function promoteDraftMediaFile(options: PromoteDraftMediaOptions): string;
30
- /**
31
- * Collects all media ULIDs referenced by an article content (frontmatter featuredImage + body images).
32
- */
33
- export declare function collectArticleReferencedMediaIds(content: string): string[];
34
- export interface PullMediaOptions {
35
- workspaceRoot: string;
36
- origin: string;
37
- token: string;
38
- refreshToken?: string;
39
- article?: string;
40
- collection?: string;
41
- limit?: number;
42
- all?: boolean;
43
- downloadFiles?: boolean;
44
- prune?: boolean;
45
- fetchFn?: typeof fetch;
46
- }
47
- export interface PullMediaResult {
48
- total: number;
49
- downloaded: number;
50
- skipped: number;
51
- deleted?: number;
52
- failed?: number;
53
- articleId?: string;
54
- mediaIds?: string[];
55
- }
56
- /**
57
- * Pulls media referenced by a specific article (by ULID or file path).
58
- */
59
- export declare function pullArticleMedia(options: {
60
- workspaceRoot: string;
61
- origin: string;
62
- token: string;
63
- refreshToken?: string;
64
- article: string;
65
- collection?: string;
66
- downloadFiles?: boolean;
67
- fetchFn?: typeof fetch;
68
- }): Promise<PullMediaResult>;
69
- /**
70
- * Pulls media metadata and files from EmDash API into media/ directory with cursor pagination.
71
- * media/<id>-<filename>.yaml
72
- * media/<id>-<filename>.<ext>
73
- */
74
- export declare function pullMedia(options: PullMediaOptions): Promise<PullMediaResult>;
1
+ export * from './media/index.js';
75
2
  //# sourceMappingURL=media.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/sync/media.ts"],"names":[],"mappings":"AAsCA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,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,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,eAAe,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA4CD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA0C/E;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAwE1E;AAoID,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB,GAAG,OAAO,CAAC,eAAe,CAAC,CA2I3B;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAkInF"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/sync/media.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}