yuzuha 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/README.md +154 -115
- package/VERSIONING.md +47 -7
- package/benchmarks/compare.mjs +8 -2
- package/benchmarks/parser.mjs +66 -0
- package/benchmarks/performance.mjs +87 -0
- package/benchmarks/refinement.mjs +99 -0
- package/benchmarks/results/v0.1.6/performance-0.1.5.json +205 -0
- package/benchmarks/results/v0.1.6/performance-0.1.6.json +263 -0
- package/benchmarks/results/v0.1.6/refinement-audio.json +147 -0
- package/benchmarks/results/v0.1.6/refinement-final-repeat.json +147 -0
- package/benchmarks/results/v0.1.6/refinement-final.json +147 -0
- package/benchmarks/results/v0.1.6/refinement-initial.json +117 -0
- package/benchmarks/results/v0.1.6/runtime-0.1.5.json +341 -0
- package/benchmarks/results/v0.1.6/runtime-0.1.6-refined.json +406 -0
- package/benchmarks/results/v0.1.6/runtime-0.1.6-repeat.json +406 -0
- package/benchmarks/results/v0.1.6/runtime-0.1.6.json +406 -0
- package/benchmarks/results/v0.1.7/parser-comparison.json +170 -0
- package/bridges/lavalink/README.md +101 -0
- package/bridges/lavalink/application.yml +20 -0
- package/bridges/lavalink/build.mjs +38 -0
- package/bridges/lavalink/integration.mjs +161 -0
- package/bridges/lavalink/results/node22.json +39 -0
- package/bridges/lavalink/results/node26.json +39 -0
- package/bridges/lavalink/src/AudioController.java +149 -0
- package/bridges/lavalink/src/WebmOpus.java +82 -0
- package/dist/cli/arguments.d.ts +1 -0
- package/dist/cli/arguments.d.ts.map +1 -1
- package/dist/cli/arguments.js +8 -3
- package/dist/cli/arguments.js.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +6 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/version.d.ts +1 -3
- package/dist/cli/version.d.ts.map +1 -1
- package/dist/cli/version.js +1 -6
- package/dist/cli/version.js.map +1 -1
- package/dist/commands/arguments.d.ts.map +1 -1
- package/dist/commands/arguments.js +54 -43
- package/dist/commands/arguments.js.map +1 -1
- package/dist/commands/context.d.ts +33 -10
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +67 -27
- package/dist/commands/context.js.map +1 -1
- package/dist/domain/decimal.d.ts +4 -0
- package/dist/domain/decimal.d.ts.map +1 -0
- package/dist/domain/decimal.js +84 -0
- package/dist/domain/decimal.js.map +1 -0
- package/dist/domain/music-state.d.ts +3 -0
- package/dist/domain/music-state.d.ts.map +1 -0
- package/dist/domain/music-state.js +10 -0
- package/dist/domain/music-state.js.map +1 -0
- package/dist/domain/music.d.ts +199 -0
- package/dist/domain/music.d.ts.map +1 -0
- package/dist/domain/music.js +2 -0
- package/dist/domain/music.js.map +1 -0
- package/dist/domain/state-validation.d.ts.map +1 -1
- package/dist/domain/state-validation.js +2 -0
- package/dist/domain/state-validation.js.map +1 -1
- package/dist/domain/state.d.ts +1 -0
- package/dist/domain/state.d.ts.map +1 -1
- package/dist/domain/state.js.map +1 -1
- package/dist/domain/track-queue.d.ts +24 -0
- package/dist/domain/track-queue.d.ts.map +1 -0
- package/dist/domain/track-queue.js +103 -0
- package/dist/domain/track-queue.js.map +1 -0
- package/dist/domain/variable-query.d.ts +29 -0
- package/dist/domain/variable-query.d.ts.map +1 -0
- package/dist/domain/variable-query.js +53 -0
- package/dist/domain/variable-query.js.map +1 -0
- package/dist/framework/bot.d.ts +15 -1
- package/dist/framework/bot.d.ts.map +1 -1
- package/dist/framework/bot.js +135 -38
- package/dist/framework/bot.js.map +1 -1
- package/dist/framework/command-registry.d.ts.map +1 -1
- package/dist/framework/command-registry.js +8 -1
- package/dist/framework/command-registry.js.map +1 -1
- package/dist/framework/options.d.ts +4 -0
- package/dist/framework/options.d.ts.map +1 -1
- package/dist/framework/options.js.map +1 -1
- package/dist/framework/rate-limits.d.ts +3 -0
- package/dist/framework/rate-limits.d.ts.map +1 -1
- package/dist/framework/rate-limits.js +15 -9
- package/dist/framework/rate-limits.js.map +1 -1
- package/dist/framework/reporting.js +1 -1
- package/dist/framework/reporting.js.map +1 -1
- package/dist/images.d.ts +3 -0
- package/dist/images.d.ts.map +1 -0
- package/dist/images.js +2 -0
- package/dist/images.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/fluxer/lavalink-bridge.d.ts +34 -0
- package/dist/infrastructure/fluxer/lavalink-bridge.d.ts.map +1 -0
- package/dist/infrastructure/fluxer/lavalink-bridge.js +250 -0
- package/dist/infrastructure/fluxer/lavalink-bridge.js.map +1 -0
- package/dist/infrastructure/fluxer/resources/users.d.ts.map +1 -1
- package/dist/infrastructure/fluxer/resources/users.js +6 -0
- package/dist/infrastructure/fluxer/resources/users.js.map +1 -1
- package/dist/infrastructure/fluxer/voice.d.ts +28 -0
- package/dist/infrastructure/fluxer/voice.d.ts.map +1 -0
- package/dist/infrastructure/fluxer/voice.js +157 -0
- package/dist/infrastructure/fluxer/voice.js.map +1 -0
- package/dist/infrastructure/images/transform.d.ts +21 -0
- package/dist/infrastructure/images/transform.d.ts.map +1 -0
- package/dist/infrastructure/images/transform.js +72 -0
- package/dist/infrastructure/images/transform.js.map +1 -0
- package/dist/infrastructure/images/worker.mjs +28 -0
- package/dist/infrastructure/lavalink/audio-stream.d.ts +12 -0
- package/dist/infrastructure/lavalink/audio-stream.d.ts.map +1 -0
- package/dist/infrastructure/lavalink/audio-stream.js +95 -0
- package/dist/infrastructure/lavalink/audio-stream.js.map +1 -0
- package/dist/infrastructure/lavalink/node.d.ts +147 -0
- package/dist/infrastructure/lavalink/node.d.ts.map +1 -0
- package/dist/infrastructure/lavalink/node.js +498 -0
- package/dist/infrastructure/lavalink/node.js.map +1 -0
- package/dist/infrastructure/lavalink/protocol.d.ts +10 -0
- package/dist/infrastructure/lavalink/protocol.d.ts.map +1 -0
- package/dist/infrastructure/lavalink/protocol.js +114 -0
- package/dist/infrastructure/lavalink/protocol.js.map +1 -0
- package/dist/infrastructure/storage/memory.d.ts +2 -0
- package/dist/infrastructure/storage/memory.d.ts.map +1 -1
- package/dist/infrastructure/storage/memory.js +8 -0
- package/dist/infrastructure/storage/memory.js.map +1 -1
- package/dist/infrastructure/storage/sqlite.d.ts +4 -0
- package/dist/infrastructure/storage/sqlite.d.ts.map +1 -1
- package/dist/infrastructure/storage/sqlite.js +53 -3
- package/dist/infrastructure/storage/sqlite.js.map +1 -1
- package/dist/music.d.ts +12 -0
- package/dist/music.d.ts.map +1 -0
- package/dist/music.js +6 -0
- package/dist/music.js.map +1 -0
- package/dist/ports/music.d.ts +25 -0
- package/dist/ports/music.d.ts.map +1 -0
- package/dist/ports/music.js +2 -0
- package/dist/ports/music.js.map +1 -0
- package/dist/ports/resources/users.d.ts +2 -0
- package/dist/ports/resources/users.d.ts.map +1 -1
- package/dist/ports/resources/users.js.map +1 -1
- package/dist/ports/store.d.ts +5 -1
- package/dist/ports/store.d.ts.map +1 -1
- package/dist/ports/store.js.map +1 -1
- package/dist/ports/voice.d.ts +28 -0
- package/dist/ports/voice.d.ts.map +1 -0
- package/dist/ports/voice.js +2 -0
- package/dist/ports/voice.js.map +1 -0
- package/dist/scripting/builtins/flow.d.ts.map +1 -1
- package/dist/scripting/builtins/flow.js +2 -1
- package/dist/scripting/builtins/flow.js.map +1 -1
- package/dist/scripting/builtins/http.d.ts.map +1 -1
- package/dist/scripting/builtins/http.js +59 -0
- package/dist/scripting/builtins/http.js.map +1 -1
- package/dist/scripting/builtins/language/decimals.d.ts +2 -0
- package/dist/scripting/builtins/language/decimals.d.ts.map +1 -0
- package/dist/scripting/builtins/language/decimals.js +9 -0
- package/dist/scripting/builtins/language/decimals.js.map +1 -0
- package/dist/scripting/builtins/language/index.d.ts.map +1 -1
- package/dist/scripting/builtins/language/index.js +6 -0
- package/dist/scripting/builtins/language/index.js.map +1 -1
- package/dist/scripting/builtins/language/loops.d.ts.map +1 -1
- package/dist/scripting/builtins/language/loops.js +69 -7
- package/dist/scripting/builtins/language/loops.js.map +1 -1
- package/dist/scripting/builtins/language/regex.d.ts +2 -0
- package/dist/scripting/builtins/language/regex.d.ts.map +1 -0
- package/dist/scripting/builtins/language/regex.js +17 -0
- package/dist/scripting/builtins/language/regex.js.map +1 -0
- package/dist/scripting/builtins/language/sort.d.ts +2 -0
- package/dist/scripting/builtins/language/sort.d.ts.map +1 -0
- package/dist/scripting/builtins/language/sort.js +55 -0
- package/dist/scripting/builtins/language/sort.js.map +1 -0
- package/dist/scripting/builtins/native-users.d.ts.map +1 -1
- package/dist/scripting/builtins/native-users.js +5 -0
- package/dist/scripting/builtins/native-users.js.map +1 -1
- package/dist/scripting/builtins/schedule.js +8 -8
- package/dist/scripting/builtins/schedule.js.map +1 -1
- package/dist/scripting/builtins/storage.d.ts.map +1 -1
- package/dist/scripting/builtins/storage.js +8 -0
- package/dist/scripting/builtins/storage.js.map +1 -1
- package/dist/scripting/control-flow.d.ts +8 -0
- package/dist/scripting/control-flow.d.ts.map +1 -0
- package/dist/scripting/control-flow.js +18 -0
- package/dist/scripting/control-flow.js.map +1 -0
- package/dist/scripting/evaluator.d.ts +1 -0
- package/dist/scripting/evaluator.d.ts.map +1 -1
- package/dist/scripting/evaluator.js +36 -11
- package/dist/scripting/evaluator.js.map +1 -1
- package/dist/scripting/parser.d.ts.map +1 -1
- package/dist/scripting/parser.js +20 -11
- package/dist/scripting/parser.js.map +1 -1
- package/dist/scripting/regex-worker.mjs +69 -0
- package/dist/scripting/regex.d.ts +19 -0
- package/dist/scripting/regex.d.ts.map +1 -0
- package/dist/scripting/regex.js +61 -0
- package/dist/scripting/regex.js.map +1 -0
- package/dist/scripting/registry.d.ts +2 -1
- package/dist/scripting/registry.d.ts.map +1 -1
- package/dist/scripting/registry.js +9 -2
- package/dist/scripting/registry.js.map +1 -1
- package/dist/services/attachments.d.ts +10 -0
- package/dist/services/attachments.d.ts.map +1 -0
- package/dist/services/attachments.js +52 -0
- package/dist/services/attachments.js.map +1 -0
- package/dist/services/authorization.d.ts +1 -0
- package/dist/services/authorization.d.ts.map +1 -1
- package/dist/services/authorization.js +10 -0
- package/dist/services/authorization.js.map +1 -1
- package/dist/services/music-player.d.ts +90 -0
- package/dist/services/music-player.d.ts.map +1 -0
- package/dist/services/music-player.js +475 -0
- package/dist/services/music-player.js.map +1 -0
- package/dist/services/music.d.ts +50 -0
- package/dist/services/music.d.ts.map +1 -0
- package/dist/services/music.js +177 -0
- package/dist/services/music.js.map +1 -0
- package/dist/services/native-data.d.ts +2 -0
- package/dist/services/native-data.d.ts.map +1 -1
- package/dist/services/native-data.js +3 -0
- package/dist/services/native-data.js.map +1 -1
- package/dist/services/scheduler.d.ts +4 -0
- package/dist/services/scheduler.d.ts.map +1 -1
- package/dist/services/scheduler.js +10 -2
- package/dist/services/scheduler.js.map +1 -1
- package/dist/services/variables.d.ts +2 -0
- package/dist/services/variables.d.ts.map +1 -1
- package/dist/services/variables.js +11 -0
- package/dist/services/variables.js.map +1 -1
- package/dist/shared/package.d.ts +4 -0
- package/dist/shared/package.d.ts.map +1 -0
- package/dist/shared/package.js +7 -0
- package/dist/shared/package.js.map +1 -0
- package/dist/testing/music.d.ts +35 -0
- package/dist/testing/music.d.ts.map +1 -0
- package/dist/testing/music.js +88 -0
- package/dist/testing/music.js.map +1 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +4 -2
- package/dist/testing.js.map +1 -1
- package/docs/API.md +48 -2
- package/docs/ARCHITECTURE.md +22 -3
- package/docs/BENCHMARKS.md +195 -2
- package/docs/CLI.md +19 -4
- package/docs/COOKBOOK.md +1 -1
- package/docs/EVENTS.md +8 -0
- package/docs/FUNCTION-GAPS.md +51 -32
- package/docs/FUNCTIONS.md +22 -4
- package/docs/HTTP.md +23 -0
- package/docs/IMAGES.md +104 -0
- package/docs/INTEGRATIONS.md +69 -0
- package/docs/LANGUAGE-EXTENSIONS.md +106 -0
- package/docs/LANGUAGE.md +4 -4
- package/docs/MUSIC.md +339 -0
- package/docs/NATIVE.md +15 -6
- package/docs/PARITY.md +27 -19
- package/docs/PLAN.md +30 -1
- package/docs/PROJECT.md +35 -0
- package/docs/QUICKSTART.md +73 -48
- package/docs/README.md +39 -24
- package/docs/REPOSITORY.md +70 -0
- package/docs/SCHEDULER.md +17 -0
- package/docs/STORAGE.md +49 -0
- package/docs/TESTING.md +21 -1
- package/docs/TROUBLESHOOTING.md +11 -1
- package/docs/VALIDATION.md +167 -4
- package/docs/tutorials/DATA.md +100 -0
- package/docs/tutorials/FIRST-COMMAND.md +134 -0
- package/docs/tutorials/FUNCTION-MODE.md +100 -0
- package/docs/tutorials/TESTING.md +84 -0
- package/editors/vscode/functions.json +147 -3
- package/editors/vscode/package.json +1 -1
- package/examples/lavalink.ts +55 -0
- package/examples/music-offline.ts +25 -0
- package/examples/native-voice.ts +26 -0
- package/package.json +37 -4
- package/src/cli/arguments.ts +8 -5
- package/src/cli/main.ts +6 -2
- package/src/cli/version.ts +1 -10
- package/src/commands/arguments.ts +45 -38
- package/src/commands/context.ts +68 -26
- package/src/domain/decimal.ts +75 -0
- package/src/domain/music-state.ts +10 -0
- package/src/domain/music.ts +82 -0
- package/src/domain/state-validation.ts +1 -0
- package/src/domain/state.ts +1 -0
- package/src/domain/track-queue.ts +79 -0
- package/src/domain/variable-query.ts +58 -0
- package/src/framework/bot.ts +113 -31
- package/src/framework/command-registry.ts +7 -1
- package/src/framework/options.ts +4 -0
- package/src/framework/rate-limits.ts +11 -6
- package/src/framework/reporting.ts +1 -1
- package/src/images.ts +2 -0
- package/src/index.ts +4 -0
- package/src/infrastructure/fluxer/lavalink-bridge.ts +200 -0
- package/src/infrastructure/fluxer/resources/users.ts +5 -0
- package/src/infrastructure/fluxer/voice.ts +108 -0
- package/src/infrastructure/images/transform.ts +66 -0
- package/src/infrastructure/images/worker.mjs +28 -0
- package/src/infrastructure/lavalink/audio-stream.ts +71 -0
- package/src/infrastructure/lavalink/node.ts +425 -0
- package/src/infrastructure/lavalink/protocol.ts +84 -0
- package/src/infrastructure/storage/memory.ts +10 -0
- package/src/infrastructure/storage/sqlite.ts +52 -4
- package/src/music.ts +11 -0
- package/src/ports/music.ts +24 -0
- package/src/ports/resources/users.ts +2 -0
- package/src/ports/store.ts +5 -1
- package/src/ports/voice.ts +26 -0
- package/src/scripting/builtins/flow.ts +2 -1
- package/src/scripting/builtins/http.ts +44 -0
- package/src/scripting/builtins/language/decimals.ts +10 -0
- package/src/scripting/builtins/language/index.ts +6 -0
- package/src/scripting/builtins/language/loops.ts +57 -8
- package/src/scripting/builtins/language/regex.ts +19 -0
- package/src/scripting/builtins/language/sort.ts +50 -0
- package/src/scripting/builtins/native-users.ts +5 -0
- package/src/scripting/builtins/schedule.ts +11 -11
- package/src/scripting/builtins/storage.ts +7 -0
- package/src/scripting/control-flow.ts +13 -0
- package/src/scripting/evaluator.ts +27 -9
- package/src/scripting/parser.ts +23 -10
- package/src/scripting/regex-worker.mjs +69 -0
- package/src/scripting/regex.ts +63 -0
- package/src/scripting/registry.ts +7 -2
- package/src/services/attachments.ts +49 -0
- package/src/services/authorization.ts +9 -0
- package/src/services/music-player.ts +340 -0
- package/src/services/music.ts +146 -0
- package/src/services/native-data.ts +5 -0
- package/src/services/scheduler.ts +11 -2
- package/src/services/variables.ts +11 -0
- package/src/shared/package.ts +10 -0
- package/src/testing/music.ts +71 -0
- package/src/testing.ts +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -21,6 +21,42 @@ documentos. Veja a [política completa](VERSIONING.md).
|
|
|
21
21
|
|
|
22
22
|
</details>
|
|
23
23
|
|
|
24
|
+
## v0.1.7 · 23/10/2026
|
|
25
|
+
|
|
26
|
+
Loops controláveis, comparadores de arrays, regex isolada, decimais exatos e busca pela CLI, com o conteúdo preparado na 0.1.6. Esta atualização da biblioteca Yuzuha foi preparada em 23/10/2026 (v0.1.7).
|
|
27
|
+
|
|
28
|
+
- `yuzuha functions --search <termo>` filtra nomes, aliases e descrições por trecho, sem distinguir maiúsculas e minúsculas. Aceita `$` inicial e combina com categoria, JSON, exportação de catálogo e filtros de plugins, preservando a ordem dos resultados.
|
|
29
|
+
- Buscas sem resultados encerram com sucesso e retornam uma mensagem no terminal ou uma lista vazia em JSON. Termos vazios, ausentes ou repetidos são recusados; categorias desconhecidas continuam sendo erros.
|
|
30
|
+
- Consultas paginadas de variáveis por prefixo, com TTL e cursor; índice SQLite derivado do snapshot e invalidado por trigger. Streaming UTF-8 em scripts, com backpressure, controle de loop e cancelamento.
|
|
31
|
+
- `yuzuha/images` adiciona transformação opcional de PNG/JPEG/WebP com Sharp em processos limitados e canceláveis. `ctx.sendStream` lê anexos com orçamento e prazo antes do upload de bytes exigido pelo SDK.
|
|
32
|
+
- Auditoria de integrações documenta configuração de shards já suportada pelo core, gerenciamento externo de processos e ausência de contratos para componentes/comandos de aplicação.
|
|
33
|
+
- Tarefas aceitam prioridade persistida; `globalConcurrency` coordena claims no store compartilhado, preservando o limite local.
|
|
34
|
+
- **18 funções novas**, totalizando **306**: `guildFeatures`, `leaveGuild`, `while`, `break`, `continue`, `arraySortWith`, `sortLeft`, `sortRight`, `regexTest`, `regexMatch`, `regexReplace`, `decimal`, `decimalCompare`, `decimalRound`, `queryVars`, `httpStream`, `httpChunk` e `httpChunkIndex`.
|
|
35
|
+
- `ctx.guildFeatures()` copia as features do servidor; `ctx.leaveGuild()` só permite a saída solicitada pelo dono do servidor, com a mesma autorização nos scripts. Ports customizados antigos continuam válidos; ausência do recurso retorna `NATIVE_UNAVAILABLE`.
|
|
36
|
+
- Loops restauram o contexto ao sair; `break` e `continue` atravessam `$try` e afetam o corpo do loop mais próximo. Comparadores usam ordenação estável e orçamento compartilhado. Decimais retornam texto e usam até 1000 dígitos, sem perda por `Number`.
|
|
37
|
+
- Regex roda em workers limitados, com cancelamento, prazo e limites de entrada, correspondências e saída. O worker é incluído no tarball e não executa JavaScript fornecido pelo script.
|
|
38
|
+
- Inclui as otimizações de dispatch, runtime e estado, as APIs nativas de música, a integração Lavalink v4 e a ponte de áudio descritas na entrada 0.1.6. SDK 3.3.0, schema 2 e imports anteriores permanecem compatíveis.
|
|
39
|
+
- Erros do gateway e de shards chegam aos hooks `onError`/`onLog` mesmo sem listeners do usuário. Os listeners padrão permanecem ativos durante o encerramento e preservam os listeners de clients injetados.
|
|
40
|
+
- O parser salta trechos de texto comum mantendo offsets, escapes e diagnósticos. A limpeza de `$httpStream` não bloqueia o comando quando a fonte deixa o cancelamento pendente.
|
|
41
|
+
- Biblioteca e CLI voltam à raiz do repositório, com instalação npm, guias Markdown e exemplos incluídos no pacote. O site fica arquivado para uma etapa futura.
|
|
42
|
+
|
|
43
|
+
## v0.1.6 · 22/10/2026
|
|
44
|
+
|
|
45
|
+
Dispatch, argumentos, runtime e leituras de estado mais rápidos, com ferramentas nativas para música e integração Lavalink v4. Esta atualização da biblioteca Yuzuha foi preparada em 22/10/2026 (v0.1.6).
|
|
46
|
+
|
|
47
|
+
- Deduplicação usa uma fila circular de 10000 entradas; mensagens ignoradas seguem um caminho curto. Prefixos estáticos são reaproveitados, o sinal de encerramento é compartilhado e serviços, mapas de argumentos e variáveis do contexto são criados sob demanda.
|
|
48
|
+
- Registro individual de comandos valida conflitos antes de inserir, sem copiar todo o catálogo. Carga e recarga continuam atômicas. Argumentos simples usam tokenização por trechos; o caminho de aspas/apóstrofos evita inspecionar repetidamente a palavra em construção. Escapes, flags e erros de entrada são preservados.
|
|
49
|
+
- Parser acumula trechos de texto; evaluator evita promises para literais e resolve funções com cache fraco por AST. A validação continua ativa para ASTs externos ou editados, com ordem, tipos, guards, orçamento e falhas parciais preservados.
|
|
50
|
+
- Leituras pontuais em memória e JSON copiam somente o valor solicitado e respeitam TTL e ordenação das transações. Stores próprios conservam o caminho anterior; `readVariable` é uma capacidade opcional. SQLite reutiliza statements sem alterar schema, WAL ou validação antes do commit.
|
|
51
|
+
- `yuzuha/music` entrega cliente Lavalink v4 com REST/WebSocket autenticados, retomada de sessão, reconexão limitada, cancelamento, limite de respostas/requisições, cache LRU com orçamento de bytes e compartilhamento de buscas simultâneas.
|
|
52
|
+
- Gerenciador de música com distribuição de novos players entre nodes disponíveis, filas limitadas por servidor, avanço automático, loop, pause, skip, stop, seek, volume e filtros. Controles e eventos são serializados; falhas de PATCH preservam as faixas pendentes.
|
|
53
|
+
- Sessões Lavalink perdidas são reconstruídas com concorrência limitada, posição, pausa, filtros e renovação de voz. Sessões retomadas preservam a reprodução; eventos aguardam a confirmação do handshake. Respostas antigas não alteram a fila.
|
|
54
|
+
- Filas permitem remover, mover, embaralhar e consultar páginas sem copiar todo o catálogo. Controles pendentes são limitados por player; eventos de fim mantêm capacidade reservada. Nodes consideram CPU, players e frames ao distribuir carga; saídas pelo plugin ignoram os contadores de voz Discord, evitando perda falsa no balanceamento.
|
|
55
|
+
- Buscas com signals distintos compartilham a requisição, com cancelamento por chamada e aborto quando todos desistem. Decode de faixas/lotes e diagnósticos de cache/rede completam a API; parsing de flags evita mapas e objetos temporários por valor.
|
|
56
|
+
- `FluxerVoice` carrega `@fluxerjs/voice` opcionalmente para áudio WebM/Opus nativo. `ctx.voice` e `ctx.music` recebem serviços configurados e participam do encerramento.
|
|
57
|
+
- `FluxerLavalinkBridge` e o plugin `yuzuha-audio` conectam a saída Opus do Lavalink 4.2.2 ao SDK do Fluxer. Mantêm uma publicação entre faixas, pausa, seek e filtros; transmissão incremental, limites, cancelamento e reconexão liberam os recursos por servidor. A integração local usa áudio e decoder reais, com publicação LiveKit simulada.
|
|
58
|
+
- `MockMusicBackend`, `mockTrack`, exemplo offline, guia de música e benchmarks adicionais acompanham a versão. Relatórios anteriores/atuais e método estão em [BENCHMARKS.md](docs/BENCHMARKS.md). SDK 3.3.0, schema 2 e 288 funções de script permanecem compatíveis.
|
|
59
|
+
|
|
24
60
|
## v0.1.5 · 22/10/2026
|
|
25
61
|
|
|
26
62
|
Subcomandos e flags tipadas, ajuda derivada das definições e testes nativos com relógio controlável, com projetos gerados prontos para compartilhar. Esta atualização da biblioteca Yuzuha foi preparada em 22/10/2026 (v0.1.5).
|
package/README.md
CHANGED
|
@@ -1,159 +1,198 @@
|
|
|
1
1
|
# Yuzuha
|
|
2
2
|
|
|
3
|
-
Framework para bots do Fluxer
|
|
4
|
-
tipados
|
|
5
|
-
|
|
3
|
+
Framework TypeScript para bots do [Fluxer](https://fluxer.app), com comandos
|
|
4
|
+
tipados em JavaScript/TypeScript e uma linguagem opcional de scripts.
|
|
5
|
+
Os dois modos compartilham permissões, moderação, estado e recursos.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
O Yuzuha usa **Fluxer.js 3.3.0**. Você continua tendo acesso ao client original
|
|
8
|
+
por `bot.client` e aos exports do SDK em `yuzuha/sdk`.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
[0.1.7](CHANGELOG.md) · Node **22.13+** · ESM · [MIT](LICENSE)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
[Começar](#começar) · [Comandos](#escrever-comandos) · [Recursos](#recursos) · [Testes](#testar-sem-token) · [Documentação](#documentação)
|
|
13
|
+
|
|
14
|
+
## Começar
|
|
15
|
+
|
|
16
|
+
### Criar um bot
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npx yuzuha@0.1.7 init ./meu-bot --ts
|
|
20
|
+
cd meu-bot
|
|
21
|
+
npm install
|
|
22
|
+
npm run check
|
|
23
|
+
npm run typecheck
|
|
24
|
+
npm test
|
|
25
|
+
cp .env.example .env
|
|
26
|
+
```
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
Preencha `FLUXER_BOT_TOKEN` no `.env` e inicie o bot:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npm run dev
|
|
28
32
|
```
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
O projeto inclui três comandos, configuração e um teste offline. Para JavaScript,
|
|
35
|
+
troque `--ts` por `--js` e omita `typecheck`. Acrescente `--functions` ao `init`
|
|
36
|
+
para incluir um comando de exemplo com scripts.
|
|
37
|
+
|
|
38
|
+
`npm run check`, `npm run typecheck` e `npm test` validam o projeto sem conectar o bot.
|
|
39
|
+
`npm run dev` conecta e recarrega os arquivos de comando ao editar;
|
|
40
|
+
`npm start` executa sem recarga automática.
|
|
41
|
+
|
|
42
|
+
### Usar em um projeto existente
|
|
33
43
|
|
|
34
|
-
|
|
44
|
+
```sh
|
|
45
|
+
npm install yuzuha@0.1.7
|
|
46
|
+
```
|
|
35
47
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- Guards, middleware, plugins, eventos tipados e recarga de comandos sem reiniciar.
|
|
39
|
-
- Moderação compartilhada (ban, kick, timeout, unban) com casos por servidor.
|
|
40
|
-
- Recursos prontos: usuários, cargos, canais, mensagens, convites, webhooks,
|
|
41
|
-
emojis, stickers, threads e fóruns, incluindo reações, membros de threads,
|
|
42
|
-
posição de cargos/canais e categorias.
|
|
43
|
-
- Estado em memória, JSON ou SQLite, com transações e variáveis por escopo.
|
|
44
|
-
- Agendamentos persistentes com cron, fuso IANA, concorrência e retry com jitter.
|
|
45
|
-
- HTTP textual/binário, streaming e multipart, com limites e políticas por comando.
|
|
46
|
-
- `createTestBot`, relógio controlável, `MockTransport` e stores isolados para testar sem token.
|
|
47
|
-
- Transações entre chaves, agendamentos editáveis com pausa/retry e apelidos com autorização compartilhada.
|
|
48
|
-
- Limpeza de expirados, estatísticas e backup/restauração versionados com simulação.
|
|
49
|
-
- `doctor`, lint JSON, cenários offline, catálogos de plugins e extensão VS Code.
|
|
50
|
-
- SDK `@fluxerjs/core` **3.3.0** reexportado em `yuzuha/sdk`, sem esconder o original.
|
|
48
|
+
Use `"type": "module"` no `package.json`. O [guia inicial](docs/QUICKSTART.md)
|
|
49
|
+
mostra como configurar o bot e carregar comandos.
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
estiver no framework continua acessível por `bot.client` e pelos tipos originais.
|
|
51
|
+
## Escrever comandos
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
Salve **uma das versões** abaixo em `commands/eco.ts` (`.js` para JavaScript).
|
|
54
|
+
Ambas respondem a `!eco Olá, Yuzuha!` com `Olá, Yuzuha!`.
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
runtime é ativado quando um comando com `code` ou um evento de script é registrado.
|
|
56
|
+
### JavaScript / TypeScript
|
|
59
57
|
|
|
60
58
|
```ts
|
|
61
|
-
import {
|
|
62
|
-
import { Yuzuha } from 'yuzuha';
|
|
59
|
+
import { arg, defineCommand } from 'yuzuha';
|
|
63
60
|
|
|
64
|
-
|
|
61
|
+
export default defineCommand({
|
|
62
|
+
name: 'eco',
|
|
63
|
+
description: 'Repete o texto informado.',
|
|
64
|
+
args: { texto: arg.text().rest().required() },
|
|
65
|
+
async run(ctx) {
|
|
66
|
+
await ctx.reply(ctx.args.get('texto'));
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Schemas `arg.*` inferem os tipos de argumentos e flags. Você também pode declarar
|
|
72
|
+
subcomandos, checks e middleware. O [guia nativo](docs/NATIVE.md) cobre esses
|
|
73
|
+
contratos, eventos, moderação e persistência.
|
|
74
|
+
|
|
75
|
+
### Function mode do Yuzuha
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { script } from 'yuzuha/functions';
|
|
65
79
|
|
|
66
|
-
|
|
67
|
-
name: '
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
export default script({
|
|
81
|
+
name: 'eco',
|
|
82
|
+
description: 'Repete o texto informado.',
|
|
83
|
+
code: '$reply[$messageSlice[0]]',
|
|
84
|
+
});
|
|
70
85
|
```
|
|
71
86
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
87
|
+
O function mode tem **306 funções** para mensagens, guards, moderação, variáveis,
|
|
88
|
+
JSON, arrays, loops, eventos e agendamentos. O runtime é ativado ao registrar um
|
|
89
|
+
comando com `code` ou um evento de script.
|
|
75
90
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
91
|
+
As funções seguem as assinaturas e regras do runtime do Yuzuha. Consulte a
|
|
92
|
+
[linguagem](docs/LANGUAGE.md), as [assinaturas das funções](docs/FUNCTIONS.md)
|
|
93
|
+
e a [cobertura](docs/PARITY.md).
|
|
79
94
|
|
|
80
|
-
##
|
|
95
|
+
## Recursos
|
|
81
96
|
|
|
82
|
-
|
|
83
|
-
|
|
97
|
+
| Área | O que está disponível |
|
|
98
|
+
|---|---|
|
|
99
|
+
| Comandos | Prefixos, aliases, subcomandos, argumentos e flags tipadas, cooldowns e ajuda gerada dos metadados |
|
|
100
|
+
| Extensões | Plugins, eventos, checks, middleware e recarga atômica de comandos |
|
|
101
|
+
| Moderação | Ban, kick, timeout, unban e moderação de voz, com permissões, hierarquia e casos por servidor |
|
|
102
|
+
| Fluxer | Usuários, membros, cargos, canais, mensagens, reações, anexos, threads, convites, webhooks e expressões |
|
|
103
|
+
| Dados | Memória, JSON e SQLite; TTL, transações, limpeza e backup/restauração com simulação |
|
|
104
|
+
| Agendamentos | Tarefas persistentes, cron, fusos IANA, pausa/retomada, histórico e retry |
|
|
105
|
+
| HTTP | Texto, bytes, streaming e multipart, com limites, cancelamento e políticas por comando |
|
|
106
|
+
| Música | Lavalink v4 com plugin e ponte de áudio para Fluxer, recuperação, filas editáveis, loop, seek, volume e filtros |
|
|
107
|
+
| Desenvolvimento | CLI, autocomplete e diagnósticos no VS Code, mocks e relógio controlável para testes |
|
|
84
108
|
|
|
85
|
-
|
|
86
|
-
npm install yuzuha@0.1.5
|
|
87
|
-
```
|
|
109
|
+
## Testar sem token
|
|
88
110
|
|
|
89
|
-
|
|
111
|
+
O scaffold já inclui um teste executável com `npm test`. Para testar o comando
|
|
112
|
+
`eco` acima, crie `test/eco.test.ts` (`.js` para JavaScript):
|
|
90
113
|
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
114
|
+
```ts
|
|
115
|
+
import test from 'node:test';
|
|
116
|
+
import assert from 'node:assert/strict';
|
|
117
|
+
import { createTestBot } from 'yuzuha/testing';
|
|
118
|
+
import eco from '../commands/eco.js';
|
|
119
|
+
|
|
120
|
+
test('eco responde com o texto informado', async t => {
|
|
121
|
+
const fixture = createTestBot({ commands: [eco] });
|
|
122
|
+
t.after(() => fixture.destroy());
|
|
123
|
+
|
|
124
|
+
assert.equal(await fixture.send('!eco Olá, Yuzuha!'), 'success');
|
|
125
|
+
assert.equal(fixture.messages.at(-1)?.payload.content, 'Olá, Yuzuha!');
|
|
126
|
+
});
|
|
99
127
|
```
|
|
100
128
|
|
|
101
|
-
`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
Para acrescentar um exemplo de script, use `--functions`.
|
|
129
|
+
`createTestBot` usa transporte e recursos simulados, com estado isolado. O relógio
|
|
130
|
+
controlável permite testar cooldown, TTL e tarefas sem aguardar tempo real.
|
|
131
|
+
Veja fixtures, stores e cenários na [documentação de testes](docs/TESTING.md).
|
|
105
132
|
|
|
106
|
-
|
|
133
|
+
## CLI
|
|
107
134
|
|
|
108
|
-
|
|
135
|
+
Execute estes comandos no diretório do seu bot:
|
|
136
|
+
|
|
137
|
+
| Comando | Uso |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `npx yuzuha check` | Validar configuração e comandos sem login |
|
|
140
|
+
| `npx yuzuha doctor` | Diagnosticar ambiente, configuração e store |
|
|
141
|
+
| `npx yuzuha lint commands --json` | Analisar scripts sem importar módulos |
|
|
142
|
+
| `npx yuzuha functions --category moderation` | Consultar funções e assinaturas |
|
|
143
|
+
| `npx yuzuha functions --search mensagem` | Buscar funções por nome, alias ou descrição |
|
|
144
|
+
| `npx yuzuha editor` | Encontrar a extensão VS Code incluída no pacote |
|
|
145
|
+
|
|
146
|
+
`check` importa configurações e comandos JS/TS de confiança; a verificação de
|
|
147
|
+
tipos é feita por `npm run typecheck`. A [referência da CLI](docs/CLI.md) também cobre
|
|
148
|
+
catálogos de plugins, cenários offline e manutenção de dados.
|
|
149
|
+
|
|
150
|
+
## Documentação
|
|
151
|
+
|
|
152
|
+
O [índice completo](docs/README.md) reúne os guias e as referências.
|
|
153
|
+
|
|
154
|
+
| Quero… | Ler |
|
|
155
|
+
|---|---|
|
|
156
|
+
| Criar e configurar um bot | [Guia inicial](docs/QUICKSTART.md) |
|
|
157
|
+
| Programar em JS/TS | [Guia nativo](docs/NATIVE.md), [framework](docs/FRAMEWORK.md) e [API](docs/API.md) |
|
|
158
|
+
| Criar um bot de música | [Lavalink, filas e voz Fluxer](docs/MUSIC.md) |
|
|
159
|
+
| Medir performance | [Benchmarks e comparações com a 0.1.5](docs/BENCHMARKS.md) |
|
|
160
|
+
| Escrever scripts `$...` | [Linguagem](docs/LANGUAGE.md) e [referência de funções](docs/FUNCTIONS.md) |
|
|
161
|
+
| Copiar exemplos | [Receitas](docs/COOKBOOK.md) e [código de exemplo](examples) |
|
|
162
|
+
| Usar o editor ou diagnosticar um erro | [VS Code](docs/EDITOR.md) e [problemas comuns](docs/TROUBLESHOOTING.md) |
|
|
163
|
+
| Entender a cobertura | [Paridade](docs/PARITY.md) e [funções ausentes](docs/FUNCTION-GAPS.md) |
|
|
164
|
+
| Conferir mudanças e validação | [Changelog](CHANGELOG.md), [versionamento](VERSIONING.md) e [evidências](docs/VALIDATION.md) |
|
|
165
|
+
|
|
166
|
+
## Desenvolver a biblioteca
|
|
167
|
+
|
|
168
|
+
Na cópia do repositório:
|
|
109
169
|
|
|
110
170
|
```sh
|
|
111
|
-
|
|
171
|
+
git clone https://github.com/horizzon3507/yuzuha.git
|
|
172
|
+
cd yuzuha
|
|
112
173
|
npm ci
|
|
113
|
-
npm run build
|
|
114
|
-
node dist/cli.js init ~/Projects/meu-bot --ts --local
|
|
115
|
-
cd ~/Projects/meu-bot
|
|
116
|
-
npm install
|
|
117
174
|
npm run check
|
|
118
|
-
npm run
|
|
119
|
-
cp .env.example .env
|
|
175
|
+
npm run smoke:package
|
|
120
176
|
```
|
|
121
177
|
|
|
122
|
-
|
|
123
|
-
[guia inicial](docs/QUICKSTART.md) explica instalação e configuração.
|
|
124
|
-
|
|
125
|
-
## Experimentar sem token
|
|
178
|
+
Para experimentar os exemplos offline:
|
|
126
179
|
|
|
127
180
|
```sh
|
|
128
181
|
npx tsx examples/offline.ts
|
|
129
182
|
npx tsx examples/function-mode.ts
|
|
130
|
-
node dist/cli.js check examples/yuzuha.config.js --json
|
|
131
|
-
node dist/cli.js functions --category moderation
|
|
132
183
|
```
|
|
133
184
|
|
|
134
|
-
|
|
135
|
-
config e comandos JS/TS de confiança, valida os scripts e não chama `login`.
|
|
136
|
-
Ele não substitui o typecheck do TypeScript.
|
|
185
|
+
Para gerar um bot que use sua instalação local da biblioteca:
|
|
137
186
|
|
|
138
|
-
|
|
187
|
+
```sh
|
|
188
|
+
node dist/cli.js init ../meu-bot-local --ts --local
|
|
189
|
+
```
|
|
139
190
|
|
|
140
|
-
|
|
191
|
+
O `init` usa a dependência npm por padrão; `--local` aponta para a instalação
|
|
192
|
+
que executa a CLI. Veja [contribuição](CONTRIBUTING.md) para as regras de código
|
|
193
|
+
e as verificações do projeto.
|
|
141
194
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
| Escrever scripts `$...` | [Function mode](docs/LANGUAGE.md) e [referência](docs/FUNCTIONS.md) |
|
|
147
|
-
| Saber quais funções de script existem | [Lacunas auditadas](docs/FUNCTION-GAPS.md) |
|
|
148
|
-
| Usar comandos, contexto e extensões | [Framework](docs/FRAMEWORK.md) e [API](docs/API.md) |
|
|
149
|
-
| Copiar exemplos completos | [Receitas](docs/COOKBOOK.md) |
|
|
150
|
-
| Usar a linha de comando | [CLI](docs/CLI.md) |
|
|
151
|
-
| Entender módulos e dependências | [Arquitetura](docs/ARCHITECTURE.md) |
|
|
152
|
-
| Escolher persistência e tratar falhas | [Estado e execução](docs/STORAGE.md) |
|
|
153
|
-
| Diagnosticar ou testar | [Problemas comuns](docs/TROUBLESHOOTING.md) e [testes](docs/TESTING.md) |
|
|
154
|
-
| Usar autocomplete e diagnóstico offline | [Editor e doctor](docs/EDITOR.md) |
|
|
155
|
-
| Medir dispatch, runtime e memória | [Benchmarks](docs/BENCHMARKS.md) |
|
|
156
|
-
| Ver evidência local | [Validação](docs/VALIDATION.md) |
|
|
157
|
-
|
|
158
|
-
As mudanças estão no [changelog](CHANGELOG.md); a política de versões está em
|
|
159
|
-
[VERSIONING.md](VERSIONING.md). Leia [CONTRIBUTING.md](CONTRIBUTING.md) para contribuir.
|
|
195
|
+
Transformações opcionais de imagens e entrada de anexos por stream estão em
|
|
196
|
+
[IMAGES.md](docs/IMAGES.md); consultas por prefixo e cursor em
|
|
197
|
+
[STORAGE.md](docs/STORAGE.md), e limites das integrações em
|
|
198
|
+
[INTEGRATIONS.md](docs/INTEGRATIONS.md).
|
package/VERSIONING.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Versionamento
|
|
2
2
|
|
|
3
3
|
O Yuzuha aplica o formato Hory ao histórico e usa **SemVer simples** no pacote.
|
|
4
|
-
A versão desta atualização é **0.1.
|
|
4
|
+
A versão desta atualização é **0.1.7**.
|
|
5
5
|
|
|
6
6
|
## Pacote e histórico
|
|
7
7
|
|
|
8
8
|
| Lugar | Formato nesta versão |
|
|
9
9
|
|---|---|
|
|
10
|
-
| `package.json` e raiz
|
|
11
|
-
| Pacote npm e saída de `yuzuha --version` | `0.1.
|
|
12
|
-
| Título do changelog | `## v0.1.
|
|
13
|
-
| Eventual tag Git | `v0.1.
|
|
10
|
+
| `package.json` e entrada raiz de `package-lock.json` | `0.1.7` |
|
|
11
|
+
| Pacote npm e saída de `yuzuha --version` | `0.1.7` |
|
|
12
|
+
| Título do changelog | `## v0.1.7 · 23/10/2026` |
|
|
13
|
+
| Eventual tag Git | `v0.1.7` |
|
|
14
14
|
|
|
15
15
|
O SDK e a CLI pertencem ao mesmo pacote. Para bibliotecas, a convenção Hory mantém
|
|
16
16
|
SemVer sem `m`, sem seções por superfície e sem sufixos de canal.
|
|
@@ -30,7 +30,7 @@ estivermos em `0.x`. Ao chegar a `1.0.0`, mudanças incompatíveis exigem major;
|
|
|
30
30
|
novas funcionalidades compatíveis, minor; correções compatíveis, patch.
|
|
31
31
|
|
|
32
32
|
Os exports públicos são `yuzuha`, `yuzuha/functions`, `yuzuha/sdk`,
|
|
33
|
-
`yuzuha/testing` e `yuzuha/
|
|
33
|
+
`yuzuha/testing`, `yuzuha/tooling`, `yuzuha/music` e `yuzuha/images`. A organização interna de `src/` não cria estabilidade de deep
|
|
34
34
|
imports. Schema persistido,
|
|
35
35
|
gramática e funções documentadas também fazem parte da compatibilidade.
|
|
36
36
|
|
|
@@ -40,6 +40,46 @@ gerado por `init` pertence ao consumidor e não precisa acompanhar a biblioteca.
|
|
|
40
40
|
|
|
41
41
|
## Preparar uma atualização
|
|
42
42
|
|
|
43
|
+
### Migrar para 0.1.7
|
|
44
|
+
|
|
45
|
+
A distribuição 0.1.7 inclui o conteúdo preparado na 0.1.6 e acrescenta
|
|
46
|
+
`yuzuha functions --search <termo>`. A busca combina com os filtros e formatos
|
|
47
|
+
existentes sem alterar imports anteriores, schema 2 ou SDK 3.3.0.
|
|
48
|
+
A linguagem recebe 18 funções, chegando a 306. `GuildInfo.features` e
|
|
49
|
+
`UsersResources.leaveGuild` são opcionais para preservar recursos customizados;
|
|
50
|
+
os novos auxiliares do contexto recusam recursos ausentes explicitamente.
|
|
51
|
+
O port `Store.queryVariables` também é opcional; memória/JSON mantêm fallback
|
|
52
|
+
por snapshot. SQLite cria um índice derivado automaticamente na primeira consulta,
|
|
53
|
+
sem alterar schema 2. Prioridade padrão é zero e capacidade compartilhada só é
|
|
54
|
+
ativada com `globalConcurrency`. `yuzuha/images` requer instalar Sharp; o restante
|
|
55
|
+
da biblioteca continua independente dele. Não há mudanças obrigatórias nos bots
|
|
56
|
+
existentes.
|
|
57
|
+
As instruções da 0.1.6 abaixo continuam aplicáveis ao atualizar da 0.1.5.
|
|
58
|
+
|
|
59
|
+
### Migrar para 0.1.6
|
|
60
|
+
|
|
61
|
+
Imports, schema 2, SDK 3.3.0 e 288 funções permanecem disponíveis. Os serviços do
|
|
62
|
+
contexto e seus mapas são inicializados sob demanda; as referências devolvidas
|
|
63
|
+
continuam estáveis por contexto. Mensagens ignoradas não criam uma execução.
|
|
64
|
+
O sinal de cancelamento pode ser compartilhado entre comandos do mesmo bot;
|
|
65
|
+
não dependa de sua identidade para correlacionar execuções: use `executionID`.
|
|
66
|
+
|
|
67
|
+
`Store.readVariable` é opcional e deve retornar uma cópia isolada, respeitar a
|
|
68
|
+
ordenação das transações e avaliar o callback de relógio `now` dentro da leitura,
|
|
69
|
+
após aguardar operações anteriores. `undefined` indica
|
|
70
|
+
ausente/expirado; `null` continua sendo um valor JSON válido. Não há migração de
|
|
71
|
+
disco. SQLite conserva validação do estado completo antes de cada commit.
|
|
72
|
+
|
|
73
|
+
`yuzuha/music` é um import adicional. Configure `music`/`voice` explicitamente;
|
|
74
|
+
o bot encerra os serviços fornecidos e o chamador fecha os nodes Lavalink.
|
|
75
|
+
`@fluxerjs/voice` é um peer opcional carregado em `join`. Para áudio Lavalink no
|
|
76
|
+
Fluxer, configure `FluxerLavalinkBridge` e instale o plugin `yuzuha-audio` fornecido
|
|
77
|
+
pelo Yuzuha no servidor; veja [MUSIC.md](docs/MUSIC.md).
|
|
78
|
+
Não há wrappers de música no function mode nesta versão.
|
|
79
|
+
|
|
80
|
+
Benchmarks agora exigem a versão exata do Node e o mesmo modo de GC, suíte e
|
|
81
|
+
carga. Relatórios de outro runtime devem ser executados novamente antes de comparar.
|
|
82
|
+
|
|
43
83
|
### Migrar para 0.1.5
|
|
44
84
|
|
|
45
85
|
Imports, argumentos posicionais e comandos existentes continuam disponíveis.
|
|
@@ -133,7 +173,7 @@ externos para idempotência. Veja [NATIVE.md](docs/NATIVE.md) e
|
|
|
133
173
|
|
|
134
174
|
### Procedimento
|
|
135
175
|
|
|
136
|
-
1. Atualize
|
|
176
|
+
1. Atualize `package.json` e regenere `package-lock.json` para a mesma versão.
|
|
137
177
|
2. Acrescente a entrada no [CHANGELOG.md](CHANGELOG.md), com data real e mudanças verificáveis.
|
|
138
178
|
3. Atualize migração, cobertura e documentação quando o contrato mudar.
|
|
139
179
|
4. Rode `npm run check` e `npm run smoke:package` e registre a evidência.
|
package/benchmarks/compare.mjs
CHANGED
|
@@ -2,17 +2,23 @@ export function compareReports(current, baseline) {
|
|
|
2
2
|
for (const field of ['platform', 'arch', 'cpu']) {
|
|
3
3
|
if (current[field] !== baseline[field]) throw new Error(`Baseline incompatível: ${field}.`);
|
|
4
4
|
}
|
|
5
|
-
if (current.node
|
|
5
|
+
if (current.node !== baseline.node) throw new Error('Baseline incompatível: versão exata do Node.');
|
|
6
|
+
if (current.suite !== baseline.suite) throw new Error('Baseline incompatível: suíte.');
|
|
7
|
+
if (baseline.gc !== undefined && current.gc !== baseline.gc) throw new Error('Baseline incompatível: GC explícito.');
|
|
6
8
|
for (const field of ['iterations', 'samples', 'concurrency']) {
|
|
7
9
|
if (current.config[field] !== baseline.config?.[field]) throw new Error(`Baseline incompatível: ${field}.`);
|
|
8
10
|
}
|
|
9
|
-
for (const field of ['catalogSize', 'payloadSize', 'soakRounds']) {
|
|
11
|
+
for (const field of ['catalogSize', 'payloadSize', 'soakRounds', 'stateKeys', 'queueSize', 'pageSize', 'fanout', 'warmup']) {
|
|
10
12
|
if (baseline.config?.[field] !== undefined && current.config[field] !== baseline.config[field]) throw new Error(`Baseline incompatível: ${field}.`);
|
|
11
13
|
}
|
|
12
14
|
if (!Array.isArray(baseline.results)) throw new Error('Baseline sem resultados.');
|
|
13
15
|
return current.results.map(row => {
|
|
14
16
|
const previous = baseline.results.find(item => item.name === row.name);
|
|
15
17
|
if (!previous) return { name: row.name, status: 'new' };
|
|
18
|
+
for (const field of ['iterations', 'unitsPerOperation']) {
|
|
19
|
+
if (previous[field] !== undefined && row[field] !== previous[field]) throw new Error(`Baseline incompatível: ${row.name}.${field}.`);
|
|
20
|
+
}
|
|
21
|
+
if (!(row.operationsPerSecond > 0) || !Number.isFinite(row.operationsPerSecond)) throw new Error(`Medição atual inválida: ${row.name}.`);
|
|
16
22
|
if (!(previous.operationsPerSecond > 0) || !Number.isFinite(previous.operationsPerSecond)) throw new Error(`Baseline inválida: ${row.name}.`);
|
|
17
23
|
const throughputChangePercent = (row.operationsPerSecond / previous.operationsPerSecond - 1) * 100;
|
|
18
24
|
return { name: row.name, status: 'compared', throughputChangePercent,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { performance } from 'node:perf_hooks';
|
|
3
|
+
import { cpus, platform, arch } from 'node:os';
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
import { createHash } from 'node:crypto';
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
import { pathToFileURL } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const modules = { current: new URL('../dist/scripting/parser.js', import.meta.url) };
|
|
10
|
+
for (let index = 2; index < process.argv.length; index += 2) {
|
|
11
|
+
const key = { '--parser-module': 'current', '--baseline-module': 'baseline' }[process.argv[index]];
|
|
12
|
+
const value = process.argv[index + 1];
|
|
13
|
+
if (!key || !value || value.startsWith('--')) throw new Error('Uso: node benchmarks/parser.mjs [--parser-module caminho] [--baseline-module caminho]');
|
|
14
|
+
modules[key] = pathToFileURL(resolve(value));
|
|
15
|
+
}
|
|
16
|
+
const implementations = {};
|
|
17
|
+
for (const [label, url] of Object.entries(modules)) implementations[label] = {
|
|
18
|
+
parse: (await import(url)).parse,
|
|
19
|
+
sourceHash: createHash('sha256').update(await readFile(url)).digest('hex'),
|
|
20
|
+
};
|
|
21
|
+
const iterations = 20_000, warmup = 2000, samples = 9, differentialCases = 20_000;
|
|
22
|
+
const cases = {
|
|
23
|
+
plain: 'a'.repeat(8000),
|
|
24
|
+
interpolated: `prefix ${'abc '.repeat(100)}$name suffix ${'xyz '.repeat(100)}`,
|
|
25
|
+
short: '$reply[Olá $username!]',
|
|
26
|
+
dense: '$f[a;b;$g[c]]'.repeat(20),
|
|
27
|
+
};
|
|
28
|
+
const outcome = (parse, source) => {
|
|
29
|
+
try { return parse(source); }
|
|
30
|
+
catch (error) { return { code: error.code, offset: error.offset, message: error.message }; }
|
|
31
|
+
};
|
|
32
|
+
if (implementations.baseline) {
|
|
33
|
+
const alphabet = ['a', '$', '[', ']', ';', '\\', 'é', '\n', '1'];
|
|
34
|
+
for (let seed = 0; seed < differentialCases; seed++) {
|
|
35
|
+
let state = seed + 1, source = '';
|
|
36
|
+
for (let index = 0; index < 50; index++) {
|
|
37
|
+
state = (Math.imul(state, 1664525) + 1013904223) >>> 0;
|
|
38
|
+
source += alphabet[state % alphabet.length];
|
|
39
|
+
}
|
|
40
|
+
assert.deepEqual(outcome(implementations.current.parse, source), outcome(implementations.baseline.parse, source), source);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const results = [];
|
|
44
|
+
for (const [name, source] of Object.entries(cases)) {
|
|
45
|
+
if (implementations.baseline) assert.deepEqual(implementations.current.parse(source), implementations.baseline.parse(source));
|
|
46
|
+
const times = Object.fromEntries(Object.keys(implementations).map(label => [label, []]));
|
|
47
|
+
for (let sample = 0; sample < samples; sample++) {
|
|
48
|
+
const entries = Object.entries(implementations);
|
|
49
|
+
if (sample % 2) entries.reverse();
|
|
50
|
+
for (const [label, { parse }] of entries) {
|
|
51
|
+
for (let index = 0; index < warmup; index++) parse(source);
|
|
52
|
+
const start = performance.now();
|
|
53
|
+
for (let index = 0; index < iterations; index++) parse(source);
|
|
54
|
+
times[label].push(performance.now() - start);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const [implementation, samplesMs] of Object.entries(times)) {
|
|
58
|
+
const sorted = [...samplesMs].sort((a, b) => a - b);
|
|
59
|
+
results.push({ name, implementation, characters: source.length, iterations, medianMs: sorted[Math.floor(samples / 2)], samplesMs });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
console.log(JSON.stringify({ suite: 'parser', date: new Date().toISOString(), node: process.versions.node,
|
|
63
|
+
platform: platform(), arch: arch(), cpu: cpus()[0]?.model, warmup, samples,
|
|
64
|
+
differentialCases: implementations.baseline ? differentialCases : 0,
|
|
65
|
+
modules: Object.fromEntries(Object.entries(implementations).map(([label, entry]) => [label, { path: modules[label].href, sourceHash: entry.sourceHash }])),
|
|
66
|
+
results }, null, 2));
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { performance } from 'node:perf_hooks';
|
|
3
|
+
import { arch, cpus, platform } from 'node:os';
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
|
+
import { compareReports } from './compare.mjs';
|
|
8
|
+
|
|
9
|
+
const config = { iterations: 10_000, samples: 9, concurrency: 1, catalogSize: 1000, payloadSize: 4096, stateKeys: 2000, json: false };
|
|
10
|
+
let packageRoot = fileURLToPath(new URL('../', import.meta.url)), baselinePath;
|
|
11
|
+
for (let i = 2; i < process.argv.length; i++) {
|
|
12
|
+
const key = process.argv[i];
|
|
13
|
+
if (key === '--json') { config.json = true; continue; }
|
|
14
|
+
if (key === '--package-root' || key === '--baseline') {
|
|
15
|
+
const path = process.argv[++i]; if (!path || path.startsWith('--')) throw new Error(`Informe ${key} <caminho>.`);
|
|
16
|
+
if (key === '--package-root') packageRoot = resolve(path); else baselinePath = path;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const name = { '--catalog-size': 'catalogSize', '--payload-size': 'payloadSize', '--state-keys': 'stateKeys' }[key] ?? key.slice(2);
|
|
20
|
+
const max = { iterations: 1_000_000, samples: 50, catalogSize: 10_000, payloadSize: 99_000, stateKeys: 10_000 }[name];
|
|
21
|
+
const value = Number(process.argv[++i]);
|
|
22
|
+
if (!max || !Number.isSafeInteger(value) || value < 1 || value > max) throw new Error(`Opção inválida: ${key}.`);
|
|
23
|
+
config[name] = value;
|
|
24
|
+
}
|
|
25
|
+
const source = pathToFileURL(resolve(packageRoot, 'dist/'));
|
|
26
|
+
source.pathname += source.pathname.endsWith('/') ? '' : '/';
|
|
27
|
+
const { Yuzuha, CommandContext, MemoryStore } = await import(new URL('index.js', source));
|
|
28
|
+
const { MockTransport, mockMessage } = await import(new URL('testing.js', source));
|
|
29
|
+
const manifest = JSON.parse(await readFile(resolve(packageRoot, 'package.json'), 'utf8'));
|
|
30
|
+
const results = [], bots = [];
|
|
31
|
+
const percentile = (values, fraction) => [...values].sort((a, b) => a - b)[Math.ceil(values.length * fraction) - 1];
|
|
32
|
+
async function measure(name, operation, iterations = config.iterations, units = 1) {
|
|
33
|
+
const run = async count => { for (let i = 0; i < count; i++) await operation(); };
|
|
34
|
+
await run(Math.min(iterations, 200)); global.gc?.();
|
|
35
|
+
const before = process.memoryUsage(), samples = [];
|
|
36
|
+
for (let sample = 0; sample < config.samples; sample++) {
|
|
37
|
+
const start = performance.now(); await run(iterations); samples.push(performance.now() - start);
|
|
38
|
+
}
|
|
39
|
+
global.gc?.(); const after = process.memoryUsage();
|
|
40
|
+
results.push({ name, iterations, unitsPerOperation: units, operations: iterations * units * config.samples, concurrency: 1,
|
|
41
|
+
medianMs: percentile(samples, 0.5), p95Ms: percentile(samples, 0.95), samplesMs: samples,
|
|
42
|
+
operationsPerSecond: iterations * units * config.samples / (samples.reduce((sum, value) => sum + value, 0) / 1000),
|
|
43
|
+
heapDeltaBytes: after.heapUsed - before.heapUsed, rssDeltaBytes: after.rss - before.rss });
|
|
44
|
+
}
|
|
45
|
+
function bot() {
|
|
46
|
+
const value = new Yuzuha({ transport: new MockTransport(), store: new MemoryStore(), scheduler: false, http: false }); bots.push(value); return value;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const dispatch = bot(); dispatch.command({ name: 'bench', run() {} });
|
|
50
|
+
for (const [name, content, authorBot] of [
|
|
51
|
+
['ordinary', 'a normal message', false], ['unknown', '!doesNotExist', false], ['bot', '!bench', true],
|
|
52
|
+
]) {
|
|
53
|
+
const message = mockMessage(content, { authorBot });
|
|
54
|
+
await measure(`dispatch/ignored-${name}`, async () => { assert.equal(await dispatch.handle(message), 'ignored'); });
|
|
55
|
+
}
|
|
56
|
+
const payload = 'x'.repeat(config.payloadSize);
|
|
57
|
+
for (const [name, input] of [['long-input', payload], ['quoted-long-input', `"${payload}"`], ['apostrophe-long-input', `${payload}'suffix`]]) {
|
|
58
|
+
const long = `!bench ${input}`;
|
|
59
|
+
await measure(`dispatch/${name}`, async () => {
|
|
60
|
+
assert.equal(await dispatch.handle(mockMessage(long)), 'success');
|
|
61
|
+
}, Math.max(1, Math.floor(config.iterations / 10)));
|
|
62
|
+
}
|
|
63
|
+
await measure('catalog/register', async () => {
|
|
64
|
+
const registered = new Yuzuha({ transport: new MockTransport(), store: new MemoryStore(), scheduler: false, http: false });
|
|
65
|
+
try {
|
|
66
|
+
for (let i = 0; i < config.catalogSize; i++) registered.command({ name: `item${i}`, run() {} });
|
|
67
|
+
assert.equal(registered.listCommands().length, config.catalogSize);
|
|
68
|
+
} finally { await registered.destroy(); }
|
|
69
|
+
}, 1, config.catalogSize);
|
|
70
|
+
const store = new MemoryStore(), ctx = new CommandContext({ store, command: { name: 'state' },
|
|
71
|
+
message: mockMessage(''), transport: new MockTransport(), cooldown: () => 0 });
|
|
72
|
+
await ctx.data.transaction(data => {
|
|
73
|
+
for (let i = 0; i < config.stateKeys; i++) data.guild.set(`item${i}`, { count: i, tags: ['one', 'two'] });
|
|
74
|
+
});
|
|
75
|
+
const expected = { count: config.stateKeys - 1, tags: ['one', 'two'] };
|
|
76
|
+
await measure('store/read-large-state', async () => {
|
|
77
|
+
assert.deepEqual(await ctx.data.guild.get(`item${config.stateKeys - 1}`), expected);
|
|
78
|
+
}, Math.max(1, Math.floor(config.iterations / 10)));
|
|
79
|
+
const report = { suite: 'performance', version: manifest.version, date: new Date().toISOString(), node: process.versions.node,
|
|
80
|
+
platform: platform(), arch: arch(), cpu: cpus()[0]?.model, gc: typeof global.gc === 'function', config, results };
|
|
81
|
+
if (baselinePath) report.comparison = compareReports(report, JSON.parse(await readFile(baselinePath, 'utf8')));
|
|
82
|
+
console.log(config.json ? JSON.stringify(report, null, 2) : [
|
|
83
|
+
`Yuzuha ${report.version} · Node ${report.node} · ${report.platform}/${report.arch}`,
|
|
84
|
+
...results.map(row => `${row.name}: ${row.operationsPerSecond.toFixed(0)} ops/s; mediana ${row.medianMs.toFixed(2)}ms`),
|
|
85
|
+
...(report.comparison ?? []).map(row => `${row.name}: ${row.status === 'new' ? 'novo' : `${row.throughputChangePercent.toFixed(1)}% ante baseline`}`),
|
|
86
|
+
].join('\n'));
|
|
87
|
+
} finally { await Promise.all(bots.map(value => value.destroy())); }
|