@learnpack/learnpack 5.0.250 → 5.0.254
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/audit.js +1 -1
- package/lib/commands/publish.js +4 -3
- package/lib/commands/serve.d.ts +0 -3
- package/lib/commands/serve.js +50 -47
- package/lib/creatorDist/assets/{index-CZYzWk3G.js → index-CFM_Ypyi.js} +25 -22
- package/lib/creatorDist/index.html +1 -1
- package/lib/managers/config/exercise.js +1 -1
- package/lib/utils/api.js +4 -3
- package/lib/utils/configBuilder.js +1 -1
- package/lib/utils/creatorUtilities.d.ts +1 -0
- package/lib/utils/creatorUtilities.js +5 -1
- package/package.json +1 -1
- package/src/commands/audit.ts +9 -18
- package/src/commands/publish.ts +4 -3
- package/src/commands/serve.ts +75 -68
- package/src/creator/src/App.tsx +1 -1
- package/src/creator/src/utils/rigo.ts +2 -0
- package/src/creatorDist/assets/{index-CZYzWk3G.js → index-CFM_Ypyi.js} +25 -22
- package/src/creatorDist/index.html +1 -1
- package/src/managers/config/exercise.ts +8 -16
- package/src/ui/_app/app.js +379 -379
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/api.ts +4 -3
- package/src/utils/configBuilder.ts +1 -1
- package/src/utils/creatorUtilities.ts +4 -0
- package/src/utils/templates/incremental/.vscode/schema.json +5 -5
- package/src/utils/templates/isolated/.vscode/schema.json +5 -5
package/src/commands/serve.ts
CHANGED
@@ -36,6 +36,7 @@ import * as dotenv from "dotenv"
|
|
36
36
|
import {
|
37
37
|
extractImagesFromMarkdown,
|
38
38
|
getFilenameFromUrl,
|
39
|
+
getReadmeExtension,
|
39
40
|
} from "../utils/creatorUtilities"
|
40
41
|
// import { handleAssetCreation } from "./publish"
|
41
42
|
import axios from "axios"
|
@@ -66,25 +67,18 @@ export const createLearnJson = (courseInfo: FormState) => {
|
|
66
67
|
// console.log("courseInfo to create learn json", courseInfo)
|
67
68
|
|
68
69
|
const expectedPreviewUrl = `https://${courseInfo.slug}.learn-pack.com/preview.png`
|
69
|
-
console.log("Preview url in generated learn.json", expectedPreviewUrl)
|
70
70
|
|
71
71
|
const language = courseInfo.language || "en"
|
72
72
|
|
73
73
|
const learnJson = {
|
74
74
|
slug: courseInfo.slug,
|
75
|
-
title:
|
76
|
-
language
|
77
|
-
|
78
|
-
us: courseInfo.title,
|
79
|
-
} :
|
80
|
-
{
|
81
|
-
[language]: courseInfo.title,
|
82
|
-
},
|
75
|
+
title: {
|
76
|
+
[language]: courseInfo.title,
|
77
|
+
},
|
83
78
|
technologies: courseInfo.technologies || [],
|
84
79
|
difficulty: "beginner",
|
85
80
|
description: {
|
86
|
-
[language
|
87
|
-
courseInfo.description,
|
81
|
+
[language]: courseInfo.description,
|
88
82
|
},
|
89
83
|
grading: "isolated",
|
90
84
|
telemetry: {
|
@@ -140,12 +134,10 @@ const createInitialSidebar = async (
|
|
140
134
|
slugs: string[],
|
141
135
|
initialLanguage = "en"
|
142
136
|
) => {
|
143
|
-
const language = initialLanguage === "en" ? "us" : initialLanguage
|
144
|
-
|
145
137
|
const sidebar: Record<string, Record<string, string>> = {}
|
146
138
|
for (const slug of slugs) {
|
147
139
|
sidebar[slug] = {
|
148
|
-
[
|
140
|
+
[initialLanguage]: slug,
|
149
141
|
}
|
150
142
|
}
|
151
143
|
|
@@ -208,9 +200,7 @@ const createMultiLangAsset = async (
|
|
208
200
|
for (const lang of availableLangs) {
|
209
201
|
// eslint-disable-next-line no-await-in-loop
|
210
202
|
const indexReadme = await bucket.file(
|
211
|
-
`courses/${courseSlug}/README
|
212
|
-
lang === "us" || lang === "en" ? "md" : `${lang}.md`
|
213
|
-
}`
|
203
|
+
`courses/${courseSlug}/README${getReadmeExtension(lang)}`
|
214
204
|
)
|
215
205
|
// eslint-disable-next-line no-await-in-loop
|
216
206
|
const [indexReadmeContent] = await indexReadme.download()
|
@@ -227,6 +217,11 @@ const createMultiLangAsset = async (
|
|
227
217
|
all_translations
|
228
218
|
)
|
229
219
|
|
220
|
+
if (!asset) {
|
221
|
+
console.log("No se pudo crear el asset, saltando idioma", lang)
|
222
|
+
continue
|
223
|
+
}
|
224
|
+
|
230
225
|
all_translations.push(asset.slug)
|
231
226
|
}
|
232
227
|
}
|
@@ -526,15 +521,10 @@ export default class ServeCommand extends SessionCommand {
|
|
526
521
|
const body = req.body
|
527
522
|
|
528
523
|
// Save the file as courses/courseSlug/README.md
|
529
|
-
const filePath = `courses/${courseSlug}/README
|
530
|
-
body.parsed.language_code
|
531
|
-
|
532
|
-
"md" :
|
533
|
-
`${body.parsed.language_code}.md`
|
534
|
-
}`
|
535
|
-
console.log("Saving initial readme to", filePath)
|
524
|
+
const filePath = `courses/${courseSlug}/README${getReadmeExtension(
|
525
|
+
body.parsed.language_code
|
526
|
+
)}`
|
536
527
|
await uploadFileToBucket(bucket, body.parsed.content, filePath)
|
537
|
-
console.log("Initial readme saved to", filePath)
|
538
528
|
|
539
529
|
res.json({ status: "SUCCESS" })
|
540
530
|
}
|
@@ -725,6 +715,32 @@ export default class ServeCommand extends SessionCommand {
|
|
725
715
|
res.json({ exists, file: file.name })
|
726
716
|
})
|
727
717
|
|
718
|
+
app.post(
|
719
|
+
"/webhooks/:courseSlug/:exSlug/:lang/update-readme/:notificationId",
|
720
|
+
async (req, res) => {
|
721
|
+
console.log("RECEIVING README UPDATE WEBHOOK")
|
722
|
+
const { courseSlug, exSlug, lang, notificationId } = req.params
|
723
|
+
const body = req.body
|
724
|
+
|
725
|
+
console.log("BODY", body)
|
726
|
+
|
727
|
+
const readmePath = `courses/${courseSlug}/exercises/${exSlug}/README${getReadmeExtension(
|
728
|
+
lang
|
729
|
+
)}`
|
730
|
+
|
731
|
+
if (body.parsed.content) {
|
732
|
+
await uploadFileToBucket(bucket, body.parsed.content, readmePath)
|
733
|
+
}
|
734
|
+
|
735
|
+
emitToNotification(notificationId, {
|
736
|
+
status: "SUCCESS",
|
737
|
+
message: "Readme updated successfully",
|
738
|
+
})
|
739
|
+
|
740
|
+
res.json({ status: "SUCCESS" })
|
741
|
+
}
|
742
|
+
)
|
743
|
+
|
728
744
|
app.get("/create", (req, res) => {
|
729
745
|
console.log("GET /create")
|
730
746
|
res.redirect("/creator/")
|
@@ -778,7 +794,9 @@ export default class ServeCommand extends SessionCommand {
|
|
778
794
|
|
779
795
|
const { slug } = req.params
|
780
796
|
const courseSlug = req.query.slug
|
781
|
-
const lang = req.query.lang || "
|
797
|
+
const lang = req.query.lang || "en"
|
798
|
+
|
799
|
+
console.log("LANG", lang)
|
782
800
|
|
783
801
|
if (!courseSlug) {
|
784
802
|
return res.status(400).json({ error: "Missing courseSlug" })
|
@@ -796,30 +814,37 @@ export default class ServeCommand extends SessionCommand {
|
|
796
814
|
return res.status(404).json({ error: "No README files found" })
|
797
815
|
}
|
798
816
|
|
799
|
-
const requestedFilename =
|
800
|
-
lang
|
801
|
-
|
802
|
-
`${basePath}README.${lang}.md`
|
817
|
+
const requestedFilename = `${basePath}README${getReadmeExtension(
|
818
|
+
lang as string
|
819
|
+
)}`
|
803
820
|
|
804
821
|
let selectedFile = readmeFiles.find(f => f === requestedFilename)
|
805
822
|
|
806
823
|
if (!selectedFile) {
|
824
|
+
console.log("No se encontro en ese idioma, devolviendo el primero")
|
807
825
|
selectedFile = readmeFiles[0]
|
808
826
|
console.warn(
|
809
827
|
`Requested README not found for lang '${lang}', using '${selectedFile}'`
|
810
828
|
)
|
811
829
|
}
|
812
830
|
|
813
|
-
let foundLang = "
|
831
|
+
let foundLang = "en"
|
814
832
|
const match = selectedFile.match(/readme(?:\.([a-z]{2}))?\.md$/i)
|
815
833
|
if (match && match[1]) {
|
816
834
|
foundLang = match[1].toLowerCase()
|
817
835
|
}
|
818
836
|
|
819
837
|
const [contentBuffer] = await bucket.file(selectedFile).download()
|
820
|
-
|
821
|
-
|
822
|
-
|
838
|
+
try {
|
839
|
+
const { attributes, body } = frontMatter(contentBuffer.toString())
|
840
|
+
res.send({ attributes, body, lang: foundLang })
|
841
|
+
} catch {
|
842
|
+
res.status(200).json({
|
843
|
+
attributes: {},
|
844
|
+
body: contentBuffer.toString(),
|
845
|
+
lang: foundLang,
|
846
|
+
})
|
847
|
+
}
|
823
848
|
} catch (error) {
|
824
849
|
console.error(error)
|
825
850
|
res.status(500).json({ error: "Internal server error" })
|
@@ -885,9 +910,9 @@ export default class ServeCommand extends SessionCommand {
|
|
885
910
|
|
886
911
|
const courseSlug = query.slug
|
887
912
|
|
888
|
-
const fileName = `courses/${courseSlug}/exercises/${title}/README${
|
889
|
-
language
|
890
|
-
}
|
913
|
+
const fileName = `courses/${courseSlug}/exercises/${title}/README${getReadmeExtension(
|
914
|
+
language
|
915
|
+
)}`
|
891
916
|
const file = bucket.file(fileName)
|
892
917
|
await file.save(readme)
|
893
918
|
const created = await file.exists()
|
@@ -935,11 +960,9 @@ export default class ServeCommand extends SessionCommand {
|
|
935
960
|
try {
|
936
961
|
await Promise.all(
|
937
962
|
exerciseSlugs.map(async (slug: string) => {
|
938
|
-
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${
|
939
|
-
currentLanguage
|
940
|
-
|
941
|
-
`.${currentLanguage}`
|
942
|
-
}.md`
|
963
|
+
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${getReadmeExtension(
|
964
|
+
currentLanguage
|
965
|
+
)}`
|
943
966
|
|
944
967
|
const readme = await bucket.file(readmePath).download()
|
945
968
|
|
@@ -952,12 +975,9 @@ export default class ServeCommand extends SessionCommand {
|
|
952
975
|
})
|
953
976
|
|
954
977
|
const translatedReadme = await bucket.file(
|
955
|
-
`courses/${courseSlug}/exercises/${slug}/README${
|
956
|
-
response.parsed.output_language_code
|
957
|
-
|
958
|
-
"" :
|
959
|
-
`.${response.parsed.output_language_code}`
|
960
|
-
}.md`
|
978
|
+
`courses/${courseSlug}/exercises/${slug}/README${getReadmeExtension(
|
979
|
+
response.parsed.output_language_code
|
980
|
+
)}`
|
961
981
|
)
|
962
982
|
await translatedReadme.save(response.parsed.translation)
|
963
983
|
|
@@ -967,11 +987,6 @@ export default class ServeCommand extends SessionCommand {
|
|
967
987
|
})
|
968
988
|
)
|
969
989
|
|
970
|
-
if (languageCodes.has("en")) {
|
971
|
-
languageCodes.delete("en")
|
972
|
-
languageCodes.add("us")
|
973
|
-
}
|
974
|
-
|
975
990
|
const currentLanguages = Object.keys(courseJson.title)
|
976
991
|
for (const languageCode of currentLanguages) {
|
977
992
|
if (languageCodes.has(languageCode)) {
|
@@ -980,8 +995,6 @@ export default class ServeCommand extends SessionCommand {
|
|
980
995
|
}
|
981
996
|
|
982
997
|
if ([...languageCodes].length > 0) {
|
983
|
-
console.log("TRANSLATING COURSE METADATA", languageCodes)
|
984
|
-
|
985
998
|
const translatedCourseMetadata = await Promise.all(
|
986
999
|
[...languageCodes].map(async languageCode => {
|
987
1000
|
const result = await translateCourseMetadata(rigoToken, {
|
@@ -1011,11 +1024,7 @@ export default class ServeCommand extends SessionCommand {
|
|
1011
1024
|
)
|
1012
1025
|
|
1013
1026
|
const previewReadme = await bucket.file(
|
1014
|
-
`courses/${courseSlug}/README${
|
1015
|
-
currentLanguage === "us" || currentLanguage === "en" ?
|
1016
|
-
"" :
|
1017
|
-
`.${currentLanguage}`
|
1018
|
-
}.md`
|
1027
|
+
`courses/${courseSlug}/README${getReadmeExtension(currentLanguage)}`
|
1019
1028
|
)
|
1020
1029
|
const [previewReadmeContent] = await previewReadme.download()
|
1021
1030
|
const previewReadmeContentString = previewReadmeContent.toString()
|
@@ -1033,11 +1042,9 @@ export default class ServeCommand extends SessionCommand {
|
|
1033
1042
|
|
1034
1043
|
await bucket
|
1035
1044
|
.file(
|
1036
|
-
`courses/${courseSlug}/README${
|
1037
|
-
languageCode
|
1038
|
-
|
1039
|
-
`.${languageCode}`
|
1040
|
-
}.md`
|
1045
|
+
`courses/${courseSlug}/README${getReadmeExtension(
|
1046
|
+
languageCode as string
|
1047
|
+
)}`
|
1041
1048
|
)
|
1042
1049
|
.save(translatedPreviewReadme.parsed.translation)
|
1043
1050
|
})
|
@@ -1436,10 +1443,10 @@ export default class ServeCommand extends SessionCommand {
|
|
1436
1443
|
|
1437
1444
|
const availableLangs = Object.keys(config.title)
|
1438
1445
|
|
1439
|
-
let selectedLang = "
|
1446
|
+
let selectedLang = "en"
|
1440
1447
|
let title = ""
|
1441
|
-
if (availableLangs.includes("
|
1442
|
-
title = config.title.
|
1448
|
+
if (availableLangs.includes("en")) {
|
1449
|
+
title = config.title.en
|
1443
1450
|
} else {
|
1444
1451
|
// Select the first available lang
|
1445
1452
|
title = config.title[availableLangs[0]]
|
package/src/creator/src/App.tsx
CHANGED
@@ -174,7 +174,7 @@ function App() {
|
|
174
174
|
let techs = technologies.filter((t) => t.lang === formState.language)
|
175
175
|
|
176
176
|
if (techs.length === 0) {
|
177
|
-
techs = technologies.filter((t) => t.lang === "
|
177
|
+
techs = technologies.filter((t) => t.lang === "en")
|
178
178
|
}
|
179
179
|
|
180
180
|
const res = await publicInteractiveCreation(
|
@@ -24,6 +24,8 @@ export const publicInteractiveCreation = async (
|
|
24
24
|
"https://9cw5zmww-3000.use2.devtunnels.ms"
|
25
25
|
}/notifications/${randomUID}`
|
26
26
|
|
27
|
+
console.log("WEBHOOK URL to send to Rigo", webhookUrl)
|
28
|
+
|
27
29
|
const response = await axios.post(
|
28
30
|
`${RIGOBOT_HOST}/v1/prompting${
|
29
31
|
publicRequest ? "/public" : ""
|
@@ -18251,28 +18251,31 @@ const d2 = async (e) => {
|
|
18251
18251
|
try {
|
18252
18252
|
const l = Ku(15),
|
18253
18253
|
u = `https://9cw5zmww-3000.use2.devtunnels.ms/notifications/${l}`
|
18254
|
-
return
|
18255
|
-
|
18256
|
-
|
18257
|
-
|
18258
|
-
|
18259
|
-
|
18260
|
-
|
18261
|
-
|
18262
|
-
|
18263
|
-
|
18264
|
-
|
18265
|
-
|
18266
|
-
|
18267
|
-
headers: {
|
18268
|
-
"Content-Type": "application/json",
|
18269
|
-
Authorization: `Token ${t}`,
|
18254
|
+
return (
|
18255
|
+
console.log("WEBHOOK URL to send to Rigo", u),
|
18256
|
+
{
|
18257
|
+
res: (
|
18258
|
+
await Pe.post(
|
18259
|
+
`${Ds}/v1/prompting${r ? "/public" : ""}/completion/${
|
18260
|
+
L1 ? "39" : "390"
|
18261
|
+
}/`,
|
18262
|
+
{
|
18263
|
+
inputs: e,
|
18264
|
+
include_purpose_objective: !0,
|
18265
|
+
purpose_slug: n,
|
18266
|
+
webhook_url: u,
|
18270
18267
|
},
|
18271
|
-
|
18272
|
-
|
18273
|
-
|
18274
|
-
|
18275
|
-
|
18268
|
+
{
|
18269
|
+
headers: {
|
18270
|
+
"Content-Type": "application/json",
|
18271
|
+
Authorization: `Token ${t}`,
|
18272
|
+
},
|
18273
|
+
}
|
18274
|
+
)
|
18275
|
+
).data,
|
18276
|
+
notificationId: l,
|
18277
|
+
}
|
18278
|
+
)
|
18276
18279
|
} catch (l) {
|
18277
18280
|
const u = l
|
18278
18281
|
return (
|
@@ -21192,7 +21195,7 @@ function K7() {
|
|
21192
21195
|
y.rigoToken &&
|
21193
21196
|
l({ ...y, rigoToken: "", bcToken: "", userId: "", user: null })
|
21194
21197
|
let $ = T.filter((ee) => ee.lang === r.language)
|
21195
|
-
$.length === 0 && ($ = T.filter((ee) => ee.lang === "
|
21198
|
+
$.length === 0 && ($ = T.filter((ee) => ee.lang === "en"))
|
21196
21199
|
const Q = await p2(
|
21197
21200
|
{
|
21198
21201
|
courseInfo: `${JSON.stringify(
|
@@ -10,7 +10,7 @@
|
|
10
10
|
/>
|
11
11
|
|
12
12
|
<title>Learnpack Creator: Craft tutorials in seconds!</title>
|
13
|
-
<script type="module" crossorigin src="/creator/assets/index-
|
13
|
+
<script type="module" crossorigin src="/creator/assets/index-CFM_Ypyi.js"></script>
|
14
14
|
<link rel="stylesheet" crossorigin href="/creator/assets/index-DmpsXknz.css">
|
15
15
|
</head>
|
16
16
|
<body>
|
@@ -85,15 +85,12 @@ export const exercise = (
|
|
85
85
|
// fs.writeFileSync(path + "/" + file, updatedMarkdown, "utf8")
|
86
86
|
// }
|
87
87
|
|
88
|
-
if (parts.length === 3)
|
89
|
-
translations
|
90
|
-
else
|
91
|
-
translations.us = file
|
88
|
+
if (parts.length === 3) translations[parts[1]] = file
|
89
|
+
else translations.us = file
|
92
90
|
}
|
93
91
|
|
94
92
|
// if the slug is a dot, it means there is not "exercises" folder, and its just a single README.md
|
95
|
-
if (slug === ".")
|
96
|
-
slug = "default-index"
|
93
|
+
if (slug === ".") slug = "default-index"
|
97
94
|
|
98
95
|
const detected = detect(configObject, files)
|
99
96
|
|
@@ -120,16 +117,14 @@ slug = "default-index"
|
|
120
117
|
exercises[position].done :
|
121
118
|
false,
|
122
119
|
getReadme: function (lang = null) {
|
123
|
-
if (lang === "us")
|
124
|
-
lang = null // <-- english is default, no need to append it to the file name
|
120
|
+
if (lang === "en" || lang === "us") lang = null // <-- english is default, no need to append it to the file name
|
125
121
|
|
126
122
|
if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`)) {
|
127
123
|
Console.error(
|
128
124
|
`Language ${lang} not found for exercise ${slug}, switching to default language`
|
129
125
|
)
|
130
126
|
|
131
|
-
if (lang)
|
132
|
-
lang = null
|
127
|
+
if (lang) lang = null
|
133
128
|
|
134
129
|
if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`))
|
135
130
|
throw new Error(
|
@@ -169,8 +164,7 @@ lang = null
|
|
169
164
|
|
170
165
|
for (const _file of this.files) {
|
171
166
|
const stats = fs.statSync(_file.path)
|
172
|
-
if (stats.isDirectory() || _file.hidden)
|
173
|
-
continue
|
167
|
+
if (stats.isDirectory() || _file.hidden) continue
|
174
168
|
const fileContent = fs.readFileSync(_file.path)
|
175
169
|
if (
|
176
170
|
!fs.existsSync(`${config?.dirPath}/resets/${this.slug}/${_file.name}`)
|
@@ -217,8 +211,7 @@ continue
|
|
217
211
|
getTestReport: function () {
|
218
212
|
const _path = `${configObject?.confPath?.base}/reports/${this.slug}.json`
|
219
213
|
|
220
|
-
if (!fs.existsSync(_path))
|
221
|
-
return {}
|
214
|
+
if (!fs.existsSync(_path)) return {}
|
222
215
|
|
223
216
|
const content = fs.readFileSync(_path)
|
224
217
|
const data = JSON.parse(`${content}`)
|
@@ -230,8 +223,7 @@ return {}
|
|
230
223
|
}
|
231
224
|
|
232
225
|
export const validateExerciseDirectoryName = (str: string) => {
|
233
|
-
if (str === "./")
|
234
|
-
return true
|
226
|
+
if (str === "./") return true
|
235
227
|
// TODO: Add nameValidationREgex from the config
|
236
228
|
const regex = /^(\d{2,3}(\.\d{1,2})?-([\dA-Za-z]+(-|_)?)+)$/
|
237
229
|
return regex.test(str)
|