HASS.Agent .NET10
A modern, lightweight Windows companion for Home Assistant: notifications, media control, sensors, commands, and one-click updates.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Los lugares que has visitado en el mundo, con lo que hiciste en cada uno. En el globo eliges un país, luego el departamento y luego el municipio, y ahí escribes la visita como un post de blog: el relato, las fotos y los lugares exactos donde estuviste. El mapa se va pintando a medida que viajas (Nicaragua: 9 de 17 departamentos). Si quieres, publicas una visita o un viaje, y otras personas guardan esos lugares en su lista "Quiero ir". Producción: https://traveltime-tan.vercel.app (un push a main despliega solo).查看完整 README ↗
Los lugares que has visitado en el mundo, con lo que hiciste en cada uno. En el globo eliges un país, luego el departamento y luego el municipio, y ahí escribes la visita como un post de blog: el relato, las fotos y los lugares exactos donde estuviste. El mapa se va pintando a medida que viajas (Nicaragua: 9 de 17 departamentos). Si quieres, publicas una visita o un viaje, y otras personas guardan esos lugares en su lista "Quiero ir".
Producción: https://traveltime-tan.vercel.app (un push a main despliega solo).
Mismo stack que deudas: sin build, funciones serverless de Vercel y Turso/libSQL. Las fotos van a Cloudflare Images y los mapas a S3 detrás de CloudFront.
Portada (#/) | Encabezado con el globo girando detrás, cómo funciona, recomendaciones, últimos lugares publicados y, con cuenta, tu resumen y tu lista "Quiero ir". Botón "Instalar app" |
Mapa (#/mundo) | Globo → país → departamento → ciudad para 198 países, búsqueda, filtro en las listas largas, tres estilos de fondo |
Visita (#/NIC.granada.granada/v/12) | Relato por bloques, galería, lugares (pines), sugerencia de fechas desde las fotos, publicar, viaje al que pertenece |
Modo escritura (…/v/12/editar) | Editor tipo blog a pantalla completa, con borrador en el teléfono |
Viaje (#/viaje/3) | Visitas agrupadas: ruta numerada en el mapa y línea de tiempo |
Publicado (#/p/12, #/t/3) | Una visita o un viaje vistos por cualquiera, con "Quiero ir", "Ya estuve", compartir y PDF |
| Endpoint | Qué hace |
|---|---|
api/auth.js | Entrar con Google, salir, y el perfil (nombre, avatar, "Sobre mí"). La contraseña queda solo para cuentas de antes que aún no conectan Google |
api/marks.js | Lo visitado: lo marcado más los lugares que tienen visitas |
api/visits.js | Visitas de un lugar o de lo que hay dentro (por prefijo del id); publicar; "Ya estuve" (fromPinId) |
api/photos.js | Fotos de una visita: pedir la subida, confirmarla, pie de foto y borrar |
api/pins.js | Lugares puntuales de una visita (ver, comer, dormir, hacer, otro) |
api/trips.js | Viajes: crear, renombrar, meter y sacar visitas, publicar; compañeros (invitar por usuario, aceptar, sacar, salir) |
api/wishes.js | "Quiero ir": desde un lugar publicado o un municipio entero |
api/public.js | Lo publicado, sin sesión: portada, visita, viaje y lugares dentro de un lugar |
El código compartido va en api/_lib/, no en un lib/ en la raíz: Vercel publica como archivo estático todo lo de la raíz, y en el primer despliegue /lib/auth.js se podía descargar. api/ no se publica, y lo que empieza con _ no se vuelve función. Son 8 funciones de las 12 del plan Hobby.
npm test # ~215 pruebas contra los handlers reales: base descartable y Cloudflare simulado
npm run dev # http://localhost:3100, con las claves del .env (contra Turso si estan)
scripts/dev.mjs aplica las mismas cabeceras de vercel.json, así que lo que choca con la CSP falla en local igual que en producción. Los handlers se importan una vez: si tocas api/, reinicia el servidor. Para pruebas de punta a punta sin ensuciar Turso, levanta otro servidor con un .env sin TURSO_* ni RESEND_* (PORT=3101).
GOOGLE_CLIENT_ID, el ID de cliente OAuth de tipo Aplicación web; no hace falta el secreto). El navegador recibe de Google un ID token firmado y el servidor lo verifica (api/_lib/google.js): firma RS256 con las claves públicas de Google, aud, emisor, vencimiento y correo verificado. El usuario sale del correo (rosa.perez, rosa.perez2…). El registro con contraseña está cerrado (ALLOW_PASSWORD_SIGNUP=1 lo abre, solo lo usan las pruebas) y la contraseña solo abre cuentas que todavía no conectaron Google: mientras quede alguna, la ventana de entrar muestra "¿Tu cuenta es de antes?" (legacyLogin en ?config=1) y desaparece sola. Una cuenta de Google solo se une sola a una existente si el correo de esa cuenta estaba verificado: si no, quien se registró con un correo ajeno se quedaría con la cuenta de su dueño.#/perfil, y el público en #/u/usuario): avatar (inicial, ícono con color, la foto de Google, que se guarda en cada entrada, o una foto subida a Cloudflare, validada como propia), nombre, y el "Sobre mí" (presentación, dónde vive, idiomas, intereses de una lista fija, viaje soñado; api/_lib/profile.js). El público muestra solo eso y lo publicado: nunca marcas, visitas privadas, correo ni "Quiero ir".api/_lib/public.js. Sale el título, el lugar, las fechas, el relato, las fotos, los lugares y el @usuario. No salen el GPS ni la hora exacta de las fotos (solo el día), el correo, el nombre completo ni ids internos. Las pruebas buscan esas cadenas en la respuesta.@usuario; la invitación aparece en la portada y en el panel. Al aceptar, el compañero lee todas las visitas del viaje (relato, fotos y lugares, sin el GPS de las fotos, que es solo de su dueño) y suma las suyas. No edita, borra, publica ni saca del viaje lo ajeno, y no renombra, publica ni borra el viaje. Salirse (o que lo saquen) deja sus visitas suyas, fuera del viaje. Un invitado que no aceptó no ve nada. La regla vive en tripRole y readableVisit (api/_lib/trips.js).no-cache) y el CDN de Vercel guarda un minuto (Vercel-CDN-Cache-Control). Con stale-while-revalidate en Cache-Control, Chrome seguía mostrando hasta 5 minutos una visita despublicada. Un 404 no lo guarda nadie, porque si no ocultaría una visita recién publicada.Editor.js (en vendor/editorjs/, se carga al abrir el modo escritura): texto, títulos, listas (con viñetas, numeradas y de tareas), citas, separadores, y tres bloques propios: aviso con ícono, foto de la galería (o subida ahí mismo) y lugar de la visita. Al seleccionar texto: negrita, cursiva, resaltado y enlace.
api/_lib/story.js) y el navegador vuelve a limpiar al mostrar (js/story.js). Son dos cercos, porque lo publicado lo lee cualquiera.Viven en Cloudflare Images; en la base queda lo necesario para listarlas.
requireSignedURLs): cada URL va firmada con HMAC y vence a las 4 horas. Sin firma o con la firma vencida, Cloudflare responde 403. Esto está probado contra Cloudflare real.npm run cf:setup, una vez): ttthumb 400², ttcard 960×640 y ttfull hasta 2560. Llevan el prefijo tt porque las variantes son de toda la cuenta de Cloudflare, que se comparte con otros proyectos. Se entregan sin metadatos.El esquema se crea solo (CREATE TABLE IF NOT EXISTS y ALTER idempotentes). Las FOREIGN KEY no son una cascada confiable en Turso: el PRAGMA es por conexión y el cliente web no la mantiene. Por eso borrar una visita borra a mano sus fotos, lugares y viaje.
país → división 1 → "ciudad" → lugares (pines)
NIC Granada Granada Convento San Francisco, Isletas…
name:es. Motor: MapLibre en vendor/.scripts/build-geo.mjs: municipio (ADM2) en Nicaragua, comuna (ADM3) en Chile, cantón en Costa Rica, municipio (ADM3) en España, condado en EE. UU.NIC › NIC.granada › NIC.granada.granada. Lo visitado se cuenta por prefijo. El id sale del nombre limpio, no del shapeID de geoBoundaries, que cambia entre versiones y haría perder las visitas.geo/<ISO>/c/<depto>.json). Brasil tiene 5.570 municipios y España 8.205.lx/ly), no en el centroide, que en una media luna cae afuera.merge funde las partes de una ciudad dentro de un departamento grande (las 34 comunas del Gran Santiago, los 33 boroughs de Londres, los 23 distritos de Budapest) y whole deja sin partir los departamentos que ya son una ciudad (Ciudad de México, CABA, Montevideo, Seúl, Tokio, Bangkok…). Se eligieron a mano: juntar todo lo que cae en una misma mancha urbana fundía también la Costa Brava o Kamakura con Yokohama.fixMojibake).npm run geo # todo (~15 min; baja a .geo-cache/)
npm run geo -- NIC BRA # solo esos países
npm run geo:upload # sube geo/ a S3 (claves de AWS en .env)
npm run geo:upload -- --prune # y borra las versiones viejas (deja la actual y la anterior)
npm run vendor # después de actualizar maplibre-gl o @editorjs/*
Son ~140 MB y ~3.100 archivos, así que no van en git ni en Vercel (geo/ está en .gitignore y en .vercelignore). Van al bucket traveltimealfa (us-east-2) y la app los lee de https://d1kbjmlkyfoz97.cloudfront.net (js/config.js).
geo/<versión>/…), con caché de un año. geo/version.json se sube al final y sin caché, así que nadie ve una versión a medias.search.json: 2,7 MB → 746 KB)./geo. Con ?geo=remoto se lee de CloudFront, para probar una subida sin desplegar.manifest.webmanifest, íconos (scripts/make-icons.mjs, dibujados píxel a píxel sin dependencias) y sw.js:
/api y las fotos nunca se guardan en el teléfono.geo.js usa la última versión de los mapas que conoció, que es la que el service worker tiene.Coral para lo visitado y el progreso; tierra y agua frías a propósito. Globo con atmósfera en el mundo. Tres fondos (Claro, Oscuro, Colorido) más Automático, y la interfaz sigue al mapa. Animaciones al hacer scroll, con prefers-reduced-motion respetado. "Quiero ir" en el mapa es un anillo ámbar.
node scripts/place-renames.mjs <copia-de-geo-vieja> > renames.jsonnode --env-file=.env scripts/migrate-place-ids.mjs renames.json--apply