location-feed-generatorcheckins.ts8 matches
1// Checkin creation API endpoint for Anchor
2import type { Context } from "jsr:@hono/hono@4.9.6";
3import { OverpassService } from "../services/overpass-service.ts";
17*/
18/**
19* Convert API PlaceInput to proper Place object
20*/
21function _sanitizePlaceInput(input: PlaceInput): Place {
123}
124125// API input format - coordinates might be strings
126interface PlaceInput {
127name: string;
129longitude: number | string;
130tags: Record<string, string>;
131// Optional fields that might be missing from API input
132id?: string;
133elementType?: "node" | "way" | "relation";
237const { message } = body;
238239// Convert API input to proper Place object and validate coordinates
240const place = _sanitizePlaceInput(body.place);
241const lat = place.latitude;
255console.log("🚀 Starting checkin creation process...");
256257// Get sessions instance for clean OAuth API access
258const { sessions } = await import("../routes/oauth.ts");
259295}
296297// Create address and checkin records via AT Protocol using clean OAuth API
298async function createAddressAndCheckin(
299sessions: OAuthSessionsInterface,
307console.log(`🔰 Getting OAuth session for DID: ${did}`);
308309// Use the clean API to get a ready-to-use OAuth session
310const oauthSession = await sessions.getOAuthSession(did);
311if (!oauthSession) {
9"Bash(/Users/tijs/projects/Anchor/location-feed-generator/scripts/test.sh:*)",
10"Bash(./scripts/test.sh:*)",
11"Bash(./scripts/test-api.sh:*)",
12"Bash(vt list:*)",
13"Bash(vt browse:*)",
14"Bash(ls:*)",
15"Bash(./scripts/monitor-api.sh:*)",
16"Bash(swift test:*)",
17"Bash(swift build:*)",
zoomtest.cursorrules10 matches
13- Generate code in TypeScript or TSX
14- Add appropriate TypeScript types and interfaces for all data structures
15- Prefer official SDKs or libraries than writing API calls directly
16- Ask the user to supply API or library documentation if you are at all unsure about it
17- **Never bake in secrets into the code** - always use environment variables
18- Include comments explaining complex logic (avoid commenting obvious operations)
23### 1. HTTP Trigger
2425- Create web APIs and endpoints
26- Handle HTTP requests and responses
27- Example structure:
173However, it's *extremely importing* to note that `parseProject` and other Standard Library utilities ONLY RUN ON THE SERVER.
174If you need access to this data on the client, run it in the server and pass it to the client by splicing it into the HTML page
175or by making an API request for it.
176177## Val Town Platform Specifics
181- **AI Image:** To inline generate an AI image use: `<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />`
182- **Storage:** DO NOT use the Deno KV module for storage
183- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
184- **Weather Data:** Use open-meteo for weather data (doesn't require API keys) unless otherwise specified
185- **View Source:** Add a view source link by importing & using `import.meta.url.replace("ems.sh", "val.town)"` (or passing this data to the client) and include `target="_top"` attribute
186- **Error Debugging:** Add `<script src="https://esm.town/v/std/catch"></script>` to HTML to capture client-side errors
187- **Error Handling:** Only use try...catch when there's a clear local resolution; Avoid catches that merely log or return 500s. Let errors bubble up with full context
188- **Environment Variables:** Use `Deno.env.get('keyname')` when you need to, but generally prefer APIs that don't require keys
189- **Imports:** Use `https://esm.sh` for npm and Deno dependencies to ensure compatibility on server and browser
190- **Storage Strategy:** Only use backend storage if explicitly required; prefer simple static client-side sites
224### Backend (Hono) Best Practices
225226- Hono is the recommended API framework
227- Main entry point should be `backend/index.ts`
228- **Static asset serving:** Use the utility functions to read and serve project files:
248});
249```
250- Create RESTful API routes for CRUD operations
251- Always include this snippet at the top-level Hono app to re-throwing errors to see full stack traces:
252```ts
285- For files in the project, use `readFile` helpers
2862875. **API Design:**
288- `fetch` handler is the entry point for HTTP vals
289- Run the Hono app with `export default app.fetch // This is the entry point for HTTP vals`
chatterchatStream.js7 matches
3// import { buildSearchPrompt, routeQueryMode } from "../../chatCompletion.js"; // routing disabled
4// import { extractOrRepairJsonResults, extractResultsFromToolOutputs, sanitizeResults, synthesizeResultsFromContext } from "../../jsonUtils.js"; // links/results disabled
5import { serverApiKey } from "../config.js";
67function collectToolTextFromArray(toolArray) {
2425export function registerChatStreamRoute(app) {
26app.post('/api/chatStream', async (c) => {
27try {
28let body = {};
3031const {
32userApiKey,
33messages,
34query,
49} = body || {};
5051const apiKey = serverApiKey || userApiKey || (typeof Deno !== 'undefined' ? Deno.env.get('GROQ_API_KEY') : null);
52if (!apiKey && !base_url) {
53return c.json({ error: 'No Groq API key available. Please provide your own key.' }, 400);
54}
55114}
115}
116const aggregates = await streamChatAndAggregate(apiKey, payload, { logSse: false, endpoint });
117// links/results extraction disabled — return only collapsed chat aggregates
118console.log('>> [chatStream] textContent:', aggregates?.collapsed?.content || '');
1// Generic Jobs API with SSE updates
2// import { buildSearchPrompt, routeQueryMode } from "../../chatCompletion.js"; // routing disabled
3// import { extractOrRepairJsonResults, extractResultsFromToolOutputs, sanitizeResults, synthesizeResultsFromContext } from "../../jsonUtils.js"; // links/results disabled
4import { serverApiKey } from "../config.js";
56/**
94const input = job.input || {};
95const {
96userApiKey,
97messages,
98query,
112} = input;
113114const apiKey = serverApiKey || userApiKey || (typeof Deno !== "undefined" ? Deno.env.get("GROQ_API_KEY") : null);
115if (!apiKey && !base_url) {
116failJob(job, "No API key (or base_url) provided");
117return;
118}
171172const baseUrl = (typeof base_url === "string" && base_url.trim()) ? base_url.trim().replace(/\/$/, "") : "";
173let endpoint = "https://api.groq.com/openai/v1/chat/completions";
174if (baseUrl) {
175if (/(\/v\d+)?\/(chat\/)?completions$/i.test(baseUrl)) {
184const headers = {
185"Content-Type": "application/json",
186...(apiKey ? { "Authorization": "Bearer " + apiKey } : {}),
187};
188306export function registerJobsRoutes(app) {
307// Create job
308app.post('/api/jobs', async (c) => {
309try {
310let body = {};
327328// Get job
329app.get('/api/jobs/:id', (c) => {
330const id = c.req.param('id');
331const job = getJob(id);
335336// List jobs (optionally filter by status)
337app.get('/api/jobs', (c) => {
338const status = c.req.query('status');
339const out = [];
346347// Cancel job
348app.post('/api/jobs/:id/cancel', (c) => {
349const id = c.req.param('id');
350const job = getJob(id);
356357// Stream job updates via SSE
358app.get('/api/jobs/:id/stream', (c) => {
359const id = c.req.param('id');
360const job = getJob(id);
chatterchatCompletion.js14 matches
1// Minimal Groq Chat Completions client using fetch
2import { extractOrRepairJsonResults, extractStructuredSummary, renderStructuredSummaryToHtml } from "./jsonUtils.js";
3export async function groqChatCompletion(apiKey, payload) {
4console.log('>>> [groqChatCompletion] Payload:', payload);
5const response = await fetch('https://api.groq.com/openai/v1/chat/completions', {
6method: 'POST',
7headers: {
8'Content-Type': 'application/json',
9'Authorization': `Bearer ${apiKey}`,
10},
11body: JSON.stringify(payload),
13if (!response.ok) {
14const text = await response.text();
15throw new Error(`Groq API error: ${response.status} ${text}`);
16}
17// console.log('>>> [groqChatCompletion] Response:', response);
5051// Lightweight router: decide between 'links' (JSON list) and 'text' (short answer)
52export async function routeQueryMode(apiKey, query) {
53// Routing disabled: force plain chat mode
54return 'text';
55/*
56try {
57const res = await groqChatCompletion(apiKey, {
58model: 'openai/gpt-oss-120b',
59messages: [
77}
7879export async function performSearch({ apiKey, query, dateRange, source, language, offset = 0, model, stream, reasoningEffort, forceLinksRoute = false }) {
80// const prompt = buildSearchPrompt(query, source, dateRange, language, offset);
81// const start = Date.now();
82// const route = forceLinksRoute ? 'links' : await routeQueryMode(apiKey, query);
83// const response = await groqChatCompletion(apiKey, {
84// model,
85// messages: route === 'text'
116// } catch (_) {
117// // as a fallback, attempt repair pass
118// results = await extractOrRepairJsonResults(contentText, apiKey, language);
119// }
120// } else {
142- If this is a research paper, use the RESEARCH format below.
143- If this is a news/blog/listing/discussion page (e.g., HN, Reddit, news site), use the GENERAL format below.
144- DO NOT include any citations, reference numbers, or raw scraping artifacts.
145- Write in clear prose without formatting artifacts.
146- The opening line of the summary must not simply repeat the title; avoid mirroring the title.
167}
168169export async function summarizeUrl({ apiKey, url, title, language, model, stream, reasoningEffort }) {
170const summaryPrompt = buildSummaryPrompt(url, title, language);
171const start = Date.now();
172const response = await groqChatCompletion(apiKey, {
173model,
174messages: [
194try {
195const inner = (responseText.match(/<summary>([\s\S]*?)<\/summary>/) || [null, responseText])[1];
196const structured = await extractStructuredSummary(inner, apiKey);
197if (structured) {
198cleanedHtml = renderStructuredSummaryToHtml(structured);
chatterchatStreamSSE.js13 matches
2// import { buildSearchPrompt, routeQueryMode } from "../../chatCompletion.js"; // routing disabled
3// import { extractOrRepairJsonResults, sanitizeResults, synthesizeResultsFromContext, extractResultsFromToolOutputs } from "../../jsonUtils.js"; // links/results disabled
4import { serverApiKey } from "../config.js";
56function collectToolTextFromArray(toolArray) {
2324export function registerChatStreamSSERoute(app) {
25app.post('/api/chatStreamSSE', async (c) => {
26try {
27let body = {};
2930const {
31userApiKey,
32messages,
33query,
48} = body || {};
4950const apiKey = serverApiKey || userApiKey || (typeof Deno !== 'undefined' ? Deno.env.get('GROQ_API_KEY') : null);
51if (!apiKey && !base_url) {
52return c.json({ error: 'No Groq API key available. Please provide your own key.' }, 400);
53}
54108const encoder = new TextEncoder();
109const baseUrl = (typeof base_url === 'string' && base_url.trim()) ? base_url.trim().replace(/\/$/, '') : '';
110let endpoint = 'https://api.groq.com/openai/v1/chat/completions';
111if (baseUrl) {
112if (/(\/v\d+)?\/(chat\/)?completions$/i.test(baseUrl)) {
123const headers = {
124'Content-Type': 'application/json',
125...(apiKey ? { 'Authorization': 'Bearer ' + apiKey } : {}),
126};
127const upstream = await fetch(endpoint, {
157// if (selectedRoute !== 'text') {
158// if (finalContent && finalContent.trim()) {
159// results = await extractOrRepairJsonResults(finalContent, apiKey, language);
160// }
161// if ((!results || results.length === 0)) {
167// reasoningText: '',
168// existingResults: []
169// }, apiKey);
170// if (Array.isArray(synthesized) && synthesized.length > 0) {
171// results = synthesized;
239// const textForExtraction = (collapsedContent && collapsedContent.trim()) ? collapsedContent : ((collapsedReasoning && collapsedReasoning.trim()) ? collapsedReasoning : '');
240// if (toolText && toolText.trim()) {
241// results = await extractResultsFromToolOutputs(toolText, apiKey, language);
242// }
243// if ((!results || results.length === 0) && textForExtraction) {
244// results = await extractOrRepairJsonResults(textForExtraction, apiKey, language);
245// }
246// if ((!results || results.length === 0)) {
252// reasoningText: String(collapsedReasoning || ''),
253// existingResults: []
254// }, apiKey);
255// if (Array.isArray(synthesized) && synthesized.length > 0) {
256// results = synthesized;
untitled-1522api.ts16 matches
29} from "../database/queries.ts";
3031const api = new Hono();
32const openai = new OpenAI();
3334// Middleware to ensure user is authenticated
35api.use('*', async (c, next) => {
36const email = c.req.header('X-LastLogin-Email');
37if (!email) {
4748// Get user's conversations
49api.get('/conversations', async (c) => {
50const user = c.get('user');
51const conversations = await getUserConversationsWithParticipants(user.id);
5455// Debug endpoint to check user status in a conversation
56api.get('/conversations/:id/status', async (c) => {
57const user = c.get('user');
58const conversationId = parseInt(c.req.param('id'));
7879// Get specific conversation with messages
80api.get('/conversations/:id', async (c) => {
81const user = c.get('user');
82const conversationId = parseInt(c.req.param('id'));
99100// Create new conversation
101api.post('/conversations', async (c) => {
102const user = c.get('user');
103const { title } = await c.req.json();
112113// Delete conversation
114api.delete('/conversations/:id', async (c) => {
115const user = c.get('user');
116const conversationId = parseInt(c.req.param('id'));
130131// Get conversation participants
132api.get('/conversations/:id/participants', async (c) => {
133const user = c.get('user');
134const conversationId = parseInt(c.req.param('id'));
152153// Invite user to conversation
154api.post('/conversations/:id/invite', async (c) => {
155const user = c.get('user');
156const conversationId = parseInt(c.req.param('id'));
194195// Send invitation email
196const inviteUrl = `${c.req.url.split('/api')[0]}/invite/${invite.invite_token}`;
197
198try {
218219// Remove participant from conversation
220api.delete('/conversations/:id/participants/:userId', async (c) => {
221const user = c.get('user');
222const conversationId = parseInt(c.req.param('id'));
248249// Send chat message
250api.post('/chat', async (c) => {
251const user = c.get('user');
252const { message, conversationId }: ChatRequest = await c.req.json();
326327// Get invite details (public endpoint)
328api.get('/invites/:token', async (c) => {
329const token = c.req.param('token');
330
348349// Accept invitation
350api.post('/invites/:token/accept', async (c) => {
351const user = c.get('user');
352const token = c.req.param('token');
381382// Server-Sent Events for real-time updates
383api.get('/conversations/:id/stream', async (c) => {
384const user = c.get('user');
385const conversationId = parseInt(c.req.param('id'));
437});
438439export default api;
untitled-1522README.md16 matches
1# Backend
23Hono-based API server with LastLogin authentication, SQLite database, and group chat functionality.
45## Structure
7- `index.ts` - Main HTTP handler with LastLogin wrapper
8- `database/` - Database migrations and query functions
9- `routes/` - API route handlers
1011## API Endpoints
1213### Authentication
14- All API routes require authentication via LastLogin
15- User email is extracted from `X-LastLogin-Email` header
1617### Conversations
18- `GET /api/conversations` - Get user's conversations (with participant info)
19- `GET /api/conversations/:id` - Get specific conversation with messages
20- `POST /api/conversations` - Create new conversation
21- `DELETE /api/conversations/:id` - Delete conversation (admin only)
2223### Group Chat Features
24- `GET /api/conversations/:id/participants` - Get conversation participants
25- `POST /api/conversations/:id/invite` - Invite user by email (admin only)
26- `DELETE /api/conversations/:id/participants/:userId` - Remove participant (admin only)
2728### Invitations
29- `GET /api/invites/:token` - Get invitation details (public)
30- `POST /api/invites/:token/accept` - Accept invitation and join conversation
3132### Chat & Real-time
33- `POST /api/chat` - Send message and get ChatGPT response
34- `GET /api/conversations/:id/stream` - Server-Sent Events for real-time updates
3536## Database Schema
49- **Automatic user creation** on first login
50- **Conversation history storage** with full message history
51- **ChatGPT integration** via OpenAI API
52- **Group chat functionality** with role-based permissions
53- **Email invitations** with secure tokens
untitled-1522README.md1 match
31## Project Structure
3233- `backend/` - Hono API server with authentication and group chat
34- `frontend/` - React chat interface with group features
35- `shared/` - Shared TypeScript types