Snotel-AnalyzerREADME.md6 matches
1# SNOTEL Data Viewer
23A web application that displays the latest SNOTEL (Snow Telemetry) data from USDA's AWDB REST API.
45## Features
7- Displays latest snow and weather data from SNOTEL sites
8- Interactive table with site information
9- Real-time data fetching from USDA AWDB API
1011## Project Structure
1213- `backend/index.ts` - Main Hono server with API endpoints
14- `frontend/index.html` - Main HTML template
15- `frontend/index.tsx` - React frontend application
16- `shared/types.ts` - Shared TypeScript types
1718## API Endpoints
1920- `GET /` - Serves the main application
21- `GET /api/sites` - Fetches SNOTEL site data
22- `GET /api/data/:stationId` - Fetches latest data for a specific station
2324## Usage
1import { Hono } from "npm:hono";
23// Import route modules
4import cobrowse from "./getCobrowseStatus.ts";
5import database from "./getDatabase.ts";
15});
1617// Gigya API Configuration
18const GIGYA_DOMAIN = Deno.env.get("GIGYA_DOMAIN") || "accounts.eu1.gigya.com";
19const GIGYA_API_KEY = Deno.env.get("GIGYA_API_KEY") || "";
20const GIGYA_APP_KEY = Deno.env.get("GIGYA_APP_KEY") || "";
21const GIGYA_APP_SECRET = Deno.env.get("GIGYA_APP_SECRET") || "";
2223if (!GIGYA_API_KEY || !GIGYA_APP_KEY || !GIGYA_APP_SECRET) {
24console.warn("Missing Gigya environment variables. Some features may not work.");
25}
2627// Direct Gigya API functions
28async function makeGigyaRequest(endpoint: string, params: Record<string, any>): Promise<any> {
29const url = `https://${GIGYA_DOMAIN}/${endpoint}?httpStatusCodes=true`;
3031const body = new URLSearchParams({
32apiKey: GIGYA_API_KEY,
33userKey: GIGYA_APP_KEY,
34secret: GIGYA_APP_SECRET,
5051if (result.errorCode !== 0) {
52throw new Error(`Gigya API Error ${result.errorCode}: ${result.errorMessage || "Unknown error"}`);
53}
54394});
395396// API Routes
397398// Get account info
399app.get("/api/account/:uid", async (c) => {
400try {
401const uid = c.req.param("uid");
413414// Search accounts
415app.get("/api/search", async (c) => {
416try {
417const query = c.req.query("q") || "";
430431// Update account
432app.put("/api/account/:uid", async (c) => {
433try {
434const uid = c.req.param("uid");
443444// Import account
445app.post("/api/account/import", async (c) => {
446try {
447const body = await c.req.json();
454455// Get schema
456app.get("/api/schema", async (c) => {
457try {
458const schema = await getSchema();
464465// Update schema
466app.put("/api/schema", async (c) => {
467try {
468const body = await c.req.json();
475476// Health check
477app.get("/api/health", (c) => {
478return c.json({
479success: true,
Loudaily_lineup_scheduler.tsx23 matches
22}
2324export interface YahooAPIConfig {
25access_token: string;
26refresh_token: string;
94}
9596// Initialize Yahoo Fantasy API client
97const yahooAPI = new YahooFantasyAPIClient(tokenData, this.tokenStorage, userId);
9899// Get user's leagues
100const leagues = await yahooAPI.getUserLeagues(userId);
101console.log(`🏟️ Found ${leagues.length} leagues for user ${userId}`);
102106107// Get user's team in this league
108const teamKey = await yahooAPI.getTeamKey(userId, league.league_id);
109if (!teamKey) {
110throw new Error(`Could not find team key for league ${league.league_id}`);
112113// Schedule pitchers for today
114const scheduleResult = await this.schedulePitchersForTeam(yahooAPI, teamKey, date);
115116results.leagues_processed.push({
134}
135136private async schedulePitchersForTeam(yahooAPI: YahooFantasyAPIClient, teamKey: string, date: Date) {
137// Get today's probable pitchers from MLB API
138const probablePitchers = await this.getTodaysProbablePitchers(date);
139console.log(`🎯 Found ${probablePitchers.length} probable pitchers for ${date.toDateString()}`);
140141// Get current team roster
142const roster = await yahooAPI.getTeamRoster(teamKey);
143console.log(`👥 Team roster has ${roster.length} players`);
144161for (const change of optimization.changes) {
162try {
163await yahooAPI.setPlayerPosition(teamKey, change.playerId, change.newPosition);
164results.pitchers_scheduled.push(change.playerId);
165results.changes_made.push(change);
181): Promise<Array<{ name: string; team: string; game_time?: string }>> {
182try {
183// Call MLB Stats API for probable pitchers
184const dateStr = date.toISOString().split("T")[0];
185const response = await fetch(
186`https://statsapi.mlb.com/api/v1/schedule?sportId=1&date=${dateStr}&hydrate=probablePitcher`,
187);
188189if (!response.ok) {
190throw new Error(`MLB API error: ${response.status}`);
191}
192326}
327328// Simplified Yahoo Fantasy API client for Val.town
329class YahooFantasyAPIClient {
330private config: YahooAPIConfig;
331private baseUrl = "https://fantasysports.yahooapis.com/fantasy/v2";
332private tokenStorage: LouTokenStorage;
333private userId: string;
334335constructor(config: YahooAPIConfig, tokenStorage: LouTokenStorage, userId: string) {
336this.config = config;
337this.tokenStorage = tokenStorage;
351private async refreshAccessToken(): Promise<void> {
352try {
353const response = await fetch("https://api.login.yahoo.com/oauth2/get_token", {
354method: "POST",
355headers: {
419420if (!retryResponse.ok) {
421throw new Error(`Yahoo API error after refresh: ${retryResponse.status} ${retryResponse.statusText}`);
422}
423426427if (!response.ok) {
428throw new Error(`Yahoo API error: ${response.status} ${response.statusText}`);
429}
430513514async setPlayerPosition(teamKey: string, playerId: string, position: string): Promise<void> {
515// Yahoo Fantasy API requires PUT/POST for roster changes
516const response = await fetch(`${this.baseUrl}/teams;team_keys=${teamKey}/roster/players;player_keys=${playerId}`, {
517method: "PUT",
558559// Store results in Val.town's blob storage for history
560await fetch("https://api.val.town/v1/blob/scheduler_results", {
561method: "POST",
562headers: {
osAccountViewer.tsx1 match
169{Object.entries(account.profile).map(([key, value]) => (
170<div key={key}>
171<dt class="text-sm font-medium text-gray-500 capitalize">
172{key.replace(/([A-Z])/g, ' $1').trim()}
173</dt>
osAccountForm.tsx1 match
51export function AccountForm({ schema, account, isImport = false }: AccountFormProps) {
52const formId = isImport ? "import-form" : "edit-form";
53const submitUrl = isImport ? "/api/account/import" : `/api/account/${account?.UID}`;
54const method = isImport ? "POST" : "PUT";
55
townie-126val-summary.ts3 matches
18SUM(num_images) as total_images
19FROM ${USAGE_TABLE}
20WHERE val_id = ? AND our_api_token = 1
21GROUP BY val_id
22`, [valId]);
34FROM ${INFERENCE_CALLS_TABLE} i
35JOIN ${USAGE_TABLE} u ON i.usage_id = u.id
36WHERE u.val_id = ? AND u.our_api_token = 1
37GROUP BY u.val_id
38`, [valId]);
41const requestsResult = await sqlite.execute(`
42SELECT * FROM ${USAGE_TABLE}
43WHERE val_id = ? AND our_api_token = 1
44ORDER BY timestamp DESC
45`, [valId]);
townie-126val-detail.ts1 match
18finish_reason?: string;
19num_images?: number;
20our_api_token: boolean;
21}
22
townie-126useUser.tsx1 match
1import { useState, useEffect } from "react";
23const USER_ENDPOINT = "/api/user";
45export function useUser() {
townie-126user-summary.ts2 matches
20SUM(num_images) as total_images
21FROM ${USAGE_TABLE}
22WHERE our_api_token = 1
23`;
24
41FROM ${INFERENCE_CALLS_TABLE} i
42JOIN ${USAGE_TABLE} u ON i.usage_id = u.id
43WHERE u.our_api_token = 1
44`;
45