@digimakers/core 0.1.4
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/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -0
- package/dist/parsing/docx-parser.d.ts +7 -0
- package/dist/parsing/docx-parser.d.ts.map +1 -0
- package/dist/parsing/docx-parser.js +75 -0
- package/dist/parsing/docx-parser.js.map +1 -0
- package/dist/parsing/file-discovery.d.ts +9 -0
- package/dist/parsing/file-discovery.d.ts.map +1 -0
- package/dist/parsing/file-discovery.js +35 -0
- package/dist/parsing/file-discovery.js.map +1 -0
- package/dist/parsing/index.d.ts +5 -0
- package/dist/parsing/index.d.ts.map +1 -0
- package/dist/parsing/index.js +3 -0
- package/dist/parsing/index.js.map +1 -0
- package/dist/pdf-generator.d.ts +13 -0
- package/dist/pdf-generator.d.ts.map +1 -0
- package/dist/pdf-generator.js +110 -0
- package/dist/pdf-generator.js.map +1 -0
- package/dist/sample-data.d.ts +3 -0
- package/dist/sample-data.d.ts.map +1 -0
- package/dist/sample-data.js +51 -0
- package/dist/sample-data.js.map +1 -0
- package/dist/schemas/generation.d.ts +8 -0
- package/dist/schemas/generation.d.ts.map +1 -0
- package/dist/schemas/generation.js +6 -0
- package/dist/schemas/generation.js.map +1 -0
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +3 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/lesson.d.ts +70 -0
- package/dist/schemas/lesson.d.ts.map +1 -0
- package/dist/schemas/lesson.js +77 -0
- package/dist/schemas/lesson.js.map +1 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +89 -0
- package/dist/server.js.map +1 -0
- package/package.json +58 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { StepWithImageSchema, StepsWithCodeBlockSchema, ChallengeSchema, NewProjectSchema, ParsedLessonSchema, GenerateOptionsSchema, type StepWithImage, type StepsWithCodeBlock, type Challenge, type NewProject, type ParsedLesson, type GenerateOptions, } from './schemas/index.js';
|
|
2
|
+
export { createPdfGenerator } from './pdf-generator.js';
|
|
3
|
+
export type { PdfGeneratorInstance } from './pdf-generator.js';
|
|
4
|
+
export { startServer, stopServer } from './server.js';
|
|
5
|
+
export type { ServerInstance } from './server.js';
|
|
6
|
+
export { logger } from './logger.js';
|
|
7
|
+
export { findDocxFiles, parseDocx } from './parsing/index.js';
|
|
8
|
+
export type { DiscoveryOptions, DiscoveredFile, ParseResult } from './parsing/index.js';
|
|
9
|
+
export { sampleLessonData } from './sample-data.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EAErB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG/D,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Public API for @digimakers/core
|
|
2
|
+
// Schemas and types (single source of truth)
|
|
3
|
+
export {
|
|
4
|
+
// Schemas
|
|
5
|
+
StepWithImageSchema, StepsWithCodeBlockSchema, ChallengeSchema, NewProjectSchema, ParsedLessonSchema, GenerateOptionsSchema, } from './schemas/index.js';
|
|
6
|
+
// PDF generation
|
|
7
|
+
export { createPdfGenerator } from './pdf-generator.js';
|
|
8
|
+
// Server
|
|
9
|
+
export { startServer, stopServer } from './server.js';
|
|
10
|
+
// Logger
|
|
11
|
+
export { logger } from './logger.js';
|
|
12
|
+
// Parsing
|
|
13
|
+
export { findDocxFiles, parseDocx } from './parsing/index.js';
|
|
14
|
+
// Sample data (for testing)
|
|
15
|
+
export { sampleLessonData } from './sample-data.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAElC,6CAA6C;AAC7C,OAAO;AACL,UAAU;AACV,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,GAQtB,MAAM,oBAAoB,CAAC;AAE5B,iBAAiB;AACjB,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGxD,SAAS;AACT,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGtD,SAAS;AACT,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,UAAU;AACV,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG9D,4BAA4B;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,eAAO,MAAM,MAAM,6BAYjB,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
export const logger = pino({
|
|
3
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
4
|
+
transport: {
|
|
5
|
+
target: 'pino-pretty',
|
|
6
|
+
options: {
|
|
7
|
+
colorize: true,
|
|
8
|
+
translateTime: 'HH:MM:ss',
|
|
9
|
+
ignore: 'pid,hostname',
|
|
10
|
+
singleLine: false,
|
|
11
|
+
messageFormat: '{msg}',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;IACtC,SAAS,EAAE;QACT,MAAM,EAAE,aAAa;QACrB,OAAO,EAAE;YACP,QAAQ,EAAE,IAAI;YACd,aAAa,EAAE,UAAU;YACzB,MAAM,EAAE,cAAc;YACtB,UAAU,EAAE,KAAK;YACjB,aAAa,EAAE,OAAO;SACvB;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docx-parser.d.ts","sourceRoot":"","sources":["../../src/parsing/docx-parser.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsB,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGvE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AA4BD,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA4DtE"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import mammoth from 'mammoth';
|
|
3
|
+
import { generateText, Output } from 'ai';
|
|
4
|
+
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
5
|
+
import { ParsedLessonSchema } from '../schemas/index.js';
|
|
6
|
+
import { logger } from '../logger.js';
|
|
7
|
+
// Setup google generative ai
|
|
8
|
+
const google = createGoogleGenerativeAI({
|
|
9
|
+
apiKey: process.env.GEMINI_API_KEY,
|
|
10
|
+
});
|
|
11
|
+
// Extract images from docx as base64 data URIs
|
|
12
|
+
async function extractImages(buffer) {
|
|
13
|
+
const images = [];
|
|
14
|
+
await mammoth.convertToHtml({ buffer }, {
|
|
15
|
+
convertImage: mammoth.images.imgElement(async (image) => {
|
|
16
|
+
const imageBuffer = await image.read();
|
|
17
|
+
const base64 = imageBuffer.toString('base64');
|
|
18
|
+
const dataUri = `data:${image.contentType};base64,${base64}`;
|
|
19
|
+
images.push(dataUri);
|
|
20
|
+
return { src: dataUri };
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
return images;
|
|
24
|
+
}
|
|
25
|
+
// Parse a .docx file and extract lesson data
|
|
26
|
+
export async function parseDocx(filePath) {
|
|
27
|
+
logger.info(`Parsing: ${filePath}`);
|
|
28
|
+
const buffer = await fs.readFile(filePath);
|
|
29
|
+
// Extract text and images in parallel
|
|
30
|
+
const [{ value: text }, allImages] = await Promise.all([
|
|
31
|
+
mammoth.extractRawText({ buffer }),
|
|
32
|
+
extractImages(buffer),
|
|
33
|
+
]);
|
|
34
|
+
logger.info(text);
|
|
35
|
+
logger.info(allImages);
|
|
36
|
+
logger.debug(`Extracted ${text.length} characters and ${allImages.length} images`);
|
|
37
|
+
// First image is project cover, rest are for code steps
|
|
38
|
+
const projectImage = allImages.length > 0 ? allImages[0] : null;
|
|
39
|
+
const stepImages = allImages.slice(1);
|
|
40
|
+
logger.info(`Found ${stepImages.length} step images, projectImage: ${projectImage ? 'yes' : 'no'}`);
|
|
41
|
+
// Use LLM to extract structured data
|
|
42
|
+
const { output } = await generateText({
|
|
43
|
+
model: google('gemini-2.0-flash'),
|
|
44
|
+
output: Output.object({
|
|
45
|
+
schema: ParsedLessonSchema,
|
|
46
|
+
}),
|
|
47
|
+
prompt: `Extract structured lesson data from this educational document.
|
|
48
|
+
|
|
49
|
+
This is a programming lesson sheet for students. Extract all the relevant sections and content.
|
|
50
|
+
|
|
51
|
+
If a section is not present in the document, use empty arrays for array fields, empty strings for required string fields, and null for nullable fields.
|
|
52
|
+
|
|
53
|
+
For the addYourCodeSection, each step should be a clear instruction. Set image to null for all steps (images will be added separately).
|
|
54
|
+
|
|
55
|
+
Document content:
|
|
56
|
+
${text}`,
|
|
57
|
+
});
|
|
58
|
+
logger.info(output);
|
|
59
|
+
logger.info(`Successfully extracted lesson: ${output.topic} - ${output.project}`);
|
|
60
|
+
// Post-process: assign images to the extracted data
|
|
61
|
+
const data = output;
|
|
62
|
+
data.projectImage = projectImage;
|
|
63
|
+
// Assign step images in order
|
|
64
|
+
if (stepImages.length > 0 && Array.isArray(data.addYourCodeSection)) {
|
|
65
|
+
data.addYourCodeSection.forEach((step, index) => {
|
|
66
|
+
step.image = stepImages[index] ?? null;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
logger.info(data);
|
|
70
|
+
return {
|
|
71
|
+
data,
|
|
72
|
+
sourcePath: filePath,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=docx-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docx-parser.js","sourceRoot":"","sources":["../../src/parsing/docx-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface DiscoveryOptions {
|
|
2
|
+
recursive?: boolean;
|
|
3
|
+
}
|
|
4
|
+
export interface DiscoveredFile {
|
|
5
|
+
path: string;
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function findDocxFiles(target: string, options?: DiscoveryOptions): Promise<DiscoveredFile[]>;
|
|
9
|
+
//# sourceMappingURL=file-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-discovery.d.ts","sourceRoot":"","sources":["../../src/parsing/file-discovery.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,cAAc,EAAE,CAAC,CAkB3B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { logger } from '../logger.js';
|
|
4
|
+
export async function findDocxFiles(target, options = {}) {
|
|
5
|
+
const { recursive = false } = options;
|
|
6
|
+
const resolvedPath = path.resolve(target);
|
|
7
|
+
const stat = await fs.stat(resolvedPath);
|
|
8
|
+
if (stat.isFile()) {
|
|
9
|
+
if (!resolvedPath.endsWith('.docx')) {
|
|
10
|
+
throw new Error(`File is not a .docx: ${resolvedPath}`);
|
|
11
|
+
}
|
|
12
|
+
return [{ path: resolvedPath, name: path.basename(resolvedPath, '.docx') }];
|
|
13
|
+
}
|
|
14
|
+
if (stat.isDirectory()) {
|
|
15
|
+
return scanDirectory(resolvedPath, recursive);
|
|
16
|
+
}
|
|
17
|
+
throw new Error(`Invalid path: ${resolvedPath}`);
|
|
18
|
+
}
|
|
19
|
+
async function scanDirectory(dir, recursive) {
|
|
20
|
+
const files = [];
|
|
21
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
const fullPath = path.join(dir, entry.name);
|
|
24
|
+
if (entry.isFile() && entry.name.endsWith('.docx')) {
|
|
25
|
+
files.push({ path: fullPath, name: path.basename(entry.name, '.docx') });
|
|
26
|
+
}
|
|
27
|
+
else if (entry.isDirectory() && recursive) {
|
|
28
|
+
const nested = await scanDirectory(fullPath, recursive);
|
|
29
|
+
files.push(...nested);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
logger.info(`Found ${files.length} .docx file(s) in ${dir}`);
|
|
33
|
+
return files;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=file-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-discovery.js","sourceRoot":"","sources":["../../src/parsing/file-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAWtC,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,UAA4B,EAAE;IAE9B,MAAM,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IACtC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAEzC,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACvB,OAAO,aAAa,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,iBAAiB,YAAY,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,SAAkB;IAC1D,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAE5C,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACnD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;aAAM,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,SAAS,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAC7D,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { findDocxFiles } from './file-discovery.js';
|
|
2
|
+
export type { DiscoveryOptions, DiscoveredFile } from './file-discovery.js';
|
|
3
|
+
export { parseDocx } from './docx-parser.js';
|
|
4
|
+
export type { ParseResult } from './docx-parser.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parsing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Browser } from 'puppeteer';
|
|
2
|
+
import { ParsedLesson, GenerateOptions } from './schemas/index.js';
|
|
3
|
+
export interface PdfGeneratorInstance {
|
|
4
|
+
browser: Browser;
|
|
5
|
+
generatePdf: (data: ParsedLesson, options?: GenerateOptions) => Promise<string>;
|
|
6
|
+
generateBatch: (items: {
|
|
7
|
+
data: ParsedLesson;
|
|
8
|
+
options: GenerateOptions;
|
|
9
|
+
}[]) => Promise<string[]>;
|
|
10
|
+
close: () => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare function createPdfGenerator(serverUrl: string): Promise<PdfGeneratorInstance>;
|
|
13
|
+
//# sourceMappingURL=pdf-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-generator.d.ts","sourceRoot":"","sources":["../src/pdf-generator.ts"],"names":[],"mappings":"AAAA,OAAkB,EAAE,OAAO,EAAQ,MAAM,WAAW,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGnE,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChF,aAAa,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAChG,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAWD,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAkIzF"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import puppeteer from 'puppeteer';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import { logger } from './logger.js';
|
|
5
|
+
const POOL_SIZE = 4;
|
|
6
|
+
const RENDER_DELAY = 100;
|
|
7
|
+
const PAGE_WAIT_MS = 30_000;
|
|
8
|
+
export async function createPdfGenerator(serverUrl) {
|
|
9
|
+
logger.info('[PDF] Launching browser...');
|
|
10
|
+
const browser = await puppeteer.launch({
|
|
11
|
+
headless: true,
|
|
12
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
|
|
13
|
+
});
|
|
14
|
+
const pool = [];
|
|
15
|
+
async function initPage() {
|
|
16
|
+
const page = await browser.newPage();
|
|
17
|
+
await page.setViewport({ width: 794, height: 1123, deviceScaleFactor: 2 });
|
|
18
|
+
const printUrl = serverUrl.endsWith('/') ? `${serverUrl}print` : `${serverUrl}/print`;
|
|
19
|
+
await page.goto(printUrl, { waitUntil: 'networkidle0' });
|
|
20
|
+
return page;
|
|
21
|
+
}
|
|
22
|
+
async function getAvailablePage() {
|
|
23
|
+
let pooledPage = pool.find((p) => !p.busy);
|
|
24
|
+
if (!pooledPage && pool.length < POOL_SIZE) {
|
|
25
|
+
const page = await initPage();
|
|
26
|
+
pooledPage = { page, busy: false };
|
|
27
|
+
pool.push(pooledPage);
|
|
28
|
+
}
|
|
29
|
+
if (!pooledPage) {
|
|
30
|
+
await new Promise((resolve) => {
|
|
31
|
+
const check = () => {
|
|
32
|
+
pooledPage = pool.find((p) => !p.busy);
|
|
33
|
+
if (pooledPage)
|
|
34
|
+
resolve();
|
|
35
|
+
else
|
|
36
|
+
setTimeout(check, 10);
|
|
37
|
+
};
|
|
38
|
+
check();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
pooledPage.busy = true;
|
|
42
|
+
return pooledPage;
|
|
43
|
+
}
|
|
44
|
+
async function generateOnPage(page, data, options) {
|
|
45
|
+
const { outputDir = './output', filename = 'output' } = options;
|
|
46
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
47
|
+
// Clear previous data
|
|
48
|
+
await page.evaluate(() => {
|
|
49
|
+
window['PDF_DATA'] = null;
|
|
50
|
+
});
|
|
51
|
+
// Small delay to ensure Angular detects the null value
|
|
52
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
53
|
+
// Set new data
|
|
54
|
+
await page.evaluate((lessonData) => {
|
|
55
|
+
window['PDF_DATA'] = lessonData;
|
|
56
|
+
}, data);
|
|
57
|
+
// Wait for Paged.js to fully complete pagination
|
|
58
|
+
// The LessonPreviewComponent sets window.PAGED_READY = true when done
|
|
59
|
+
await page.waitForFunction(() => window['PAGED_READY'] === true, {
|
|
60
|
+
timeout: PAGE_WAIT_MS,
|
|
61
|
+
polling: 100,
|
|
62
|
+
});
|
|
63
|
+
// Wait for all images to be fully loaded
|
|
64
|
+
await page.waitForFunction(() => {
|
|
65
|
+
const images = Array.from(document.querySelectorAll('img'));
|
|
66
|
+
return images.every((img) => img.complete && img.naturalHeight > 0);
|
|
67
|
+
}, { timeout: PAGE_WAIT_MS, polling: 100 });
|
|
68
|
+
// Small delay for any final paint operations
|
|
69
|
+
await new Promise((resolve) => setTimeout(resolve, RENDER_DELAY));
|
|
70
|
+
const pdfPath = path.join(outputDir, `${filename}.pdf`);
|
|
71
|
+
await page.pdf({
|
|
72
|
+
path: pdfPath,
|
|
73
|
+
printBackground: true,
|
|
74
|
+
width: '210mm', // A4 width
|
|
75
|
+
height: '297mm', // A4 height
|
|
76
|
+
});
|
|
77
|
+
return pdfPath;
|
|
78
|
+
}
|
|
79
|
+
async function generatePdf(data, options = {}) {
|
|
80
|
+
const pooledPage = await getAvailablePage();
|
|
81
|
+
try {
|
|
82
|
+
const result = await generateOnPage(pooledPage.page, data, options);
|
|
83
|
+
logger.info(`[PDF] Saved: ${result}`);
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
pooledPage.busy = false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function generateBatch(items) {
|
|
91
|
+
logger.info(`[PDF] Processing ${items.length} files with ${POOL_SIZE} parallel workers...`);
|
|
92
|
+
const results = [];
|
|
93
|
+
const promises = items.map(async (item, index) => {
|
|
94
|
+
const result = await generatePdf(item.data, item.options);
|
|
95
|
+
results[index] = result;
|
|
96
|
+
});
|
|
97
|
+
await Promise.all(promises);
|
|
98
|
+
return results;
|
|
99
|
+
}
|
|
100
|
+
async function close() {
|
|
101
|
+
for (const pooledPage of pool) {
|
|
102
|
+
await pooledPage.page.close();
|
|
103
|
+
}
|
|
104
|
+
await browser.close();
|
|
105
|
+
logger.info('[PDF] Browser closed');
|
|
106
|
+
}
|
|
107
|
+
logger.info('[PDF] Browser launched');
|
|
108
|
+
return { browser, generatePdf, generateBatch, close };
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=pdf-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-generator.js","sourceRoot":"","sources":["../src/pdf-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-data.d.ts","sourceRoot":"","sources":["../src/sample-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,eAAO,MAAM,gBAAgB,EAAE,YAoD9B,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const sampleLessonData = {
|
|
2
|
+
topic: 'Decisions',
|
|
3
|
+
project: 'Crossy Road',
|
|
4
|
+
description: 'Decision making is important when there will be situations with multiple options and an option needs to be selected based on the given conditions.',
|
|
5
|
+
projectExplainer: 'In this lesson, we will create a Crossy Road style game where a penguin needs to cross the road and get to the other side without being hit by cars.',
|
|
6
|
+
projectImage: null,
|
|
7
|
+
getReadySection: ['Add Backdrop "street"', 'Add Sprites: Car and Penguin (set sizes to 40)'],
|
|
8
|
+
addYourCodeSection: [
|
|
9
|
+
{
|
|
10
|
+
step: 'Car: When green flag is clicked, set Rotation style left-right, size 40%. Forever, move 5 steps, if on edge, bounce.',
|
|
11
|
+
image: null,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
step: 'Penguin: When green flag is clicked, Forever: if UP arrow key is pressed, change y by 10.',
|
|
15
|
+
image: null,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
step: 'Penguin: Inside Forever; If DOWN arrow key is pressed, change y by -10.',
|
|
19
|
+
image: null,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
step: 'Penguin: Inside Forever; If RIGHT arrow key is pressed, change x by 10.',
|
|
23
|
+
image: null,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
step: 'Penguin: Inside Forever; If LEFT arrow key is pressed, change x by -10.',
|
|
27
|
+
image: null,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
step: 'Penguin: Inside Forever; If Penguin touches the car, say "Ouch!" and go back to its start position.',
|
|
31
|
+
image: null,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
tryItOutSection: [
|
|
35
|
+
'Click the green flag and test your game',
|
|
36
|
+
'Make sure the penguin can move in all directions',
|
|
37
|
+
'Check if the car bounces at the edges',
|
|
38
|
+
],
|
|
39
|
+
challengeSection: [
|
|
40
|
+
{ name: 'Bruise Penguin', task: 'Add sound effects when the penguin gets hit' },
|
|
41
|
+
{ name: 'Add more cars', task: 'Add more cars moving at different speeds' },
|
|
42
|
+
{ name: 'Multiple Levels', task: 'Create multiple levels with increasing difficulty' },
|
|
43
|
+
],
|
|
44
|
+
newProject: {
|
|
45
|
+
name: 'Energy Boost',
|
|
46
|
+
task: 'Try creating a similar game with different sprites and backgrounds',
|
|
47
|
+
},
|
|
48
|
+
testYourself: 'http://youtube.com',
|
|
49
|
+
funFact: 'The original Crossy Road game was inspired by the classic arcade game Frogger from 1981!',
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=sample-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-data.js","sourceRoot":"","sources":["../src/sample-data.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAiB;IAC5C,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,aAAa;IACtB,WAAW,EACT,oJAAoJ;IACtJ,gBAAgB,EACd,sJAAsJ;IACxJ,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,CAAC,uBAAuB,EAAE,gDAAgD,CAAC;IAC5F,kBAAkB,EAAE;QAClB;YACE,IAAI,EAAE,sHAAsH;YAC5H,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,2FAA2F;YACjG,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,yEAAyE;YAC/E,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,yEAAyE;YAC/E,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,yEAAyE;YAC/E,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,qGAAqG;YAC3G,KAAK,EAAE,IAAI;SACZ;KACF;IACD,eAAe,EAAE;QACf,yCAAyC;QACzC,kDAAkD;QAClD,uCAAuC;KACxC;IACD,gBAAgB,EAAE;QAChB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,6CAA6C,EAAE;QAC/E,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,0CAA0C,EAAE;QAC3E,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,mDAAmD,EAAE;KACvF;IACD,UAAU,EAAE;QACV,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,oEAAoE;KAC3E;IACD,YAAY,EAAE,oBAAoB;IAClC,OAAO,EACL,0FAA0F;CAC7F,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const GenerateOptionsSchema: z.ZodObject<{
|
|
3
|
+
outputDir: z.ZodOptional<z.ZodString>;
|
|
4
|
+
filename: z.ZodOptional<z.ZodString>;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export interface GenerateOptions extends z.infer<typeof GenerateOptionsSchema> {
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=generation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../src/schemas/generation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qBAAqB;;;iBAGhC,CAAC;AAEH,MAAM,WAAW,eAAgB,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation.js","sourceRoot":"","sources":["../../src/schemas/generation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { StepWithImageSchema, StepsWithCodeBlockSchema, ChallengeSchema, NewProjectSchema, ParsedLessonSchema, type StepWithImage, type StepsWithCodeBlock, type Challenge, type NewProject, type ParsedLesson, } from './lesson.js';
|
|
2
|
+
export { GenerateOptionsSchema, type GenerateOptions } from './generation.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GAMnB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,qBAAqB,EAAwB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const StepWithImageSchema: z.ZodObject<{
|
|
3
|
+
step: z.ZodString;
|
|
4
|
+
image: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export declare const StepsWithCodeBlockSchema: z.ZodObject<{
|
|
7
|
+
codeBlock: z.ZodString;
|
|
8
|
+
codeBlockLanguage: z.ZodDefault<z.ZodEnum<{
|
|
9
|
+
none: "none";
|
|
10
|
+
"small-basic": "small-basic";
|
|
11
|
+
"javascript or html or css": "javascript or html or css";
|
|
12
|
+
python: "python";
|
|
13
|
+
java: "java";
|
|
14
|
+
c: "c";
|
|
15
|
+
}>>;
|
|
16
|
+
steps: z.ZodArray<z.ZodString>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
export declare const ChallengeSchema: z.ZodObject<{
|
|
19
|
+
name: z.ZodString;
|
|
20
|
+
task: z.ZodString;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
export declare const NewProjectSchema: z.ZodObject<{
|
|
23
|
+
name: z.ZodString;
|
|
24
|
+
task: z.ZodString;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
export declare const ParsedLessonSchema: z.ZodObject<{
|
|
27
|
+
topic: z.ZodString;
|
|
28
|
+
project: z.ZodString;
|
|
29
|
+
description: z.ZodString;
|
|
30
|
+
projectExplainer: z.ZodString;
|
|
31
|
+
projectImage: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
32
|
+
getReadySection: z.ZodArray<z.ZodString>;
|
|
33
|
+
addYourCodeSection: z.ZodUnion<readonly [z.ZodArray<z.ZodObject<{
|
|
34
|
+
step: z.ZodString;
|
|
35
|
+
image: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
36
|
+
}, z.core.$strip>>, z.ZodObject<{
|
|
37
|
+
codeBlock: z.ZodString;
|
|
38
|
+
codeBlockLanguage: z.ZodDefault<z.ZodEnum<{
|
|
39
|
+
none: "none";
|
|
40
|
+
"small-basic": "small-basic";
|
|
41
|
+
"javascript or html or css": "javascript or html or css";
|
|
42
|
+
python: "python";
|
|
43
|
+
java: "java";
|
|
44
|
+
c: "c";
|
|
45
|
+
}>>;
|
|
46
|
+
steps: z.ZodArray<z.ZodString>;
|
|
47
|
+
}, z.core.$strip>]>;
|
|
48
|
+
tryItOutSection: z.ZodDefault<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
49
|
+
challengeSection: z.ZodArray<z.ZodObject<{
|
|
50
|
+
name: z.ZodString;
|
|
51
|
+
task: z.ZodString;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
newProject: z.ZodObject<{
|
|
54
|
+
name: z.ZodString;
|
|
55
|
+
task: z.ZodString;
|
|
56
|
+
}, z.core.$strip>;
|
|
57
|
+
testYourself: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
58
|
+
funFact: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
59
|
+
}, z.core.$strip>;
|
|
60
|
+
export interface StepWithImage extends z.infer<typeof StepWithImageSchema> {
|
|
61
|
+
}
|
|
62
|
+
export interface StepsWithCodeBlock extends z.infer<typeof StepsWithCodeBlockSchema> {
|
|
63
|
+
}
|
|
64
|
+
export interface Challenge extends z.infer<typeof ChallengeSchema> {
|
|
65
|
+
}
|
|
66
|
+
export interface NewProject extends z.infer<typeof NewProjectSchema> {
|
|
67
|
+
}
|
|
68
|
+
export interface ParsedLesson extends z.infer<typeof ParsedLessonSchema> {
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=lesson.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lesson.d.ts","sourceRoot":"","sources":["../../src/schemas/lesson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,mBAAmB;;;iBAG9B,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;;iBAanC,CAAC;AAEH,eAAO,MAAM,eAAe;;;iBAO1B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;iBAS3B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4C7B,CAAC;AAGH,MAAM,WAAW,aAAc,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC;CAAG;AAC7E,MAAM,WAAW,kBAAmB,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC;CAAG;AACvF,MAAM,WAAW,SAAU,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC;CAAG;AACrE,MAAM,WAAW,UAAW,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC;CAAG;AACvE,MAAM,WAAW,YAAa,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC;CAAG"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const StepWithImageSchema = z.object({
|
|
3
|
+
step: z.string().describe('The instruction text for this step'),
|
|
4
|
+
image: z.string().nullable().default(null).describe('Image reference if present, otherwise null'),
|
|
5
|
+
});
|
|
6
|
+
export const StepsWithCodeBlockSchema = z.object({
|
|
7
|
+
codeBlock: z.string().describe('The code block that students have to write to get started'),
|
|
8
|
+
codeBlockLanguage: z
|
|
9
|
+
.enum(['none', 'small-basic', 'javascript or html or css', 'python', 'java', 'c'])
|
|
10
|
+
.default('small-basic')
|
|
11
|
+
.describe('The programming language used in the code block. Detect from syntax, "none" if unsure'),
|
|
12
|
+
steps: z
|
|
13
|
+
.array(z.string())
|
|
14
|
+
.describe('The steps listed above the code block but below the "Add your code header", says "Main Program"'),
|
|
15
|
+
});
|
|
16
|
+
export const ChallengeSchema = z.object({
|
|
17
|
+
name: z
|
|
18
|
+
.string()
|
|
19
|
+
.describe('The name of the specific challenge, excluding the "- New Project" text'),
|
|
20
|
+
task: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe('The task for the challenge, explained as a requirement or feature to add'),
|
|
23
|
+
});
|
|
24
|
+
export const NewProjectSchema = z.object({
|
|
25
|
+
name: z
|
|
26
|
+
.string()
|
|
27
|
+
.describe('The name of the new project, usually shown in the header title next to "New Project"'),
|
|
28
|
+
task: z
|
|
29
|
+
.string()
|
|
30
|
+
.describe('The task for the new project, explained as a requirement or new feature to add'),
|
|
31
|
+
});
|
|
32
|
+
export const ParsedLessonSchema = z.object({
|
|
33
|
+
topic: z
|
|
34
|
+
.string()
|
|
35
|
+
.describe('The main topic/category of the lesson (e.g., "Decisions", "Loops", "Variables")'),
|
|
36
|
+
project: z
|
|
37
|
+
.string()
|
|
38
|
+
.describe('The name of the project being built (e.g., "Crossy Road", "Space Invaders")'),
|
|
39
|
+
description: z
|
|
40
|
+
.string()
|
|
41
|
+
.describe('A brief description explaining the programming concept being taught'),
|
|
42
|
+
projectExplainer: z.string().describe('Explanation of what will be built in this lesson'),
|
|
43
|
+
projectImage: z
|
|
44
|
+
.string()
|
|
45
|
+
.nullable()
|
|
46
|
+
.default(null)
|
|
47
|
+
.describe('Reference to the main project image if present'),
|
|
48
|
+
getReadySection: z
|
|
49
|
+
.array(z.string())
|
|
50
|
+
.describe('List of setup steps to prepare for the project (adding sprites, backdrops, etc.)'),
|
|
51
|
+
addYourCodeSection: z.union([
|
|
52
|
+
z
|
|
53
|
+
.array(StepWithImageSchema)
|
|
54
|
+
.describe('Step-by-step coding instructions, each step may have an associated image'),
|
|
55
|
+
StepsWithCodeBlockSchema.describe('A block of code given with steps on what it does'),
|
|
56
|
+
]),
|
|
57
|
+
tryItOutSection: z
|
|
58
|
+
.array(z.string())
|
|
59
|
+
.nullable()
|
|
60
|
+
.default(null)
|
|
61
|
+
.describe('Steps to test the project after coding'),
|
|
62
|
+
challengeSection: z
|
|
63
|
+
.array(ChallengeSchema)
|
|
64
|
+
.describe('Challenge tasks for students to extend the project'),
|
|
65
|
+
newProject: NewProjectSchema.describe('Suggestion for a new project or extension activity'),
|
|
66
|
+
testYourself: z
|
|
67
|
+
.string()
|
|
68
|
+
.nullable()
|
|
69
|
+
.default(null)
|
|
70
|
+
.describe('A link to the quiz, found under the "Test Yourself" header'),
|
|
71
|
+
funFact: z
|
|
72
|
+
.string()
|
|
73
|
+
.nullable()
|
|
74
|
+
.default(null)
|
|
75
|
+
.describe('An interesting fact related to the lesson topic'),
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=lesson.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lesson.js","sourceRoot":"","sources":["../../src/schemas/lesson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;IAC/D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;CAClG,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;IAC3F,iBAAiB,EAAE,CAAC;SACjB,IAAI,CAAC,CAAC,MAAM,EAAE,aAAa,EAAE,2BAA2B,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;SACjF,OAAO,CAAC,aAAa,CAAC;SACtB,QAAQ,CACP,uFAAuF,CACxF;IACH,KAAK,EAAE,CAAC;SACL,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,CACP,iGAAiG,CAClG;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,CAAC,wEAAwE,CAAC;IACrF,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,CAAC,0EAA0E,CAAC;CACxF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,CACP,sFAAsF,CACvF;IACH,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,CAAC,gFAAgF,CAAC;CAC9F,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,CAAC,iFAAiF,CAAC;IAC9F,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,CAAC,6EAA6E,CAAC;IAC1F,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,QAAQ,CAAC,qEAAqE,CAAC;IAClF,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;IACzF,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,gDAAgD,CAAC;IAC7D,eAAe,EAAE,CAAC;SACf,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,CAAC,kFAAkF,CAAC;IAC/F,kBAAkB,EAAE,CAAC,CAAC,KAAK,CAAC;QAC1B,CAAC;aACE,KAAK,CAAC,mBAAmB,CAAC;aAC1B,QAAQ,CAAC,0EAA0E,CAAC;QACvF,wBAAwB,CAAC,QAAQ,CAAC,kDAAkD,CAAC;KACtF,CAAC;IACF,eAAe,EAAE,CAAC;SACf,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,wCAAwC,CAAC;IACrD,gBAAgB,EAAE,CAAC;SAChB,KAAK,CAAC,eAAe,CAAC;SACtB,QAAQ,CAAC,oDAAoD,CAAC;IACjE,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CAAC,oDAAoD,CAAC;IAC3F,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,4DAA4D,CAAC;IACzE,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,iDAAiD,CAAC;CAC/D,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Express } from 'express';
|
|
2
|
+
import { Server } from 'http';
|
|
3
|
+
export interface ServerInstance {
|
|
4
|
+
app: Express;
|
|
5
|
+
server: Server;
|
|
6
|
+
port: number;
|
|
7
|
+
url: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function startServer(): Promise<ServerInstance>;
|
|
10
|
+
export declare function stopServer(instance: ServerInstance): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AA4D9B,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,cAAc,CAAC,CA0B3D;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxE"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { logger } from './logger.js';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
// Resolve the frontend dist path
|
|
9
|
+
// Priority order:
|
|
10
|
+
// 1. DIGIMAKER_FRONTEND_PATH env var (for custom setups)
|
|
11
|
+
// 2. Bundled with CLI package (npm global install): @digimakers/cli/dist/frontend/browser
|
|
12
|
+
// 3. Monorepo sibling (development): packages/frontend/dist/frontend/browser
|
|
13
|
+
function resolveFrontendPath() {
|
|
14
|
+
// 1. Check for environment variable override
|
|
15
|
+
if (process.env.DIGIMAKER_FRONTEND_PATH) {
|
|
16
|
+
const envPath = process.env.DIGIMAKER_FRONTEND_PATH;
|
|
17
|
+
if (fs.existsSync(envPath)) {
|
|
18
|
+
logger.debug(`[Server] Using frontend from DIGIMAKER_FRONTEND_PATH: ${envPath}`);
|
|
19
|
+
return envPath;
|
|
20
|
+
}
|
|
21
|
+
logger.warn(`[Server] DIGIMAKER_FRONTEND_PATH set but path not found: ${envPath}`);
|
|
22
|
+
}
|
|
23
|
+
// 2. Check if running from CLI package (npm global install)
|
|
24
|
+
// When installed globally, the structure can vary based on npm hoisting
|
|
25
|
+
// Frontend is bundled at @digimakers/cli/dist/frontend/browser
|
|
26
|
+
const cliModulePaths = [
|
|
27
|
+
// npm global install (hoisted): @digimakers/core and @digimakers/cli are siblings
|
|
28
|
+
path.resolve(__dirname, '../cli/dist/frontend/browser'),
|
|
29
|
+
path.resolve(__dirname, '../../cli/dist/frontend/browser'),
|
|
30
|
+
// npm global install (nested): core is inside cli's node_modules
|
|
31
|
+
path.resolve(__dirname, '../../../../dist/frontend/browser'),
|
|
32
|
+
path.resolve(__dirname, '../../../dist/frontend/browser'),
|
|
33
|
+
// Same directory (if frontend is bundled with core)
|
|
34
|
+
path.resolve(__dirname, './frontend/browser'),
|
|
35
|
+
path.resolve(__dirname, '../frontend/browser'),
|
|
36
|
+
];
|
|
37
|
+
for (const cliPath of cliModulePaths) {
|
|
38
|
+
if (fs.existsSync(cliPath)) {
|
|
39
|
+
logger.debug(`[Server] Using bundled frontend from CLI package: ${cliPath}`);
|
|
40
|
+
return cliPath;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// 3. Monorepo development: sibling frontend package
|
|
44
|
+
const monorepoPath = path.resolve(__dirname, '../../frontend/dist/frontend/browser');
|
|
45
|
+
if (fs.existsSync(monorepoPath)) {
|
|
46
|
+
logger.debug(`[Server] Using frontend from monorepo: ${monorepoPath}`);
|
|
47
|
+
return monorepoPath;
|
|
48
|
+
}
|
|
49
|
+
// Fallback: return monorepo path and let it fail with a clear error
|
|
50
|
+
logger.error(`[Server] Frontend assets not found. Checked paths:`);
|
|
51
|
+
logger.error(` - ${cliModulePaths.join('\n - ')}`);
|
|
52
|
+
logger.error(` - ${monorepoPath}`);
|
|
53
|
+
return monorepoPath;
|
|
54
|
+
}
|
|
55
|
+
export async function startServer() {
|
|
56
|
+
const app = express();
|
|
57
|
+
const frontendPath = resolveFrontendPath();
|
|
58
|
+
app.use(express.static(frontendPath));
|
|
59
|
+
app.get('/{*path}', (req, res) => {
|
|
60
|
+
res.sendFile(path.join(frontendPath, 'index.html'));
|
|
61
|
+
});
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const server = app.listen(0, () => {
|
|
64
|
+
const address = server.address();
|
|
65
|
+
if (!address || typeof address === 'string') {
|
|
66
|
+
reject(new Error('Failed to get server address'));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const port = address.port;
|
|
70
|
+
const url = `http://localhost:${port}`;
|
|
71
|
+
logger.info(`[Server] Running at ${url}`);
|
|
72
|
+
resolve({ app, server, port, url });
|
|
73
|
+
});
|
|
74
|
+
server.on('error', reject);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export async function stopServer(instance) {
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
instance.server.close((err) => {
|
|
80
|
+
if (err)
|
|
81
|
+
reject(err);
|
|
82
|
+
else {
|
|
83
|
+
logger.info('[Server] Stopped');
|
|
84
|
+
resolve();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@digimakers/core",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Core library for Digimaker - docx to PDF conversion",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./schemas": {
|
|
14
|
+
"types": "./dist/schemas/index.d.ts",
|
|
15
|
+
"import": "./dist/schemas/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"dev": "tsc --watch",
|
|
21
|
+
"clean": "rm -rf dist"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@ai-sdk/google": "^3.0.10",
|
|
25
|
+
"ai": "6.0.39",
|
|
26
|
+
"dotenv": "^17.2.3",
|
|
27
|
+
"express": "5.2.1",
|
|
28
|
+
"mammoth": "^1.8.0",
|
|
29
|
+
"pino": "^10.2.0",
|
|
30
|
+
"pino-pretty": "^13.1.3",
|
|
31
|
+
"puppeteer": "24.35.0",
|
|
32
|
+
"zod": "4.3.5"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/express": "5.0.6",
|
|
36
|
+
"@types/node": "24.0.0",
|
|
37
|
+
"typescript": "^5.5.0"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist/**/*"
|
|
41
|
+
],
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/jenul-ferdinand/digimaker.git",
|
|
46
|
+
"directory": "packages/core"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/jenul-ferdinand/digimaker/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/jenul-ferdinand/digimaker#readme",
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=18.0.0"
|
|
57
|
+
}
|
|
58
|
+
}
|