storyblok 4.17.0 → 4.17.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/dist/index.d.mts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.mjs +270 -92
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -68,7 +68,7 @@ interface StoryblokMultilinkUrl {
|
|
|
68
68
|
url: string;
|
|
69
69
|
full_slug: string;
|
|
70
70
|
}
|
|
71
|
-
interface
|
|
71
|
+
interface StoryblokMultilinkBase {
|
|
72
72
|
fieldtype: 'multilink';
|
|
73
73
|
id: string;
|
|
74
74
|
url: string;
|
|
@@ -78,10 +78,18 @@ interface StoryblokMultilink {
|
|
|
78
78
|
rel?: string;
|
|
79
79
|
title?: string;
|
|
80
80
|
prep?: string;
|
|
81
|
-
linktype: 'story' | 'url' | 'email' | 'asset';
|
|
82
|
-
story?: StoryblokMultilinkStory | StoryblokMultilinkLink | StoryblokMultilinkUrl;
|
|
83
|
-
email?: string;
|
|
84
81
|
}
|
|
82
|
+
type StoryblokMultilink = (StoryblokMultilinkBase & {
|
|
83
|
+
linktype: 'story';
|
|
84
|
+
story?: StoryblokMultilinkStory | StoryblokMultilinkLink | StoryblokMultilinkUrl;
|
|
85
|
+
}) | (StoryblokMultilinkBase & {
|
|
86
|
+
linktype: 'url';
|
|
87
|
+
}) | (StoryblokMultilinkBase & {
|
|
88
|
+
linktype: 'email';
|
|
89
|
+
email: string;
|
|
90
|
+
}) | (StoryblokMultilinkBase & {
|
|
91
|
+
linktype: 'asset';
|
|
92
|
+
});
|
|
85
93
|
interface StoryblokTable {
|
|
86
94
|
fieldtype: 'table';
|
|
87
95
|
thead: Array<{
|
package/dist/index.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ interface StoryblokMultilinkUrl {
|
|
|
68
68
|
url: string;
|
|
69
69
|
full_slug: string;
|
|
70
70
|
}
|
|
71
|
-
interface
|
|
71
|
+
interface StoryblokMultilinkBase {
|
|
72
72
|
fieldtype: 'multilink';
|
|
73
73
|
id: string;
|
|
74
74
|
url: string;
|
|
@@ -78,10 +78,18 @@ interface StoryblokMultilink {
|
|
|
78
78
|
rel?: string;
|
|
79
79
|
title?: string;
|
|
80
80
|
prep?: string;
|
|
81
|
-
linktype: 'story' | 'url' | 'email' | 'asset';
|
|
82
|
-
story?: StoryblokMultilinkStory | StoryblokMultilinkLink | StoryblokMultilinkUrl;
|
|
83
|
-
email?: string;
|
|
84
81
|
}
|
|
82
|
+
type StoryblokMultilink = (StoryblokMultilinkBase & {
|
|
83
|
+
linktype: 'story';
|
|
84
|
+
story?: StoryblokMultilinkStory | StoryblokMultilinkLink | StoryblokMultilinkUrl;
|
|
85
|
+
}) | (StoryblokMultilinkBase & {
|
|
86
|
+
linktype: 'url';
|
|
87
|
+
}) | (StoryblokMultilinkBase & {
|
|
88
|
+
linktype: 'email';
|
|
89
|
+
email: string;
|
|
90
|
+
}) | (StoryblokMultilinkBase & {
|
|
91
|
+
linktype: 'asset';
|
|
92
|
+
});
|
|
85
93
|
interface StoryblokTable {
|
|
86
94
|
fieldtype: 'table';
|
|
87
95
|
thead: Array<{
|
package/dist/index.mjs
CHANGED
|
@@ -578,10 +578,12 @@ function setActiveConfig(config) {
|
|
|
578
578
|
|
|
579
579
|
class FetchError extends Error {
|
|
580
580
|
response;
|
|
581
|
-
|
|
581
|
+
request;
|
|
582
|
+
constructor(message, response, request = {}) {
|
|
582
583
|
super(message);
|
|
583
584
|
this.name = "FetchError";
|
|
584
585
|
this.response = response;
|
|
586
|
+
this.request = request;
|
|
585
587
|
}
|
|
586
588
|
}
|
|
587
589
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -589,6 +591,7 @@ async function customFetch(url, options = {}) {
|
|
|
589
591
|
const { api } = getActiveConfig();
|
|
590
592
|
const maxRetries = options.maxRetries ?? api.maxRetries;
|
|
591
593
|
const baseDelay = options.baseDelay ?? 500;
|
|
594
|
+
const requestContext = { url, method: options.method ?? "GET" };
|
|
592
595
|
let attempt = 0;
|
|
593
596
|
while (attempt <= maxRetries) {
|
|
594
597
|
try {
|
|
@@ -612,7 +615,7 @@ async function customFetch(url, options = {}) {
|
|
|
612
615
|
status: response.status,
|
|
613
616
|
statusText: response.statusText,
|
|
614
617
|
data: null
|
|
615
|
-
});
|
|
618
|
+
}, requestContext);
|
|
616
619
|
}
|
|
617
620
|
if (!response.ok) {
|
|
618
621
|
if (response.status === 429 && attempt < maxRetries) {
|
|
@@ -625,7 +628,7 @@ async function customFetch(url, options = {}) {
|
|
|
625
628
|
status: response.status,
|
|
626
629
|
statusText: response.statusText,
|
|
627
630
|
data
|
|
628
|
-
});
|
|
631
|
+
}, requestContext);
|
|
629
632
|
}
|
|
630
633
|
return {
|
|
631
634
|
...data,
|
|
@@ -640,14 +643,14 @@ async function customFetch(url, options = {}) {
|
|
|
640
643
|
status: 0,
|
|
641
644
|
statusText: "Network Error",
|
|
642
645
|
data: null
|
|
643
|
-
});
|
|
646
|
+
}, requestContext);
|
|
644
647
|
}
|
|
645
648
|
}
|
|
646
649
|
throw new FetchError("Max retries exceeded", {
|
|
647
650
|
status: 429,
|
|
648
651
|
statusText: "Rate Limit Exceeded",
|
|
649
652
|
data: null
|
|
650
|
-
});
|
|
653
|
+
}, requestContext);
|
|
651
654
|
}
|
|
652
655
|
|
|
653
656
|
const API_ACTIONS = {
|
|
@@ -719,9 +722,14 @@ function handleAPIError(action, error, customMessage) {
|
|
|
719
722
|
}
|
|
720
723
|
const response = error?.response;
|
|
721
724
|
if (response?.status) {
|
|
725
|
+
const reqCandidate = error?.request;
|
|
722
726
|
const wrappedError = new FetchError(
|
|
723
727
|
response.statusText ?? error.message,
|
|
724
|
-
{ status: response.status, statusText: response.statusText ?? "", data: response.data }
|
|
728
|
+
{ status: response.status, statusText: response.statusText ?? "", data: response.data },
|
|
729
|
+
{
|
|
730
|
+
url: typeof reqCandidate?.url === "string" ? reqCandidate.url : void 0,
|
|
731
|
+
method: typeof reqCandidate?.method === "string" ? reqCandidate.method : void 0
|
|
732
|
+
}
|
|
725
733
|
);
|
|
726
734
|
const errorId = getErrorId(response.status);
|
|
727
735
|
throw new APIError(errorId, action, wrappedError, customMessage);
|
|
@@ -763,6 +771,8 @@ class APIError extends Error {
|
|
|
763
771
|
}
|
|
764
772
|
}
|
|
765
773
|
getInfo() {
|
|
774
|
+
const request = this.error?.request;
|
|
775
|
+
const hasRequestContext = Boolean(request && (request.url || request.method));
|
|
766
776
|
return {
|
|
767
777
|
name: this.name,
|
|
768
778
|
message: this.message,
|
|
@@ -770,7 +780,8 @@ class APIError extends Error {
|
|
|
770
780
|
cause: this.cause,
|
|
771
781
|
errorId: this.errorId,
|
|
772
782
|
stack: this.stack,
|
|
773
|
-
responseData: this.response?.data
|
|
783
|
+
responseData: this.response?.data,
|
|
784
|
+
...hasRequestContext ? { request: { url: request.url, method: request.method } } : {}
|
|
774
785
|
};
|
|
775
786
|
}
|
|
776
787
|
}
|
|
@@ -1106,7 +1117,7 @@ const isVitest = process.env.VITEST === "true";
|
|
|
1106
1117
|
const noopProgressBar = {
|
|
1107
1118
|
increment: () => {
|
|
1108
1119
|
},
|
|
1109
|
-
setTotal: (
|
|
1120
|
+
setTotal: () => {
|
|
1110
1121
|
},
|
|
1111
1122
|
stop: () => {
|
|
1112
1123
|
}
|
|
@@ -1190,7 +1201,17 @@ class UI {
|
|
|
1190
1201
|
}
|
|
1191
1202
|
}
|
|
1192
1203
|
createProgressBar(options) {
|
|
1193
|
-
|
|
1204
|
+
const bar = this.multiBar?.create(0, 0, options);
|
|
1205
|
+
if (!bar) {
|
|
1206
|
+
return noopProgressBar;
|
|
1207
|
+
}
|
|
1208
|
+
return {
|
|
1209
|
+
increment: (count = 1) => bar.increment(count),
|
|
1210
|
+
// cli-progress renders `{eta_formatted}` as "LLs" when total is 0.
|
|
1211
|
+
// Floor at 1 so an empty phase stays a clean 0/1 instead.
|
|
1212
|
+
setTotal: (total) => bar.setTotal(Math.max(total, 1)),
|
|
1213
|
+
stop: () => bar.stop()
|
|
1214
|
+
};
|
|
1194
1215
|
}
|
|
1195
1216
|
stopAllProgressBars() {
|
|
1196
1217
|
this.multiBar?.stop();
|
|
@@ -2258,16 +2279,40 @@ const DEFAULT_GROUPS_FILENAME = "groups";
|
|
|
2258
2279
|
const DEFAULT_PRESETS_FILENAME = "presets";
|
|
2259
2280
|
const DEFAULT_TAGS_FILENAME = "tags";
|
|
2260
2281
|
|
|
2282
|
+
async function fetchAllPages(fetchFunction, extractDataFunction) {
|
|
2283
|
+
const items = [];
|
|
2284
|
+
let page = 1;
|
|
2285
|
+
while (true) {
|
|
2286
|
+
const { data, response } = await fetchFunction(page);
|
|
2287
|
+
const totalHeader = response.headers.get("total");
|
|
2288
|
+
const fetchedItems = extractDataFunction(data);
|
|
2289
|
+
items.push(...fetchedItems);
|
|
2290
|
+
if (!totalHeader) {
|
|
2291
|
+
return items;
|
|
2292
|
+
}
|
|
2293
|
+
const total = Number(totalHeader);
|
|
2294
|
+
if (Number.isNaN(total) || items.length >= total || fetchedItems.length === 0) {
|
|
2295
|
+
return items;
|
|
2296
|
+
}
|
|
2297
|
+
page++;
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2261
2301
|
const fetchComponents = async (spaceId) => {
|
|
2262
2302
|
try {
|
|
2263
2303
|
const client = getMapiClient();
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2304
|
+
return await fetchAllPages(
|
|
2305
|
+
(page) => client.components.list({
|
|
2306
|
+
path: {
|
|
2307
|
+
space_id: Number(spaceId)
|
|
2308
|
+
},
|
|
2309
|
+
query: {
|
|
2310
|
+
page
|
|
2311
|
+
},
|
|
2312
|
+
throwOnError: true
|
|
2313
|
+
}),
|
|
2314
|
+
(data) => data?.components ?? []
|
|
2315
|
+
);
|
|
2271
2316
|
} catch (error) {
|
|
2272
2317
|
handleAPIError("pull_components", error);
|
|
2273
2318
|
}
|
|
@@ -2275,16 +2320,20 @@ const fetchComponents = async (spaceId) => {
|
|
|
2275
2320
|
const fetchComponent = async (spaceId, componentName) => {
|
|
2276
2321
|
try {
|
|
2277
2322
|
const client = getMapiClient();
|
|
2278
|
-
const
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2323
|
+
const matches = await fetchAllPages(
|
|
2324
|
+
(page) => client.components.list({
|
|
2325
|
+
path: {
|
|
2326
|
+
space_id: Number(spaceId)
|
|
2327
|
+
},
|
|
2328
|
+
query: {
|
|
2329
|
+
page,
|
|
2330
|
+
search: componentName
|
|
2331
|
+
},
|
|
2332
|
+
throwOnError: true
|
|
2333
|
+
}),
|
|
2334
|
+
(data) => data?.components ?? []
|
|
2335
|
+
);
|
|
2336
|
+
return matches.find((c) => c.name === componentName);
|
|
2288
2337
|
} catch (error) {
|
|
2289
2338
|
handleAPIError("pull_components", error, `Failed to fetch component ${componentName}`);
|
|
2290
2339
|
}
|
|
@@ -2318,12 +2367,19 @@ const fetchComponentPresets = async (spaceId) => {
|
|
|
2318
2367
|
const fetchComponentInternalTags = async (spaceId) => {
|
|
2319
2368
|
try {
|
|
2320
2369
|
const client = getMapiClient();
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2370
|
+
return await fetchAllPages(
|
|
2371
|
+
(page) => client.internalTags.list({
|
|
2372
|
+
path: {
|
|
2373
|
+
space_id: Number(spaceId)
|
|
2374
|
+
},
|
|
2375
|
+
query: {
|
|
2376
|
+
page,
|
|
2377
|
+
by_object_type: "component"
|
|
2378
|
+
},
|
|
2379
|
+
throwOnError: true
|
|
2380
|
+
}),
|
|
2381
|
+
(data) => data?.internal_tags ?? []
|
|
2382
|
+
);
|
|
2327
2383
|
} catch (error) {
|
|
2328
2384
|
handleAPIError("pull_component_internal_tags", error);
|
|
2329
2385
|
}
|
|
@@ -6104,20 +6160,6 @@ generateCmd.action(async (options, command) => {
|
|
|
6104
6160
|
const program$6 = getProgram();
|
|
6105
6161
|
const datasourcesCommand = program$6.command(commands.DATASOURCES).alias("ds").description(`Manage your space's datasources`);
|
|
6106
6162
|
|
|
6107
|
-
async function fetchAllPages(fetchFunction, extractDataFunction, page = 1, collectedItems = []) {
|
|
6108
|
-
const { data, response } = await fetchFunction(page);
|
|
6109
|
-
const totalHeader = response.headers.get("total");
|
|
6110
|
-
const total = Number(totalHeader);
|
|
6111
|
-
const fetchedItems = extractDataFunction(data);
|
|
6112
|
-
const allItems = [...collectedItems, ...fetchedItems];
|
|
6113
|
-
if (!totalHeader || Number.isNaN(total)) {
|
|
6114
|
-
return allItems;
|
|
6115
|
-
}
|
|
6116
|
-
if (allItems.length < total && fetchedItems.length > 0) {
|
|
6117
|
-
return fetchAllPages(fetchFunction, extractDataFunction, page + 1, allItems);
|
|
6118
|
-
}
|
|
6119
|
-
return allItems;
|
|
6120
|
-
}
|
|
6121
6163
|
const fetchDatasourceEntries = async (spaceId, datasourceId) => {
|
|
6122
6164
|
try {
|
|
6123
6165
|
const client = getMapiClient();
|
|
@@ -6170,16 +6212,20 @@ const fetchDatasources = async (spaceId) => {
|
|
|
6170
6212
|
const fetchDatasource = async (spaceId, datasourceName) => {
|
|
6171
6213
|
try {
|
|
6172
6214
|
const client = getMapiClient();
|
|
6173
|
-
const
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6215
|
+
const matches = await fetchAllPages(
|
|
6216
|
+
(page) => client.datasources.list({
|
|
6217
|
+
path: {
|
|
6218
|
+
space_id: Number(spaceId)
|
|
6219
|
+
},
|
|
6220
|
+
query: {
|
|
6221
|
+
page,
|
|
6222
|
+
search: datasourceName
|
|
6223
|
+
},
|
|
6224
|
+
throwOnError: true
|
|
6225
|
+
}),
|
|
6226
|
+
(data) => data.datasources || []
|
|
6227
|
+
);
|
|
6228
|
+
const found = matches.find((d) => d.name === datasourceName);
|
|
6183
6229
|
if (!found) {
|
|
6184
6230
|
return void 0;
|
|
6185
6231
|
}
|
|
@@ -8047,13 +8093,6 @@ const fetchStoryStream = ({
|
|
|
8047
8093
|
}
|
|
8048
8094
|
});
|
|
8049
8095
|
};
|
|
8050
|
-
const getUUIDFromFilename = (filename) => {
|
|
8051
|
-
const uuid = basename(filename, extname(filename)).split("_").at(-1);
|
|
8052
|
-
if (!uuid) {
|
|
8053
|
-
throw new Error(`Unable to extract UUID from local story "${filename}"`);
|
|
8054
|
-
}
|
|
8055
|
-
return uuid;
|
|
8056
|
-
};
|
|
8057
8096
|
const readLocalStoriesStream = ({
|
|
8058
8097
|
directoryPath,
|
|
8059
8098
|
fileFilter = () => true,
|
|
@@ -8063,7 +8102,7 @@ const readLocalStoriesStream = ({
|
|
|
8063
8102
|
onStoryError
|
|
8064
8103
|
}) => {
|
|
8065
8104
|
const listGenerator = async function* localStoryIterator() {
|
|
8066
|
-
const files = (await readDirectory(directoryPath)).filter((f) => extname(f) === ".json" && fileFilter({
|
|
8105
|
+
const files = (await readDirectory(directoryPath)).filter((f) => extname(f) === ".json" && fileFilter({ filename: f }));
|
|
8067
8106
|
setTotalStories?.(files.length);
|
|
8068
8107
|
for (const file of files) {
|
|
8069
8108
|
try {
|
|
@@ -8131,10 +8170,13 @@ const scanLocalStoryIndex = async ({
|
|
|
8131
8170
|
const filePath = join(directoryPath, file);
|
|
8132
8171
|
const fileContent = await readFile$1(filePath, "utf-8");
|
|
8133
8172
|
const story = JSON.parse(fileContent);
|
|
8173
|
+
if (!story.uuid) {
|
|
8174
|
+
throw new Error(`Story "${file}" is missing a uuid and cannot be pushed.`);
|
|
8175
|
+
}
|
|
8134
8176
|
entries.push({
|
|
8135
8177
|
filename: file,
|
|
8136
8178
|
id: story.id,
|
|
8137
|
-
uuid: story.uuid
|
|
8179
|
+
uuid: story.uuid,
|
|
8138
8180
|
slug: story.slug ?? "",
|
|
8139
8181
|
name: story.name ?? "",
|
|
8140
8182
|
full_slug: story.full_slug ?? "",
|
|
@@ -8968,6 +9010,105 @@ pullCmd.action(async (options, command) => {
|
|
|
8968
9010
|
}
|
|
8969
9011
|
});
|
|
8970
9012
|
|
|
9013
|
+
function formatStoryIdentifier(record) {
|
|
9014
|
+
const title = record.full_slug ?? record.slug ?? record.uuid ?? record.id?.toString() ?? record.filename ?? "unknown story";
|
|
9015
|
+
const extras = [];
|
|
9016
|
+
if (record.uuid && record.uuid !== title) {
|
|
9017
|
+
extras.push(`uuid: ${record.uuid}`);
|
|
9018
|
+
}
|
|
9019
|
+
if (record.filename && record.filename !== title) {
|
|
9020
|
+
extras.push(`file: ${record.filename}`);
|
|
9021
|
+
}
|
|
9022
|
+
return extras.length > 0 ? `${title} (${extras.join(", ")})` : title;
|
|
9023
|
+
}
|
|
9024
|
+
const ENRICHABLE_FIELDS = ["full_slug", "slug", "uuid", "id", "filename"];
|
|
9025
|
+
function enrichFieldMessage(detail, record) {
|
|
9026
|
+
const match = detail.match(/^(\w+):/);
|
|
9027
|
+
if (!match) {
|
|
9028
|
+
return detail;
|
|
9029
|
+
}
|
|
9030
|
+
const field = match[1];
|
|
9031
|
+
if (!ENRICHABLE_FIELDS.includes(field)) {
|
|
9032
|
+
return detail;
|
|
9033
|
+
}
|
|
9034
|
+
const value = record[field];
|
|
9035
|
+
if (value == null || value === "" || value instanceof Error) {
|
|
9036
|
+
return detail;
|
|
9037
|
+
}
|
|
9038
|
+
return `${field} (${String(value)})${detail.slice(field.length)}`;
|
|
9039
|
+
}
|
|
9040
|
+
function renderFailureReport(ui, records, verbose) {
|
|
9041
|
+
if (records.length === 0) {
|
|
9042
|
+
return;
|
|
9043
|
+
}
|
|
9044
|
+
ui.error(`Failed stories (${records.length}):`, void 0, { header: false, margin: false });
|
|
9045
|
+
const lines = [];
|
|
9046
|
+
for (const record of records) {
|
|
9047
|
+
lines.push(formatStoryIdentifier(record));
|
|
9048
|
+
const messages = record.error instanceof APIError ? record.error.messageStack : [record.error.message];
|
|
9049
|
+
const [primary, ...rest] = messages;
|
|
9050
|
+
lines.push(` \u2022 ${enrichFieldMessage(primary ?? "Unknown error", record)}`);
|
|
9051
|
+
for (const detail of rest) {
|
|
9052
|
+
lines.push(` \u2514\u2500 ${enrichFieldMessage(detail, record)}`);
|
|
9053
|
+
}
|
|
9054
|
+
if (verbose && record.error.stack) {
|
|
9055
|
+
for (const frame of record.error.stack.split("\n")) {
|
|
9056
|
+
lines.push(` ${frame}`);
|
|
9057
|
+
}
|
|
9058
|
+
}
|
|
9059
|
+
}
|
|
9060
|
+
ui.list(lines);
|
|
9061
|
+
ui.br();
|
|
9062
|
+
if (!verbose) {
|
|
9063
|
+
ui.info("Re-run with the `--verbose` flag for full stack traces.", { margin: false });
|
|
9064
|
+
}
|
|
9065
|
+
}
|
|
9066
|
+
class FailureCollector {
|
|
9067
|
+
records = /* @__PURE__ */ new Map();
|
|
9068
|
+
keyFor(story) {
|
|
9069
|
+
return story.full_slug ?? story.uuid ?? story.filename ?? `__unknown_${this.records.size}`;
|
|
9070
|
+
}
|
|
9071
|
+
/**
|
|
9072
|
+
* Record a failure. Returns `true` if this is the first failure seen for
|
|
9073
|
+
* this story's identity, `false` if one was already recorded (in which case
|
|
9074
|
+
* the caller should skip counter updates to avoid double-billing).
|
|
9075
|
+
*/
|
|
9076
|
+
record(story, error) {
|
|
9077
|
+
const key = this.keyFor(story);
|
|
9078
|
+
if (this.records.has(key)) {
|
|
9079
|
+
return false;
|
|
9080
|
+
}
|
|
9081
|
+
this.records.set(key, {
|
|
9082
|
+
filename: story.filename,
|
|
9083
|
+
full_slug: story.full_slug,
|
|
9084
|
+
slug: story.slug,
|
|
9085
|
+
uuid: story.uuid,
|
|
9086
|
+
id: story.id,
|
|
9087
|
+
error
|
|
9088
|
+
});
|
|
9089
|
+
return true;
|
|
9090
|
+
}
|
|
9091
|
+
get isEmpty() {
|
|
9092
|
+
return this.records.size === 0;
|
|
9093
|
+
}
|
|
9094
|
+
get size() {
|
|
9095
|
+
return this.records.size;
|
|
9096
|
+
}
|
|
9097
|
+
render(ui, verbose = false) {
|
|
9098
|
+
renderFailureReport(ui, [...this.records.values()], verbose);
|
|
9099
|
+
}
|
|
9100
|
+
toReporterMeta() {
|
|
9101
|
+
return [...this.records.values()].map((r) => ({
|
|
9102
|
+
filename: r.filename,
|
|
9103
|
+
full_slug: r.full_slug,
|
|
9104
|
+
slug: r.slug,
|
|
9105
|
+
uuid: r.uuid,
|
|
9106
|
+
id: r.id,
|
|
9107
|
+
error: r.error.message
|
|
9108
|
+
}));
|
|
9109
|
+
}
|
|
9110
|
+
}
|
|
9111
|
+
|
|
8971
9112
|
const pushCmd = storiesCommand.command("push").option("-s, --space <space>", "space ID").option("-f, --from <from>", "source space id").option("-d, --dry-run", "Preview changes without applying them to Storyblok").option("--publish", "Publish stories after pushing").option("--cleanup", "delete local stories after a successful push (note: does not cleanup manifests)").description(`Push local stories to a Storyblok space.`);
|
|
8972
9113
|
pushCmd.action(async (options, command) => {
|
|
8973
9114
|
const ui = getUI();
|
|
@@ -8991,6 +9132,7 @@ pushCmd.action(async (options, command) => {
|
|
|
8991
9132
|
return;
|
|
8992
9133
|
}
|
|
8993
9134
|
const pendingWarnings = [];
|
|
9135
|
+
const failures = new FailureCollector();
|
|
8994
9136
|
const summary = {
|
|
8995
9137
|
creationResults: { total: 0, succeeded: 0, skipped: 0, failed: 0 },
|
|
8996
9138
|
processResults: { total: 0, succeeded: 0, failed: 0 },
|
|
@@ -9064,8 +9206,10 @@ pushCmd.action(async (options, command) => {
|
|
|
9064
9206
|
scanProgress.increment();
|
|
9065
9207
|
},
|
|
9066
9208
|
onError(error, filename) {
|
|
9067
|
-
|
|
9068
|
-
|
|
9209
|
+
if (failures.record({ filename }, error)) {
|
|
9210
|
+
summary.creationResults.failed += 1;
|
|
9211
|
+
}
|
|
9212
|
+
logOnlyError(error, { storyFile: filename });
|
|
9069
9213
|
}
|
|
9070
9214
|
});
|
|
9071
9215
|
const levels = groupStoriesByDepth(storyIndex);
|
|
@@ -9093,8 +9237,11 @@ pushCmd.action(async (options, command) => {
|
|
|
9093
9237
|
dryRun: options.dryRun ?? false,
|
|
9094
9238
|
appendToManifest,
|
|
9095
9239
|
onStorySuccess(entry, remoteStory) {
|
|
9096
|
-
if (!entry.uuid
|
|
9097
|
-
throw new Error("
|
|
9240
|
+
if (!entry.uuid) {
|
|
9241
|
+
throw new Error(`Local story file "${entry.filename}" is missing a "uuid" field. Re-pull the story or add the uuid manually.`);
|
|
9242
|
+
}
|
|
9243
|
+
if (!remoteStory.uuid) {
|
|
9244
|
+
throw new Error(`Storyblok API returned a story without a uuid for slug "${entry.slug}".`);
|
|
9098
9245
|
}
|
|
9099
9246
|
maps.stories.set(entry.id, remoteStory.id);
|
|
9100
9247
|
maps.stories.set(entry.uuid, remoteStory.uuid);
|
|
@@ -9103,8 +9250,11 @@ pushCmd.action(async (options, command) => {
|
|
|
9103
9250
|
creationProgress.increment();
|
|
9104
9251
|
},
|
|
9105
9252
|
onStorySkipped(entry, remoteStory, reason) {
|
|
9106
|
-
if (!entry.uuid
|
|
9107
|
-
throw new Error("
|
|
9253
|
+
if (!entry.uuid) {
|
|
9254
|
+
throw new Error(`Local story file "${entry.filename}" is missing a "uuid" field. Re-pull the story or add the uuid manually.`);
|
|
9255
|
+
}
|
|
9256
|
+
if (!remoteStory.uuid) {
|
|
9257
|
+
throw new Error(`Storyblok API returned a story without a uuid for slug "${entry.slug}".`);
|
|
9108
9258
|
}
|
|
9109
9259
|
maps.stories.set(entry.id, remoteStory.id);
|
|
9110
9260
|
maps.stories.set(entry.uuid, remoteStory.uuid);
|
|
@@ -9113,13 +9263,15 @@ pushCmd.action(async (options, command) => {
|
|
|
9113
9263
|
creationProgress.increment();
|
|
9114
9264
|
},
|
|
9115
9265
|
onStoryError(error, entry) {
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9266
|
+
if (failures.record(entry, error)) {
|
|
9267
|
+
summary.creationResults.failed += 1;
|
|
9268
|
+
summary.processResults.total -= 1;
|
|
9269
|
+
summary.updateResults.total -= 1;
|
|
9270
|
+
processProgress.setTotal(summary.processResults.total);
|
|
9271
|
+
updateProgress.setTotal(summary.updateResults.total);
|
|
9272
|
+
}
|
|
9121
9273
|
creationProgress.increment();
|
|
9122
|
-
|
|
9274
|
+
logOnlyError(error, { storyId: entry.uuid });
|
|
9123
9275
|
}
|
|
9124
9276
|
});
|
|
9125
9277
|
}
|
|
@@ -9128,12 +9280,14 @@ pushCmd.action(async (options, command) => {
|
|
|
9128
9280
|
pendingWarnings.push(message);
|
|
9129
9281
|
logger.warn(message);
|
|
9130
9282
|
}
|
|
9283
|
+
const uuidByFilename = new Map(storyIndex.map((entry) => [entry.filename, entry.uuid]));
|
|
9131
9284
|
await pipeline$1(
|
|
9132
9285
|
// Read local stories from `.json` files.
|
|
9133
9286
|
readLocalStoriesStream({
|
|
9134
9287
|
directoryPath: storiesDirectoryPath,
|
|
9135
|
-
fileFilter({
|
|
9136
|
-
|
|
9288
|
+
fileFilter({ filename }) {
|
|
9289
|
+
const uuid = uuidByFilename.get(filename);
|
|
9290
|
+
return uuid != null && Boolean(maps.stories.get(uuid));
|
|
9137
9291
|
},
|
|
9138
9292
|
setTotalStories(total) {
|
|
9139
9293
|
summary.processResults.total = total;
|
|
@@ -9142,12 +9296,15 @@ pushCmd.action(async (options, command) => {
|
|
|
9142
9296
|
updateProgress.setTotal(total);
|
|
9143
9297
|
},
|
|
9144
9298
|
onStoryError(error, filename) {
|
|
9145
|
-
|
|
9146
|
-
|
|
9299
|
+
if (failures.record({ filename }, error)) {
|
|
9300
|
+
summary.processResults.failed += 1;
|
|
9301
|
+
} else {
|
|
9302
|
+
summary.processResults.total -= 1;
|
|
9303
|
+
processProgress.setTotal(summary.processResults.total);
|
|
9304
|
+
}
|
|
9147
9305
|
summary.updateResults.total -= 1;
|
|
9148
|
-
processProgress.setTotal(summary.processResults.total);
|
|
9149
9306
|
updateProgress.setTotal(summary.updateResults.total);
|
|
9150
|
-
|
|
9307
|
+
logOnlyError(error, { storyFile: filename });
|
|
9151
9308
|
}
|
|
9152
9309
|
}),
|
|
9153
9310
|
// Map all references to numeric ids and uuids.
|
|
@@ -9163,10 +9320,15 @@ pushCmd.action(async (options, command) => {
|
|
|
9163
9320
|
summary.processResults.succeeded += 1;
|
|
9164
9321
|
},
|
|
9165
9322
|
onStoryError(error, localStory) {
|
|
9166
|
-
|
|
9323
|
+
logOnlyError(error, { storyId: localStory.uuid });
|
|
9324
|
+
if (failures.record(localStory, error)) {
|
|
9325
|
+
summary.processResults.failed += 1;
|
|
9326
|
+
} else {
|
|
9327
|
+
summary.processResults.total -= 1;
|
|
9328
|
+
processProgress.setTotal(summary.processResults.total);
|
|
9329
|
+
}
|
|
9167
9330
|
summary.updateResults.total -= 1;
|
|
9168
9331
|
updateProgress.setTotal(summary.updateResults.total);
|
|
9169
|
-
handleError(error, verbose, { storyId: localStory.uuid });
|
|
9170
9332
|
}
|
|
9171
9333
|
}),
|
|
9172
9334
|
// Update remote stories with correct references.
|
|
@@ -9186,8 +9348,13 @@ pushCmd.action(async (options, command) => {
|
|
|
9186
9348
|
summary.updateResults.succeeded += 1;
|
|
9187
9349
|
},
|
|
9188
9350
|
onStoryError(error, localStory) {
|
|
9189
|
-
|
|
9190
|
-
|
|
9351
|
+
logOnlyError(error, { storyId: localStory.uuid });
|
|
9352
|
+
if (failures.record(localStory, error)) {
|
|
9353
|
+
summary.updateResults.failed += 1;
|
|
9354
|
+
} else {
|
|
9355
|
+
summary.updateResults.total -= 1;
|
|
9356
|
+
updateProgress.setTotal(summary.updateResults.total);
|
|
9357
|
+
}
|
|
9191
9358
|
}
|
|
9192
9359
|
})
|
|
9193
9360
|
);
|
|
@@ -9196,19 +9363,30 @@ pushCmd.action(async (options, command) => {
|
|
|
9196
9363
|
} finally {
|
|
9197
9364
|
logger.info("Pushing stories finished", summary);
|
|
9198
9365
|
ui.stopAllProgressBars();
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
}
|
|
9202
|
-
const failedStories = Math.max(summary.creationResults.failed, summary.processResults.failed, summary.updateResults.failed);
|
|
9203
|
-
ui.info(`Push results: ${summary.creationResults.total} ${summary.creationResults.total === 1 ? "story" : "stories"} pushed, ${failedStories} ${failedStories === 1 ? "story" : "stories"} failed`);
|
|
9366
|
+
ui.br();
|
|
9367
|
+
const failedCount = failures.size;
|
|
9368
|
+
ui.info(`Push results: ${summary.creationResults.total} ${summary.creationResults.total === 1 ? "story" : "stories"} pushed, ${failedCount} ${failedCount === 1 ? "story" : "stories"} failed`);
|
|
9204
9369
|
ui.list([
|
|
9205
9370
|
`Creating stories: ${summary.creationResults.succeeded + summary.creationResults.skipped}/${summary.creationResults.total} succeeded, ${summary.creationResults.failed} failed.`,
|
|
9206
9371
|
`Processing stories: ${summary.processResults.succeeded}/${summary.processResults.total} succeeded, ${summary.processResults.failed} failed.`,
|
|
9207
9372
|
`Updating stories: ${summary.updateResults.succeeded}/${summary.updateResults.total} succeeded, ${summary.updateResults.failed} failed.`
|
|
9208
9373
|
]);
|
|
9374
|
+
if (pendingWarnings.length > 0 || !failures.isEmpty) {
|
|
9375
|
+
ui.br();
|
|
9376
|
+
}
|
|
9377
|
+
for (const warning of pendingWarnings) {
|
|
9378
|
+
ui.warn(warning);
|
|
9379
|
+
}
|
|
9380
|
+
if (pendingWarnings.length > 0 && !failures.isEmpty) {
|
|
9381
|
+
ui.br();
|
|
9382
|
+
}
|
|
9383
|
+
failures.render(ui, verbose);
|
|
9209
9384
|
reporter.addSummary("creationResults", summary.creationResults);
|
|
9210
9385
|
reporter.addSummary("processResults", summary.processResults);
|
|
9211
9386
|
reporter.addSummary("updateResults", summary.updateResults);
|
|
9387
|
+
if (!failures.isEmpty) {
|
|
9388
|
+
reporter.addMeta("failedStories", failures.toReporterMeta());
|
|
9389
|
+
}
|
|
9212
9390
|
reporter.finalize();
|
|
9213
9391
|
}
|
|
9214
9392
|
});
|