untitled-3016chat.ts9 matches
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { getRecentMessages, createMessage } from "../database/queries.ts";
3import type { ChatMessage, ApiResponse } from "../../shared/types.ts";
45const chat = new Hono();
9try {
10const messages = await getRecentMessages(50);
11const response: ApiResponse<ChatMessage[]> = {
12success: true,
13data: messages
15return c.json(response);
16} catch (error) {
17const response: ApiResponse<ChatMessage[]> = {
18success: false,
19error: "Failed to fetch messages"
30// Basic validation
31if (!messageData.username || !messageData.message) {
32const response: ApiResponse<ChatMessage> = {
33success: false,
34error: "Username and message are required"
40const trimmedMessage = messageData.message.trim();
41if (trimmedMessage.length === 0) {
42const response: ApiResponse<ChatMessage> = {
43success: false,
44error: "Message cannot be empty"
4849if (trimmedMessage.length > 500) {
50const response: ApiResponse<ChatMessage> = {
51success: false,
52error: "Message too long (max 500 characters)"
58const trimmedUsername = messageData.username.trim();
59if (trimmedUsername.length === 0 || trimmedUsername.length > 50) {
60const response: ApiResponse<ChatMessage> = {
61success: false,
62error: "Username must be 1-50 characters"
70});
7172const response: ApiResponse<ChatMessage> = {
73success: true,
74data: newMessage
76return c.json(response, 201);
77} catch (error) {
78const response: ApiResponse<ChatMessage> = {
79success: false,
80error: "Failed to send message"
untitled-3016jobs.ts11 matches
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { getAllJobs, createJob, deleteJob } from "../database/queries.ts";
3import type { Job, ApiResponse } from "../../shared/types.ts";
45const jobs = new Hono();
9try {
10const jobList = await getAllJobs();
11const response: ApiResponse<Job[]> = {
12success: true,
13data: jobList
15return c.json(response);
16} catch (error) {
17const response: ApiResponse<Job[]> = {
18success: false,
19error: "Failed to fetch jobs"
31if (!jobData.title || !jobData.company || !jobData.description ||
32!jobData.location || !jobData.contact_email) {
33const response: ApiResponse<Job> = {
34success: false,
35error: "Missing required fields"
41const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
42if (!emailRegex.test(jobData.contact_email)) {
43const response: ApiResponse<Job> = {
44success: false,
45error: "Invalid email format"
4950const newJob = await createJob(jobData);
51const response: ApiResponse<Job> = {
52success: true,
53data: newJob
55return c.json(response, 201);
56} catch (error) {
57const response: ApiResponse<Job> = {
58success: false,
59error: "Failed to create job"
68const id = parseInt(c.req.param("id"));
69if (isNaN(id)) {
70const response: ApiResponse<boolean> = {
71success: false,
72error: "Invalid job ID"
77const deleted = await deleteJob(id);
78if (!deleted) {
79const response: ApiResponse<boolean> = {
80success: false,
81error: "Job not found"
84}
8586const response: ApiResponse<boolean> = {
87success: true,
88data: true
90return c.json(response);
91} catch (error) {
92const response: ApiResponse<boolean> = {
93success: false,
94error: "Failed to delete job"
20const fetchOrders = async () => {
21try {
22const response = await fetch('/api/orders');
23const result = await response.json();
24if (result.success) {
untitled-3016types.ts1 match
19}
2021export interface ApiResponse<T> {
22success: boolean;
23data?: T;
untitled-3016README.md8 matches
17β β βββ queries.ts # Database query functions
18β βββ routes/
19β β βββ jobs.ts # Job posting API routes
20β β βββ chat.ts # Chat API routes
21β βββ index.ts # Main Hono server
22βββ frontend/
32```
3334## API Endpoints
3536### Jobs
37- `GET /api/jobs` - Get all job postings
38- `POST /api/jobs` - Create a new job posting
39- `DELETE /api/jobs/:id` - Delete a job posting
4041### Chat
42- `GET /api/chat/messages` - Get recent chat messages
43- `POST /api/chat/messages` - Send a new chat message
4445## Database Schema
crm_OBUO_FARMSClientOrderForm.tsx6 matches
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, { useState, useEffect } from 'https://esm.sh/react@18.2.0';
3import type { CreateOrderRequest, ApiResponse, Order, Product } from '../../shared/types.ts';
45export default function ClientOrderForm() {
2324const productCategories = ['Fish', 'Poultry', 'Feed'] as const;
25const fishTypes = ['Catfish', 'Tilapia'] as const;
26const productForms = ['Fresh', 'Frozen', 'Live', 'Fillet', 'Smoked', 'Dried'] as const;
27const poultryTypes = ['Chicken (Whole)', 'Chicken (Parts)', 'Turkey', 'Guinea Fowl'] as const;
41const fetchProducts = async () => {
42try {
43const response = await fetch('/api/products');
44const result: ApiResponse<Product[]> = await response.json();
45if (result.success && result.data) {
46setProducts(result.data);
110111try {
112const response = await fetch('/api/orders', {
113method: 'POST',
114headers: {
118});
119120const result: ApiResponse<Order> = await response.json();
121122if (result.success && result.data) {
ChatuseAnthropicStream.tsx7 matches
86/* Anthropic SDK instance β memoised so we don't recreate each render */
87const anthropic = React.useMemo(() => {
88if (!config.anthropicApiKey) return null;
89return new Anthropic({
90dangerouslyAllowBrowser: true,
91apiKey: config.anthropicApiKey,
92baseURL: "https://api.anthropic.com", // explicit so it works with CORS preβflights
93defaultHeaders: {
94"anthropic-version": "2023-06-01",
95// Allow calling the API directly from the browser β you accept the risk!
96"anthropic-dangerous-direct-browser-access": "true",
97},
98});
99}, [config.anthropicApiKey]);
100101/* Abort helper */
110const send = React.useCallback(
111async (history: Message[], userText: string): Promise<AssistantMsg> => {
112if (!anthropic) throw new Error("API key missing");
113if (status !== "idle") throw new Error("Stream already in progress");
114135})) as AsyncIterable<MessageStreamEvent>;
136} catch (err: any) {
137console.error("Failed to call Anthropic API", err);
138throw err;
139}
112model: string;
113max_tokens: number;
114anthropic_api_key: string;
115mcp_servers?: Array<{
116type: string;
ChatStreamingChat.tsx8 matches
179/** Retry a user message */
180const retryMessage = async (messageId: string) => {
181if (status !== "idle" || !config.anthropicApiKey) return;
182183const userText = onRetryFromMessage(messageId);
202/** Dispatch user input */
203const fireSend = async () => {
204if (!input.trim() || status !== "idle" || !config.anthropicApiKey) return;
205206const userText = input.trim();
309};
310311const canSend = input.trim() && status === "idle" && config.anthropicApiKey;
312313/* ββ UI βββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
315<>
316<div className="chat-messages">
317{!config.anthropicApiKey && (
318<div className="message system">
319Please configure your Anthropic API key in settings to start chatting
320</div>
321)}
383}}
384onKeyDown={handleKeyDown}
385placeholder={config.anthropicApiKey
386? streaming
387? "Press Enter to stop streamingβ¦"
388: "Type your messageβ¦"
389: "Configure API key in settings first"}
390className="chat-input"
391disabled={!config.anthropicApiKey || thinking}
392rows={1}
393/>
ChatSettings.tsx7 matches
1819export default function Settings({ config, onUpdateConfig, onClose }: SettingsProps) {
20const [apiKey, setApiKey] = useState(config.anthropicApiKey);
21const [mcpServers, setMcpServers] = useState<MCPServer[]>(config.mcpServers);
22const [selectedModel, setSelectedModel] = useState(config.selectedModel);
37const handleSave = () => {
38onUpdateConfig({
39anthropicApiKey: apiKey,
40mcpServers: mcpServers,
41selectedModel: selectedModel,
141</div>
142143{/* API Key Section */}
144<div className="form-group">
145<label className="form-label">Anthropic API Key</label>
146<input
147type="password"
148value={apiKey}
149onChange={(e) => setApiKey(e.target.value)}
150placeholder="sk-ant-..."
151className="form-input"
152/>
153<div className="text-sm text-gray-600 mt-1">
154Get your API key from{" "}
155<a
156href="https://console.anthropic.com/"