@learnpack/learnpack 5.0.344 → 5.0.347
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/lib/commands/publish.d.ts +7 -1
- package/lib/commands/publish.js +71 -21
- package/lib/commands/serve.js +126 -28
- package/lib/utils/api.d.ts +25 -1
- package/lib/utils/api.js +71 -18
- package/package.json +1 -1
- package/src/commands/publish.ts +122 -30
- package/src/commands/serve.ts +146 -47
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +511 -512
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/api.ts +93 -21
package/src/commands/publish.ts
CHANGED
|
@@ -54,6 +54,54 @@ const getLocalizedValue = (
|
|
|
54
54
|
return typeof first === "string" ? first : ""
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
type ExistingAssetInfo = {
|
|
58
|
+
lang: string;
|
|
59
|
+
slug: string;
|
|
60
|
+
exists: boolean;
|
|
61
|
+
academyId?: number;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type AcademyMode =
|
|
65
|
+
| { type: "select" }
|
|
66
|
+
| { type: "locked"; academyId: number }
|
|
67
|
+
| { type: "conflict"; academies: number[] };
|
|
68
|
+
|
|
69
|
+
const getExistingAssetsInfo = async (
|
|
70
|
+
token: string,
|
|
71
|
+
learnJson: any
|
|
72
|
+
): Promise<ExistingAssetInfo[]> => {
|
|
73
|
+
const availableLangs = getAvailableLangs(learnJson)
|
|
74
|
+
const results: ExistingAssetInfo[] = []
|
|
75
|
+
|
|
76
|
+
for (const lang of availableLangs) {
|
|
77
|
+
const assetTitle = getLocalizedValue(learnJson?.title, lang)
|
|
78
|
+
if (!assetTitle) continue
|
|
79
|
+
|
|
80
|
+
let slug = slugify(assetTitle).slice(0, 47)
|
|
81
|
+
slug = `${slug}-${lang}`
|
|
82
|
+
|
|
83
|
+
// eslint-disable-next-line no-await-in-loop
|
|
84
|
+
const { exists, academyId } = await api.doesAssetExists(token, slug)
|
|
85
|
+
results.push({ lang, slug, exists, academyId })
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return results
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const determinePublishAcademyMode = (
|
|
92
|
+
existingAssets: ExistingAssetInfo[]
|
|
93
|
+
): AcademyMode => {
|
|
94
|
+
const academyIds = existingAssets
|
|
95
|
+
.filter((a) => a.exists && a.academyId !== undefined)
|
|
96
|
+
.map((a) => a.academyId as number)
|
|
97
|
+
|
|
98
|
+
const unique = [...new Set(academyIds)]
|
|
99
|
+
|
|
100
|
+
if (unique.length === 0) return { type: "select" }
|
|
101
|
+
if (unique.length === 1) return { type: "locked", academyId: unique[0] }
|
|
102
|
+
return { type: "conflict", academies: unique }
|
|
103
|
+
}
|
|
104
|
+
|
|
57
105
|
export const handleAssetCreation = async (
|
|
58
106
|
sessionPayload: { token: string; rigobotToken: string },
|
|
59
107
|
learnJson: any,
|
|
@@ -61,6 +109,8 @@ export const handleAssetCreation = async (
|
|
|
61
109
|
learnpackDeployUrl: string,
|
|
62
110
|
b64IndexReadme: string,
|
|
63
111
|
academyId: number | undefined,
|
|
112
|
+
learnpackId: number,
|
|
113
|
+
preflightInfo?: ExistingAssetInfo,
|
|
64
114
|
all_translations: string[] = []
|
|
65
115
|
) => {
|
|
66
116
|
const category = "uncategorized"
|
|
@@ -83,23 +133,9 @@ export const handleAssetCreation = async (
|
|
|
83
133
|
let slug = slugify(assetTitle).slice(0, 47)
|
|
84
134
|
slug = `${slug}-${selectedLang}`
|
|
85
135
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
slug
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
// Compare academy IDs if asset exists and academyId is provided
|
|
92
|
-
if (
|
|
93
|
-
exists &&
|
|
94
|
-
existingAcademyId !== undefined &&
|
|
95
|
-
academyId !== undefined &&
|
|
96
|
-
existingAcademyId !== academyId
|
|
97
|
-
) {
|
|
98
|
-
Console.warning(
|
|
99
|
-
`Asset exists in academy ${existingAcademyId}, but attempting to publish to academy ${academyId}. ` +
|
|
100
|
-
`The asset will be updated in its current academy (${existingAcademyId}).`
|
|
101
|
-
)
|
|
102
|
-
}
|
|
136
|
+
// Use pre-flight info when available to avoid an extra GET request
|
|
137
|
+
const { exists, academyId: existingAcademyId } =
|
|
138
|
+
preflightInfo ?? (await api.doesAssetExists(sessionPayload.token, slug))
|
|
103
139
|
|
|
104
140
|
// const technologies: unknown[] = Array.isArray(learnJson?.technologies) ?
|
|
105
141
|
// learnJson.technologies :
|
|
@@ -125,6 +161,7 @@ export const handleAssetCreation = async (
|
|
|
125
161
|
preview: learnJson.preview,
|
|
126
162
|
readme_raw: b64IndexReadme,
|
|
127
163
|
all_translations,
|
|
164
|
+
learnpack_id: learnpackId,
|
|
128
165
|
}
|
|
129
166
|
if (academyId !== undefined) {
|
|
130
167
|
assetPayload.academy_id = academyId
|
|
@@ -148,14 +185,25 @@ export const handleAssetCreation = async (
|
|
|
148
185
|
}
|
|
149
186
|
|
|
150
187
|
Console.info("Asset exists, updating it")
|
|
151
|
-
const
|
|
188
|
+
const updatePayload: any = {
|
|
152
189
|
graded: true,
|
|
153
190
|
learnpack_deploy_url: learnpackDeployUrl,
|
|
154
191
|
title: assetTitle,
|
|
155
192
|
category: category,
|
|
156
193
|
description: assetDescription,
|
|
157
194
|
all_translations,
|
|
158
|
-
|
|
195
|
+
learnpack_id: learnpackId,
|
|
196
|
+
}
|
|
197
|
+
// Only set academy when the asset has none yet and the user selected one
|
|
198
|
+
if (existingAcademyId === undefined && academyId !== undefined) {
|
|
199
|
+
updatePayload.academy_id = academyId
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const asset = await api.updateAsset(
|
|
203
|
+
sessionPayload.token,
|
|
204
|
+
slug,
|
|
205
|
+
updatePayload
|
|
206
|
+
)
|
|
159
207
|
try {
|
|
160
208
|
await api.updateRigoPackage(
|
|
161
209
|
sessionPayload.rigobotToken.trim(),
|
|
@@ -179,7 +227,9 @@ export const handleAssetCreation = async (
|
|
|
179
227
|
const createMultiLangAssetFromDisk = async (
|
|
180
228
|
sessionPayload: { token: string; rigobotToken: string },
|
|
181
229
|
learnJson: any,
|
|
182
|
-
deployUrl: string
|
|
230
|
+
deployUrl: string,
|
|
231
|
+
selectedAcademyId?: number,
|
|
232
|
+
existingAssetsInfo: ExistingAssetInfo[] = []
|
|
183
233
|
) => {
|
|
184
234
|
const availableLangs = getAvailableLangs(learnJson)
|
|
185
235
|
|
|
@@ -190,6 +240,17 @@ const createMultiLangAssetFromDisk = async (
|
|
|
190
240
|
return
|
|
191
241
|
}
|
|
192
242
|
|
|
243
|
+
const learnpackId = await api.resolveLearnpackPackageId(
|
|
244
|
+
sessionPayload.rigobotToken,
|
|
245
|
+
learnJson.slug
|
|
246
|
+
)
|
|
247
|
+
if (learnpackId === null) {
|
|
248
|
+
Console.warning(
|
|
249
|
+
"Breathecode assets skipped: could not resolve Learnpack package id"
|
|
250
|
+
)
|
|
251
|
+
return
|
|
252
|
+
}
|
|
253
|
+
|
|
193
254
|
const all_translations: string[] = []
|
|
194
255
|
for (const lang of availableLangs) {
|
|
195
256
|
const readmePath = path.join(
|
|
@@ -208,6 +269,7 @@ const createMultiLangAssetFromDisk = async (
|
|
|
208
269
|
}
|
|
209
270
|
|
|
210
271
|
const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64")
|
|
272
|
+
const preflightInfo = existingAssetsInfo.find((a) => a.lang === lang)
|
|
211
273
|
|
|
212
274
|
try {
|
|
213
275
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -217,7 +279,9 @@ const createMultiLangAssetFromDisk = async (
|
|
|
217
279
|
lang,
|
|
218
280
|
deployUrl,
|
|
219
281
|
b64IndexReadme,
|
|
220
|
-
|
|
282
|
+
selectedAcademyId,
|
|
283
|
+
learnpackId,
|
|
284
|
+
preflightInfo,
|
|
221
285
|
all_translations
|
|
222
286
|
)
|
|
223
287
|
|
|
@@ -406,6 +470,13 @@ class BuildCommand extends SessionCommand {
|
|
|
406
470
|
this.configManager?.buildIndex()
|
|
407
471
|
}
|
|
408
472
|
|
|
473
|
+
const learnJsonPath = path.join(process.cwd(), "learn.json")
|
|
474
|
+
if (!fs.existsSync(learnJsonPath)) {
|
|
475
|
+
this.error("learn.json not found")
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const learnJson = JSON.parse(fs.readFileSync(learnJsonPath, "utf-8"))
|
|
479
|
+
|
|
409
480
|
const academies = await api.listUserAcademies(sessionPayload.token)
|
|
410
481
|
|
|
411
482
|
if (academies.length === 0) {
|
|
@@ -415,17 +486,36 @@ class BuildCommand extends SessionCommand {
|
|
|
415
486
|
process.exit(1)
|
|
416
487
|
}
|
|
417
488
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
sessionPayload.token
|
|
489
|
+
Console.info("Checking existing assets...")
|
|
490
|
+
const existingAssetsInfo = await getExistingAssetsInfo(
|
|
491
|
+
sessionPayload.token,
|
|
492
|
+
learnJson
|
|
421
493
|
)
|
|
494
|
+
const academyMode = determinePublishAcademyMode(existingAssetsInfo)
|
|
422
495
|
|
|
423
|
-
|
|
424
|
-
if (!fs.existsSync(learnJsonPath)) {
|
|
425
|
-
this.error("learn.json not found")
|
|
426
|
-
}
|
|
496
|
+
let selectedAcademyId: number | undefined
|
|
427
497
|
|
|
428
|
-
|
|
498
|
+
if (academyMode.type === "conflict") {
|
|
499
|
+
Console.warning(
|
|
500
|
+
`Some of your assets are associated with different academies ` +
|
|
501
|
+
`(${academyMode.academies.join(", ")}). ` +
|
|
502
|
+
`Academy assignment will be skipped to avoid conflicts.`
|
|
503
|
+
)
|
|
504
|
+
} else if (academyMode.type === "locked") {
|
|
505
|
+
const lockedAcademy = academies.find(
|
|
506
|
+
(a) => a.id === academyMode.academyId
|
|
507
|
+
)
|
|
508
|
+
Console.info(
|
|
509
|
+
`This package is associated with academy: ${
|
|
510
|
+
lockedAcademy?.name ?? academyMode.academyId
|
|
511
|
+
}. Academy cannot be changed.`
|
|
512
|
+
)
|
|
513
|
+
selectedAcademyId = academyMode.academyId
|
|
514
|
+
} else {
|
|
515
|
+
// mode === "select": all existing assets have no academy, user picks one
|
|
516
|
+
const { academy } = await selectAcademy(academies, sessionPayload.token)
|
|
517
|
+
selectedAcademyId = academy?.id
|
|
518
|
+
}
|
|
429
519
|
|
|
430
520
|
const zipFilePath = path.join(process.cwd(), `${learnJson.slug}.zip`)
|
|
431
521
|
|
|
@@ -595,7 +685,9 @@ class BuildCommand extends SessionCommand {
|
|
|
595
685
|
await createMultiLangAssetFromDisk(
|
|
596
686
|
{ token: sessionPayload.token, rigobotToken: rigoToken },
|
|
597
687
|
learnJson,
|
|
598
|
-
res.data.url
|
|
688
|
+
res.data.url,
|
|
689
|
+
selectedAcademyId,
|
|
690
|
+
existingAssetsInfo
|
|
599
691
|
)
|
|
600
692
|
} catch (error) {
|
|
601
693
|
if (axios.isAxiosError(error)) {
|
package/src/commands/serve.ts
CHANGED
|
@@ -55,6 +55,8 @@ import api, {
|
|
|
55
55
|
RIGOBOT_REALTIME_HOST,
|
|
56
56
|
listUserAcademies,
|
|
57
57
|
doesAssetExists,
|
|
58
|
+
type AssetSyncError,
|
|
59
|
+
resolveLearnpackPackageId,
|
|
58
60
|
} from "../utils/api"
|
|
59
61
|
import {
|
|
60
62
|
createUploadMiddleware,
|
|
@@ -87,7 +89,8 @@ import { HistoryManager } from "../managers/historyManager"
|
|
|
87
89
|
import { ReadmeHistoryService } from "../managers/readmeHistoryService"
|
|
88
90
|
import { sanitizeReadmeNewlines } from "../utils/readmeSanitizer"
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
// eslint-disable-next-line
|
|
93
|
+
const frontMatter = require("front-matter");
|
|
91
94
|
|
|
92
95
|
if (process.env.NEW_RELIC_ENABLED === "true") {
|
|
93
96
|
require("newrelic")
|
|
@@ -582,6 +585,16 @@ const getLocalizedValue = (
|
|
|
582
585
|
return typeof first === "string" ? first : ""
|
|
583
586
|
}
|
|
584
587
|
|
|
588
|
+
function assetSyncErrorDetail(err: any): string {
|
|
589
|
+
if (typeof err?.detail === "string") return err.detail
|
|
590
|
+
if (typeof err?.message === "string") return err.message
|
|
591
|
+
try {
|
|
592
|
+
return JSON.stringify(err)
|
|
593
|
+
} catch {
|
|
594
|
+
return String(err)
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
585
598
|
const createMultiLangAsset = async (
|
|
586
599
|
bucket: Bucket,
|
|
587
600
|
rigoToken: string,
|
|
@@ -590,12 +603,27 @@ const createMultiLangAsset = async (
|
|
|
590
603
|
courseJson: any,
|
|
591
604
|
deployUrl: string,
|
|
592
605
|
academyId?: number
|
|
593
|
-
): Promise<{ errors:
|
|
606
|
+
): Promise<{ errors: AssetSyncError[] }> => {
|
|
607
|
+
const learnpackId = await resolveLearnpackPackageId(rigoToken, courseSlug)
|
|
608
|
+
if (learnpackId === null) {
|
|
609
|
+
return {
|
|
610
|
+
errors: [
|
|
611
|
+
{
|
|
612
|
+
kind: "package_error",
|
|
613
|
+
error: {
|
|
614
|
+
detail:
|
|
615
|
+
"Could not resolve Learnpack package id; assets not synced to Breathecode.",
|
|
616
|
+
},
|
|
617
|
+
},
|
|
618
|
+
],
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
594
622
|
const availableLangs = Object.keys(courseJson.title)
|
|
595
623
|
console.log("AVAILABLE LANGUAGES to upload asset", availableLangs)
|
|
596
624
|
|
|
597
625
|
const all_translations: string[] = []
|
|
598
|
-
const errors:
|
|
626
|
+
const errors: AssetSyncError[] = []
|
|
599
627
|
|
|
600
628
|
for (const lang of availableLangs) {
|
|
601
629
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -624,13 +652,16 @@ const createMultiLangAsset = async (
|
|
|
624
652
|
deployUrl,
|
|
625
653
|
b64IndexReadme,
|
|
626
654
|
academyId,
|
|
655
|
+
learnpackId,
|
|
656
|
+
undefined,
|
|
627
657
|
all_translations
|
|
628
658
|
)
|
|
629
659
|
|
|
630
660
|
if (!asset) {
|
|
631
661
|
errors.push({
|
|
662
|
+
kind: "lang_error",
|
|
632
663
|
lang,
|
|
633
|
-
error: { detail: "Failed to create asset"
|
|
664
|
+
error: { detail: "Failed to create asset" },
|
|
634
665
|
})
|
|
635
666
|
console.log("No se pudo crear el asset, saltando idioma", lang)
|
|
636
667
|
continue
|
|
@@ -642,7 +673,11 @@ const createMultiLangAsset = async (
|
|
|
642
673
|
error && typeof error === "object" && "response" in error ?
|
|
643
674
|
(error as any).response?.data || error :
|
|
644
675
|
error
|
|
645
|
-
errors.push({
|
|
676
|
+
errors.push({
|
|
677
|
+
kind: "lang_error",
|
|
678
|
+
lang,
|
|
679
|
+
error: { detail: assetSyncErrorDetail(errorData) },
|
|
680
|
+
})
|
|
646
681
|
console.error(`Error creating asset for language ${lang}:`, error)
|
|
647
682
|
}
|
|
648
683
|
}
|
|
@@ -5451,30 +5486,56 @@ class ServeCommand extends SessionCommand {
|
|
|
5451
5486
|
const { config } = configJson
|
|
5452
5487
|
|
|
5453
5488
|
const availableLangs = Object.keys(config.title || {})
|
|
5454
|
-
let academyId: number | null = null
|
|
5455
5489
|
let isPublished = false
|
|
5456
5490
|
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
if (!assetTitle) continue
|
|
5491
|
+
// Collect academy ids from all existing assets
|
|
5492
|
+
const foundAcademyIds: number[] = []
|
|
5460
5493
|
|
|
5461
|
-
|
|
5462
|
-
|
|
5494
|
+
const slugsToCheck = availableLangs
|
|
5495
|
+
.map(lang => {
|
|
5496
|
+
const assetTitle = getLocalizedValue(config.title, lang)
|
|
5497
|
+
if (!assetTitle) return null
|
|
5498
|
+
const assetSlug = slugify(assetTitle).slice(0, 47)
|
|
5499
|
+
return `${assetSlug}-${lang}`
|
|
5500
|
+
})
|
|
5501
|
+
.filter((slug): slug is string => slug !== null)
|
|
5463
5502
|
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5503
|
+
const assetChecks = await Promise.all(
|
|
5504
|
+
slugsToCheck.map(slug => doesAssetExists(bcToken, slug))
|
|
5505
|
+
)
|
|
5467
5506
|
|
|
5507
|
+
for (const { exists, academyId: existingAcademyId } of assetChecks) {
|
|
5468
5508
|
if (exists) {
|
|
5469
5509
|
isPublished = true
|
|
5470
5510
|
if (existingAcademyId !== undefined) {
|
|
5471
|
-
|
|
5472
|
-
break
|
|
5511
|
+
foundAcademyIds.push(existingAcademyId)
|
|
5473
5512
|
}
|
|
5474
5513
|
}
|
|
5475
5514
|
}
|
|
5476
5515
|
|
|
5477
|
-
|
|
5516
|
+
const uniqueAcademies = [...new Set(foundAcademyIds)]
|
|
5517
|
+
|
|
5518
|
+
type AcademyMode = "select" | "locked" | "conflict";
|
|
5519
|
+
let mode: AcademyMode
|
|
5520
|
+
let lockedAcademyId: number | undefined
|
|
5521
|
+
let conflictAcademies: number[] | undefined
|
|
5522
|
+
|
|
5523
|
+
if (uniqueAcademies.length === 0) {
|
|
5524
|
+
mode = "select"
|
|
5525
|
+
} else if (uniqueAcademies.length === 1) {
|
|
5526
|
+
mode = "locked"
|
|
5527
|
+
lockedAcademyId = uniqueAcademies[0]
|
|
5528
|
+
} else {
|
|
5529
|
+
mode = "conflict"
|
|
5530
|
+
conflictAcademies = uniqueAcademies
|
|
5531
|
+
}
|
|
5532
|
+
|
|
5533
|
+
return res.json({
|
|
5534
|
+
isPublished,
|
|
5535
|
+
mode,
|
|
5536
|
+
lockedAcademyId,
|
|
5537
|
+
conflictAcademies,
|
|
5538
|
+
})
|
|
5478
5539
|
} catch (error) {
|
|
5479
5540
|
console.error("Error fetching package academy:", error)
|
|
5480
5541
|
return res.status(500).json({ error: (error as Error).message })
|
|
@@ -5592,38 +5653,76 @@ class ServeCommand extends SessionCommand {
|
|
|
5592
5653
|
const archive = archiver("zip", { zlib: { level: 9 } })
|
|
5593
5654
|
|
|
5594
5655
|
output.on("close", async () => {
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5656
|
+
let rigoPublishUrl: string | undefined
|
|
5657
|
+
try {
|
|
5658
|
+
// 10) Subir ZIP a RigoBot
|
|
5659
|
+
const form = new FormData()
|
|
5660
|
+
form.append("file", fs.createReadStream(zipPath))
|
|
5661
|
+
form.append("config", JSON.stringify(config))
|
|
5662
|
+
|
|
5663
|
+
const rigoRes = await axios.post(
|
|
5664
|
+
`${RIGOBOT_HOST}/v1/learnpack/upload`,
|
|
5665
|
+
form,
|
|
5666
|
+
{
|
|
5667
|
+
headers: {
|
|
5668
|
+
...form.getHeaders(),
|
|
5669
|
+
Authorization: "Token " + rigoToken.trim(),
|
|
5670
|
+
},
|
|
5671
|
+
}
|
|
5672
|
+
)
|
|
5673
|
+
rigoPublishUrl = rigoRes.data.url
|
|
5610
5674
|
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5675
|
+
let errors: AssetSyncError[]
|
|
5676
|
+
try {
|
|
5677
|
+
const assetResults = await createMultiLangAsset(
|
|
5678
|
+
bucket,
|
|
5679
|
+
rigoToken,
|
|
5680
|
+
bcToken,
|
|
5681
|
+
slug,
|
|
5682
|
+
fullConfig.config,
|
|
5683
|
+
rigoRes.data.url,
|
|
5684
|
+
academyId
|
|
5685
|
+
)
|
|
5686
|
+
errors = assetResults.errors
|
|
5687
|
+
} catch (error) {
|
|
5688
|
+
console.error("Asset sync failed unexpectedly:", error)
|
|
5689
|
+
errors = [
|
|
5690
|
+
{
|
|
5691
|
+
kind: "package_error",
|
|
5692
|
+
error: { detail: "Asset sync failed unexpectedly." },
|
|
5693
|
+
},
|
|
5694
|
+
]
|
|
5695
|
+
}
|
|
5620
5696
|
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5697
|
+
if (res.headersSent) return
|
|
5698
|
+
console.log("RigoRes", rigoRes.data)
|
|
5699
|
+
res.json({
|
|
5700
|
+
url: rigoPublishUrl,
|
|
5701
|
+
errors,
|
|
5702
|
+
})
|
|
5703
|
+
} catch (error) {
|
|
5704
|
+
console.error(error)
|
|
5705
|
+
if (res.headersSent) return
|
|
5706
|
+
if (rigoPublishUrl !== undefined) {
|
|
5707
|
+
res.json({
|
|
5708
|
+
url: rigoPublishUrl,
|
|
5709
|
+
errors: [
|
|
5710
|
+
{
|
|
5711
|
+
kind: "package_error",
|
|
5712
|
+
error: { detail: "Asset sync failed unexpectedly." },
|
|
5713
|
+
},
|
|
5714
|
+
],
|
|
5715
|
+
})
|
|
5716
|
+
} else {
|
|
5717
|
+
res.status(500).json({ error: (error as Error).message })
|
|
5718
|
+
}
|
|
5719
|
+
} finally {
|
|
5720
|
+
try {
|
|
5721
|
+
rimraf.sync(tmpRoot)
|
|
5722
|
+
} catch (error) {
|
|
5723
|
+
console.error("rimraf tmpRoot:", error)
|
|
5724
|
+
}
|
|
5725
|
+
}
|
|
5627
5726
|
})
|
|
5628
5727
|
|
|
5629
5728
|
archive.on("error", err => {
|