@learnpack/learnpack 5.0.198 → 5.0.202

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 (39) hide show
  1. package/README.md +13 -13
  2. package/lib/commands/serve.d.ts +5 -28
  3. package/lib/commands/serve.js +45 -14
  4. package/lib/creatorDist/assets/index-C_HbkVCg.js +38491 -0
  5. package/lib/creatorDist/index.html +1 -1
  6. package/lib/models/creator.d.ts +30 -0
  7. package/lib/models/creator.js +2 -0
  8. package/lib/utils/creatorUtilities.js +3 -2
  9. package/oclif.manifest.json +1 -1
  10. package/package.json +1 -1
  11. package/src/commands/serve.ts +58 -49
  12. package/src/creator/package-lock.json +97 -1
  13. package/src/creator/package.json +3 -0
  14. package/src/creator/src/App.tsx +48 -22
  15. package/src/creator/src/components/FileUploader.tsx +6 -5
  16. package/src/creator/src/components/LinkUploader.tsx +3 -1
  17. package/src/creator/src/components/Login.tsx +33 -27
  18. package/src/creator/src/components/PurposeSelector.tsx +32 -25
  19. package/src/creator/src/components/StepWizard.tsx +8 -4
  20. package/src/creator/src/components/Uploader.tsx +8 -5
  21. package/src/creator/src/components/syllabus/ContentIndex.tsx +17 -11
  22. package/src/creator/src/components/syllabus/Sidebar.tsx +4 -3
  23. package/src/creator/src/components/syllabus/SyllabusEditor.tsx +18 -2
  24. package/src/creator/src/i18n.ts +28 -0
  25. package/src/creator/src/locales/en.json +110 -0
  26. package/src/creator/src/locales/es.json +110 -0
  27. package/src/creator/src/main.tsx +1 -0
  28. package/src/creator/src/utils/creatorUtils.ts +2 -2
  29. package/src/creator/src/utils/lib.ts +7 -0
  30. package/src/creator/src/utils/store.ts +8 -5
  31. package/src/creatorDist/assets/index-C_HbkVCg.js +38491 -0
  32. package/src/creatorDist/index.html +1 -1
  33. package/src/models/creator.ts +32 -0
  34. package/src/ui/_app/app.css +1 -1
  35. package/src/ui/_app/app.js +55 -55
  36. package/src/ui/app.tar.gz +0 -0
  37. package/src/utils/creatorUtilities.ts +4 -4
  38. package/lib/creatorDist/assets/index-DszesaEz.js +0 -35438
  39. package/src/creatorDist/assets/index-DszesaEz.js +0 -35438
@@ -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-DszesaEz.js"></script>
13
+ <script type="module" crossorigin src="/creator/assets/index-C_HbkVCg.js"></script>
14
14
  <link rel="stylesheet" crossorigin href="/creator/assets/index-Bnq3eZ3T.css">
15
15
  </head>
16
16
  <body>
@@ -0,0 +1,30 @@
1
+ export interface Lesson {
2
+ id: string;
3
+ uid: string;
4
+ title: string;
5
+ type: "READ" | "CODE" | "QUIZ";
6
+ description: string;
7
+ duration?: number;
8
+ }
9
+ export interface ParsedLink {
10
+ name: string;
11
+ text: string;
12
+ }
13
+ export type FormState = {
14
+ description: string;
15
+ duration: number;
16
+ hasContentIndex: boolean;
17
+ contentIndex: string;
18
+ language?: string;
19
+ technologies?: string[];
20
+ isCompleted: boolean;
21
+ variables: string[];
22
+ currentStep: string;
23
+ title: string;
24
+ purpose: string;
25
+ };
26
+ export type Syllabus = {
27
+ lessons: Lesson[];
28
+ courseInfo: FormState;
29
+ sources: ParsedLink[];
30
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -87,11 +87,12 @@ const slugify = (text) => {
87
87
  return text
88
88
  .toString()
89
89
  .normalize("NFD")
90
- .replace(/[\u0300-\u036F]/g, "")
90
+ .replace(/[\u0300-\u036F]/g, "") // Elimina acentos
91
91
  .toLowerCase()
92
92
  .trim()
93
93
  .replace(/\s+/g, "-")
94
- .replace(/[^\w.-]+/g, "");
94
+ .replace(/["*/:<>?\\|]/g, "")
95
+ .replace(/-+/g, "-");
95
96
  };
96
97
  exports.slugify = slugify;
97
98
  const getExInfo = (title) => {
@@ -1 +1 @@
1
- {"version":"5.0.198","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":[]}}}
1
+ {"version":"5.0.202","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.198",
4
+ "version": "5.0.202",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -45,10 +45,31 @@ import { buildConfig, ConfigResponse } from "../utils/configBuilder"
45
45
  import { checkReadability, slugify } from "../utils/creatorUtilities"
46
46
  import { checkAndFixSidebarPure } from "../utils/sidebarGenerator"
47
47
  import { handleAssetCreation } from "./publish"
48
+ import { FormState, Lesson, Syllabus } from "../models/creator"
48
49
  const frontMatter = require("front-matter")
49
50
 
50
51
  dotenv.config()
51
52
 
53
+ const validateLanguage = (language: string) => {
54
+ if (!language || language.length !== 2) {
55
+ return "en"
56
+ }
57
+
58
+ return language
59
+ }
60
+
61
+ function fixSlugLength(slug: string): string {
62
+ let clean = slug.toLowerCase()
63
+ clean = clean.replace(/[^\da-z-]+/g, "-")
64
+ clean = clean.replace(/-+/g, "-")
65
+ clean = clean.slice(0, 49)
66
+ clean = clean.replace(/^-+/, "").replace(/-+$/, "")
67
+ clean = clean.replace(/^[^\da-z]+/, "").replace(/[^\da-z]+$/, "")
68
+ if (!clean) throw new Error("Invalid slug after cleaning")
69
+
70
+ return clean
71
+ }
72
+
52
73
  export const createLearnJson = (courseInfo: FormState) => {
53
74
  console.log("courseInfo to create learn json", courseInfo)
54
75
 
@@ -57,11 +78,19 @@ export const createLearnJson = (courseInfo: FormState) => {
57
78
  )}.learn-pack.com/preview.png`
58
79
  console.log("Preview url in generated learn.json", expectedPreviewUrl)
59
80
 
81
+ const language = courseInfo.language || "en"
82
+
60
83
  const learnJson = {
61
84
  slug: slugify(courseInfo.title as string),
62
- title: {
63
- us: courseInfo.title,
64
- },
85
+ title:
86
+ language === "en" ?
87
+ {
88
+ us: courseInfo.title,
89
+ } :
90
+ {
91
+ [language]: courseInfo.title,
92
+ // us: courseInfo.title,
93
+ },
65
94
  technologies: courseInfo.technologies || [],
66
95
  difficulty: "beginner",
67
96
  description: {
@@ -153,7 +182,7 @@ export async function processExercise(
153
182
  bucket: Bucket,
154
183
  rigoToken: string,
155
184
  steps: Lesson[],
156
- packageContext: string,
185
+ packageContext: FormState,
157
186
  exercise: Lesson,
158
187
  exercisesDir: string,
159
188
  courseSlug: string,
@@ -163,7 +192,11 @@ export async function processExercise(
163
192
  const exSlug = slugify(exercise.id + "-" + exercise.title)
164
193
  console.log("exSlug", exSlug)
165
194
 
166
- const readmeFilename = "README.md"
195
+ const readmeFilename = `README.${
196
+ packageContext.language && packageContext.language !== "en" ?
197
+ `${packageContext.language}.` :
198
+ ""
199
+ }md`
167
200
  const targetDir = `${exercisesDir}/${exSlug}`
168
201
 
169
202
  console.log("✍🏻 Generating lesson", exercise.id, exercise.title)
@@ -184,9 +217,9 @@ export async function processExercise(
184
217
  rigoToken,
185
218
  {
186
219
  title: `${exercise.id} - ${exercise.title}`,
187
- output_lang: "en",
220
+ output_lang: packageContext.language || "en",
188
221
  list_of_exercises: JSON.stringify(steps),
189
- tutorial_description: packageContext,
222
+ tutorial_description: JSON.stringify(packageContext),
190
223
  lesson_description: exercise.description,
191
224
  kind: exercise.type.toLowerCase(),
192
225
  },
@@ -195,7 +228,7 @@ export async function processExercise(
195
228
 
196
229
  const duration = exercise.duration
197
230
  let attempts = 0
198
- let readability = checkReadability(readme.parsed.content, 200, duration || 1)
231
+ let readability = checkReadability(readme.parsed.content, 250, duration || 3)
199
232
 
200
233
  while (
201
234
  readability.fkglResult.fkgl > PARAMS.max_fkgl &&
@@ -247,7 +280,7 @@ export async function processExercise(
247
280
 
248
281
  const codeFile = await createCodeFile(rigoToken, {
249
282
  readme: readability.newMarkdown,
250
- tutorial_info: packageContext,
283
+ tutorial_info: JSON.stringify(packageContext),
251
284
  })
252
285
  await uploadFileToBucket(
253
286
  bucket,
@@ -264,40 +297,6 @@ export async function processExercise(
264
297
  return readability.newMarkdown
265
298
  }
266
299
 
267
- interface Lesson {
268
- id: string
269
- uid: string
270
- title: string
271
- type: "READ" | "CODE" | "QUIZ"
272
- description: string
273
- duration?: number
274
- }
275
-
276
- interface ParsedLink {
277
- name: string
278
- text: string
279
- }
280
- type FormState = {
281
- description: string
282
- duration: number
283
- targetAudience: string
284
- hasContentIndex: boolean
285
- contentIndex: string
286
- sources: ParsedLink[]
287
- isCompleted: boolean
288
- variables: string[]
289
- currentStep: string
290
- title: string
291
- technologies?: string[]
292
- purpose: string
293
- }
294
-
295
- type Syllabus = {
296
- lessons: Lesson[]
297
- courseInfo: FormState
298
- sources: ParsedLink[]
299
- }
300
-
301
300
  const fixPreviewUrl = (slug: string, previewUrl: string) => {
302
301
  if (!previewUrl) {
303
302
  return null
@@ -960,7 +959,7 @@ export default class ServeCommand extends SessionCommand {
960
959
  bucket,
961
960
  rigoToken,
962
961
  syllabus.lessons,
963
- JSON.stringify(syllabus.courseInfo),
962
+ syllabus.courseInfo,
964
963
  lesson,
965
964
  tutorialDir + "/exercises",
966
965
  slugify(syllabus.courseInfo.title),
@@ -1062,7 +1061,7 @@ export default class ServeCommand extends SessionCommand {
1062
1061
  if (!rigoToken || !bcToken) {
1063
1062
  return res
1064
1063
  .status(400)
1065
- .json({ error: "Faltan tokens o academy/category" })
1064
+ .json({ error: "Authentication failed, missing tokens" })
1066
1065
  }
1067
1066
 
1068
1067
  const { config, exercises }: ConfigResponse = await buildConfig(
@@ -1070,7 +1069,12 @@ export default class ServeCommand extends SessionCommand {
1070
1069
  slug
1071
1070
  )
1072
1071
 
1073
- // 3) Preparar dirs temporales
1072
+ // console.log(slug, "SLUG")
1073
+
1074
+ const fixedSlug = fixSlugLength(slug)
1075
+
1076
+ // console.log(fixedSlug, "FIXED SLUG")
1077
+
1074
1078
  const prefix = `courses/${slug}/`
1075
1079
  const tmpRoot = path.join(os.tmpdir(), `learnpack-${slug}`)
1076
1080
  const buildRoot = path.join(tmpRoot, "build")
@@ -1102,7 +1106,7 @@ export default class ServeCommand extends SessionCommand {
1102
1106
  .replace(/{{description}}/g, config.description.us)
1103
1107
  .replace(
1104
1108
  /{{preview}}/g,
1105
- fixPreviewUrl(slug, config.preview) ||
1109
+ fixPreviewUrl(fixedSlug, "") ||
1106
1110
  "https://raw.githubusercontent.com/learnpack/ide/master/public/learnpack.svg"
1107
1111
  )
1108
1112
  .replace(/{{slug}}/g, slug)
@@ -1132,6 +1136,11 @@ export default class ServeCommand extends SessionCommand {
1132
1136
 
1133
1137
  // 8) Crear el config.json en buildRoot con lo que retorna buildConfig
1134
1138
  const fullConfig = { config, exercises }
1139
+ fullConfig.config.slug = fixedSlug
1140
+ fullConfig.config.preview =
1141
+ fixPreviewUrl(fixedSlug, "") ||
1142
+ "https://raw.githubusercontent.com/learnpack/ide/master/public/learnpack.svg"
1143
+
1135
1144
  fs.writeFileSync(
1136
1145
  path.join(buildRoot, "config.json"),
1137
1146
  JSON.stringify(fullConfig, null, 2),
@@ -1139,7 +1148,7 @@ export default class ServeCommand extends SessionCommand {
1139
1148
  )
1140
1149
 
1141
1150
  // 9) Empaquetar en ZIP (solo contenido de buildRoot)
1142
- const zipName = `${slug}.zip`
1151
+ const zipName = `${fixedSlug}.zip`
1143
1152
  const zipPath = path.join(tmpRoot, zipName)
1144
1153
  const output = fs.createWriteStream(zipPath)
1145
1154
  const archive = archiver("zip", { zlib: { level: 9 } })
@@ -1163,7 +1172,7 @@ export default class ServeCommand extends SessionCommand {
1163
1172
 
1164
1173
  await handleAssetCreation(
1165
1174
  { token: bcToken, rigobotToken: rigoToken },
1166
- config,
1175
+ fullConfig.config,
1167
1176
  rigoRes.data.url
1168
1177
  )
1169
1178
 
@@ -14,6 +14,8 @@
14
14
  "framer-motion": "^12.9.2",
15
15
  "front-matter": "^4.0.2",
16
16
  "html2canvas": "^1.4.1",
17
+ "i18next": "^25.2.1",
18
+ "i18next-browser-languagedetector": "^8.2.0",
17
19
  "js-yaml": "^4.1.0",
18
20
  "mammoth": "^1.9.0",
19
21
  "mitt": "^3.0.1",
@@ -21,6 +23,7 @@
21
23
  "react": "^19.0.0",
22
24
  "react-dom": "^19.0.0",
23
25
  "react-hot-toast": "^2.5.2",
26
+ "react-i18next": "^15.5.2",
24
27
  "react-markdown": "^10.1.0",
25
28
  "react-router": "^7.5.0",
26
29
  "socket.io-client": "^4.8.1",
@@ -45,6 +48,15 @@
45
48
  "vite": "^6.2.0"
46
49
  }
47
50
  },
51
+ "node_modules/@babel/runtime": {
52
+ "version": "7.27.6",
53
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
54
+ "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
55
+ "license": "MIT",
56
+ "engines": {
57
+ "node": ">=6.9.0"
58
+ }
59
+ },
48
60
  "node_modules/@esbuild/aix-ppc64": {
49
61
  "version": "0.25.2",
50
62
  "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz",
@@ -3613,6 +3625,15 @@
3613
3625
  ],
3614
3626
  "license": "MIT"
3615
3627
  },
3628
+ "node_modules/html-parse-stringify": {
3629
+ "version": "3.0.1",
3630
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
3631
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
3632
+ "license": "MIT",
3633
+ "dependencies": {
3634
+ "void-elements": "3.1.0"
3635
+ }
3636
+ },
3616
3637
  "node_modules/html-url-attributes": {
3617
3638
  "version": "3.0.1",
3618
3639
  "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz",
@@ -3675,6 +3696,46 @@
3675
3696
  "node": ">= 14"
3676
3697
  }
3677
3698
  },
3699
+ "node_modules/i18next": {
3700
+ "version": "25.2.1",
3701
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.2.1.tgz",
3702
+ "integrity": "sha512-+UoXK5wh+VlE1Zy5p6MjcvctHXAhRwQKCxiJD8noKZzIXmnAX8gdHX5fLPA3MEVxEN4vbZkQFy8N0LyD9tUqPw==",
3703
+ "funding": [
3704
+ {
3705
+ "type": "individual",
3706
+ "url": "https://locize.com"
3707
+ },
3708
+ {
3709
+ "type": "individual",
3710
+ "url": "https://locize.com/i18next.html"
3711
+ },
3712
+ {
3713
+ "type": "individual",
3714
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
3715
+ }
3716
+ ],
3717
+ "license": "MIT",
3718
+ "dependencies": {
3719
+ "@babel/runtime": "^7.27.1"
3720
+ },
3721
+ "peerDependencies": {
3722
+ "typescript": "^5"
3723
+ },
3724
+ "peerDependenciesMeta": {
3725
+ "typescript": {
3726
+ "optional": true
3727
+ }
3728
+ }
3729
+ },
3730
+ "node_modules/i18next-browser-languagedetector": {
3731
+ "version": "8.2.0",
3732
+ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz",
3733
+ "integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==",
3734
+ "license": "MIT",
3735
+ "dependencies": {
3736
+ "@babel/runtime": "^7.23.2"
3737
+ }
3738
+ },
3678
3739
  "node_modules/ignore": {
3679
3740
  "version": "5.3.2",
3680
3741
  "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -5378,6 +5439,32 @@
5378
5439
  "react-dom": ">=16"
5379
5440
  }
5380
5441
  },
5442
+ "node_modules/react-i18next": {
5443
+ "version": "15.5.2",
5444
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.2.tgz",
5445
+ "integrity": "sha512-ePODyXgmZQAOYTbZXQn5rRsSBu3Gszo69jxW6aKmlSgxKAI1fOhDwSu6bT4EKHciWPKQ7v7lPrjeiadR6Gi+1A==",
5446
+ "license": "MIT",
5447
+ "dependencies": {
5448
+ "@babel/runtime": "^7.25.0",
5449
+ "html-parse-stringify": "^3.0.1"
5450
+ },
5451
+ "peerDependencies": {
5452
+ "i18next": ">= 23.2.3",
5453
+ "react": ">= 16.8.0",
5454
+ "typescript": "^5"
5455
+ },
5456
+ "peerDependenciesMeta": {
5457
+ "react-dom": {
5458
+ "optional": true
5459
+ },
5460
+ "react-native": {
5461
+ "optional": true
5462
+ },
5463
+ "typescript": {
5464
+ "optional": true
5465
+ }
5466
+ }
5467
+ },
5381
5468
  "node_modules/react-markdown": {
5382
5469
  "version": "10.1.0",
5383
5470
  "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz",
@@ -6021,7 +6108,7 @@
6021
6108
  "version": "5.7.3",
6022
6109
  "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
6023
6110
  "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
6024
- "dev": true,
6111
+ "devOptional": true,
6025
6112
  "license": "Apache-2.0",
6026
6113
  "bin": {
6027
6114
  "tsc": "bin/tsc",
@@ -6317,6 +6404,15 @@
6317
6404
  }
6318
6405
  }
6319
6406
  },
6407
+ "node_modules/void-elements": {
6408
+ "version": "3.1.0",
6409
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
6410
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
6411
+ "license": "MIT",
6412
+ "engines": {
6413
+ "node": ">=0.10.0"
6414
+ }
6415
+ },
6320
6416
  "node_modules/webidl-conversions": {
6321
6417
  "version": "3.0.1",
6322
6418
  "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
@@ -17,6 +17,8 @@
17
17
  "framer-motion": "^12.9.2",
18
18
  "front-matter": "^4.0.2",
19
19
  "html2canvas": "^1.4.1",
20
+ "i18next": "^25.2.1",
21
+ "i18next-browser-languagedetector": "^8.2.0",
20
22
  "js-yaml": "^4.1.0",
21
23
  "mammoth": "^1.9.0",
22
24
  "mitt": "^3.0.1",
@@ -24,6 +26,7 @@
24
26
  "react": "^19.0.0",
25
27
  "react-dom": "^19.0.0",
26
28
  "react-hot-toast": "^2.5.2",
29
+ "react-i18next": "^15.5.2",
27
30
  "react-markdown": "^10.1.0",
28
31
  "react-router": "^7.5.0",
29
32
  "socket.io-client": "^4.8.1",