@learnpack/learnpack 5.0.298 → 5.0.301

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.
Files changed (84) hide show
  1. package/README.md +409 -409
  2. package/lib/commands/audit.js +15 -15
  3. package/lib/commands/breakToken.js +19 -19
  4. package/lib/commands/clean.js +3 -3
  5. package/lib/commands/logout.js +3 -3
  6. package/lib/commands/serve.js +32 -13
  7. package/lib/creatorDist/assets/{index-D25zkBaN.js → index-DoYRptnk.js} +11875 -11992
  8. package/lib/creatorDist/index.html +1 -1
  9. package/lib/managers/config/index.js +77 -77
  10. package/lib/utils/creatorUtilities.js +14 -14
  11. package/lib/utils/templates/isolated/exercises/01-hello-world/README.es.md +26 -26
  12. package/lib/utils/templates/isolated/exercises/01-hello-world/README.md +26 -26
  13. package/lib/utils/templates/scorm/adlcp_rootv1p2.xsd +110 -110
  14. package/lib/utils/templates/scorm/config/index.html +209 -209
  15. package/lib/utils/templates/scorm/ims_xml.xsd +1 -1
  16. package/lib/utils/templates/scorm/imscp_rootv1p1p2.xsd +345 -345
  17. package/lib/utils/templates/scorm/imsmanifest.xml +38 -38
  18. package/lib/utils/templates/scorm/imsmd_rootv1p2p1.xsd +573 -573
  19. package/package.json +1 -1
  20. package/src/commands/audit.ts +487 -487
  21. package/src/commands/breakToken.ts +67 -67
  22. package/src/commands/clean.ts +30 -30
  23. package/src/commands/logout.ts +38 -38
  24. package/src/commands/serve.ts +49 -27
  25. package/src/commands/start.ts +333 -333
  26. package/src/commands/translate.ts +123 -123
  27. package/src/creator/README.md +54 -54
  28. package/src/creator/package-lock.json +6621 -6621
  29. package/src/creator/package.json +55 -55
  30. package/src/creator/src/App.tsx +569 -569
  31. package/src/creator/src/components/FileUploader.tsx +302 -302
  32. package/src/creator/src/components/Icon.tsx +18 -18
  33. package/src/creator/src/components/LessonItem.tsx +152 -152
  34. package/src/creator/src/components/Login.tsx +259 -259
  35. package/src/creator/src/components/syllabus/ContentIndex.tsx +323 -323
  36. package/src/creator/src/components/syllabus/SyllabusEditor.tsx +337 -337
  37. package/src/creator/src/i18n.ts +28 -28
  38. package/src/creator/src/locales/en.json +127 -127
  39. package/src/creator/src/locales/es.json +127 -127
  40. package/src/creator/src/utils/configTypes.ts +122 -122
  41. package/src/creator/src/utils/constants.ts +13 -13
  42. package/src/creator/src/utils/creatorUtils.ts +46 -46
  43. package/src/creator/src/utils/eventBus.ts +2 -2
  44. package/src/creator/src/utils/socket.ts +61 -61
  45. package/src/creator/src/utils/store.ts +222 -222
  46. package/src/creator/src/vite-env.d.ts +1 -1
  47. package/src/creator/vite.config.ts +13 -13
  48. package/src/creatorDist/assets/{index-D25zkBaN.js → index-DoYRptnk.js} +11875 -11992
  49. package/src/creatorDist/index.html +1 -1
  50. package/src/managers/config/defaults.ts +49 -49
  51. package/src/managers/config/exercise.ts +364 -364
  52. package/src/managers/config/index.ts +775 -775
  53. package/src/managers/file.ts +236 -236
  54. package/src/managers/server/routes.ts +554 -554
  55. package/src/managers/telemetry.ts +188 -188
  56. package/src/models/action.ts +13 -13
  57. package/src/models/config-manager.ts +28 -28
  58. package/src/models/config.ts +106 -106
  59. package/src/models/exercise-obj.ts +30 -30
  60. package/src/models/session.ts +39 -39
  61. package/src/models/socket.ts +61 -61
  62. package/src/models/status.ts +16 -16
  63. package/src/ui/_app/app.css +1 -1
  64. package/src/ui/_app/app.js +768 -768
  65. package/src/ui/_app/learnpack.svg +7 -7
  66. package/src/ui/_app/sw.js +59 -59
  67. package/src/ui/app.tar.gz +0 -0
  68. package/src/utils/BaseCommand.ts +56 -56
  69. package/src/utils/audit.ts +392 -392
  70. package/src/utils/checkNotInstalled.ts +267 -267
  71. package/src/utils/convertCreds.js +34 -34
  72. package/src/utils/creatorUtilities.ts +504 -504
  73. package/src/utils/export/README.md +178 -178
  74. package/src/utils/incrementVersion.js +74 -74
  75. package/src/utils/misc.ts +58 -58
  76. package/src/utils/sidebarGenerator.ts +195 -195
  77. package/src/utils/templates/isolated/exercises/01-hello-world/README.es.md +26 -26
  78. package/src/utils/templates/isolated/exercises/01-hello-world/README.md +26 -26
  79. package/src/utils/templates/scorm/adlcp_rootv1p2.xsd +110 -110
  80. package/src/utils/templates/scorm/config/index.html +209 -209
  81. package/src/utils/templates/scorm/ims_xml.xsd +1 -1
  82. package/src/utils/templates/scorm/imscp_rootv1p1p2.xsd +345 -345
  83. package/src/utils/templates/scorm/imsmanifest.xml +38 -38
  84. package/src/utils/templates/scorm/imsmd_rootv1p2p1.xsd +573 -573
@@ -1,67 +1,67 @@
1
- import { flags } from "@oclif/command"
2
- import BaseCommand from "../utils/BaseCommand"
3
-
4
- import Console from "../utils/console"
5
-
6
- import {
7
- extractParagraphs,
8
- splitIntoSyllables,
9
- extractWords,
10
- countSentences,
11
- fleschKincaidGrade,
12
- } from "../utils/creatorUtilities"
13
-
14
- const exampleMd = `# How to Install Node.js
15
-
16
- Node.js lets you run JavaScript outside a web browser.
17
-
18
- ## Step 1: Download Node.js
19
-
20
- Get the Node.js installer from the [official site](https://nodejs.org/en/download/).
21
-
22
- ## Step 2: Install Node.js
23
-
24
- Open the installer and follow the steps to finish.
25
-
26
- ## Step 3: Verify the Installation
27
-
28
- Open a terminal and type:
29
-
30
- \`\`\`bash
31
- node -v
32
- \`\`\`
33
- `
34
-
35
- class BreakTokenCommand extends BaseCommand {
36
- static description = "Break the token"
37
-
38
- static flags = {
39
- ...BaseCommand.flags,
40
- grading: flags.help({ char: "h" }),
41
- }
42
-
43
- async run() {
44
- const { flags } = this.parse(BreakTokenCommand)
45
-
46
- // await SessionManager.breakToken()
47
- const paragraphs = extractParagraphs(exampleMd)
48
- for (const paragraph of paragraphs) {
49
- const syllables = splitIntoSyllables(paragraph)
50
- const words = extractWords(paragraph)
51
- const sentences = countSentences(paragraph)
52
- const fkgl = fleschKincaidGrade(paragraph)
53
- Console.info(paragraph)
54
- Console.info(`Number of syllables: ${syllables.length}`)
55
- Console.info(syllables)
56
- Console.info(`Number of words: ${words.length}`)
57
- Console.info(words)
58
- Console.info(`Number of sentences: ${sentences}`)
59
- Console.info(`FKGL: ${fkgl}`)
60
- Console.info("---")
61
- }
62
-
63
- process.exit(0)
64
- }
65
- }
66
-
67
- export default BreakTokenCommand
1
+ import { flags } from "@oclif/command"
2
+ import BaseCommand from "../utils/BaseCommand"
3
+
4
+ import Console from "../utils/console"
5
+
6
+ import {
7
+ extractParagraphs,
8
+ splitIntoSyllables,
9
+ extractWords,
10
+ countSentences,
11
+ fleschKincaidGrade,
12
+ } from "../utils/creatorUtilities"
13
+
14
+ const exampleMd = `# How to Install Node.js
15
+
16
+ Node.js lets you run JavaScript outside a web browser.
17
+
18
+ ## Step 1: Download Node.js
19
+
20
+ Get the Node.js installer from the [official site](https://nodejs.org/en/download/).
21
+
22
+ ## Step 2: Install Node.js
23
+
24
+ Open the installer and follow the steps to finish.
25
+
26
+ ## Step 3: Verify the Installation
27
+
28
+ Open a terminal and type:
29
+
30
+ \`\`\`bash
31
+ node -v
32
+ \`\`\`
33
+ `
34
+
35
+ class BreakTokenCommand extends BaseCommand {
36
+ static description = "Break the token"
37
+
38
+ static flags = {
39
+ ...BaseCommand.flags,
40
+ grading: flags.help({ char: "h" }),
41
+ }
42
+
43
+ async run() {
44
+ const { flags } = this.parse(BreakTokenCommand)
45
+
46
+ // await SessionManager.breakToken()
47
+ const paragraphs = extractParagraphs(exampleMd)
48
+ for (const paragraph of paragraphs) {
49
+ const syllables = splitIntoSyllables(paragraph)
50
+ const words = extractWords(paragraph)
51
+ const sentences = countSentences(paragraph)
52
+ const fkgl = fleschKincaidGrade(paragraph)
53
+ Console.info(paragraph)
54
+ Console.info(`Number of syllables: ${syllables.length}`)
55
+ Console.info(syllables)
56
+ Console.info(`Number of words: ${words.length}`)
57
+ Console.info(words)
58
+ Console.info(`Number of sentences: ${sentences}`)
59
+ Console.info(`FKGL: ${fkgl}`)
60
+ Console.info("---")
61
+ }
62
+
63
+ process.exit(0)
64
+ }
65
+ }
66
+
67
+ export default BreakTokenCommand
@@ -1,30 +1,30 @@
1
- // import {flags} from '@oclif/command'
2
- import Console from "../utils/console"
3
- import SessionCommand from "../utils/SessionCommand"
4
-
5
- class CleanCommand extends SessionCommand {
6
- static description = `Clean the configuration object
7
- ...
8
- Extra documentation goes here
9
- `
10
-
11
- static flags: any = {
12
- // name: flags.string({char: 'n', description: 'name to print'}),
13
- }
14
-
15
- async init() {
16
- const { flags } = this.parse(CleanCommand)
17
- await this.initSession(flags)
18
- }
19
-
20
- async run() {
21
- const { flags } = this.parse(CleanCommand)
22
-
23
- this.configManager?.buildIndex()
24
- await this.configManager?.clean()
25
-
26
- Console.success("Package cleaned successfully, ready to publish")
27
- }
28
- }
29
-
30
- export default CleanCommand
1
+ // import {flags} from '@oclif/command'
2
+ import Console from "../utils/console"
3
+ import SessionCommand from "../utils/SessionCommand"
4
+
5
+ class CleanCommand extends SessionCommand {
6
+ static description = `Clean the configuration object
7
+ ...
8
+ Extra documentation goes here
9
+ `
10
+
11
+ static flags: any = {
12
+ // name: flags.string({char: 'n', description: 'name to print'}),
13
+ }
14
+
15
+ async init() {
16
+ const { flags } = this.parse(CleanCommand)
17
+ await this.initSession(flags)
18
+ }
19
+
20
+ async run() {
21
+ const { flags } = this.parse(CleanCommand)
22
+
23
+ this.configManager?.buildIndex()
24
+ await this.configManager?.clean()
25
+
26
+ Console.success("Package cleaned successfully, ready to publish")
27
+ }
28
+ }
29
+
30
+ export default CleanCommand
@@ -1,38 +1,38 @@
1
- import SessionCommand from "../utils/SessionCommand"
2
- import SessionManager from "../managers/session"
3
- import Console from "../utils/console"
4
-
5
- class LogoutCommand extends SessionCommand {
6
- static description = `Describe the command here
7
- ...
8
- Extra documentation goes here
9
- `
10
-
11
- static flags: any = {
12
- // name: flags.string({char: 'n', description: 'name to print'}),
13
- }
14
-
15
- static args = [
16
- {
17
- name: "package", // name of arg to show in help and reference with args[name]
18
- required: false, // make the arg required with `required: true`
19
- description:
20
- "The unique string that identifies this package on learnpack", // help description
21
- hidden: false, // hide this arg from help
22
- },
23
- ]
24
-
25
- async init() {
26
- const { flags } = this.parse(LogoutCommand)
27
- // await this.initSession(flags)
28
- Console.debug("Logout command")
29
- }
30
-
31
- async run() {
32
- // const {flags, args} = this.parse(LogoutCommand)
33
-
34
- SessionManager.destroy()
35
- }
36
- }
37
-
38
- export default LogoutCommand
1
+ import SessionCommand from "../utils/SessionCommand"
2
+ import SessionManager from "../managers/session"
3
+ import Console from "../utils/console"
4
+
5
+ class LogoutCommand extends SessionCommand {
6
+ static description = `Describe the command here
7
+ ...
8
+ Extra documentation goes here
9
+ `
10
+
11
+ static flags: any = {
12
+ // name: flags.string({char: 'n', description: 'name to print'}),
13
+ }
14
+
15
+ static args = [
16
+ {
17
+ name: "package", // name of arg to show in help and reference with args[name]
18
+ required: false, // make the arg required with `required: true`
19
+ description:
20
+ "The unique string that identifies this package on learnpack", // help description
21
+ hidden: false, // hide this arg from help
22
+ },
23
+ ]
24
+
25
+ async init() {
26
+ const { flags } = this.parse(LogoutCommand)
27
+ // await this.initSession(flags)
28
+ Console.debug("Logout command")
29
+ }
30
+
31
+ async run() {
32
+ // const {flags, args} = this.parse(LogoutCommand)
33
+
34
+ SessionManager.destroy()
35
+ }
36
+ }
37
+
38
+ export default LogoutCommand
@@ -52,10 +52,7 @@ import {
52
52
  import axios from "axios"
53
53
  import * as FormData from "form-data"
54
54
  import api, { RIGOBOT_HOST, RIGOBOT_REALTIME_HOST } from "../utils/api"
55
- import {
56
- createUploadMiddleware,
57
- minutesToISO8601Duration,
58
- } from "../utils/misc"
55
+ import { createUploadMiddleware, minutesToISO8601Duration } from "../utils/misc"
59
56
  import { buildConfig, ConfigResponse } from "../utils/configBuilder"
60
57
  import { checkReadability, slugify } from "../utils/creatorUtilities"
61
58
  import { checkAndFixSidebarPure } from "../utils/sidebarGenerator"
@@ -333,12 +330,13 @@ async function startExerciseGeneration(
333
330
  const lessonCleaner = (lesson: Lesson) => {
334
331
  return {
335
332
  ...lesson,
336
- description: lesson.description,
337
333
  duration: undefined,
338
334
  generated: undefined,
339
335
  status: undefined,
340
336
  translations: undefined,
341
337
  uid: undefined,
338
+ initialContent: undefined,
339
+ locked: undefined,
342
340
  }
343
341
  }
344
342
 
@@ -366,7 +364,6 @@ async function startInitialContentGeneration(
366
364
  const fullSyllabus = {
367
365
  steps: [steps.map(lessonCleaner)],
368
366
  courseInfo: cleanFormStateForSyllabus(packageContext),
369
- purpose: purposeSlug,
370
367
  }
371
368
 
372
369
  // Add random 6-digit number to avoid cache issues
@@ -1030,9 +1027,13 @@ export default class ServeCommand extends SessionCommand {
1030
1027
  if (files && Array.isArray(files)) {
1031
1028
  console.log("✅ Processing files for coding challenge...")
1032
1029
 
1033
- // Get the current exercise info to determine the exercise directory
1034
- const syllabus = await getSyllabus(courseSlug, bucket)
1035
- const exercise = syllabus.lessons[parseInt(exercisePosition)]
1030
+ const configFile = await bucket.file(
1031
+ `courses/${courseSlug}/.learn/config.json`
1032
+ )
1033
+ const [configContent] = await configFile.download()
1034
+ const { exercises } = JSON.parse(configContent.toString())
1035
+
1036
+ const exercise = exercises[parseInt(exercisePosition)]
1036
1037
 
1037
1038
  if (!exercise) {
1038
1039
  console.error(
@@ -1041,8 +1042,7 @@ export default class ServeCommand extends SessionCommand {
1041
1042
  return res.status(404).json({ error: "Exercise not found" })
1042
1043
  }
1043
1044
 
1044
- const exSlug = slugify(exercise.id + "-" + exercise.title)
1045
- const exerciseDir = `courses/${courseSlug}/exercises/${exSlug}`
1045
+ const exerciseDir = `courses/${courseSlug}/exercises/${exercise.slug}`
1046
1046
 
1047
1047
  for (const fileStr of files) {
1048
1048
  try {
@@ -1071,9 +1071,7 @@ export default class ServeCommand extends SessionCommand {
1071
1071
  fileObj.solution,
1072
1072
  solutionFilePath
1073
1073
  )
1074
- console.log(
1075
- `✅ Saved solution file: ${solutionFilePath}`
1076
- )
1074
+ console.log(`✅ Saved solution file: ${solutionFilePath}`)
1077
1075
  } else {
1078
1076
  // If no extension, just add .solution.hide
1079
1077
  const solutionFileName = `${fileObj.name}.solution.hide`
@@ -1084,9 +1082,7 @@ export default class ServeCommand extends SessionCommand {
1084
1082
  fileObj.solution,
1085
1083
  solutionFilePath
1086
1084
  )
1087
- console.log(
1088
- `✅ Saved solution file: ${solutionFilePath}`
1089
- )
1085
+ console.log(`✅ Saved solution file: ${solutionFilePath}`)
1090
1086
  }
1091
1087
  }
1092
1088
  } catch (parseError) {
@@ -2754,6 +2750,39 @@ export default class ServeCommand extends SessionCommand {
2754
2750
  }
2755
2751
  )
2756
2752
 
2753
+ app.delete(
2754
+ "/courses/:courseSlug/exercises/:exerciseSlug/file/:filename",
2755
+ async (req, res) => {
2756
+ console.log(
2757
+ "DELETE /courses/:courseSlug/exercises/:exerciseSlug/file/:filename",
2758
+ req.params
2759
+ )
2760
+ const { courseSlug, exerciseSlug, filename } = req.params
2761
+
2762
+ try {
2763
+ const filePath = `courses/${courseSlug}/exercises/${exerciseSlug}/${filename}`
2764
+ const file = bucket.file(filePath)
2765
+ const [exists] = await file.exists()
2766
+
2767
+ if (!exists) {
2768
+ return res.status(404).json({ error: "File not found" })
2769
+ }
2770
+
2771
+ await file.delete()
2772
+ console.log(`✅ Deleted file: ${filePath}`)
2773
+ return res.json({
2774
+ success: true,
2775
+ message: "File deleted successfully",
2776
+ })
2777
+ } catch (error) {
2778
+ console.error("❌ Error deleting file:", error)
2779
+ return res.status(500).json({
2780
+ error: (error as Error).message || "Unable to delete file",
2781
+ })
2782
+ }
2783
+ }
2784
+ )
2785
+
2757
2786
  const YT_REGEX = /(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]{11})/
2758
2787
 
2759
2788
  app.get("/actions/fetch/:link", async (req, res) => {
@@ -2796,9 +2825,7 @@ export default class ServeCommand extends SessionCommand {
2796
2825
  })
2797
2826
  } catch (error: any) {
2798
2827
  console.error("❌ /actions/fetch error:", error.message || error)
2799
- res
2800
- .status(500)
2801
- .json({ error: error.message || "Failed to fetch link" })
2828
+ res.status(500).json({ error: error.message || "Failed to fetch link" })
2802
2829
  }
2803
2830
  })
2804
2831
  app.delete("/packages/:slug", async (req, res) => {
@@ -2978,10 +3005,7 @@ export default class ServeCommand extends SessionCommand {
2978
3005
  !metadata.rights ||
2979
3006
  !metadata.lang
2980
3007
  ) {
2981
- console.log(
2982
- "Missing required metadata for EPUB export",
2983
- metadata
2984
- )
3008
+ console.log("Missing required metadata for EPUB export", metadata)
2985
3009
  return res.status(400).json({
2986
3010
  error: "Missing required metadata for EPUB export",
2987
3011
  required: ["creator", "publisher", "title", "rights", "lang"],
@@ -3026,9 +3050,7 @@ export default class ServeCommand extends SessionCommand {
3026
3050
  })
3027
3051
  } catch (error: any) {
3028
3052
  console.error("Export error:", error)
3029
- res
3030
- .status(500)
3031
- .json({ error: "Export failed", details: error.message })
3053
+ res.status(500).json({ error: "Export failed", details: error.message })
3032
3054
  }
3033
3055
  })
3034
3056