sparky 2.3.1
sparky: ^2.3.1 copied to clipboard
Sparky é pacote que ajuda na construção de apis rest de forma simples com suporte a websocket a autenticação jwt.
2.3.1 #
Documentação #
- README (PT + EN): Adicionadas seções para as features já presentes no pacote e que não estavam documentadas no README: OpenAPI / Swagger UI, CSRF protection, Métricas Prometheus, Health checks e Task scheduling (cron + intervalo). Cada seção traz exemplo mínimo de configuração, comportamento padrão e observações de produção (CDN da CSP do
/docs,cookieSecureem dev, agregação de séries em cluster, exactly-once em scheduler). A lista de Features no topo dos dois READMEs foi atualizada com os bullets correspondentes. Nenhuma mudança de código.
2.3.0 #
Breaking Changes #
- CSRF:
cookieSecuredefault agora étrue:CsrfConfig().cookieSecurepassou defalseparatrue. O cookiesparky_csrfsó será enviado em HTTPS por padrão. Em desenvolvimento local sem TLS, passeCsrfConfig(cookieSecure: false)explicitamente.
Novas Funcionalidades #
- Health checks (
/health+/ready): NovoHealthCheckConfigemSparky.singlecom endpoints built-in para liveness e readiness. Cada check é umHealthCheckplugável executado em paralelo com timeout configurável; exceções e timeouts viramHealthStatus.downautomaticamente. Status geral agrega o pior resultado (DOWN > DEGRADED > UP), com HTTP503quandoDOWN(e opcionalmente quandoDEGRADEDviafailReadinessOnDegraded). SuportaauthGuardpara proteger os probes. Body JSON no formato{status, checks: {name: {status, message?, details?}}}. - Task scheduling (cron + intervalo): Novo
SchedulerConfigemSparky.single.ScheduledTask(expression: '0 */5 * * *', job: ...)para cron de 5 campos (com aliasesjan-dec/sun-sat, ranges, listas e*/N) eScheduledTask.every(interval: Duration(...), job: ...)para cadência fixa. Scheduler sobe junto com o servidor e para emclose()aguardando jobs em voo.onErrorrecebe exceções sem derrubar o loop;allowOverlapcontrola se ticks rodam em paralelo (defaulttrueno cron,falsenoevery). MetricsConfig.authGuard: Novo campo opcionalMiddlewareNullable? authGuardemMetricsConfigque, quando fornecido, é anexado à rota/metricscomo guard. Protege o scrape contra acesso não autenticado (ex.: validar token bearer, IP allowlist) sem precisar expor um listener separado.OpenApiOperation.parameters: Novo campoList<Map<String, Object?>>? parametersemOpenApiOperationpara documentar parâmetros de query, header e cookie. São mescladas com os path params auto-gerados; em caso de colisão (name|in), o valor do usuário prevalece — isso permite refinar oschemade path params (ex.:integer/uuidem vez do defaultstring).
Correções #
- Cache de response vs. guards: Rotas estáticas com
guardsnão-vazios não são mais cacheadas. O cache anterior armazenava a primeira response (tipicamente o 401 de um guard que rejeitava) e a servia para todas as chamadas subsequentes, anulando o guard. AgoraisCachedé consultado apenas quandoroute.guards.isEmpty. - Swagger UI em
/docsficava em branco comSecurityHeadersConfig: A CSP default (default-src 'self') bloqueava o CDN e o script inline do Swagger UI. A rota/docsagora emite umContent-Security-Policypróprio que libera a origem doswaggerUiCdnBase(scripts/styles/imgs/fonts) e mantémconnect-src 'self'para o fetch do spec — a CSP global continua valendo para as demais rotas.
2.2.0 #
Novas Funcionalidades #
- Parser multipart robusto: Parsing real de
multipart/form-datacom suporte a upload de arquivos binários.request.getMultipartData()retornaMultipartDatacomfields(Map<String, String>) efiles/fileList(Map/List deUploadedFile). Parser opera em bytes brutos (binary-safe).UploadedFileexpõefilename,bytes,contentTypeesize. - Streaming de response (SSE):
Response.sse(stream)para Server-Sent Events eResponse.stream(body: stream)para download/streaming de arquivos grandes.SseEventserializa no formato SSE wire protocol com suporte adata,event,ideretry. - Tratamento de erros estruturado: Exceções tipadas (
NotFound,BadRequest,Forbidden,Unauthorized,Conflict,UnprocessableEntity,TooManyRequests,InternalServerError,BadGateway,ServiceUnavailable) que mapeiam automaticamente para HTTP status codes com body JSON padronizado.throw NotFound(message: 'User not found')vira 404 com{"errorCode": "404", "message": "User not found"}. - Dependency injection por request:
request.provide<T>(value)/request.read<T>()/request.tryRead<T>()via Expando. Armazenamento por tipo, escopo por request. Funciona em guards, pipeline middlewares e handlers. - Suporte a isolates (cluster mode):
Sparky.cluster(factory, isolates: 4)cria N isolates compartilhando a mesma porta. Factory deve ser função top-level ou estática. RetornaSparkyClustercom.porte.close(). Default:Platform.numberOfProcessorsisolates. - Security headers (Helmet-style):
SecurityHeadersConfig().createMiddleware()adiciona headers de segurança padrão — X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security, Content-Security-Policy, Referrer-Policy, Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy e mais. Todos configuráveis individualmente. - Test utilities:
SparkyTestClientque boota o servidor numa porta OS-assigned (port 0) com API limpa para GET/POST/PUT/PATCH/DELETE/HEAD. Importável viapackage:sparky/testing.dart.
Breaking Changes #
Sparky.serverrenomeado paraSparky.single: O construtor principal agora éSparky.single(...).Sparky.servernão existe mais.
2.1.0 #
Melhorias de Segurança #
- CORS corrigido conforme a spec:
Access-Control-Allow-Originnão aceita múltiplas origins separadas por vírgula. Agora o middleware verifica oOrigindo request e reflete a origin permitida. QuandoallowCredentials: truecom wildcard, reflete a origin do request ao invés de*(conforme exigido pela spec). HeaderVary: Originadicionado quando a resposta varia por origin. - JWT: remoção de padding base64url (RFC 7515/7519): Tokens gerados agora usam base64url sem padding (
=), conforme exigido pelas RFCs. Tokens antigos com padding continuam sendo decodificados viabase64Url.normalize(). - JWT: validação de algoritmo no
verifyToken: Previne ataques de algorithm confusion — agora verifica que o header especificaHS256antes de aceitar o token.
Melhorias #
- Gzip em stream responses: Responses baseadas em
Stream<List<int>>(ex: arquivos estáticos viaStaticFiles) agora são comprimidas com gzip quandoenableGzip: truee o content-type é comprimível (text/*, application/json, etc.). Binários como imagens não são comprimidos. RateLimiter.maxClientsobrigatório com default: Antes eraint?— agora éintcom default10000, garantindo que o mapa de clientes nunca cresce indefinidamente.- Encapsulamento do cache:
cacheManagerpúblico substituído por_cacheManagerprivado com métodos públicosisCached(),getCachedResponse()ecacheResponse(). Sparky.actualPort: Nova propriedade para obter a porta real quando usandoport: 0(porta atribuída pelo OS).- Reorganização de
Response: Construtores mais usados (created,internalServerError,noContent,tooManyRequests,serviceUnavailable, etc.) separados no topo. Construtores raramente usados marcados com@Deprecatedcom mensagem indicando o construtor genérico.
Breaking Changes #
MiddlewareNulablerenomeado paraMiddlewareNullable: Correção de typo no typedef público. AtualizeMiddlewareNulable→MiddlewareNullableno seu código.RateLimiter.maxClientsagora éint(não maisint?). O default10000mantém o comportamento anterior para quem não passava o parâmetro.SparkyBase.cacheManagernão é mais acessível publicamente. UseisCached(),getCachedResponse()ecacheResponse().
Testes #
- Adicionados testes para CORS (multi-origin, origin não permitida, wildcard, credentials + wildcard, preflight).
- Adicionados testes para gzip em stream responses (text comprimido, binário não comprimido).
- Adicionado teste para tokens JWT sem padding base64url.
- Todos os testes migrados de portas hardcoded para
port: 0+server.actualPort, eliminando colisões de porta em CI. - Total: 105 testes passando.
2.0.1 #
Correções de Bugs #
- Cache em rotas dinâmicas: Rotas com path parameters (
:param) não são mais cacheadas, corrigindo bug onde/users/2retornava os dados de/users/1(cache usava o objetoRoutecomo chave, ignorando os parâmetros reais). RouteGroup.flatten()perdiaacceptedMethods: Rotas criadas comRouteHttp.get()dentro de umRouteGrouppassavam a aceitar todos os métodos HTTP após oflatten(). Agora oacceptedMethodsé preservado corretamente.- CORS double close: O middleware de CORS fechava
request.responsediretamente e depois retornava umResponse, fazendo o servidor tentar escrever na response já fechada (HttpException: HTTP headers are not mutable). Agora o preflight OPTIONS retorna umResponsecom os headers CORS sem manipular a response diretamente, e opipelineAfterexecuta normalmente.
2.0.0 #
Correções de Bugs #
runPipeline: Corrigida condição que sempre avaliava comotrue(!= nulltrocado por checagem correta deisNotEmpty).- Sistema de logs: Reestruturada a lógica dos métodos
_openServerLog,_errorServerLoge_requestServerLogpara que o modoLogConfig.writeLogsfuncione corretamente (antes o arquivo de log nunca era criado nesse modo). - Status 405: Corrigido handler de "Method Not Allowed" que retornava status 404 em vez de 405.
- Estado global no
RequestTools: Removidas variáveis top-level mutáveis (_hashe_cache) compartilhadas entre requisições concorrentes, substituídas porExpandopara isolamento por request. _start()async void: Corrigido paraFuture<void>, com validações síncronas no construtor e binding assíncrono observável viaserver.ready.- JSON inválido nos erros: Bodies de erro internos agora usam JSON válido com aspas duplas em vez de aspas simples.
- Objetos
Routetemporários: Removida criação desnecessária deRoute('/404', ...)eRoute('/405', ...)no_internalHandler, retornandoResponsediretamente.
Novas Funcionalidades #
- Rotas dinâmicas com path parameters: Suporte a segmentos dinâmicos usando sintaxe
:param(ex:/users/:id,/products/:category/:itemId). Parâmetros acessíveis viarequest.pathParams['id']. - Parsing de JSON body e URL-encoded: Novos métodos
getJsonBody()(retornaMap<String, dynamic>),getFormData()(paraapplication/x-www-form-urlencoded) egetRawBody()(body cru com cache) na extensionRequestTools. - Suporte a CORS: Nova classe
CorsConfigcom construtoresCorsConfig()eCorsConfig.permissive(), e métodocreateMiddleware()para adicionar ao pipeline. Trata preflightOPTIONSautomaticamente. - Headers customizados na Response: Novo campo opcional
Map<String, String>? headersem todos os construtores deResponse, aplicados automaticamente na resposta HTTP. - JWT com expiração e decodificação:
generateToken()agora aceitaDuration? expiresIne adiciona claimsiateexp.verifyToken()valida expiração automaticamente. Novo métododecodePayload()para extrair dados do token. - Agrupamento de rotas (RouteGroup): Nova classe
RouteGroupque permite agrupar rotas sob um prefixo comum (ex:RouteGroup('/api/v1', routes: [...]).flatten()). - Serialização automática para JSON: O
bodydaResponseagora aceitaObject(String, Map, List). Valores não-String são serializados automaticamente comjson.encode. - Graceful shutdown: Novo método
close()noSparkypara encerrar o servidor de forma limpa, cancelando a subscription e fechando o arquivo de log. - try-catch global: Erros não tratados em middlewares/handlers agora retornam
500 Internal Server Errorem vez de travar o servidor. - Cache diferenciado por método HTTP: O cache agora usa a combinação de
Route+ método HTTP como chave, evitando que GET e POST na mesma rota compartilhem cache. - Nome do arquivo de log configurável: Novo parâmetro
logFilePathno construtor deSparky.server(padrão:'logs.txt'). pipelineAfterem WebSocket: OpipelineAfteragora também é executado após conexões WebSocket.server.ready: Nova propriedadeFuture<void> get readypara aguardar o servidor estar pronto.
Testes #
- Adicionados 42 testes unitários e de integração cobrindo: validação de rotas, Response (status codes, auto-serialização, headers), JWT (geração, verificação, expiração, decodificação), route matching (estático e dinâmico), cache versioning, RouteHttp, RouteGroup, Pipeline, CorsConfig, integração HTTP completa (GET, POST, 404, 405, path params) e graceful shutdown.
Breaking Changes #
- O campo
bodydeResponseagora é do tipoObjectinternamente (acessado via getterString get body). Código existente que usaStringcontinua funcionando sem alterações. _CacheManageragora requer o método HTTP como parâmetro emverifyVersionCache,getCacheesaveCache.- O construtor
Sparky.serveragora aceitalogFilePathcomo parâmetro opcional.
1.1.1 #
- update packages!!!
1.1.0 #
- Cache Adicionado!!!
1.0.15 #
- Foram adicionados os metodos de requisição web que faltavam.
1.0.14 #
- export necessario para usar criar rotas com herança de route.
1.0.13 #
- Correção de bug em websocket quando ela recebe uma request get,post,put ou delete.
1.0.12 #
- Melhoria nos construtores de rotas.
1.0.11 #
- Topico novo adicionado no pubspec, e pequenas correções em construtores e nomes.
1.0.10 #
- Topicos adicionados no pubspec.
1.0.9 #
- Melhoria na doc da Pagina inicial.
1.0.8 #
- Mais opções de responses com contrutores com status prontos, melhoria no código de exemplo a parte do login jwt não estava de maneira adequada antes.
1.0.7 #
- Melhoria na função de validação de rotas repetidas.
1.0.6 #
- A vesão anterior foi com um commit a menos 😅
1.0.5 #
- Melhoria no sistema de busca de rotas antes a cada request ele fazia um lop de complexidade O(N) para achar a rota correta e executada, agora todas rotas são pré-carregadas no início da função em um map e acessadas diretamente com a complexidade O(1) o que entrega mais performance é mais perceptível em casos de grandes números de rotas.
1.0.4 #
- Melhoria no sistema de logs, agora ele não fecha o arquivo e reabre toda vez que precisar salvar uma nova informação.
1.0.3 #
- Correção de exemplo.
1.0.2 #
- Add doc english.
1.0.1 #
- Uptade doc.
1.0.0 #
- Initial version.