chore: scripts Dokploy/BPS (cron secret, Ads MCC, sync y probes)

Incluye utilidades de ops para CRON_SECRET, login customer Google Ads, sync de seguimiento BPS y probes de conexiones.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-09-29 16:48:44 +02:00
parent 8c5acb626f
commit 1a58af129d
17 changed files with 2913 additions and 0 deletions

View File

@@ -0,0 +1,145 @@
import { config } from 'dotenv';
import { resolve } from 'path';
config({ path: resolve(process.cwd(), '.env.local') });
import {
exportGoogleDocPlain,
exportGoogleDocHtml,
upsertSeguimientoRows,
patchSuperhumanIntegration,
} from '../src/lib/superhuman-docs';
import { getValidAccessToken } from '../src/lib/google-drive';
const BPS = '8bec977a-6032-4759-aa7f-b5042081f450';
const FILE = '1uDnRPWf1Dqx5b9L3TuhfvutyZpSaifz7YFNrRy_eBhw';
const DOC = '7TGywaNiUY';
function parseDayLabel(raw: string): { dateIso: string; label: string } | null {
const m = raw.trim().match(/^(\d{1,2})[\/.\-](\d{1,2})[\/.\-](\d{2,4})$/);
if (!m) return null;
let y = Number(m[3]);
const mo = Number(m[2]);
const d = Number(m[1]);
if (y < 100) y += 2000;
if (y < 2000 || y > 2100 || mo < 1 || mo > 12 || d < 1 || d > 31) return null;
return {
dateIso: `${y}-${String(mo).padStart(2, '0')}-${String(d).padStart(2, '0')}`,
label: `${d}/${mo}/${String(y).slice(2)}`,
};
}
function splitNotesByDay(text: string) {
const clean = text.replace(/^\uFEFF/, '').replace(/\r\n/g, '\n');
const dayRe =
/^(?:#{1,4}\s*)?(\d{1,2})[\/.\-](\d{1,2})[\/.\-](\d{2,4})\s*$/;
const lines = clean.split('\n');
const hits: { idx: number; label: string; dateIso: string }[] = [];
for (let i = 0; i < lines.length; i++) {
const m = lines[i].trim().match(dayRe);
if (!m) continue;
const parsed = parseDayLabel(`${m[1]}/${m[2]}/${m[3]}`);
if (!parsed) continue;
hits.push({ idx: i, ...parsed });
}
if (!hits.length) return [] as { dateIso: string; label: string; body: string }[];
const sections: { dateIso: string; label: string; body: string }[] = [];
for (let h = 0; h < hits.length; h++) {
const start = hits[h].idx + 1;
const end = h + 1 < hits.length ? hits[h + 1].idx : lines.length;
const body = lines
.slice(start, end)
.join('\n')
.replace(/^\n+/, '')
.replace(/\n{3,}/g, '\n\n')
.trim();
if (!body) continue;
sections.push({ dateIso: hits[h].dateIso, label: hits[h].label, body });
}
sections.sort((a, b) => b.dateIso.localeCompare(a.dateIso));
return sections;
}
async function exportViaDownload(fileId: string, mime: string) {
const token = await getValidAccessToken();
const url = `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}/export?mimeType=${encodeURIComponent(mime)}`;
const r = await fetch(url, {
headers: { Authorization: `Bearer ${token}` },
});
if (!r.ok) throw new Error(`${mime} ${r.status}: ${(await r.text()).slice(0, 200)}`);
return await r.text();
}
async function main() {
let plain = '';
try {
plain = await exportGoogleDocPlain(FILE);
console.log('plain via helper', plain.length);
} catch (e) {
console.log('plain helper fail', e instanceof Error ? e.message : e);
}
if (!plain) {
try {
plain = await exportViaDownload(FILE, 'text/plain');
console.log('plain via download', plain.length);
} catch (e) {
console.log('plain download fail', e instanceof Error ? e.message : e);
}
}
try {
const html = await exportGoogleDocHtml(FILE);
console.log('html ok', html.length);
} catch (e) {
console.log('html fail', e instanceof Error ? e.message : e);
}
if (!plain) throw new Error('no plain export');
console.log('--- sample ---\n', plain.slice(0, 2000));
const secs = splitNotesByDay(plain);
console.log('sections', secs.length, secs.slice(0, 8).map((s) => s.label));
const now = new Date().toISOString();
const rows = secs.slice(0, 120).map((sec) => {
const firstLine =
sec.body
.split('\n')
.map((l) => l.replace(/^[\s*•\-]+/, '').trim())
.find((l) => l.length > 8) || '';
return {
tenant_id: BPS,
source: 'superhuman' as const,
entry_type: 'meeting' as const,
external_id: `gdoc:${FILE}:${sec.dateIso}`,
title: `Seguimiento · ${sec.label}`,
summary: firstLine.slice(0, 220) || null,
body_md: `<pre>${sec.body
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')}</pre>`,
browser_link: `https://docs.google.com/document/d/${FILE}/edit`,
metrics: {},
occurred_at: `${sec.dateIso}T12:00:00.000Z`,
synced_at: now,
updated_at: now,
};
});
const n = await upsertSeguimientoRows(rows);
await patchSuperhumanIntegration(BPS, {
status: 'connected',
external_account_id: DOC,
label: '01.BLUE PARROT SCHOOL',
last_sync_at: now,
error_message: null,
meta: {
doc_name: '01.BLUE PARROT SCHOOL',
gdoc_id: FILE,
gdoc_days: n,
synced_at: now,
},
});
console.log('upserted day notes', n);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});