Skip to content

Commit b06dadf

Browse files
author
root
committed
chore: capture uncommitted VM production work before reconciling with main
Captured directly from the running VM working tree before it could be lost to disk failure. Mixes several unrelated pieces of work that had accumulated without ever being committed: - Internal cross-reference linking (posts.service.ts resolveInternalCrossReferences) - OpenRouter AI provider integration (new packages/ai-content/api/openrouter/) - ai-content service/module changes (provider selection logic) - auto-pipeline classification/generation/posting worker changes Several other files here (config.ts WAL fix, /noticias route, esports formatting, posts.service savePost success-check, championships debug.txt removal) already exist identically on origin/main from a separate session — this commit was made on top of the VM local HEAD (5 commits behind origin/main) and has NOT been reconciled. Do not merge into main without review.
1 parent 75966e7 commit b06dadf

29 files changed

Lines changed: 424 additions & 111 deletions

File tree

apps/admin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cmmv-blog-admin",
3-
"version": "0.0.300",
3+
"version": "0.0.302",
44
"private": true,
55
"description": "Blog admin package for CMMV",
66
"type": "module",

apps/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cmmv-blog-api",
3-
"version": "0.0.300",
3+
"version": "0.0.302",
44
"private": true,
55
"description": "Blog API sample",
66
"dev": {

apps/api/src/config.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,16 @@ Config.assign({
2828
database: "./database.sqlite",
2929
synchronize: true,
3030
logging: process.env.NODE_ENV === 'development' ? ['error'] : false,
31+
// TypeORM's sqlite driver only recognizes these as top-level DataSource
32+
// options (see typeorm/driver/sqlite/SqliteDriver.js) — nesting them under
33+
// `extra` is silently ignored, which is why WAL was never actually enabled.
34+
// Enable WAL mode for better concurrency (allows reads during writes)
35+
enableWAL: true,
36+
// Wait up to 5s for a write lock instead of throwing SQLITE_BUSY immediately
37+
busyTimeout: 5000,
3138
// SQLite performance optimizations
3239
// These will be applied when the database connection is established
3340
extra: {
34-
// Enable WAL mode for better concurrency (allows reads during writes)
35-
// Set via PRAGMA journal_mode=WAL when connection opens
36-
enableWAL: true,
3741
// Cache size: 64MB (negative value means KB, so -64000 = 64MB)
3842
cacheSize: -64000,
3943
// Use memory for temporary storage (faster than disk)
@@ -91,8 +95,8 @@ Config.assign({
9195
},
9296

9397
blog: {
94-
// AI provider — groq é gratuito e rápido, fallback para deepseek
95-
aiService: process.env.AI_SERVICE || "groq",
98+
// AI provider — deepseek é principal (créditos ativos), fallback automático para groq/gemini
99+
aiService: process.env.AI_SERVICE || "deepseek",
96100
groqApiKey: process.env.GROQ_API_KEY || "",
97101
groqModel: process.env.GROQ_MODEL || "llama-3.3-70b-versatile",
98102
deepseekApiKey: process.env.DEEPSEEK_API_KEY || "",

apps/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cmmv-blog",
3-
"version": "0.0.300",
3+
"version": "0.0.302",
44
"private": true,
55
"description": "Blog package for CMMV",
66
"type": "module",

apps/web/src/theme-proplaynews/router.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export function createRouter() {
1616
{ path: '/preview/:id', component: () => import('./views/PagePost.vue') },
1717
{ path: '/preview-page/:id', component: () => import('./views/PagePage.vue') },
1818
{ path: '/post/:slug', component: () => import('./views/PagePost.vue') },
19+
{ path: '/noticias/:id/:slug', component: () => import('./views/PagePost.vue') },
1920
{ path: '/tag/:slug', component: () => import('./views/PageTag.vue') },
2021
{ path: '/author/:slug', component: () => import('./views/PageAuthor.vue') },
2122
{ path: '/contato', component: () => import('./views/ContactPage.vue') },

apps/web/src/theme-proplaynews/views/PagePost.vue

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="w-full relative bg-neutral-100">
33
<div class="w-full max-w-[1200px] mx-auto px-4">
4-
<div v-if="!post" class="bg-white rounded-lg p-6">
4+
<div v-if="!post?.id" class="bg-white rounded-lg p-6">
55
<div class="text-center">
66
<h1 class="text-2xl font-bold text-neutral-800 mb-4">Post não encontrado</h1>
77
<p class="text-neutral-600">O post que você está procurando não existe ou está indisponível.</p>
@@ -746,6 +746,15 @@ function escapeRegex(str: string): string {
746746
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
747747
}
748748
749+
// Apply a transform only to text nodes, never to HTML tags (attributes, href, etc.)
750+
function transformTextNodes(html: string, transform: (segment: string) => string): string {
751+
return html.replace(/<[^>]+>|[^<]+/g, (token) => {
752+
// Leave HTML tags (including their attributes such as href) untouched
753+
if (token.startsWith('<')) return token;
754+
return transform(token);
755+
});
756+
}
757+
749758
function applyEsportsFormatting(html: string): string {
750759
// Only process text nodes inside <p> and <li> — avoid breaking HTML tags
751760
// We use a tag-aware split strategy
@@ -759,26 +768,31 @@ function applyEsportsFormatting(html: string): string {
759768
return match;
760769
}
761770
762-
// Apply bold keywords first
763-
BOLD_KEYWORDS.forEach(kw => {
764-
const rx = new RegExp(`\\b(${escapeRegex(kw)})\\b`, 'g');
765-
text = text.replace(rx, '<strong class="kw-bold">$1</strong>');
771+
// Apply bold keywords first (text nodes only)
772+
text = transformTextNodes(text, (segment) => {
773+
BOLD_KEYWORDS.forEach(kw => {
774+
const rx = new RegExp(`\\b(${escapeRegex(kw)})\\b`, 'g');
775+
segment = segment.replace(rx, '<strong class="kw-bold">$1</strong>');
776+
});
777+
return segment;
766778
});
767779
768-
// Apply team names
769-
KNOWN_TEAMS.forEach(team => {
770-
const rx = new RegExp(`(?<![\\w#@])${escapeRegex(team)}(?![\\w])`, 'g');
771-
text = text.replace(rx, (m) => {
772-
// Don't double-wrap if already inside a tag
773-
if (text.slice(Math.max(0, text.indexOf(m) - 30), text.indexOf(m)).includes('<em')) return m;
774-
return `<em class="team-name">${m}</em>`;
780+
// Apply team names (text nodes only — never inside href/attributes)
781+
text = transformTextNodes(text, (segment) => {
782+
KNOWN_TEAMS.forEach(team => {
783+
const rx = new RegExp(`(?<![\\w#@])${escapeRegex(team)}(?![\\w])`, 'g');
784+
segment = segment.replace(rx, '<em class="team-name">$&</em>');
775785
});
786+
return segment;
776787
});
777788
778-
// Apply player names (italic)
779-
KNOWN_PLAYERS.forEach(player => {
780-
const rx = new RegExp(`(?<![\\w#@])${escapeRegex(player)}(?![\\w])`, 'g');
781-
text = text.replace(rx, `<em class="player-name">${player}</em>`);
789+
// Apply player names (italic, text nodes only)
790+
text = transformTextNodes(text, (segment) => {
791+
KNOWN_PLAYERS.forEach(player => {
792+
const rx = new RegExp(`(?<![\\w#@])${escapeRegex(player)}(?![\\w])`, 'g');
793+
segment = segment.replace(rx, `<em class="player-name">${player}</em>`);
794+
});
795+
return segment;
782796
});
783797
784798
return openTag + text + closeTag;
@@ -980,7 +994,7 @@ const headData = computed(() => ({
980994
link: [
981995
{ rel: 'canonical', href: pageUrl.value },
982996
],
983-
script: isSSR ? [
997+
script: (isSSR && post.value?.id) ? [
984998
{
985999
type: 'application/ld+json',
9861000
innerHTML: JSON.stringify(vue3.createLdJSON('post', post.value, settings.value))

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cmmv/blog",
3-
"version": "0.1.299",
3+
"version": "0.1.301",
44
"description": "Blog plugin for CMMV",
55
"keywords": [
66
"cmmv",

packages/access-control/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cmmv/access-control",
3-
"version": "0.1.299",
3+
"version": "0.1.301",
44
"description": "Access Control package for CMMV",
55
"scripts": {
66
"build": "tsup"

packages/affiliate/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cmmv/affiliate",
3-
"version": "0.1.299",
3+
"version": "0.1.301",
44
"description": "Affiliate package for CMMV",
55
"scripts": {
66
"build": "tsup"
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
import { Module } from '@cmmv/core';
1+
import { Module } from "@cmmv/core";
22

33
import { GeminiModule } from "./gemini/gemini.module";
4-
import { ChatGPTModule } from './chatgpt/chatgpt.module';
5-
import { GrokModule } from './grok/grok.module';
6-
import { GroqModule } from './groq/groq.module';
7-
import { DeepSeekModule } from './deepseek/deepseek.module';
8-
import { AIContentService } from './ai-content.service';
4+
import { ChatGPTModule } from "./chatgpt/chatgpt.module";
5+
import { GrokModule } from "./grok/grok.module";
6+
import { GroqModule } from "./groq/groq.module";
7+
import { DeepSeekModule } from "./deepseek/deepseek.module";
8+
import { OpenRouterModule } from "./openrouter/openrouter.module";
9+
import { AIContentService } from "./ai-content.service";
910

10-
export const AIContentModule = new Module('ai-content', {
11+
export const AIContentModule = new Module("ai-content", {
1112
submodules: [
1213
GeminiModule,
1314
ChatGPTModule,
1415
DeepSeekModule,
1516
GrokModule,
16-
GroqModule
17+
GroqModule,
18+
OpenRouterModule
1719
],
1820
providers: [AIContentService]
1921
});

0 commit comments

Comments
 (0)