187 cursor: not-allowed;
188 }
189 .api-key-input {
190 padding: 6px 10px;
191 border: 1px solid #ced4da;
309 <p><strong>To test:</strong> Get the <code>NOTION_WEBHOOK_SECRET</code> value from your <code>vars.env</code> file (provided by your administrator)</p>
310 <form class="test-controls" onsubmit="testWebhook(event)">
311 <input type="text" class="api-key-input" id="customApiKey" placeholder="Enter webhook secret" required>
312 <button type="submit" class="test-btn">Test Webhook</button>
313 </form>
317
318 <div class="webhook-section">
319 <h3>🔍 Demo API Endpoints</h3>
320
321 ${demoDatabaseId ? `
375
376 const resultDiv = document.getElementById('testResult');
377 const customKeyInput = document.getElementById('customApiKey');
378
379 // Clear previous result
389 }
390
391 const headers = { 'X-API-KEY': customKey };
392
393 const response = await fetch('/tasks/test', {
6import webhookAuth from "./backend/routes/webhookAuthCheck.ts";
7import dashboardRoute from "./backend/routes/views/dashboard.tsx";
8import apiRoutes from "./backend/routes/api/_api.routes.ts";
9import taskRoutes from "./backend/routes/tasks/_tasks.routes.ts";
10import viewRoutes from "./backend/routes/views/_views.routes.ts";
22
23// 2. User auth - for ALL routes EXCEPT /tasks/*
24app.use("/api/*", authCheck);
25app.use("/views/*", authCheck);
26app.use("/glimpse/*", authCheck);
31
32// 3. Mount routes AFTER middleware
33app.route("/api", apiRoutes);
34app.route("/tasks", taskRoutes);
35app.route("/views", viewRoutes);
16
17async function testMethod(methodName, ...args) {
18 const apiKey = document.getElementById('apiKey').value;
19 const docId = document.getElementById('docId').value;
20 const tableId = document.getElementById('tableId').value;
21
22 if (!apiKey || (!docId && methodName.includes('Records') || !tableId && methodName.includes('Records'))) {
23 printToOutput({ error: 'Falta la API Key, el ID de Documento o el ID de Tabla' });
24 return;
25 }
26
27 const client = new GristAPIClient(apiKey);
28
29 try {
1// Webhook authentication middleware for /tasks/* routes
2export default async (c, next) => {
3 const apiKey = c.req.header("X-API-KEY");
4 const expectedSecret = Deno.env.get("NOTION_WEBHOOK_SECRET");
5
10 }
11
12 // Check if API key is provided
13 if (!apiKey) {
14 console.log("Webhook authentication failed: No X-API-KEY header provided");
15 return c.json({ error: "Authentication required" }, 401);
16 }
18 // Use constant-time comparison to prevent timing attacks
19 const expectedBuffer = new TextEncoder().encode(expectedSecret);
20 const providedBuffer = new TextEncoder().encode(apiKey);
21
22 // Ensure buffers are same length for constant-time comparison
23 if (expectedBuffer.length !== providedBuffer.length) {
24 console.log("Webhook authentication failed: Invalid API key length");
25 return c.json({ error: "Authentication failed" }, 403);
26 }
35
36 if (!isValid) {
37 console.log("Webhook authentication failed: Invalid API key");
38 return c.json({ error: "Authentication failed" }, 403);
39 }
1// Public routes that don't require authentication
2const PUBLIC_ROUTES = [
3 "/api/health", // Health check endpoint should be public
4 // Add other public routes here as needed
5 // '/demo/:id', // Example: public demo viewing
6 // '/api/public', // Example: public API endpoints
7];
8
1import { Hono } from "npm:hono@3.12.12";
2import { getHealthStatus } from "../../controllers/health.controller.ts";
3
4const app = new Hono();
5
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Probador de API de Grist</title>
7 <script src="https://cdn.tailwindcss.com"></script>
8 <link href="./static/style.css" />
11 <div class="max-w-4xl mx-auto bg-white p-8 rounded-xl shadow-lg">
12 <h1 class="text-3xl font-bold text-center mb-6 text-gray-800">
13 Probador de API de Grist
14 </h1>
15 <p class="text-center text-gray-600 mb-8">
16 Una herramienta para explorar y probar los endpoints de la API de Grist.
17 </p>
18
19 <div class="mb-6 space-y-4">
20 <div class="bg-gray-100 p-4 rounded-lg flex items-center shadow-sm">
21 <label for="apiKey" class="font-medium text-gray-700 w-32"
22 >API Key:</label>
23 <input
24 type="text"
25 id="apiKey"
26 class="flex-1 p-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500"
27 placeholder="Ingresa tu API Key (Bearer Token)"
28 >
29 </div>
319 </div>
320
321 <script src="./static/api.js"></script>
322 <script src="./static/main.js"></script>
323 </body>
3Files used by both backend and frontend.
4
5Note: Code in shared/ must work in both frontend and backend environments and cannot use Deno-specific APIs.
1# API Routes
2
3JSON API endpoints for frontend/backend communication.
6
7- **routes/** - HTTP route handlers organized by functionality
8- **api/** - JSON API endpoints for frontend/backend communication
9- **tasks/** - Webhook handlers for Notion integrations
10- **views/** - Server-side rendered views for frontend
11- **services/** - External API integrations (pure API calls only)
12- **controllers/** - Business logic coordination between routes and services
13- **crons/** - Scheduled task handlers