nodefony 7.0.2 → 10.0.0-alpha.2
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/.ai/symbols.json +36135 -0
- package/LICENSE +544 -0
- package/README.md +316 -694
- package/bin/nodefony +2183 -85
- package/dist/client/Container.js +367 -0
- package/dist/client/Event.js +198 -0
- package/dist/client/Service.js +344 -0
- package/dist/client/Tools.js +162 -0
- package/dist/client/client/ClientKernel.js +276 -0
- package/dist/client/client/angular/index.js +352 -0
- package/dist/client/client/announce.js +212 -0
- package/dist/client/client/debugbar/DebugBar.js +1624 -0
- package/dist/client/client/debugbar/format.js +103 -0
- package/dist/client/client/debugbar/hmr.js +37 -0
- package/dist/client/client/debugbar/index.js +29 -0
- package/dist/client/client/debugbar/model.js +133 -0
- package/dist/client/client/debugbar/network.js +173 -0
- package/dist/client/client/debugbar/profile.js +114 -0
- package/dist/client/client/index.js +34 -0
- package/dist/client/client/react/index.js +268 -0
- package/dist/client/client/realtime/AdaptiveRate.js +240 -0
- package/dist/client/client/realtime/BrowserWsTransport.js +57 -0
- package/dist/client/client/realtime/RealtimeClient.js +898 -0
- package/dist/client/client/realtime/localEvents.js +56 -0
- package/dist/client/client/realtime/notice.js +125 -0
- package/dist/client/client/realtime/observe.js +280 -0
- package/dist/client/client/roles/index.js +3 -0
- package/dist/client/client/roles/registry.js +97 -0
- package/dist/client/client/roles/roles.js +91 -0
- package/dist/client/client/shim/events.js +88 -0
- package/dist/client/client/shim/util.js +20 -0
- package/dist/client/client/svelte/index.js +319 -0
- package/dist/client/client/syslog/context.js +122 -0
- package/dist/client/client/syslog/errors.js +49 -0
- package/dist/client/client/syslog/uplink.js +106 -0
- package/dist/client/client/vue/index.js +321 -0
- package/dist/client/colors.js +63 -0
- package/dist/client/debugbar.standalone.js +4274 -0
- package/dist/client/realtime/IRealtimeTransport.js +32 -0
- package/dist/client/realtime/JsonRpcPeer.js +251 -0
- package/dist/client/realtime/channelRate.js +39 -0
- package/dist/client/realtime/platformChannels.js +155 -0
- package/dist/client/syslog/Pdu.js +224 -0
- package/dist/client/syslog/Syslog.js +1159 -0
- package/dist/client/syslog/drivers/pduFlow.js +106 -0
- package/dist/client/syslog/drivers/pduProtocol.js +28 -0
- package/dist/client/syslog/logColor.js +80 -0
- package/dist/client/types/src/Container.d.ts +221 -0
- package/dist/client/types/src/Event.d.ts +171 -0
- package/dist/client/types/src/FileClass.d.ts +184 -0
- package/dist/client/types/src/Service.d.ts +165 -0
- package/dist/client/types/src/Tools.d.ts +116 -0
- package/dist/client/types/src/client/ClientKernel.d.ts +90 -0
- package/dist/client/types/src/client/IClientKernel.d.ts +195 -0
- package/dist/client/types/src/client/angular/index.d.ts +273 -0
- package/dist/client/types/src/client/announce.d.ts +74 -0
- package/dist/client/types/src/client/debugbar/DebugBar.d.ts +279 -0
- package/dist/client/types/src/client/debugbar/format.d.ts +48 -0
- package/dist/client/types/src/client/debugbar/hmr.d.ts +16 -0
- package/dist/client/types/src/client/debugbar/index.d.ts +30 -0
- package/dist/client/types/src/client/debugbar/model.d.ts +158 -0
- package/dist/client/types/src/client/debugbar/network.d.ts +55 -0
- package/dist/client/types/src/client/debugbar/profile.d.ts +99 -0
- package/dist/client/types/src/client/index.d.ts +47 -0
- package/dist/client/types/src/client/react/index.d.ts +207 -0
- package/dist/client/types/src/client/realtime/AdaptiveRate.d.ts +138 -0
- package/dist/client/types/src/client/realtime/BrowserWsTransport.d.ts +27 -0
- package/dist/client/types/src/client/realtime/RealtimeClient.d.ts +573 -0
- package/dist/client/types/src/client/realtime/localEvents.d.ts +53 -0
- package/dist/client/types/src/client/realtime/notice.d.ts +70 -0
- package/dist/client/types/src/client/realtime/observe.d.ts +284 -0
- package/dist/client/types/src/client/roles/index.d.ts +15 -0
- package/dist/client/types/src/client/roles/registry.d.ts +72 -0
- package/dist/client/types/src/client/roles/roles.d.ts +68 -0
- package/dist/client/types/src/client/shim/cli-color.d.ts +2 -0
- package/dist/client/types/src/client/shim/events.d.ts +39 -0
- package/dist/client/types/src/client/shim/util.d.ts +14 -0
- package/dist/client/types/src/client/svelte/index.d.ts +216 -0
- package/dist/client/types/src/client/syslog/context.d.ts +76 -0
- package/dist/client/types/src/client/syslog/errors.d.ts +46 -0
- package/dist/client/types/src/client/syslog/uplink.d.ts +89 -0
- package/dist/client/types/src/client/transport/websocket.d.ts +5 -0
- package/dist/client/types/src/client/vue/index.d.ts +234 -0
- package/dist/client/types/src/colors.d.ts +32 -0
- package/dist/client/types/src/config/infra.d.ts +171 -0
- package/dist/client/types/src/kernel/bootReport.d.ts +112 -0
- package/dist/client/types/src/kernel/readinessRegistry.d.ts +104 -0
- package/dist/client/types/src/realtime/IRealtimeSocket.d.ts +142 -0
- package/dist/client/types/src/realtime/IRealtimeTransport.d.ts +50 -0
- package/dist/client/types/src/realtime/JsonRpcPeer.d.ts +251 -0
- package/dist/client/types/src/realtime/RealtimeEventMap.d.ts +269 -0
- package/dist/client/types/src/realtime/channelRate.d.ts +55 -0
- package/dist/client/types/src/realtime/platformChannels.d.ts +147 -0
- package/dist/client/types/src/syslog/Pdu.d.ts +134 -0
- package/dist/client/types/src/syslog/Syslog.d.ts +482 -0
- package/dist/client/types/src/syslog/drivers/ILogDriver.d.ts +177 -0
- package/dist/client/types/src/syslog/drivers/pduFlow.d.ts +53 -0
- package/dist/client/types/src/syslog/drivers/pduProtocol.d.ts +20 -0
- package/dist/client/types/src/syslog/logColor.d.ts +59 -0
- package/dist/client/types/src/types/ICliKernel.d.ts +28 -0
- package/dist/client/types/src/types/ICommand.d.ts +14 -0
- package/dist/client/types/src/types/IContainer.d.ts +35 -0
- package/dist/client/types/src/types/IKernel.d.ts +138 -0
- package/dist/client/types/src/types/IMcpTool.d.ts +157 -0
- package/dist/client/types/src/types/IModule.d.ts +73 -0
- package/dist/client/types/src/types/IPage.d.ts +119 -0
- package/dist/client/types/src/types/IService.d.ts +62 -0
- package/dist/client/types/src/types/ISyslog.d.ts +58 -0
- package/dist/client/types/src/types/ITransport.d.ts +5 -0
- package/dist/client/types/src/types/globals.d.ts +47 -0
- package/dist/node/Cli.js +750 -0
- package/dist/node/Container.js +367 -0
- package/dist/node/Error.js +309 -0
- package/dist/node/Event.js +198 -0
- package/dist/node/FileClass.js +308 -0
- package/dist/node/Nodefony.js +78 -0
- package/dist/node/Service.js +344 -0
- package/dist/node/Tools.js +205 -0
- package/dist/node/bin/resolveLocalCli.js +10 -0
- package/dist/node/bundler/index.js +103 -0
- package/dist/node/cli/agentTargets.js +461 -0
- package/dist/node/cli/aiMcp.js +553 -0
- package/dist/node/cli/aiMcpReport.js +129 -0
- package/dist/node/cli/aiSync.js +323 -0
- package/dist/node/cli/aiSyncReport.js +142 -0
- package/dist/node/cli/card.js +186 -0
- package/dist/node/cli/cardReport.js +110 -0
- package/dist/node/cli/completion.js +415 -0
- package/dist/node/cli/create.js +805 -0
- package/dist/node/cli/env.js +332 -0
- package/dist/node/cli/envReport.js +159 -0
- package/dist/node/cli/execPortable.js +60 -0
- package/dist/node/cli/gitHooks.js +191 -0
- package/dist/node/cli/gitHooksReport.js +119 -0
- package/dist/node/cli/globalFlags.js +67 -0
- package/dist/node/cli/helpReport.js +288 -0
- package/dist/node/cli/manPage.js +165 -0
- package/dist/node/cli/nodefonyBin.js +61 -0
- package/dist/node/cli/outdated.js +144 -0
- package/dist/node/cli/progress.js +555 -0
- package/dist/node/cli/projectRoot.js +32 -0
- package/dist/node/cli/promptPassword.js +44 -0
- package/dist/node/cli/prompts.js +86 -0
- package/dist/node/cli/scaffold/destination.js +92 -0
- package/dist/node/cli/scaffold/engine.js +2156 -0
- package/dist/node/cli/scaffold/entityFields.js +589 -0
- package/dist/node/cli/scaffold/format.js +243 -0
- package/dist/node/cli/scaffold/interactive.js +124 -0
- package/dist/node/cli/scaffold/moduleLayout.js +38 -0
- package/dist/node/cli/scaffold/reservedEntities.js +74 -0
- package/dist/node/cli/scaffold/spec.js +704 -0
- package/dist/node/cli/scaffold/steps.js +40 -0
- package/dist/node/cli/scaffold/userContractSource.js +133 -0
- package/dist/node/cli/scaffold/versions.js +57 -0
- package/dist/node/cli/scaffold/writer.js +172 -0
- package/dist/node/cli/startMenu.js +496 -0
- package/dist/node/cli/symbols.js +205 -0
- package/dist/node/cli/sysexits.js +34 -0
- package/dist/node/cli/tableReport.js +184 -0
- package/dist/node/cli/usageReport.js +144 -0
- package/dist/node/colors.js +63 -0
- package/dist/node/command/Builder.js +153 -0
- package/dist/node/command/Command.js +348 -0
- package/dist/node/config/configProvenance.js +101 -0
- package/dist/node/config/defaults.js +39 -0
- package/dist/node/config/defineConfig.js +129 -0
- package/dist/node/config/defineEnv.js +264 -0
- package/dist/node/config/envExample.js +41 -0
- package/dist/node/config/envOverride.js +423 -0
- package/dist/node/config/infra.js +163 -0
- package/dist/node/config/reactivity.js +23 -0
- package/dist/node/config/reservedEnv.js +118 -0
- package/dist/node/config/schema.js +134 -0
- package/dist/node/config/use.js +24 -0
- package/dist/node/finder/File.js +49 -0
- package/dist/node/finder/FileResult.js +86 -0
- package/dist/node/finder/Finder.js +201 -0
- package/dist/node/finder/Result.js +45 -0
- package/dist/node/index.js +121 -0
- package/dist/node/kernel/BootConfigurationError.js +54 -0
- package/dist/node/kernel/CliKernel.js +630 -0
- package/dist/node/kernel/Kernel.js +2198 -0
- package/dist/node/kernel/Module.js +453 -0
- package/dist/node/kernel/adminPlane/adminCaller.js +98 -0
- package/dist/node/kernel/adminPlane/adminRbac.js +51 -0
- package/dist/node/kernel/adminPlane/catalog.js +158 -0
- package/dist/node/kernel/adminPlane/executeAdmin.js +78 -0
- package/dist/node/kernel/checks/deep.js +335 -0
- package/dist/node/kernel/checks/freshness.js +139 -0
- package/dist/node/kernel/checks/gating.js +231 -0
- package/dist/node/kernel/checks/guards.js +232 -0
- package/dist/node/kernel/checks/lastBoot.js +136 -0
- package/dist/node/kernel/checks/live.js +330 -0
- package/dist/node/kernel/checks/packageDeps.js +292 -0
- package/dist/node/kernel/checks/readiness.js +153 -0
- package/dist/node/kernel/checks/renderReport.js +780 -0
- package/dist/node/kernel/checks/report.js +421 -0
- package/dist/node/kernel/checks/runDoctor.js +731 -0
- package/dist/node/kernel/checks/surface.js +364 -0
- package/dist/node/kernel/checks/walk.js +100 -0
- package/dist/node/kernel/checks/wiring.js +450 -0
- package/dist/node/kernel/commands/AiMcpCommand.js +65 -0
- package/dist/node/kernel/commands/AiSyncCommand.js +48 -0
- package/dist/node/kernel/commands/BuildCommand.js +49 -0
- package/dist/node/kernel/commands/CardCommand.js +50 -0
- package/dist/node/kernel/commands/ClusterCommand.js +58 -0
- package/dist/node/kernel/commands/CompletionCommand.js +31 -0
- package/dist/node/kernel/commands/CreateCommand.js +45 -0
- package/dist/node/kernel/commands/DevCommand.js +99 -0
- package/dist/node/kernel/commands/DoctorCommand.js +115 -0
- package/dist/node/kernel/commands/EnvCommand.js +52 -0
- package/dist/node/kernel/commands/GitHooksCommand.js +47 -0
- package/dist/node/kernel/commands/InspectCommand.js +153 -0
- package/dist/node/kernel/commands/InstallCommand.js +20 -0
- package/dist/node/kernel/commands/MenuCommand.js +261 -0
- package/dist/node/kernel/commands/OutdatedCommand.js +164 -0
- package/dist/node/kernel/commands/ProdCommand.js +60 -0
- package/dist/node/kernel/commands/StatusCommand.js +30 -0
- package/dist/node/kernel/commands/StopCommand.js +35 -0
- package/dist/node/kernel/commands/SymbolsCommand.js +45 -0
- package/dist/node/kernel/commands/runtimeLauncher.js +95 -0
- package/dist/node/kernel/decorators/kernelDecorator.js +110 -0
- package/dist/node/kernel/injector/injector.js +137 -0
- package/dist/node/kernel/injector/serviceOrder.js +106 -0
- package/dist/node/kernel/inspect/adminSubjects.js +194 -0
- package/dist/node/kernel/inspect/docOutline.js +86 -0
- package/dist/node/kernel/lifecycleTags.js +76 -0
- package/dist/node/kernel/moduleConfig.js +75 -0
- package/dist/node/kernel/moduleGating.js +68 -0
- package/dist/node/kernel/readinessRegistry.js +98 -0
- package/dist/node/kernel/resolveModuleEntry.js +61 -0
- package/dist/node/mcp/caller.js +40 -0
- package/dist/node/mcp/guard.js +51 -0
- package/dist/node/mcp/protocol.js +157 -0
- package/dist/node/mcp/server.js +216 -0
- package/dist/node/mcp/tools.js +861 -0
- package/dist/node/oauth/authorizationServer.js +221 -0
- package/dist/node/oauth/protectedResource.js +293 -0
- package/dist/node/package.js +4 -0
- package/dist/node/realtime/IRealtimeTransport.js +32 -0
- package/dist/node/realtime/JsonRpcPeer.js +251 -0
- package/dist/node/realtime/RealtimeEventMap.js +15 -0
- package/dist/node/realtime/channelRate.js +39 -0
- package/dist/node/realtime/platformChannels.js +155 -0
- package/dist/node/runtime/GcScheduler.js +92 -0
- package/dist/node/runtime/RequestContext.js +76 -0
- package/dist/node/runtime/bearer.js +84 -0
- package/dist/node/runtime/engineEnvironment.js +79 -0
- package/dist/node/runtime/loadEnv.js +105 -0
- package/dist/node/runtime/pageFacets.js +85 -0
- package/dist/node/runtime/pageFilters.js +103 -0
- package/dist/node/runtime/pageGuard.js +84 -0
- package/dist/node/runtime/pageQuery.js +160 -0
- package/dist/node/runtime/pageSort.js +114 -0
- package/dist/node/runtime/redact.js +43 -0
- package/dist/node/runtime/withTimeout.js +71 -0
- package/dist/node/service/cluster/ClusterManager.js +202 -0
- package/dist/node/service/cluster/ClusterProbeAggregator.js +120 -0
- package/dist/node/service/cluster/ClusterRelay.js +74 -0
- package/dist/node/service/cluster/clusterMaster.js +65 -0
- package/dist/node/service/cluster/clusterMessage.js +70 -0
- package/dist/node/service/cluster/cpuQuota.js +59 -0
- package/dist/node/service/cluster/instanceProbe.js +52 -0
- package/dist/node/service/cluster/podEnvironment.js +48 -0
- package/dist/node/service/cluster/processProbe.js +70 -0
- package/dist/node/service/cluster/richProcessProbe.js +115 -0
- package/dist/node/service/cluster/topology.js +71 -0
- package/dist/node/service/dev/BootReporter.js +490 -0
- package/dist/node/service/dev/DevSupervisor.js +1004 -0
- package/dist/node/service/dev/bootVerdict.js +158 -0
- package/dist/node/service/dev/detachedStart.js +372 -0
- package/dist/node/service/dev/devProcess.js +1137 -0
- package/dist/node/service/dev/devProjects.js +138 -0
- package/dist/node/service/dev/devStatusReport.js +395 -0
- package/dist/node/service/dev/devStop.js +263 -0
- package/dist/node/service/fetchService.js +35 -0
- package/dist/node/service/gitService.js +62 -0
- package/dist/node/syslog/Pdu.js +224 -0
- package/dist/node/syslog/Syslog.js +1159 -0
- package/dist/node/syslog/drivers/ClusterFileLogDriver.js +114 -0
- package/dist/node/syslog/drivers/FileLogDriver.js +127 -0
- package/dist/node/syslog/drivers/ILogDriver.js +26 -0
- package/dist/node/syslog/drivers/LokiLogDriver.js +144 -0
- package/dist/node/syslog/drivers/MemoryLogDriver.js +33 -0
- package/dist/node/syslog/drivers/OpenSearchLogDriver.js +159 -0
- package/dist/node/syslog/drivers/builtinLogDrivers.js +114 -0
- package/dist/node/syslog/drivers/filterPdus.js +71 -0
- package/dist/node/syslog/drivers/logDriverRegistry.js +83 -0
- package/dist/node/syslog/drivers/opensearchShared.js +17 -0
- package/dist/node/syslog/drivers/pduFlow.js +106 -0
- package/dist/node/syslog/drivers/pduProtocol.js +28 -0
- package/dist/node/syslog/httpFetch.js +43 -0
- package/dist/node/syslog/logColor.js +80 -0
- package/dist/node/syslog/sinks/FileSink.js +142 -0
- package/dist/node/syslog/transports/BatchingHttpTransport.js +98 -0
- package/dist/node/syslog/transports/ConsoleTransport.js +14 -0
- package/dist/node/syslog/transports/FileTransport.js +17 -0
- package/dist/node/syslog/transports/HttpTransport.js +44 -0
- package/dist/node/syslog/transports/LokiTransport.js +80 -0
- package/dist/node/syslog/transports/OpenSearchTransport.js +53 -0
- package/dist/node/syslog/transports/SyslogTransport.js +13 -0
- package/dist/node/syslog/transports/index.js +8 -0
- package/dist/node/testing/index.js +190 -0
- package/dist/types/Cli.d.ts +177 -0
- package/dist/types/Container.d.ts +221 -0
- package/dist/types/Error.d.ts +162 -0
- package/dist/types/Event.d.ts +171 -0
- package/dist/types/FileClass.d.ts +184 -0
- package/dist/types/Nodefony.d.ts +66 -0
- package/dist/types/Service.d.ts +165 -0
- package/dist/types/Tools.d.ts +116 -0
- package/dist/types/bin/resolveLocalCli.d.ts +49 -0
- package/dist/types/bundler/index.d.ts +66 -0
- package/dist/types/cli/agentTargets.d.ts +378 -0
- package/dist/types/cli/aiMcp.d.ts +239 -0
- package/dist/types/cli/aiMcpReport.d.ts +113 -0
- package/dist/types/cli/aiSync.d.ts +68 -0
- package/dist/types/cli/aiSyncReport.d.ts +149 -0
- package/dist/types/cli/card.d.ts +49 -0
- package/dist/types/cli/cardReport.d.ts +127 -0
- package/dist/types/cli/completion.d.ts +154 -0
- package/dist/types/cli/create.d.ts +177 -0
- package/dist/types/cli/env.d.ts +103 -0
- package/dist/types/cli/envReport.d.ts +153 -0
- package/dist/types/cli/execPortable.d.ts +54 -0
- package/dist/types/cli/gitHooks.d.ts +48 -0
- package/dist/types/cli/gitHooksReport.d.ts +101 -0
- package/dist/types/cli/globalFlags.d.ts +48 -0
- package/dist/types/cli/helpReport.d.ts +110 -0
- package/dist/types/cli/manPage.d.ts +21 -0
- package/dist/types/cli/nodefonyBin.d.ts +45 -0
- package/dist/types/cli/outdated.d.ts +119 -0
- package/dist/types/cli/progress.d.ts +349 -0
- package/dist/types/cli/projectRoot.d.ts +19 -0
- package/dist/types/cli/promptPassword.d.ts +22 -0
- package/dist/types/cli/prompts.d.ts +102 -0
- package/dist/types/cli/scaffold/destination.d.ts +70 -0
- package/dist/types/cli/scaffold/engine.d.ts +545 -0
- package/dist/types/cli/scaffold/entityFields.d.ts +238 -0
- package/dist/types/cli/scaffold/format.d.ts +78 -0
- package/dist/types/cli/scaffold/interactive.d.ts +11 -0
- package/dist/types/cli/scaffold/moduleLayout.d.ts +69 -0
- package/dist/types/cli/scaffold/reservedEntities.d.ts +49 -0
- package/dist/types/cli/scaffold/spec.d.ts +159 -0
- package/dist/types/cli/scaffold/steps.d.ts +24 -0
- package/dist/types/cli/scaffold/userContractSource.d.ts +86 -0
- package/dist/types/cli/scaffold/versions.d.ts +14 -0
- package/dist/types/cli/scaffold/writer.d.ts +100 -0
- package/dist/types/cli/startMenu.d.ts +195 -0
- package/dist/types/cli/symbols.d.ts +84 -0
- package/dist/types/cli/sysexits.d.ts +31 -0
- package/dist/types/cli/tableReport.d.ts +44 -0
- package/dist/types/cli/usageReport.d.ts +108 -0
- package/dist/types/client/ClientKernel.d.ts +90 -0
- package/dist/types/client/IClientKernel.d.ts +195 -0
- package/dist/types/client/angular/index.d.ts +273 -0
- package/dist/types/client/announce.d.ts +74 -0
- package/dist/types/client/debugbar/DebugBar.d.ts +279 -0
- package/dist/types/client/debugbar/format.d.ts +48 -0
- package/dist/types/client/debugbar/hmr.d.ts +16 -0
- package/dist/types/client/debugbar/index.d.ts +30 -0
- package/dist/types/client/debugbar/model.d.ts +158 -0
- package/dist/types/client/debugbar/network.d.ts +55 -0
- package/dist/types/client/debugbar/profile.d.ts +99 -0
- package/dist/types/client/index.d.ts +47 -0
- package/dist/types/client/react/index.d.ts +207 -0
- package/dist/types/client/realtime/AdaptiveRate.d.ts +138 -0
- package/dist/types/client/realtime/BrowserWsTransport.d.ts +27 -0
- package/dist/types/client/realtime/RealtimeClient.d.ts +573 -0
- package/dist/types/client/realtime/localEvents.d.ts +53 -0
- package/dist/types/client/realtime/notice.d.ts +70 -0
- package/dist/types/client/realtime/observe.d.ts +284 -0
- package/dist/types/client/roles/index.d.ts +15 -0
- package/dist/types/client/roles/registry.d.ts +72 -0
- package/dist/types/client/roles/roles.d.ts +68 -0
- package/dist/types/client/shim/cli-color.d.ts +2 -0
- package/dist/types/client/shim/events.d.ts +39 -0
- package/dist/types/client/shim/util.d.ts +14 -0
- package/dist/types/client/svelte/index.d.ts +216 -0
- package/dist/types/client/syslog/context.d.ts +76 -0
- package/dist/types/client/syslog/errors.d.ts +46 -0
- package/dist/types/client/syslog/uplink.d.ts +89 -0
- package/dist/types/client/transport/websocket.d.ts +5 -0
- package/dist/types/client/vue/index.d.ts +234 -0
- package/dist/types/colors.d.ts +32 -0
- package/dist/types/command/Builder.d.ts +47 -0
- package/dist/types/command/Command.d.ts +268 -0
- package/dist/types/config/configMeta.d.ts +53 -0
- package/dist/types/config/configProvenance.d.ts +58 -0
- package/dist/types/config/defaults.d.ts +33 -0
- package/dist/types/config/defineConfig.d.ts +70 -0
- package/dist/types/config/defineEnv.d.ts +170 -0
- package/dist/types/config/envExample.d.ts +23 -0
- package/dist/types/config/envOverride.d.ts +236 -0
- package/dist/types/config/index.d.ts +23 -0
- package/dist/types/config/infra.d.ts +171 -0
- package/dist/types/config/reactivity.d.ts +36 -0
- package/dist/types/config/reservedEnv.d.ts +145 -0
- package/dist/types/config/schema.d.ts +113 -0
- package/dist/types/config/types.d.ts +374 -0
- package/dist/types/config/use.d.ts +80 -0
- package/dist/types/finder/File.d.ts +26 -0
- package/dist/types/finder/FileResult.d.ts +14 -0
- package/dist/types/finder/Finder.d.ts +51 -0
- package/dist/types/finder/Result.d.ts +10 -0
- package/dist/types/index.d.ts +205 -0
- package/dist/types/kernel/BootConfigurationError.d.ts +50 -0
- package/dist/types/kernel/CliKernel.d.ts +289 -0
- package/dist/types/kernel/Kernel.d.ts +1255 -0
- package/dist/types/kernel/Module.d.ts +326 -0
- package/dist/types/kernel/adminPlane/adminCaller.d.ts +105 -0
- package/dist/types/kernel/adminPlane/adminRbac.d.ts +44 -0
- package/dist/types/kernel/adminPlane/catalog.d.ts +122 -0
- package/dist/types/kernel/adminPlane/executeAdmin.d.ts +99 -0
- package/dist/types/kernel/bootReport.d.ts +112 -0
- package/dist/types/kernel/checks/deep.d.ts +122 -0
- package/dist/types/kernel/checks/freshness.d.ts +49 -0
- package/dist/types/kernel/checks/gating.d.ts +134 -0
- package/dist/types/kernel/checks/guards.d.ts +57 -0
- package/dist/types/kernel/checks/lastBoot.d.ts +189 -0
- package/dist/types/kernel/checks/live.d.ts +110 -0
- package/dist/types/kernel/checks/packageDeps.d.ts +44 -0
- package/dist/types/kernel/checks/readiness.d.ts +97 -0
- package/dist/types/kernel/checks/renderReport.d.ts +107 -0
- package/dist/types/kernel/checks/report.d.ts +414 -0
- package/dist/types/kernel/checks/runDoctor.d.ts +361 -0
- package/dist/types/kernel/checks/surface.d.ts +148 -0
- package/dist/types/kernel/checks/walk.d.ts +45 -0
- package/dist/types/kernel/checks/wiring.d.ts +54 -0
- package/dist/types/kernel/commands/AiMcpCommand.d.ts +39 -0
- package/dist/types/kernel/commands/AiSyncCommand.d.ts +28 -0
- package/dist/types/kernel/commands/BuildCommand.d.ts +13 -0
- package/dist/types/kernel/commands/CardCommand.d.ts +34 -0
- package/dist/types/kernel/commands/ClusterCommand.d.ts +29 -0
- package/dist/types/kernel/commands/CompletionCommand.d.ts +17 -0
- package/dist/types/kernel/commands/CreateCommand.d.ts +16 -0
- package/dist/types/kernel/commands/DevCommand.d.ts +40 -0
- package/dist/types/kernel/commands/DoctorCommand.d.ts +55 -0
- package/dist/types/kernel/commands/EnvCommand.d.ts +35 -0
- package/dist/types/kernel/commands/GitHooksCommand.d.ts +27 -0
- package/dist/types/kernel/commands/InspectCommand.d.ts +59 -0
- package/dist/types/kernel/commands/InstallCommand.d.ts +7 -0
- package/dist/types/kernel/commands/MenuCommand.d.ts +58 -0
- package/dist/types/kernel/commands/OutdatedCommand.d.ts +47 -0
- package/dist/types/kernel/commands/ProdCommand.d.ts +29 -0
- package/dist/types/kernel/commands/StatusCommand.d.ts +17 -0
- package/dist/types/kernel/commands/StopCommand.d.ts +17 -0
- package/dist/types/kernel/commands/SymbolsCommand.d.ts +29 -0
- package/dist/types/kernel/commands/runtimeLauncher.d.ts +76 -0
- package/dist/types/kernel/decorators/kernelDecorator.d.ts +76 -0
- package/dist/types/kernel/injector/injector.d.ts +47 -0
- package/dist/types/kernel/injector/serviceOrder.d.ts +29 -0
- package/dist/types/kernel/inspect/adminSubjects.d.ts +169 -0
- package/dist/types/kernel/inspect/docOutline.d.ts +53 -0
- package/dist/types/kernel/lifecycleTags.d.ts +79 -0
- package/dist/types/kernel/moduleConfig.d.ts +35 -0
- package/dist/types/kernel/moduleGating.d.ts +78 -0
- package/dist/types/kernel/readinessRegistry.d.ts +104 -0
- package/dist/types/kernel/resolveModuleEntry.d.ts +46 -0
- package/dist/types/mcp/caller.d.ts +55 -0
- package/dist/types/mcp/guard.d.ts +66 -0
- package/dist/types/mcp/protocol.d.ts +163 -0
- package/dist/types/mcp/server.d.ts +70 -0
- package/dist/types/mcp/tools.d.ts +209 -0
- package/dist/types/oauth/authorizationServer.d.ts +204 -0
- package/dist/types/oauth/protectedResource.d.ts +339 -0
- package/dist/types/realtime/IRealtimeSocket.d.ts +142 -0
- package/dist/types/realtime/IRealtimeTransport.d.ts +50 -0
- package/dist/types/realtime/JsonRpcPeer.d.ts +251 -0
- package/dist/types/realtime/RealtimeEventMap.d.ts +269 -0
- package/dist/types/realtime/channelRate.d.ts +55 -0
- package/dist/types/realtime/platformChannels.d.ts +147 -0
- package/dist/types/runtime/GcScheduler.d.ts +96 -0
- package/dist/types/runtime/RequestContext.d.ts +152 -0
- package/dist/types/runtime/bearer.d.ts +88 -0
- package/dist/types/runtime/engineEnvironment.d.ts +115 -0
- package/dist/types/runtime/loadEnv.d.ts +86 -0
- package/dist/types/runtime/pageFacets.d.ts +104 -0
- package/dist/types/runtime/pageFilters.d.ts +139 -0
- package/dist/types/runtime/pageGuard.d.ts +78 -0
- package/dist/types/runtime/pageQuery.d.ts +138 -0
- package/dist/types/runtime/pageSort.d.ts +86 -0
- package/dist/types/runtime/redact.d.ts +27 -0
- package/dist/types/runtime/withTimeout.d.ts +51 -0
- package/dist/types/service/cluster/ClusterManager.d.ts +112 -0
- package/dist/types/service/cluster/ClusterProbeAggregator.d.ts +68 -0
- package/dist/types/service/cluster/ClusterRelay.d.ts +57 -0
- package/dist/types/service/cluster/clusterMaster.d.ts +40 -0
- package/dist/types/service/cluster/clusterMessage.d.ts +94 -0
- package/dist/types/service/cluster/cpuQuota.d.ts +37 -0
- package/dist/types/service/cluster/instanceProbe.d.ts +82 -0
- package/dist/types/service/cluster/podEnvironment.d.ts +35 -0
- package/dist/types/service/cluster/processProbe.d.ts +53 -0
- package/dist/types/service/cluster/richProcessProbe.d.ts +77 -0
- package/dist/types/service/cluster/topology.d.ts +64 -0
- package/dist/types/service/dev/BootReporter.d.ts +67 -0
- package/dist/types/service/dev/DevSupervisor.d.ts +117 -0
- package/dist/types/service/dev/bootVerdict.d.ts +99 -0
- package/dist/types/service/dev/detachedStart.d.ts +164 -0
- package/dist/types/service/dev/devProcess.d.ts +638 -0
- package/dist/types/service/dev/devProjects.d.ts +121 -0
- package/dist/types/service/dev/devStatusReport.d.ts +141 -0
- package/dist/types/service/dev/devStop.d.ts +57 -0
- package/dist/types/service/fetchService.d.ts +29 -0
- package/dist/types/service/gitService.d.ts +24 -0
- package/dist/types/syslog/Pdu.d.ts +134 -0
- package/dist/types/syslog/Syslog.d.ts +482 -0
- package/dist/types/syslog/drivers/ClusterFileLogDriver.d.ts +40 -0
- package/dist/types/syslog/drivers/FileLogDriver.d.ts +55 -0
- package/dist/types/syslog/drivers/ILogDriver.d.ts +177 -0
- package/dist/types/syslog/drivers/LokiLogDriver.d.ts +44 -0
- package/dist/types/syslog/drivers/MemoryLogDriver.d.ts +20 -0
- package/dist/types/syslog/drivers/OpenSearchLogDriver.d.ts +40 -0
- package/dist/types/syslog/drivers/builtinLogDrivers.d.ts +43 -0
- package/dist/types/syslog/drivers/filterPdus.d.ts +21 -0
- package/dist/types/syslog/drivers/logDriverRegistry.d.ts +100 -0
- package/dist/types/syslog/drivers/opensearchShared.d.ts +11 -0
- package/dist/types/syslog/drivers/pduFlow.d.ts +53 -0
- package/dist/types/syslog/drivers/pduProtocol.d.ts +20 -0
- package/dist/types/syslog/httpFetch.d.ts +48 -0
- package/dist/types/syslog/logColor.d.ts +59 -0
- package/dist/types/syslog/sinks/FileSink.d.ts +78 -0
- package/dist/types/syslog/transports/BatchingHttpTransport.d.ts +59 -0
- package/dist/types/syslog/transports/ConsoleTransport.d.ts +8 -0
- package/dist/types/syslog/transports/FileTransport.d.ts +13 -0
- package/dist/types/syslog/transports/HttpTransport.d.ts +15 -0
- package/dist/types/syslog/transports/LokiTransport.d.ts +45 -0
- package/dist/types/syslog/transports/OpenSearchTransport.d.ts +40 -0
- package/dist/types/syslog/transports/SyslogTransport.d.ts +9 -0
- package/dist/types/syslog/transports/index.d.ts +12 -0
- package/dist/types/testing/index.d.ts +197 -0
- package/dist/types/types/IAdminApi.d.ts +246 -0
- package/dist/types/types/ICliKernel.d.ts +28 -0
- package/dist/types/types/ICommand.d.ts +14 -0
- package/dist/types/types/IContainer.d.ts +35 -0
- package/dist/types/types/IIdempotencyStore.d.ts +159 -0
- package/dist/types/types/IKernel.d.ts +138 -0
- package/dist/types/types/IMcpTool.d.ts +157 -0
- package/dist/types/types/IModule.d.ts +73 -0
- package/dist/types/types/IModuleManifest.d.ts +49 -0
- package/dist/types/types/IPage.d.ts +119 -0
- package/dist/types/types/IService.d.ts +62 -0
- package/dist/types/types/ISyslog.d.ts +58 -0
- package/dist/types/types/ITransport.d.ts +5 -0
- package/dist/types/types/globals.d.ts +47 -0
- package/docs/angular-services.md +318 -0
- package/docs/catalogue.md +184 -0
- package/docs/cli.md +369 -0
- package/docs/client.md +616 -0
- package/docs/debugbar.md +218 -0
- package/docs/environnement.md +308 -0
- package/docs/index.md +388 -0
- package/docs/kernel.md +670 -0
- package/docs/progression.md +228 -0
- package/docs/react-hooks.md +686 -0
- package/docs/request-context.md +507 -0
- package/docs/service.md +590 -0
- package/docs/svelte-reactivite.md +293 -0
- package/docs/syslog.md +848 -0
- package/docs/testing.md +203 -0
- package/docs/vue-composables.md +255 -0
- package/man/nodefony.1 +152 -0
- package/package.json +163 -83
- package/templates/app/agents/AGENTS.md.tpl +967 -0
- package/templates/app/agents/POINTEUR.md.tpl +12 -0
- package/templates/app/base/Dockerfile.tpl +104 -0
- package/templates/app/base/README.md.tpl +314 -0
- package/templates/app/base/dockerignore.tpl +28 -0
- package/templates/app/base/env.ts.tpl +130 -0
- package/templates/app/base/gitattributes.tpl +28 -0
- package/templates/app/base/github/workflows/ci.yml.tpl +91 -0
- package/templates/app/base/gitignore.tpl +46 -0
- package/templates/app/base/gitlab-ci.yml.tpl +42 -0
- package/templates/app/base/index.ts.tpl +69 -0
- package/templates/app/base/nodefony.config.ts.tpl +342 -0
- package/templates/app/base/oxlintrc.json.tpl +127 -0
- package/templates/app/base/package.json.tpl +75 -0
- package/templates/app/base/prettierignore.tpl +24 -0
- package/templates/app/base/prettierrc.json.tpl +12 -0
- package/templates/app/base/rolldown.config.ts.tpl +8 -0
- package/templates/app/base/tests/config.test.ts.tpl +29 -0
- package/templates/app/base/tests/e2e.setup.ts.tpl +181 -0
- package/templates/app/base/tests/e2e.test.ts.tpl +105 -0
- package/templates/app/base/tests/migrations.e2e.test.ts.tpl +579 -0
- package/templates/app/base/tsconfig.json.tpl +47 -0
- package/templates/app/base/vitest.config.ts.tpl +88 -0
- package/templates/app/base/vitest.e2e.config.ts.tpl +39 -0
- package/templates/app/complete/compose.yaml.tpl +328 -0
- package/templates/app/complete/deploy/migrate-job.yaml.tpl +100 -0
- package/templates/app/complete/docker/db/init-nodefony-e2e.sql.tpl +30 -0
- package/templates/app/complete/docker/grafana/provisioning/datasources/loki.yaml.tpl +15 -0
- package/templates/app/complete/env.local.tpl +11 -0
- package/templates/app/complete/env.tpl +53 -0
- package/templates/app/complete/nodefony/entity/User.ts.tpl +69 -0
- package/templates/app/complete/nodefony/security/provisionUsers.ts.tpl +124 -0
- package/templates/app/complete/nodefony/service/AppBannerService.ts.tpl +98 -0
- package/templates/app/complete/nodefony/service/AppInfoService.ts.tpl +85 -0
- package/templates/app/frontend/angular/frontend/src/accent.css.tpl +34 -0
- package/templates/app/frontend/angular/frontend/src/app/app.component.ts.tpl +400 -0
- package/templates/app/frontend/react/frontend/src/App.tsx.tpl +421 -0
- package/templates/app/frontend/react/frontend/src/accent.css.tpl +30 -0
- package/templates/app/frontend/shared/frontend/src/brand.ts.tpl +3 -0
- package/templates/app/frontend/shared/frontend/src/showcase.css.tpl +224 -0
- package/templates/app/frontend/shared/nodefony/controllers/AppController.ts.tpl +45 -0
- package/templates/app/frontend/svelte/frontend/src/App.svelte.tpl +371 -0
- package/templates/app/frontend/svelte/frontend/src/accent.css.tpl +34 -0
- package/templates/app/frontend/vue/frontend/src/App.vue.tpl +367 -0
- package/templates/app/frontend/vue/frontend/src/accent.css.tpl +34 -0
- package/templates/app/home/nodefony/controllers/HomeController.ts.tpl +38 -0
- package/templates/command/nodefony/command/__NAME__.ts.tpl +132 -0
- package/templates/controller/duplex/nodefony/controllers/__NAME__.ts.tpl +188 -0
- package/templates/controller/example/nodefony/controllers/__NAME__.ts.tpl +348 -0
- package/templates/controller/hello/nodefony/controllers/__NAME__.ts.tpl +143 -0
- package/templates/controller/realtime/nodefony/controllers/__NAME__.ts.tpl +153 -0
- package/templates/controller/realtime/tests/__KEBAB__-realtime.test.ts.tpl +79 -0
- package/templates/controller/rest/nodefony/controllers/__NAME__.ts.tpl +159 -0
- package/templates/entity/base/nodefony/entity/__PASCAL__.schema.ts.tpl +31 -0
- package/templates/entity/base/nodefony/entity/__PASCAL__.ts.tpl +68 -0
- package/templates/entity/controller/nodefony/controllers/__PASCAL__Controller.ts.tpl +335 -0
- package/templates/entity/service/nodefony/service/__PASCAL__Service.ts.tpl +126 -0
- package/templates/entity/tests/tests/__KEBAB__.e2e.test.ts.tpl +358 -0
- package/templates/entity/tests/tests/__KEBAB__.test.ts.tpl +87 -0
- package/templates/front/angular/frontend/src/app/app.component.ts.tpl +30 -0
- package/templates/front/base/nodefony/controllers/__NAME__.ts.tpl +60 -0
- package/templates/front/react/frontend/src/App.tsx.tpl +26 -0
- package/templates/front/svelte/frontend/src/App.svelte.tpl +19 -0
- package/templates/front/vue/frontend/src/App.vue.tpl +23 -0
- package/templates/module/ai/AGENTS.md.tpl +71 -0
- package/templates/module/base/README.md.tpl +62 -0
- package/templates/module/base/docs/index.md.tpl +55 -0
- package/templates/module/base/index.ts.tpl +50 -0
- package/templates/module/base/nodefony/config/config.ts.tpl +60 -0
- package/templates/module/base/nodefony/config/defineModuleConfig.ts.tpl +55 -0
- package/templates/module/base/nodefony/src/errors/__PASCAL__Error.ts.tpl +20 -0
- package/templates/module/base/package.json.tpl +53 -0
- package/templates/module/base/rolldown.config.ts.tpl +14 -0
- package/templates/module/base/tests/__KEBAB__.test.ts.tpl +39 -0
- package/templates/module/base/tsconfig.json.tpl +42 -0
- package/templates/module/base/vitest.config.ts.tpl +27 -0
- package/templates/module/packages/CLAUDE.md.tpl +51 -0
- package/templates/module/packages/MEMORY.md.tpl +39 -0
- package/templates/module/packages/tsconfig.declarations.json.tpl +19 -0
- package/templates/module/packages/tsconfig.tests.json.tpl +11 -0
- package/templates/module/service/nodefony/interfaces/I__PASCAL__Service.ts.tpl +14 -0
- package/templates/module/service/nodefony/interfaces/index.ts.tpl +1 -0
- package/templates/module/service/nodefony/service/__PASCAL__Service.ts.tpl +116 -0
- package/templates/service/nodefony/interfaces/I__PASCAL__Service.ts.tpl +19 -0
- package/templates/service/nodefony/service/__PASCAL__Service.ts.tpl +136 -0
- package/templates/service/tests/__PASCAL__Service.test.ts.tpl +53 -0
- package/templates/shared/front-entry/angular/frontend/src/main.ts.tpl +17 -0
- package/templates/shared/front-entry/react/frontend/src/main.tsx.tpl +11 -0
- package/templates/shared/front-entry/svelte/frontend/src/main.ts.tpl +13 -0
- package/templates/shared/front-entry/vue/frontend/src/main.ts.tpl +12 -0
- package/templates/shared/front-registrar/nodefony/frontend/register__PASCAL__Entry.ts.tpl +40 -0
- package/templates/shared/front-shell/frontend/index.html.tpl +39 -0
- package/templates/shared/ng-app-tsconfig/frontend/tsconfig.app.json.tpl +18 -0
- package/templates/shared/svelte-shim/frontend/src/env.d.ts.tpl +12 -0
- package/templates/shared/vue-shim/frontend/src/env.d.ts.tpl +15 -0
- package/.yarnclean +0 -45
- package/CHANGELOG.md +0 -406
- package/autoloader.es6 +0 -253
- package/builder.es6 +0 -366
- package/cli/builder/bundles/bundle.js +0 -328
- package/cli/builder/bundles/controller.js +0 -73
- package/cli/builder/bundles/users-bundle/.yarnclean +0 -45
- package/cli/builder/bundles/users-bundle/Command/fixtureTask.js +0 -47
- package/cli/builder/bundles/users-bundle/Command/usersCommand.js +0 -105
- package/cli/builder/bundles/users-bundle/Entity/mongoose/userEntity.js +0 -168
- package/cli/builder/bundles/users-bundle/Entity/sequelize/userEntity.js +0 -231
- package/cli/builder/bundles/users-bundle/Fixtures/users.js +0 -117
- package/cli/builder/bundles/users-bundle/Fixtures/usersFixtures.js +0 -114
- package/cli/builder/bundles/users-bundle/Resources/config/config.js +0 -90
- package/cli/builder/bundles/users-bundle/Resources/config/routing.js +0 -17
- package/cli/builder/bundles/users-bundle/Resources/config/security.js +0 -96
- package/cli/builder/bundles/users-bundle/Resources/config/services.js +0 -7
- package/cli/builder/bundles/users-bundle/Resources/config/webpack/webpack.dev.config.js +0 -13
- package/cli/builder/bundles/users-bundle/Resources/config/webpack/webpack.prod.config.js +0 -31
- package/cli/builder/bundles/users-bundle/Resources/config/webpack.config.js +0 -146
- package/cli/builder/bundles/users-bundle/Resources/js/users.js +0 -153
- package/cli/builder/bundles/users-bundle/Resources/public/favicon.ico +0 -0
- package/cli/builder/bundles/users-bundle/Resources/public/images/users-logo.png +0 -0
- package/cli/builder/bundles/users-bundle/Resources/scss/awesome/font-awesome.config.js +0 -11
- package/cli/builder/bundles/users-bundle/Resources/scss/custom.scss +0 -23
- package/cli/builder/bundles/users-bundle/Resources/scss/users.scss +0 -59
- package/cli/builder/bundles/users-bundle/Resources/swagger/openapi/login.js +0 -235
- package/cli/builder/bundles/users-bundle/Resources/swagger/openapi/users.js +0 -232
- package/cli/builder/bundles/users-bundle/Resources/translations/login.en_en.yml +0 -14
- package/cli/builder/bundles/users-bundle/Resources/translations/login.fr_fr.yml +0 -14
- package/cli/builder/bundles/users-bundle/Resources/translations/users.en_en.yml +0 -35
- package/cli/builder/bundles/users-bundle/Resources/translations/users.fr_fr.yml +0 -36
- package/cli/builder/bundles/users-bundle/Resources/views/base.html.twig +0 -32
- package/cli/builder/bundles/users-bundle/Resources/views/footer.html.twig +0 -7
- package/cli/builder/bundles/users-bundle/Resources/views/header.html.twig +0 -90
- package/cli/builder/bundles/users-bundle/Resources/views/login/login.html.twig +0 -43
- package/cli/builder/bundles/users-bundle/Resources/views/users/createUser.html.twig +0 -296
- package/cli/builder/bundles/users-bundle/Resources/views/users/readUsers.html.twig +0 -94
- package/cli/builder/bundles/users-bundle/controller/api/graphql/graphqlController.js +0 -56
- package/cli/builder/bundles/users-bundle/controller/api/graphql/userResolver.js +0 -121
- package/cli/builder/bundles/users-bundle/controller/api/graphql/usertype.js +0 -58
- package/cli/builder/bundles/users-bundle/controller/api/openapi/loginApiController.js +0 -210
- package/cli/builder/bundles/users-bundle/controller/api/openapi/restUserController.js +0 -244
- package/cli/builder/bundles/users-bundle/controller/loginController.js +0 -91
- package/cli/builder/bundles/users-bundle/controller/usersController.js +0 -332
- package/cli/builder/bundles/users-bundle/package.json +0 -58
- package/cli/builder/bundles/users-bundle/readme.md +0 -360
- package/cli/builder/bundles/users-bundle/services/usersService.js +0 -411
- package/cli/builder/bundles/users-bundle/src/providers/mongoose/userProvider.js +0 -47
- package/cli/builder/bundles/users-bundle/src/providers/sequelize/userProvider.js +0 -48
- package/cli/builder/bundles/users-bundle/tests/loginTest.js +0 -182
- package/cli/builder/bundles/users-bundle/usersBundle.js +0 -26
- package/cli/builder/microService/microService.js +0 -261
- package/cli/builder/microService/skeletons/.editorconfig +0 -18
- package/cli/builder/microService/skeletons/.env-cmdrc.js +0 -32
- package/cli/builder/microService/skeletons/.jshintrc +0 -37
- package/cli/builder/microService/skeletons/README.md +0 -117
- package/cli/builder/microService/skeletons/bin/bash/hello.sh +0 -5
- package/cli/builder/microService/skeletons/bin/cli +0 -13
- package/cli/builder/microService/skeletons/bin/python/hello.py +0 -20
- package/cli/builder/microService/skeletons/config/config.js +0 -29
- package/cli/builder/microService/skeletons/config/pm2.config.js +0 -72
- package/cli/builder/microService/skeletons/config/webpack/webpack.config.dev.js +0 -8
- package/cli/builder/microService/skeletons/config/webpack/webpack.config.prod.js +0 -25
- package/cli/builder/microService/skeletons/config/webpack.config.js +0 -114
- package/cli/builder/microService/skeletons/package.json +0 -76
- package/cli/builder/microService/skeletons/src/browser/index.css +0 -3
- package/cli/builder/microService/skeletons/src/browser/index.js +0 -16
- package/cli/builder/microService/skeletons/src/browser/socketio.js +0 -46
- package/cli/builder/microService/skeletons/src/cli/cli.js +0 -224
- package/cli/builder/microService/skeletons/src/cli/menu.js +0 -28
- package/cli/builder/microService/skeletons/src/n-api/README.md +0 -1
- package/cli/builder/microService/skeletons/src/n-api/binding.gyp +0 -14
- package/cli/builder/microService/skeletons/src/n-api/hello.cc +0 -14
- package/cli/builder/microService/skeletons/src/n-api/hello.js +0 -23
- package/cli/builder/microService/skeletons/src/n-api/package.json +0 -15
- package/cli/builder/microService/skeletons/src/node/examples/index.js +0 -120
- package/cli/builder/microService/skeletons/src/node/index.js +0 -102
- package/cli/builder/microService/skeletons/src/node/services/markdown/markdown.js +0 -27
- package/cli/builder/microService/skeletons/src/node/services/servers/http.js +0 -45
- package/cli/builder/microService/skeletons/src/node/services/servers/https.js +0 -44
- package/cli/builder/microService/skeletons/src/node/services/socketio/socketio.js +0 -46
- package/cli/builder/microService/skeletons/src/node/services/syscall/syscall.js +0 -111
- package/cli/builder/microService/skeletons/src/node/services/worker/thread.js +0 -59
- package/cli/builder/microService/skeletons/src/node/services/worker/worker.js +0 -60
- package/cli/builder/microService/skeletons/src/templates/base.html +0 -12
- package/cli/builder/microService/skeletons/src/templates/socket.html +0 -23
- package/cli/builder/microService/skeletons/tests/unit/serviceTest.js +0 -30
- package/cli/builder/project/project.js +0 -474
- package/cli/builder/project/skeletons/README.md +0 -778
- package/cli/builder/project/skeletons/bin/dev-deploy.sh +0 -5
- package/cli/builder/project/skeletons/bin/generateCertificates.sh.skeleton +0 -180
- package/cli/builder/project/skeletons/bin/prod-deploy.sh +0 -3
- package/cli/builder/project/skeletons/config/config.js.skeleton +0 -178
- package/cli/builder/project/skeletons/config/openssl/ca/openssl.cnf.skeleton +0 -150
- package/cli/builder/project/skeletons/config/openssl/ca_intermediate/openssl.cnf.skeleton +0 -152
- package/cli/builder/project/skeletons/config/pm2.config.js.skeleton +0 -62
- package/cli/builder/project/skeletons/documentation.html.twig +0 -24
- package/cli/builder/project/skeletons/editorconfig.skeleton +0 -18
- package/cli/builder/project/skeletons/eslintignore.skeleton +0 -15
- package/cli/builder/project/skeletons/eslintrc.js.skeleton +0 -97
- package/cli/builder/project/skeletons/gitignore.skeleton +0 -32
- package/cli/builder/project/skeletons/migrations/2022.12.25T17.37.37.entity-user.js +0 -137
- package/cli/builder/project/skeletons/migrations/2022.12.25T17.37.38.entity-session.js +0 -97
- package/cli/builder/project/skeletons/migrations/2022.12.25T17.37.39.entity-requests.js +0 -115
- package/cli/builder/project/skeletons/migrations/2022.12.25T17.37.40.entity-jwts.js +0 -97
- package/cli/builder/project/skeletons/migrations/migrations.skeleton.js +0 -101
- package/cli/builder/project/skeletons/package.json.twig +0 -71
- package/cli/builder/react/reactBuilder.js +0 -224
- package/cli/builder/react/skeletons/app/Resources/databases/nodefony.db +0 -0
- package/cli/builder/react/skeletons/app/Resources/translations/messages.en_en.yml +0 -5
- package/cli/builder/react/skeletons/app/Resources/translations/messages.fr_fr.yml +0 -5
- package/cli/builder/react/skeletons/app/Resources/views/base.html.twig +0 -33
- package/cli/builder/react/skeletons/app/config/config.js +0 -392
- package/cli/builder/react/skeletons/app/config/routing.js +0 -10
- package/cli/builder/react/skeletons/app/config/security.js +0 -74
- package/cli/builder/react/skeletons/app/controller/appController.js +0 -22
- package/cli/builder/sandbox/sandBoxBuilder.js +0 -610
- package/cli/builder/sandbox/skeletons/Resources/css/entry.css +0 -48
- package/cli/builder/sandbox/skeletons/Resources/js/entry.js +0 -60
- package/cli/builder/sandbox/skeletons/Resources/public/manifest.json +0 -32
- package/cli/builder/sandbox/skeletons/Resources/translations/messages.en_en.yml +0 -5
- package/cli/builder/sandbox/skeletons/Resources/translations/messages.fr_fr.yml +0 -5
- package/cli/builder/sandbox/skeletons/Resources/views/base.html.twig +0 -46
- package/cli/builder/sandbox/skeletons/Resources/views/index.html.twig +0 -34
- package/cli/builder/sandbox/skeletons/bootstrap/custom.scss +0 -27
- package/cli/builder/sandbox/skeletons/bootstrap/entry.scss +0 -60
- package/cli/builder/sandbox/skeletons/workbox/templates/index.html.twig +0 -32
- package/cli/builder/sandbox/skeletons/workbox/workers/service-worker.js +0 -196
- package/cli/builder/skeletons/Resources/public/favicon.ico +0 -0
- package/cli/builder/skeletons/Resources/public/images/app-logo.png +0 -0
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/401.html.twig +0 -1
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/401.json.twig +0 -24
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/403.html.twig +0 -1
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/403.json.twig +0 -20
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/404.html.twig +0 -1
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/404.json.twig +0 -20
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/500.html.twig +0 -1
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/base.html.twig +0 -30
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/exception.html.twig +0 -1
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/exception.json.twig +0 -24
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/footer.html.twig +0 -33
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/header.html.twig +0 -6
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/index.html.twig +0 -6
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/index.json.twig +0 -1
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/layout.html.twig +0 -125
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/layout.json.twig +0 -5
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/timeout.html.twig +0 -1
- package/cli/builder/skeletons/Resources/views/framework-bundle/views/timeout.json.twig +0 -24
- package/cli/builder/skeletons/app/appKernel.js +0 -133
- package/cli/builder/skeletons/binding/binding.cc +0 -26
- package/cli/builder/skeletons/binding/binding.skeleton +0 -8
- package/cli/builder/skeletons/bundle/bundleClass.js +0 -37
- package/cli/builder/skeletons/command/commandClass.js +0 -11
- package/cli/builder/skeletons/command/taskClass.js +0 -20
- package/cli/builder/skeletons/config/config.js +0 -138
- package/cli/builder/skeletons/config/nodefony/elastic-bundle.js +0 -37
- package/cli/builder/skeletons/config/nodefony/framework-bundle.js +0 -22
- package/cli/builder/skeletons/config/nodefony/http-bundle.js +0 -104
- package/cli/builder/skeletons/config/nodefony/mail-bundle.js +0 -44
- package/cli/builder/skeletons/config/nodefony/mongoose-bundle.js +0 -51
- package/cli/builder/skeletons/config/nodefony/monitoring-bundle.js +0 -34
- package/cli/builder/skeletons/config/nodefony/realtime-bundle.js +0 -15
- package/cli/builder/skeletons/config/nodefony/redis-bundle.js +0 -44
- package/cli/builder/skeletons/config/nodefony/security-bundle.js +0 -25
- package/cli/builder/skeletons/config/nodefony/sequelize-bundle.js +0 -156
- package/cli/builder/skeletons/config/routing.js +0 -55
- package/cli/builder/skeletons/config/security.js +0 -102
- package/cli/builder/skeletons/config/services.js +0 -1
- package/cli/builder/skeletons/config/webpack/webpack.dev.config.js +0 -13
- package/cli/builder/skeletons/config/webpack/webpack.prod.config.js +0 -20
- package/cli/builder/skeletons/config/webpack.config.js +0 -148
- package/cli/builder/skeletons/controller/controllerClass.js +0 -75
- package/cli/builder/skeletons/package.json.twig +0 -57
- package/cli/builder/skeletons/unittest/testFile.js +0 -46
- package/cli/builder/vue/skeletons/Resources/public/images/app-logo.png +0 -0
- package/cli/builder/vue/skeletons/Resources/translations/messages.en_en.yml +0 -5
- package/cli/builder/vue/skeletons/Resources/translations/messages.fr_fr.yml +0 -5
- package/cli/builder/vue/skeletons/vue.config.js +0 -129
- package/cli/builder/vue/vueBuilder.js +0 -410
- package/cli/generate/generate.es6 +0 -103
- package/cli/install/install.js +0 -190
- package/cli/sequelize/sequelize.js +0 -94
- package/cli/start.js +0 -702
- package/cli/tools/pm2.es6 +0 -112
- package/cli/tools/tools.es6 +0 -97
- package/cli.es6 +0 -925
- package/container.es6 +0 -272
- package/error.es6 +0 -293
- package/fileClass.es6 +0 -242
- package/finder/file.es6 +0 -33
- package/finder/fileResult.es6 +0 -138
- package/finder/finder2.es6 +0 -275
- package/finder.es6 +0 -427
- package/kernel/annotations/annotations.es6 +0 -286
- package/kernel/api/api.es6 +0 -61
- package/kernel/api/graphqlApi.es6 +0 -107
- package/kernel/api/jsonApi.es6 +0 -177
- package/kernel/api/openApi.es6 +0 -139
- package/kernel/api/schemas/openApiSchema.js +0 -394
- package/kernel/babylon.es6 +0 -162
- package/kernel/bundle.es6 +0 -1200
- package/kernel/cliKernel.es6 +0 -869
- package/kernel/command.es6 +0 -78
- package/kernel/commands/nodefonyCommand.es6 +0 -247
- package/kernel/commands/tasks/bundlesTask.es6 +0 -59
- package/kernel/controllers/controller.es6 +0 -791
- package/kernel/fixture.es6 +0 -19
- package/kernel/injections/injections.es6 +0 -424
- package/kernel/kernel.es6 +0 -1960
- package/kernel/kernelWatcher.es6 +0 -387
- package/kernel/orm/entity.es6 +0 -59
- package/kernel/orm/orm.es6 +0 -139
- package/kernel/reader.es6 +0 -290
- package/kernel/security/encoder.es6 +0 -17
- package/kernel/security/factories/factory.es6 +0 -111
- package/kernel/security/factories/passeportFactory.es6 +0 -61
- package/kernel/security/provider.es6 +0 -58
- package/kernel/security/providers/chainProvider.es6 +0 -99
- package/kernel/security/providers/memoryProvider.es6 +0 -55
- package/kernel/security/providers/providerManager.es6 +0 -67
- package/kernel/security/providers/userEntityProvider.es6 +0 -50
- package/kernel/security/role.es6 +0 -12
- package/kernel/security/secureArea.es6 +0 -431
- package/kernel/security/tokens/token.es6 +0 -171
- package/kernel/security/user.es6 +0 -106
- package/kernel/serviceRealTime.es6 +0 -21
- package/kernel/services/connectionsService.es6 +0 -93
- package/kernel/services/cron/cronService.es6 +0 -123
- package/kernel/task.es6 +0 -80
- package/kernel/templates.es6 +0 -22
- package/kernel/templating/twig.es6 +0 -218
- package/kernel/tests/cliTest.js +0 -59
- package/kernel/tests/containerTest.js +0 -232
- package/kernel/tests/kernelTest.js +0 -39
- package/nodefony.es6 +0 -1084
- package/notificationsCenter.es6 +0 -118
- package/protocol.es6 +0 -86
- package/protocols/bayeux.es6 +0 -174
- package/protocols/jsonRpc/jsonrpc.es6 +0 -56
- package/result.es6 +0 -99
- package/service.es6 +0 -288
- package/syslog/pdu.es6 +0 -141
- package/syslog/syslog.es6 +0 -754
- package/watcher.es6 +0 -113
|
@@ -0,0 +1,1624 @@
|
|
|
1
|
+
import { PLATFORM_CHANNELS, PLATFORM_EVENTS } from "../../realtime/platformChannels.js";
|
|
2
|
+
import { RealtimeClient } from "../realtime/RealtimeClient.js";
|
|
3
|
+
import { fmtClock, formatBytes, formatUptime, gauge, sparklinePoints } from "./format.js";
|
|
4
|
+
import { DebugBarModel } from "./model.js";
|
|
5
|
+
import { observeViteHmr } from "./hmr.js";
|
|
6
|
+
import { installNetworkInterceptor } from "./network.js";
|
|
7
|
+
import { NetworkModel, computeWaterfall, isError } from "./profile.js";
|
|
8
|
+
//#region src/client/debugbar/DebugBar.ts
|
|
9
|
+
/**
|
|
10
|
+
* DebugBar — toolbar de debug par-page type Symfony WDT, **dev-only**, pensée
|
|
11
|
+
* comme une **vitrine du realtime Nodefony** (on doit *voir* le framework
|
|
12
|
+
* respirer en direct).
|
|
13
|
+
*
|
|
14
|
+
* 2ᵉ consommateur navigateur du Core isomorphe après Studio : MÊME backbone
|
|
15
|
+
* realtime (WS JSON-RPC 2.0, canaux `nodefony:supervision` / `nodefony:syslog`) via
|
|
16
|
+
* {@link RealtimeClient}. Aucun rendu serveur splicé dans le body : le serveur
|
|
17
|
+
* *collecte*, le client *rend*.
|
|
18
|
+
*
|
|
19
|
+
* UI : **onglets** (Realtime / Network / Perf / Logs / Runtime) — un seul pane
|
|
20
|
+
* rendu/visible à la fois (≠ grid fourre-tout) + **poignée de resize** (hauteur
|
|
21
|
+
* persistée). Vanilla TS + **Shadow DOM** + sparklines **SVG maison** — 0 dep UI.
|
|
22
|
+
*
|
|
23
|
+
* Perf scroll (critique) : fond OPAQUE sur le panneau (le `backdrop-filter:blur`
|
|
24
|
+
* sur le conteneur scrollable recompositait à chaque frame), `contain:content`
|
|
25
|
+
* par pane, et la liste Network en **mise à jour incrémentale** (nœuds stables,
|
|
26
|
+
* jamais de rebuild `innerHTML` global → le clic n'est plus perdu, le scroll ne
|
|
27
|
+
* saute plus).
|
|
28
|
+
*
|
|
29
|
+
* Panneau **Network** (dev-only) : intercepte `fetch`/`XHR` (header-only,
|
|
30
|
+
* défensif, réversible) → liste des appels AJAX ; clic sur un appel → fetch du
|
|
31
|
+
* profil serveur (`/nodefony/profiler/api/{requestId}`, corrélé via le header
|
|
32
|
+
* `X-Request-Id`) → **waterfall des phases** du pipeline. SPA-first : on profile
|
|
33
|
+
* les appels, pas la page. Le `traceparent` W3C (RFC-propre) est aussi remonté.
|
|
34
|
+
*/
|
|
35
|
+
/** Canaux realtime consommés (figés, alignés sur les providers Studio). */
|
|
36
|
+
const CHANNELS = {
|
|
37
|
+
stats: PLATFORM_CHANNELS.debugbar,
|
|
38
|
+
syslog: PLATFORM_CHANNELS.syslog
|
|
39
|
+
};
|
|
40
|
+
/** Endpoint WS realtime par défaut (porté par Studio aujourd'hui, RealtimeService demain). */
|
|
41
|
+
const DEFAULT_PATH = "/nodefony/studio/api/realtime";
|
|
42
|
+
/** Base du data-plane profiler (data-plane admin `IAdminApi` namespace `profiler`). */
|
|
43
|
+
const DEFAULT_PROFILER_BASE = "/nodefony/profiler/api";
|
|
44
|
+
const HOST_ID = "nodefony-debugbar";
|
|
45
|
+
/** Dimensions des sparklines (unités viewBox SVG). */
|
|
46
|
+
const MINI_W = 58;
|
|
47
|
+
const MINI_H = 20;
|
|
48
|
+
const CHART_W = 260;
|
|
49
|
+
const CHART_H = 46;
|
|
50
|
+
const RT_POINTS = 60;
|
|
51
|
+
/** Borne basse de hauteur du panneau (px). */
|
|
52
|
+
const PANEL_H_MIN = 140;
|
|
53
|
+
/**
|
|
54
|
+
* Hauteur par défaut = **fraction de l'écran** (≈48 % du viewport) — gros écran
|
|
55
|
+
* → grand panneau, petit écran → panneau modeste. Bornée [300, 640] pour rester
|
|
56
|
+
* raisonnable aux extrêmes.
|
|
57
|
+
*/
|
|
58
|
+
function defaultPanelH() {
|
|
59
|
+
const vh = typeof window !== "undefined" ? window.innerHeight : 800;
|
|
60
|
+
return Math.min(640, Math.max(300, Math.round(vh * .48)));
|
|
61
|
+
}
|
|
62
|
+
/** Hauteur mini à l'ouverture d'un profil (waterfall confortable) ≈55 % écran. */
|
|
63
|
+
function detailPanelH() {
|
|
64
|
+
const vh = typeof window !== "undefined" ? window.innerHeight : 800;
|
|
65
|
+
return Math.min(680, Math.max(360, Math.round(vh * .55)));
|
|
66
|
+
}
|
|
67
|
+
/** Métadonnées d'affichage par framework (couleur de marque officielle). */
|
|
68
|
+
const FRAMEWORKS = {
|
|
69
|
+
react19: {
|
|
70
|
+
label: "React 19",
|
|
71
|
+
color: "#61dafb"
|
|
72
|
+
},
|
|
73
|
+
react: {
|
|
74
|
+
label: "React",
|
|
75
|
+
color: "#61dafb"
|
|
76
|
+
},
|
|
77
|
+
vue3: {
|
|
78
|
+
label: "Vue 3",
|
|
79
|
+
color: "#42b883"
|
|
80
|
+
},
|
|
81
|
+
vue: {
|
|
82
|
+
label: "Vue",
|
|
83
|
+
color: "#42b883"
|
|
84
|
+
},
|
|
85
|
+
angular: {
|
|
86
|
+
label: "Angular",
|
|
87
|
+
color: "#dd0031"
|
|
88
|
+
},
|
|
89
|
+
vanilla: {
|
|
90
|
+
label: "Vanilla",
|
|
91
|
+
color: "#f7df1e"
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const STYLES = `
|
|
95
|
+
:host { all: initial; }
|
|
96
|
+
* { box-sizing: border-box; }
|
|
97
|
+
.bar {
|
|
98
|
+
position: fixed; left: 0; right: 0; z-index: 2147483000;
|
|
99
|
+
font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
100
|
+
color: #e8eaed;
|
|
101
|
+
/* Fond OPAQUE (pas de backdrop-filter sur le conteneur scrollable : il
|
|
102
|
+
recompositait le blur à chaque frame de scroll → lag). Blur seulement sur
|
|
103
|
+
.strip (fin, non scrollé). */
|
|
104
|
+
background: #14161a;
|
|
105
|
+
--blue:#0067ba; --blue2:#3aa0ff; --orange:#ff8a3d; --ok:#36b37e; --warn:#ffab00;
|
|
106
|
+
--crit:#ff5630; --info:#4c9aff; --muted:#8a9099; --line:#2a2e36; --card:#1c1f26;
|
|
107
|
+
box-shadow: 0 -8px 40px rgba(0,0,0,.5);
|
|
108
|
+
}
|
|
109
|
+
.bar.bottom { bottom: 0; }
|
|
110
|
+
.bar.top { top: 0; }
|
|
111
|
+
.bar::before {
|
|
112
|
+
content:""; position:absolute; left:0; right:0; height:2px;
|
|
113
|
+
background: linear-gradient(90deg, var(--blue), var(--blue2), var(--orange));
|
|
114
|
+
background-size: 200% 100%; animation: flow 4s linear infinite; opacity:.9;
|
|
115
|
+
}
|
|
116
|
+
.bar.bottom::before { top:0; } .bar.top::before { bottom:0; }
|
|
117
|
+
@keyframes flow { to { background-position: 200% 0; } }
|
|
118
|
+
|
|
119
|
+
/* Strip responsive : police (et tout le contenu en em) scale avec la largeur
|
|
120
|
+
d'écran, bornée 12→15px. Padding scale aussi. */
|
|
121
|
+
.strip { display: flex; align-items: center; gap: clamp(12px,1.1vw,20px);
|
|
122
|
+
padding: clamp(8px,1vh,13px) clamp(14px,1.4vw,26px); cursor: pointer;
|
|
123
|
+
font-size: clamp(12px, 0.35vw + 8px, 16px); flex-wrap: nowrap; overflow: hidden;
|
|
124
|
+
background: rgba(20,22,26,.6); backdrop-filter: blur(14px) saturate(140%); }
|
|
125
|
+
.strip:hover { background: rgba(255,255,255,.03); }
|
|
126
|
+
.brand { display:flex; align-items:center; gap:8px; font-weight:800; letter-spacing:.2px; flex:none; }
|
|
127
|
+
.brand .logo { color: var(--blue2); font-size:1.05em; filter: drop-shadow(0 0 6px rgba(58,160,255,.6)); }
|
|
128
|
+
.brand .name { background: linear-gradient(90deg,#fff,var(--blue2)); -webkit-background-clip:text;
|
|
129
|
+
background-clip:text; -webkit-text-fill-color:transparent; }
|
|
130
|
+
.rt-pill { display:flex; align-items:center; gap:5px; padding:.2em .7em; border-radius:11px; flex:none;
|
|
131
|
+
font-size:.76em; font-weight:800; letter-spacing:.6px; text-transform:uppercase;
|
|
132
|
+
color:var(--muted); background:#22262e; border:1px solid var(--line); }
|
|
133
|
+
.rt-pill.connected { color:#fff; border-color:rgba(58,160,255,.5);
|
|
134
|
+
background: linear-gradient(90deg, rgba(0,103,186,.35), rgba(255,138,61,.25));
|
|
135
|
+
box-shadow: 0 0 14px rgba(58,160,255,.35); }
|
|
136
|
+
.rt-pill .bolt { animation: bolt 1.6s ease-in-out infinite; }
|
|
137
|
+
.rt-pill.connected .bolt { color: var(--orange); }
|
|
138
|
+
@keyframes bolt { 0%,100%{opacity:.5;transform:scale(.9)} 50%{opacity:1;transform:scale(1.15)} }
|
|
139
|
+
|
|
140
|
+
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); flex: none; color: var(--muted); }
|
|
141
|
+
.dot.connected { background: var(--ok); color: var(--ok); animation: pulse 2s infinite; }
|
|
142
|
+
.dot.connecting, .dot.reconnecting { background: var(--warn); color: var(--warn); }
|
|
143
|
+
.dot.error, .dot.disconnected { background: var(--crit); color: var(--crit); }
|
|
144
|
+
@keyframes pulse { 0%{box-shadow:0 0 0 0 currentColor} 70%{box-shadow:0 0 0 5px transparent} 100%{box-shadow:0 0 0 0 transparent} }
|
|
145
|
+
|
|
146
|
+
.metric { display: flex; align-items: center; gap: 6px; white-space: nowrap; flex:none; }
|
|
147
|
+
.metric .k { color: var(--muted); text-transform: uppercase; font-size: .76em; letter-spacing:.5px; }
|
|
148
|
+
.metric .v { font-weight: 700; min-width: 2.6em; font-size: 1em; }
|
|
149
|
+
.mini { width: 3.8em; height: 1.35em; display:block; }
|
|
150
|
+
.mini polyline { fill:none; stroke-width:1.5; vector-effect:non-scaling-stroke; }
|
|
151
|
+
.chip { display:flex; align-items:center; gap:6px; padding:.2em .7em; border-radius:11px; flex:none;
|
|
152
|
+
background:#22262e; font-weight:700; font-size:.92em; white-space:nowrap; }
|
|
153
|
+
.chip .k { color: var(--muted); font-size:.82em; text-transform:uppercase; }
|
|
154
|
+
.spacer { flex: 1 1 auto; min-width: 8px; }
|
|
155
|
+
.toggle { color: var(--muted); font-size: .85em; transition: transform .25s; flex:none; }
|
|
156
|
+
.bar.open .toggle { transform: rotate(180deg); }
|
|
157
|
+
.ok{color:var(--ok)} .warn{color:var(--warn)} .crit{color:var(--crit)} .info{color:var(--info)} .muted{color:var(--muted)} .blue{color:var(--blue2)}
|
|
158
|
+
.spark.ok{stroke:var(--ok)} .spark.warn{stroke:var(--warn)} .spark.crit{stroke:var(--crit)} .spark.rt{stroke:var(--blue2)}
|
|
159
|
+
.area.ok{fill:rgba(54,179,126,.12)} .area.warn{fill:rgba(255,171,0,.14)} .area.crit{fill:rgba(255,86,48,.16)} .area.rt{fill:rgba(58,160,255,.16)}
|
|
160
|
+
|
|
161
|
+
/* ── Panneau : resize + onglets + panes ──────────────────────────────────── */
|
|
162
|
+
.panelwrap { display:none; flex-direction:column; border-top:1px solid var(--line); }
|
|
163
|
+
.bar.open .panelwrap { display:flex; }
|
|
164
|
+
.resize { height:8px; cursor:ns-resize; display:flex; align-items:center; justify-content:center;
|
|
165
|
+
flex:none; background:rgba(255,255,255,.015); }
|
|
166
|
+
.resize::after { content:""; width:42px; height:3px; border-radius:2px; background:var(--line); transition:background .15s; }
|
|
167
|
+
.resize:hover::after { background:var(--blue2); }
|
|
168
|
+
.tabs { display:flex; gap:2px; padding:0 8px; flex:none; border-bottom:1px solid var(--line);
|
|
169
|
+
overflow-x:auto; scrollbar-width:none; }
|
|
170
|
+
.tabs::-webkit-scrollbar { display:none; }
|
|
171
|
+
.tab { padding:7px 12px; font:inherit; font-size:11px; font-weight:700; color:var(--muted);
|
|
172
|
+
cursor:pointer; border:0; background:none; border-bottom:2px solid transparent;
|
|
173
|
+
text-transform:uppercase; letter-spacing:.4px; white-space:nowrap; display:flex; align-items:center; gap:5px; }
|
|
174
|
+
.tab:hover { color:#fff; }
|
|
175
|
+
.tab.active { color:#fff; border-bottom-color:var(--blue2); }
|
|
176
|
+
.tab .tcount { font-size:9px; padding:0 5px; border-radius:8px; background:#22262e; color:var(--muted); }
|
|
177
|
+
.tab.active .tcount { background:rgba(58,160,255,.25); color:#fff; }
|
|
178
|
+
.tab .tcount.crit { background:rgba(255,86,48,.3); color:#fff; }
|
|
179
|
+
.panes { overflow:hidden; }
|
|
180
|
+
.pane { display:none; height:100%; overflow:auto; padding:14px; contain:content; }
|
|
181
|
+
.pane.active { display:block; }
|
|
182
|
+
.cards { display:grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap:14px; align-items:start; }
|
|
183
|
+
.card { background:var(--card); border:1px solid var(--line); border-radius:10px; padding:11px 13px; }
|
|
184
|
+
.card.hero { border-color: rgba(58,160,255,.35);
|
|
185
|
+
background: linear-gradient(160deg, rgba(0,103,186,.16), rgba(28,31,38,.7) 60%); }
|
|
186
|
+
.card > h4 { margin:0 0 9px; font-size:10px; letter-spacing:1px; text-transform:uppercase; color:var(--muted); font-weight:800; display:flex; gap:6px; align-items:center; }
|
|
187
|
+
|
|
188
|
+
.hero .big { font-size:30px; font-weight:800; line-height:1; letter-spacing:-.5px;
|
|
189
|
+
background:linear-gradient(90deg,var(--blue2),var(--orange)); -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; }
|
|
190
|
+
.hero .big small { font-size:12px; -webkit-text-fill-color:var(--muted); color:var(--muted); font-weight:700; margin-left:4px; }
|
|
191
|
+
.hero svg { width:100%; height:38px; display:block; margin:6px 0 8px; }
|
|
192
|
+
.hero polyline { fill:none; stroke-width:1.75; vector-effect:non-scaling-stroke; }
|
|
193
|
+
.tag { margin-top:9px; padding-top:8px; border-top:1px solid var(--line); color:var(--muted);
|
|
194
|
+
font-size:10px; line-height:1.5; }
|
|
195
|
+
.tag b { color:#cfd3d8; }
|
|
196
|
+
|
|
197
|
+
.chart { margin-bottom:10px; } .chart:last-child { margin-bottom:0; }
|
|
198
|
+
.chart .hd { display:flex; justify-content:space-between; align-items:baseline; margin-bottom:2px; }
|
|
199
|
+
.chart .lbl { color:var(--muted); font-size:10px; text-transform:uppercase; letter-spacing:.5px; }
|
|
200
|
+
.chart .val { font-weight:700; font-size:13px; }
|
|
201
|
+
.chart .peak { color:var(--muted); font-size:9px; }
|
|
202
|
+
.chart svg { width:100%; height:${CHART_H}px; display:block; }
|
|
203
|
+
.chart polyline { fill:none; stroke-width:1.5; vector-effect:non-scaling-stroke; }
|
|
204
|
+
|
|
205
|
+
.kv { display:flex; justify-content:space-between; gap:8px; padding:2px 0; }
|
|
206
|
+
.kv .k { color:var(--muted); } .kv .v { font-weight:600; text-align:right; overflow:hidden; text-overflow:ellipsis; }
|
|
207
|
+
|
|
208
|
+
.counts { display:flex; gap:8px; margin-bottom:8px; flex-wrap:wrap; }
|
|
209
|
+
.feed { font-size:11px; }
|
|
210
|
+
/* ── Explorateur de journal ─────────────────────────────────────────────── */
|
|
211
|
+
.counts { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
|
|
212
|
+
.counts .spacer { flex:1 1 auto; }
|
|
213
|
+
.counts button { font: inherit; color: inherit; background:none; border:1px solid transparent; cursor:pointer; }
|
|
214
|
+
.chip.sevf { border-color: var(--line); }
|
|
215
|
+
.chip.sevf.on { border-color: var(--ok); color:#fff; }
|
|
216
|
+
.search { font: inherit; font-size:11px; color:inherit; background:rgba(255,255,255,.04);
|
|
217
|
+
border:1px solid var(--line); border-radius:6px; padding:3px 8px; min-width:120px; max-width:220px; }
|
|
218
|
+
.search::placeholder { color: var(--muted); }
|
|
219
|
+
.toolbtn { font: inherit; font-size:12px; line-height:1; color:var(--muted); background:none;
|
|
220
|
+
border:1px solid var(--line); border-radius:6px; padding:3px 7px; cursor:pointer; }
|
|
221
|
+
.toolbtn:hover { color:#fff; }
|
|
222
|
+
.toolbtn.on { color:var(--ok); border-color:var(--ok); }
|
|
223
|
+
.log { display:flex; align-items:baseline; gap:8px; padding:2px 0; cursor:pointer; }
|
|
224
|
+
.log:hover { background:rgba(255,255,255,.04); }
|
|
225
|
+
.log .ts { color:var(--muted); font-variant-numeric: tabular-nums; flex:none; }
|
|
226
|
+
.log .rid { color:var(--muted); font-family:monospace; flex:none; margin-left:auto;
|
|
227
|
+
border:1px solid var(--line); border-radius:4px; padding:0 4px; }
|
|
228
|
+
.logdetail { margin:2px 0 6px 0; padding:6px 8px; border-left:2px solid var(--line);
|
|
229
|
+
background:rgba(255,255,255,.03); border-radius:0 6px 6px 0; }
|
|
230
|
+
.drow { display:flex; gap:8px; padding:1px 0; }
|
|
231
|
+
.drow .dk { color:var(--muted); min-width:92px; flex:none; }
|
|
232
|
+
.drow .dv { word-break:break-word; }
|
|
233
|
+
.feed .empty { color:var(--muted); padding:6px 0; }
|
|
234
|
+
.log { display:flex; gap:7px; padding:2px 0; align-items:baseline; border-bottom:1px solid rgba(255,255,255,.04); }
|
|
235
|
+
.log .sev { flex:none; width:54px; font-size:9px; font-weight:800; text-transform:uppercase; }
|
|
236
|
+
.log .mod { flex:none; color:var(--muted); max-width:90px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
237
|
+
.log .txt { flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
238
|
+
|
|
239
|
+
.card.fe { border-color: rgba(255,138,61,.3);
|
|
240
|
+
background: linear-gradient(160deg, rgba(255,138,61,.12), rgba(28,31,38,.7) 60%); }
|
|
241
|
+
.fw { display:flex; align-items:center; gap:9px; margin-bottom:9px; }
|
|
242
|
+
.fw .badge { padding:2px 10px; border-radius:7px; font-weight:800; font-size:11px; color:#0b0d10; }
|
|
243
|
+
.fw .name { color:var(--muted); }
|
|
244
|
+
.fe .hd { display:flex; justify-content:space-between; align-items:baseline; margin-bottom:2px; }
|
|
245
|
+
.fe .lbl { color:var(--muted); font-size:10px; text-transform:uppercase; letter-spacing:.5px; }
|
|
246
|
+
.hmr-big { font-size:26px; font-weight:800; line-height:1; transition: color .2s; }
|
|
247
|
+
.hmr-big.hmr-flash { color: var(--orange); text-shadow: 0 0 14px rgba(255,138,61,.7); }
|
|
248
|
+
.fe svg { width:100%; height:34px; display:block; margin:6px 0 8px; }
|
|
249
|
+
.fe polyline { fill:none; stroke-width:1.75; vector-effect:non-scaling-stroke; }
|
|
250
|
+
.spark.fe { stroke:var(--orange); } .area.fe { fill:rgba(255,138,61,.16); }
|
|
251
|
+
|
|
252
|
+
.env-badge { padding:.2em .7em; border-radius:6px; font-size:.76em; font-weight:800;
|
|
253
|
+
letter-spacing:.6px; text-transform:uppercase; color:#0b0d10; background:var(--muted); flex:none; }
|
|
254
|
+
.env-badge.dev { background: var(--ok); } .env-badge.prod { background: var(--crit); color:#fff; }
|
|
255
|
+
.env-badge.test { background: var(--warn); } .env-badge.staging { background:#a06bff; color:#fff; }
|
|
256
|
+
.branch { display:flex; align-items:center; gap:5px; padding:2px 9px; border-radius:6px; flex:none;
|
|
257
|
+
background:#22262e; font-weight:700; max-width:200px; cursor:help; }
|
|
258
|
+
.branch .git { color:var(--blue2); } .branch span:last-child { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
259
|
+
/* Les contrôles et les indicateurs du bandeau sont de VRAIS <button> : ils
|
|
260
|
+
s'atteignent au clavier et s'annoncent. Ce bloc leur retire l'apparence
|
|
261
|
+
native que le navigateur leur donne, sans leur retirer leur nature. */
|
|
262
|
+
.strip button { font: inherit; color: inherit; background: none; border: 0; margin: 0; padding: 0; cursor: pointer; }
|
|
263
|
+
.strip button:focus-visible, .tab:focus-visible, .toolbtn:focus-visible {
|
|
264
|
+
outline: 2px solid var(--ok); outline-offset: 2px; border-radius: 4px; }
|
|
265
|
+
.goto:hover .v, .goto:hover .k { color: #fff; }
|
|
266
|
+
|
|
267
|
+
/* ── Infobulles ────────────────────────────────────────────────────────────
|
|
268
|
+
Maison, et non l'attribut « title » du navigateur : celui-là met environ une
|
|
269
|
+
seconde à venir, ne se style pas, et surtout n'apparaît JAMAIS au focus
|
|
270
|
+
clavier — l'aide restait donc inaccessible à qui n'utilise pas la souris.
|
|
271
|
+
Celle-ci s'ouvre au survol ET au focus, ce qui la rend utilisable par tout le
|
|
272
|
+
monde. En CSS pur : aucun script, aucun écouteur, rien à libérer. */
|
|
273
|
+
[data-tip] { position: relative; }
|
|
274
|
+
[data-tip]::after {
|
|
275
|
+
content: attr(data-tip);
|
|
276
|
+
position: absolute; bottom: calc(100% + 9px); left: 50%; transform: translateX(-50%);
|
|
277
|
+
width: max-content; max-width: 280px; white-space: normal; text-align: left;
|
|
278
|
+
background: #0b0b0d; color: #f2f2f2; border: 1px solid var(--line);
|
|
279
|
+
border-radius: 6px; padding: 6px 9px; font-size: 11px; line-height: 1.45;
|
|
280
|
+
font-weight: 400; text-transform: none; letter-spacing: 0;
|
|
281
|
+
box-shadow: 0 6px 20px rgba(0,0,0,.5);
|
|
282
|
+
opacity: 0; visibility: hidden; transition: opacity .12s ease; pointer-events: none; z-index: 20;
|
|
283
|
+
}
|
|
284
|
+
[data-tip]:hover::after, [data-tip]:focus-visible::after { opacity: 1; visibility: visible; }
|
|
285
|
+
/* Barre ancrée en haut : l'infobulle bascule dessous, sinon elle sort de l'écran. */
|
|
286
|
+
.bar.top [data-tip]::after { bottom: auto; top: calc(100% + 9px); }
|
|
287
|
+
/* Les bords : l'infobulle se recale pour ne pas déborder de la fenêtre. */
|
|
288
|
+
.strip > :first-child[data-tip]::after { left: 0; transform: none; }
|
|
289
|
+
.strip > :last-child[data-tip]::after { left: auto; right: 0; transform: none; }
|
|
290
|
+
@media (prefers-reduced-motion: reduce) { [data-tip]::after { transition: none; } }
|
|
291
|
+
|
|
292
|
+
.ctrl { color:var(--muted); cursor:pointer; padding:0 4px; font-weight:800; font-size:1.05em; line-height:1; flex:none; }
|
|
293
|
+
.ctrl:hover { color:#fff; }
|
|
294
|
+
.ctrl.live { font-size:.78em; font-weight:700; border:1px solid var(--line); border-radius:6px; padding:2px 7px; letter-spacing:.3px; }
|
|
295
|
+
.ctrl.live.on { color:var(--ok); border-color:var(--ok); }
|
|
296
|
+
.ctrl.live:not(.on) { color:var(--muted); }
|
|
297
|
+
|
|
298
|
+
.minbar { position:fixed; z-index:2147483000; display:none; align-items:center; gap:8px;
|
|
299
|
+
padding:6px 13px; border-radius:22px; cursor:pointer;
|
|
300
|
+
font:12px/1 ui-monospace, SFMono-Regular, Menlo, monospace; color:#e8eaed;
|
|
301
|
+
background:rgba(18,20,25,.92); backdrop-filter:blur(12px);
|
|
302
|
+
border:1px solid rgba(58,160,255,.45); box-shadow:0 4px 20px rgba(0,0,0,.5); }
|
|
303
|
+
.minbar:hover { border-color:#3aa0ff; box-shadow:0 4px 26px rgba(58,160,255,.4); }
|
|
304
|
+
.minbar.bottom { bottom:14px; } .minbar.top { top:14px; }
|
|
305
|
+
.minbar.dock-left { left:14px; } .minbar.dock-right { right:14px; }
|
|
306
|
+
.minbar .dot { width:8px; height:8px; border-radius:50%; background:#36b37e; }
|
|
307
|
+
.minbar .dot.connected { background:#36b37e; } .minbar .dot.disconnected,.minbar .dot.error { background:#ff5630; }
|
|
308
|
+
.minbar .dot.connecting,.minbar .dot.reconnecting { background:#ffab00; }
|
|
309
|
+
.minbar .mlogo { color:#ff8a3d; } .minbar .mrate { font-weight:800; }
|
|
310
|
+
.minbar .mbadge { font-size:9px; font-weight:800; text-transform:uppercase; color:#8a9099; }
|
|
311
|
+
|
|
312
|
+
/* ── Network ─────────────────────────────────────────────────────────────── */
|
|
313
|
+
.net-head { display:flex; align-items:center; gap:8px; margin-bottom:8px; flex-wrap:wrap; }
|
|
314
|
+
.net-clear { margin-left:auto; color:var(--muted); cursor:pointer; font-size:10px;
|
|
315
|
+
text-transform:uppercase; letter-spacing:.5px; padding:2px 6px; border-radius:6px; }
|
|
316
|
+
.net-clear:hover { color:#fff; background:rgba(255,255,255,.06); }
|
|
317
|
+
.net-list { border-top:1px solid var(--line); }
|
|
318
|
+
.net-list .empty { color:var(--muted); padding:8px 0; }
|
|
319
|
+
.net-row { display:flex; align-items:center; gap:9px; padding:3px 4px; cursor:pointer;
|
|
320
|
+
border-bottom:1px solid rgba(255,255,255,.04); }
|
|
321
|
+
.net-row:hover { background:rgba(255,255,255,.04); }
|
|
322
|
+
.net-row.sel { background:rgba(58,160,255,.14); }
|
|
323
|
+
.net-row.err .net-path { color:#ffb4a6; }
|
|
324
|
+
.net-method { flex:none; width:46px; text-align:center; font-weight:800; font-size:9px;
|
|
325
|
+
padding:1px 0; border-radius:5px; text-transform:uppercase; color:#0b0d10; background:var(--muted); }
|
|
326
|
+
.net-method.get { background:var(--blue2); } .net-method.post { background:var(--ok); }
|
|
327
|
+
.net-method.put,.net-method.patch { background:var(--orange); }
|
|
328
|
+
.net-method.delete { background:var(--crit); color:#fff; }
|
|
329
|
+
.net-method.ws { background:#a06bff; color:#fff; }
|
|
330
|
+
.net-path { flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
331
|
+
.net-status { flex:none; width:38px; text-align:center; font-weight:800; font-size:10px; }
|
|
332
|
+
.net-status.s2 { color:var(--ok); } .net-status.s3 { color:var(--info); }
|
|
333
|
+
.net-status.s4 { color:var(--warn); } .net-status.s5 { color:var(--crit); }
|
|
334
|
+
.net-status.sp { color:var(--muted); }
|
|
335
|
+
.net-dur { flex:none; width:58px; text-align:right; color:var(--muted); font-size:10px; }
|
|
336
|
+
.net-rid { flex:none; color:var(--blue2); font-size:9px; opacity:.7; }
|
|
337
|
+
|
|
338
|
+
.net-detail { margin-top:10px; border-top:1px solid var(--line); padding-top:10px; }
|
|
339
|
+
.net-detail .empty { color:var(--muted); }
|
|
340
|
+
.det-grid { display:grid; grid-template-columns: repeat(auto-fit, minmax(160px,1fr)); gap:2px 14px; margin-bottom:10px; }
|
|
341
|
+
.wf { display:flex; flex-direction:column; gap:3px; }
|
|
342
|
+
.wf-title { color:var(--muted); font-size:10px; text-transform:uppercase; letter-spacing:.5px; margin-bottom:4px; }
|
|
343
|
+
.wf-row { display:flex; align-items:center; gap:8px; }
|
|
344
|
+
.wf-name { flex:none; width:74px; text-align:right; color:#cfd3d8; font-size:10px; }
|
|
345
|
+
.wf-track { flex:1; position:relative; height:14px; background:rgba(255,255,255,.04); border-radius:3px; }
|
|
346
|
+
.wf-bar { position:absolute; top:0; bottom:0; border-radius:3px; min-width:2px;
|
|
347
|
+
box-shadow: inset 0 0 0 1px rgba(255,255,255,.12); }
|
|
348
|
+
.wf-ms { flex:none; width:62px; text-align:right; color:var(--muted); font-size:10px; }
|
|
349
|
+
.wf-bar.parse { background:#4c9aff; } .wf-bar.resolve { background:#3aa0ff; }
|
|
350
|
+
.wf-bar.firewall { background:#ff8a3d; } .wf-bar.init { background:#a06bff; }
|
|
351
|
+
.wf-bar.action { background:#36b37e; } .wf-bar.render { background:#ffab00; }
|
|
352
|
+
.wf-bar.send { background:#00b8d9; } .wf-bar.other { background:#8a9099; }
|
|
353
|
+
.wf-bar.identity { background:#ff5c8a; }
|
|
354
|
+
.det-loading,.det-err { color:var(--muted); padding:6px 0; } .det-err { color:var(--crit); }
|
|
355
|
+
|
|
356
|
+
/* Network pane = split DevTools : liste (scroll) + détail (scroll), détail
|
|
357
|
+
TOUJOURS visible (≠ tout dans un seul scroll où le détail finit hors écran). */
|
|
358
|
+
.pane.np.active { display:flex; flex-direction:column; padding:0; }
|
|
359
|
+
.np .net-head { padding:10px 14px 8px; flex:none; margin:0; }
|
|
360
|
+
.np .net-list { flex:1 1 auto; min-height:56px; overflow:auto; padding:0 14px; border-top:1px solid var(--line); }
|
|
361
|
+
/* Détail : placeholder = petit (flex:0). Sélection active (.np.sel) → le détail
|
|
362
|
+
prend une vraie part (60%) avec son propre scroll → le waterfall est visible,
|
|
363
|
+
la liste se réduit. */
|
|
364
|
+
.np .net-detail { flex:0 1 auto; max-height:50%; overflow:auto; padding:8px 14px 12px; margin-top:0; border-top:1px solid var(--line); }
|
|
365
|
+
.np.sel .net-list { flex:1 1 40%; min-height:48px; }
|
|
366
|
+
.np.sel .net-detail { flex:1 1 60%; max-height:none; }
|
|
367
|
+
.det-bar { display:flex; justify-content:flex-end; margin-bottom:2px; }
|
|
368
|
+
.det-close { cursor:pointer; color:var(--muted); font-weight:800; font-size:15px; line-height:1; padding:0 4px; }
|
|
369
|
+
.det-close:hover { color:#fff; }
|
|
370
|
+
`;
|
|
371
|
+
function pushCap(arr, v, cap) {
|
|
372
|
+
arr.push(v);
|
|
373
|
+
if (arr.length > cap) arr.shift();
|
|
374
|
+
}
|
|
375
|
+
function clampH(h) {
|
|
376
|
+
const max = typeof window !== "undefined" ? window.innerHeight * .85 : 700;
|
|
377
|
+
if (h < PANEL_H_MIN) return PANEL_H_MIN;
|
|
378
|
+
if (h > max) return Math.round(max);
|
|
379
|
+
return Math.round(h);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Version du format de l'état persisté.
|
|
383
|
+
*
|
|
384
|
+
* Elle existe pour une raison précise : ces clés survivent aux mises à jour du
|
|
385
|
+
* framework, dans un navigateur que personne ne nettoie. Le jour où l'une change
|
|
386
|
+
* de sens, une valeur écrite par une version d'avant est lue comme si elle
|
|
387
|
+
* disait la même chose — et la barre s'ouvre dans un état incohérent que
|
|
388
|
+
* l'utilisateur ne sait pas défaire. Au changement de version, tout est purgé :
|
|
389
|
+
* on perd une préférence d'affichage, ce qui ne coûte rien, plutôt que de
|
|
390
|
+
* charger un état dont on ne sait rien.
|
|
391
|
+
*/
|
|
392
|
+
const LS_VERSION = "1";
|
|
393
|
+
/** Clés de persistance localStorage (état chrome de la barre). */
|
|
394
|
+
const LS = {
|
|
395
|
+
/** Version du format — jamais purgée, c'est elle qui décide de la purge. */
|
|
396
|
+
version: "nf.debugbar.v",
|
|
397
|
+
visible: "nf.debugbar.visible",
|
|
398
|
+
min: "nf.debugbar.min",
|
|
399
|
+
side: "nf.debugbar.side",
|
|
400
|
+
tab: "nf.debugbar.tab",
|
|
401
|
+
h: "nf.debugbar.h",
|
|
402
|
+
live: "nf.debugbar.live"
|
|
403
|
+
};
|
|
404
|
+
/**
|
|
405
|
+
* Toutes les clés que la barre écrit sur CE navigateur.
|
|
406
|
+
*
|
|
407
|
+
* Cette liste n'est pas décorative : elle est ce que la barre AFFICHE dans son
|
|
408
|
+
* onglet Runtime et ce que sa purge efface. Trois choses qui doivent rester
|
|
409
|
+
* d'accord, donc une seule source.
|
|
410
|
+
*/
|
|
411
|
+
function lsKeys() {
|
|
412
|
+
return Object.values(LS);
|
|
413
|
+
}
|
|
414
|
+
/** Efface l'état persisté de la barre — et rien d'autre du stockage de l'app. */
|
|
415
|
+
function lsPurge() {
|
|
416
|
+
try {
|
|
417
|
+
for (const k of lsKeys()) localStorage.removeItem(k);
|
|
418
|
+
} catch {}
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Purge l'état si le format a changé depuis la dernière visite.
|
|
422
|
+
*
|
|
423
|
+
* Appelée avant toute lecture — sinon on lirait justement les valeurs qu'on
|
|
424
|
+
* s'apprête à jeter.
|
|
425
|
+
*/
|
|
426
|
+
function lsMigrate() {
|
|
427
|
+
try {
|
|
428
|
+
if (localStorage.getItem(LS.version) === LS_VERSION) return;
|
|
429
|
+
lsPurge();
|
|
430
|
+
localStorage.setItem(LS.version, LS_VERSION);
|
|
431
|
+
} catch {}
|
|
432
|
+
}
|
|
433
|
+
function lsGet(key, def) {
|
|
434
|
+
try {
|
|
435
|
+
return localStorage.getItem(key) ?? def;
|
|
436
|
+
} catch {
|
|
437
|
+
return def;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function lsSet(key, val) {
|
|
441
|
+
try {
|
|
442
|
+
localStorage.setItem(key, val);
|
|
443
|
+
} catch {}
|
|
444
|
+
}
|
|
445
|
+
const GLOBAL_KEY = "__NODEFONY_DEBUGBAR__";
|
|
446
|
+
/**
|
|
447
|
+
* Widget DOM. Lazy : ne construit le Shadow DOM qu'au `mount()`. Idempotent
|
|
448
|
+
* (un seul `#nodefony-debugbar` par page).
|
|
449
|
+
*/
|
|
450
|
+
var DebugBar = class DebugBar {
|
|
451
|
+
client;
|
|
452
|
+
model = new DebugBarModel();
|
|
453
|
+
url;
|
|
454
|
+
position;
|
|
455
|
+
startOpen;
|
|
456
|
+
ownClient;
|
|
457
|
+
frontend;
|
|
458
|
+
host = null;
|
|
459
|
+
bar = null;
|
|
460
|
+
visible;
|
|
461
|
+
minimized;
|
|
462
|
+
side;
|
|
463
|
+
activeTab;
|
|
464
|
+
panelH;
|
|
465
|
+
live;
|
|
466
|
+
/** dispose des abonnements realtime (null quand OFF). */
|
|
467
|
+
liveOff = null;
|
|
468
|
+
rafPending = false;
|
|
469
|
+
feedLen = -1;
|
|
470
|
+
/** Filtre de sévérité de l'onglet Logs — `all` par défaut. */
|
|
471
|
+
feedSev = "all";
|
|
472
|
+
/** Recherche courante, déjà en minuscules (comparée telle quelle). */
|
|
473
|
+
feedQuery = "";
|
|
474
|
+
/**
|
|
475
|
+
* Affichage suspendu. Les entrées continuent d'arriver dans le modèle : à la
|
|
476
|
+
* reprise, la liste se reconstruit complète — mettre en pause ne fait pas
|
|
477
|
+
* perdre ce qui s'est passé pendant, ce qui serait le pire des deux mondes.
|
|
478
|
+
*/
|
|
479
|
+
feedPaused = false;
|
|
480
|
+
/** La liste affichée doit être refaite (changement de filtre ou de recherche). */
|
|
481
|
+
feedDirty = false;
|
|
482
|
+
prevFrames = 0;
|
|
483
|
+
rtRate = 0;
|
|
484
|
+
rtPeak = 0;
|
|
485
|
+
rtSeries = [];
|
|
486
|
+
viteConnected = false;
|
|
487
|
+
hmrCount = 0;
|
|
488
|
+
hmrPrev = 0;
|
|
489
|
+
hmrRate = 0;
|
|
490
|
+
hmrLast = "—";
|
|
491
|
+
hmrSeries = [];
|
|
492
|
+
flashTimer = null;
|
|
493
|
+
disposers = [];
|
|
494
|
+
el = Object.create(null);
|
|
495
|
+
networkEnabled;
|
|
496
|
+
profilerBase;
|
|
497
|
+
net = new NetworkModel();
|
|
498
|
+
/** Observe la barre → publie sa hauteur (var CSS) pour l'app hôte. */
|
|
499
|
+
ro = null;
|
|
500
|
+
netRows = /* @__PURE__ */ new Map();
|
|
501
|
+
selectedRid = null;
|
|
502
|
+
selRowId = null;
|
|
503
|
+
selNoRid = false;
|
|
504
|
+
detailVersion = 0;
|
|
505
|
+
detailRendered = -1;
|
|
506
|
+
constructor(opts = {}) {
|
|
507
|
+
this.url = opts.url ?? DEFAULT_PATH;
|
|
508
|
+
this.position = opts.position ?? "bottom";
|
|
509
|
+
this.startOpen = opts.open ?? false;
|
|
510
|
+
this.ownClient = false;
|
|
511
|
+
this.frontend = opts.frontend ?? null;
|
|
512
|
+
this.networkEnabled = opts.network !== false;
|
|
513
|
+
this.profilerBase = (opts.profilerBase ?? DEFAULT_PROFILER_BASE).replace(/\/$/, "");
|
|
514
|
+
this.client = opts.client ?? RealtimeClient.shared({ url: this.url });
|
|
515
|
+
lsMigrate();
|
|
516
|
+
this.visible = lsGet(LS.visible, "1") !== "0";
|
|
517
|
+
this.minimized = lsGet(LS.min, "0") === "1";
|
|
518
|
+
this.side = lsGet(LS.side, "right") === "left" ? "left" : "right";
|
|
519
|
+
this.activeTab = lsGet(LS.tab, "realtime") || "realtime";
|
|
520
|
+
this.panelH = clampH(parseInt(lsGet(LS.h, String(defaultPanelH())), 10) || defaultPanelH());
|
|
521
|
+
this.live = lsGet(LS.live, "0") === "1";
|
|
522
|
+
}
|
|
523
|
+
/** Construit le DOM, branche le realtime et ouvre la connexion. No-op si déjà monté. */
|
|
524
|
+
mount() {
|
|
525
|
+
if (typeof document === "undefined") return this;
|
|
526
|
+
if (document.getElementById(HOST_ID)) return this;
|
|
527
|
+
this.buildDom();
|
|
528
|
+
this.wireRealtime();
|
|
529
|
+
this.wireHmr();
|
|
530
|
+
this.wireNetwork();
|
|
531
|
+
this.applyChrome();
|
|
532
|
+
this.registerHandle();
|
|
533
|
+
this.client.connect().catch(() => {});
|
|
534
|
+
this.render();
|
|
535
|
+
return this;
|
|
536
|
+
}
|
|
537
|
+
/** Détache listeners, ferme la connexion (si propriétaire) et retire le DOM. */
|
|
538
|
+
unmount() {
|
|
539
|
+
for (const d of this.disposers) d();
|
|
540
|
+
this.disposers.length = 0;
|
|
541
|
+
if (this.flashTimer) clearTimeout(this.flashTimer);
|
|
542
|
+
this.flashTimer = null;
|
|
543
|
+
if (this.ownClient) this.client.disconnect();
|
|
544
|
+
this.unregisterHandle();
|
|
545
|
+
this.ro?.disconnect();
|
|
546
|
+
this.ro = null;
|
|
547
|
+
try {
|
|
548
|
+
document.documentElement.style.removeProperty("--nodefony-debugbar-height");
|
|
549
|
+
} catch {}
|
|
550
|
+
this.host?.remove();
|
|
551
|
+
this.host = null;
|
|
552
|
+
this.bar = null;
|
|
553
|
+
}
|
|
554
|
+
/** Affiche/masque la barre (pilotable depuis une app via le handle global). */
|
|
555
|
+
setVisible(v) {
|
|
556
|
+
this.visible = v;
|
|
557
|
+
lsSet(LS.visible, v ? "1" : "0");
|
|
558
|
+
this.applyChrome();
|
|
559
|
+
}
|
|
560
|
+
setMinimized(v) {
|
|
561
|
+
this.minimized = v;
|
|
562
|
+
lsSet(LS.min, v ? "1" : "0");
|
|
563
|
+
this.applyChrome();
|
|
564
|
+
}
|
|
565
|
+
toggleSide() {
|
|
566
|
+
this.side = this.side === "left" ? "right" : "left";
|
|
567
|
+
lsSet(LS.side, this.side);
|
|
568
|
+
this.applyChrome();
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Déplie ou replie le panneau — le SEUL endroit qui bascule cet état.
|
|
572
|
+
*
|
|
573
|
+
* Il porte aussi ce qu'un lecteur d'écran doit entendre : `aria-expanded` sur
|
|
574
|
+
* le bouton qui commande, et un nom qui dit l'action à venir (« Déplier » /
|
|
575
|
+
* « Replier »), pas l'état courant — un nom qui décrit l'état laisse
|
|
576
|
+
* l'utilisateur deviner ce que le bouton va faire.
|
|
577
|
+
*/
|
|
578
|
+
setOpen(open) {
|
|
579
|
+
const bar = this.bar;
|
|
580
|
+
if (!bar) return;
|
|
581
|
+
bar.classList.toggle("open", open);
|
|
582
|
+
const btn = this.el.btnToggle;
|
|
583
|
+
if (btn) {
|
|
584
|
+
btn.setAttribute("aria-expanded", open ? "true" : "false");
|
|
585
|
+
const label = open ? "Replier le panneau" : "Déplier le panneau";
|
|
586
|
+
btn.setAttribute("aria-label", label);
|
|
587
|
+
btn.setAttribute("data-tip", label);
|
|
588
|
+
}
|
|
589
|
+
this.render();
|
|
590
|
+
}
|
|
591
|
+
setTab(tab) {
|
|
592
|
+
this.activeTab = tab;
|
|
593
|
+
lsSet(LS.tab, tab);
|
|
594
|
+
this.applyTab();
|
|
595
|
+
this.render();
|
|
596
|
+
}
|
|
597
|
+
setPanelH(h) {
|
|
598
|
+
this.panelH = clampH(h);
|
|
599
|
+
const panes = this.el.panes;
|
|
600
|
+
if (panes) panes.style.height = `${this.panelH}px`;
|
|
601
|
+
}
|
|
602
|
+
/** Reflète l'onglet actif sur les boutons + panes. */
|
|
603
|
+
applyTab() {
|
|
604
|
+
(this.bar?.querySelectorAll(".tab"))?.forEach((t) => t.classList.toggle("active", t.getAttribute("data-tab") === this.activeTab));
|
|
605
|
+
(this.bar?.querySelectorAll(".pane"))?.forEach((p) => p.classList.toggle("active", p.getAttribute("data-pane") === this.activeTab));
|
|
606
|
+
}
|
|
607
|
+
/** Applique l'état chrome au DOM (display + classes de dock + hauteur). */
|
|
608
|
+
applyChrome() {
|
|
609
|
+
if (!this.host || !this.bar) return;
|
|
610
|
+
this.host.style.display = this.visible ? "" : "none";
|
|
611
|
+
this.bar.style.display = this.minimized ? "none" : "";
|
|
612
|
+
const min = this.el.minbar;
|
|
613
|
+
if (min) {
|
|
614
|
+
min.style.display = this.minimized ? "flex" : "none";
|
|
615
|
+
min.setAttribute("class", `minbar ${this.position} dock-${this.side}`);
|
|
616
|
+
}
|
|
617
|
+
this.setPanelH(this.panelH);
|
|
618
|
+
this.applyTab();
|
|
619
|
+
this.publishHeight();
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Publie la hauteur occupée par la barre (dock bas, visible, dépliée) en
|
|
623
|
+
* variable CSS `--nodefony-debugbar-height` sur `:root`. L'app hôte (Studio)
|
|
624
|
+
* la réserve en `padding-bottom` → le contenu n'est jamais masqué. `0px` si
|
|
625
|
+
* masquée / réduite (chip flottante) / dockée en haut.
|
|
626
|
+
*/
|
|
627
|
+
publishHeight() {
|
|
628
|
+
if (typeof document === "undefined") return;
|
|
629
|
+
const h = this.visible && !this.minimized && this.position === "bottom" && this.bar ? this.bar.offsetHeight : 0;
|
|
630
|
+
document.documentElement.style.setProperty("--nodefony-debugbar-height", `${h}px`);
|
|
631
|
+
}
|
|
632
|
+
registerHandle() {
|
|
633
|
+
globalThis[GLOBAL_KEY] = {
|
|
634
|
+
isVisible: () => this.visible,
|
|
635
|
+
setVisible: (v) => this.setVisible(v),
|
|
636
|
+
toggle: () => this.setVisible(!this.visible),
|
|
637
|
+
minimize: () => this.setMinimized(true),
|
|
638
|
+
restore: () => this.setMinimized(false)
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
unregisterHandle() {
|
|
642
|
+
try {
|
|
643
|
+
delete globalThis[GLOBAL_KEY];
|
|
644
|
+
} catch {}
|
|
645
|
+
}
|
|
646
|
+
buildDom() {
|
|
647
|
+
const host = document.createElement("div");
|
|
648
|
+
host.id = HOST_ID;
|
|
649
|
+
host.setAttribute("role", "complementary");
|
|
650
|
+
host.setAttribute("aria-label", "Barre de débogage Nodefony");
|
|
651
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
652
|
+
const style = document.createElement("style");
|
|
653
|
+
style.textContent = STYLES;
|
|
654
|
+
const bar = document.createElement("div");
|
|
655
|
+
bar.className = `bar ${this.position}${this.startOpen ? " open" : ""}`;
|
|
656
|
+
bar.innerHTML = this.template();
|
|
657
|
+
const minbar = document.createElement("div");
|
|
658
|
+
minbar.className = `minbar ${this.position} dock-${this.side}`;
|
|
659
|
+
minbar.innerHTML = `<span class="dot" data-el="mdot"></span><span class="mlogo">⚡</span><span class="mrate" data-el="mrate">0/s</span><span class="mbadge" data-el="mEnv"></span>`;
|
|
660
|
+
shadow.append(style, bar, minbar);
|
|
661
|
+
document.body.appendChild(host);
|
|
662
|
+
this.host = host;
|
|
663
|
+
this.bar = bar;
|
|
664
|
+
this.el.minbar = minbar;
|
|
665
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
666
|
+
this.ro = new ResizeObserver(() => this.publishHeight());
|
|
667
|
+
this.ro.observe(bar);
|
|
668
|
+
}
|
|
669
|
+
shadow.querySelectorAll("[data-el]").forEach((node) => {
|
|
670
|
+
const key = node.getAttribute("data-el");
|
|
671
|
+
if (key) this.el[key] = node;
|
|
672
|
+
});
|
|
673
|
+
const strip = bar.querySelector(".strip");
|
|
674
|
+
this.wireBtn("btnToggle", () => this.setOpen(!bar.classList.contains("open")));
|
|
675
|
+
const onGoto = (ev) => {
|
|
676
|
+
const id = (ev.target?.closest?.(".goto"))?.getAttribute("data-goto");
|
|
677
|
+
if (!id) return;
|
|
678
|
+
this.setOpen(true);
|
|
679
|
+
this.setTab(id);
|
|
680
|
+
};
|
|
681
|
+
strip.addEventListener("click", onGoto);
|
|
682
|
+
this.disposers.push(() => strip.removeEventListener("click", onGoto));
|
|
683
|
+
this.wireBtn("btnMin", () => this.setMinimized(true));
|
|
684
|
+
this.wireBtn("btnSide", () => this.toggleSide());
|
|
685
|
+
this.wireBtn("btnLive", () => this.setLive(!this.live));
|
|
686
|
+
this.updateLiveBtn();
|
|
687
|
+
const tabsBar = bar.querySelector(".tabs");
|
|
688
|
+
if (tabsBar) {
|
|
689
|
+
const onTab = (ev) => {
|
|
690
|
+
const id = (ev.target?.closest?.(".tab"))?.getAttribute("data-tab");
|
|
691
|
+
if (id) this.setTab(id);
|
|
692
|
+
};
|
|
693
|
+
tabsBar.addEventListener("click", onTab);
|
|
694
|
+
this.disposers.push(() => tabsBar.removeEventListener("click", onTab));
|
|
695
|
+
}
|
|
696
|
+
const resize = this.el.resize;
|
|
697
|
+
if (resize) {
|
|
698
|
+
const onDown = (e) => this.startResize(e);
|
|
699
|
+
resize.addEventListener("pointerdown", onDown);
|
|
700
|
+
this.disposers.push(() => resize.removeEventListener("pointerdown", onDown));
|
|
701
|
+
}
|
|
702
|
+
const counts = bar.querySelector(".counts");
|
|
703
|
+
if (counts) {
|
|
704
|
+
const onSev = (ev) => {
|
|
705
|
+
const sev = (ev.target?.closest?.(".sevf"))?.getAttribute("data-sev");
|
|
706
|
+
if (sev !== "all" && sev !== "err" && sev !== "warn") return;
|
|
707
|
+
this.feedSev = this.feedSev === sev ? "all" : sev;
|
|
708
|
+
counts.querySelectorAll(".sevf").forEach((n) => n.classList.toggle("on", n.getAttribute("data-sev") === this.feedSev && this.feedSev !== "all"));
|
|
709
|
+
this.feedDirty = true;
|
|
710
|
+
this.render();
|
|
711
|
+
};
|
|
712
|
+
counts.addEventListener("click", onSev);
|
|
713
|
+
this.disposers.push(() => counts.removeEventListener("click", onSev));
|
|
714
|
+
}
|
|
715
|
+
const search = this.el.logSearch;
|
|
716
|
+
if (search) {
|
|
717
|
+
const onSearch = () => {
|
|
718
|
+
this.feedQuery = search.value.trim().toLowerCase();
|
|
719
|
+
this.feedDirty = true;
|
|
720
|
+
this.render();
|
|
721
|
+
};
|
|
722
|
+
search.addEventListener("input", onSearch);
|
|
723
|
+
this.disposers.push(() => search.removeEventListener("input", onSearch));
|
|
724
|
+
}
|
|
725
|
+
this.wireBtn("btnPause", () => {
|
|
726
|
+
this.feedPaused = !this.feedPaused;
|
|
727
|
+
const b = this.el.btnPause;
|
|
728
|
+
if (b) {
|
|
729
|
+
b.setAttribute("aria-pressed", this.feedPaused ? "true" : "false");
|
|
730
|
+
b.classList.toggle("on", this.feedPaused);
|
|
731
|
+
b.textContent = this.feedPaused ? "▶" : "⏸";
|
|
732
|
+
const tip = this.feedPaused ? "Reprendre l'affichage — la liste se recompose avec ce qui est arrivé pendant la pause" : "Suspendre l'affichage — les entrées continuent d'arriver et se rattrapent à la reprise";
|
|
733
|
+
b.setAttribute("data-tip", tip);
|
|
734
|
+
}
|
|
735
|
+
if (!this.feedPaused) {
|
|
736
|
+
this.feedDirty = true;
|
|
737
|
+
this.render();
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
this.wireBtn("btnCopy", () => {
|
|
741
|
+
const node = this.el.feed;
|
|
742
|
+
const text = node ? node.textContent ?? "" : "";
|
|
743
|
+
navigator.clipboard?.writeText(text).then(() => this.flashBtn("btnCopy", "✓"), () => this.flashBtn("btnCopy", "✗"));
|
|
744
|
+
});
|
|
745
|
+
this.wireBtn("btnClearFeed", () => {
|
|
746
|
+
const node = this.el.feed;
|
|
747
|
+
if (node) node.innerHTML = `<div class="empty">liste vidée — les nouvelles entrées s'afficheront ici.</div>`;
|
|
748
|
+
this.feedLen = this.model.view.feed.length;
|
|
749
|
+
});
|
|
750
|
+
const feed = this.el.feed;
|
|
751
|
+
if (feed) {
|
|
752
|
+
const onFeed = (ev) => {
|
|
753
|
+
const row = ev.target?.closest?.(".log");
|
|
754
|
+
if (!row) return;
|
|
755
|
+
if (row.nextElementSibling?.classList.contains("logdetail")) {
|
|
756
|
+
row.nextElementSibling?.remove();
|
|
757
|
+
row.setAttribute("aria-expanded", "false");
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
const uid = Number(row.getAttribute("data-uid"));
|
|
761
|
+
const entry = this.model.view.feed.find((l) => l.uid === uid);
|
|
762
|
+
if (!entry) return;
|
|
763
|
+
feed.querySelectorAll(".logdetail").forEach((n) => n.remove());
|
|
764
|
+
feed.querySelectorAll(".log[aria-expanded='true']").forEach((n) => n.setAttribute("aria-expanded", "false"));
|
|
765
|
+
row.insertAdjacentHTML("afterend", this.feedDetail(entry));
|
|
766
|
+
row.setAttribute("aria-expanded", "true");
|
|
767
|
+
};
|
|
768
|
+
const onFeedKey = (ev) => {
|
|
769
|
+
const k = ev.key;
|
|
770
|
+
if (k !== "Enter" && k !== " ") return;
|
|
771
|
+
const row = ev.target?.closest?.(".log");
|
|
772
|
+
if (!row) return;
|
|
773
|
+
ev.preventDefault();
|
|
774
|
+
row.click();
|
|
775
|
+
};
|
|
776
|
+
feed.addEventListener("click", onFeed);
|
|
777
|
+
feed.addEventListener("keydown", onFeedKey);
|
|
778
|
+
this.disposers.push(() => {
|
|
779
|
+
feed.removeEventListener("click", onFeed);
|
|
780
|
+
feed.removeEventListener("keydown", onFeedKey);
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
this.wireBtn("btnPurge", () => {
|
|
784
|
+
lsPurge();
|
|
785
|
+
this.flashBtn("btnPurge", "état effacé ✓");
|
|
786
|
+
});
|
|
787
|
+
const onMin = () => this.setMinimized(false);
|
|
788
|
+
minbar.addEventListener("click", onMin);
|
|
789
|
+
this.disposers.push(() => minbar.removeEventListener("click", onMin));
|
|
790
|
+
let resizePending = false;
|
|
791
|
+
const onWinResize = () => {
|
|
792
|
+
if (resizePending) return;
|
|
793
|
+
resizePending = true;
|
|
794
|
+
requestAnimationFrame(() => {
|
|
795
|
+
resizePending = false;
|
|
796
|
+
this.setPanelH(this.panelH);
|
|
797
|
+
});
|
|
798
|
+
};
|
|
799
|
+
window.addEventListener("resize", onWinResize);
|
|
800
|
+
this.disposers.push(() => window.removeEventListener("resize", onWinResize));
|
|
801
|
+
}
|
|
802
|
+
startResize(ev) {
|
|
803
|
+
ev.preventDefault();
|
|
804
|
+
const startY = ev.clientY;
|
|
805
|
+
const startH = this.panelH;
|
|
806
|
+
const onMove = (e) => {
|
|
807
|
+
const delta = this.position === "bottom" ? startY - e.clientY : e.clientY - startY;
|
|
808
|
+
this.setPanelH(startH + delta);
|
|
809
|
+
};
|
|
810
|
+
const onUp = () => {
|
|
811
|
+
document.removeEventListener("pointermove", onMove);
|
|
812
|
+
document.removeEventListener("pointerup", onUp);
|
|
813
|
+
lsSet(LS.h, String(this.panelH));
|
|
814
|
+
};
|
|
815
|
+
document.addEventListener("pointermove", onMove);
|
|
816
|
+
document.addEventListener("pointerup", onUp);
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Retour visuel bref sur un bouton d'action.
|
|
820
|
+
*
|
|
821
|
+
* Une copie réussie ne change rien à l'écran : sans ce clin d'œil, on ne sait
|
|
822
|
+
* pas si le clic a porté, et on reclique.
|
|
823
|
+
*/
|
|
824
|
+
flashBtn(key, glyph) {
|
|
825
|
+
const b = this.el[key];
|
|
826
|
+
if (!b) return;
|
|
827
|
+
const before = b.textContent ?? "";
|
|
828
|
+
b.textContent = glyph;
|
|
829
|
+
const t = setTimeout(() => {
|
|
830
|
+
b.textContent = before;
|
|
831
|
+
}, 900);
|
|
832
|
+
this.disposers.push(() => clearTimeout(t));
|
|
833
|
+
}
|
|
834
|
+
wireBtn(key, handler) {
|
|
835
|
+
const node = this.el[key];
|
|
836
|
+
if (!node) return;
|
|
837
|
+
node.addEventListener("click", handler);
|
|
838
|
+
this.disposers.push(() => node.removeEventListener("click", handler));
|
|
839
|
+
}
|
|
840
|
+
template() {
|
|
841
|
+
return `
|
|
842
|
+
<div class="strip">
|
|
843
|
+
<span class="dot" data-el="dot" data-tip="État de la connexion temps réel"></span>
|
|
844
|
+
<span class="brand" data-tip="Barre de débogage Nodefony — visible en développement uniquement"><span class="logo">◆</span><span class="name">nodefony</span></span>
|
|
845
|
+
<span class="env-badge" data-el="envBadge" data-tip="Environnement dans lequel tourne l'application">env</span>
|
|
846
|
+
<span class="branch" data-el="branch" data-tip="Branche git de la copie de travail"><span class="git">⎇</span><span data-el="branchName">—</span></span>
|
|
847
|
+
<span class="rt-pill" data-el="rtPill" data-tip="Transport temps réel et état de la socket"><span class="bolt">⚡</span> realtime</span>
|
|
848
|
+
${this.miniMetric("rt", "rt", "rtMini", "0/s", "realtime", "Messages temps réel reçus par seconde — cliquer pour ouvrir l'onglet Realtime")}
|
|
849
|
+
${this.miniMetric("cpu", "cpu", "cpuMini", "0%", "perf", "Charge processeur du serveur — cliquer pour ouvrir l'onglet Perf")}
|
|
850
|
+
${this.miniMetric("mem", "mem", "memMini", "0%", "perf", "Mémoire utilisée par le serveur — cliquer pour ouvrir l'onglet Perf")}
|
|
851
|
+
<span class="spacer"></span>
|
|
852
|
+
${this.networkEnabled ? `<button type="button" class="chip goto" data-goto="network" data-tip="Requêtes réseau observées — cliquer pour ouvrir l'onglet Network"><span class="k">net</span><span class="blue" data-el="netChip">0</span></button>` : ""}
|
|
853
|
+
<button type="button" class="chip goto" data-goto="logs" data-tip="Entrées de journal reçues — cliquer pour ouvrir l'onglet Logs"><span class="k">logs</span><span data-el="logs">0</span></button>
|
|
854
|
+
<button type="button" class="chip goto" data-goto="logs" data-tip="Erreurs et alertes — cliquer pour ouvrir l'onglet Logs"><span class="k">err</span><span class="crit" data-el="err">0</span></button>
|
|
855
|
+
<button type="button" class="ctrl live" data-el="btnLive" aria-pressed="false" data-tip="Recevoir les mesures et les journaux en direct. Coupé par défaut : le flux maintient des compteurs côté serveur.">flux OFF</button>
|
|
856
|
+
<button type="button" class="ctrl" data-el="btnSide" aria-label="Changer la barre de côté" data-tip="Changer la barre de côté">⇄</button>
|
|
857
|
+
<button type="button" class="ctrl" data-el="btnMin" aria-label="Réduire la barre en pastille" data-tip="Réduire en pastille">—</button>
|
|
858
|
+
<button type="button" class="toggle" data-el="btnToggle" aria-expanded="${this.startOpen}" aria-controls="nf-db-panel" aria-label="${this.startOpen ? "Replier" : "Déplier"} le panneau" data-tip="${this.startOpen ? "Replier" : "Déplier"} le panneau">▴</button>
|
|
859
|
+
</div>
|
|
860
|
+
<div class="panelwrap" id="nf-db-panel">
|
|
861
|
+
<div class="resize" data-el="resize" title="Redimensionner"></div>
|
|
862
|
+
<div class="tabs">
|
|
863
|
+
<button class="tab" data-tab="realtime">Realtime</button>
|
|
864
|
+
${this.networkEnabled ? `<button class="tab" data-tab="network">Network <span class="tcount" data-el="netTab">0</span></button>` : ""}
|
|
865
|
+
<button class="tab" data-tab="perf">Perf</button>
|
|
866
|
+
<button class="tab" data-tab="logs">Logs <span class="tcount" data-el="logsTab">0</span></button>
|
|
867
|
+
<button class="tab" data-tab="runtime">Runtime</button>
|
|
868
|
+
</div>
|
|
869
|
+
<div class="panes" data-el="panes">
|
|
870
|
+
${this.realtimePane()}
|
|
871
|
+
${this.networkEnabled ? this.networkPane() : ""}
|
|
872
|
+
${this.perfPane()}
|
|
873
|
+
${this.logsPane()}
|
|
874
|
+
${this.runtimePane()}
|
|
875
|
+
</div>
|
|
876
|
+
</div>`;
|
|
877
|
+
}
|
|
878
|
+
realtimePane() {
|
|
879
|
+
return `<div class="pane" data-pane="realtime"><div class="cards">
|
|
880
|
+
<div class="card hero">
|
|
881
|
+
<h4><span class="blue">⚡</span> Realtime</h4>
|
|
882
|
+
<div class="big"><span data-el="rtBig">0</span><small>msg/s</small></div>
|
|
883
|
+
<svg viewBox="0 0 ${CHART_W} 38" preserveAspectRatio="none">
|
|
884
|
+
<polygon class="area rt" data-el="rtArea" points=""/>
|
|
885
|
+
<polyline class="spark rt" data-el="rtLine" points=""/>
|
|
886
|
+
</svg>
|
|
887
|
+
${this.kv("transport", "rtTransport")}
|
|
888
|
+
${this.kv("protocole", "rtProto")}
|
|
889
|
+
${this.kv("état", "rtState")}
|
|
890
|
+
${this.kv("frames reçues", "rtFrames")}
|
|
891
|
+
${this.kv("pic", "rtPeak")}
|
|
892
|
+
<div class="tag"><b>HTTP & WebSocket, même contexte.</b> Push natif, <b>0 polling</b> — chaque chiffre arrive en temps réel par le Core isomorphe.</div>
|
|
893
|
+
</div>
|
|
894
|
+
${this.frontendCard()}
|
|
895
|
+
</div></div>`;
|
|
896
|
+
}
|
|
897
|
+
networkPane() {
|
|
898
|
+
return `<div class="pane np" data-pane="network">
|
|
899
|
+
<div class="net-head">
|
|
900
|
+
<span class="chip"><span class="k">total</span><span data-el="netTotal">0</span></span>
|
|
901
|
+
<span class="chip"><span class="k">err</span><span class="crit" data-el="netErr">0</span></span>
|
|
902
|
+
<span class="chip"><span class="k">pending</span><span class="muted" data-el="netPend">0</span></span>
|
|
903
|
+
<span class="net-clear" data-el="netClear" title="vider la liste">vider</span>
|
|
904
|
+
</div>
|
|
905
|
+
<div class="net-list" data-el="netList"><div class="empty">en attente d'appels AJAX (fetch / XHR)…</div></div>
|
|
906
|
+
<div class="net-detail" data-el="netDetail"><div class="empty">clique un appel → profil serveur (waterfall des phases, route, user).</div></div>
|
|
907
|
+
</div>`;
|
|
908
|
+
}
|
|
909
|
+
perfPane() {
|
|
910
|
+
return `<div class="pane" data-pane="perf"><div class="cards">
|
|
911
|
+
<div class="card">
|
|
912
|
+
<h4>Performance</h4>
|
|
913
|
+
${this.chart("CPU", "cpuVal", "cpuPeak", "cpuLine", "cpuArea")}
|
|
914
|
+
${this.chart("Heap", "heapVal", "heapPeak", "heapLine", "heapArea")}
|
|
915
|
+
${this.chart("Event loop", "loopVal", "loopPeak", "loopLine", "loopArea")}
|
|
916
|
+
</div>
|
|
917
|
+
</div></div>`;
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* L'onglet Logs — une petite console de lecture, pas une liste qui défile.
|
|
921
|
+
*
|
|
922
|
+
* Ce qu'elle porte, et pourquoi : un FILTRE par sévérité et une RECHERCHE
|
|
923
|
+
* (sans quoi on lit le bruit au lieu de son incident) ; une PAUSE (sans quoi
|
|
924
|
+
* la ligne qu'on essaie de lire s'en va) ; une COPIE (une trace se colle dans
|
|
925
|
+
* un ticket) ; et le DÉTAIL d'une entrée, où vit le `requestId` — le champ qui
|
|
926
|
+
* relie ce journal à sa requête, et que la barre recevait sans jamais le
|
|
927
|
+
* montrer.
|
|
928
|
+
*/
|
|
929
|
+
logsPane() {
|
|
930
|
+
return `<div class="pane" data-pane="logs">
|
|
931
|
+
<div class="counts">
|
|
932
|
+
<button type="button" class="chip sevf" data-sev="all" data-tip="Tout afficher"><span class="k">total</span><span data-el="cTotal">0</span></button>
|
|
933
|
+
<button type="button" class="chip sevf" data-sev="err" data-tip="N'afficher que les erreurs (sévérité 0 à 3)"><span class="k">err</span><span class="crit" data-el="cErr">0</span></button>
|
|
934
|
+
<button type="button" class="chip sevf" data-sev="warn" data-tip="N'afficher que les alertes (sévérité 4)"><span class="k">warn</span><span class="warn" data-el="cWarn">0</span></button>
|
|
935
|
+
<span class="chip" data-tip="Entrées écartées par le serveur faute de place dans le tampon — le flux était plus rapide que l'envoi"><span class="k">dropped</span><span class="muted" data-el="cDrop">0</span></span>
|
|
936
|
+
<span class="spacer"></span>
|
|
937
|
+
<input class="search" data-el="logSearch" type="search" placeholder="rechercher…"
|
|
938
|
+
aria-label="Filtrer les journaux sur leur texte, leur module ou leur requête" />
|
|
939
|
+
<button type="button" class="toolbtn" data-el="btnPause" aria-pressed="false" data-tip="Suspendre l'affichage — les entrées continuent d'arriver et se rattrapent à la reprise">⏸</button>
|
|
940
|
+
<button type="button" class="toolbtn" data-el="btnCopy" data-tip="Copier les entrées affichées dans le presse-papiers">⧉</button>
|
|
941
|
+
<button type="button" class="toolbtn" data-el="btnClearFeed" data-tip="Vider la liste affichée (n'efface rien côté serveur)">⌫</button>
|
|
942
|
+
</div>
|
|
943
|
+
<div class="feed" data-el="feed" role="log" aria-label="Journaux du serveur"><div class="empty">en attente de logs…</div></div>
|
|
944
|
+
</div>`;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Ce que la barre garde sur CE navigateur — écrit noir sur blanc.
|
|
948
|
+
*
|
|
949
|
+
* Une console de développement qui écrit dans le stockage local sans le dire
|
|
950
|
+
* est exactement ce qu'on reproche aux autres. La liste est dérivée des clés
|
|
951
|
+
* réelles, donc elle ne peut pas mentir par oubli, et le bouton efface
|
|
952
|
+
* précisément celles-là — jamais le stockage de l'application hôte.
|
|
953
|
+
*/
|
|
954
|
+
storageCard() {
|
|
955
|
+
return `<div class="card">
|
|
956
|
+
<h4>Stockage local</h4>
|
|
957
|
+
<div class="tag">Ces valeurs vivent dans ce navigateur, sur cet appareil. Elles ne quittent jamais la page et ne concernent que l'apparence de la barre.</div>
|
|
958
|
+
${lsKeys().map((k) => `<div class="drow"><span class="dk">${escapeHtml(k.replace("nf.debugbar.", ""))}</span><span class="dv">${escapeHtml(lsGet(k, "—"))}</span></div>`).join("")}
|
|
959
|
+
<div style="margin-top:8px"><button type="button" class="toolbtn" data-el="btnPurge" data-tip="Effacer les préférences de la barre sur ce navigateur — l'application n'est pas touchée">Purger l'état de la barre</button></div>
|
|
960
|
+
</div>`;
|
|
961
|
+
}
|
|
962
|
+
runtimePane() {
|
|
963
|
+
return `<div class="pane" data-pane="runtime"><div class="cards">
|
|
964
|
+
${this.storageCard()}
|
|
965
|
+
<div class="card">
|
|
966
|
+
<h4>Runtime</h4>
|
|
967
|
+
${this.kv("app", "appName")}
|
|
968
|
+
${this.kv("version", "appVersion")}
|
|
969
|
+
${this.kv("environnement", "envRow")}
|
|
970
|
+
${this.kv("branche", "branchRow")}
|
|
971
|
+
${this.kv("pid", "pid")}
|
|
972
|
+
${this.kv("uptime", "uptime")}
|
|
973
|
+
${this.kv("instance", "instance")}
|
|
974
|
+
${this.kv("cpu cores", "cores")}
|
|
975
|
+
${this.kv("loadavg", "load")}
|
|
976
|
+
${this.kv("rss", "rss")}
|
|
977
|
+
${this.kv("heap used", "heapUsed")}
|
|
978
|
+
${this.kv("heap total", "heapTotal")}
|
|
979
|
+
${this.kv("heap limit", "heapLimit")}
|
|
980
|
+
${this.kv("external", "external")}
|
|
981
|
+
</div>
|
|
982
|
+
</div></div>`;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Un indicateur du bandeau — et un RACCOURCI vers l'onglet qui le détaille.
|
|
986
|
+
*
|
|
987
|
+
* C'est un `<button>` et non un `<span>` : le bandeau ne se replie plus au
|
|
988
|
+
* clic (c'était le défaut principal — lire une valeur refermait le panneau),
|
|
989
|
+
* donc chaque indicateur peut faire quelque chose d'utile de son propre clic.
|
|
990
|
+
* Mener à l'onglet qui explique le chiffre est ce que l'utilisateur attend,
|
|
991
|
+
* et un bouton l'annonce et s'atteint au clavier.
|
|
992
|
+
*/
|
|
993
|
+
miniMetric(label, valKey, sparkKey, init, goto, tip) {
|
|
994
|
+
return `<button type="button" class="metric goto" data-goto="${goto}" data-tip="${escapeHtml(tip)}">
|
|
995
|
+
<span class="k">${label}</span>
|
|
996
|
+
<span class="v" data-el="${valKey}">${init}</span>
|
|
997
|
+
<svg class="mini" viewBox="0 0 ${MINI_W} ${MINI_H}" preserveAspectRatio="none">
|
|
998
|
+
<polyline class="spark ok" data-el="${sparkKey}" points=""/>
|
|
999
|
+
</svg>
|
|
1000
|
+
</button>`;
|
|
1001
|
+
}
|
|
1002
|
+
chart(label, valKey, peakKey, lineKey, areaKey) {
|
|
1003
|
+
return `<div class="chart">
|
|
1004
|
+
<div class="hd">
|
|
1005
|
+
<span class="lbl">${label}</span>
|
|
1006
|
+
<span><span class="val" data-el="${valKey}">—</span> <span class="peak" data-el="${peakKey}"></span></span>
|
|
1007
|
+
</div>
|
|
1008
|
+
<svg viewBox="0 0 ${CHART_W} ${CHART_H}" preserveAspectRatio="none">
|
|
1009
|
+
<polygon class="area ok" data-el="${areaKey}" points=""/>
|
|
1010
|
+
<polyline class="spark ok" data-el="${lineKey}" points=""/>
|
|
1011
|
+
</svg>
|
|
1012
|
+
</div>`;
|
|
1013
|
+
}
|
|
1014
|
+
kv(label, key) {
|
|
1015
|
+
return `<div class="kv"><span class="k">${label}</span><span class="v" data-el="${key}">—</span></div>`;
|
|
1016
|
+
}
|
|
1017
|
+
/** Carte Frontend / HMR — affichée seulement si un contexte frontend est fourni. */
|
|
1018
|
+
frontendCard() {
|
|
1019
|
+
if (!this.frontend) return "";
|
|
1020
|
+
const fw = FRAMEWORKS[this.frontend.framework ?? ""] ?? {
|
|
1021
|
+
label: this.frontend.framework ?? "Frontend",
|
|
1022
|
+
color: "#3aa0ff"
|
|
1023
|
+
};
|
|
1024
|
+
return `<div class="card fe">
|
|
1025
|
+
<h4><span style="color:${fw.color}">●</span> Frontend</h4>
|
|
1026
|
+
<div class="fw">
|
|
1027
|
+
<span class="badge" style="background:${fw.color}">${escapeHtml(fw.label)}</span>
|
|
1028
|
+
<span class="name">${escapeHtml(this.frontend.name ?? "")}</span>
|
|
1029
|
+
</div>
|
|
1030
|
+
<div class="hd"><span class="lbl">HMR hot updates</span><span class="hmr-big" data-el="hmrBig">0</span></div>
|
|
1031
|
+
<svg viewBox="0 0 ${CHART_W} 34" preserveAspectRatio="none">
|
|
1032
|
+
<polygon class="area fe" data-el="hmrArea" points=""/>
|
|
1033
|
+
<polyline class="spark fe" data-el="hmrLine" points=""/>
|
|
1034
|
+
</svg>
|
|
1035
|
+
${this.kv("bundler", "feVite")}
|
|
1036
|
+
${this.kv("dernier module", "hmrLast")}
|
|
1037
|
+
<div class="tag"><b>Backend & frontend, un seul process.</b> HMR Vite branché au runtime — sauvegarde un composant, la barre pulse.</div>
|
|
1038
|
+
</div>`;
|
|
1039
|
+
}
|
|
1040
|
+
wireRealtime() {
|
|
1041
|
+
const offState = this.client.onState((state) => {
|
|
1042
|
+
this.model.setState(state);
|
|
1043
|
+
this.scheduleRender();
|
|
1044
|
+
});
|
|
1045
|
+
const offTick = this.client.onStats(() => {
|
|
1046
|
+
if (!this.live) return;
|
|
1047
|
+
this.sampleThroughput();
|
|
1048
|
+
this.scheduleRender();
|
|
1049
|
+
});
|
|
1050
|
+
const offStats = this.client.on(CHANNELS.stats, (...a) => {
|
|
1051
|
+
const p = a[0];
|
|
1052
|
+
if (p && typeof p === "object") this.model.ingestStats(p);
|
|
1053
|
+
this.scheduleRender();
|
|
1054
|
+
});
|
|
1055
|
+
const offSyslog = this.client.on(CHANNELS.syslog, (...a) => {
|
|
1056
|
+
const p = a[0];
|
|
1057
|
+
if (p && typeof p === "object") this.model.ingestSyslog(p);
|
|
1058
|
+
this.scheduleRender();
|
|
1059
|
+
});
|
|
1060
|
+
this.model.setState(this.client.state);
|
|
1061
|
+
this.disposers.push(offState, offTick, offStats, offSyslog, () => {
|
|
1062
|
+
this.stopLive();
|
|
1063
|
+
});
|
|
1064
|
+
if (this.live) this.startLive();
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Démarre les abonnements realtime (tickers serveur stats+syslog). REF-COMPTÉ
|
|
1068
|
+
* (UNE fois) sur le client PARTAGÉ : un canal reste actif tant qu'un
|
|
1069
|
+
* consommateur le veut ; le client ré-abonne seul au reconnect. Idempotent.
|
|
1070
|
+
*/
|
|
1071
|
+
startLive() {
|
|
1072
|
+
if (this.liveOff) return;
|
|
1073
|
+
this.client.subscribe(CHANNELS.stats);
|
|
1074
|
+
this.client.subscribe(CHANNELS.syslog);
|
|
1075
|
+
this.liveOff = () => {
|
|
1076
|
+
this.client.unsubscribe(CHANNELS.stats);
|
|
1077
|
+
this.client.unsubscribe(CHANNELS.syslog);
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
/** Arrête les abonnements realtime (relâche la réf de la barre). Idempotent. */
|
|
1081
|
+
stopLive() {
|
|
1082
|
+
if (!this.liveOff) return;
|
|
1083
|
+
this.liveOff();
|
|
1084
|
+
this.liveOff = null;
|
|
1085
|
+
}
|
|
1086
|
+
/** Active/désactive le temps réel (bouton de la barre) + persiste la préférence. */
|
|
1087
|
+
setLive(v) {
|
|
1088
|
+
if (v === this.live && !!this.liveOff === v) return;
|
|
1089
|
+
this.live = v;
|
|
1090
|
+
lsSet(LS.live, v ? "1" : "0");
|
|
1091
|
+
if (v) {
|
|
1092
|
+
this.prevFrames = this.client.framesReceived;
|
|
1093
|
+
this.startLive();
|
|
1094
|
+
} else {
|
|
1095
|
+
this.stopLive();
|
|
1096
|
+
this.rtRate = 0;
|
|
1097
|
+
pushCap(this.rtSeries, 0, RT_POINTS);
|
|
1098
|
+
}
|
|
1099
|
+
this.updateLiveBtn();
|
|
1100
|
+
this.scheduleRender();
|
|
1101
|
+
}
|
|
1102
|
+
/** Met à jour l'aspect du bouton « Temps réel » selon l'état. */
|
|
1103
|
+
updateLiveBtn() {
|
|
1104
|
+
const btn = this.el["btnLive"];
|
|
1105
|
+
if (!btn) return;
|
|
1106
|
+
btn.textContent = this.live ? "flux ON" : "flux OFF";
|
|
1107
|
+
btn.title = this.live ? "Flux push ACTIF (stats + logs) — clic pour couper. ≠ état de la connexion (pastille « realtime »)." : "Flux push coupé (perf) — clic pour activer (stats + logs). ≠ état de la connexion (pastille « realtime »).";
|
|
1108
|
+
btn.setAttribute("aria-pressed", this.live ? "true" : "false");
|
|
1109
|
+
btn.classList.toggle("on", this.live);
|
|
1110
|
+
}
|
|
1111
|
+
sampleThroughput() {
|
|
1112
|
+
const total = this.client.framesReceived;
|
|
1113
|
+
this.rtRate = Math.max(0, total - this.prevFrames);
|
|
1114
|
+
this.prevFrames = total;
|
|
1115
|
+
if (this.rtRate > this.rtPeak) this.rtPeak = this.rtRate;
|
|
1116
|
+
pushCap(this.rtSeries, this.rtRate, RT_POINTS);
|
|
1117
|
+
this.hmrRate = Math.max(0, this.hmrCount - this.hmrPrev);
|
|
1118
|
+
this.hmrPrev = this.hmrCount;
|
|
1119
|
+
pushCap(this.hmrSeries, this.hmrRate, RT_POINTS);
|
|
1120
|
+
}
|
|
1121
|
+
wireHmr() {
|
|
1122
|
+
if (!this.frontend) return;
|
|
1123
|
+
const dispose = observeViteHmr((e) => this.onHmr(e));
|
|
1124
|
+
this.disposers.push(dispose);
|
|
1125
|
+
}
|
|
1126
|
+
onHmr(e) {
|
|
1127
|
+
if (e.kind === "connected") this.viteConnected = true;
|
|
1128
|
+
else if (e.kind === "update") {
|
|
1129
|
+
this.hmrCount++;
|
|
1130
|
+
this.hmrLast = e.path ?? "(module)";
|
|
1131
|
+
this.flashHmr();
|
|
1132
|
+
} else if (e.kind === "full-reload") {
|
|
1133
|
+
this.hmrCount++;
|
|
1134
|
+
this.hmrLast = e.path ?? "full reload";
|
|
1135
|
+
this.flashHmr();
|
|
1136
|
+
}
|
|
1137
|
+
this.scheduleRender();
|
|
1138
|
+
}
|
|
1139
|
+
flashHmr() {
|
|
1140
|
+
const node = this.el.hmrBig;
|
|
1141
|
+
if (!node) return;
|
|
1142
|
+
node.setAttribute("class", "hmr-big hmr-flash");
|
|
1143
|
+
if (this.flashTimer) clearTimeout(this.flashTimer);
|
|
1144
|
+
this.flashTimer = setTimeout(() => {
|
|
1145
|
+
node.setAttribute("class", "hmr-big");
|
|
1146
|
+
}, 600);
|
|
1147
|
+
}
|
|
1148
|
+
wireNetwork() {
|
|
1149
|
+
if (!this.networkEnabled) return;
|
|
1150
|
+
const viteOrigin = this.frontend?.viteOrigin ?? "";
|
|
1151
|
+
const uninstall = installNetworkInterceptor({
|
|
1152
|
+
onChange: (e) => this.onNetEntry(e),
|
|
1153
|
+
ignore: (url) => url.includes(this.profilerBase) || url.includes("/@vite/") || url.includes("/@fs/") || url.includes("/node_modules/.vite/") || viteOrigin !== "" && url.includes(viteOrigin)
|
|
1154
|
+
});
|
|
1155
|
+
this.disposers.push(uninstall);
|
|
1156
|
+
const list = this.el.netList;
|
|
1157
|
+
if (list) {
|
|
1158
|
+
const onClick = (ev) => {
|
|
1159
|
+
const row = ev.target?.closest?.(".net-row");
|
|
1160
|
+
if (!row) return;
|
|
1161
|
+
const rid = row.dataset.rid;
|
|
1162
|
+
this.selectRow(row, rid || null);
|
|
1163
|
+
};
|
|
1164
|
+
list.addEventListener("click", onClick);
|
|
1165
|
+
this.disposers.push(() => list.removeEventListener("click", onClick));
|
|
1166
|
+
}
|
|
1167
|
+
const detail = this.el.netDetail;
|
|
1168
|
+
if (detail) {
|
|
1169
|
+
const onDetail = (ev) => {
|
|
1170
|
+
if (ev.target?.closest?.("[data-act=\"close\"]")) this.deselect();
|
|
1171
|
+
};
|
|
1172
|
+
detail.addEventListener("click", onDetail);
|
|
1173
|
+
this.disposers.push(() => detail.removeEventListener("click", onDetail));
|
|
1174
|
+
}
|
|
1175
|
+
const clear = this.el.netClear;
|
|
1176
|
+
if (clear) {
|
|
1177
|
+
const onClear = (e) => {
|
|
1178
|
+
e.stopPropagation();
|
|
1179
|
+
this.net.clear();
|
|
1180
|
+
this.netRows.clear();
|
|
1181
|
+
this.selectedRid = null;
|
|
1182
|
+
this.selRowId = null;
|
|
1183
|
+
const node = this.el.netList;
|
|
1184
|
+
if (node) node.innerHTML = `<div class="empty">en attente d'appels AJAX (fetch / XHR)…</div>`;
|
|
1185
|
+
this.detailVersion++;
|
|
1186
|
+
this.scheduleRender();
|
|
1187
|
+
};
|
|
1188
|
+
clear.addEventListener("click", onClear);
|
|
1189
|
+
this.disposers.push(() => clear.removeEventListener("click", onClear));
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
onNetEntry(e) {
|
|
1193
|
+
this.net.ingest(e);
|
|
1194
|
+
this.upsertNetRow(e);
|
|
1195
|
+
if (e.requestId && e.requestId === this.selectedRid) this.detailVersion++;
|
|
1196
|
+
this.scheduleRender();
|
|
1197
|
+
}
|
|
1198
|
+
/** Crée ou met à jour le nœud de ligne d'un appel (jamais d'innerHTML global). */
|
|
1199
|
+
upsertNetRow(e) {
|
|
1200
|
+
const list = this.el.netList;
|
|
1201
|
+
if (!list) return;
|
|
1202
|
+
let row = this.netRows.get(e.id);
|
|
1203
|
+
if (!row) {
|
|
1204
|
+
if (this.netRows.size === 0) list.textContent = "";
|
|
1205
|
+
row = document.createElement("div");
|
|
1206
|
+
row.className = "net-row";
|
|
1207
|
+
row.innerHTML = "<span class=\"net-method\"></span><span class=\"net-path\"></span><span class=\"net-rid\"></span><span class=\"net-status\"></span><span class=\"net-dur\"></span>";
|
|
1208
|
+
this.netRows.set(e.id, row);
|
|
1209
|
+
list.insertBefore(row, list.firstChild);
|
|
1210
|
+
while (this.netRows.size > 80 && list.lastElementChild) {
|
|
1211
|
+
const last = list.lastElementChild;
|
|
1212
|
+
for (const [id, n] of this.netRows) if (n === last) {
|
|
1213
|
+
this.netRows.delete(id);
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
last.remove();
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
this.fillNetRow(row, e);
|
|
1220
|
+
}
|
|
1221
|
+
/** Remplit/actualise les cellules d'une ligne (textContent → 0 échappement). */
|
|
1222
|
+
fillNetRow(row, e) {
|
|
1223
|
+
row.dataset.rid = e.requestId ?? "";
|
|
1224
|
+
row.className = `net-row${e.requestId && e.requestId === this.selectedRid ? " sel" : ""}${isError(e) ? " err" : ""}`;
|
|
1225
|
+
const [m, path, rid, status, dur] = row.children;
|
|
1226
|
+
m.className = `net-method ${methodClass(e.method)}`;
|
|
1227
|
+
m.textContent = e.method;
|
|
1228
|
+
path.textContent = e.path;
|
|
1229
|
+
path.title = e.url;
|
|
1230
|
+
rid.textContent = e.requestId ? shortId(e.requestId) : "";
|
|
1231
|
+
if (e.pending) {
|
|
1232
|
+
status.className = "net-status sp";
|
|
1233
|
+
status.textContent = "···";
|
|
1234
|
+
} else if (e.error) {
|
|
1235
|
+
status.className = "net-status s5";
|
|
1236
|
+
status.textContent = "ERR";
|
|
1237
|
+
} else {
|
|
1238
|
+
status.className = `net-status s${statusFamily(e.status)}`;
|
|
1239
|
+
status.textContent = e.status === null ? "—" : String(e.status);
|
|
1240
|
+
}
|
|
1241
|
+
dur.textContent = e.durationMs === null ? "" : `${e.durationMs}ms`;
|
|
1242
|
+
}
|
|
1243
|
+
/** Sélectionne une ligne (highlight) + déclenche le fetch du profil. */
|
|
1244
|
+
selectRow(row, rid) {
|
|
1245
|
+
if (this.selRowId !== null) this.netRows.get(this.selRowId)?.classList.remove("sel");
|
|
1246
|
+
row.classList.add("sel");
|
|
1247
|
+
const idEntry = [...this.netRows.entries()].find(([, n]) => n === row);
|
|
1248
|
+
this.selRowId = idEntry ? idEntry[0] : null;
|
|
1249
|
+
this.selectedRid = rid;
|
|
1250
|
+
this.selNoRid = !rid;
|
|
1251
|
+
this.detailVersion++;
|
|
1252
|
+
const minDetail = detailPanelH();
|
|
1253
|
+
if (rid && this.panelH < minDetail) this.setPanelH(minDetail);
|
|
1254
|
+
if (rid && !this.net.profileState(rid)) this.fetchProfile(rid);
|
|
1255
|
+
if (rid && typeof window !== "undefined") try {
|
|
1256
|
+
window.dispatchEvent(new CustomEvent(PLATFORM_EVENTS.debugbarSelect, { detail: { requestId: rid } }));
|
|
1257
|
+
} catch {}
|
|
1258
|
+
this.scheduleRender();
|
|
1259
|
+
}
|
|
1260
|
+
/** Fetch `/{profilerBase}/{requestId}` (ignoré par l'intercepteur). */
|
|
1261
|
+
fetchProfile(requestId) {
|
|
1262
|
+
if (typeof fetch === "undefined") return;
|
|
1263
|
+
this.net.setProfileState(requestId, { status: "loading" });
|
|
1264
|
+
fetch(`${this.profilerBase}/${encodeURIComponent(requestId)}`, { headers: { accept: "application/json" } }).then(async (res) => {
|
|
1265
|
+
if (res.status === 404) {
|
|
1266
|
+
this.net.setProfileState(requestId, { status: "missing" });
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
1270
|
+
if (!res.ok || !ct.includes("application/json")) {
|
|
1271
|
+
this.net.setProfileState(requestId, {
|
|
1272
|
+
status: "error",
|
|
1273
|
+
message: res.ok ? "réponse non-JSON (path profiler non proxifié par Vite ?)" : `HTTP ${res.status}`
|
|
1274
|
+
});
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
const profile = await res.json();
|
|
1278
|
+
this.net.setProfileState(requestId, {
|
|
1279
|
+
status: "ready",
|
|
1280
|
+
profile
|
|
1281
|
+
});
|
|
1282
|
+
}).catch((err) => {
|
|
1283
|
+
this.net.setProfileState(requestId, {
|
|
1284
|
+
status: "error",
|
|
1285
|
+
message: err instanceof Error ? err.message : "fetch failed"
|
|
1286
|
+
});
|
|
1287
|
+
}).finally(() => {
|
|
1288
|
+
if (requestId === this.selectedRid) this.detailVersion++;
|
|
1289
|
+
this.scheduleRender();
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
scheduleRender() {
|
|
1293
|
+
if (typeof requestAnimationFrame === "undefined") {
|
|
1294
|
+
this.render();
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
if (this.rafPending) return;
|
|
1298
|
+
this.rafPending = true;
|
|
1299
|
+
requestAnimationFrame(() => {
|
|
1300
|
+
this.rafPending = false;
|
|
1301
|
+
this.render();
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
text(key, value) {
|
|
1305
|
+
const node = this.el[key];
|
|
1306
|
+
if (node) node.textContent = value;
|
|
1307
|
+
}
|
|
1308
|
+
/** className safe pour HTML *et* SVG (SVGElement.className n'est pas une string). */
|
|
1309
|
+
cls(key, value) {
|
|
1310
|
+
this.el[key]?.setAttribute("class", value);
|
|
1311
|
+
}
|
|
1312
|
+
setPoints(lineKey, areaKey, series, tier, height, max) {
|
|
1313
|
+
const pts = sparklinePoints(series, CHART_W, height, max);
|
|
1314
|
+
this.el[lineKey]?.setAttribute("points", pts);
|
|
1315
|
+
this.el[lineKey]?.setAttribute("class", `spark ${tier}`);
|
|
1316
|
+
if (areaKey) {
|
|
1317
|
+
const area = this.el[areaKey];
|
|
1318
|
+
if (area) {
|
|
1319
|
+
area.setAttribute("points", pts ? `${pts} ${CHART_W},${height} 0,${height}` : "");
|
|
1320
|
+
area.setAttribute("class", `area ${tier}`);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
render() {
|
|
1325
|
+
if (!this.bar) return;
|
|
1326
|
+
const v = this.model.view;
|
|
1327
|
+
this.renderStrip(v);
|
|
1328
|
+
if (!this.bar.classList.contains("open")) return;
|
|
1329
|
+
switch (this.activeTab) {
|
|
1330
|
+
case "realtime":
|
|
1331
|
+
this.renderRealtimePane(v);
|
|
1332
|
+
break;
|
|
1333
|
+
case "network":
|
|
1334
|
+
this.renderNetwork();
|
|
1335
|
+
break;
|
|
1336
|
+
case "perf":
|
|
1337
|
+
this.renderPerf(v);
|
|
1338
|
+
break;
|
|
1339
|
+
case "logs":
|
|
1340
|
+
this.renderLogsPane(v);
|
|
1341
|
+
break;
|
|
1342
|
+
case "runtime": this.renderRuntime(v);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
/** Bandeau toujours visible (chips + pouls) — léger. */
|
|
1346
|
+
renderStrip(v) {
|
|
1347
|
+
const connected = v.state === "connected";
|
|
1348
|
+
const cpuT = gauge(v.cpuPercent);
|
|
1349
|
+
const memT = gauge(v.heapPercent);
|
|
1350
|
+
this.text("envBadge", v.env || "env");
|
|
1351
|
+
this.cls("envBadge", `env-badge ${envClass(v.env)}`);
|
|
1352
|
+
this.text("branchName", v.branch || "—");
|
|
1353
|
+
this.el.branch?.setAttribute("title", v.branch ? `branche git : ${v.branch}` : "branche git");
|
|
1354
|
+
this.text("mEnv", v.env);
|
|
1355
|
+
this.cls("dot", `dot ${v.state}`);
|
|
1356
|
+
this.cls("mdot", `dot ${v.state}`);
|
|
1357
|
+
this.text("mrate", `${this.rtRate}/s`);
|
|
1358
|
+
this.cls("rtPill", connected ? "rt-pill connected" : "rt-pill");
|
|
1359
|
+
const connTitle = `Connexion temps réel : ${v.state}`;
|
|
1360
|
+
this.el.rtPill?.setAttribute("title", connTitle);
|
|
1361
|
+
this.el.dot?.setAttribute("title", connTitle);
|
|
1362
|
+
this.text("rt", `${this.rtRate}/s`);
|
|
1363
|
+
this.cls("rt", "v blue");
|
|
1364
|
+
this.el.rtMini?.setAttribute("points", sparklinePoints(this.rtSeries, MINI_W, MINI_H));
|
|
1365
|
+
this.el.rtMini?.setAttribute("class", "spark rt");
|
|
1366
|
+
this.text("cpu", `${v.cpuPercent}%`);
|
|
1367
|
+
this.cls("cpu", `v ${cpuT}`);
|
|
1368
|
+
this.text("mem", `${v.heapPercent}%`);
|
|
1369
|
+
this.cls("mem", `v ${memT}`);
|
|
1370
|
+
this.el.cpuMini?.setAttribute("points", sparklinePoints(v.cpuSeries, MINI_W, MINI_H, 100));
|
|
1371
|
+
this.el.cpuMini?.setAttribute("class", `spark ${cpuT}`);
|
|
1372
|
+
this.el.memMini?.setAttribute("points", sparklinePoints(v.heapSeries, MINI_W, MINI_H, 100));
|
|
1373
|
+
this.el.memMini?.setAttribute("class", `spark ${memT}`);
|
|
1374
|
+
if (this.networkEnabled) {
|
|
1375
|
+
this.text("netChip", String(this.net.total));
|
|
1376
|
+
this.cls("netChip", this.net.errors > 0 ? "crit" : "blue");
|
|
1377
|
+
this.text("netTab", String(this.net.total));
|
|
1378
|
+
this.cls("netTab", this.net.errors > 0 ? "tcount crit" : "tcount");
|
|
1379
|
+
}
|
|
1380
|
+
this.text("logs", String(v.logTotal));
|
|
1381
|
+
this.text("err", String(v.errorCount));
|
|
1382
|
+
this.text("logsTab", String(v.logTotal));
|
|
1383
|
+
this.cls("logsTab", v.errorCount > 0 ? "tcount crit" : "tcount");
|
|
1384
|
+
}
|
|
1385
|
+
renderRealtimePane(v) {
|
|
1386
|
+
const live = v.state === "connected";
|
|
1387
|
+
this.text("rtBig", String(this.rtRate));
|
|
1388
|
+
this.setPoints("rtLine", "rtArea", this.rtSeries, "rt", 38);
|
|
1389
|
+
this.text("rtTransport", "WebSocket");
|
|
1390
|
+
this.text("rtProto", "JSON-RPC 2.0");
|
|
1391
|
+
this.text("rtState", v.state);
|
|
1392
|
+
this.cls("rtState", `v ${live ? "ok" : "warn"}`);
|
|
1393
|
+
this.text("rtFrames", String(this.client.framesReceived));
|
|
1394
|
+
this.text("rtPeak", `${this.rtPeak}/s`);
|
|
1395
|
+
if (this.frontend) {
|
|
1396
|
+
this.text("hmrBig", String(this.hmrCount));
|
|
1397
|
+
this.setPoints("hmrLine", "hmrArea", this.hmrSeries, "fe", 34);
|
|
1398
|
+
this.text("feVite", this.viteConnected ? "Vite · connecté" : "Vite · …");
|
|
1399
|
+
this.cls("feVite", `v ${this.viteConnected ? "ok" : "warn"}`);
|
|
1400
|
+
this.text("hmrLast", this.hmrLast);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
renderPerf(v) {
|
|
1404
|
+
const cpuT = gauge(v.cpuPercent);
|
|
1405
|
+
const memT = gauge(v.heapPercent);
|
|
1406
|
+
const loopT = gauge(v.eventLoopMs, 50, 200);
|
|
1407
|
+
this.text("cpuVal", `${v.cpuPercent}%`);
|
|
1408
|
+
this.text("cpuPeak", v.cpuPeak ? `peak ${v.cpuPeak}%` : "");
|
|
1409
|
+
this.cls("cpuVal", `val ${cpuT}`);
|
|
1410
|
+
this.setPoints("cpuLine", "cpuArea", v.cpuSeries, cpuT, CHART_H, 100);
|
|
1411
|
+
this.text("heapVal", `${v.heapPercent}%`);
|
|
1412
|
+
this.text("heapPeak", v.heapPeak ? `peak ${v.heapPeak}%` : "");
|
|
1413
|
+
this.cls("heapVal", `val ${memT}`);
|
|
1414
|
+
this.setPoints("heapLine", "heapArea", v.heapSeries, memT, CHART_H, 100);
|
|
1415
|
+
this.text("loopVal", `${v.eventLoopMs}ms`);
|
|
1416
|
+
this.text("loopPeak", v.eventLoopPeak ? `peak ${v.eventLoopPeak}ms` : "");
|
|
1417
|
+
this.cls("loopVal", `val ${loopT}`);
|
|
1418
|
+
this.setPoints("loopLine", "loopArea", v.loopSeries, loopT, CHART_H);
|
|
1419
|
+
}
|
|
1420
|
+
renderRuntime(v) {
|
|
1421
|
+
this.text("appName", v.appName || "—");
|
|
1422
|
+
this.text("appVersion", v.appVersion || "—");
|
|
1423
|
+
this.text("envRow", v.debug ? `${v.env} · debug` : v.env || "—");
|
|
1424
|
+
this.text("branchRow", v.branch || "—");
|
|
1425
|
+
this.text("pid", String(v.pid));
|
|
1426
|
+
this.text("uptime", formatUptime(v.uptime));
|
|
1427
|
+
this.text("instance", v.instanceId);
|
|
1428
|
+
this.text("cores", String(v.cpuCount));
|
|
1429
|
+
this.text("load", v.loadavg.map((n) => n.toFixed(2)).join(" ") || "—");
|
|
1430
|
+
this.text("rss", formatBytes(v.rss));
|
|
1431
|
+
this.text("heapUsed", formatBytes(v.heapUsed));
|
|
1432
|
+
this.text("heapTotal", formatBytes(v.heapTotal));
|
|
1433
|
+
this.text("heapLimit", formatBytes(v.heapLimit));
|
|
1434
|
+
this.text("external", formatBytes(v.external));
|
|
1435
|
+
}
|
|
1436
|
+
renderLogsPane(v) {
|
|
1437
|
+
this.text("cTotal", String(v.logTotal));
|
|
1438
|
+
this.text("cErr", String(v.errorCount));
|
|
1439
|
+
this.text("cWarn", String(v.warnCount));
|
|
1440
|
+
this.text("cDrop", String(v.dropped));
|
|
1441
|
+
this.renderFeed(v.feed);
|
|
1442
|
+
}
|
|
1443
|
+
/** Classe de couleur d'une entrée, dérivée de sa sévérité RFC 5424. */
|
|
1444
|
+
static tierOf(severity) {
|
|
1445
|
+
if (severity <= 3) return "crit";
|
|
1446
|
+
if (severity === 4) return "warn";
|
|
1447
|
+
if (severity === 7) return "muted";
|
|
1448
|
+
return "info";
|
|
1449
|
+
}
|
|
1450
|
+
/** L'entrée passe-t-elle le filtre de sévérité et la recherche en cours ? */
|
|
1451
|
+
feedMatch(l) {
|
|
1452
|
+
if (this.feedSev === "err" && l.severity > 3) return false;
|
|
1453
|
+
if (this.feedSev === "warn" && l.severity !== 4) return false;
|
|
1454
|
+
const q = this.feedQuery;
|
|
1455
|
+
if (q === "") return true;
|
|
1456
|
+
return l.text.toLowerCase().includes(q) || l.module.toLowerCase().includes(q) || l.msgid.toLowerCase().includes(q) || (l.requestId ?? "").toLowerCase().includes(q);
|
|
1457
|
+
}
|
|
1458
|
+
/** Une ligne de journal — horodatage, sévérité, module, texte, requête. */
|
|
1459
|
+
feedRow(l) {
|
|
1460
|
+
const tier = DebugBar.tierOf(l.severity);
|
|
1461
|
+
const rid = l.requestId ? `<span class="rid" data-tip="requête ${escapeHtml(l.requestId)} — la même valeur relie ce journal à sa route, à ses requêtes de base et à sa réponse">${escapeHtml(l.requestId.slice(0, 8))}</span>` : "";
|
|
1462
|
+
return `<div class="log" data-uid="${l.uid}" tabindex="0" role="button" aria-expanded="false" aria-label="Entrée ${escapeHtml(l.name)} de ${escapeHtml(l.module)} — ouvrir le détail"><span class="ts">${fmtClock(l.ts)}</span><span class="sev ${tier}">${escapeHtml(l.name)}</span><span class="mod">${escapeHtml(l.module)}</span><span class="txt">${escapeHtml(l.text)}</span>${rid}</div>`;
|
|
1463
|
+
}
|
|
1464
|
+
/** Le détail d'une entrée — ce qu'on colle dans un ticket. */
|
|
1465
|
+
feedDetail(l) {
|
|
1466
|
+
const row = (k, v) => `<div class="drow"><span class="dk">${k}</span><span class="dv">${escapeHtml(v)}</span></div>`;
|
|
1467
|
+
return `<div class="logdetail">
|
|
1468
|
+
${row("horodatage", new Date(l.ts).toISOString())}
|
|
1469
|
+
${row("sévérité", `${l.name} (${l.severity})`)}
|
|
1470
|
+
${row("module", l.module)}
|
|
1471
|
+
${l.msgid ? row("catégorie", l.msgid) : ""}
|
|
1472
|
+
${l.pid ? row("worker (pid)", String(l.pid)) : ""}
|
|
1473
|
+
${row("séquence", String(l.uid))}
|
|
1474
|
+
${l.requestId ? row("requête", l.requestId) : ""}
|
|
1475
|
+
${row("message", l.text)}
|
|
1476
|
+
</div>`;
|
|
1477
|
+
}
|
|
1478
|
+
/**
|
|
1479
|
+
* Rendu du journal — **incrémental**, et c'est le point.
|
|
1480
|
+
*
|
|
1481
|
+
* L'ancienne version réassignait `innerHTML` en entier à chaque arrivée. Deux
|
|
1482
|
+
* conséquences qu'on ne voit pas dans le code et qu'on subit à l'écran : la
|
|
1483
|
+
* SÉLECTION de texte s'efface — impossible de copier une ligne pendant que le
|
|
1484
|
+
* flux tourne — et la position de DÉFILEMENT saute. Ici, seules les entrées
|
|
1485
|
+
* nouvelles sont insérées en tête ; ce qui est affiché n'est jamais reconstruit.
|
|
1486
|
+
*
|
|
1487
|
+
* Un changement de filtre ou de recherche, lui, refait bien la liste : le jeu
|
|
1488
|
+
* affiché change entièrement, il n'y a rien à préserver.
|
|
1489
|
+
*/
|
|
1490
|
+
renderFeed(feed) {
|
|
1491
|
+
const node = this.el.feed;
|
|
1492
|
+
if (!node) return;
|
|
1493
|
+
if (this.feedPaused) return;
|
|
1494
|
+
const refilter = this.feedDirty;
|
|
1495
|
+
if (!refilter && feed.length === this.feedLen) return;
|
|
1496
|
+
const previous = this.feedLen;
|
|
1497
|
+
this.feedLen = feed.length;
|
|
1498
|
+
this.feedDirty = false;
|
|
1499
|
+
if (refilter) {
|
|
1500
|
+
const rows = [];
|
|
1501
|
+
for (let i = feed.length - 1; i >= 0; i--) {
|
|
1502
|
+
const l = feed[i];
|
|
1503
|
+
if (this.feedMatch(l)) rows.push(this.feedRow(l));
|
|
1504
|
+
}
|
|
1505
|
+
node.innerHTML = rows.length === 0 ? `<div class="empty">${feed.length === 0 ? "en attente de logs…" : "aucune entrée ne correspond au filtre."}</div>` : rows.join("");
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
const added = feed.length - previous;
|
|
1509
|
+
if (previous < 0 || added < 0 || added > feed.length) {
|
|
1510
|
+
this.feedDirty = true;
|
|
1511
|
+
this.renderFeed(feed);
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
if (added === 0) return;
|
|
1515
|
+
let html = "";
|
|
1516
|
+
for (let i = feed.length - 1; i >= feed.length - added; i--) {
|
|
1517
|
+
const l = feed[i];
|
|
1518
|
+
if (this.feedMatch(l)) html += this.feedRow(l);
|
|
1519
|
+
}
|
|
1520
|
+
if (html === "") return;
|
|
1521
|
+
if (node.querySelector(".empty")) node.innerHTML = "";
|
|
1522
|
+
node.insertAdjacentHTML("afterbegin", html);
|
|
1523
|
+
while (node.childElementCount > 40) node.lastElementChild?.remove();
|
|
1524
|
+
}
|
|
1525
|
+
renderNetwork() {
|
|
1526
|
+
this.text("netTotal", String(this.net.total));
|
|
1527
|
+
this.text("netErr", String(this.net.errors));
|
|
1528
|
+
this.text("netPend", String(this.net.pending));
|
|
1529
|
+
if (this.detailVersion !== this.detailRendered) {
|
|
1530
|
+
this.detailRendered = this.detailVersion;
|
|
1531
|
+
this.renderDetail();
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
renderDetail() {
|
|
1535
|
+
const node = this.el.netDetail;
|
|
1536
|
+
if (!node) return;
|
|
1537
|
+
const rid = this.selectedRid;
|
|
1538
|
+
const hasSel = !!rid || this.selNoRid;
|
|
1539
|
+
node.parentElement?.classList.toggle("sel", hasSel);
|
|
1540
|
+
if (!hasSel) {
|
|
1541
|
+
node.innerHTML = `<div class="empty">clique un appel → profil serveur (waterfall des phases, route, user).</div>`;
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
const closeBar = `<div class="det-bar"><span class="det-close" data-act="close" title="Fermer le détail">✕</span></div>`;
|
|
1545
|
+
let body;
|
|
1546
|
+
if (!rid) body = `<div class="det-err">cet appel n'a pas de requestId lisible — réponse sans header <b>X-Request-Id</b> (cross-origin sans Access-Control-Expose-Headers, ou appel hors Nodefony).</div>`;
|
|
1547
|
+
else {
|
|
1548
|
+
const st = this.net.profileState(rid);
|
|
1549
|
+
if (!st || st.status === "loading") body = `<div class="det-loading">profil <b>${escapeHtml(shortId(rid))}</b> — chargement…</div>`;
|
|
1550
|
+
else if (st.status === "missing") body = `<div class="det-err">profil introuvable (évincé du ring buffer, ou requête sans timing).</div>`;
|
|
1551
|
+
else if (st.status === "error") body = `<div class="det-err">erreur profiler : ${escapeHtml(st.message)}</div>`;
|
|
1552
|
+
else body = this.profileHtml(st.profile);
|
|
1553
|
+
}
|
|
1554
|
+
node.innerHTML = closeBar + body;
|
|
1555
|
+
}
|
|
1556
|
+
/** Désélectionne la requête → referme le détail (placeholder). */
|
|
1557
|
+
deselect() {
|
|
1558
|
+
if (this.selRowId !== null) this.netRows.get(this.selRowId)?.classList.remove("sel");
|
|
1559
|
+
this.selRowId = null;
|
|
1560
|
+
this.selectedRid = null;
|
|
1561
|
+
this.selNoRid = false;
|
|
1562
|
+
this.detailVersion++;
|
|
1563
|
+
this.scheduleRender();
|
|
1564
|
+
}
|
|
1565
|
+
/** Rend le détail d'un profil serveur (méta + waterfall des phases). */
|
|
1566
|
+
profileHtml(p) {
|
|
1567
|
+
const bars = computeWaterfall(p.phases);
|
|
1568
|
+
const total = p.durationMs === null ? "—" : `${p.durationMs}ms`;
|
|
1569
|
+
const kv = (k, val) => `<div class="kv"><span class="k">${k}</span><span class="v">${val}</span></div>`;
|
|
1570
|
+
const meta = `<div class="det-grid">` + kv("route", escapeHtml(p.route ?? "—")) + kv("controller", escapeHtml(p.controller ? `${p.controller}.${p.action ?? "?"}` : "—")) + kv("status", `${p.status ?? "—"}`) + kv("total serveur", total) + kv("user", escapeHtml(p.user ?? "anonyme")) + kv("kind", p.kind) + kv("requestId", escapeHtml(shortId(p.requestId))) + kv("traceparent", escapeHtml(traceId(p))) + (p.error ? kv("erreur", `<span class="crit">${escapeHtml(p.error)}</span>`) : "") + `</div>`;
|
|
1571
|
+
let wf = "";
|
|
1572
|
+
if (bars.length === 0) wf = `<div class="empty">aucune phase mesurée (timing désactivé ?).</div>`;
|
|
1573
|
+
else {
|
|
1574
|
+
wf = `<div class="wf-title">timeline des phases (serveur)</div><div class="wf">`;
|
|
1575
|
+
for (const b of bars) wf += `<div class="wf-row"><span class="wf-name">${escapeHtml(b.name)}</span><div class="wf-track"><div class="wf-bar ${b.tier}" style="left:${b.leftPct}%;width:${b.widthPct}%"></div></div><span class="wf-ms">${b.durationMs}ms</span></div>`;
|
|
1576
|
+
wf += `</div>`;
|
|
1577
|
+
}
|
|
1578
|
+
return meta + wf + this.queriesHtml(p.queries);
|
|
1579
|
+
}
|
|
1580
|
+
/** Rend les requêtes ORM (SEAM futur) — vide tant qu'aucun adapter ne pushe. */
|
|
1581
|
+
queriesHtml(queries) {
|
|
1582
|
+
if (!queries || queries.length === 0) return "";
|
|
1583
|
+
let out = `<div class="wf-title" style="margin-top:10px">requêtes ORM (${queries.length})</div><div class="net-list" style="border:0">`;
|
|
1584
|
+
for (const q of queries) out += `<div class="net-row" style="cursor:default"><span class="net-path" title="${escapeHtml(q.sql)}">${escapeHtml(q.sql)}</span>` + (q.connector ? `<span class="net-rid">${escapeHtml(q.connector)}</span>` : "") + (typeof q.rows === "number" ? `<span class="net-dur">${q.rows} rows</span>` : "") + `<span class="net-dur">${q.durationMs}ms</span></div>`;
|
|
1585
|
+
out += `</div>`;
|
|
1586
|
+
return out;
|
|
1587
|
+
}
|
|
1588
|
+
};
|
|
1589
|
+
/** Famille de status (2/3/4/5) → classe de couleur. `null` → 5 (inconnu). */
|
|
1590
|
+
function statusFamily(status) {
|
|
1591
|
+
if (status === null) return 5;
|
|
1592
|
+
return Math.floor(status / 100);
|
|
1593
|
+
}
|
|
1594
|
+
/** Méthode HTTP → classe de couleur du chip. */
|
|
1595
|
+
function methodClass(method) {
|
|
1596
|
+
const m = method.toLowerCase();
|
|
1597
|
+
if (m === "get" || m === "post" || m === "put" || m === "patch" || m === "delete") return m;
|
|
1598
|
+
return "ws";
|
|
1599
|
+
}
|
|
1600
|
+
/** Raccourci d'un id (1er bloc UUID, ou 8 chars). */
|
|
1601
|
+
function shortId(id) {
|
|
1602
|
+
return id.length > 8 ? id.slice(0, 8) : id;
|
|
1603
|
+
}
|
|
1604
|
+
/** Extrait le trace-id (2ᵉ segment) d'un `traceparent` W3C, raccourci. */
|
|
1605
|
+
function traceId(p) {
|
|
1606
|
+
if (!p.traceparent) return "—";
|
|
1607
|
+
const seg = p.traceparent.split("-");
|
|
1608
|
+
const tid = seg.length >= 2 ? seg[1] : p.traceparent;
|
|
1609
|
+
return tid && tid.length > 12 ? tid.slice(0, 12) + "…" : tid ?? "—";
|
|
1610
|
+
}
|
|
1611
|
+
/** Mappe un nom d'environnement vers une classe de couleur du badge. */
|
|
1612
|
+
function envClass(env) {
|
|
1613
|
+
const e = env.toLowerCase();
|
|
1614
|
+
if (e.startsWith("prod")) return "prod";
|
|
1615
|
+
if (e.startsWith("dev")) return "dev";
|
|
1616
|
+
if (e.startsWith("test")) return "test";
|
|
1617
|
+
if (e.startsWith("stag")) return "staging";
|
|
1618
|
+
return "";
|
|
1619
|
+
}
|
|
1620
|
+
function escapeHtml(s) {
|
|
1621
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1622
|
+
}
|
|
1623
|
+
//#endregion
|
|
1624
|
+
export { DebugBar, DebugBar as default };
|