@learnpack/learnpack 5.0.355 → 5.0.358
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/lib/commands/publish.js +2 -2
- package/lib/commands/serve.d.ts +0 -17
- package/lib/commands/serve.js +252 -147
- package/lib/creatorDist/assets/{index-DnthLsvb.js → index-D6pmbMe9.js} +14030 -13903
- package/lib/creatorDist/assets/index-zrPponAn.css +1701 -0
- package/lib/creatorDist/index.html +2 -2
- package/lib/models/creator.d.ts +1 -1
- package/lib/services/ingest/adapters/gcsCourseStorage.d.ts +13 -0
- package/lib/services/ingest/adapters/gcsCourseStorage.js +58 -0
- package/lib/services/ingest/adapters/rigoUserTokenAuth.d.ts +15 -0
- package/lib/services/ingest/adapters/rigoUserTokenAuth.js +46 -0
- package/lib/services/ingest/adapters/rigobotPackageRegistry.d.ts +7 -0
- package/lib/services/ingest/adapters/rigobotPackageRegistry.js +119 -0
- package/lib/services/ingest/core/buildIngestConfig.d.ts +27 -0
- package/lib/services/ingest/core/buildIngestConfig.js +40 -0
- package/lib/services/ingest/core/buildInitialSyllabus.d.ts +24 -0
- package/lib/services/ingest/core/buildInitialSyllabus.js +104 -0
- package/lib/services/ingest/core/buildSidebar.d.ts +13 -0
- package/lib/services/ingest/core/buildSidebar.js +28 -0
- package/lib/services/ingest/core/coursePaths.d.ts +31 -0
- package/lib/services/ingest/core/coursePaths.js +50 -0
- package/lib/services/ingest/core/ingestCoursePackage.d.ts +52 -0
- package/lib/services/ingest/core/ingestCoursePackage.js +217 -0
- package/lib/services/ingest/core/normalizeLearnJson.d.ts +25 -0
- package/lib/services/ingest/core/normalizeLearnJson.js +29 -0
- package/lib/services/ingest/core/pairLessons.d.ts +29 -0
- package/lib/services/ingest/core/pairLessons.js +102 -0
- package/lib/services/ingest/core/planWrites.d.ts +44 -0
- package/lib/services/ingest/core/planWrites.js +59 -0
- package/lib/services/ingest/core/resolveSlug.d.ts +53 -0
- package/lib/services/ingest/core/resolveSlug.js +93 -0
- package/lib/services/ingest/core/types.d.ts +53 -0
- package/lib/services/ingest/core/types.js +2 -0
- package/lib/services/ingest/core/validatePackage.d.ts +38 -0
- package/lib/services/ingest/core/validatePackage.js +97 -0
- package/lib/services/ingest/createIngestService.d.ts +34 -0
- package/lib/services/ingest/createIngestService.js +38 -0
- package/lib/services/ingest/errors.d.ts +22 -0
- package/lib/services/ingest/errors.js +34 -0
- package/lib/services/ingest/http/errorMapping.d.ts +8 -0
- package/lib/services/ingest/http/errorMapping.js +40 -0
- package/lib/services/ingest/http/router.d.ts +32 -0
- package/lib/services/ingest/http/router.js +124 -0
- package/lib/services/ingest/http/zipPackageReader.d.ts +26 -0
- package/lib/services/ingest/http/zipPackageReader.js +62 -0
- package/lib/services/ingest/ports/courseStorage.d.ts +25 -0
- package/lib/services/ingest/ports/courseStorage.js +2 -0
- package/lib/services/ingest/ports/packageRegistry.d.ts +58 -0
- package/lib/services/ingest/ports/packageRegistry.js +2 -0
- package/lib/services/ingest/ports/requestAuthenticator.d.ts +25 -0
- package/lib/services/ingest/ports/requestAuthenticator.js +2 -0
- package/lib/ui/static/og-image.png +0 -0
- package/lib/utils/branding.d.ts +43 -0
- package/lib/utils/branding.js +75 -0
- package/lib/utils/coursePackage/bucketIo.d.ts +23 -0
- package/lib/utils/coursePackage/bucketIo.js +36 -0
- package/lib/utils/coursePackage/learnJson.d.ts +26 -0
- package/lib/utils/coursePackage/learnJson.js +36 -0
- package/lib/utils/coursePackage/sidebar.d.ts +15 -0
- package/lib/utils/coursePackage/sidebar.js +26 -0
- package/lib/utils/creatorSocket.js +15 -21
- package/lib/utils/gcpCredentials.d.ts +18 -0
- package/lib/utils/gcpCredentials.js +27 -0
- package/lib/utils/rigoActions.d.ts +16 -0
- package/lib/utils/rigoActions.js +102 -1
- package/lib/utils/socketRegistry.d.ts +46 -0
- package/lib/utils/socketRegistry.js +83 -0
- package/package.json +2 -2
- package/src/commands/publish.ts +2 -3
- package/src/commands/serve.ts +297 -136
- package/src/creator/README.md +63 -51
- package/src/creator/package-lock.json +1188 -8
- package/src/creator/package.json +5 -1
- package/src/creator/src/App.tsx +120 -54
- package/src/creator/src/components/FileUploader.tsx +1 -12
- package/src/creator/src/components/NotificationListener.tsx +1 -8
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +101 -36
- package/src/creator/src/locales/en.json +8 -0
- package/src/creator/src/locales/es.json +8 -0
- package/src/creator/src/utils/completionResult.test.ts +144 -0
- package/src/creator/src/utils/completionResult.ts +154 -0
- package/src/creator/src/utils/constants.ts +17 -4
- package/src/creator/src/utils/socket.test.ts +113 -0
- package/src/creator/src/utils/socket.ts +60 -37
- package/src/creator/src/utils/store.ts +84 -67
- package/src/creator/src/utils/useCompletionWatchdog.test.ts +99 -0
- package/src/creator/src/utils/useCompletionWatchdog.ts +37 -0
- package/src/creator/vitest.config.ts +16 -0
- package/src/creatorDist/assets/{index-DnthLsvb.js → index-D6pmbMe9.js} +14030 -13903
- package/src/creatorDist/assets/index-zrPponAn.css +1701 -0
- package/src/creatorDist/index.html +2 -2
- package/src/models/creator.ts +1 -1
- package/src/services/ingest/adapters/gcsCourseStorage.ts +70 -0
- package/src/services/ingest/adapters/rigoUserTokenAuth.ts +65 -0
- package/src/services/ingest/adapters/rigobotPackageRegistry.ts +161 -0
- package/src/services/ingest/core/buildIngestConfig.ts +51 -0
- package/src/services/ingest/core/buildInitialSyllabus.ts +122 -0
- package/src/services/ingest/core/buildSidebar.ts +32 -0
- package/src/services/ingest/core/coursePaths.ts +59 -0
- package/src/services/ingest/core/ingestCoursePackage.ts +343 -0
- package/src/services/ingest/core/normalizeLearnJson.ts +47 -0
- package/src/services/ingest/core/pairLessons.ts +132 -0
- package/src/services/ingest/core/planWrites.ts +91 -0
- package/src/services/ingest/core/resolveSlug.ts +119 -0
- package/src/services/ingest/core/types.ts +57 -0
- package/src/services/ingest/core/validatePackage.ts +132 -0
- package/src/services/ingest/createIngestService.ts +66 -0
- package/src/services/ingest/errors.ts +45 -0
- package/src/services/ingest/http/errorMapping.ts +49 -0
- package/src/services/ingest/http/router.ts +156 -0
- package/src/services/ingest/http/zipPackageReader.ts +81 -0
- package/src/services/ingest/ports/courseStorage.ts +25 -0
- package/src/services/ingest/ports/packageRegistry.ts +60 -0
- package/src/services/ingest/ports/requestAuthenticator.ts +28 -0
- package/src/ui/_app/app.js +825 -825
- package/src/ui/app.tar.gz +0 -0
- package/src/ui/static/og-image.png +0 -0
- package/src/utils/branding.ts +78 -0
- package/src/utils/coursePackage/bucketIo.ts +46 -0
- package/src/utils/coursePackage/learnJson.ts +37 -0
- package/src/utils/coursePackage/sidebar.ts +28 -0
- package/src/utils/creatorSocket.ts +16 -22
- package/src/utils/gcpCredentials.ts +38 -0
- package/src/utils/rigoActions.ts +163 -0
- package/src/utils/socketRegistry.ts +85 -0
- package/lib/creatorDist/assets/index-CjddKHB_.css +0 -1
- package/src/creatorDist/assets/index-CjddKHB_.css +0 -1
package/lib/utils/rigoActions.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateStepSlug = exports.generateCodeChallenge = exports.addInteractivity = exports.generateStepDescriptions = exports.initialContentGenerator = exports.getLanguageCodes = exports.isPackageAuthor = exports.fillSidebarJSON = exports.generateCourseShortName = exports.isValidRigoToken = exports.translateCourseMetadata = exports.createStructuredPreviewReadme = exports.readmeCreator = exports.createCodingReadme = exports.createCodeFile = exports.interactiveCreation = exports.generateCourseIntroduction = exports.translateExercise = exports.generateImage = exports.hasCreatorPermission = exports.createReadme = void 0;
|
|
3
|
+
exports.generateStepSlug = exports.generateCodeChallenge = exports.addInteractivity = exports.generateStepDescriptions = exports.initialContentGenerator = exports.getLanguageCodes = exports.isPackageAuthor = exports.fillSidebarJSON = exports.generateCourseShortName = exports.isValidRigoToken = exports.translateCourseMetadata = exports.createStructuredPreviewReadme = exports.readmeCreator = exports.createCodingReadme = exports.createCodeFile = exports.interactiveCreation = exports.generateCourseIntroduction = exports.translateExerciseAndWait = exports.getCompletionJob = exports.translateExercise = exports.generateImage = exports.hasCreatorPermission = exports.createReadme = void 0;
|
|
4
4
|
exports.downloadImage = downloadImage;
|
|
5
5
|
exports.createPreviewReadme = createPreviewReadme;
|
|
6
6
|
exports.makeReadmeReadable = makeReadmeReadable;
|
|
@@ -96,6 +96,107 @@ const translateExercise = async (token, inputs, webhookUrl) => {
|
|
|
96
96
|
return response.data;
|
|
97
97
|
};
|
|
98
98
|
exports.translateExercise = translateExercise;
|
|
99
|
+
const POST_RETRY_DELAYS_MS = [1000, 3000, 6000];
|
|
100
|
+
const MAX_CONSECUTIVE_POLL_ERRORS = 5;
|
|
101
|
+
const sleep = (ms) => new Promise(resolve => {
|
|
102
|
+
setTimeout(resolve, ms);
|
|
103
|
+
});
|
|
104
|
+
const isFinalStatus = (status) => status === "SUCCESS" || status === "ERROR";
|
|
105
|
+
// Network failures and 5xx are worth retrying, a 4xx is not going to fix itself.
|
|
106
|
+
const isRetriablePostError = (error) => {
|
|
107
|
+
var _a;
|
|
108
|
+
const status = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status;
|
|
109
|
+
return status === undefined || status >= 500;
|
|
110
|
+
};
|
|
111
|
+
const assertJobSucceeded = (job) => {
|
|
112
|
+
if (job.status === "ERROR") {
|
|
113
|
+
throw new Error(job.status_text || `Rigobot translation job ${job.id} finished with ERROR`);
|
|
114
|
+
}
|
|
115
|
+
return job;
|
|
116
|
+
};
|
|
117
|
+
const getCompletionJob = async (token, completionId) => {
|
|
118
|
+
const response = await axios_1.default.get(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/${completionId}/`, {
|
|
119
|
+
headers: {
|
|
120
|
+
"Content-Type": "application/json",
|
|
121
|
+
Authorization: "Token " + token,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
return response.data;
|
|
125
|
+
};
|
|
126
|
+
exports.getCompletionJob = getCompletionJob;
|
|
127
|
+
// Translates an exercise as an asynchronous Rigobot job and waits for the
|
|
128
|
+
// result by polling.
|
|
129
|
+
//
|
|
130
|
+
// Running the completion synchronously (execute_async: false) keeps the HTTP
|
|
131
|
+
// request open until the LLM is done, which for a full README takes 28-45s and
|
|
132
|
+
// gets killed by Heroku's 30s router limit. Firing the job asynchronously
|
|
133
|
+
// answers in about a second and moves the waiting to the polling loop, so it
|
|
134
|
+
// is no longer bound to the lifetime of a single request.
|
|
135
|
+
const translateExerciseAndWait = async (token, inputs, options = {}) => {
|
|
136
|
+
const { pollIntervalMs = 3000, timeoutMs = 6 * 60 * 1000, onPoll } = options;
|
|
137
|
+
let job;
|
|
138
|
+
for (let attempt = 0; attempt <= POST_RETRY_DELAYS_MS.length; attempt++) {
|
|
139
|
+
try {
|
|
140
|
+
// eslint-disable-next-line no-await-in-loop
|
|
141
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/translate-asset-markdown/`, {
|
|
142
|
+
inputs: inputs,
|
|
143
|
+
include_purpose_objective: false,
|
|
144
|
+
execute_async: true,
|
|
145
|
+
}, {
|
|
146
|
+
headers: {
|
|
147
|
+
"Content-Type": "application/json",
|
|
148
|
+
Authorization: "Token " + token,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
job = response.data;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
if (!isRetriablePostError(error) ||
|
|
156
|
+
attempt === POST_RETRY_DELAYS_MS.length) {
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
// eslint-disable-next-line no-await-in-loop
|
|
160
|
+
await sleep(POST_RETRY_DELAYS_MS[attempt]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (!job) {
|
|
164
|
+
throw new Error("Rigobot did not return a translation job");
|
|
165
|
+
}
|
|
166
|
+
// Rigobot answers straight away with the cached completion when the very
|
|
167
|
+
// same inputs were translated before, so there is nothing to wait for.
|
|
168
|
+
if (isFinalStatus(job.status)) {
|
|
169
|
+
return assertJobSucceeded(job);
|
|
170
|
+
}
|
|
171
|
+
const jobId = job.id;
|
|
172
|
+
const startedAt = Date.now();
|
|
173
|
+
let consecutivePollErrors = 0;
|
|
174
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
175
|
+
// eslint-disable-next-line no-await-in-loop
|
|
176
|
+
await sleep(pollIntervalMs);
|
|
177
|
+
try {
|
|
178
|
+
// eslint-disable-next-line no-await-in-loop
|
|
179
|
+
job = await (0, exports.getCompletionJob)(token, jobId);
|
|
180
|
+
consecutivePollErrors = 0;
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
consecutivePollErrors++;
|
|
184
|
+
if (consecutivePollErrors >= MAX_CONSECUTIVE_POLL_ERRORS) {
|
|
185
|
+
throw new Error(`Could not read the status of the translation job ${jobId} after ${MAX_CONSECUTIVE_POLL_ERRORS} attempts: ${error.message}`);
|
|
186
|
+
}
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (onPoll) {
|
|
190
|
+
// eslint-disable-next-line no-await-in-loop
|
|
191
|
+
await onPoll(job);
|
|
192
|
+
}
|
|
193
|
+
if (isFinalStatus(job.status)) {
|
|
194
|
+
return assertJobSucceeded(job);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
throw new Error(`The translation job ${jobId} did not finish after ${Math.round(timeoutMs / 1000)}s, its last known status was ${job.status}`);
|
|
198
|
+
};
|
|
199
|
+
exports.translateExerciseAndWait = translateExerciseAndWait;
|
|
99
200
|
const generateCourseIntroduction = async (token, inputs) => {
|
|
100
201
|
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/192/`, {
|
|
101
202
|
inputs: inputs,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which sockets are listening on which channel.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `creatorSocket.ts` so the bookkeeping can be tested without
|
|
5
|
+
* standing up a socket.io server. The registry deals in socket ids only; the
|
|
6
|
+
* socket objects themselves stay with the transport layer.
|
|
7
|
+
*
|
|
8
|
+
* The behaviour that matters is `removeSocket`: a disconnecting client has to
|
|
9
|
+
* disappear from **every** channel it joined. The notification map used to be
|
|
10
|
+
* skipped on disconnect, so it grew for the lifetime of the process and
|
|
11
|
+
* accumulated ids of sockets that were long gone.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SocketRegistry {
|
|
14
|
+
private readonly channels;
|
|
15
|
+
/**
|
|
16
|
+
* Adds a socket to a channel.
|
|
17
|
+
* @param channel - Channel key, such as a course slug or a notification id.
|
|
18
|
+
* @param socketId - The socket joining it.
|
|
19
|
+
*/
|
|
20
|
+
register(channel: string, socketId: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Removes a socket from one channel, dropping the channel when it empties.
|
|
23
|
+
* @param channel - Channel to leave.
|
|
24
|
+
* @param socketId - The socket leaving it.
|
|
25
|
+
*/
|
|
26
|
+
unregister(channel: string, socketId: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Removes a socket from every channel it joined.
|
|
29
|
+
*
|
|
30
|
+
* Called when the socket disconnects. Without it the registry keeps growing
|
|
31
|
+
* with ids that can never receive anything again.
|
|
32
|
+
* @param socketId - The socket that went away.
|
|
33
|
+
*/
|
|
34
|
+
removeSocket(socketId: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* The sockets currently listening on a channel.
|
|
37
|
+
* @param channel - Channel to look up.
|
|
38
|
+
* @returns Their socket ids, empty when nobody is listening.
|
|
39
|
+
*/
|
|
40
|
+
listeners(channel: string): string[];
|
|
41
|
+
/**
|
|
42
|
+
* How many channels are being tracked. Exposed for tests and diagnostics.
|
|
43
|
+
* @returns The number of non-empty channels.
|
|
44
|
+
*/
|
|
45
|
+
channelCount(): number;
|
|
46
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SocketRegistry = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Which sockets are listening on which channel.
|
|
6
|
+
*
|
|
7
|
+
* Extracted from `creatorSocket.ts` so the bookkeeping can be tested without
|
|
8
|
+
* standing up a socket.io server. The registry deals in socket ids only; the
|
|
9
|
+
* socket objects themselves stay with the transport layer.
|
|
10
|
+
*
|
|
11
|
+
* The behaviour that matters is `removeSocket`: a disconnecting client has to
|
|
12
|
+
* disappear from **every** channel it joined. The notification map used to be
|
|
13
|
+
* skipped on disconnect, so it grew for the lifetime of the process and
|
|
14
|
+
* accumulated ids of sockets that were long gone.
|
|
15
|
+
*/
|
|
16
|
+
class SocketRegistry {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.channels = new Map();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Adds a socket to a channel.
|
|
22
|
+
* @param channel - Channel key, such as a course slug or a notification id.
|
|
23
|
+
* @param socketId - The socket joining it.
|
|
24
|
+
*/
|
|
25
|
+
register(channel, socketId) {
|
|
26
|
+
if (!channel || !socketId) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let listeners = this.channels.get(channel);
|
|
30
|
+
if (!listeners) {
|
|
31
|
+
listeners = new Set();
|
|
32
|
+
this.channels.set(channel, listeners);
|
|
33
|
+
}
|
|
34
|
+
listeners.add(socketId);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Removes a socket from one channel, dropping the channel when it empties.
|
|
38
|
+
* @param channel - Channel to leave.
|
|
39
|
+
* @param socketId - The socket leaving it.
|
|
40
|
+
*/
|
|
41
|
+
unregister(channel, socketId) {
|
|
42
|
+
const listeners = this.channels.get(channel);
|
|
43
|
+
if (!listeners) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
listeners.delete(socketId);
|
|
47
|
+
if (listeners.size === 0) {
|
|
48
|
+
this.channels.delete(channel);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Removes a socket from every channel it joined.
|
|
53
|
+
*
|
|
54
|
+
* Called when the socket disconnects. Without it the registry keeps growing
|
|
55
|
+
* with ids that can never receive anything again.
|
|
56
|
+
* @param socketId - The socket that went away.
|
|
57
|
+
*/
|
|
58
|
+
removeSocket(socketId) {
|
|
59
|
+
for (const [channel, listeners] of this.channels) {
|
|
60
|
+
listeners.delete(socketId);
|
|
61
|
+
if (listeners.size === 0) {
|
|
62
|
+
this.channels.delete(channel);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The sockets currently listening on a channel.
|
|
68
|
+
* @param channel - Channel to look up.
|
|
69
|
+
* @returns Their socket ids, empty when nobody is listening.
|
|
70
|
+
*/
|
|
71
|
+
listeners(channel) {
|
|
72
|
+
const listeners = this.channels.get(channel);
|
|
73
|
+
return listeners ? [...listeners] : [];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* How many channels are being tracked. Exposed for tests and diagnostics.
|
|
77
|
+
* @returns The number of non-empty channels.
|
|
78
|
+
*/
|
|
79
|
+
channelCount() {
|
|
80
|
+
return this.channels.size;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.SocketRegistry = SocketRegistry;
|
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.358",
|
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
|
6
6
|
"contributors": [
|
|
7
7
|
{
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
"audit:package-sources": "ts-node --project ./tsconfig.json ./scripts/audit-package-sources.ts",
|
|
167
167
|
"backfill:package-manifest": "ts-node --project ./tsconfig.json ./scripts/backfill-package-manifest-s3.ts",
|
|
168
168
|
"repair:legacy-packages": "ts-node --project ./tsconfig.json ./scripts/repair-legacy-packages.ts",
|
|
169
|
-
"copy-assets": "npx cpy src/creatorDist/**/* lib/creatorDist --parents --verbose && npx cpy src/utils/templates/**/* lib/utils/templates --parents --verbose && npx cpy src/lua/**/* lib/lua --parents --verbose",
|
|
169
|
+
"copy-assets": "npx cpy src/creatorDist/**/* lib/creatorDist --parents --verbose && npx cpy src/utils/templates/**/* lib/utils/templates --parents --verbose && npx cpy src/lua/**/* lib/lua --parents --verbose && npx cpy src/ui/static/**/* lib/ui/static --parents --verbose",
|
|
170
170
|
"tsc": "tsc -b",
|
|
171
171
|
"postpack": "rm -f oclif.manifest.json && eslint . --ext .ts --config .eslintrc",
|
|
172
172
|
"prepack": "rm -rf lib && tsc -b && npm run copy-assets",
|
package/src/commands/publish.ts
CHANGED
|
@@ -20,6 +20,7 @@ import * as prompts from "prompts"
|
|
|
20
20
|
import { isValidRigoToken } from "../utils/rigoActions"
|
|
21
21
|
import { minutesToISO8601Duration } from "../utils/misc"
|
|
22
22
|
import { getReadmeExtension, slugify } from "../utils/creatorUtilities"
|
|
23
|
+
import { getFallbackPreviewUrl } from "../utils/branding"
|
|
23
24
|
|
|
24
25
|
const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload"
|
|
25
26
|
|
|
@@ -588,9 +589,7 @@ class BuildCommand extends SessionCommand {
|
|
|
588
589
|
getLocalizedValue(learnJson?.title, selectedLang) ||
|
|
589
590
|
"LearnPack: Interactive Learning as a Service"
|
|
590
591
|
|
|
591
|
-
const previewUrl =
|
|
592
|
-
learnJson.preview ||
|
|
593
|
-
"https://raw.githubusercontent.com/learnpack/ide/refs/heads/master/public/learnpack.svg"
|
|
592
|
+
const previewUrl = learnJson.preview || getFallbackPreviewUrl()
|
|
594
593
|
// Replace placeholders and the <title>Old title </title> tag for a new tag with the title
|
|
595
594
|
indexHtmlContent = indexHtmlContent
|
|
596
595
|
.replace(/{{description}}/g, description)
|