storyblok 4.7.0 → 4.8.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.mjs +640 -201
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -5,21 +5,21 @@ import { dirname } from 'pathe';
|
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import { readPackageUp } from 'read-package-up';
|
|
8
|
+
import path, { join, resolve, parse, dirname as dirname$1, extname } from 'node:path';
|
|
9
|
+
import { MultiBar, Presets } from 'cli-progress';
|
|
8
10
|
import { Spinner } from '@topcli/spinner';
|
|
11
|
+
import fs, { mkdir, writeFile, readFile as readFile$1, appendFile, access, readdir } from 'node:fs/promises';
|
|
12
|
+
import filenamify from 'filenamify';
|
|
13
|
+
import { mkdirSync, appendFileSync, existsSync, readdirSync, unlinkSync, readFileSync } from 'node:fs';
|
|
9
14
|
import { select, password, input, confirm } from '@inquirer/prompts';
|
|
10
15
|
import { ManagementApiClient } from '@storyblok/management-api-client';
|
|
11
16
|
import { RateLimit, Sema } from 'async-sema';
|
|
12
|
-
import fs, { mkdir, writeFile, readFile as readFile$1, appendFile, access, readdir } from 'node:fs/promises';
|
|
13
|
-
import path, { join, parse, resolve } from 'node:path';
|
|
14
|
-
import filenamify from 'filenamify';
|
|
15
17
|
import { exec, spawn } from 'node:child_process';
|
|
16
18
|
import { promisify } from 'node:util';
|
|
17
19
|
import { minimatch } from 'minimatch';
|
|
18
20
|
import { Readable, pipeline, Transform, Writable } from 'node:stream';
|
|
19
21
|
import { hash } from 'ohash';
|
|
20
|
-
import { MultiBar, Presets } from 'cli-progress';
|
|
21
22
|
import { compile } from 'json-schema-to-typescript';
|
|
22
|
-
import { readFileSync } from 'node:fs';
|
|
23
23
|
import open from 'open';
|
|
24
24
|
import { Octokit } from 'octokit';
|
|
25
25
|
|
|
@@ -33,7 +33,8 @@ const commands = {
|
|
|
33
33
|
MIGRATIONS: "migrations",
|
|
34
34
|
TYPES: "types",
|
|
35
35
|
DATASOURCES: "datasources",
|
|
36
|
-
CREATE: "create"
|
|
36
|
+
CREATE: "create",
|
|
37
|
+
LOGS: "logs"
|
|
37
38
|
};
|
|
38
39
|
const colorPalette = {
|
|
39
40
|
PRIMARY: "#8d60ff",
|
|
@@ -49,7 +50,8 @@ const colorPalette = {
|
|
|
49
50
|
GROUPS: "#4ade80",
|
|
50
51
|
TAGS: "#fbbf24",
|
|
51
52
|
PRESETS: "#a855f7",
|
|
52
|
-
DATASOURCES: "#4ade80"
|
|
53
|
+
DATASOURCES: "#4ade80",
|
|
54
|
+
LOGS: "#4ade80"
|
|
53
55
|
};
|
|
54
56
|
const regions = {
|
|
55
57
|
EU: "eu",
|
|
@@ -89,6 +91,9 @@ const regionNames = {
|
|
|
89
91
|
({
|
|
90
92
|
SB_Agent_Version: process.env.npm_package_version || "4.x"
|
|
91
93
|
});
|
|
94
|
+
const directories = {
|
|
95
|
+
log: "logs"
|
|
96
|
+
};
|
|
92
97
|
|
|
93
98
|
class FetchError extends Error {
|
|
94
99
|
response;
|
|
@@ -279,6 +284,51 @@ class CommandError extends Error {
|
|
|
279
284
|
}
|
|
280
285
|
}
|
|
281
286
|
|
|
287
|
+
class Logger {
|
|
288
|
+
transports = [];
|
|
289
|
+
context = {};
|
|
290
|
+
constructor(options) {
|
|
291
|
+
if (options?.transports) {
|
|
292
|
+
this.transports = options.transports;
|
|
293
|
+
}
|
|
294
|
+
if (options?.context) {
|
|
295
|
+
this.context = options.context;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
log(level, message, context) {
|
|
299
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
300
|
+
const mergedContext = context ? { ...this.context, ...context } : this.context;
|
|
301
|
+
const record = {
|
|
302
|
+
timestamp,
|
|
303
|
+
level,
|
|
304
|
+
message,
|
|
305
|
+
context: Object.keys(mergedContext).length ? mergedContext : void 0
|
|
306
|
+
};
|
|
307
|
+
for (const transport of this.transports) {
|
|
308
|
+
transport.log(record);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
error(message, context) {
|
|
312
|
+
this.log("error", message, context);
|
|
313
|
+
}
|
|
314
|
+
warn(message, context) {
|
|
315
|
+
this.log("warn", message, context);
|
|
316
|
+
}
|
|
317
|
+
info(message, context) {
|
|
318
|
+
this.log("info", message, context);
|
|
319
|
+
}
|
|
320
|
+
debug(message, context) {
|
|
321
|
+
this.log("debug", message, context);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
let loggerInstance = null;
|
|
325
|
+
function getLogger(options) {
|
|
326
|
+
if (!loggerInstance) {
|
|
327
|
+
loggerInstance = new Logger(options);
|
|
328
|
+
}
|
|
329
|
+
return loggerInstance;
|
|
330
|
+
}
|
|
331
|
+
|
|
282
332
|
const FS_ERRORS = {
|
|
283
333
|
file_not_found: "The file requested was not found",
|
|
284
334
|
permission_denied: "Permission denied while accessing the file",
|
|
@@ -359,6 +409,25 @@ class FileSystemError extends Error {
|
|
|
359
409
|
}
|
|
360
410
|
}
|
|
361
411
|
|
|
412
|
+
function hasMessage(error) {
|
|
413
|
+
return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
|
|
414
|
+
}
|
|
415
|
+
function toError(maybeError) {
|
|
416
|
+
if (maybeError instanceof Error) {
|
|
417
|
+
return maybeError;
|
|
418
|
+
}
|
|
419
|
+
if (typeof maybeError === "string") {
|
|
420
|
+
return new Error(maybeError);
|
|
421
|
+
}
|
|
422
|
+
if (hasMessage(maybeError)) {
|
|
423
|
+
return new Error(maybeError.message);
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
return new Error(JSON.stringify(maybeError));
|
|
427
|
+
} catch {
|
|
428
|
+
return new Error(String(maybeError));
|
|
429
|
+
}
|
|
430
|
+
}
|
|
362
431
|
function handleVerboseError(error) {
|
|
363
432
|
if (error instanceof CommandError || error instanceof APIError || error instanceof FileSystemError) {
|
|
364
433
|
const errorDetails = "getInfo" in error ? error.getInfo() : {};
|
|
@@ -398,6 +467,7 @@ function handleError(error, verbose = false) {
|
|
|
398
467
|
if (!process.env.VITEST) {
|
|
399
468
|
console.log("");
|
|
400
469
|
}
|
|
470
|
+
getLogger().error(error.message, { error, errorCode: "code" in error ? String(error.code) : "UNKNOWN_ERROR" });
|
|
401
471
|
}
|
|
402
472
|
|
|
403
473
|
function requireAuthentication(state, verbose = false) {
|
|
@@ -503,6 +573,311 @@ function isRegion(value) {
|
|
|
503
573
|
}
|
|
504
574
|
const isVitest = process.env.VITEST === "true";
|
|
505
575
|
|
|
576
|
+
const noopProgressBar = {
|
|
577
|
+
increment: () => {
|
|
578
|
+
},
|
|
579
|
+
setTotal: (_n) => {
|
|
580
|
+
},
|
|
581
|
+
stop: () => {
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
const noopSpinner = {
|
|
585
|
+
failed: (_title) => {
|
|
586
|
+
},
|
|
587
|
+
succeed: (_title) => {
|
|
588
|
+
},
|
|
589
|
+
elapsedTime: 0
|
|
590
|
+
};
|
|
591
|
+
class UI {
|
|
592
|
+
console;
|
|
593
|
+
enabled;
|
|
594
|
+
multiBar;
|
|
595
|
+
constructor({ enabled }) {
|
|
596
|
+
this.console = enabled ? console : null;
|
|
597
|
+
this.enabled = enabled;
|
|
598
|
+
this.multiBar = enabled ? new MultiBar({
|
|
599
|
+
clearOnComplete: false,
|
|
600
|
+
format: `${chalk.bold(" {title} ")} ${chalk.hex(colorPalette.PRIMARY)("[{bar}]")} {percentage}% | {eta_formatted} | {value}/{total} processed`,
|
|
601
|
+
etaBuffer: 60
|
|
602
|
+
}, Presets.rect) : null;
|
|
603
|
+
}
|
|
604
|
+
title(message, color, subtitle) {
|
|
605
|
+
if (subtitle) {
|
|
606
|
+
this.console?.log(`${chalk.bgHex(color).bold(` ${capitalize(message)} `)} ${subtitle}`);
|
|
607
|
+
} else {
|
|
608
|
+
this.console?.log(chalk.bgHex(color).bold(` ${capitalize(message)} `));
|
|
609
|
+
}
|
|
610
|
+
this.br();
|
|
611
|
+
this.br();
|
|
612
|
+
}
|
|
613
|
+
br() {
|
|
614
|
+
this.console?.log("");
|
|
615
|
+
}
|
|
616
|
+
ok(message, header = false) {
|
|
617
|
+
if (header) {
|
|
618
|
+
this.br();
|
|
619
|
+
const successHeader = chalk.bgGreen.bold.white(` Success `);
|
|
620
|
+
this.console?.log(successHeader);
|
|
621
|
+
this.br();
|
|
622
|
+
}
|
|
623
|
+
this.console?.log(message ? `${chalk.green("\u2714")} ${message}` : "");
|
|
624
|
+
}
|
|
625
|
+
info(message, options = {
|
|
626
|
+
header: false,
|
|
627
|
+
margin: true
|
|
628
|
+
}) {
|
|
629
|
+
if (options.header) {
|
|
630
|
+
this.br();
|
|
631
|
+
const infoHeader = chalk.bgBlue.bold.white(` Info `);
|
|
632
|
+
this.console?.info(infoHeader);
|
|
633
|
+
}
|
|
634
|
+
this.console?.info(message ? `${chalk.blue("\u2139")} ${message}` : "");
|
|
635
|
+
if (options.margin) {
|
|
636
|
+
this.br();
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
warn(message, header = false) {
|
|
640
|
+
if (header) {
|
|
641
|
+
this.br();
|
|
642
|
+
const warnHeader = chalk.bgYellow.bold.black(` Warning `);
|
|
643
|
+
this.console?.warn(warnHeader);
|
|
644
|
+
}
|
|
645
|
+
this.console?.warn(message ? `${chalk.yellow("\u26A0\uFE0F ")} ${message}` : "");
|
|
646
|
+
}
|
|
647
|
+
error(message, info, options = {
|
|
648
|
+
header: false,
|
|
649
|
+
margin: false
|
|
650
|
+
}) {
|
|
651
|
+
if (options.header) {
|
|
652
|
+
const errorHeader = chalk.bgRed.bold.white(` Error `);
|
|
653
|
+
this.console?.error(errorHeader);
|
|
654
|
+
this.br();
|
|
655
|
+
}
|
|
656
|
+
this.console?.error(`${chalk.red.bold("\u25B2 error")} ${message}`, info || "");
|
|
657
|
+
if (options.margin) {
|
|
658
|
+
this.br();
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
list(items) {
|
|
662
|
+
for (const item of items) {
|
|
663
|
+
this.console?.log(` ${item}`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
createProgressBar(options) {
|
|
667
|
+
return this.multiBar?.create(0, 0, options) || noopProgressBar;
|
|
668
|
+
}
|
|
669
|
+
stopAllProgressBars() {
|
|
670
|
+
this.multiBar?.stop();
|
|
671
|
+
}
|
|
672
|
+
createSpinner(title) {
|
|
673
|
+
return this.enabled ? new Spinner({
|
|
674
|
+
verbose: !isVitest
|
|
675
|
+
}).start(title) : noopSpinner;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
let uiInstance = null;
|
|
679
|
+
function getUI(options = { enabled: false }) {
|
|
680
|
+
if (!uiInstance) {
|
|
681
|
+
uiInstance = new UI(options);
|
|
682
|
+
}
|
|
683
|
+
return uiInstance;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const getStoryblokGlobalPath = () => {
|
|
687
|
+
const homeDirectory = process.env[process.platform.startsWith("win") ? "USERPROFILE" : "HOME"] || process.cwd();
|
|
688
|
+
return join(homeDirectory, ".storyblok");
|
|
689
|
+
};
|
|
690
|
+
const saveToFile = async (filePath, data, options) => {
|
|
691
|
+
const resolvedPath = parse(filePath).dir;
|
|
692
|
+
try {
|
|
693
|
+
await mkdir(resolvedPath, { recursive: true });
|
|
694
|
+
} catch (mkdirError) {
|
|
695
|
+
handleFileSystemError("mkdir", mkdirError);
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
try {
|
|
699
|
+
await writeFile(filePath, data, options);
|
|
700
|
+
} catch (writeError) {
|
|
701
|
+
handleFileSystemError("write", writeError);
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
const appendToFile = async (filePath, data, options) => {
|
|
705
|
+
const resolvedPath = parse(filePath).dir;
|
|
706
|
+
try {
|
|
707
|
+
await mkdir(resolvedPath, { recursive: true });
|
|
708
|
+
} catch (mkdirError) {
|
|
709
|
+
handleFileSystemError("mkdir", mkdirError);
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
try {
|
|
713
|
+
const dataWithNewline = data.endsWith("\n") ? data : `${data}
|
|
714
|
+
`;
|
|
715
|
+
await appendFile(filePath, dataWithNewline, options);
|
|
716
|
+
} catch (writeError) {
|
|
717
|
+
handleFileSystemError("write", writeError);
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
const appendToFileSync = (filePath, data, options) => {
|
|
721
|
+
const resolvedPath = parse(filePath).dir;
|
|
722
|
+
try {
|
|
723
|
+
mkdirSync(resolvedPath, { recursive: true });
|
|
724
|
+
} catch (mkdirError) {
|
|
725
|
+
handleFileSystemError("mkdir", mkdirError);
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
try {
|
|
729
|
+
const dataWithNewline = data.endsWith("\n") ? data : `${data}
|
|
730
|
+
`;
|
|
731
|
+
appendFileSync(filePath, dataWithNewline, options);
|
|
732
|
+
} catch (writeError) {
|
|
733
|
+
handleFileSystemError("write", writeError);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
const readFile = async (filePath) => {
|
|
737
|
+
try {
|
|
738
|
+
return await readFile$1(filePath, "utf8");
|
|
739
|
+
} catch (error) {
|
|
740
|
+
handleFileSystemError("read", error);
|
|
741
|
+
return "";
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
const resolvePath = (path, folder) => {
|
|
745
|
+
if (path) {
|
|
746
|
+
return resolve(process.cwd(), path, folder);
|
|
747
|
+
}
|
|
748
|
+
return resolve(resolve(process.cwd(), ".storyblok"), folder);
|
|
749
|
+
};
|
|
750
|
+
const getComponentNameFromFilename = (filename) => {
|
|
751
|
+
return filename.replace(/\.js$/, "");
|
|
752
|
+
};
|
|
753
|
+
const sanitizeFilename = (filename) => {
|
|
754
|
+
return filenamify(filename, {
|
|
755
|
+
replacement: "_"
|
|
756
|
+
});
|
|
757
|
+
};
|
|
758
|
+
async function readJsonFile(filePath) {
|
|
759
|
+
try {
|
|
760
|
+
const content = (await readFile(filePath)).toString();
|
|
761
|
+
if (!content) {
|
|
762
|
+
return { data: [] };
|
|
763
|
+
}
|
|
764
|
+
const parsed = JSON.parse(content);
|
|
765
|
+
return { data: Array.isArray(parsed) ? parsed : [parsed] };
|
|
766
|
+
} catch (error) {
|
|
767
|
+
return { data: [], error };
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
function importModule(filePath) {
|
|
771
|
+
return import(`file://${filePath}`);
|
|
772
|
+
}
|
|
773
|
+
function getLogsPath(logFileDir, space, baseDir) {
|
|
774
|
+
if (space) {
|
|
775
|
+
return resolvePath(baseDir, join(logFileDir, space));
|
|
776
|
+
}
|
|
777
|
+
return resolvePath(baseDir, logFileDir);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
class FileTransport {
|
|
781
|
+
filePath;
|
|
782
|
+
level;
|
|
783
|
+
maxFiles;
|
|
784
|
+
hasPruned = false;
|
|
785
|
+
constructor(options) {
|
|
786
|
+
this.filePath = options?.filePath ?? `./${Date.now()}.jsonl`;
|
|
787
|
+
this.level = options?.level ?? "info";
|
|
788
|
+
this.maxFiles = options?.maxFiles;
|
|
789
|
+
}
|
|
790
|
+
log(record) {
|
|
791
|
+
if (!this.shouldLog(record.level)) {
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
const line = this.format(record);
|
|
795
|
+
appendToFileSync(this.filePath, line);
|
|
796
|
+
if (!this.hasPruned && this.maxFiles !== void 0) {
|
|
797
|
+
this.hasPruned = true;
|
|
798
|
+
this.pruneOldFiles();
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
pruneOldFiles() {
|
|
802
|
+
if (this.maxFiles === void 0) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
const dir = dirname$1(this.filePath);
|
|
806
|
+
const ext = extname(this.filePath);
|
|
807
|
+
FileTransport.pruneLogFiles(dir, this.maxFiles, ext);
|
|
808
|
+
}
|
|
809
|
+
static pruneLogFiles(directory, keep, extension = ".jsonl") {
|
|
810
|
+
if (!existsSync(directory)) {
|
|
811
|
+
return 0;
|
|
812
|
+
}
|
|
813
|
+
const files = readdirSync(directory).filter((file) => extname(file) === extension).sort();
|
|
814
|
+
const filesToDelete = files.length - keep;
|
|
815
|
+
if (filesToDelete <= 0) {
|
|
816
|
+
return 0;
|
|
817
|
+
}
|
|
818
|
+
for (const file of files.slice(0, filesToDelete)) {
|
|
819
|
+
unlinkSync(join(directory, file));
|
|
820
|
+
}
|
|
821
|
+
return filesToDelete;
|
|
822
|
+
}
|
|
823
|
+
static listLogFiles(directory, extension = ".jsonl") {
|
|
824
|
+
if (!existsSync(directory)) {
|
|
825
|
+
return [];
|
|
826
|
+
}
|
|
827
|
+
const files = readdirSync(directory).filter((file) => extname(file) === extension).sort();
|
|
828
|
+
return files.map((f) => join(directory, f).replace(process.cwd(), "."));
|
|
829
|
+
}
|
|
830
|
+
levelRank(level) {
|
|
831
|
+
switch (level) {
|
|
832
|
+
case "error":
|
|
833
|
+
return 0;
|
|
834
|
+
case "warn":
|
|
835
|
+
return 1;
|
|
836
|
+
case "info":
|
|
837
|
+
return 2;
|
|
838
|
+
case "debug":
|
|
839
|
+
return 3;
|
|
840
|
+
default:
|
|
841
|
+
return 3;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
shouldLog(level) {
|
|
845
|
+
return this.levelRank(level) <= this.levelRank(this.level);
|
|
846
|
+
}
|
|
847
|
+
format(record) {
|
|
848
|
+
const timestamp = (record.timestamp ?? /* @__PURE__ */ new Date()).toISOString();
|
|
849
|
+
const level = record.level.toUpperCase();
|
|
850
|
+
const message = record.message.replaceAll("\n", "\\n");
|
|
851
|
+
const contextNormalized = record.context && this.formatContext(record.context);
|
|
852
|
+
return JSON.stringify({ timestamp, level, message, context: contextNormalized });
|
|
853
|
+
}
|
|
854
|
+
formatContext(context) {
|
|
855
|
+
const contextNormalized = {};
|
|
856
|
+
for (const [key, value] of Object.entries(context)) {
|
|
857
|
+
if (value instanceof APIError) {
|
|
858
|
+
contextNormalized[key] = {
|
|
859
|
+
name: value.name,
|
|
860
|
+
message: value.message,
|
|
861
|
+
httpCode: value.code,
|
|
862
|
+
httpStatusText: value.error?.response.statusText,
|
|
863
|
+
stack: value.stack
|
|
864
|
+
};
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
if (value instanceof Error) {
|
|
868
|
+
contextNormalized[key] = {
|
|
869
|
+
name: value.name,
|
|
870
|
+
message: value.message,
|
|
871
|
+
stack: value.stack
|
|
872
|
+
};
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
contextNormalized[key] = value;
|
|
876
|
+
}
|
|
877
|
+
return contextNormalized;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
506
881
|
let packageJson;
|
|
507
882
|
const result = await readPackageUp({
|
|
508
883
|
cwd: __dirname
|
|
@@ -521,7 +896,28 @@ let programInstance = null;
|
|
|
521
896
|
function getProgram() {
|
|
522
897
|
if (!programInstance) {
|
|
523
898
|
programInstance = new Command();
|
|
524
|
-
programInstance.name(packageJson.name).description(packageJson.description || "").version(packageJson.version)
|
|
899
|
+
programInstance.name(packageJson.name).description(packageJson.description || "").version(packageJson.version).hook("preAction", (_, actionCmd) => {
|
|
900
|
+
const options = actionCmd.optsWithGlobals();
|
|
901
|
+
const commandPieces = [];
|
|
902
|
+
for (let c = actionCmd; c; c = c.parent) {
|
|
903
|
+
commandPieces.unshift(c.name());
|
|
904
|
+
}
|
|
905
|
+
const command = commandPieces.join(" ");
|
|
906
|
+
const runId = Date.now();
|
|
907
|
+
const transports = [];
|
|
908
|
+
const logsPath = getLogsPath(directories.log, options.space, options.path);
|
|
909
|
+
const logFilename = `${commandPieces.join("-")}-${runId}.jsonl`;
|
|
910
|
+
const filePath = path.join(logsPath, logFilename);
|
|
911
|
+
transports.push(new FileTransport({
|
|
912
|
+
filePath,
|
|
913
|
+
maxFiles: 10
|
|
914
|
+
}));
|
|
915
|
+
getLogger({
|
|
916
|
+
context: { runId, command, options, cliVersion: packageJson.version },
|
|
917
|
+
transports
|
|
918
|
+
});
|
|
919
|
+
getUI({ enabled: true });
|
|
920
|
+
});
|
|
525
921
|
programInstance.configureOutput({
|
|
526
922
|
writeErr: (str) => handleError(new Error(str))
|
|
527
923
|
});
|
|
@@ -650,75 +1046,6 @@ const loginWithOtp = async (email, password, otp, region) => {
|
|
|
650
1046
|
}
|
|
651
1047
|
};
|
|
652
1048
|
|
|
653
|
-
const getStoryblokGlobalPath = () => {
|
|
654
|
-
const homeDirectory = process.env[process.platform.startsWith("win") ? "USERPROFILE" : "HOME"] || process.cwd();
|
|
655
|
-
return join(homeDirectory, ".storyblok");
|
|
656
|
-
};
|
|
657
|
-
const saveToFile = async (filePath, data, options) => {
|
|
658
|
-
const resolvedPath = parse(filePath).dir;
|
|
659
|
-
try {
|
|
660
|
-
await mkdir(resolvedPath, { recursive: true });
|
|
661
|
-
} catch (mkdirError) {
|
|
662
|
-
handleFileSystemError("mkdir", mkdirError);
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
try {
|
|
666
|
-
await writeFile(filePath, data, options);
|
|
667
|
-
} catch (writeError) {
|
|
668
|
-
handleFileSystemError("write", writeError);
|
|
669
|
-
}
|
|
670
|
-
};
|
|
671
|
-
const appendToFile = async (filePath, data, options) => {
|
|
672
|
-
const resolvedPath = parse(filePath).dir;
|
|
673
|
-
try {
|
|
674
|
-
await mkdir(resolvedPath, { recursive: true });
|
|
675
|
-
} catch (mkdirError) {
|
|
676
|
-
handleFileSystemError("mkdir", mkdirError);
|
|
677
|
-
return;
|
|
678
|
-
}
|
|
679
|
-
try {
|
|
680
|
-
const dataWithNewline = data.endsWith("\n") ? data : `${data}
|
|
681
|
-
`;
|
|
682
|
-
await appendFile(filePath, dataWithNewline, options);
|
|
683
|
-
} catch (writeError) {
|
|
684
|
-
handleFileSystemError("write", writeError);
|
|
685
|
-
}
|
|
686
|
-
};
|
|
687
|
-
const readFile = async (filePath) => {
|
|
688
|
-
try {
|
|
689
|
-
return await readFile$1(filePath, "utf8");
|
|
690
|
-
} catch (error) {
|
|
691
|
-
handleFileSystemError("read", error);
|
|
692
|
-
return "";
|
|
693
|
-
}
|
|
694
|
-
};
|
|
695
|
-
const resolvePath = (path, folder) => {
|
|
696
|
-
if (path) {
|
|
697
|
-
return resolve(process.cwd(), path, folder);
|
|
698
|
-
}
|
|
699
|
-
return resolve(resolve(process.cwd(), ".storyblok"), folder);
|
|
700
|
-
};
|
|
701
|
-
const getComponentNameFromFilename = (filename) => {
|
|
702
|
-
return filename.replace(/\.js$/, "");
|
|
703
|
-
};
|
|
704
|
-
const sanitizeFilename = (filename) => {
|
|
705
|
-
return filenamify(filename, {
|
|
706
|
-
replacement: "_"
|
|
707
|
-
});
|
|
708
|
-
};
|
|
709
|
-
async function readJsonFile(filePath) {
|
|
710
|
-
try {
|
|
711
|
-
const content = (await readFile(filePath)).toString();
|
|
712
|
-
if (!content) {
|
|
713
|
-
return { data: [] };
|
|
714
|
-
}
|
|
715
|
-
const parsed = JSON.parse(content);
|
|
716
|
-
return { data: Array.isArray(parsed) ? parsed : [parsed] };
|
|
717
|
-
} catch (error) {
|
|
718
|
-
return { data: [], error };
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
1049
|
const getCredentials = async (filePath = join(getStoryblokGlobalPath(), "credentials.json")) => {
|
|
723
1050
|
try {
|
|
724
1051
|
await access(filePath);
|
|
@@ -845,7 +1172,7 @@ function session() {
|
|
|
845
1172
|
return sessionInstance;
|
|
846
1173
|
}
|
|
847
1174
|
|
|
848
|
-
const program$
|
|
1175
|
+
const program$g = getProgram();
|
|
849
1176
|
const allRegionsText = Object.values(regions).join(",");
|
|
850
1177
|
const loginStrategy = {
|
|
851
1178
|
message: "How would you like to login?",
|
|
@@ -862,12 +1189,12 @@ const loginStrategy = {
|
|
|
862
1189
|
}
|
|
863
1190
|
]
|
|
864
1191
|
};
|
|
865
|
-
program$
|
|
1192
|
+
program$g.command(commands.LOGIN).description("Login to the Storyblok CLI").option("-t, --token <token>", "Token to login directly without questions, like for CI environments").option(
|
|
866
1193
|
"-r, --region <region>",
|
|
867
1194
|
`The region you would like to work in. Please keep in mind that the region must match the region of your space. This region flag will be used for the other cli's commands. You can use the values: ${allRegionsText}.`
|
|
868
1195
|
).action(async (options) => {
|
|
869
1196
|
konsola.title(`${commands.LOGIN}`, colorPalette.LOGIN);
|
|
870
|
-
const verbose = program$
|
|
1197
|
+
const verbose = program$g.opts().verbose;
|
|
871
1198
|
const { token, region } = options;
|
|
872
1199
|
const { state, updateSession, persistCredentials, initializeSession } = session();
|
|
873
1200
|
await initializeSession();
|
|
@@ -995,10 +1322,10 @@ program$i.command(commands.LOGIN).description("Login to the Storyblok CLI").opti
|
|
|
995
1322
|
konsola.br();
|
|
996
1323
|
});
|
|
997
1324
|
|
|
998
|
-
const program$
|
|
999
|
-
program$
|
|
1325
|
+
const program$f = getProgram();
|
|
1326
|
+
program$f.command(commands.LOGOUT).description("Logout from the Storyblok CLI").action(async () => {
|
|
1000
1327
|
konsola.title(`${commands.LOGOUT}`, colorPalette.LOGOUT);
|
|
1001
|
-
const verbose = program$
|
|
1328
|
+
const verbose = program$f.opts().verbose;
|
|
1002
1329
|
try {
|
|
1003
1330
|
const { state, initializeSession } = session();
|
|
1004
1331
|
await initializeSession();
|
|
@@ -1046,10 +1373,10 @@ async function openSignupInBrowser(url) {
|
|
|
1046
1373
|
}
|
|
1047
1374
|
}
|
|
1048
1375
|
|
|
1049
|
-
const program$
|
|
1050
|
-
program$
|
|
1376
|
+
const program$e = getProgram();
|
|
1377
|
+
program$e.command(commands.SIGNUP).description("Sign up for Storyblok").action(async () => {
|
|
1051
1378
|
konsola.title(`${commands.SIGNUP}`, colorPalette.SIGNUP);
|
|
1052
|
-
const verbose = program$
|
|
1379
|
+
const verbose = program$e.opts().verbose;
|
|
1053
1380
|
const { state, initializeSession } = session();
|
|
1054
1381
|
await initializeSession();
|
|
1055
1382
|
if (state.isLoggedIn && !state.envLogin) {
|
|
@@ -1071,10 +1398,10 @@ program$g.command(commands.SIGNUP).description("Sign up for Storyblok").action(a
|
|
|
1071
1398
|
konsola.br();
|
|
1072
1399
|
});
|
|
1073
1400
|
|
|
1074
|
-
const program$
|
|
1075
|
-
program$
|
|
1401
|
+
const program$d = getProgram();
|
|
1402
|
+
program$d.command(commands.USER).description("Get the current user").action(async () => {
|
|
1076
1403
|
konsola.title(`${commands.USER}`, colorPalette.USER);
|
|
1077
|
-
const verbose = program$
|
|
1404
|
+
const verbose = program$d.opts().verbose;
|
|
1078
1405
|
const { state, initializeSession } = session();
|
|
1079
1406
|
await initializeSession();
|
|
1080
1407
|
if (!requireAuthentication(state)) {
|
|
@@ -1103,8 +1430,8 @@ program$f.command(commands.USER).description("Get the current user").action(asyn
|
|
|
1103
1430
|
konsola.br();
|
|
1104
1431
|
});
|
|
1105
1432
|
|
|
1106
|
-
const program$
|
|
1107
|
-
const componentsCommand = program$
|
|
1433
|
+
const program$c = getProgram();
|
|
1434
|
+
const componentsCommand = program$c.command(commands.COMPONENTS).alias("comp").description(`Manage your space's block schema`).option("-s, --space <space>", "space ID").option("-p, --path <path>", "path to save the file. Default is .storyblok/components");
|
|
1108
1435
|
|
|
1109
1436
|
const fetchComponents = async (spaceId) => {
|
|
1110
1437
|
try {
|
|
@@ -1484,10 +1811,10 @@ async function readConsolidatedFiles$1(resolvedPath, suffix) {
|
|
|
1484
1811
|
};
|
|
1485
1812
|
}
|
|
1486
1813
|
|
|
1487
|
-
const program$
|
|
1814
|
+
const program$b = getProgram();
|
|
1488
1815
|
componentsCommand.command("pull [componentName]").option("-f, --filename <filename>", "custom name to be used in file(s) name instead of space id").option("--sf, --separate-files", "Argument to create a single file for each component").option("--su, --suffix <suffix>", "suffix to add to the file name (e.g. components.<suffix>.json)").description(`Download your space's components schema as json. Optionally specify a component name to pull a single component.`).action(async (componentName, options) => {
|
|
1489
1816
|
konsola.title(`${commands.COMPONENTS}`, colorPalette.COMPONENTS, componentName ? `Pulling component ${componentName}...` : "Pulling components...");
|
|
1490
|
-
const verbose = program$
|
|
1817
|
+
const verbose = program$b.opts().verbose;
|
|
1491
1818
|
const { space, path } = componentsCommand.opts();
|
|
1492
1819
|
const { separateFiles, suffix, filename = "components" } = options;
|
|
1493
1820
|
const { state, initializeSession } = session();
|
|
@@ -2520,10 +2847,10 @@ async function pushWithDependencyGraph(space, spaceState, maxConcurrency = 5) {
|
|
|
2520
2847
|
return results;
|
|
2521
2848
|
}
|
|
2522
2849
|
|
|
2523
|
-
const program$
|
|
2850
|
+
const program$a = getProgram();
|
|
2524
2851
|
componentsCommand.command("push [componentName]").description(`Push your space's components schema as json`).option("-f, --from <from>", "source space id").option("--fi, --filter <filter>", "glob filter to apply to the components before pushing").option("--sf, --separate-files", "Read from separate files instead of consolidated files").option("--su, --suffix <suffix>", "Suffix to add to the component name").action(async (componentName, options) => {
|
|
2525
2852
|
konsola.title(`${commands.COMPONENTS}`, colorPalette.COMPONENTS, componentName ? `Pushing component ${componentName}...` : "Pushing components...");
|
|
2526
|
-
const verbose = program$
|
|
2853
|
+
const verbose = program$a.opts().verbose;
|
|
2527
2854
|
const { space, path } = componentsCommand.opts();
|
|
2528
2855
|
const { from, filter } = options;
|
|
2529
2856
|
const { state, initializeSession } = session();
|
|
@@ -2719,11 +3046,11 @@ const saveLanguagesToFile = async (space, internationalizationOptions, options)
|
|
|
2719
3046
|
}
|
|
2720
3047
|
};
|
|
2721
3048
|
|
|
2722
|
-
const program$
|
|
2723
|
-
const languagesCommand = program$
|
|
3049
|
+
const program$9 = getProgram();
|
|
3050
|
+
const languagesCommand = program$9.command(commands.LANGUAGES).alias("lang").description(`Manage your space's languages`).option("-s, --space <space>", "space ID").option("-p, --path <path>", "path to save the file. Default is .storyblok/languages");
|
|
2724
3051
|
languagesCommand.command("pull").description(`Download your space's languages schema as json`).option("-f, --filename <filename>", "filename to save the file as <filename>.<suffix>.json").option("--su, --suffix <suffix>", "suffix to add to the file name (e.g. languages.<suffix>.json). By default, the space ID is used.").action(async (options) => {
|
|
2725
3052
|
konsola.title(`${commands.LANGUAGES}`, colorPalette.LANGUAGES);
|
|
2726
|
-
const verbose = program$
|
|
3053
|
+
const verbose = program$9.opts().verbose;
|
|
2727
3054
|
const { space, path } = languagesCommand.opts();
|
|
2728
3055
|
const { filename = "languages", suffix = options.space } = options;
|
|
2729
3056
|
const { state, initializeSession } = session();
|
|
@@ -2770,8 +3097,8 @@ languagesCommand.command("pull").description(`Download your space's languages sc
|
|
|
2770
3097
|
konsola.br();
|
|
2771
3098
|
});
|
|
2772
3099
|
|
|
2773
|
-
const program$
|
|
2774
|
-
const migrationsCommand = program$
|
|
3100
|
+
const program$8 = getProgram();
|
|
3101
|
+
const migrationsCommand = program$8.command(commands.MIGRATIONS).alias("mig").description(`Manage your space's migrations`).option("-s, --space <space>", "space ID").option("-p, --path <path>", "path to save the file. Default is .storyblok/migrations");
|
|
2775
3102
|
|
|
2776
3103
|
const getMigrationTemplate = () => {
|
|
2777
3104
|
return `export default function (block) {
|
|
@@ -2799,12 +3126,19 @@ const generateMigration = async (space, path, component, suffix) => {
|
|
|
2799
3126
|
}
|
|
2800
3127
|
};
|
|
2801
3128
|
|
|
2802
|
-
const program$9 = getProgram();
|
|
2803
3129
|
migrationsCommand.command("generate [componentName]").description("Generate a migration file").option("--su, --suffix <suffix>", "suffix to add to the file name (e.g. {component-name}.<suffix>.js)").action(async (componentName, options) => {
|
|
2804
|
-
|
|
2805
|
-
const
|
|
3130
|
+
const program = getProgram();
|
|
3131
|
+
const ui = getUI();
|
|
3132
|
+
const logger = getLogger();
|
|
3133
|
+
ui.title(`${commands.MIGRATIONS}`, colorPalette.MIGRATIONS, componentName ? `Generating migration for component ${componentName}...` : "Generating migrations...");
|
|
3134
|
+
const verbose = program.opts().verbose;
|
|
2806
3135
|
const { space, path } = migrationsCommand.opts();
|
|
2807
3136
|
const { suffix } = options;
|
|
3137
|
+
logger.info("Migration generation started", {
|
|
3138
|
+
componentName,
|
|
3139
|
+
space,
|
|
3140
|
+
suffix
|
|
3141
|
+
});
|
|
2808
3142
|
if (!componentName) {
|
|
2809
3143
|
handleError(new CommandError(`Please provide the component name as argument ${chalk.hex(colorPalette.MIGRATIONS)("storyblok migrations generate YOUR_COMPONENT_NAME.")}`), verbose);
|
|
2810
3144
|
return;
|
|
@@ -2825,9 +3159,7 @@ migrationsCommand.command("generate [componentName]").description("Generate a mi
|
|
|
2825
3159
|
},
|
|
2826
3160
|
region
|
|
2827
3161
|
});
|
|
2828
|
-
const spinner =
|
|
2829
|
-
verbose: !isVitest
|
|
2830
|
-
}).start(`Generating migration for component ${componentName}...`);
|
|
3162
|
+
const spinner = ui.createSpinner(`Generating migration for component ${componentName}...`);
|
|
2831
3163
|
try {
|
|
2832
3164
|
const component = await fetchComponent(space, componentName);
|
|
2833
3165
|
if (!component) {
|
|
@@ -2839,7 +3171,13 @@ migrationsCommand.command("generate [componentName]").description("Generate a mi
|
|
|
2839
3171
|
spinner.succeed(`Migration generated for component ${chalk.hex(colorPalette.MIGRATIONS)(componentName)} - Completed in ${spinner.elapsedTime.toFixed(2)}ms`);
|
|
2840
3172
|
const fileName = suffix ? `${component.name}.${suffix}.js` : `${component.name}.js`;
|
|
2841
3173
|
const migrationPath = path ? `${path}/migrations/${space}/${fileName}` : `.storyblok/migrations/${space}/${fileName}`;
|
|
2842
|
-
|
|
3174
|
+
ui.ok(`You can find the migration file in ${chalk.hex(colorPalette.MIGRATIONS)(migrationPath)}`);
|
|
3175
|
+
logger.info("Migration generation finished", {
|
|
3176
|
+
componentName: component.name,
|
|
3177
|
+
migrationPath,
|
|
3178
|
+
space,
|
|
3179
|
+
suffix
|
|
3180
|
+
});
|
|
2843
3181
|
} catch (error) {
|
|
2844
3182
|
spinner.failed(`Failed to generate migration for component ${componentName}`);
|
|
2845
3183
|
handleError(error, verbose);
|
|
@@ -2904,6 +3242,18 @@ const updateStory = async (spaceId, storyId, payload) => {
|
|
|
2904
3242
|
}
|
|
2905
3243
|
};
|
|
2906
3244
|
|
|
3245
|
+
const ERROR_CODES = {
|
|
3246
|
+
MIGRATION_APPLY_TO_STORY_ERROR: "MIGRATION_APPLY_TO_STORY_ERROR",
|
|
3247
|
+
MIGRATION_CREATE_STORIES_PIPELINE_ERROR: "MIGRATION_CREATE_STORIES_PIPELINE_ERROR",
|
|
3248
|
+
MIGRATION_FILE_NO_DEFAULT_EXPORT: "MIGRATION_FILE_NO_DEFAULT_EXPORT",
|
|
3249
|
+
MIGRATION_FILE_NOT_FOUND: "MIGRATION_FILE_NOT_FOUND",
|
|
3250
|
+
MIGRATION_LOAD_ERROR: "MIGRATION_LOAD_ERROR",
|
|
3251
|
+
MIGRATION_STORY_CONTENT_MISSING: "MIGRATION_STORY_CONTENT_MISSING",
|
|
3252
|
+
MIGRATION_STORY_FETCH_ERROR: "MIGRATION_STORY_FETCH_ERROR",
|
|
3253
|
+
MIGRATION_STORY_UPDATE_ERROR: "MIGRATION_STORY_UPDATE_ERROR",
|
|
3254
|
+
MIGRATION_STORY_UPDATE_NULL: "MIGRATION_STORY_UPDATE_NULL"
|
|
3255
|
+
};
|
|
3256
|
+
|
|
2907
3257
|
async function* storiesIterator(spaceId, params, onTotal) {
|
|
2908
3258
|
try {
|
|
2909
3259
|
let perPage = 500;
|
|
@@ -2924,6 +3274,7 @@ async function* storiesIterator(spaceId, params, onTotal) {
|
|
|
2924
3274
|
page: 1,
|
|
2925
3275
|
story_only: true
|
|
2926
3276
|
});
|
|
3277
|
+
getLogger().info(`Fetched stories page 1 of ${perPage}`);
|
|
2927
3278
|
if (!result) {
|
|
2928
3279
|
return;
|
|
2929
3280
|
}
|
|
@@ -2941,6 +3292,7 @@ async function* storiesIterator(spaceId, params, onTotal) {
|
|
|
2941
3292
|
page,
|
|
2942
3293
|
story_only: true
|
|
2943
3294
|
});
|
|
3295
|
+
getLogger().info(`Fetched stories page ${page} of ${perPage}`);
|
|
2944
3296
|
if (!result2) {
|
|
2945
3297
|
return;
|
|
2946
3298
|
}
|
|
@@ -2965,14 +3317,20 @@ class StoriesStream extends Transform {
|
|
|
2965
3317
|
}
|
|
2966
3318
|
semaphore;
|
|
2967
3319
|
async _transform(chunk, _encoding, callback) {
|
|
2968
|
-
|
|
2969
|
-
|
|
3320
|
+
try {
|
|
3321
|
+
await this.semaphore.acquire();
|
|
3322
|
+
const story = await fetchStory(this.spaceId, chunk.id.toString());
|
|
2970
3323
|
this.push(story);
|
|
2971
3324
|
this.onProgress?.();
|
|
2972
|
-
|
|
3325
|
+
getLogger().info("Fetched story", { storyId: chunk.id });
|
|
3326
|
+
callback();
|
|
3327
|
+
} catch (maybeError) {
|
|
3328
|
+
const error = toError(maybeError);
|
|
3329
|
+
getLogger().error(error.message, { storyId: chunk.id, error, errorCode: ERROR_CODES.MIGRATION_STORY_FETCH_ERROR });
|
|
3330
|
+
callback(error);
|
|
3331
|
+
} finally {
|
|
2973
3332
|
this.semaphore.release();
|
|
2974
|
-
}
|
|
2975
|
-
callback();
|
|
3333
|
+
}
|
|
2976
3334
|
}
|
|
2977
3335
|
_flush(callback) {
|
|
2978
3336
|
this.semaphore.drain().then(() => {
|
|
@@ -2992,37 +3350,14 @@ const createStoriesStream = async ({
|
|
|
2992
3350
|
return pipeline(listStoriesStream, new StoriesStream(spaceId, batchSize, onProgress), (err) => {
|
|
2993
3351
|
if (err) {
|
|
2994
3352
|
console.error(err);
|
|
3353
|
+
getLogger().error(err.message, { errorCode: ERROR_CODES.MIGRATION_CREATE_STORIES_PIPELINE_ERROR });
|
|
2995
3354
|
}
|
|
2996
3355
|
});
|
|
2997
3356
|
};
|
|
2998
3357
|
|
|
2999
|
-
async function readJavascriptFile(filePath) {
|
|
3000
|
-
try {
|
|
3001
|
-
const content = await readFile$1(filePath, "utf-8");
|
|
3002
|
-
if (!content) {
|
|
3003
|
-
throw new FileSystemError("invalid_argument", "read", new Error(`File ${filePath} is empty`));
|
|
3004
|
-
}
|
|
3005
|
-
return content;
|
|
3006
|
-
} catch (error) {
|
|
3007
|
-
throw new FileSystemError("file_not_found", "read", error);
|
|
3008
|
-
}
|
|
3009
|
-
}
|
|
3010
3358
|
async function readMigrationFiles(options) {
|
|
3011
3359
|
const { space, path, filter } = options;
|
|
3012
3360
|
const resolvedPath = resolvePath(path, `migrations/${space}`);
|
|
3013
|
-
try {
|
|
3014
|
-
await readdir(resolvedPath);
|
|
3015
|
-
} catch (error) {
|
|
3016
|
-
const message = `No directory found for space "${space}". Please make sure you have pulled the migrations first by running:
|
|
3017
|
-
|
|
3018
|
-
storyblok migrations pull --space ${space}`;
|
|
3019
|
-
throw new FileSystemError(
|
|
3020
|
-
"file_not_found",
|
|
3021
|
-
"read",
|
|
3022
|
-
error,
|
|
3023
|
-
message
|
|
3024
|
-
);
|
|
3025
|
-
}
|
|
3026
3361
|
try {
|
|
3027
3362
|
const dirFiles = await readdir(resolvedPath);
|
|
3028
3363
|
const migrationFiles = [];
|
|
@@ -3035,20 +3370,21 @@ async function readMigrationFiles(options) {
|
|
|
3035
3370
|
if (filterRegex && !filterRegex.test(file)) {
|
|
3036
3371
|
continue;
|
|
3037
3372
|
}
|
|
3038
|
-
const filePath = join(resolvedPath, file);
|
|
3039
|
-
const content = await readJavascriptFile(filePath);
|
|
3040
3373
|
migrationFiles.push({
|
|
3041
|
-
name: file
|
|
3042
|
-
content
|
|
3374
|
+
name: file
|
|
3043
3375
|
});
|
|
3044
3376
|
}
|
|
3045
3377
|
}
|
|
3046
3378
|
return migrationFiles;
|
|
3047
3379
|
} catch (error) {
|
|
3380
|
+
const message = `No directory found for space "${space}". Please make sure you have generated migrations first by running:
|
|
3381
|
+
|
|
3382
|
+
storyblok migrations generate YOUR_COMPONENT_NAME --space ${space}`;
|
|
3048
3383
|
throw new FileSystemError(
|
|
3049
3384
|
"file_not_found",
|
|
3050
3385
|
"read",
|
|
3051
|
-
error
|
|
3386
|
+
error,
|
|
3387
|
+
message
|
|
3052
3388
|
);
|
|
3053
3389
|
}
|
|
3054
3390
|
}
|
|
@@ -3056,14 +3392,24 @@ async function getMigrationFunction(fileName, space, basePath) {
|
|
|
3056
3392
|
try {
|
|
3057
3393
|
const resolvedPath = resolvePath(basePath, `migrations/${space}`);
|
|
3058
3394
|
const filePath = join(resolvedPath, fileName);
|
|
3059
|
-
const migrationModule = await
|
|
3395
|
+
const migrationModule = await importModule(filePath);
|
|
3060
3396
|
if (typeof migrationModule.default === "function") {
|
|
3061
3397
|
return migrationModule.default;
|
|
3062
3398
|
}
|
|
3063
|
-
|
|
3399
|
+
getUI().error(`Migration file "${fileName}" does not export a default function.`);
|
|
3400
|
+
getLogger().error("Migration file does not export a default function", {
|
|
3401
|
+
fileName,
|
|
3402
|
+
errorCode: ERROR_CODES.MIGRATION_FILE_NO_DEFAULT_EXPORT
|
|
3403
|
+
});
|
|
3064
3404
|
return null;
|
|
3065
|
-
} catch (
|
|
3066
|
-
|
|
3405
|
+
} catch (maybeError) {
|
|
3406
|
+
const error = toError(maybeError);
|
|
3407
|
+
getUI().error(`Error loading migration function from "${fileName}": ${error.message}`);
|
|
3408
|
+
getLogger().error("Couldn't load migration function", {
|
|
3409
|
+
fileName,
|
|
3410
|
+
error,
|
|
3411
|
+
errorCode: ERROR_CODES.MIGRATION_LOAD_ERROR
|
|
3412
|
+
});
|
|
3067
3413
|
return null;
|
|
3068
3414
|
}
|
|
3069
3415
|
}
|
|
@@ -3200,6 +3546,10 @@ class MigrationStream extends Transform {
|
|
|
3200
3546
|
migrationNames: relevantMigrations.map((m) => m.name),
|
|
3201
3547
|
error: new Error("Story content is missing")
|
|
3202
3548
|
});
|
|
3549
|
+
getLogger().error("Failed to process story: Content is missing", {
|
|
3550
|
+
storyId: story.id,
|
|
3551
|
+
errorCode: ERROR_CODES.MIGRATION_STORY_CONTENT_MISSING
|
|
3552
|
+
});
|
|
3203
3553
|
return [];
|
|
3204
3554
|
}
|
|
3205
3555
|
const successfulResults = [];
|
|
@@ -3218,10 +3568,14 @@ class MigrationStream extends Transform {
|
|
|
3218
3568
|
for (const migrationFile of migrationFiles) {
|
|
3219
3569
|
const migrationFunction = await this.getOrLoadMigrationFunction(migrationFile);
|
|
3220
3570
|
if (!migrationFunction) {
|
|
3571
|
+
const error = new Error(`Failed to load migration function from file "${migrationFile.name}"`);
|
|
3221
3572
|
this.results.failed.push({
|
|
3222
3573
|
storyId: story.id,
|
|
3223
3574
|
migrationNames,
|
|
3224
|
-
error
|
|
3575
|
+
error
|
|
3576
|
+
});
|
|
3577
|
+
getLogger().error(error.message, {
|
|
3578
|
+
errorCode: ERROR_CODES.MIGRATION_FILE_NOT_FOUND
|
|
3225
3579
|
});
|
|
3226
3580
|
return null;
|
|
3227
3581
|
}
|
|
@@ -3251,6 +3605,7 @@ class MigrationStream extends Transform {
|
|
|
3251
3605
|
migrationNames,
|
|
3252
3606
|
content: storyContent
|
|
3253
3607
|
});
|
|
3608
|
+
getLogger().info("Applied migration", { storyId: story.id, migrationNames });
|
|
3254
3609
|
return {
|
|
3255
3610
|
storyId: story.id,
|
|
3256
3611
|
name: story.name,
|
|
@@ -3265,6 +3620,7 @@ class MigrationStream extends Transform {
|
|
|
3265
3620
|
migrationNames,
|
|
3266
3621
|
reason: "No changes detected after migration"
|
|
3267
3622
|
});
|
|
3623
|
+
getLogger().info("Skipped migration: No changes detected", { storyId: story.id, migrationNames });
|
|
3268
3624
|
return null;
|
|
3269
3625
|
} else {
|
|
3270
3626
|
const reason = migrationFiles.map((migrationFile) => {
|
|
@@ -3278,14 +3634,22 @@ class MigrationStream extends Transform {
|
|
|
3278
3634
|
migrationNames,
|
|
3279
3635
|
reason
|
|
3280
3636
|
});
|
|
3637
|
+
getLogger().info(`Skipped migration: ${reason}`, { storyId: story.id, migrationNames });
|
|
3281
3638
|
return null;
|
|
3282
3639
|
}
|
|
3283
|
-
} catch (
|
|
3640
|
+
} catch (maybeError) {
|
|
3641
|
+
const error = toError(maybeError);
|
|
3284
3642
|
this.results.failed.push({
|
|
3285
3643
|
storyId: story.id,
|
|
3286
3644
|
migrationNames,
|
|
3287
3645
|
error
|
|
3288
3646
|
});
|
|
3647
|
+
getLogger().error(error.message, {
|
|
3648
|
+
storyId: story.id,
|
|
3649
|
+
migrationNames,
|
|
3650
|
+
error,
|
|
3651
|
+
errorCode: ERROR_CODES.MIGRATION_APPLY_TO_STORY_ERROR
|
|
3652
|
+
});
|
|
3289
3653
|
return null;
|
|
3290
3654
|
}
|
|
3291
3655
|
}
|
|
@@ -3385,16 +3749,23 @@ class UpdateStream extends Writable {
|
|
|
3385
3749
|
this.results.successful.push({ storyId, name: storyName });
|
|
3386
3750
|
this.results.totalProcessed++;
|
|
3387
3751
|
this.options.onProgress?.(this.results.totalProcessed);
|
|
3752
|
+
getLogger().info("Updated story", { storyId });
|
|
3388
3753
|
} else {
|
|
3754
|
+
const error = new Error("Update returned null");
|
|
3389
3755
|
this.results.failed.push({
|
|
3390
3756
|
storyId,
|
|
3391
3757
|
name: storyName,
|
|
3392
|
-
error
|
|
3758
|
+
error
|
|
3393
3759
|
});
|
|
3394
3760
|
this.results.totalProcessed++;
|
|
3395
3761
|
this.options.onProgress?.(this.results.totalProcessed);
|
|
3762
|
+
getLogger().error(`Failed to update story: ${error.message}`, {
|
|
3763
|
+
storyId,
|
|
3764
|
+
errorCode: ERROR_CODES.MIGRATION_STORY_UPDATE_NULL
|
|
3765
|
+
});
|
|
3396
3766
|
}
|
|
3397
|
-
} catch (
|
|
3767
|
+
} catch (maybeError) {
|
|
3768
|
+
const error = toError(maybeError);
|
|
3398
3769
|
this.results.failed.push({
|
|
3399
3770
|
storyId,
|
|
3400
3771
|
name: storyName,
|
|
@@ -3402,6 +3773,11 @@ class UpdateStream extends Writable {
|
|
|
3402
3773
|
});
|
|
3403
3774
|
this.results.totalProcessed++;
|
|
3404
3775
|
this.options.onProgress?.(this.results.totalProcessed);
|
|
3776
|
+
getLogger().error(error.message, {
|
|
3777
|
+
storyId,
|
|
3778
|
+
error,
|
|
3779
|
+
errorCode: ERROR_CODES.MIGRATION_STORY_UPDATE_ERROR
|
|
3780
|
+
});
|
|
3405
3781
|
}
|
|
3406
3782
|
}
|
|
3407
3783
|
async _destroy(error, callback) {
|
|
@@ -3437,15 +3813,18 @@ class UpdateStream extends Writable {
|
|
|
3437
3813
|
}
|
|
3438
3814
|
}
|
|
3439
3815
|
|
|
3440
|
-
const program$8 = getProgram();
|
|
3441
3816
|
migrationsCommand.command("run [componentName]").description("Run migrations").option("--fi, --filter <filter>", "glob filter to apply to the components before pushing").option("-d, --dry-run", "Preview changes without applying them to Storyblok").option("-q, --query <query>", 'Filter stories by content attributes using Storyblok filter query syntax. Example: --query="[highlighted][in]=true"').option("--starts-with <path>", 'Filter stories by path. Example: --starts-with="/en/blog/"').option("--publish <publish>", "Options for publication mode: all | published | published-with-changes").action(async (componentName, options) => {
|
|
3442
|
-
|
|
3817
|
+
const program = getProgram();
|
|
3818
|
+
const ui = getUI();
|
|
3819
|
+
const logger = getLogger();
|
|
3820
|
+
ui.title(`${commands.MIGRATIONS}`, colorPalette.MIGRATIONS, componentName ? `Running migrations for component ${componentName}...` : "Running migrations...");
|
|
3821
|
+
logger.info("Migration started");
|
|
3443
3822
|
if (options.dryRun) {
|
|
3444
|
-
|
|
3823
|
+
ui.warn(`DRY RUN MODE ENABLED: No changes will be made.
|
|
3445
3824
|
`);
|
|
3825
|
+
logger.warn("Dry run mode enabled");
|
|
3446
3826
|
}
|
|
3447
|
-
const verbose = program
|
|
3448
|
-
const { filter, dryRun = false, query, startsWith, publish } = options;
|
|
3827
|
+
const verbose = program.opts().verbose;
|
|
3449
3828
|
const { space, path } = migrationsCommand.opts();
|
|
3450
3829
|
const { state, initializeSession } = session();
|
|
3451
3830
|
await initializeSession();
|
|
@@ -3456,6 +3835,7 @@ migrationsCommand.command("run [componentName]").description("Run migrations").o
|
|
|
3456
3835
|
handleError(new CommandError(`Please provide the space as argument --space YOUR_SPACE_ID.`), verbose);
|
|
3457
3836
|
return;
|
|
3458
3837
|
}
|
|
3838
|
+
const { filter, dryRun = false, query, startsWith, publish } = options;
|
|
3459
3839
|
const { password, region } = state;
|
|
3460
3840
|
mapiClient({
|
|
3461
3841
|
token: {
|
|
@@ -3464,40 +3844,25 @@ migrationsCommand.command("run [componentName]").description("Run migrations").o
|
|
|
3464
3844
|
region
|
|
3465
3845
|
});
|
|
3466
3846
|
try {
|
|
3467
|
-
const spinner =
|
|
3468
|
-
verbose: !isVitest
|
|
3469
|
-
}).start(`Fetching migration files and stories...`);
|
|
3847
|
+
const spinner = ui.createSpinner(`Fetching migration files and stories...`);
|
|
3470
3848
|
const migrationFiles = await readMigrationFiles({
|
|
3471
3849
|
space,
|
|
3472
3850
|
path,
|
|
3473
3851
|
filter
|
|
3474
3852
|
});
|
|
3475
|
-
if (migrationFiles.length === 0) {
|
|
3476
|
-
spinner.failed(`No migration files found for space "${space}"${filter ? ` matching filter "${filter}"` : ""}.`);
|
|
3477
|
-
return;
|
|
3478
|
-
}
|
|
3479
3853
|
const filteredMigrations = componentName ? migrationFiles.filter((file) => {
|
|
3480
3854
|
return file.name.match(new RegExp(`^${componentName}(\\..*)?.js$`));
|
|
3481
3855
|
}) : migrationFiles;
|
|
3482
3856
|
if (filteredMigrations.length === 0) {
|
|
3483
3857
|
spinner.failed(`No migration files found${componentName ? ` for component "${componentName}"` : ""}${filter ? ` matching filter "${filter}"` : ""} in space "${space}".`);
|
|
3858
|
+
logger.warn("No migration files found");
|
|
3859
|
+
logger.info("Migration finished");
|
|
3484
3860
|
return;
|
|
3485
3861
|
}
|
|
3486
3862
|
spinner.succeed(`Found ${filteredMigrations.length} migration files.`);
|
|
3487
|
-
const
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
etaBuffer: 60
|
|
3491
|
-
}, Presets.rect);
|
|
3492
|
-
const storiesProgress = multiBar.create(0, 0, {
|
|
3493
|
-
title: "Fetching Stories...".padEnd(19)
|
|
3494
|
-
});
|
|
3495
|
-
const migrationsProgress = multiBar.create(0, 0, {
|
|
3496
|
-
title: "Applying Migrations".padEnd(19)
|
|
3497
|
-
});
|
|
3498
|
-
const updateProgress = multiBar.create(0, 0, {
|
|
3499
|
-
title: "Updating Stories...".padEnd(19)
|
|
3500
|
-
});
|
|
3863
|
+
const storiesProgress = ui.createProgressBar({ title: "Fetching Stories...".padEnd(19) });
|
|
3864
|
+
const migrationsProgress = ui.createProgressBar({ title: "Applying Migrations".padEnd(19) });
|
|
3865
|
+
const updateProgress = ui.createProgressBar({ title: "Updating Stories...".padEnd(19) });
|
|
3501
3866
|
const storiesStream = await createStoriesStream({
|
|
3502
3867
|
spaceId: space,
|
|
3503
3868
|
params: {
|
|
@@ -3535,7 +3900,7 @@ migrationsCommand.command("run [componentName]").description("Run migrations").o
|
|
|
3535
3900
|
updateProgress.increment();
|
|
3536
3901
|
}
|
|
3537
3902
|
});
|
|
3538
|
-
|
|
3903
|
+
await new Promise((resolve, reject) => {
|
|
3539
3904
|
pipeline(
|
|
3540
3905
|
storiesStream,
|
|
3541
3906
|
migrationStream,
|
|
@@ -3545,25 +3910,51 @@ migrationsCommand.command("run [componentName]").description("Run migrations").o
|
|
|
3545
3910
|
reject(err);
|
|
3546
3911
|
return;
|
|
3547
3912
|
}
|
|
3548
|
-
multiBar.stop();
|
|
3549
|
-
const migrationSummary = migrationStream.getSummary();
|
|
3550
|
-
konsola.info(migrationSummary);
|
|
3551
|
-
const updateSummary = updateStream.getSummary();
|
|
3552
|
-
konsola.info(updateSummary);
|
|
3553
3913
|
resolve();
|
|
3554
3914
|
}
|
|
3555
3915
|
);
|
|
3556
3916
|
});
|
|
3917
|
+
ui.stopAllProgressBars();
|
|
3918
|
+
const migrationSummary = migrationStream.getSummary();
|
|
3919
|
+
ui.info(migrationSummary);
|
|
3920
|
+
const updateSummary = updateStream.getSummary();
|
|
3921
|
+
ui.info(updateSummary);
|
|
3922
|
+
const migrationResults = migrationStream.getResults();
|
|
3923
|
+
const updateResults = updateStream.getResults();
|
|
3924
|
+
logger.info("Migration finished", {
|
|
3925
|
+
migrationResults: {
|
|
3926
|
+
total: migrationResults.totalProcessed,
|
|
3927
|
+
succeeded: migrationResults.successful.length,
|
|
3928
|
+
skipped: migrationResults.skipped.length,
|
|
3929
|
+
failed: migrationResults.failed.length
|
|
3930
|
+
},
|
|
3931
|
+
updateResults: {
|
|
3932
|
+
total: updateResults.totalProcessed,
|
|
3933
|
+
succeeded: updateResults.successful.length,
|
|
3934
|
+
failed: updateResults.failed.length
|
|
3935
|
+
}
|
|
3936
|
+
});
|
|
3557
3937
|
} catch (error) {
|
|
3558
3938
|
handleError(error, verbose);
|
|
3559
3939
|
}
|
|
3560
3940
|
});
|
|
3561
3941
|
|
|
3562
|
-
const program$7 = getProgram();
|
|
3563
3942
|
migrationsCommand.command("rollback [migrationFile]").description("Rollback a migration").action(async (migrationFile) => {
|
|
3564
|
-
|
|
3565
|
-
const
|
|
3943
|
+
const program = getProgram();
|
|
3944
|
+
const ui = getUI();
|
|
3945
|
+
const logger = getLogger();
|
|
3946
|
+
ui.title(
|
|
3947
|
+
`${commands.MIGRATIONS}`,
|
|
3948
|
+
colorPalette.MIGRATIONS,
|
|
3949
|
+
migrationFile ? `Rolling back migration ${chalk.hex(colorPalette.MIGRATIONS)(migrationFile)}...` : "Rolling back migration..."
|
|
3950
|
+
);
|
|
3951
|
+
const verbose = program.opts().verbose;
|
|
3566
3952
|
const { space, path } = migrationsCommand.opts();
|
|
3953
|
+
logger.info("Migration rollback started", {
|
|
3954
|
+
migrationFile,
|
|
3955
|
+
space,
|
|
3956
|
+
path
|
|
3957
|
+
});
|
|
3567
3958
|
const { state, initializeSession } = session();
|
|
3568
3959
|
await initializeSession();
|
|
3569
3960
|
if (!requireAuthentication(state, verbose)) {
|
|
@@ -3586,8 +3977,13 @@ migrationsCommand.command("rollback [migrationFile]").description("Rollback a mi
|
|
|
3586
3977
|
path,
|
|
3587
3978
|
migrationFile
|
|
3588
3979
|
});
|
|
3980
|
+
const rollbackSummary = {
|
|
3981
|
+
total: rollbackData.stories.length,
|
|
3982
|
+
succeeded: 0,
|
|
3983
|
+
failed: 0
|
|
3984
|
+
};
|
|
3589
3985
|
for (const story of rollbackData.stories) {
|
|
3590
|
-
const spinner =
|
|
3986
|
+
const spinner = ui.createSpinner(`Restoring story ${chalk.hex(colorPalette.PRIMARY)(story.name || story.storyId)}...`);
|
|
3591
3987
|
try {
|
|
3592
3988
|
const payload = {
|
|
3593
3989
|
story: {
|
|
@@ -3603,18 +3999,37 @@ migrationsCommand.command("rollback [migrationFile]").description("Rollback a mi
|
|
|
3603
3999
|
}
|
|
3604
4000
|
}
|
|
3605
4001
|
await updateStory(space, story.storyId, payload);
|
|
3606
|
-
|
|
3607
|
-
|
|
4002
|
+
rollbackSummary.succeeded += 1;
|
|
4003
|
+
spinner.succeed(`Restored story ${chalk.hex(colorPalette.PRIMARY)(story.name || story.storyId)} - Completed in ${spinner.elapsedTime.toFixed(2)}ms`);
|
|
4004
|
+
logger.info("Story restored", {
|
|
4005
|
+
storyId: story.storyId,
|
|
4006
|
+
migrationFile,
|
|
4007
|
+
space
|
|
4008
|
+
});
|
|
4009
|
+
} catch (maybeError) {
|
|
4010
|
+
const error = toError(maybeError);
|
|
4011
|
+
rollbackSummary.failed += 1;
|
|
3608
4012
|
spinner.failed(`Failed to restore story ${chalk.hex(colorPalette.PRIMARY)(story.name || story.storyId)}: ${error.message}`);
|
|
4013
|
+
logger.error("Failed to restore story", {
|
|
4014
|
+
storyId: story.storyId,
|
|
4015
|
+
migrationFile,
|
|
4016
|
+
space,
|
|
4017
|
+
error
|
|
4018
|
+
});
|
|
3609
4019
|
}
|
|
3610
4020
|
}
|
|
4021
|
+
logger.info("Migration rollback finished", {
|
|
4022
|
+
migrationFile,
|
|
4023
|
+
space,
|
|
4024
|
+
results: rollbackSummary
|
|
4025
|
+
});
|
|
3611
4026
|
} catch (error) {
|
|
3612
4027
|
handleError(new CommandError(`Failed to rollback migration: ${error.message}`), verbose);
|
|
3613
4028
|
}
|
|
3614
4029
|
});
|
|
3615
4030
|
|
|
3616
|
-
const program$
|
|
3617
|
-
const typesCommand = program$
|
|
4031
|
+
const program$7 = getProgram();
|
|
4032
|
+
const typesCommand = program$7.command(commands.TYPES).alias("ts").description(`Generate types d.ts for your component schemas`).option("-s, --space <space>", "space ID").option("-p, --path <path>", "path to save the file. Default is .storyblok/types");
|
|
3618
4033
|
|
|
3619
4034
|
const getAssetJSONSchema = (title) => ({
|
|
3620
4035
|
$id: "#/asset",
|
|
@@ -4522,13 +4937,13 @@ async function readConsolidatedFiles(resolvedPath, suffix) {
|
|
|
4522
4937
|
};
|
|
4523
4938
|
}
|
|
4524
4939
|
|
|
4525
|
-
const program$
|
|
4940
|
+
const program$6 = getProgram();
|
|
4526
4941
|
typesCommand.command("generate").description("Generate types d.ts for your component schemas").option("--sf, --separate-files", "Generate one .d.ts file per component instead of a single combined file").option(
|
|
4527
4942
|
"--filename <name>",
|
|
4528
4943
|
"Base file name for all component types when generating a single declarations file (e.g. components.d.ts). Ignored when using --separate-files."
|
|
4529
4944
|
).option("--strict", "strict mode, no loose typing").option("--type-prefix <prefix>", "prefix to be prepended to all generated component type names").option("--type-suffix <suffix>", "suffix to be appended to all generated component type names").option("--suffix <suffix>", "Components suffix").option("--custom-fields-parser <path>", "Path to the parser file for Custom Field Types").option("--compiler-options <options>", "path to the compiler options from json-schema-to-typescript").action(async (options) => {
|
|
4530
4945
|
konsola.title(`${commands.TYPES}`, colorPalette.TYPES, "Generating types...");
|
|
4531
|
-
const verbose = program$
|
|
4946
|
+
const verbose = program$6.opts().verbose;
|
|
4532
4947
|
const { space, path } = typesCommand.opts();
|
|
4533
4948
|
const spinner = new Spinner({
|
|
4534
4949
|
verbose: !isVitest
|
|
@@ -4581,8 +4996,8 @@ typesCommand.command("generate").description("Generate types d.ts for your compo
|
|
|
4581
4996
|
}
|
|
4582
4997
|
});
|
|
4583
4998
|
|
|
4584
|
-
const program$
|
|
4585
|
-
const datasourcesCommand = program$
|
|
4999
|
+
const program$5 = getProgram();
|
|
5000
|
+
const datasourcesCommand = program$5.command(commands.DATASOURCES).alias("ds").description(`Manage your space's datasources`).option("-s, --space <space>", "space ID").option("-p, --path <path>", "path to save the file. Default is .storyblok/datasources");
|
|
4586
5001
|
|
|
4587
5002
|
async function fetchAllPages(fetchFunction, extractDataFunction, page = 1, collectedItems = []) {
|
|
4588
5003
|
const { data, response } = await fetchFunction(page);
|
|
@@ -4688,10 +5103,10 @@ const saveDatasourcesToFiles = async (space, datasources, options) => {
|
|
|
4688
5103
|
}
|
|
4689
5104
|
};
|
|
4690
5105
|
|
|
4691
|
-
const program$
|
|
5106
|
+
const program$4 = getProgram();
|
|
4692
5107
|
datasourcesCommand.command("pull [datasourceName]").option("-f, --filename <filename>", "custom name to be used in file(s) name instead of space id").option("--sf, --separate-files", "Argument to create a single file for each datasource").option("--su, --suffix <suffix>", "suffix to add to the file name (e.g. datasources.<suffix>.json)").description("Pull datasources from your space").action(async (datasourceName, options) => {
|
|
4693
5108
|
konsola.title(`${commands.DATASOURCES}`, colorPalette.DATASOURCES, datasourceName ? `Pulling datasource ${datasourceName}...` : "Pulling datasources...");
|
|
4694
|
-
const verbose = program$
|
|
5109
|
+
const verbose = program$4.opts().verbose;
|
|
4695
5110
|
const { space, path } = datasourcesCommand.opts();
|
|
4696
5111
|
const { separateFiles, suffix, filename = "datasources" } = options;
|
|
4697
5112
|
const { state, initializeSession } = session();
|
|
@@ -4760,10 +5175,10 @@ datasourcesCommand.command("pull [datasourceName]").option("-f, --filename <file
|
|
|
4760
5175
|
}
|
|
4761
5176
|
});
|
|
4762
5177
|
|
|
4763
|
-
const program$
|
|
5178
|
+
const program$3 = getProgram();
|
|
4764
5179
|
datasourcesCommand.command("push [datasourceName]").description(`Push your space's datasources schema as json`).option("-f, --from <from>", "source space id").option("--fi, --filter <filter>", "glob filter to apply to the datasources before pushing").option("--sf, --separate-files", "Read from separate files instead of consolidated files").option("--su, --suffix <suffix>", "Suffix to add to the datasource name").action(async (datasourceName, options) => {
|
|
4765
5180
|
konsola.title(`${commands.DATASOURCES}`, colorPalette.DATASOURCES, datasourceName ? `Pushing datasource ${datasourceName}...` : "Pushing datasources...");
|
|
4766
|
-
const verbose = program$
|
|
5181
|
+
const verbose = program$3.opts().verbose;
|
|
4767
5182
|
const { space, path } = datasourcesCommand.opts();
|
|
4768
5183
|
const { from, filter } = options;
|
|
4769
5184
|
const { state, initializeSession } = session();
|
|
@@ -5080,10 +5495,10 @@ const fetchBlueprintRepositories = async () => {
|
|
|
5080
5495
|
}
|
|
5081
5496
|
};
|
|
5082
5497
|
|
|
5083
|
-
const program$
|
|
5084
|
-
program$
|
|
5498
|
+
const program$2 = getProgram();
|
|
5499
|
+
program$2.command(`${commands.CREATE} [project-path]`).alias("c").description(`Scaffold a new project using Storyblok`).option("-t, --template <template>", "technology starter template").option("-b, --blueprint <blueprint>", "[DEPRECATED] use --template instead").option("--skip-space", "skip space creation").action(async (projectPath, options) => {
|
|
5085
5500
|
konsola.title(`${commands.CREATE}`, colorPalette.CREATE);
|
|
5086
|
-
const verbose = program$
|
|
5501
|
+
const verbose = program$2.opts().verbose;
|
|
5087
5502
|
const { template, blueprint } = options;
|
|
5088
5503
|
let selectedTemplate = template;
|
|
5089
5504
|
if (blueprint && !template) {
|
|
@@ -5271,7 +5686,31 @@ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
|
|
|
5271
5686
|
konsola.br();
|
|
5272
5687
|
});
|
|
5273
5688
|
|
|
5274
|
-
const
|
|
5689
|
+
const program$1 = getProgram();
|
|
5690
|
+
const logsCommand = program$1.command(commands.LOGS).alias("lg").description(`Inspect and manage logs.`).option("-s, --space <space>", "The space ID.").option("-p, --path <path>", "Path to the directory containing the logs directory. Defaults to '.storyblok'.");
|
|
5691
|
+
|
|
5692
|
+
logsCommand.command("list").description("List logs").action(async () => {
|
|
5693
|
+
const { space, path } = logsCommand.opts();
|
|
5694
|
+
const ui = getUI();
|
|
5695
|
+
const logsPath = getLogsPath(directories.log, space, path);
|
|
5696
|
+
const logFiles = FileTransport.listLogFiles(logsPath);
|
|
5697
|
+
if (logFiles.length === 0) {
|
|
5698
|
+
ui.info(`No logs found for space "${space}".`);
|
|
5699
|
+
return;
|
|
5700
|
+
}
|
|
5701
|
+
ui.info(`Found ${logFiles.length} log file${logFiles.length === 1 ? "" : "s"} for space "${space}":`);
|
|
5702
|
+
ui.list(logFiles);
|
|
5703
|
+
});
|
|
5704
|
+
|
|
5705
|
+
logsCommand.command("prune").description("Prune logs").option("--keep <number>", "Max number of log files to keep (default `0`, meaning remove all)", Number.parseInt, 0).action(async ({ keep }) => {
|
|
5706
|
+
const { space, path } = logsCommand.opts();
|
|
5707
|
+
const ui = getUI();
|
|
5708
|
+
const logsPath = getLogsPath(directories.log, space, path);
|
|
5709
|
+
const deletedFilesCount = FileTransport.pruneLogFiles(logsPath, keep);
|
|
5710
|
+
ui.info(`Deleted ${deletedFilesCount} log file${deletedFilesCount === 1 ? "" : "s"}`);
|
|
5711
|
+
});
|
|
5712
|
+
|
|
5713
|
+
const version = "4.8.0";
|
|
5275
5714
|
const pkg = {
|
|
5276
5715
|
version: version};
|
|
5277
5716
|
|