feat: export bridge generator from core package

Added exports for SorobanGeneratorBridge to enable access to the Python
bridge generator that supports SVG generation. This allows the web app
to use the more capable bridge generator instead of the basic PDF-only
generator.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-09-14 17:48:57 -05:00
parent 6c49e0335e
commit 90a5c06f7c
3 changed files with 224 additions and 0 deletions

View File

@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
var src_exports = {};
__export(src_exports, {
SorobanGenerator: () => SorobanGenerator,
SorobanGeneratorBridge: () => SorobanGenerator2,
default: () => SorobanGenerator,
expressExample: () => expressExample
});
@ -191,8 +192,116 @@ var SorobanGenerator = class {
async function expressExample() {
const generator = new SorobanGenerator();
}
// src/soroban-generator-bridge.ts
var import_python_shell = require("python-shell");
var path2 = __toESM(require("path"));
var SorobanGenerator2 = class {
pythonShell = null;
projectRoot;
constructor(projectRoot) {
this.projectRoot = projectRoot || path2.join(__dirname, "../../");
}
/**
* Initialize persistent Python process for better performance
*/
async initialize() {
if (this.pythonShell)
return;
this.pythonShell = new import_python_shell.PythonShell(
path2.join(this.projectRoot, "src", "bridge.py"),
{
mode: "json",
pythonPath: "python3",
pythonOptions: ["-u"],
// Unbuffered
scriptPath: this.projectRoot
}
);
}
/**
* Generate flashcards - clean function interface
*/
async generate(config) {
if (!this.pythonShell) {
return new Promise((resolve, reject) => {
import_python_shell.PythonShell.run(
path2.join(this.projectRoot, "src", "bridge.py"),
{
mode: "json",
pythonPath: "python3",
scriptPath: this.projectRoot,
args: []
},
(err, results) => {
if (err) {
reject(err);
} else if (results && results[0]) {
const result = results[0];
if (result.error) {
reject(new Error(result.error));
} else {
resolve(result);
}
} else {
reject(new Error("No result from Python"));
}
}
);
import_python_shell.PythonShell.defaultOptions = {};
const shell = new import_python_shell.PythonShell(
path2.join(this.projectRoot, "src", "bridge.py"),
{
mode: "json",
pythonPath: "python3",
scriptPath: this.projectRoot
}
);
shell.send(config);
shell.end((err, code, signal) => {
if (err)
console.error(err);
});
});
}
return new Promise((resolve, reject) => {
if (!this.pythonShell) {
reject(new Error("Not initialized"));
return;
}
const handler = (message) => {
if (message.error) {
reject(new Error(message.error));
} else {
resolve(message);
}
this.pythonShell?.removeListener("message", handler);
};
this.pythonShell.on("message", handler);
this.pythonShell.send(config);
});
}
/**
* Generate and return as Buffer
*/
async generateBuffer(config) {
const result = await this.generate(config);
return Buffer.from(result.pdf, "base64");
}
/**
* Clean up Python process
*/
async close() {
if (this.pythonShell) {
this.pythonShell.end(() => {
});
this.pythonShell = null;
}
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SorobanGenerator,
SorobanGeneratorBridge,
expressExample
});

View File

@ -153,8 +153,116 @@ var SorobanGenerator = class {
async function expressExample() {
const generator = new SorobanGenerator();
}
// src/soroban-generator-bridge.ts
import { PythonShell } from "python-shell";
import * as path2 from "path";
var SorobanGenerator2 = class {
pythonShell = null;
projectRoot;
constructor(projectRoot) {
this.projectRoot = projectRoot || path2.join(__dirname, "../../");
}
/**
* Initialize persistent Python process for better performance
*/
async initialize() {
if (this.pythonShell)
return;
this.pythonShell = new PythonShell(
path2.join(this.projectRoot, "src", "bridge.py"),
{
mode: "json",
pythonPath: "python3",
pythonOptions: ["-u"],
// Unbuffered
scriptPath: this.projectRoot
}
);
}
/**
* Generate flashcards - clean function interface
*/
async generate(config) {
if (!this.pythonShell) {
return new Promise((resolve, reject) => {
PythonShell.run(
path2.join(this.projectRoot, "src", "bridge.py"),
{
mode: "json",
pythonPath: "python3",
scriptPath: this.projectRoot,
args: []
},
(err, results) => {
if (err) {
reject(err);
} else if (results && results[0]) {
const result = results[0];
if (result.error) {
reject(new Error(result.error));
} else {
resolve(result);
}
} else {
reject(new Error("No result from Python"));
}
}
);
PythonShell.defaultOptions = {};
const shell = new PythonShell(
path2.join(this.projectRoot, "src", "bridge.py"),
{
mode: "json",
pythonPath: "python3",
scriptPath: this.projectRoot
}
);
shell.send(config);
shell.end((err, code, signal) => {
if (err)
console.error(err);
});
});
}
return new Promise((resolve, reject) => {
if (!this.pythonShell) {
reject(new Error("Not initialized"));
return;
}
const handler = (message) => {
if (message.error) {
reject(new Error(message.error));
} else {
resolve(message);
}
this.pythonShell?.removeListener("message", handler);
};
this.pythonShell.on("message", handler);
this.pythonShell.send(config);
});
}
/**
* Generate and return as Buffer
*/
async generateBuffer(config) {
const result = await this.generate(config);
return Buffer.from(result.pdf, "base64");
}
/**
* Clean up Python process
*/
async close() {
if (this.pythonShell) {
this.pythonShell.end(() => {
});
this.pythonShell = null;
}
}
};
export {
SorobanGenerator,
SorobanGenerator2 as SorobanGeneratorBridge,
SorobanGenerator as default,
expressExample
};

View File

@ -5,5 +5,12 @@
export * from './soroban-generator'
// Export bridge generator with different name to avoid conflicts
export {
SorobanGenerator as SorobanGeneratorBridge,
FlashcardConfig as BridgeFlashcardConfig,
FlashcardResult as BridgeFlashcardResult
} from './soroban-generator-bridge'
// Default export for convenience
export { SorobanGenerator as default } from './soroban-generator'