@learnpack/learnpack 5.0.148 → 5.0.152
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/lib/commands/serve.js +11 -6
- package/lib/creatorDist/assets/{index-DUPYM87B.css → index-CztA582_.css} +0 -12
- package/lib/creatorDist/assets/{index-ETBXfIew.js → index-l0lFNoeD.js} +32788 -36295
- package/lib/creatorDist/index.html +2 -2
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/serve.ts +15 -6
- package/src/creator/src/App.tsx +28 -12
- package/src/creator/src/components/TurnstileChallenge.tsx +2 -9
- package/src/creator/src/utils/creatorUtils.ts +1 -141
- package/src/creator/src/utils/rigo.ts +21 -377
- package/src/creatorDist/assets/{index-DUPYM87B.css → index-CztA582_.css} +0 -12
- package/src/creatorDist/assets/{index-ETBXfIew.js → index-l0lFNoeD.js} +32788 -36295
- package/src/creatorDist/index.html +2 -2
- package/src/ui/_app/app.js +241 -241
- package/src/ui/app.tar.gz +0 -0
@@ -10,8 +10,8 @@
|
|
10
10
|
/>
|
11
11
|
|
12
12
|
<title>Learnpack Creator: Craft tutorials in seconds!</title>
|
13
|
-
<script type="module" crossorigin src="/creator/assets/index-
|
14
|
-
<link rel="stylesheet" crossorigin href="/creator/assets/index-
|
13
|
+
<script type="module" crossorigin src="/creator/assets/index-l0lFNoeD.js"></script>
|
14
|
+
<link rel="stylesheet" crossorigin href="/creator/assets/index-CztA582_.css">
|
15
15
|
</head>
|
16
16
|
<body>
|
17
17
|
<div id="root"></div>
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"5.0.
|
1
|
+
{"version":"5.0.152","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"serve":{"id":"serve","description":"Runs a small server to build tutorials","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@learnpack/learnpack",
|
3
3
|
"description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
|
4
|
-
"version": "5.0.
|
4
|
+
"version": "5.0.152",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
package/src/commands/serve.ts
CHANGED
@@ -45,6 +45,11 @@ dotenv.config()
|
|
45
45
|
export const createLearnJson = (courseInfo: FormState) => {
|
46
46
|
console.log("courseInfo to create learn json", courseInfo)
|
47
47
|
|
48
|
+
const expectedPreviewUrl = `https://${slugify(
|
49
|
+
courseInfo.title as string
|
50
|
+
)}.learn-pack.com/preview.png`
|
51
|
+
console.log("Preview url in generated learn.json", expectedPreviewUrl)
|
52
|
+
|
48
53
|
const learnJson = {
|
49
54
|
slug: slugify(courseInfo.title as string),
|
50
55
|
title: {
|
@@ -59,7 +64,7 @@ export const createLearnJson = (courseInfo: FormState) => {
|
|
59
64
|
telemetry: {
|
60
65
|
batch: "https://breathecode.herokuapp.com/v1/assignment/me/telemetry",
|
61
66
|
},
|
62
|
-
preview:
|
67
|
+
preview: expectedPreviewUrl,
|
63
68
|
}
|
64
69
|
return learnJson
|
65
70
|
}
|
@@ -292,7 +297,7 @@ const fixPreviewUrl = (slug: string, previewUrl: string) => {
|
|
292
297
|
}
|
293
298
|
|
294
299
|
const expectedUrl = `https://${slug}.learn-pack.com/preview.png`
|
295
|
-
console.log("
|
300
|
+
console.log("Preview url fixed!", expectedUrl)
|
296
301
|
return expectedUrl
|
297
302
|
}
|
298
303
|
|
@@ -473,8 +478,13 @@ export default class ServeCommand extends SessionCommand {
|
|
473
478
|
|
474
479
|
app.get("/config", async (req, res) => {
|
475
480
|
const courseSlug = req.query.slug as string
|
481
|
+
// GEt the x-rigo-token
|
482
|
+
// const rigoToken = req.header("x-rigo-token")
|
483
|
+
|
476
484
|
if (!courseSlug) {
|
477
|
-
return res
|
485
|
+
return res
|
486
|
+
.status(400)
|
487
|
+
.json({ error: "Course slug and rigo token required" })
|
478
488
|
}
|
479
489
|
|
480
490
|
try {
|
@@ -878,15 +888,14 @@ export default class ServeCommand extends SessionCommand {
|
|
878
888
|
const { slug } = req.params
|
879
889
|
const rigoToken = req.header("x-rigo-token")
|
880
890
|
const bcToken = req.header("x-breathecode-token")
|
881
|
-
const { academyId, categoryId } = req.body
|
891
|
+
// const { academyId, categoryId } = req.body
|
882
892
|
|
883
|
-
if (!rigoToken || !bcToken
|
893
|
+
if (!rigoToken || !bcToken) {
|
884
894
|
return res
|
885
895
|
.status(400)
|
886
896
|
.json({ error: "Faltan tokens o academy/category" })
|
887
897
|
}
|
888
898
|
|
889
|
-
// 2) Leer y construir config.json vía buildConfig
|
890
899
|
const { config, exercises }: ConfigResponse = await buildConfig(
|
891
900
|
bucket,
|
892
901
|
slug
|
package/src/creator/src/App.tsx
CHANGED
@@ -6,13 +6,14 @@ import { useNavigate } from "react-router"
|
|
6
6
|
import { useShallow } from "zustand/react/shallow"
|
7
7
|
import useStore from "./utils/store"
|
8
8
|
|
9
|
-
import { interactiveCreation } from "./utils/rigo"
|
9
|
+
import { interactiveCreation, isHuman } from "./utils/rigo"
|
10
10
|
import { checkParams, loginWithToken, parseLesson } from "./utils/lib"
|
11
11
|
|
12
12
|
import { Uploader } from "./components/Uploader"
|
13
13
|
import toast from "react-hot-toast"
|
14
14
|
import { ParamsChecker } from "./components/ParamsChecker"
|
15
15
|
import { RIGO_FLOAT_GIT } from "./utils/constants"
|
16
|
+
import TurnstileChallenge from "./components/TurnstileChallenge"
|
16
17
|
// import TurnstileChallenge from "./components/TurnstileChallenge"
|
17
18
|
|
18
19
|
function App() {
|
@@ -227,18 +228,10 @@ function App() {
|
|
227
228
|
<SelectableCard
|
228
229
|
title="🛠️ No, help me create one"
|
229
230
|
onClick={() => {
|
230
|
-
if (!formState.contentIndex && !formState.description) {
|
231
|
-
toast.error(
|
232
|
-
"Please provide at least a description for your course!"
|
233
|
-
)
|
234
|
-
setFormState({
|
235
|
-
currentStep: "description",
|
236
|
-
})
|
237
|
-
return
|
238
|
-
}
|
239
231
|
setFormState({
|
240
232
|
hasContentIndex: false,
|
241
|
-
|
233
|
+
currentStep: "verifyHuman",
|
234
|
+
// isCompleted: true,
|
242
235
|
})
|
243
236
|
}}
|
244
237
|
selected={false}
|
@@ -258,12 +251,35 @@ function App() {
|
|
258
251
|
onFinish={(text) => {
|
259
252
|
setFormState({
|
260
253
|
contentIndex: text,
|
261
|
-
|
254
|
+
currentStep: "verifyHuman",
|
255
|
+
// isCompleted: true,
|
262
256
|
})
|
263
257
|
}}
|
264
258
|
/>
|
265
259
|
),
|
266
260
|
},
|
261
|
+
{
|
262
|
+
title: "Please verify you are a human",
|
263
|
+
slug: "verifyHuman",
|
264
|
+
isCompleted: false,
|
265
|
+
content: (
|
266
|
+
<TurnstileChallenge
|
267
|
+
siteKey={"0x4AAAAAABeKMBYYinMU4Ib0"}
|
268
|
+
onSuccess={async (token) => {
|
269
|
+
const _isHuman = await isHuman(token)
|
270
|
+
if (_isHuman) {
|
271
|
+
toast.success("You are a human! 👌🏻")
|
272
|
+
setFormState({ isCompleted: true })
|
273
|
+
} else {
|
274
|
+
toast.error("You are not a human! 🤖")
|
275
|
+
setFormState({
|
276
|
+
currentStep: "hasContentIndex",
|
277
|
+
})
|
278
|
+
}
|
279
|
+
}}
|
280
|
+
/>
|
281
|
+
),
|
282
|
+
},
|
267
283
|
]
|
268
284
|
|
269
285
|
return steps.filter(
|
@@ -61,18 +61,11 @@ const TurnstileChallenge = ({
|
|
61
61
|
return () => clearInterval(interval)
|
62
62
|
}, [siteKey, autoStart, onSuccess, onError])
|
63
63
|
|
64
|
-
// const reset = () => {
|
65
|
-
// if (widgetId.current && window.turnstile) {
|
66
|
-
// window.turnstile.reset(widgetId.current)
|
67
|
-
// }
|
68
|
-
// }
|
69
64
|
|
70
65
|
return (
|
71
|
-
|
66
|
+
|
72
67
|
<div className="">
|
73
|
-
|
74
|
-
We must verify you are human
|
75
|
-
</h3> */}
|
68
|
+
|
76
69
|
<div id={containerId} data-refresh-timeout="auto" />
|
77
70
|
{!ready && <p className="">...</p>}
|
78
71
|
{/* <button onClick={reset}>RESET</button> */}
|
@@ -1,18 +1,5 @@
|
|
1
|
-
import { Lesson } from "../components/LessonItem"
|
2
1
|
import { eventBus } from "./eventBus"
|
3
|
-
import {
|
4
|
-
generateImage,
|
5
|
-
getFilenameFromUrl,
|
6
|
-
uploadFileToBucket,
|
7
|
-
uploadImageToBucket,
|
8
|
-
} from "./lib"
|
9
|
-
import {
|
10
|
-
makeReadmeReadable,
|
11
|
-
readmeCreator,
|
12
|
-
checkReadability,
|
13
|
-
createCodeFile,
|
14
|
-
} from "./rigo"
|
15
|
-
import { FormState } from "./store"
|
2
|
+
import { generateImage, getFilenameFromUrl, uploadImageToBucket } from "./lib"
|
16
3
|
|
17
4
|
export const slugify = (text: string) => {
|
18
5
|
return text
|
@@ -21,133 +8,6 @@ export const slugify = (text: string) => {
|
|
21
8
|
.replace(/[^\w.-]+/g, "")
|
22
9
|
}
|
23
10
|
|
24
|
-
export const createLearnJson = (courseInfo: FormState) => {
|
25
|
-
console.log("courseInfo to create learn json", courseInfo)
|
26
|
-
|
27
|
-
const learnJson = {
|
28
|
-
slug: slugify(courseInfo.title as string),
|
29
|
-
title: {
|
30
|
-
us: courseInfo.title,
|
31
|
-
},
|
32
|
-
technologies: courseInfo.technologies || [],
|
33
|
-
difficulty: "beginner",
|
34
|
-
description: {
|
35
|
-
us: courseInfo.description,
|
36
|
-
},
|
37
|
-
grading: "isolated",
|
38
|
-
telemetry: {
|
39
|
-
batch: "https://breathecode.herokuapp.com/v1/assignment/me/telemetry",
|
40
|
-
},
|
41
|
-
preview: "preview.png",
|
42
|
-
}
|
43
|
-
return learnJson
|
44
|
-
}
|
45
|
-
|
46
|
-
const PARAMS = {
|
47
|
-
expected_grade_level: "6",
|
48
|
-
max_fkgl: 8,
|
49
|
-
max_words: 200,
|
50
|
-
max_rewrite_attempts: 3,
|
51
|
-
max_title_length: 50,
|
52
|
-
}
|
53
|
-
export async function processExercise(
|
54
|
-
rigoToken: string,
|
55
|
-
steps: Lesson[],
|
56
|
-
packageContext: string,
|
57
|
-
exercise: Lesson,
|
58
|
-
exercisesDir: string
|
59
|
-
): Promise<string> {
|
60
|
-
// const tid = toast.loading("Generating lesson...")
|
61
|
-
setTimeout(() => {
|
62
|
-
eventBus.emit("course-generation", {
|
63
|
-
message: `✍🏻 Generating lesson ${exercise.id} - ${exercise.title}...`,
|
64
|
-
})
|
65
|
-
}, 500)
|
66
|
-
const readme = await readmeCreator(rigoToken, {
|
67
|
-
title: `${exercise.id} - ${exercise.title}`,
|
68
|
-
output_lang: "en",
|
69
|
-
list_of_exercises: JSON.stringify(steps),
|
70
|
-
tutorial_description: packageContext,
|
71
|
-
lesson_description: exercise.description,
|
72
|
-
kind: exercise.type.toLowerCase(),
|
73
|
-
})
|
74
|
-
|
75
|
-
const duration = exercise.duration
|
76
|
-
let attempts = 0
|
77
|
-
let readability = checkReadability(readme.parsed.content, 200, duration || 1)
|
78
|
-
|
79
|
-
while (
|
80
|
-
readability.fkglResult.fkgl > PARAMS.max_fkgl &&
|
81
|
-
attempts < PARAMS.max_rewrite_attempts
|
82
|
-
) {
|
83
|
-
setTimeout(() => {
|
84
|
-
eventBus.emit("course-generation", {
|
85
|
-
message: `🔄 The lesson ${exercise.id} - ${
|
86
|
-
exercise.title
|
87
|
-
} has a readability score of ${
|
88
|
-
readability.fkglResult.fkgl
|
89
|
-
}. Rewriting it... (Attempt ${attempts + 1})`,
|
90
|
-
})
|
91
|
-
}, 500)
|
92
|
-
// eslint-disable-next-line
|
93
|
-
const reducedReadme = await makeReadmeReadable(rigoToken, {
|
94
|
-
lesson: readability.body,
|
95
|
-
number_of_words: readability.minutes.toString(),
|
96
|
-
expected_number_words: PARAMS.max_words.toString(),
|
97
|
-
fkgl_results: JSON.stringify(readability.fkglResult),
|
98
|
-
expected_grade_level: PARAMS.expected_grade_level,
|
99
|
-
})
|
100
|
-
|
101
|
-
if (!reducedReadme) break
|
102
|
-
|
103
|
-
readability = checkReadability(
|
104
|
-
reducedReadme.parsed.content,
|
105
|
-
PARAMS.max_words,
|
106
|
-
duration || 1
|
107
|
-
)
|
108
|
-
|
109
|
-
attempts++
|
110
|
-
}
|
111
|
-
|
112
|
-
setTimeout(() => {
|
113
|
-
eventBus.emit("course-generation", {
|
114
|
-
message: `✅ After ${attempts} attempts, the lesson ${
|
115
|
-
exercise.title
|
116
|
-
} has a readability score of ${
|
117
|
-
readability.fkglResult.fkgl
|
118
|
-
} using FKGL. And it has ${readability.minutes.toFixed(
|
119
|
-
2
|
120
|
-
)} minutes of reading time.`,
|
121
|
-
})
|
122
|
-
}, 500)
|
123
|
-
|
124
|
-
const readmeFilename = "README.md"
|
125
|
-
|
126
|
-
const targetDir = `${exercisesDir}/${slugify(
|
127
|
-
exercise.id + "-" + exercise.title
|
128
|
-
)}`
|
129
|
-
await uploadFileToBucket(
|
130
|
-
readability.newMarkdown,
|
131
|
-
`${targetDir}/${readmeFilename}`
|
132
|
-
)
|
133
|
-
|
134
|
-
if (exercise.type.toLowerCase() === "code") {
|
135
|
-
eventBus.emit("course-generation", {
|
136
|
-
message: `🔍 Creating code file for ${exercise.title}`,
|
137
|
-
})
|
138
|
-
const codeFile = await createCodeFile(rigoToken, {
|
139
|
-
readme: readability.newMarkdown,
|
140
|
-
tutorial_info: packageContext,
|
141
|
-
})
|
142
|
-
await uploadFileToBucket(
|
143
|
-
codeFile.parsed.content,
|
144
|
-
`${targetDir}/index.${codeFile.parsed.extension.replace(".", "")}`
|
145
|
-
)
|
146
|
-
}
|
147
|
-
|
148
|
-
return readability.newMarkdown
|
149
|
-
}
|
150
|
-
|
151
11
|
export const randomUUID = () => {
|
152
12
|
return Math.random().toString(36).substring(2, 15)
|
153
13
|
}
|