sb-mig 6.2.0 → 6.3.0-beta.2
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/README.md +15 -4
- package/dist/api/assets/asset-folders.d.ts +3 -0
- package/dist/api/assets/asset-folders.js +56 -0
- package/dist/api/assets/asset-folders.types.d.ts +29 -0
- package/dist/api/assets/asset-folders.types.js +1 -0
- package/dist/api/assets/assets.d.ts +4 -1
- package/dist/api/assets/assets.js +61 -16
- package/dist/api/assets/assets.types.d.ts +12 -1
- package/dist/api/assets/index.d.ts +4 -2
- package/dist/api/assets/index.js +2 -1
- package/dist/api/copy/assets.d.ts +12 -0
- package/dist/api/copy/assets.js +84 -0
- package/dist/api/copy/graph.d.ts +8 -0
- package/dist/api/copy/graph.js +27 -0
- package/dist/api/copy/index.d.ts +6 -0
- package/dist/api/copy/index.js +6 -0
- package/dist/api/copy/manifest.d.ts +23 -0
- package/dist/api/copy/manifest.js +115 -0
- package/dist/api/copy/reference-rewriter.d.ts +6 -0
- package/dist/api/copy/reference-rewriter.js +153 -0
- package/dist/api/copy/reference-scanner.d.ts +23 -0
- package/dist/api/copy/reference-scanner.js +322 -0
- package/dist/api/copy/types.d.ts +196 -0
- package/dist/api/copy/types.js +1 -0
- package/dist/api/data-migration/component-data-migration.d.ts +81 -0
- package/dist/api/data-migration/component-data-migration.js +391 -95
- package/dist/api/data-migration/migration-run-log.d.ts +3 -1
- package/dist/api/data-migration/migration-run-log.js +2 -1
- package/dist/api/managementApi.d.ts +6 -0
- package/dist/api/stories/stories.js +3 -3
- package/dist/api/stories/stories.types.d.ts +3 -1
- package/dist/api/testApi.d.ts +6 -0
- package/dist/api-v2/requestConfig.d.ts +17 -1
- package/dist/api-v2/requestConfig.js +28 -0
- package/dist/cli/cli-descriptions.d.ts +3 -3
- package/dist/cli/cli-descriptions.js +92 -18
- package/dist/cli/commands/copy.js +2091 -145
- package/dist/cli/commands/migrate.js +27 -1
- package/dist/cli/index.js +3 -0
- package/dist/utils/files.d.ts +2 -0
- package/dist/utils/files.js +86 -3
- package/dist-cjs/api/stories/stories.js +3 -3
- package/dist-cjs/api-v2/requestConfig.js +29 -0
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import { migrateAllComponentsDataInStories, migrateProvidedComponentsDataInStories, } from "../../api/data-migration/component-data-migration.js";
|
|
2
|
+
import { migrateAllComponentsDataInStories, migrateProvidedComponentsDataInStories, prepareContinueMigration, } from "../../api/data-migration/component-data-migration.js";
|
|
3
3
|
import { buildStoryBackupBaseName } from "../../api/data-migration/file-naming.js";
|
|
4
4
|
import { parseMigrationComponentAliasFlags, parseMigrationComponentOverrideFlags, } from "../../api/data-migration/migration-component-scope.js";
|
|
5
5
|
import { managementApi } from "../../api/managementApi.js";
|
|
@@ -13,6 +13,7 @@ import { isItFactory, unpackElements, getFrom, getTo, } from "../utils/cli-utils
|
|
|
13
13
|
const MIGRATE_COMMANDS = {
|
|
14
14
|
content: "content",
|
|
15
15
|
presets: "presets",
|
|
16
|
+
continue: "continue",
|
|
16
17
|
};
|
|
17
18
|
const normalizeMigrationFlags = (migrationFlag) => {
|
|
18
19
|
if (Array.isArray(migrationFlag)) {
|
|
@@ -280,6 +281,31 @@ export const migrate = async (props) => {
|
|
|
280
281
|
}
|
|
281
282
|
break;
|
|
282
283
|
}
|
|
284
|
+
case MIGRATE_COMMANDS.continue: {
|
|
285
|
+
const manifestFileName = flags["manifest"];
|
|
286
|
+
const plan = await prepareContinueMigration({ manifestFileName }, apiConfig);
|
|
287
|
+
const { summary } = plan;
|
|
288
|
+
Logger.log("Found dry-run to continue:");
|
|
289
|
+
console.log(` manifest: ${summary.manifestFileName}`);
|
|
290
|
+
console.log(` space (from→to): ${summary.from} → ${summary.to}`);
|
|
291
|
+
console.log(` publication mode: ${summary.publicationMode}`);
|
|
292
|
+
console.log(` migrations: ${summary.migrationConfigNames.join(", ") || "(none recorded)"}`);
|
|
293
|
+
if (summary.resolvedPublishLanguages.length > 0) {
|
|
294
|
+
console.log(` languages: ${summary.resolvedPublishLanguages.join(", ")}`);
|
|
295
|
+
}
|
|
296
|
+
console.log(` ${summary.itemType}s to write: ${summary.changedCount} changed${summary.dirtyPublishedCount > 0
|
|
297
|
+
? ` (${summary.dirtyPublishedCount} dirty-published dual-layer write(s))`
|
|
298
|
+
: ""}`);
|
|
299
|
+
console.log(" using artifacts:");
|
|
300
|
+
summary.artifactFiles.forEach((file) => console.log(` - ${file}`));
|
|
301
|
+
console.log(" ");
|
|
302
|
+
await askForConfirmation(`Continue and write these to Storyblok space ${summary.to}? (it will overwrite ${summary.itemType}s)`, async () => {
|
|
303
|
+
await plan.run();
|
|
304
|
+
}, () => {
|
|
305
|
+
Logger.warning("Continue not started, exiting the program...");
|
|
306
|
+
}, flags["yes"]);
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
283
309
|
default:
|
|
284
310
|
console.log(`no command like that: ${command}`);
|
|
285
311
|
}
|
package/dist/cli/index.js
CHANGED
package/dist/utils/files.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare const getPackageJson: () => any;
|
|
|
38
38
|
export declare const isDirectoryExists: (path: string) => boolean;
|
|
39
39
|
export declare const createDir: (dirPath: string) => Promise<void>;
|
|
40
40
|
export declare const createJsonFile: (content: string, pathWithFilename: string) => Promise<void>;
|
|
41
|
+
export declare const writeJsonArrayStreamed: (items: any[], pathWithFilename: string) => Promise<void>;
|
|
41
42
|
export declare const createJSAllComponentsFile: (content: string, pathWithFilename: string, timestamp?: boolean) => Promise<void>;
|
|
42
43
|
export declare const copyFolder: (src: string, dest: string) => Promise<unknown>;
|
|
43
44
|
export declare const copyFile: (src: string, dest: string) => Promise<void>;
|
|
@@ -59,6 +60,7 @@ type CreateAndSaveToFile = (args: {
|
|
|
59
60
|
}, config: RequestBaseConfig) => void;
|
|
60
61
|
export declare const createAndSaveToFile: CreateAndSaveToFile;
|
|
61
62
|
export declare const createAndSaveComponentListToFile: CreateAndSaveComponentListToFile;
|
|
63
|
+
export declare const listFilesInDir: (dirPath: string) => Promise<string[]>;
|
|
62
64
|
export declare const readFile: (pathToFile: string) => Promise<string | undefined>;
|
|
63
65
|
export declare const dumpToFile: (path: string, content: string) => Promise<void>;
|
|
64
66
|
export declare const getConsumerPackageJson: () => Promise<any>;
|
package/dist/utils/files.js
CHANGED
|
@@ -84,6 +84,75 @@ export const createDir = async (dirPath) => {
|
|
|
84
84
|
export const createJsonFile = async (content, pathWithFilename) => {
|
|
85
85
|
await fs.promises.writeFile(pathWithFilename, content, { flag: "w" });
|
|
86
86
|
};
|
|
87
|
+
/*
|
|
88
|
+
* Streams an array to disk as a pretty-printed (2-space) JSON array,
|
|
89
|
+
* one element at a time. Avoids building the whole document as a single
|
|
90
|
+
* string, which overflows V8's max string length (~512 MB) for large
|
|
91
|
+
* migration sets. Output is byte-for-byte identical to
|
|
92
|
+
* JSON.stringify(items, null, 2).
|
|
93
|
+
* */
|
|
94
|
+
export const writeJsonArrayStreamed = (items, pathWithFilename) => {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
const stream = fs.createWriteStream(pathWithFilename, { flags: "w" });
|
|
97
|
+
let settled = false;
|
|
98
|
+
const fail = (err) => {
|
|
99
|
+
if (settled)
|
|
100
|
+
return;
|
|
101
|
+
settled = true;
|
|
102
|
+
reject(err);
|
|
103
|
+
};
|
|
104
|
+
stream.on("error", fail);
|
|
105
|
+
stream.on("finish", () => {
|
|
106
|
+
if (settled)
|
|
107
|
+
return;
|
|
108
|
+
settled = true;
|
|
109
|
+
resolve();
|
|
110
|
+
});
|
|
111
|
+
const indentElement = (item) => {
|
|
112
|
+
const serialized = JSON.stringify(item, null, 2);
|
|
113
|
+
const body = serialized === undefined ? "null" : serialized;
|
|
114
|
+
return ` ${body.replace(/\n/g, "\n ")}`;
|
|
115
|
+
};
|
|
116
|
+
const writeChunk = (chunk) => new Promise((res, rej) => {
|
|
117
|
+
const onErr = (err) => rej(err);
|
|
118
|
+
const ok = stream.write(chunk, (err) => {
|
|
119
|
+
if (err) {
|
|
120
|
+
rej(err);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (ok) {
|
|
124
|
+
stream.removeListener("error", onErr);
|
|
125
|
+
res();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
if (!ok) {
|
|
129
|
+
stream.once("drain", () => {
|
|
130
|
+
stream.removeListener("error", onErr);
|
|
131
|
+
res();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
stream.once("error", onErr);
|
|
135
|
+
});
|
|
136
|
+
const writeChunks = async () => {
|
|
137
|
+
if (items.length === 0) {
|
|
138
|
+
stream.write("[]");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
await writeChunk("[\n");
|
|
142
|
+
for (let i = 0; i < items.length; i++) {
|
|
143
|
+
const prefix = i === 0 ? "" : ",\n";
|
|
144
|
+
await writeChunk(`${prefix}${indentElement(items[i])}`);
|
|
145
|
+
}
|
|
146
|
+
await writeChunk("\n]");
|
|
147
|
+
};
|
|
148
|
+
writeChunks()
|
|
149
|
+
.then(() => stream.end())
|
|
150
|
+
.catch((err) => {
|
|
151
|
+
stream.destroy();
|
|
152
|
+
fail(err);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
};
|
|
87
156
|
export const createJSAllComponentsFile = async (content, pathWithFilename, timestamp = false) => {
|
|
88
157
|
const datestamp = new Date();
|
|
89
158
|
const finalContent = `/*
|
|
@@ -146,8 +215,8 @@ export const createAndSaveToFile = async (args, config) => {
|
|
|
146
215
|
const finalFilename = `${prefix}${filename}${datestamp ? `__${timestamp}` : ""}`;
|
|
147
216
|
const fullPath = `${sbmigWorkingDirectory}/${folder}/${finalFilename}${suffix}.${ext}`;
|
|
148
217
|
await createDir(`${sbmigWorkingDirectory}/${folder}/`);
|
|
149
|
-
if (
|
|
150
|
-
await
|
|
218
|
+
if (Array.isArray(res)) {
|
|
219
|
+
await writeJsonArrayStreamed(res, fullPath);
|
|
151
220
|
}
|
|
152
221
|
else {
|
|
153
222
|
await createJsonFile(JSON.stringify(res, undefined, 2), fullPath);
|
|
@@ -157,7 +226,12 @@ export const createAndSaveToFile = async (args, config) => {
|
|
|
157
226
|
if (path) {
|
|
158
227
|
const folderPath = nodePath.dirname(path);
|
|
159
228
|
await createDir(folderPath);
|
|
160
|
-
|
|
229
|
+
if (Array.isArray(res)) {
|
|
230
|
+
await writeJsonArrayStreamed(res, path);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
await createJsonFile(JSON.stringify(res, undefined, 2), path);
|
|
234
|
+
}
|
|
161
235
|
Logger.success(`All response written to a file: ${path}`);
|
|
162
236
|
}
|
|
163
237
|
};
|
|
@@ -179,6 +253,15 @@ export const createAndSaveComponentListToFile = async ({ file, folder, res, time
|
|
|
179
253
|
: `${sbmigWorkingDirectory}/${filename}.ts`, timestamp);
|
|
180
254
|
Logger.success(`All components written to a file: ${filename}`);
|
|
181
255
|
};
|
|
256
|
+
export const listFilesInDir = async (dirPath) => {
|
|
257
|
+
const absolutePath = resolveFromCwd(dirPath);
|
|
258
|
+
try {
|
|
259
|
+
return await fs.promises.readdir(absolutePath);
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
};
|
|
182
265
|
export const readFile = async (pathToFile) => {
|
|
183
266
|
const absolutePath = resolveFromCwd(pathToFile);
|
|
184
267
|
try {
|
|
@@ -354,13 +354,13 @@ const getStoryVersions = async ({ storyId, showContent = true, page = 1, perPage
|
|
|
354
354
|
};
|
|
355
355
|
exports.getStoryVersions = getStoryVersions;
|
|
356
356
|
// CREATE
|
|
357
|
-
const createStory = (content, config) => {
|
|
357
|
+
const createStory = (content, config, options) => {
|
|
358
358
|
const { spaceId, sbApi } = config;
|
|
359
359
|
logger_js_1.default.log(`Creating story with name: ${content.name} in space: ${spaceId}`);
|
|
360
360
|
return sbApi
|
|
361
361
|
.post(`spaces/${spaceId}/stories/`, {
|
|
362
362
|
story: content,
|
|
363
|
-
publish: true,
|
|
363
|
+
publish: options?.publish ?? true,
|
|
364
364
|
})
|
|
365
365
|
.then((res) => res.data)
|
|
366
366
|
.catch((err) => console.error(err));
|
|
@@ -371,7 +371,7 @@ const updateStory = (content, storyId, options, config) => {
|
|
|
371
371
|
const { spaceId, sbApi } = config;
|
|
372
372
|
const storyLabel = resolveStoryLabel(content, storyId);
|
|
373
373
|
logger_js_1.default.warning("Trying to update Story...");
|
|
374
|
-
logger_js_1.default.log(`Updating story
|
|
374
|
+
logger_js_1.default.log(`Updating story '${storyLabel}' in space: ${spaceId}`);
|
|
375
375
|
// console.log("THis is content to update: ");
|
|
376
376
|
// console.log(JSON.stringify(content, null, 2));
|
|
377
377
|
return sbApi
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toRequestConfig = toRequestConfig;
|
|
4
|
+
exports.configToClient = configToClient;
|
|
4
5
|
function toRequestConfig(client, overrides) {
|
|
5
6
|
return {
|
|
6
7
|
spaceId: overrides?.spaceId ?? client.spaceId,
|
|
@@ -35,3 +36,31 @@ function toRequestConfig(client, overrides) {
|
|
|
35
36
|
storyblokComponentsLocalDirectory: overrides?.storyblokComponentsLocalDirectory,
|
|
36
37
|
};
|
|
37
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Inverse of `toRequestConfig`: adapt a legacy `RequestBaseConfig` into an
|
|
41
|
+
* `ApiClient`.
|
|
42
|
+
*
|
|
43
|
+
* This is the primitive used by the Strategy-B shims (see SDK-REFACTOR.md §3): a
|
|
44
|
+
* legacy `api/<x>` function receives a `RequestBaseConfig` and delegates to the
|
|
45
|
+
* moved `api-v2/<x>` function, which takes an `ApiClient`. The live `sbApi`
|
|
46
|
+
* instance is reused (not recreated) so rate-limit and cache state are preserved.
|
|
47
|
+
*
|
|
48
|
+
* Note: `ApiClient` intentionally carries only the data-API essentials (`sbApi`,
|
|
49
|
+
* `spaceId`, tokens). The remaining `IStoryblokConfig` fields on
|
|
50
|
+
* `RequestBaseConfig` (directories, extensions, resolvers, …) are node-tier /
|
|
51
|
+
* file-discovery concerns handled separately — they are not represented on
|
|
52
|
+
* `ApiClient`. See SDK-REFACTOR.md §4 and ticket F5.
|
|
53
|
+
*/
|
|
54
|
+
function configToClient(config, overrides) {
|
|
55
|
+
const clientConfig = {
|
|
56
|
+
oauthToken: overrides?.oauthToken ?? config.oauthToken ?? "",
|
|
57
|
+
spaceId: overrides?.spaceId ?? config.spaceId,
|
|
58
|
+
accessToken: overrides?.accessToken ?? config.accessToken,
|
|
59
|
+
rateLimit: overrides?.rateLimit ?? config.rateLimit,
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
config: clientConfig,
|
|
63
|
+
sbApi: config.sbApi,
|
|
64
|
+
spaceId: clientConfig.spaceId,
|
|
65
|
+
};
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sb-mig",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.0-beta.2",
|
|
4
4
|
"description": "CLI to rule the world. (and handle stuff related to Storyblok CMS)",
|
|
5
5
|
"author": "Marcin Krawczyk <marckraw@icloud.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"access": "public"
|
|
16
16
|
},
|
|
17
17
|
"bugs": "https://github.com/sb-mig/sb-mig/issues",
|
|
18
|
-
"homepage": "https://
|
|
18
|
+
"homepage": "https://sb-mig.vercel.app",
|
|
19
19
|
"keywords": [
|
|
20
20
|
"cli",
|
|
21
21
|
"storyblok",
|