@artinstack/migrator 0.1.0

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/dist/index.js ADDED
@@ -0,0 +1,376 @@
1
+ import {
2
+ SMUGMUG_API_BASE,
3
+ SMUGMUG_OAUTH_ENDPOINTS,
4
+ SmugMugApiClient,
5
+ buildSmugMugAuthorizationHeader,
6
+ getAdapter,
7
+ readSmugMugCredentialsFromEnv,
8
+ signSmugMugOAuthRequest,
9
+ smugMugCredentialsSchema,
10
+ smugmugAdapter,
11
+ squarespaceAdapter,
12
+ wordpressAdapter
13
+ } from "./chunk-FXXKLYO5.js";
14
+ import "./chunk-2RWAXT6O.js";
15
+ import {
16
+ FALLBACK_ASSET_BYTES,
17
+ FilesystemMigrationSink,
18
+ MIGRATION_WRITE_STAGES,
19
+ SQUARESPACE_JSON_FORMAT,
20
+ SquarespaceCollectionClient,
21
+ analyzeConflicts,
22
+ buildJsonPrettyUrl,
23
+ buildMigrationReport,
24
+ buildRedirectMap,
25
+ bundleToCombinedJson,
26
+ createFilesystemMigrationSink,
27
+ detectRedirectLoops,
28
+ emptyConflictReport,
29
+ estimateStorage,
30
+ hasBlockingConflicts,
31
+ hasWarnings,
32
+ mapJsonPrettyWire,
33
+ portfolioMediaMatchesBundle,
34
+ rewriteInlineImages,
35
+ runDryRun,
36
+ runMigration,
37
+ runMigrationFromBundle,
38
+ staleUrlsFromEstimate,
39
+ writeFilesystemExport
40
+ } from "./chunk-LKNIQQJO.js";
41
+ import {
42
+ buildPortfolioMediaLinks,
43
+ bundleCounts,
44
+ collectEntities,
45
+ emptyBundle,
46
+ entityKey,
47
+ isTerminalState,
48
+ shouldProcessEntity
49
+ } from "./chunk-JKDRTL24.js";
50
+
51
+ // src/transformers/html-to-grapes/index.ts
52
+ import * as cheerio from "cheerio";
53
+
54
+ // src/transformers/css-to-styles/index.ts
55
+ function stripCssComments(css) {
56
+ return css.replace(/\/\*[\s\S]*?\*\//g, "");
57
+ }
58
+ function parseDeclarations(block) {
59
+ const style = {};
60
+ for (const declaration of block.split(";")) {
61
+ const trimmed = declaration.trim();
62
+ if (!trimmed) continue;
63
+ const separator = trimmed.indexOf(":");
64
+ if (separator === -1) continue;
65
+ const property = trimmed.slice(0, separator).trim();
66
+ const value = trimmed.slice(separator + 1).trim();
67
+ if (!property || !value) continue;
68
+ style[property] = value;
69
+ }
70
+ return style;
71
+ }
72
+ function cssToStyles(css) {
73
+ const cleaned = stripCssComments(css);
74
+ const rules = [];
75
+ const rulePattern = /([^{]+)\{([^}]*)\}/g;
76
+ for (const match of cleaned.matchAll(rulePattern)) {
77
+ const selectorText = match[1]?.trim() ?? "";
78
+ const declarationBlock = match[2] ?? "";
79
+ if (!selectorText || selectorText.startsWith("@")) continue;
80
+ const style = parseDeclarations(declarationBlock);
81
+ if (Object.keys(style).length === 0) continue;
82
+ const selectors = selectorText.split(",").map((selector) => selector.trim()).filter(Boolean);
83
+ if (selectors.length === 0) continue;
84
+ rules.push({ selectors, style });
85
+ }
86
+ return rules;
87
+ }
88
+
89
+ // src/transformers/html-to-grapes/walk.ts
90
+ var INLINE_TAGS = /* @__PURE__ */ new Set([
91
+ "a",
92
+ "abbr",
93
+ "b",
94
+ "br",
95
+ "cite",
96
+ "code",
97
+ "del",
98
+ "em",
99
+ "i",
100
+ "img",
101
+ "ins",
102
+ "mark",
103
+ "q",
104
+ "s",
105
+ "small",
106
+ "span",
107
+ "strong",
108
+ "sub",
109
+ "sup",
110
+ "u",
111
+ "wbr"
112
+ ]);
113
+ var VOID_TAGS = /* @__PURE__ */ new Set([
114
+ "area",
115
+ "base",
116
+ "br",
117
+ "col",
118
+ "embed",
119
+ "hr",
120
+ "img",
121
+ "input",
122
+ "link",
123
+ "meta",
124
+ "param",
125
+ "source",
126
+ "track",
127
+ "wbr"
128
+ ]);
129
+ var TEXT_CONTAINER_TAGS = /* @__PURE__ */ new Set([
130
+ "blockquote",
131
+ "figcaption",
132
+ "h1",
133
+ "h2",
134
+ "h3",
135
+ "h4",
136
+ "h5",
137
+ "h6",
138
+ "label",
139
+ "li",
140
+ "p",
141
+ "pre",
142
+ "td",
143
+ "th"
144
+ ]);
145
+ var SKIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "noscript", "template"]);
146
+ var DEFAULT_TYPES = {
147
+ a: "link",
148
+ img: "image"
149
+ };
150
+ function tagNameOf($el) {
151
+ const raw = $el.prop("tagName");
152
+ return typeof raw === "string" ? raw.toLowerCase() : void 0;
153
+ }
154
+ function applyElementMeta(component, meta) {
155
+ if (meta.attributes) component.attributes = meta.attributes;
156
+ if (meta.classes) component.classes = meta.classes;
157
+ return component;
158
+ }
159
+ function pickElementMeta($el) {
160
+ const attributes = {};
161
+ const classes = [];
162
+ if (typeof $el.attr() === "object") {
163
+ for (const [key, value] of Object.entries($el.attr() ?? {})) {
164
+ if (key === "class") {
165
+ classes.push(...value.split(/\s+/).filter(Boolean));
166
+ continue;
167
+ }
168
+ attributes[key] = value;
169
+ }
170
+ }
171
+ return {
172
+ attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
173
+ classes: classes.length > 0 ? classes : void 0
174
+ };
175
+ }
176
+ function resolveComponentType(tagName, classes, options) {
177
+ if (options.componentMap && classes) {
178
+ for (const className of classes) {
179
+ const mapped = options.componentMap[className];
180
+ if (mapped) return mapped;
181
+ }
182
+ }
183
+ return DEFAULT_TYPES[tagName] ?? "default";
184
+ }
185
+ function hasOnlyInlineContent($, $el) {
186
+ let inlineOnly = true;
187
+ $el.contents().each((_, node) => {
188
+ if (!inlineOnly) return;
189
+ const $child = $(node);
190
+ if ($child.get(0)?.type === "text") return;
191
+ const childTag = tagNameOf($child);
192
+ if (!childTag || !INLINE_TAGS.has(childTag)) {
193
+ inlineOnly = false;
194
+ return;
195
+ }
196
+ if (!hasOnlyInlineContent($, $child)) {
197
+ inlineOnly = false;
198
+ }
199
+ });
200
+ return inlineOnly;
201
+ }
202
+ function walkChildren($, $el, options) {
203
+ const components = [];
204
+ $el.contents().each((_, node) => {
205
+ const walked = walkNode($, $(node), options);
206
+ if (!walked) return;
207
+ if (Array.isArray(walked)) {
208
+ components.push(...walked);
209
+ } else {
210
+ components.push(walked);
211
+ }
212
+ });
213
+ return components;
214
+ }
215
+ function walkNode($, $el, options) {
216
+ const node = $el.get(0);
217
+ if (!node) return null;
218
+ if (node.type === "text") {
219
+ const text = "data" in node ? String(node.data ?? "") : "";
220
+ if (!text.trim()) return null;
221
+ return { type: "textnode", content: text };
222
+ }
223
+ if (node.type !== "tag") return null;
224
+ const tagName = tagNameOf($el);
225
+ if (!tagName || SKIP_TAGS.has(tagName)) return null;
226
+ const meta = pickElementMeta($el);
227
+ if (VOID_TAGS.has(tagName)) {
228
+ return applyElementMeta(
229
+ {
230
+ type: resolveComponentType(tagName, meta.classes, options),
231
+ tagName,
232
+ void: true
233
+ },
234
+ meta
235
+ );
236
+ }
237
+ if (TEXT_CONTAINER_TAGS.has(tagName) && hasOnlyInlineContent($, $el)) {
238
+ return applyElementMeta(
239
+ {
240
+ type: "text",
241
+ tagName,
242
+ content: $el.html() ?? ""
243
+ },
244
+ meta
245
+ );
246
+ }
247
+ if (INLINE_TAGS.has(tagName)) {
248
+ return applyElementMeta(
249
+ {
250
+ type: "text",
251
+ content: $.html($el) ?? ""
252
+ },
253
+ meta
254
+ );
255
+ }
256
+ const components = walkChildren($, $el, options);
257
+ const component = applyElementMeta(
258
+ {
259
+ type: resolveComponentType(tagName, meta.classes, options),
260
+ tagName
261
+ },
262
+ meta
263
+ );
264
+ if (components.length > 0) {
265
+ component.components = components;
266
+ }
267
+ return component;
268
+ }
269
+ function appendWalked(content, walked) {
270
+ if (!walked) return;
271
+ if (Array.isArray(walked)) {
272
+ content.push(...walked);
273
+ return;
274
+ }
275
+ content.push(walked);
276
+ }
277
+ function walkNodes($, $nodes, content, options) {
278
+ $nodes.each((_, node) => {
279
+ appendWalked(content, walkNode($, $(node), options));
280
+ });
281
+ }
282
+ function walkHtmlToComponents($, options = {}) {
283
+ const content = [];
284
+ const body = $("body");
285
+ if (body.length) {
286
+ walkNodes($, body.contents(), content, options);
287
+ return content;
288
+ }
289
+ const children = $.root().children();
290
+ if (children.length) {
291
+ walkNodes($, children, content, options);
292
+ } else {
293
+ walkNodes($, $.root().contents(), content, options);
294
+ }
295
+ return content;
296
+ }
297
+
298
+ // src/transformers/html-to-grapes/index.ts
299
+ function htmlToGrapes(html, options = {}) {
300
+ const trimmed = html.trim();
301
+ if (!trimmed) {
302
+ return { content: [], styles: [] };
303
+ }
304
+ const $ = cheerio.load(trimmed, { xml: false });
305
+ const styleBlocks = [];
306
+ $("style").each((_, element) => {
307
+ styleBlocks.push($(element).html() ?? "");
308
+ $(element).remove();
309
+ });
310
+ const contentCss = styleBlocks.join("\n").trim();
311
+ const styles = cssToStyles(contentCss);
312
+ const content = walkHtmlToComponents($, options);
313
+ const contentHtml = serializeContentHtml($);
314
+ return {
315
+ content,
316
+ styles,
317
+ ...contentHtml ? { contentHtml } : {},
318
+ ...contentCss ? { contentCss } : {}
319
+ };
320
+ }
321
+ function serializeContentHtml($) {
322
+ const body = $("body");
323
+ if (body.length) {
324
+ const html = body.html()?.trim();
325
+ return html || void 0;
326
+ }
327
+ const rootHtml = $.root().html()?.trim();
328
+ return rootHtml || void 0;
329
+ }
330
+ export {
331
+ FALLBACK_ASSET_BYTES,
332
+ FilesystemMigrationSink,
333
+ MIGRATION_WRITE_STAGES,
334
+ SMUGMUG_API_BASE,
335
+ SMUGMUG_OAUTH_ENDPOINTS,
336
+ SQUARESPACE_JSON_FORMAT,
337
+ SmugMugApiClient,
338
+ SquarespaceCollectionClient,
339
+ analyzeConflicts,
340
+ buildJsonPrettyUrl,
341
+ buildMigrationReport,
342
+ buildPortfolioMediaLinks,
343
+ buildRedirectMap,
344
+ buildSmugMugAuthorizationHeader,
345
+ bundleCounts,
346
+ bundleToCombinedJson,
347
+ collectEntities,
348
+ createFilesystemMigrationSink,
349
+ cssToStyles,
350
+ detectRedirectLoops,
351
+ emptyBundle,
352
+ emptyConflictReport,
353
+ entityKey,
354
+ estimateStorage,
355
+ getAdapter,
356
+ hasBlockingConflicts,
357
+ hasWarnings,
358
+ htmlToGrapes,
359
+ isTerminalState,
360
+ mapJsonPrettyWire,
361
+ portfolioMediaMatchesBundle,
362
+ readSmugMugCredentialsFromEnv,
363
+ rewriteInlineImages,
364
+ runDryRun,
365
+ runMigration,
366
+ runMigrationFromBundle,
367
+ shouldProcessEntity,
368
+ signSmugMugOAuthRequest,
369
+ smugMugCredentialsSchema,
370
+ smugmugAdapter,
371
+ squarespaceAdapter,
372
+ staleUrlsFromEstimate,
373
+ wordpressAdapter,
374
+ writeFilesystemExport
375
+ };
376
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/transformers/html-to-grapes/index.ts","../src/transformers/css-to-styles/index.ts","../src/transformers/html-to-grapes/walk.ts"],"sourcesContent":["import * as cheerio from \"cheerio\";\n\nimport { cssToStyles } from \"../css-to-styles/index.js\";\nimport type { GrapesProjectSnapshot, HtmlToGrapesOptions } from \"./types.js\";\nimport { walkHtmlToComponents } from \"./walk.js\";\n\nexport type {\n GrapesComponent,\n GrapesProjectSnapshot,\n GrapesStyleRule,\n HtmlToGrapesOptions,\n} from \"./types.js\";\n\n/** Cheerio HTML walk → Grapes `content` + root `styles`. */\nexport function htmlToGrapes(html: string, options: HtmlToGrapesOptions = {}): GrapesProjectSnapshot {\n const trimmed = html.trim();\n if (!trimmed) {\n return { content: [], styles: [] };\n }\n\n const $ = cheerio.load(trimmed, { xml: false });\n const styleBlocks: string[] = [];\n\n $(\"style\").each((_, element) => {\n styleBlocks.push($(element).html() ?? \"\");\n $(element).remove();\n });\n\n const contentCss = styleBlocks.join(\"\\n\").trim();\n const styles = cssToStyles(contentCss);\n const content = walkHtmlToComponents($, options);\n const contentHtml = serializeContentHtml($);\n\n return {\n content,\n styles,\n ...(contentHtml ? { contentHtml } : {}),\n ...(contentCss ? { contentCss } : {}),\n };\n}\n\nfunction serializeContentHtml($: cheerio.CheerioAPI): string | undefined {\n const body = $(\"body\");\n if (body.length) {\n const html = body.html()?.trim();\n return html || undefined;\n }\n\n const rootHtml = $.root().html()?.trim();\n return rootHtml || undefined;\n}\n","import type { GrapesStyleRule } from \"../html-to-grapes/types.js\";\n\nfunction stripCssComments(css: string): string {\n return css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n}\n\nfunction parseDeclarations(block: string): Record<string, string> {\n const style: Record<string, string> = {};\n for (const declaration of block.split(\";\")) {\n const trimmed = declaration.trim();\n if (!trimmed) continue;\n const separator = trimmed.indexOf(\":\");\n if (separator === -1) continue;\n const property = trimmed.slice(0, separator).trim();\n const value = trimmed.slice(separator + 1).trim();\n if (!property || !value) continue;\n style[property] = value;\n }\n return style;\n}\n\n/** Parse `<style>` blocks and class rules into Grapes root `styles[]`. */\nexport function cssToStyles(css: string): GrapesStyleRule[] {\n const cleaned = stripCssComments(css);\n const rules: GrapesStyleRule[] = [];\n const rulePattern = /([^{]+)\\{([^}]*)\\}/g;\n\n for (const match of cleaned.matchAll(rulePattern)) {\n const selectorText = match[1]?.trim() ?? \"\";\n const declarationBlock = match[2] ?? \"\";\n if (!selectorText || selectorText.startsWith(\"@\")) continue;\n\n const style = parseDeclarations(declarationBlock);\n if (Object.keys(style).length === 0) continue;\n\n const selectors = selectorText\n .split(\",\")\n .map((selector) => selector.trim())\n .filter(Boolean);\n\n if (selectors.length === 0) continue;\n rules.push({ selectors, style });\n }\n\n return rules;\n}\n","import type { Cheerio, CheerioAPI } from \"cheerio\";\nimport type { AnyNode } from \"domhandler\";\n\nimport type { GrapesComponent, HtmlToGrapesOptions } from \"./types.js\";\n\ntype CheerioSelection = Cheerio<AnyNode>;\n\nconst INLINE_TAGS = new Set([\n \"a\",\n \"abbr\",\n \"b\",\n \"br\",\n \"cite\",\n \"code\",\n \"del\",\n \"em\",\n \"i\",\n \"img\",\n \"ins\",\n \"mark\",\n \"q\",\n \"s\",\n \"small\",\n \"span\",\n \"strong\",\n \"sub\",\n \"sup\",\n \"u\",\n \"wbr\",\n]);\n\nconst VOID_TAGS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"param\",\n \"source\",\n \"track\",\n \"wbr\",\n]);\n\nconst TEXT_CONTAINER_TAGS = new Set([\n \"blockquote\",\n \"figcaption\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"label\",\n \"li\",\n \"p\",\n \"pre\",\n \"td\",\n \"th\",\n]);\n\nconst SKIP_TAGS = new Set([\"script\", \"style\", \"noscript\", \"template\"]);\n\nconst DEFAULT_TYPES: Record<string, string> = {\n a: \"link\",\n img: \"image\",\n};\n\nfunction tagNameOf($el: CheerioSelection): string | undefined {\n const raw = $el.prop(\"tagName\");\n return typeof raw === \"string\" ? raw.toLowerCase() : undefined;\n}\n\nfunction applyElementMeta(\n component: GrapesComponent,\n meta: Pick<GrapesComponent, \"attributes\" | \"classes\">,\n): GrapesComponent {\n if (meta.attributes) component.attributes = meta.attributes;\n if (meta.classes) component.classes = meta.classes;\n return component;\n}\n\nfunction pickElementMeta($el: CheerioSelection): Pick<GrapesComponent, \"attributes\" | \"classes\"> {\n const attributes: Record<string, string> = {};\n const classes: string[] = [];\n\n if (typeof $el.attr() === \"object\") {\n for (const [key, value] of Object.entries($el.attr() ?? {})) {\n if (key === \"class\") {\n classes.push(...value.split(/\\s+/).filter(Boolean));\n continue;\n }\n attributes[key] = value;\n }\n }\n\n return {\n attributes: Object.keys(attributes).length > 0 ? attributes : undefined,\n classes: classes.length > 0 ? classes : undefined,\n };\n}\n\nfunction resolveComponentType(\n tagName: string,\n classes: string[] | undefined,\n options: HtmlToGrapesOptions,\n): string {\n if (options.componentMap && classes) {\n for (const className of classes) {\n const mapped = options.componentMap[className];\n if (mapped) return mapped;\n }\n }\n return DEFAULT_TYPES[tagName] ?? \"default\";\n}\n\nfunction hasOnlyInlineContent($: CheerioAPI, $el: CheerioSelection): boolean {\n let inlineOnly = true;\n\n $el.contents().each((_, node) => {\n if (!inlineOnly) return;\n const $child = $(node);\n if ($child.get(0)?.type === \"text\") return;\n const childTag = tagNameOf($child);\n if (!childTag || !INLINE_TAGS.has(childTag)) {\n inlineOnly = false;\n return;\n }\n if (!hasOnlyInlineContent($, $child)) {\n inlineOnly = false;\n }\n });\n\n return inlineOnly;\n}\n\nfunction walkChildren(\n $: CheerioAPI,\n $el: CheerioSelection,\n options: HtmlToGrapesOptions,\n): GrapesComponent[] {\n const components: GrapesComponent[] = [];\n\n $el.contents().each((_, node) => {\n const walked = walkNode($, $(node), options);\n if (!walked) return;\n if (Array.isArray(walked)) {\n components.push(...walked);\n } else {\n components.push(walked);\n }\n });\n\n return components;\n}\n\nfunction walkNode(\n $: CheerioAPI,\n $el: CheerioSelection,\n options: HtmlToGrapesOptions,\n): GrapesComponent | GrapesComponent[] | null {\n const node = $el.get(0);\n if (!node) return null;\n\n if (node.type === \"text\") {\n const text = \"data\" in node ? String(node.data ?? \"\") : \"\";\n if (!text.trim()) return null;\n return { type: \"textnode\", content: text };\n }\n\n if (node.type !== \"tag\") return null;\n\n const tagName = tagNameOf($el);\n if (!tagName || SKIP_TAGS.has(tagName)) return null;\n\n const meta = pickElementMeta($el);\n\n if (VOID_TAGS.has(tagName)) {\n return applyElementMeta(\n {\n type: resolveComponentType(tagName, meta.classes, options),\n tagName,\n void: true,\n },\n meta,\n );\n }\n\n if (TEXT_CONTAINER_TAGS.has(tagName) && hasOnlyInlineContent($, $el)) {\n return applyElementMeta(\n {\n type: \"text\",\n tagName,\n content: $el.html() ?? \"\",\n },\n meta,\n );\n }\n\n if (INLINE_TAGS.has(tagName)) {\n return applyElementMeta(\n {\n type: \"text\",\n content: $.html($el) ?? \"\",\n },\n meta,\n );\n }\n\n const components = walkChildren($, $el, options);\n const component = applyElementMeta(\n {\n type: resolveComponentType(tagName, meta.classes, options),\n tagName,\n },\n meta,\n );\n\n if (components.length > 0) {\n component.components = components;\n }\n\n return component;\n}\n\nfunction appendWalked(\n content: GrapesComponent[],\n walked: GrapesComponent | GrapesComponent[] | null,\n): void {\n if (!walked) return;\n if (Array.isArray(walked)) {\n content.push(...walked);\n return;\n }\n content.push(walked);\n}\n\nfunction walkNodes(\n $: CheerioAPI,\n $nodes: CheerioSelection,\n content: GrapesComponent[],\n options: HtmlToGrapesOptions,\n): void {\n $nodes.each((_, node) => {\n appendWalked(content, walkNode($, $(node), options));\n });\n}\n\nexport function walkHtmlToComponents(\n $: CheerioAPI,\n options: HtmlToGrapesOptions = {},\n): GrapesComponent[] {\n const content: GrapesComponent[] = [];\n const body = $(\"body\");\n\n if (body.length) {\n walkNodes($, body.contents(), content, options);\n return content;\n }\n\n const children = $.root().children();\n if (children.length) {\n walkNodes($, children, content, options);\n } else {\n walkNodes($, $.root().contents(), content, options);\n }\n\n return content;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,23 @@
1
+ import { d as MigrationCursor, b as EntityKey, E as EntityBundle, P as PortfolioMediaLink } from '../bundle-BfZqiKV_.js';
2
+ export { A as AdapterContext, B as BundleCounts, c as EntityType, M as MigrationAdapter, a as MigrationPlatform, N as NormalizedAsset, e as NormalizedAssetExif, f as NormalizedCategory, g as NormalizedEntity, h as NormalizedPage, i as NormalizedPortfolio, j as NormalizedPost, k as NormalizedTag, l as PublishStatus, S as SourceMetadata, V as ValidationIssue, m as ValidationResult, n as bundleCounts, o as collectEntities, p as emptyBundle, q as entityKey } from '../bundle-BfZqiKV_.js';
3
+
4
+ /** Portable entity state for resume / idempotency (not Directus field names). */
5
+ type EntityState = "pending" | "done" | "failed" | "skipped";
6
+ interface TrackedEntity extends EntityKey {
7
+ state: EntityState;
8
+ targetId?: string;
9
+ errorMessage?: string;
10
+ }
11
+ interface MigrationCheckpoint {
12
+ jobId: string;
13
+ cursor: MigrationCursor;
14
+ entities: TrackedEntity[];
15
+ updatedAt: string;
16
+ }
17
+ declare function isTerminalState(state: EntityState): boolean;
18
+ declare function shouldProcessEntity(key: EntityKey, entities: TrackedEntity[]): boolean;
19
+
20
+ /** Derive portfolio↔asset M2M rows from assets carrying `portfolioSourceId`. */
21
+ declare function buildPortfolioMediaLinks(bundle: EntityBundle): PortfolioMediaLink[];
22
+
23
+ export { EntityBundle, EntityKey, type EntityState, type MigrationCheckpoint, MigrationCursor, PortfolioMediaLink, type TrackedEntity, buildPortfolioMediaLinks, isTerminalState, shouldProcessEntity };
@@ -0,0 +1,20 @@
1
+ import "../chunk-2RWAXT6O.js";
2
+ import {
3
+ buildPortfolioMediaLinks,
4
+ bundleCounts,
5
+ collectEntities,
6
+ emptyBundle,
7
+ entityKey,
8
+ isTerminalState,
9
+ shouldProcessEntity
10
+ } from "../chunk-JKDRTL24.js";
11
+ export {
12
+ buildPortfolioMediaLinks,
13
+ bundleCounts,
14
+ collectEntities,
15
+ emptyBundle,
16
+ entityKey,
17
+ isTerminalState,
18
+ shouldProcessEntity
19
+ };
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,3 @@
1
+ export { C as ConflictReport, D as DryRunOptions, a as DryRunResult, F as FALLBACK_ASSET_BYTES, b as FilesystemMigrationSink, M as MIGRATION_WRITE_STAGES, c as MigrationRedirect, d as MigrationReport, e as MigrationRunMode, f as MigrationRunOptions, g as MigrationRunResult, h as MigrationSink, i as MigrationWriteStage, j as RewriteInlineImagesOptions, k as RewriteInlineImagesResult, S as StorageEstimate, U as UploadAssetInput, l as UploadAssetResult, W as WriteFilesystemOptions, n as analyzeConflicts, o as buildMigrationReport, p as buildRedirectMap, q as bundleToCombinedJson, r as createFilesystemMigrationSink, s as detectRedirectLoops, t as emptyConflictReport, u as estimateStorage, v as hasBlockingConflicts, w as hasWarnings, x as portfolioMediaMatchesBundle, y as rewriteInlineImages, z as runDryRun, A as runMigration, B as runMigrationFromBundle, E as staleUrlsFromEstimate, G as writeFilesystemExport } from '../index-DQNzrygx.js';
2
+ import '../bundle-BfZqiKV_.js';
3
+ import 'node:stream';
@@ -0,0 +1,46 @@
1
+ import {
2
+ FALLBACK_ASSET_BYTES,
3
+ FilesystemMigrationSink,
4
+ MIGRATION_WRITE_STAGES,
5
+ analyzeConflicts,
6
+ buildMigrationReport,
7
+ buildRedirectMap,
8
+ bundleToCombinedJson,
9
+ createFilesystemMigrationSink,
10
+ detectRedirectLoops,
11
+ emptyConflictReport,
12
+ estimateStorage,
13
+ hasBlockingConflicts,
14
+ hasWarnings,
15
+ portfolioMediaMatchesBundle,
16
+ rewriteInlineImages,
17
+ runDryRun,
18
+ runMigration,
19
+ runMigrationFromBundle,
20
+ staleUrlsFromEstimate,
21
+ writeFilesystemExport
22
+ } from "../chunk-LKNIQQJO.js";
23
+ import "../chunk-JKDRTL24.js";
24
+ export {
25
+ FALLBACK_ASSET_BYTES,
26
+ FilesystemMigrationSink,
27
+ MIGRATION_WRITE_STAGES,
28
+ analyzeConflicts,
29
+ buildMigrationReport,
30
+ buildRedirectMap,
31
+ bundleToCombinedJson,
32
+ createFilesystemMigrationSink,
33
+ detectRedirectLoops,
34
+ emptyConflictReport,
35
+ estimateStorage,
36
+ hasBlockingConflicts,
37
+ hasWarnings,
38
+ portfolioMediaMatchesBundle,
39
+ rewriteInlineImages,
40
+ runDryRun,
41
+ runMigration,
42
+ runMigrationFromBundle,
43
+ staleUrlsFromEstimate,
44
+ writeFilesystemExport
45
+ };
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@artinstack/migrator",
3
+ "version": "0.1.0",
4
+ "description": "Stateless content normalizer and migration framework — WordPress, SmugMug, Squarespace → platform-agnostic schema",
5
+ "license": "MIT",
6
+ "author": "ArtInStack",
7
+ "homepage": "https://github.com/naikondev/artinstack-migrator#readme",
8
+ "bugs": {
9
+ "url": "https://github.com/naikondev/artinstack-migrator/issues"
10
+ },
11
+ "keywords": [
12
+ "migration",
13
+ "wordpress",
14
+ "smugmug",
15
+ "squarespace",
16
+ "content",
17
+ "normalizer",
18
+ "wxr",
19
+ "grapesjs"
20
+ ],
21
+ "type": "module",
22
+ "sideEffects": false,
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/naikondev/artinstack-migrator.git"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public",
29
+ "registry": "https://registry.npmjs.org/"
30
+ },
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js"
37
+ },
38
+ "./normalizer": {
39
+ "types": "./dist/normalizer/index.d.ts",
40
+ "import": "./dist/normalizer/index.js"
41
+ },
42
+ "./sinks": {
43
+ "types": "./dist/sinks/index.d.ts",
44
+ "import": "./dist/sinks/index.js"
45
+ }
46
+ },
47
+ "bin": {
48
+ "artinstack-migrate": "./dist/cli/index.js"
49
+ },
50
+ "files": [
51
+ "dist",
52
+ "README.md",
53
+ "LICENSE"
54
+ ],
55
+ "engines": {
56
+ "node": ">=20"
57
+ },
58
+ "dependencies": {
59
+ "cheerio": "^1.0.0",
60
+ "domhandler": "^5.0.3",
61
+ "fast-xml-parser": "^5.8.0",
62
+ "zod": "^3.23.8"
63
+ },
64
+ "devDependencies": {
65
+ "@types/node": "^20.0.0",
66
+ "tsup": "^8.4.0",
67
+ "typescript": "^5.4.5",
68
+ "vitest": "^3.0.0"
69
+ },
70
+ "scripts": {
71
+ "build": "tsup",
72
+ "dev": "tsup --watch",
73
+ "typecheck": "tsc --noEmit",
74
+ "test": "vitest run",
75
+ "test:validate-fixtures": "vitest run fixtures",
76
+ "test:watch": "vitest",
77
+ "cli": "node dist/cli/index.js",
78
+ "migrate": "node dist/cli/index.js"
79
+ }
80
+ }