fix(backend): enhance sequence discovery from sister website directories and sync in post-receive
This commit is contained in:
1 parent
0bf544720b
commit
ca79692b3e
3 files changed
+71
-10
No files matched your search
@@ -35,7 +35,7 @@ import { crmRoute } from "./routes/crm";
|
|||||||
import { brandKnowledgeRoute } from "./routes/brandKnowledge";
|
import { brandKnowledgeRoute } from "./routes/brandKnowledge";
|
||||||
import { categorySectionsRoute } from "./routes/categorySections";
|
import { categorySectionsRoute } from "./routes/categorySections";
|
||||||
import { llmPromptsRoute } from "./routes/llmPrompts";
|
import { llmPromptsRoute } from "./routes/llmPrompts";
|
||||||
import { frameSequencesRoute } from "./routes/frame-sequences";
|
import { frameSequencesRoute, getCandidateSequenceDirs } from "./routes/frame-sequences";
|
||||||
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3051;
|
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3051;
|
||||||
const CORS_ORIGIN = process.env.CORS_ORIGIN || "http://localhost:5173";
|
const CORS_ORIGIN = process.env.CORS_ORIGIN || "http://localhost:5173";
|
||||||
const JWT_SECRET = process.env.JWT_SECRET || "homaroma_secret_2026_brand";
|
const JWT_SECRET = process.env.JWT_SECRET || "homaroma_secret_2026_brand";
|
||||||
@@ -142,9 +142,16 @@ const app = new Elysia()
|
|||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
})
|
})
|
||||||
.get("/frame-sequences/:sequence/:filename", ({ params: { sequence, filename }, set }) => {
|
.get("/frame-sequences/:sequence/:filename", async ({ params: { sequence, filename }, set }) => {
|
||||||
const file = Bun.file(`public/frame-sequences/${sequence}/${filename}`);
|
let file = Bun.file(`public/frame-sequences/${sequence}/${filename}`);
|
||||||
if (file.size === 0) {
|
if (file.size === 0) {
|
||||||
|
const candidateDirs = await getCandidateSequenceDirs();
|
||||||
|
for (const d of candidateDirs) {
|
||||||
|
const altFile = Bun.file(`${d}/${sequence}/${filename}`);
|
||||||
|
if (altFile.size > 0) {
|
||||||
|
return altFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
set.status = 404;
|
set.status = 404;
|
||||||
return "File not found";
|
return "File not found";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,28 +19,73 @@ export interface FrameSequenceManifest {
|
|||||||
|
|
||||||
const getBaseDir = () => join(process.cwd(), "public", "frame-sequences");
|
const getBaseDir = () => join(process.cwd(), "public", "frame-sequences");
|
||||||
|
|
||||||
|
export const getCandidateSequenceDirs = async (): Promise<string[]> => {
|
||||||
|
const candidates: string[] = [
|
||||||
|
getBaseDir(),
|
||||||
|
join(process.cwd(), "..", "website", "public", "frame-sequences"),
|
||||||
|
join(process.cwd(), "..", "..", "website", "public", "frame-sequences"),
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check sister projects in deployment layout (e.g. /home/ti/projects/ddc-website/apps/website/public/frame-sequences)
|
||||||
|
const possibleProjectRoots = [
|
||||||
|
join(process.cwd(), "..", ".."),
|
||||||
|
join(process.cwd(), "..", "..", ".."),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const root of possibleProjectRoots) {
|
||||||
|
if (existsSync(root)) {
|
||||||
|
const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
|
||||||
|
for (const e of entries) {
|
||||||
|
if (e.isDirectory() && (e.name.includes("website") || e.name.includes("shop"))) {
|
||||||
|
candidates.push(join(root, e.name, "apps", "website", "public", "frame-sequences"));
|
||||||
|
candidates.push(join(root, e.name, "public", "frame-sequences"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// non-fatal
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(new Set(candidates.filter((d) => existsSync(d))));
|
||||||
|
};
|
||||||
|
|
||||||
export const frameSequencesRoute = new Elysia({ prefix: "/frame-sequences" })
|
export const frameSequencesRoute = new Elysia({ prefix: "/frame-sequences" })
|
||||||
// 1. List all Frame Sequences (Reads manifests from public/frame-sequences/*)
|
// 1. List all Frame Sequences (Reads manifests from public/frame-sequences/* and candidate directories)
|
||||||
.get("/", async () => {
|
.get("/", async () => {
|
||||||
const baseDir = getBaseDir();
|
const baseDir = getBaseDir();
|
||||||
if (!existsSync(baseDir)) {
|
if (!existsSync(baseDir)) {
|
||||||
await mkdir(baseDir, { recursive: true });
|
await mkdir(baseDir, { recursive: true }).catch(() => {});
|
||||||
return { sequences: [] };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const entries = await readdir(baseDir, { withFileTypes: true });
|
const searchDirs = await getCandidateSequenceDirs();
|
||||||
|
const seenSlugs = new Set<string>();
|
||||||
const sequences: FrameSequenceManifest[] = [];
|
const sequences: FrameSequenceManifest[] = [];
|
||||||
|
|
||||||
|
for (const dir of searchDirs) {
|
||||||
|
try {
|
||||||
|
const entries = await readdir(dir, { withFileTypes: true });
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (!entry.isDirectory()) continue;
|
if (!entry.isDirectory()) continue;
|
||||||
const folderPath = join(baseDir, entry.name);
|
if (seenSlugs.has(entry.name)) continue;
|
||||||
|
|
||||||
|
const folderPath = join(dir, entry.name);
|
||||||
const manifestPath = join(folderPath, "manifest.json");
|
const manifestPath = join(folderPath, "manifest.json");
|
||||||
|
|
||||||
if (existsSync(manifestPath)) {
|
if (existsSync(manifestPath)) {
|
||||||
try {
|
try {
|
||||||
const raw = await readFile(manifestPath, "utf8");
|
const raw = await readFile(manifestPath, "utf8");
|
||||||
const manifest: FrameSequenceManifest = JSON.parse(raw);
|
const manifest: FrameSequenceManifest = JSON.parse(raw);
|
||||||
|
seenSlugs.add(entry.name);
|
||||||
sequences.push(manifest);
|
sequences.push(manifest);
|
||||||
|
|
||||||
|
// Auto-sync manifest to local backend baseDir if not present
|
||||||
|
const localSeqDir = join(baseDir, entry.name);
|
||||||
|
if (!existsSync(localSeqDir)) {
|
||||||
|
await mkdir(localSeqDir, { recursive: true }).catch(() => {});
|
||||||
|
await writeFile(join(localSeqDir, "manifest.json"), raw, "utf8").catch(() => {});
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`Failed to parse manifest in ${entry.name}`, e);
|
console.error(`Failed to parse manifest in ${entry.name}`, e);
|
||||||
@@ -69,11 +114,16 @@ export const frameSequencesRoute = new Elysia({ prefix: "/frame-sequences" })
|
|||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
await writeFile(manifestPath, JSON.stringify(autoManifest, null, 2), "utf8");
|
await writeFile(manifestPath, JSON.stringify(autoManifest, null, 2), "utf8").catch(() => {});
|
||||||
|
seenSlugs.add(entry.name);
|
||||||
sequences.push(autoManifest);
|
sequences.push(autoManifest);
|
||||||
}
|
}
|
||||||
|
} catch (scanErr) {
|
||||||
|
console.error(`Error scanning sequence folder ${entry.name}`, scanErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`Error scanning sequence folder ${entry.name}`, err);
|
// Continue to next candidate dir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ $BUN install
|
|||||||
|
|
||||||
# สร้าง public/ folder สำหรับ static files (upload images)
|
# สร้าง public/ folder สำหรับ static files (upload images)
|
||||||
mkdir -p $TARGET_BACKEND/apps/backend/public
|
mkdir -p $TARGET_BACKEND/apps/backend/public
|
||||||
|
if [ -d "$TEMP_DIR/apps/backend/public/frame-sequences" ]; then
|
||||||
|
mkdir -p $TARGET_BACKEND/apps/backend/public/frame-sequences
|
||||||
|
rsync -av "$TEMP_DIR/apps/backend/public/frame-sequences/" "$TARGET_BACKEND/apps/backend/public/frame-sequences/"
|
||||||
|
fi
|
||||||
|
|
||||||
cd $TARGET_BACKEND/apps/backend
|
cd $TARGET_BACKEND/apps/backend
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user