feat: versión inicial de GLM Hub
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import ts from '../node_modules/typescript/lib/typescript.js';
|
||||
|
||||
const root = path.resolve(new URL('..', import.meta.url).pathname);
|
||||
const srcDir = path.join(root, 'src');
|
||||
const distDir = path.join(root, 'dist');
|
||||
const assetsDir = path.join(distDir, 'assets');
|
||||
|
||||
const env = {
|
||||
VITE_SUPABASE_URL: 'https://dbit.digitalcompass.agency',
|
||||
VITE_SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE',
|
||||
VITE_ICON_GENERATOR_WEBHOOK_URL: 'https://agenteit.digitalcompass.agency/webhook/glm-hub-generar-icono',
|
||||
VITE_ACCESS_REQUEST_WEBHOOK_URL: 'https://agenteit.digitalcompass.agency/webhook/glm-hub-solicitar-acceso',
|
||||
BASE_URL: '/',
|
||||
};
|
||||
|
||||
function replaceEnv(source) {
|
||||
return source
|
||||
.replaceAll('import.meta.env.VITE_SUPABASE_URL', JSON.stringify(env.VITE_SUPABASE_URL))
|
||||
.replaceAll('import.meta.env.VITE_SUPABASE_ANON_KEY', JSON.stringify(env.VITE_SUPABASE_ANON_KEY))
|
||||
.replaceAll('import.meta.env.VITE_ICON_GENERATOR_WEBHOOK_URL', JSON.stringify(env.VITE_ICON_GENERATOR_WEBHOOK_URL))
|
||||
.replaceAll('import.meta.env.VITE_ACCESS_REQUEST_WEBHOOK_URL', JSON.stringify(env.VITE_ACCESS_REQUEST_WEBHOOK_URL))
|
||||
.replaceAll('import.meta.env.BASE_URL', JSON.stringify(env.BASE_URL));
|
||||
}
|
||||
|
||||
function fixLocalImports(code) {
|
||||
return code
|
||||
.replace(/^import\s+["']\.\/styles\.css["'];?\s*$/gm, '')
|
||||
.replace(/(from\s+["'])(\.\.?\/[^"']+)(["'])/g, (_m, start, spec, end) => {
|
||||
if (/\.(?:js|mjs|cjs|json|css)$/.test(spec)) return `${start}${spec}${end}`;
|
||||
return `${start}${spec}.js${end}`;
|
||||
});
|
||||
}
|
||||
|
||||
fs.rmSync(distDir, { recursive: true, force: true });
|
||||
fs.mkdirSync(assetsDir, { recursive: true });
|
||||
|
||||
const sourceFiles = ['main.tsx', 'App.tsx', 'data.ts', 'repository.ts', 'storage.ts', 'supabase.ts', 'types.ts'];
|
||||
for (const file of sourceFiles) {
|
||||
const sourcePath = path.join(srcDir, file);
|
||||
const source = replaceEnv(fs.readFileSync(sourcePath, 'utf8'));
|
||||
const result = ts.transpileModule(source, {
|
||||
fileName: file,
|
||||
compilerOptions: {
|
||||
target: ts.ScriptTarget.ES2022,
|
||||
module: ts.ModuleKind.ESNext,
|
||||
jsx: ts.JsxEmit.ReactJSX,
|
||||
importsNotUsedAsValues: ts.ImportsNotUsedAsValues.Remove,
|
||||
sourceMap: false,
|
||||
},
|
||||
reportDiagnostics: true,
|
||||
});
|
||||
const errors = (result.diagnostics ?? []).filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error);
|
||||
if (errors.length) {
|
||||
throw new Error(`${file}: ${errors.map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')).join('\n')}`);
|
||||
}
|
||||
const outputName = file.replace(/\.tsx?$/, '.js');
|
||||
fs.writeFileSync(path.join(assetsDir, outputName), fixLocalImports(result.outputText));
|
||||
}
|
||||
|
||||
fs.copyFileSync(path.join(srcDir, 'styles.css'), path.join(assetsDir, 'styles.css'));
|
||||
for (const asset of ['glm-logo.png', 'glm-favicon.png', 'glm-tab-icon-16-20260722.png', 'glm-tab-icon-32-20260722.png', 'glm-tab-icon-64-20260722.png', 'glm-tab-icon-180-20260722.png', 'glm-tab-icon-20260722.ico']) {
|
||||
const source = path.join(root, 'public', asset);
|
||||
if (fs.existsSync(source)) fs.copyFileSync(source, path.join(distDir, asset));
|
||||
}
|
||||
|
||||
const indexHtml = `<!doctype html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<meta name="description" content="Hub interno de aplicaciones de GomezLee Marketing." />
|
||||
<link rel="icon" type="image/png" sizes="512x512" href="https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png?v=glm-hub-20260728-access" />
|
||||
<link rel="shortcut icon" type="image/png" href="https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png?v=glm-hub-20260728-access" />
|
||||
<link rel="apple-touch-icon" href="https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png?v=glm-hub-20260728-access" />
|
||||
<title>GLM Hub — GomezLee Marketing</title>
|
||||
<link rel="stylesheet" href="/assets/styles.css" />
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"react": "https://cdn.jsdelivr.net/npm/react@19.2.7/+esm",
|
||||
"react/jsx-runtime": "https://cdn.jsdelivr.net/npm/react@19.2.7/jsx-runtime/+esm",
|
||||
"react-dom/client": "https://cdn.jsdelivr.net/npm/react-dom@19.2.7/client/+esm",
|
||||
"lucide-react": "https://cdn.jsdelivr.net/npm/lucide-react@0.575.0/+esm"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2.110.8"></script>
|
||||
<script type="module" src="/assets/main.js"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
fs.writeFileSync(path.join(distDir, 'index.html'), indexHtml);
|
||||
console.log(`Static ESM build created at ${distDir}`);
|
||||
@@ -0,0 +1,21 @@
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$projectRoot = [System.IO.Path]::GetFullPath((Split-Path -Parent $PSScriptRoot))
|
||||
Push-Location $projectRoot
|
||||
|
||||
try {
|
||||
& npm run typecheck
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "TypeScript encontró errores."
|
||||
}
|
||||
|
||||
& npm exec vite build
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Vite no pudo compilar la aplicación."
|
||||
}
|
||||
|
||||
Write-Host "GLM Hub compilado en $(Join-Path $projectRoot 'dist')"
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { createReadStream, existsSync, statSync } from "node:fs";
|
||||
import { createServer } from "node:http";
|
||||
import { extname, join, normalize, resolve } from "node:path";
|
||||
|
||||
const root = resolve(process.cwd(), process.argv[2] ?? "dist");
|
||||
const port = Number(process.env.PORT ?? 4173);
|
||||
const mimeTypes = new Map([
|
||||
[".css", "text/css; charset=utf-8"],
|
||||
[".html", "text/html; charset=utf-8"],
|
||||
[".js", "text/javascript; charset=utf-8"],
|
||||
[".json", "application/json; charset=utf-8"],
|
||||
[".png", "image/png"],
|
||||
[".svg", "image/svg+xml"],
|
||||
[".webp", "image/webp"],
|
||||
]);
|
||||
|
||||
const server = createServer((request, response) => {
|
||||
const rawPath = decodeURIComponent((request.url ?? "/").split("?")[0]);
|
||||
const relativePath = normalize(rawPath).replace(/^([/\\])+/, "");
|
||||
let filePath = resolve(join(root, relativePath || "index.html"));
|
||||
|
||||
if (!filePath.startsWith(root)) {
|
||||
response.writeHead(403).end("Forbidden");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!existsSync(filePath) || statSync(filePath).isDirectory()) {
|
||||
filePath = join(root, "index.html");
|
||||
}
|
||||
|
||||
response.setHeader("Content-Type", mimeTypes.get(extname(filePath)) ?? "application/octet-stream");
|
||||
response.setHeader("X-Content-Type-Options", "nosniff");
|
||||
response.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
|
||||
response.setHeader("Cross-Origin-Opener-Policy", "same-origin");
|
||||
createReadStream(filePath).pipe(response);
|
||||
});
|
||||
|
||||
server.listen(port, "127.0.0.1", () => {
|
||||
console.log(`GLM Hub disponible en http://127.0.0.1:${port}`);
|
||||
});
|
||||
Reference in New Issue
Block a user