@learnpack/learnpack 5.0.297 → 5.0.300

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 (79) 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 -11
  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 -26
  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/utils/BaseCommand.ts +56 -56
  64. package/src/utils/audit.ts +392 -392
  65. package/src/utils/checkNotInstalled.ts +267 -267
  66. package/src/utils/convertCreds.js +34 -34
  67. package/src/utils/creatorUtilities.ts +504 -504
  68. package/src/utils/export/README.md +178 -178
  69. package/src/utils/incrementVersion.js +74 -74
  70. package/src/utils/misc.ts +58 -58
  71. package/src/utils/sidebarGenerator.ts +195 -195
  72. package/src/utils/templates/isolated/exercises/01-hello-world/README.es.md +26 -26
  73. package/src/utils/templates/isolated/exercises/01-hello-world/README.md +26 -26
  74. package/src/utils/templates/scorm/adlcp_rootv1p2.xsd +110 -110
  75. package/src/utils/templates/scorm/config/index.html +209 -209
  76. package/src/utils/templates/scorm/ims_xml.xsd +1 -1
  77. package/src/utils/templates/scorm/imscp_rootv1p1p2.xsd +345 -345
  78. package/src/utils/templates/scorm/imsmanifest.xml +38 -38
  79. 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
@@ -1,4 +1,5 @@
1
- import * as newrelic from "newrelic"
1
+ require("newrelic")
2
+
2
3
  import { flags } from "@oclif/command"
3
4
 
4
5
  import { Buffer } from "buffer"
@@ -51,10 +52,7 @@ import {
51
52
  import axios from "axios"
52
53
  import * as FormData from "form-data"
53
54
  import api, { RIGOBOT_HOST, RIGOBOT_REALTIME_HOST } from "../utils/api"
54
- import {
55
- createUploadMiddleware,
56
- minutesToISO8601Duration,
57
- } from "../utils/misc"
55
+ import { createUploadMiddleware, minutesToISO8601Duration } from "../utils/misc"
58
56
  import { buildConfig, ConfigResponse } from "../utils/configBuilder"
59
57
  import { checkReadability, slugify } from "../utils/creatorUtilities"
60
58
  import { checkAndFixSidebarPure } from "../utils/sidebarGenerator"
@@ -1029,9 +1027,13 @@ export default class ServeCommand extends SessionCommand {
1029
1027
  if (files && Array.isArray(files)) {
1030
1028
  console.log("✅ Processing files for coding challenge...")
1031
1029
 
1032
- // Get the current exercise info to determine the exercise directory
1033
- const syllabus = await getSyllabus(courseSlug, bucket)
1034
- 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)]
1035
1037
 
1036
1038
  if (!exercise) {
1037
1039
  console.error(
@@ -1040,8 +1042,7 @@ export default class ServeCommand extends SessionCommand {
1040
1042
  return res.status(404).json({ error: "Exercise not found" })
1041
1043
  }
1042
1044
 
1043
- const exSlug = slugify(exercise.id + "-" + exercise.title)
1044
- const exerciseDir = `courses/${courseSlug}/exercises/${exSlug}`
1045
+ const exerciseDir = `courses/${courseSlug}/exercises/${exercise.slug}`
1045
1046
 
1046
1047
  for (const fileStr of files) {
1047
1048
  try {
@@ -1070,9 +1071,7 @@ export default class ServeCommand extends SessionCommand {
1070
1071
  fileObj.solution,
1071
1072
  solutionFilePath
1072
1073
  )
1073
- console.log(
1074
- `✅ Saved solution file: ${solutionFilePath}`
1075
- )
1074
+ console.log(`✅ Saved solution file: ${solutionFilePath}`)
1076
1075
  } else {
1077
1076
  // If no extension, just add .solution.hide
1078
1077
  const solutionFileName = `${fileObj.name}.solution.hide`
@@ -1083,9 +1082,7 @@ export default class ServeCommand extends SessionCommand {
1083
1082
  fileObj.solution,
1084
1083
  solutionFilePath
1085
1084
  )
1086
- console.log(
1087
- `✅ Saved solution file: ${solutionFilePath}`
1088
- )
1085
+ console.log(`✅ Saved solution file: ${solutionFilePath}`)
1089
1086
  }
1090
1087
  }
1091
1088
  } catch (parseError) {
@@ -2753,6 +2750,39 @@ export default class ServeCommand extends SessionCommand {
2753
2750
  }
2754
2751
  )
2755
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
+
2756
2786
  const YT_REGEX = /(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]{11})/
2757
2787
 
2758
2788
  app.get("/actions/fetch/:link", async (req, res) => {
@@ -2795,9 +2825,7 @@ export default class ServeCommand extends SessionCommand {
2795
2825
  })
2796
2826
  } catch (error: any) {
2797
2827
  console.error("❌ /actions/fetch error:", error.message || error)
2798
- res
2799
- .status(500)
2800
- .json({ error: error.message || "Failed to fetch link" })
2828
+ res.status(500).json({ error: error.message || "Failed to fetch link" })
2801
2829
  }
2802
2830
  })
2803
2831
  app.delete("/packages/:slug", async (req, res) => {
@@ -2977,10 +3005,7 @@ export default class ServeCommand extends SessionCommand {
2977
3005
  !metadata.rights ||
2978
3006
  !metadata.lang
2979
3007
  ) {
2980
- console.log(
2981
- "Missing required metadata for EPUB export",
2982
- metadata
2983
- )
3008
+ console.log("Missing required metadata for EPUB export", metadata)
2984
3009
  return res.status(400).json({
2985
3010
  error: "Missing required metadata for EPUB export",
2986
3011
  required: ["creator", "publisher", "title", "rights", "lang"],
@@ -3025,9 +3050,7 @@ export default class ServeCommand extends SessionCommand {
3025
3050
  })
3026
3051
  } catch (error: any) {
3027
3052
  console.error("Export error:", error)
3028
- res
3029
- .status(500)
3030
- .json({ error: "Export failed", details: error.message })
3053
+ res.status(500).json({ error: "Export failed", details: error.message })
3031
3054
  }
3032
3055
  })
3033
3056