removed scaffold
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import { Hono } from 'hono';
|
||||
import { serveStatic } from 'hono/bun';
|
||||
import { cors } from 'hono/cors';
|
||||
import PocketBase from 'pocketbase';
|
||||
import { ConfidentialClientApplication } from '@azure/msal-node';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
// Load env from local .env
|
||||
const envPath = join(import.meta.dir, '.env');
|
||||
try {
|
||||
const envContent = readFileSync(envPath, 'utf-8');
|
||||
envContent.split('\n').forEach(line => {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed && !trimmed.startsWith('#')) {
|
||||
const [key, ...valueParts] = trimmed.split('=');
|
||||
if (key && valueParts.length > 0) {
|
||||
process.env[key.trim()] = valueParts.join('=').trim();
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log('✓ Loaded env from .env');
|
||||
} catch (e) {
|
||||
console.warn('⚠ Could not load .env:', (e as Error).message);
|
||||
}
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
// Enable CORS
|
||||
app.use('/*', cors({
|
||||
origin: '*',
|
||||
credentials: true,
|
||||
}));
|
||||
|
||||
// PocketBase client
|
||||
const pb = new PocketBase(process.env.PB_DB || 'http://127.0.0.1:8090');
|
||||
|
||||
// Use user's PocketBase token
|
||||
function setUserPocketBaseAuth(token: string) {
|
||||
pb.authStore.save(token, null);
|
||||
}
|
||||
|
||||
// MSAL config for Graph token (client credentials)
|
||||
const msalConfig = {
|
||||
auth: {
|
||||
clientId: process.env.CLIENT_ID || '',
|
||||
authority: `https://login.microsoftonline.com/${process.env.TENANT_ID}`,
|
||||
clientSecret: process.env.CLIENT_SECRET || '',
|
||||
},
|
||||
};
|
||||
const cca = new ConfidentialClientApplication(msalConfig);
|
||||
|
||||
// Simple in-memory cache for Graph token
|
||||
let graphTokenCache: { token: string; expiresOn: number } | null = null;
|
||||
|
||||
async function getGraphToken(): Promise<{ token: string; expiresOn: number }> {
|
||||
const now = Date.now();
|
||||
if (graphTokenCache && graphTokenCache.expiresOn - 60000 > now) {
|
||||
return graphTokenCache;
|
||||
}
|
||||
const result = await cca.acquireTokenByClientCredential({
|
||||
scopes: ['https://graph.microsoft.com/.default'],
|
||||
});
|
||||
if (!result || !result.accessToken) {
|
||||
throw new Error('Failed to acquire Graph token');
|
||||
}
|
||||
const expiresOn = result.expiresOn ? new Date(result.expiresOn).getTime() : now + 55 * 60 * 1000;
|
||||
graphTokenCache = { token: result.accessToken, expiresOn };
|
||||
return graphTokenCache;
|
||||
}
|
||||
|
||||
// Health check
|
||||
app.get('/health', (c) => {
|
||||
return c.json({ ok: true, pbDB: process.env.PB_DB });
|
||||
});
|
||||
|
||||
// Graph token status (acquires if missing/expired)
|
||||
app.get('/api/graph/status', async (c) => {
|
||||
try {
|
||||
const tokenInfo = await getGraphToken();
|
||||
return c.json({ active: true, expiresOnISO: new Date(tokenInfo.expiresOn).toISOString() });
|
||||
} catch (e) {
|
||||
return c.json({ active: false, error: (e as Error)?.message || 'Failed to acquire token' }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Submit endpoint (example)
|
||||
app.post('/api/submit', async (c) => {
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
const pbToken = body.pbToken;
|
||||
|
||||
if (!pbToken) {
|
||||
return c.json({ success: false, message: 'Missing pbToken' }, 401);
|
||||
}
|
||||
|
||||
// Validate user token
|
||||
setUserPocketBaseAuth(pbToken);
|
||||
try {
|
||||
await pb.collection(process.env.PB_AUTH_COLLECTION || 'Users').authRefresh();
|
||||
} catch (e) {
|
||||
console.error('auth_validation_failed', { message: (e as Error)?.message });
|
||||
return c.json({ success: false, message: 'Invalid token' }, 401);
|
||||
}
|
||||
|
||||
// Store in PocketBase collection (adjust fields as needed)
|
||||
const record = await pb
|
||||
.collection(process.env.PB_COLLECTION || 'Job_Info_TestEnv')
|
||||
.create({
|
||||
...body,
|
||||
submittedBy: pb.authStore.model?.email || 'unknown',
|
||||
submittedAt: new Date().toISOString(),
|
||||
});
|
||||
|
||||
console.log('submission_success', { recordId: record.id });
|
||||
return c.json({ success: true, message: 'Feedback submitted successfully', recordId: record.id });
|
||||
} catch (err) {
|
||||
console.error('submit_error', { message: (err as Error)?.message });
|
||||
return c.json({ success: false, message: 'Internal error' }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Serve static index.html
|
||||
app.get('/', async (c) => {
|
||||
const html = await Bun.file(new URL('./index.html', import.meta.url)).text();
|
||||
return c.html(html);
|
||||
});
|
||||
|
||||
const PORT = Number(process.env.PORT || 5500);
|
||||
console.log(`PBandGraph server running at http://localhost:${PORT}`);
|
||||
|
||||
export default {
|
||||
port: PORT,
|
||||
fetch: app.fetch,
|
||||
};
|
||||
Reference in New Issue
Block a user