@learnpack/learnpack 5.0.238 → 5.0.244

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.
@@ -270,8 +270,12 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
270
270
  const imagePromises = imagesArray.map(async (image) => {
271
271
  try {
272
272
  const filename = (0, creatorUtilities_1.getFilenameFromUrl)(image.url);
273
+ const webhookUrl = `${process.env.HOST}/webhooks/${(0, creatorUtilities_1.slugify)(packageInfo.title.us)}/images/${filename}`;
273
274
  const imagePath = path.join(tutorialDir, ".learn", "assets", filename);
274
- const res = await (0, rigoActions_1.generateImage)(rigoToken, { prompt: image.alt });
275
+ const res = await (0, rigoActions_1.generateImage)(rigoToken, {
276
+ prompt: image.alt,
277
+ callbackUrl: webhookUrl,
278
+ });
275
279
  await (0, rigoActions_1.downloadImage)(res.image_url, imagePath);
276
280
  return true;
277
281
  }
@@ -289,8 +293,9 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
289
293
  prompt: "Generate a preview image for the tutorial. This is all the tutorial information: " +
290
294
  packageContext +
291
295
  "\n Generate only a basic preview image, add the tutorial Title as a text add the top middle, avoid adding any other text elements. Try to generate an image that related with the tutorial content.",
296
+ callbackUrl: `${process.env.HOST}/webhooks/${(0, creatorUtilities_1.slugify)(packageInfo.title.us)}/images/preview.png`,
292
297
  });
293
- await (0, rigoActions_1.downloadImage)(res.image_url, imagePath);
298
+ // await downloadImage(res.image_url, imagePath)
294
299
  return true;
295
300
  };
296
301
  const getChoices = async (empty) => {
@@ -2,7 +2,7 @@ import SessionCommand from "../utils/SessionCommand";
2
2
  export declare const handleAssetCreation: (sessionPayload: {
3
3
  token: string;
4
4
  rigobotToken: string;
5
- }, learnJson: any, selectedLang: string, learnpackDeployUrl: string) => Promise<void>;
5
+ }, learnJson: any, selectedLang: string, learnpackDeployUrl: string, b64IndexReadme: string, all_translations?: string[]) => Promise<any>;
6
6
  declare class BuildCommand extends SessionCommand {
7
7
  static description: string;
8
8
  static flags: {
@@ -18,11 +18,12 @@ const api_1 = require("../utils/api");
18
18
  const prompts = require("prompts");
19
19
  const rigoActions_1 = require("../utils/rigoActions");
20
20
  const misc_1 = require("../utils/misc");
21
+ const creatorUtilities_1 = require("../utils/creatorUtilities");
21
22
  const uploadZipEndpont = api_1.RIGOBOT_HOST + "/v1/learnpack/upload";
22
- const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, learnpackDeployUrl) => {
23
+ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, learnpackDeployUrl, b64IndexReadme, all_translations = []) => {
23
24
  const categories = {
24
- us: 91,
25
- es: 92,
25
+ us: 9,
26
+ es: 10,
26
27
  };
27
28
  let category = categories[selectedLang];
28
29
  if (!category) {
@@ -30,11 +31,12 @@ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, lear
30
31
  }
31
32
  try {
32
33
  const user = await api_1.default.validateToken(sessionPayload.token);
33
- const { exists } = await api_1.default.doesAssetExists(sessionPayload.token, learnJson.slug);
34
+ const slug = (0, creatorUtilities_1.slugify)(learnJson.title[selectedLang]).slice(0, 50);
35
+ const { exists } = await api_1.default.doesAssetExists(sessionPayload.token, slug);
34
36
  if (!exists) {
35
37
  console_1.default.info("Asset does not exist in this academy, creating it");
36
38
  const asset = await api_1.default.createAsset(sessionPayload.token, {
37
- slug: learnJson.slug,
39
+ slug: slug,
38
40
  title: learnJson.title[selectedLang],
39
41
  lang: selectedLang,
40
42
  description: learnJson.description[selectedLang],
@@ -45,23 +47,27 @@ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, lear
45
47
  owner: user.id,
46
48
  author: user.id,
47
49
  preview: learnJson.preview,
50
+ readme_raw: b64IndexReadme,
51
+ all_translations,
48
52
  });
49
53
  await api_1.default.updateRigoAssetID(sessionPayload.token, learnJson.slug, asset.id);
50
54
  console_1.default.info("Asset created with id", asset.id);
55
+ return asset;
51
56
  }
52
- else {
53
- console_1.default.info("Asset exists, updating it");
54
- const asset = await api_1.default.updateAsset(sessionPayload.token, learnJson.slug, {
55
- learnpack_deploy_url: learnpackDeployUrl,
56
- title: learnJson.title[selectedLang],
57
- description: learnJson.description[selectedLang],
58
- });
59
- await api_1.default.updateRigoAssetID(sessionPayload.rigobotToken, learnJson.slug, asset.id);
60
- console_1.default.info("Asset updated with id", asset.id);
61
- }
57
+ console_1.default.info("Asset exists, updating it");
58
+ const asset = await api_1.default.updateAsset(sessionPayload.token, slug, {
59
+ learnpack_deploy_url: learnpackDeployUrl,
60
+ title: learnJson.title[selectedLang],
61
+ description: learnJson.description[selectedLang],
62
+ all_translations,
63
+ });
64
+ await api_1.default.updateRigoAssetID(sessionPayload.rigobotToken.trim(), learnJson.slug, asset.id);
65
+ console_1.default.info("Asset updated with id", asset.id);
66
+ return asset;
62
67
  }
63
68
  catch (error) {
64
69
  console_1.default.error("Error updating or creating asset:", error);
70
+ return null;
65
71
  }
66
72
  };
67
73
  exports.handleAssetCreation = handleAssetCreation;
@@ -295,7 +301,7 @@ class BuildCommand extends SessionCommand_1.default {
295
301
  console.log(res.data);
296
302
  fs.unlinkSync(zipFilePath);
297
303
  this.removeDirectory(buildDir);
298
- await (0, exports.handleAssetCreation)(sessionPayload, learnJson, "us", res.data.url);
304
+ await (0, exports.handleAssetCreation)(sessionPayload, learnJson, "us", res.data.url, "", []);
299
305
  }
300
306
  catch (error) {
301
307
  if (axios_1.default.isAxiosError(error)) {
@@ -1,5 +1,4 @@
1
1
  import SessionCommand from "../utils/SessionCommand";
2
- import { Bucket } from "@google-cloud/storage";
3
2
  import { FormState } from "../models/creator";
4
3
  export declare const createLearnJson: (courseInfo: FormState) => {
5
4
  slug: string;
@@ -20,7 +19,7 @@ export declare const createLearnJson: (courseInfo: FormState) => {
20
19
  };
21
20
  preview: string;
22
21
  };
23
- export declare const processImage: (bucket: Bucket, tutorialDir: string, url: string, description: string, rigoToken: string) => Promise<boolean>;
22
+ export declare const processImage: (url: string, description: string, rigoToken: string, courseSlug: string) => Promise<boolean>;
24
23
  export default class ServeCommand extends SessionCommand {
25
24
  static description: string;
26
25
  static flags: any;
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.processImage = exports.createLearnJson = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const command_1 = require("@oclif/command");
6
- // import { readDocument } from "../utils/readDocuments"
7
6
  const youtube_transcript_1 = require("youtube-transcript");
8
7
  const express = require("express");
9
8
  const cors = require("cors");
@@ -42,11 +41,11 @@ function findLast(array, predicate) {
42
41
  }
43
42
  const createLearnJson = (courseInfo) => {
44
43
  // console.log("courseInfo to create learn json", courseInfo)
45
- const expectedPreviewUrl = `https://${(0, creatorUtilities_2.slugify)(courseInfo.title)}.learn-pack.com/preview.png`;
44
+ const expectedPreviewUrl = `https://${courseInfo.slug}.learn-pack.com/preview.png`;
46
45
  console.log("Preview url in generated learn.json", expectedPreviewUrl);
47
46
  const language = courseInfo.language || "en";
48
47
  const learnJson = {
49
- slug: (0, creatorUtilities_2.slugify)(courseInfo.title),
48
+ slug: courseInfo.slug,
50
49
  title: language === "en" || language === "us" ?
51
50
  {
52
51
  us: courseInfo.title,
@@ -72,19 +71,6 @@ const uploadFileToBucket = async (bucket, file, path) => {
72
71
  const fileRef = bucket.file(path);
73
72
  await fileRef.save(Buffer.from(file, "utf8"));
74
73
  };
75
- const uploadImageToBucket = async (bucket, url, path) => {
76
- const response = await fetch(url);
77
- if (!response.ok) {
78
- throw new Error(`Failed to download image: ${response.statusText}`);
79
- }
80
- const contentType = response.headers.get("content-type") || "application/octet-stream";
81
- const buffer = await response.arrayBuffer();
82
- const fileRef = bucket.file(path);
83
- await fileRef.save(Buffer.from(buffer), {
84
- resumable: false,
85
- contentType,
86
- });
87
- };
88
74
  const PARAMS = {
89
75
  expected_grade_level: "8",
90
76
  max_fkgl: 10,
@@ -92,16 +78,16 @@ const PARAMS = {
92
78
  max_rewrite_attempts: 2,
93
79
  max_title_length: 50,
94
80
  };
95
- const processImage = async (bucket, tutorialDir, url, description, rigoToken) => {
81
+ const processImage = async (url, description, rigoToken, courseSlug) => {
96
82
  try {
97
83
  // TODO: MAKE THIS ASYNC
98
84
  const filename = (0, creatorUtilities_1.getFilenameFromUrl)(url);
99
- console.log("🖼️ IMAGE FILENAME", filename);
100
- const imagePath = `${tutorialDir}/.learn/assets/${filename}`;
101
- console.log("🖼️ Generating image", imagePath);
102
- const res = await (0, rigoActions_1.generateImage)(rigoToken, { prompt: description });
103
- await uploadImageToBucket(bucket, res.image_url, imagePath);
104
- console.log("✅ Image", imagePath, "generated successfully!");
85
+ const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/images/${filename}`;
86
+ await (0, rigoActions_1.generateImage)(rigoToken, {
87
+ prompt: description,
88
+ callbackUrl: webhookUrl,
89
+ });
90
+ // console.log("✅ Image", imagePath, "generated successfully!")
105
91
  return true;
106
92
  }
107
93
  catch (_a) {
@@ -131,10 +117,31 @@ const uploadInitialReadme = async (bucket, exSlug, targetDir, packageContext) =>
131
117
  await uploadFileToBucket(bucket, isGeneratingText, `${targetDir}/${readmeFilename}`);
132
118
  };
133
119
  const cleanFormState = (formState) => {
134
- // keysToDelete: description, technologies, purpose
135
120
  const { description, technologies, purpose, hasContentIndex, duration, isCompleted, variables, currentStep, language } = formState, rest = tslib_1.__rest(formState, ["description", "technologies", "purpose", "hasContentIndex", "duration", "isCompleted", "variables", "currentStep", "language"]);
136
121
  return rest;
137
122
  };
123
+ const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, courseJson, deployUrl) => {
124
+ const availableLangs = Object.keys(courseJson.title);
125
+ console.log("AVAILABLE LANGUAGES to upload asset", availableLangs);
126
+ const all_translations = [];
127
+ for (const lang of availableLangs) {
128
+ // eslint-disable-next-line no-await-in-loop
129
+ const indexReadme = await bucket.file(`courses/${courseSlug}/README.${lang === "us" || lang === "en" ? "md" : `${lang}.md`}`);
130
+ // eslint-disable-next-line no-await-in-loop
131
+ const [indexReadmeContent] = await indexReadme.download();
132
+ const indexReadmeString = indexReadmeContent.toString();
133
+ const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64");
134
+ // eslint-disable-next-line no-await-in-loop
135
+ const asset = await (0, publish_1.handleAssetCreation)({ token: bcToken, rigobotToken: rigoToken }, courseJson, lang, deployUrl, b64IndexReadme, all_translations);
136
+ all_translations.push(asset.slug);
137
+ }
138
+ // const languageCodes = new Set(languageCodes)
139
+ // const asset = await api.createAsset(rigoToken, {
140
+ // slug: courseSlug,
141
+ // title: courseJson.title,
142
+ // description: courseJson.description,
143
+ // })
144
+ };
138
145
  async function startExerciseGeneration(bucket, rigoToken, steps, packageContext, exercise, tutorialDir, courseSlug, purposeSlug, lastLesson = "") {
139
146
  const exSlug = (0, creatorUtilities_2.slugify)(exercise.id + "-" + exercise.title);
140
147
  console.log("Starting generation of", exSlug);
@@ -150,6 +157,19 @@ async function startExerciseGeneration(bucket, rigoToken, steps, packageContext,
150
157
  last_lesson: lastLesson,
151
158
  }, purposeSlug, webhookUrl);
152
159
  }
160
+ async function createInitialReadme(tutorialInfo, tutorialSlug, rigoToken) {
161
+ const webhookUrl = `${process.env.HOST}/webhooks/${tutorialSlug}/initial-readme-processor`;
162
+ console.log("Creating initial readme", webhookUrl);
163
+ try {
164
+ const res = await (0, rigoActions_1.createStructuredPreviewReadme)(rigoToken, {
165
+ tutorial_info: tutorialInfo,
166
+ }, webhookUrl);
167
+ console.log("Initial readme created", res);
168
+ }
169
+ catch (error) {
170
+ console.error("Error creating initial readme", error);
171
+ }
172
+ }
153
173
  const fixPreviewUrl = (slug, previewUrl) => {
154
174
  if (!previewUrl) {
155
175
  return null;
@@ -315,6 +335,19 @@ class ServeCommand extends SessionCommand_1.default {
315
335
  (0, creatorSocket_1.emitToNotification)(id, body);
316
336
  res.json({ id, status: "SUCCESS" });
317
337
  });
338
+ app.post("/webhooks/:courseSlug/initial-readme-processor", async (req, res) => {
339
+ const { courseSlug } = req.params;
340
+ const body = req.body;
341
+ // Save the file as courses/courseSlug/README.md
342
+ const filePath = `courses/${courseSlug}/README.${body.parsed.language_code === "us" ||
343
+ body.parsed.language_code === "en" ?
344
+ "md" :
345
+ `${body.parsed.language_code}.md`}`;
346
+ console.log("Saving initial readme to", filePath);
347
+ await uploadFileToBucket(bucket, body.parsed.content, filePath);
348
+ console.log("Initial readme saved to", filePath);
349
+ res.json({ status: "SUCCESS" });
350
+ });
318
351
  app.post("/webhooks/:courseSlug/images/:imageId", async (req, res) => {
319
352
  const { courseSlug, imageId } = req.params;
320
353
  const body = req.body;
@@ -401,7 +434,7 @@ class ServeCommand extends SessionCommand_1.default {
401
434
  });
402
435
  for (const image of imagesArray) {
403
436
  // eslint-disable-next-line no-await-in-loop
404
- await (0, exports.processImage)(bucket, `courses/${courseSlug}`, image.url, image.alt, rigoToken);
437
+ await (0, exports.processImage)(image.url, image.alt, rigoToken, courseSlug);
405
438
  }
406
439
  }
407
440
  (0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
@@ -572,19 +605,23 @@ class ServeCommand extends SessionCommand_1.default {
572
605
  });
573
606
  app.post("/actions/translate", express.json(), async (req, res) => {
574
607
  console.log("POST /actions/translate");
575
- const { exerciseSlugs, languages, rigoToken } = req.body;
608
+ const { exerciseSlugs, languages, rigoToken, currentLanguage } = req.body;
576
609
  const query = req.query;
577
610
  const courseSlug = query.slug;
578
- console.log("EXERCISE SLUGS", exerciseSlugs);
579
- console.log("LANGUAGES", languages);
580
- console.log("RIGO TOKEN", rigoToken);
581
611
  if (!rigoToken) {
582
612
  return res.status(400).json({ error: "RigoToken not found" });
583
613
  }
584
614
  const languagesToTranslate = languages.split(",");
615
+ const course = await bucket
616
+ .file(`courses/${courseSlug}/learn.json`)
617
+ .download();
618
+ const courseJson = JSON.parse(course.toString());
619
+ const languageCodes = new Set();
585
620
  try {
586
621
  await Promise.all(exerciseSlugs.map(async (slug) => {
587
- const readmePath = `courses/${courseSlug}/exercises/${slug}/README.md`;
622
+ const readmePath = `courses/${courseSlug}/exercises/${slug}/README${currentLanguage === "us" || currentLanguage === "en" ?
623
+ "" :
624
+ `.${currentLanguage}`}.md`;
588
625
  const readme = await bucket.file(readmePath).download();
589
626
  await Promise.all(languagesToTranslate.map(async (language) => {
590
627
  const response = await (0, rigoActions_1.translateExercise)(rigoToken, {
@@ -592,10 +629,62 @@ class ServeCommand extends SessionCommand_1.default {
592
629
  output_language: language,
593
630
  exercise_slug: slug,
594
631
  });
595
- const translatedReadme = await bucket.file(`courses/${courseSlug}/exercises/${slug}/README.${response.parsed.output_language_code}.md`);
632
+ const translatedReadme = await bucket.file(`courses/${courseSlug}/exercises/${slug}/README${response.parsed.output_language_code === "us" ||
633
+ response.parsed.output_language_code === "en" ?
634
+ "" :
635
+ `.${response.parsed.output_language_code}`}.md`);
596
636
  await translatedReadme.save(response.parsed.translation);
637
+ languageCodes.add(response.parsed.output_language_code);
597
638
  }));
598
639
  }));
640
+ if (languageCodes.has("en")) {
641
+ languageCodes.delete("en");
642
+ languageCodes.add("us");
643
+ }
644
+ const currentLanguages = Object.keys(courseJson.title);
645
+ for (const languageCode of currentLanguages) {
646
+ if (languageCodes.has(languageCode)) {
647
+ languageCodes.delete(languageCode);
648
+ }
649
+ }
650
+ if ([...languageCodes].length > 0) {
651
+ console.log("TRANSLATING COURSE METADATA", languageCodes);
652
+ const translatedCourseMetadata = await Promise.all([...languageCodes].map(async (languageCode) => {
653
+ const result = await (0, rigoActions_1.translateCourseMetadata)(rigoToken, {
654
+ title: courseJson.title[currentLanguage],
655
+ description: courseJson.description[currentLanguage],
656
+ destination_lang_code: languageCode,
657
+ });
658
+ return {
659
+ languageCode,
660
+ title: result.parsed.title,
661
+ description: result.parsed.description,
662
+ };
663
+ }));
664
+ for (const metadata of translatedCourseMetadata) {
665
+ courseJson.title[metadata.languageCode] = metadata.title;
666
+ courseJson.description[metadata.languageCode] =
667
+ metadata.description;
668
+ }
669
+ await uploadFileToBucket(bucket, JSON.stringify(courseJson), `courses/${courseSlug}/learn.json`);
670
+ const previewReadme = await bucket.file(`courses/${courseSlug}/README${currentLanguage === "us" || currentLanguage === "en" ?
671
+ "" :
672
+ `.${currentLanguage}`}.md`);
673
+ const [previewReadmeContent] = await previewReadme.download();
674
+ const previewReadmeContentString = previewReadmeContent.toString();
675
+ await Promise.all([...languageCodes].map(async (languageCode) => {
676
+ const translatedPreviewReadme = await (0, rigoActions_1.translateExercise)(rigoToken, {
677
+ text_to_translate: previewReadmeContentString,
678
+ output_language: languageCode,
679
+ exercise_slug: "preview-readme",
680
+ });
681
+ await bucket
682
+ .file(`courses/${courseSlug}/README${languageCode === "us" || languageCode === "en" ?
683
+ "" :
684
+ `.${languageCode}`}.md`)
685
+ .save(translatedPreviewReadme.parsed.translation);
686
+ }));
687
+ }
599
688
  return res.status(200).json({ message: "Translated exercises" });
600
689
  }
601
690
  catch (error) {
@@ -604,6 +693,7 @@ class ServeCommand extends SessionCommand_1.default {
604
693
  }
605
694
  });
606
695
  app.delete("/exercise/:slug/delete", async (req, res) => {
696
+ console.log("DELETE /exercise/:slug/delete");
607
697
  const { slug } = req.params;
608
698
  const query = req.query;
609
699
  const courseSlug = query.slug;
@@ -639,53 +729,23 @@ class ServeCommand extends SessionCommand_1.default {
639
729
  }
640
730
  catch (error) {
641
731
  if (error.code === 404) {
642
- console.log("SIDEBAR FILE NOT FOUND", courseSlug);
643
732
  const { exercises } = await (0, configBuilder_1.buildConfig)(bucket, courseSlug);
644
733
  const exerciseSlugsArray = exercises.map(exercise => exercise.slug);
645
734
  const sidebar = await createInitialSidebar(exerciseSlugsArray);
735
+ await uploadFileToBucket(bucket, JSON.stringify(sidebar), `courses/${courseSlug}/.learn/sidebar.json`);
646
736
  if (rigoToken) {
647
737
  const { fixedSidebar } = await (0, sidebarGenerator_1.checkAndFixSidebarPure)(sidebar, exercises, rigoToken);
648
738
  if (fixedSidebar) {
649
739
  await uploadFileToBucket(bucket, JSON.stringify(fixedSidebar), `courses/${courseSlug}/.learn/sidebar.json`);
650
740
  }
651
- await uploadFileToBucket(bucket, JSON.stringify(sidebar), `courses/${courseSlug}/.learn/sidebar.json`);
652
741
  return res.status(200).json(fixedSidebar);
653
742
  }
654
- await uploadFileToBucket(bucket, JSON.stringify(sidebar), `courses/${courseSlug}/.learn/sidebar.json`);
655
743
  return res.status(200).json(sidebar);
656
744
  }
657
745
  console.error("Unexpected error:", error);
658
746
  res.status(500).json({ error: error.message });
659
747
  }
660
748
  });
661
- // app.get("/test/:slug", (req, res) => {
662
- // emitToCourse(req.params.slug, "course-creation", {
663
- // lesson: "000-welcome-to-bird-domestication",
664
- // status: "generating",
665
- // log: "Hello",
666
- // })
667
- // emitToCourse(req.params.slug, "course-creation", {
668
- // lesson: "000-welcome-to-bird-domestication",
669
- // status: "generating",
670
- // log: "Hello",
671
- // })
672
- // emitToCourse(req.params.slug, "course-creation", {
673
- // lesson: "000-welcome-to-bird-domestication",
674
- // status: "generating",
675
- // log: "Hello broder",
676
- // })
677
- // emitToCourse(req.params.slug, "course-creation", {
678
- // lesson: "000-welcome-to-bird-domestication",
679
- // status: "done",
680
- // log: "Hello broder",
681
- // })
682
- // emitToCourse(req.params.slug, "course-creation", {
683
- // lesson: "other",
684
- // status: "generating",
685
- // log: "Hello",
686
- // })
687
- // res.send({ message: "Course creation started" })
688
- // })
689
749
  app.get("/technologies", async (req, res) => {
690
750
  console.log("GET /technologies");
691
751
  const technologies = await api_1.default.getCurrentTechnologies();
@@ -718,7 +778,7 @@ class ServeCommand extends SessionCommand_1.default {
718
778
  if (!rigoToken || !bcToken) {
719
779
  return res.status(400).json({ error: "Missing tokens" });
720
780
  }
721
- const courseSlug = (0, creatorUtilities_2.slugify)(syllabus.courseInfo.title);
781
+ const courseSlug = syllabus.courseInfo.slug;
722
782
  const tutorialDir = `courses/${courseSlug}`;
723
783
  const learnJson = (0, exports.createLearnJson)(syllabus.courseInfo);
724
784
  try {
@@ -755,9 +815,10 @@ class ServeCommand extends SessionCommand_1.default {
755
815
  const firstLesson = syllabus.lessons[0];
756
816
  const lastResult = "Nothing";
757
817
  await startExerciseGeneration(bucket, rigoToken, syllabus.lessons, syllabus.courseInfo, firstLesson, tutorialDir, courseSlug, syllabus.courseInfo.purpose, lastResult);
818
+ await createInitialReadme(JSON.stringify(syllabus.courseInfo), courseSlug, rigoToken);
758
819
  return res.json({
759
820
  message: "Course created",
760
- slug: (0, creatorUtilities_2.slugify)(syllabus.courseInfo.title),
821
+ slug: syllabus.courseInfo.slug,
761
822
  });
762
823
  });
763
824
  app.get("/courses/:courseSlug/syllabus", async (req, res) => {
@@ -873,11 +934,6 @@ class ServeCommand extends SessionCommand_1.default {
873
934
  title = config.title[availableLangs[0]];
874
935
  selectedLang = availableLangs[0];
875
936
  }
876
- console.log(config.description, "CONFIG DESCRIPTION");
877
- // console.log(availableLangs, "AVAILABLE LANGs")
878
- // console.log(selectedLang, "SELECTED LANG")
879
- // console.log(title, "TITLE")
880
- // 5) Inyectar placeholders en index.html
881
937
  const idxTpl = fs.readFileSync(path.join(uiSrc, "index.html"), "utf-8");
882
938
  const idxHtml = idxTpl
883
939
  .replace(/{{title}}/g, title)
@@ -920,10 +976,11 @@ class ServeCommand extends SessionCommand_1.default {
920
976
  form.append("file", fs.createReadStream(zipPath));
921
977
  form.append("config", JSON.stringify(config));
922
978
  const rigoRes = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/learnpack/upload`, form, {
923
- headers: Object.assign(Object.assign({}, form.getHeaders()), { Authorization: `Token ${rigoToken}` }),
979
+ headers: Object.assign(Object.assign({}, form.getHeaders()), { Authorization: `Token ${rigoToken.trim()}` }),
924
980
  });
925
- await (0, publish_1.handleAssetCreation)({ token: bcToken, rigobotToken: rigoToken }, fullConfig.config, selectedLang, rigoRes.data.url);
981
+ await createMultiLangAsset(bucket, rigoToken, bcToken, slug, fullConfig.config, rigoRes.data.url);
926
982
  rimraf.sync(tmpRoot);
983
+ console.log("RigoRes", rigoRes.data);
927
984
  return res.json({ url: rigoRes.data.url });
928
985
  });
929
986
  archive.on("error", err => {