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
package/bin/nodefony
CHANGED
|
@@ -1,87 +1,2185 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
throw e;
|
|
36
|
-
}
|
|
37
|
-
error.push(e);
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
return require("nodefony");
|
|
41
|
-
} catch (e) {
|
|
42
|
-
if (e && e.name && e.name === "nodefonyError") {
|
|
43
|
-
throw e;
|
|
44
|
-
}
|
|
45
|
-
error.push(e);
|
|
46
|
-
}
|
|
47
|
-
try {
|
|
48
|
-
return require(path.resolve(__dirname, ".."));
|
|
49
|
-
} catch (e) {
|
|
50
|
-
if (e && e.name && e.name === "nodefonyError") {
|
|
51
|
-
throw e;
|
|
52
|
-
}
|
|
53
|
-
error.push(e);
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
const globalPath = path.resolve(process.argv[1], '..', '..', 'lib', 'node_modules');
|
|
57
|
-
return require(path.resolve(globalPath, "nodefony"));
|
|
58
|
-
} catch (e) {
|
|
59
|
-
error.push(e);
|
|
60
|
-
console.trace(error);
|
|
61
|
-
throw new Error("Module nodefony not found try npm -g install nodefony");
|
|
62
|
-
}
|
|
63
|
-
}();
|
|
64
|
-
|
|
65
|
-
const isElectronDev = function () {
|
|
66
|
-
return process.mainModule.filename.indexOf('app.asar') === -1;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
if (nodefony.isElectron) {
|
|
70
|
-
if (!isElectronDev()) {
|
|
71
|
-
process.chdir(nodefony.isElectron.app.getAppPath());
|
|
72
|
-
}
|
|
73
|
-
nodefony.isElectron.app.on('ready', () => {
|
|
74
|
-
try {
|
|
75
|
-
return new nodefony.cliStart();
|
|
76
|
-
} catch (e) {
|
|
77
|
-
throw e;
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
module.exports = nodefony.isElectron;
|
|
81
|
-
} else {
|
|
82
|
-
try {
|
|
83
|
-
module.exports = new nodefony.cliStart();
|
|
84
|
-
} catch (e) {
|
|
85
|
-
throw e;
|
|
86
|
-
}
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
+
import { exit } from "node:process";
|
|
5
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
6
|
+
import { inspect, styleText } from "node:util";
|
|
7
|
+
import { EventEmitter } from "node:events";
|
|
8
|
+
//#region src/cli/projectRoot.ts
|
|
9
|
+
/**
|
|
10
|
+
* Racine du PROJET Nodefony courant (app générée / app utilisateur) : remonte
|
|
11
|
+
* depuis `from` jusqu'au premier dossier portant `nodefony.config.ts` +
|
|
12
|
+
* `package.json`.
|
|
13
|
+
*
|
|
14
|
+
* Deux consommateurs, une seule définition de « où commence l'app » :
|
|
15
|
+
* - les scaffolds IN-PROJECT (`create controller|module|entity`) — par
|
|
16
|
+
* opposition à `create app` qui crée un dossier neuf ;
|
|
17
|
+
* - le **lanceur** (`bin/nodefony`), qui délègue au CLI de l'app quand il en
|
|
18
|
+
* trouve un (cf `../bin/resolveLocalCli`).
|
|
19
|
+
*
|
|
20
|
+
* Vit ici (module sans dépendance, `node:fs`/`node:path` seuls) et pas dans
|
|
21
|
+
* `scaffold/engine.ts` : le bundle du binaire importerait alors `eta` et tout le
|
|
22
|
+
* moteur de templates, payés à CHAQUE invocation du CLI.
|
|
23
|
+
*
|
|
24
|
+
* @param from - dossier de départ (typiquement `process.cwd()`).
|
|
25
|
+
* @returns racine absolue, ou `null` hors projet.
|
|
26
|
+
*/
|
|
27
|
+
function findProjectRoot(from) {
|
|
28
|
+
let dir = path.resolve(from);
|
|
29
|
+
for (;;) {
|
|
30
|
+
if (existsSync(path.join(dir, "nodefony.config.ts")) && existsSync(path.join(dir, "package.json"))) return dir;
|
|
31
|
+
const parent = path.dirname(dir);
|
|
32
|
+
if (parent === dir) return null;
|
|
33
|
+
dir = parent;
|
|
34
|
+
}
|
|
87
35
|
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/config/reservedEnv.ts
|
|
38
|
+
/**
|
|
39
|
+
* Le catalogue des variables réservées, indexé par nom.
|
|
40
|
+
*
|
|
41
|
+
* Ajouter une entrée ici est OBLIGATOIRE dès qu'un code du framework écrit une
|
|
42
|
+
* `NF_*` dans l'environnement d'un process : sans elle, la variable ressort en
|
|
43
|
+
* « inconnue » chez tout utilisateur qui lance la commande au mauvais moment.
|
|
44
|
+
*/
|
|
45
|
+
const RESERVED_ENV = Object.freeze({
|
|
46
|
+
NF_CLI_DELEGATED: {
|
|
47
|
+
name: "NF_CLI_DELEGATED",
|
|
48
|
+
role: "posée par le lanceur du CLI quand il passe la main au `nodefony` du projet (garde anti-boucle)"
|
|
49
|
+
},
|
|
50
|
+
NF_CLI_DEBUG: {
|
|
51
|
+
name: "NF_CLI_DEBUG",
|
|
52
|
+
role: "trace la décision du lanceur du CLI sur la sortie d'erreur"
|
|
53
|
+
},
|
|
54
|
+
NF_MODE_START: {
|
|
55
|
+
name: "NF_MODE_START",
|
|
56
|
+
role: "posée par la commande de démarrage — le mode par lequel l'application a été lancée"
|
|
57
|
+
},
|
|
58
|
+
NF_CLUSTER: {
|
|
59
|
+
name: "NF_CLUSTER",
|
|
60
|
+
role: "posée par le maître de grappe dans chaque worker"
|
|
61
|
+
},
|
|
62
|
+
NF_MCP_TOKEN: {
|
|
63
|
+
name: "NF_MCP_TOKEN",
|
|
64
|
+
role: "jeton d'accès au serveur MCP de l'application, lu par le client de l'agent (`nodefony ai:mcp --auth`)"
|
|
65
|
+
},
|
|
66
|
+
NF_ENV: {
|
|
67
|
+
name: "NF_ENV",
|
|
68
|
+
role: "environnement de déploiement quand il diffère du mode runtime (`APP_ENV` gagne)"
|
|
69
|
+
},
|
|
70
|
+
NF_START: {
|
|
71
|
+
name: "NF_START",
|
|
72
|
+
role: "point d'entrée que le Kernel démarre, quand il ne doit pas être celui du projet"
|
|
73
|
+
},
|
|
74
|
+
NF_WORKERS: {
|
|
75
|
+
name: "NF_WORKERS",
|
|
76
|
+
role: "nombre de workers de la grappe (`nodefony cluster -w N`, en variable)"
|
|
77
|
+
},
|
|
78
|
+
NF_CLUSTER_PROBE: {
|
|
79
|
+
name: "NF_CLUSTER_PROBE",
|
|
80
|
+
role: "coupe la sonde du maître de grappe quand elle vaut `0`"
|
|
81
|
+
},
|
|
82
|
+
NF_POD_NAME: {
|
|
83
|
+
name: "NF_POD_NAME",
|
|
84
|
+
role: "nom du pod, dont se dérive l'identité d'origine du backplane temps réel"
|
|
85
|
+
},
|
|
86
|
+
NF_INSTANCE_ID: {
|
|
87
|
+
name: "NF_INSTANCE_ID",
|
|
88
|
+
role: "identifiant d'instance rendu par le plan d'administration (défaut : le pid)"
|
|
89
|
+
},
|
|
90
|
+
NF_DEV_CHILD: {
|
|
91
|
+
name: "NF_DEV_CHILD",
|
|
92
|
+
role: "posée par le superviseur de développement dans l'application qu'il relance"
|
|
93
|
+
},
|
|
94
|
+
NF_DEV_PORTS: {
|
|
95
|
+
name: "NF_DEV_PORTS",
|
|
96
|
+
role: "ports que le superviseur de développement doit libérer, imposés par l'opérateur"
|
|
97
|
+
},
|
|
98
|
+
NF_BOOT_TIMEOUT_MS: {
|
|
99
|
+
name: "NF_BOOT_TIMEOUT_MS",
|
|
100
|
+
role: "délai au-delà duquel un démarrage est déclaré perdu"
|
|
101
|
+
},
|
|
102
|
+
NF_BOOT_WARN_MS: {
|
|
103
|
+
name: "NF_BOOT_WARN_MS",
|
|
104
|
+
role: "délai au-delà duquel un démarrage lent est signalé"
|
|
105
|
+
},
|
|
106
|
+
NF_KERNEL_TRACE_FILE: {
|
|
107
|
+
name: "NF_KERNEL_TRACE_FILE",
|
|
108
|
+
role: "fichier où le Kernel écrit sa trace de démarrage (diagnostic)"
|
|
109
|
+
},
|
|
110
|
+
NF_NO_TTY: {
|
|
111
|
+
name: "NF_NO_TTY",
|
|
112
|
+
role: "force le rendu non interactif, quel que soit le terminal"
|
|
113
|
+
},
|
|
114
|
+
NF_PERF_PROBE: {
|
|
115
|
+
name: "NF_PERF_PROBE",
|
|
116
|
+
role: "arme la sonde de performance du pipeline HTTP"
|
|
117
|
+
},
|
|
118
|
+
NF_ORM_FLOW: {
|
|
119
|
+
name: "NF_ORM_FLOW",
|
|
120
|
+
role: "arme la sonde de flux de l'ORM"
|
|
121
|
+
},
|
|
122
|
+
NF_ORM_HEARTBEAT_MS: {
|
|
123
|
+
name: "NF_ORM_HEARTBEAT_MS",
|
|
124
|
+
role: "période du battement de cœur qui surveille les connecteurs de l'ORM"
|
|
125
|
+
},
|
|
126
|
+
NF_REALTIME_DRIVER: {
|
|
127
|
+
name: "NF_REALTIME_DRIVER",
|
|
128
|
+
role: "pilote du backplane temps réel (mémoire, Redis…)"
|
|
129
|
+
},
|
|
130
|
+
NF_REALTIME_BACKPLANE_SECRET: {
|
|
131
|
+
name: "NF_REALTIME_BACKPLANE_SECRET",
|
|
132
|
+
role: "secret qui scelle les enveloppes du backplane temps réel"
|
|
133
|
+
},
|
|
134
|
+
NF_REALTIME_BACKPLANE_NAMESPACE: {
|
|
135
|
+
name: "NF_REALTIME_BACKPLANE_NAMESPACE",
|
|
136
|
+
role: "espace de noms du backplane — ce qui cloisonne deux applications sur un même bus"
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/bin/resolveLocalCli.ts
|
|
141
|
+
/** Variable de garde : le CLI délégué ne délègue pas à son tour (anti-boucle). */
|
|
142
|
+
const DELEGATED_ENV = RESERVED_ENV.NF_CLI_DELEGATED.name;
|
|
143
|
+
/** Trace la décision du lanceur sur stderr quand la variable vaut `1`. */
|
|
144
|
+
const DEBUG_ENV = RESERVED_ENV.NF_CLI_DEBUG.name;
|
|
145
|
+
/** Lit un `package.json` — `null` si absent ou illisible (jamais de throw). */
|
|
146
|
+
function readPackageJson(dir) {
|
|
147
|
+
try {
|
|
148
|
+
return JSON.parse(readFileSync(path.join(dir, "package.json"), "utf8"));
|
|
149
|
+
} catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/** Chemin déclaré par le champ `bin` d'un package.json (forme string ou map). */
|
|
154
|
+
function binEntry(pkg) {
|
|
155
|
+
const bin = pkg.bin;
|
|
156
|
+
if (typeof bin === "string") return bin;
|
|
157
|
+
if (bin && typeof bin === "object") {
|
|
158
|
+
const entry = bin.nodefony;
|
|
159
|
+
if (typeof entry === "string") return entry;
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
/** `realpath` tolérant — retombe sur le chemin brut si la cible n'existe pas. */
|
|
164
|
+
function realOrSelf(p) {
|
|
165
|
+
try {
|
|
166
|
+
return realpathSync(p);
|
|
167
|
+
} catch {
|
|
168
|
+
return p;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Décide quel CLI Nodefony doit réellement s'exécuter : **celui de l'application**
|
|
173
|
+
* dès qu'on se trouve dans un projet, sinon celui qu'on a lancé.
|
|
174
|
+
*
|
|
175
|
+
* Pourquoi cette règle : le binaire installé en global (`npm i -g nodefony`) est
|
|
176
|
+
* la porte d'entrée du framework (c'est lui qui fait `create app`), mais sa version
|
|
177
|
+
* dérive de celle des applications déjà générées. Exécuter le CLI global **dans**
|
|
178
|
+
* une app reviendrait à piloter cette app avec un autre framework que celui de ses
|
|
179
|
+
* `node_modules` : configs, scaffolds et commandes de module peuvent diverger.
|
|
180
|
+
* La version qui fait autorité est donc toujours celle de l'application — comme le
|
|
181
|
+
* wrapper d'un projet (`gradlew`, `mvnw`) prime sur l'outil de la machine.
|
|
182
|
+
*
|
|
183
|
+
* Fonction PURE (aucun effet de bord, aucun `process`) : les entrées sont passées
|
|
184
|
+
* explicitement pour que la décision soit testable sans lancer de binaire.
|
|
185
|
+
*
|
|
186
|
+
* @param input.cwd - dossier courant, point de départ de la recherche du projet.
|
|
187
|
+
* @param input.selfDir - racine du paquet `nodefony` en train de s'exécuter.
|
|
188
|
+
* @param input.env - environnement (lu pour la garde anti-boucle).
|
|
189
|
+
* @returns la décision : `delegate` = chemin du binaire à charger, ou `null` pour soi.
|
|
190
|
+
*/
|
|
191
|
+
function resolveLocalCli(input) {
|
|
192
|
+
if ((input.env ?? {})[DELEGATED_ENV]) return {
|
|
193
|
+
delegate: null,
|
|
194
|
+
reason: "already-delegated"
|
|
195
|
+
};
|
|
196
|
+
const projectRoot = findProjectRoot(input.cwd);
|
|
197
|
+
if (!projectRoot) return {
|
|
198
|
+
delegate: null,
|
|
199
|
+
reason: "no-project"
|
|
200
|
+
};
|
|
201
|
+
const localPkgDir = path.join(projectRoot, "node_modules", "nodefony");
|
|
202
|
+
const localPkg = existsSync(localPkgDir) ? readPackageJson(localPkgDir) : null;
|
|
203
|
+
if (!localPkg) return {
|
|
204
|
+
delegate: null,
|
|
205
|
+
reason: "no-local-cli",
|
|
206
|
+
detail: `${localPkgDir} absent`
|
|
207
|
+
};
|
|
208
|
+
if (realOrSelf(localPkgDir) === realOrSelf(input.selfDir)) return {
|
|
209
|
+
delegate: null,
|
|
210
|
+
reason: "same-package"
|
|
211
|
+
};
|
|
212
|
+
const rel = binEntry(localPkg);
|
|
213
|
+
if (!rel) return {
|
|
214
|
+
delegate: null,
|
|
215
|
+
reason: "local-cli-broken",
|
|
216
|
+
projectRoot,
|
|
217
|
+
detail: `le paquet nodefony de ${projectRoot} ne déclare aucun binaire (champ "bin")`
|
|
218
|
+
};
|
|
219
|
+
const localBin = path.resolve(localPkgDir, rel);
|
|
220
|
+
if (!existsSync(localBin)) return {
|
|
221
|
+
delegate: null,
|
|
222
|
+
reason: "local-cli-broken",
|
|
223
|
+
projectRoot,
|
|
224
|
+
detail: `le CLI du projet est déclaré mais absent : ${localBin} (paquet non construit ? \`npm install\` / \`npm run build\`)`
|
|
225
|
+
};
|
|
226
|
+
const version = (pkg) => typeof pkg?.version === "string" ? pkg.version : null;
|
|
227
|
+
return {
|
|
228
|
+
delegate: localBin,
|
|
229
|
+
reason: "local-cli",
|
|
230
|
+
projectRoot,
|
|
231
|
+
selfVersion: version(readPackageJson(input.selfDir)),
|
|
232
|
+
localVersion: version(localPkg)
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
//#endregion
|
|
236
|
+
//#region src/colors.ts
|
|
237
|
+
const VALID = /* @__PURE__ */ new Set([
|
|
238
|
+
"reset",
|
|
239
|
+
"bold",
|
|
240
|
+
"dim",
|
|
241
|
+
"italic",
|
|
242
|
+
"underline",
|
|
243
|
+
"inverse",
|
|
244
|
+
"strikethrough",
|
|
245
|
+
"black",
|
|
246
|
+
"red",
|
|
247
|
+
"green",
|
|
248
|
+
"yellow",
|
|
249
|
+
"blue",
|
|
250
|
+
"magenta",
|
|
251
|
+
"cyan",
|
|
252
|
+
"white",
|
|
253
|
+
"gray",
|
|
254
|
+
"blackBright",
|
|
255
|
+
"redBright",
|
|
256
|
+
"greenBright",
|
|
257
|
+
"yellowBright",
|
|
258
|
+
"blueBright",
|
|
259
|
+
"magentaBright",
|
|
260
|
+
"cyanBright",
|
|
261
|
+
"whiteBright",
|
|
262
|
+
"bgBlack",
|
|
263
|
+
"bgRed",
|
|
264
|
+
"bgGreen",
|
|
265
|
+
"bgYellow",
|
|
266
|
+
"bgBlue",
|
|
267
|
+
"bgMagenta",
|
|
268
|
+
"bgCyan",
|
|
269
|
+
"bgWhite",
|
|
270
|
+
"bgGray"
|
|
271
|
+
]);
|
|
272
|
+
/** Séquence ANSI de remise à zéro — exposée brute par `clc.reset` (parité cli-color). */
|
|
273
|
+
const RESET = "\x1B[0m";
|
|
274
|
+
/**
|
|
275
|
+
* Construit une `ColorFn` figée pour la liste de styles donnée. Le Proxy ne
|
|
276
|
+
* piège QUE l'accès de propriété (chaînage) — l'appel forward directement vers
|
|
277
|
+
* la fonction cible (aucun surcoût de trap à l'invocation, hot path préservé).
|
|
278
|
+
*/
|
|
279
|
+
function make(styles) {
|
|
280
|
+
const apply = (s) => {
|
|
281
|
+
const str = String(s);
|
|
282
|
+
if (styles.length === 0) return str;
|
|
283
|
+
try {
|
|
284
|
+
return styleText(styles, str, { validateStream: false });
|
|
285
|
+
} catch {
|
|
286
|
+
return str;
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
return new Proxy(apply, { get(target, prop, receiver) {
|
|
290
|
+
if (prop === "reset") return RESET;
|
|
291
|
+
if (typeof prop === "string" && VALID.has(prop)) return make([...styles, prop]);
|
|
292
|
+
return Reflect.get(target, prop, receiver);
|
|
293
|
+
} });
|
|
294
|
+
}
|
|
295
|
+
const clc = make([]);
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/kernel/checks/report.ts
|
|
298
|
+
/**
|
|
299
|
+
* L'ordre de lecture des familles — celui du sommaire ET du détail.
|
|
300
|
+
*
|
|
301
|
+
* L'ordre n'est pas cosmétique : la fraîcheur d'abord, parce qu'un build en
|
|
302
|
+
* retard rend faux tout ce qui suit ; puis ce qui empêche de démarrer, qui
|
|
303
|
+
* explique souvent le reste.
|
|
304
|
+
*/
|
|
305
|
+
const FAMILIES = [
|
|
306
|
+
"freshness",
|
|
307
|
+
"readiness",
|
|
308
|
+
"envCatalog",
|
|
309
|
+
"envTracked",
|
|
310
|
+
"deps",
|
|
311
|
+
"wiring",
|
|
312
|
+
"surface",
|
|
313
|
+
"dialect",
|
|
314
|
+
"guards",
|
|
315
|
+
"migrations",
|
|
316
|
+
"firewall",
|
|
317
|
+
"gating",
|
|
318
|
+
"verify",
|
|
319
|
+
"outdated"
|
|
320
|
+
];
|
|
321
|
+
/**
|
|
322
|
+
* Les SOUS-RÈGLES de `readiness` — des contrôles à part entière, mais qui ne
|
|
323
|
+
* sont pas des familles.
|
|
324
|
+
*
|
|
325
|
+
* Elles ont besoin de leur propre état d'exécution (leur silence peut ne rien
|
|
326
|
+
* prouver : catalogue illisible, pas de dépôt git), sans quoi elles seraient
|
|
327
|
+
* affichées en vert alors qu'elles n'ont rien regardé. Mais les compter comme
|
|
328
|
+
* familles gonflerait le bilan de contrôles que le sommaire n'affiche pas.
|
|
329
|
+
*
|
|
330
|
+
* Une seule liste, dont TOUT le reste se dérive : quand la deuxième sous-règle
|
|
331
|
+
* est arrivée, la condition `f !== "envCatalog"` était écrite en dur à trois
|
|
332
|
+
* endroits — le compteur du bilan, le filtre du sommaire, et le dédoublonnage
|
|
333
|
+
* des contrôles sautés.
|
|
334
|
+
*/
|
|
335
|
+
const SUBRULES = ["envCatalog", "envTracked"];
|
|
336
|
+
/** `true` si cette famille est une sous-règle de `readiness`. */
|
|
337
|
+
function isSubrule(family) {
|
|
338
|
+
return SUBRULES.includes(family);
|
|
339
|
+
}
|
|
340
|
+
FAMILIES.filter((f) => !isSubrule(f));
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/Tools.ts
|
|
343
|
+
const ObjProto = Object.prototype;
|
|
344
|
+
const _toString = ObjProto.toString;
|
|
345
|
+
const hasOwn = ObjProto.hasOwnProperty;
|
|
346
|
+
const fnToString = hasOwn.toString;
|
|
347
|
+
const ObjectFunctionString = fnToString.call(Object);
|
|
348
|
+
const getProto = Object.getPrototypeOf;
|
|
349
|
+
/** Alias direct de `Array.isArray` — exporté pour usage cohérent dans les modules. */
|
|
350
|
+
const isArray = Array.isArray;
|
|
351
|
+
/**
|
|
352
|
+
* Vérifie qu'un objet est un "plain object" — `{}` ou `Object.create(null)`.
|
|
353
|
+
*
|
|
354
|
+
* Rejette les instances de classes, les `Array`, `Date`, `RegExp`, etc.
|
|
355
|
+
* Implémentation alignée sur jQuery.isPlainObject (compatible cross-realm).
|
|
356
|
+
*
|
|
357
|
+
* @param obj - valeur à tester.
|
|
358
|
+
* @returns `true` si l'objet vient directement de `Object` ou n'a pas de prototype.
|
|
359
|
+
*/
|
|
360
|
+
const isPlainObject = (obj) => {
|
|
361
|
+
if (!obj || _toString.call(obj) !== "[object Object]") return false;
|
|
362
|
+
const proto = getProto(obj);
|
|
363
|
+
if (!proto) return true;
|
|
364
|
+
const Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
|
|
365
|
+
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
|
|
366
|
+
};
|
|
367
|
+
/**
|
|
368
|
+
* Fusionne plusieurs objets dans une cible — API compatible `jQuery.extend`.
|
|
369
|
+
*
|
|
370
|
+
* Mode `shallow` (défaut) : copie les clés du dernier au premier source.
|
|
371
|
+
* Mode `deep` (1er arg `true`) : récurse dans les plain objects et arrays.
|
|
372
|
+
* Sécurité : ignore `__proto__`, `constructor`, `prototype` (anti prototype pollution).
|
|
373
|
+
*
|
|
374
|
+
* @param args - `[target, ...sources]` ou `[true, target, ...sources]` pour deep.
|
|
375
|
+
* @returns la cible mutée (ou objet vide si appel à un seul argument).
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* ```ts
|
|
379
|
+
* extend({ a: 1 }, { b: 2 }); // { a: 1, b: 2 }
|
|
380
|
+
* extend(true, { a: { x: 1 } }, { a: { y: 2 } }); // { a: { x: 1, y: 2 } }
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
const extend = (...args) => {
|
|
384
|
+
let options, name, src, copy, copyIsArray = false, clone, target = args[0] || {}, i = 1, deep = false;
|
|
385
|
+
const { length } = args;
|
|
386
|
+
if (typeof target === "boolean") {
|
|
387
|
+
deep = target;
|
|
388
|
+
target = args[i] || {};
|
|
389
|
+
i++;
|
|
390
|
+
}
|
|
391
|
+
if (typeof target !== "object" && typeof target !== "function") target = {};
|
|
392
|
+
if (i === length) {
|
|
393
|
+
target = {};
|
|
394
|
+
i--;
|
|
395
|
+
}
|
|
396
|
+
for (; i < length; i++) if ((options = args[i]) != null) for (name in options) {
|
|
397
|
+
if (!hasOwn.call(options, name)) continue;
|
|
398
|
+
copy = options[name];
|
|
399
|
+
if (name === "__proto__" || name === "constructor" || name === "prototype" || target === copy) continue;
|
|
400
|
+
if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
|
|
401
|
+
src = target[name];
|
|
402
|
+
if (copyIsArray && !isArray(src)) clone = [];
|
|
403
|
+
else if (!copyIsArray && !isPlainObject(src)) clone = {};
|
|
404
|
+
else clone = src;
|
|
405
|
+
copyIsArray = false;
|
|
406
|
+
target[name] = extend(deep, clone, copy);
|
|
407
|
+
} else if (copy !== void 0) target[name] = copy;
|
|
408
|
+
}
|
|
409
|
+
return target;
|
|
410
|
+
};
|
|
411
|
+
globalThis.Buffer;
|
|
412
|
+
//#endregion
|
|
413
|
+
//#region src/Event.ts
|
|
414
|
+
const regListenOn = /^on(.*)$/;
|
|
415
|
+
/** Sentinelle de rejet interne au timeout d'{@link Event.emitAsyncGuarded} (jamais exposée). */
|
|
416
|
+
const timeoutSentinel = Symbol("nodefony.emitAsyncGuarded.timeout");
|
|
417
|
+
/**
|
|
418
|
+
* Bus d'événements Nodefony — extension de Node.js {@link EventEmitter} avec
|
|
419
|
+
* deux ajouts maison : `emitAsync` (await tous les listeners en séquence) et
|
|
420
|
+
* `settingsToListen` (mapping config → listeners via convention `onXxx`).
|
|
421
|
+
*
|
|
422
|
+
* Utilisé par {@link Service} comme `notificationsCenter`. Une seule instance
|
|
423
|
+
* peut être partagée entre plusieurs services — chaque service track ses
|
|
424
|
+
* propres listeners pour les retirer proprement à `clean()`.
|
|
425
|
+
*
|
|
426
|
+
* @example Bus dédié
|
|
427
|
+
* ```ts
|
|
428
|
+
* const bus = new Event({ onReady: () => console.log("ready!") }, this);
|
|
429
|
+
* bus.fire("onReady");
|
|
430
|
+
* ```
|
|
431
|
+
*
|
|
432
|
+
* @example Bus partagé entre services
|
|
433
|
+
* ```ts
|
|
434
|
+
* const sharedBus = new Event();
|
|
435
|
+
* new ServiceA(name, container, sharedBus);
|
|
436
|
+
* new ServiceB(name, container, sharedBus);
|
|
437
|
+
* ```
|
|
438
|
+
*/
|
|
439
|
+
var Event = class extends EventEmitter {
|
|
440
|
+
/**
|
|
441
|
+
* @param settings - objet de config dont les clés `onXxx` sont auto-bindées
|
|
442
|
+
* comme listeners (via {@link settingsToListen}).
|
|
443
|
+
* @param context - `this` à bind sur les listeners auto-enregistrés.
|
|
444
|
+
* @param options - `nbListeners` surcharge la limite d'abonnés de Node.js ;
|
|
445
|
+
* absent, c'est celle de Node qui s'applique (10), et le dépassement
|
|
446
|
+
* signale une fuite probable. La valeur `0` vaut **illimité**, comme dans
|
|
447
|
+
* `setMaxListeners` — un bus dont on SAIT qu'il portera beaucoup d'abonnés
|
|
448
|
+
* se déclare ainsi, au lieu de subir un avertissement qui n'annonce rien.
|
|
449
|
+
*/
|
|
450
|
+
constructor(settings, context, options) {
|
|
451
|
+
super();
|
|
452
|
+
if (options?.nbListeners !== void 0) this.setMaxListeners(options.nbListeners);
|
|
453
|
+
if (settings) this.settingsToListen(settings, context);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Parcourt `localSettings` et enregistre chaque clé matchant `/^on(.*)$/`
|
|
457
|
+
* comme listener — convention héritée des composants WebComponent / config
|
|
458
|
+
* Nodefony historique. Utile pour wirer des hooks via config plate.
|
|
459
|
+
*
|
|
460
|
+
* @param localSettings - objet plat ; les clés `onReady`, `onClose`, etc.
|
|
461
|
+
* sont prises comme noms d'événements ET comme listeners.
|
|
462
|
+
* @param context - si fourni, le listener est bindé sur ce contexte.
|
|
463
|
+
*/
|
|
464
|
+
settingsToListen(localSettings, context) {
|
|
465
|
+
for (const i of Object.keys(localSettings)) {
|
|
466
|
+
const res = regListenOn.exec(i);
|
|
467
|
+
if (!res) continue;
|
|
468
|
+
if (context) {
|
|
469
|
+
this.listen(context, res[0], localSettings[i]);
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
this.on(res[0], localSettings[i]);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Bind `listener` sur `context` puis l'enregistre. Renvoie une fonction
|
|
477
|
+
* dispatcher qui ré-émet l'événement avec ses propres args (façon trigger).
|
|
478
|
+
*
|
|
479
|
+
* @returns dispatcher `(...args) => this.emit(eventName, ...args)` — pratique
|
|
480
|
+
* pour exposer un trigger sans donner accès au bus complet.
|
|
481
|
+
*/
|
|
482
|
+
listen(context, eventName, listener) {
|
|
483
|
+
if (typeof listener === "function") this.addListener(eventName, listener.bind(context));
|
|
484
|
+
return (...args) => this.emit(eventName, ...args);
|
|
485
|
+
}
|
|
486
|
+
/** Alias `emit` — émission synchrone (API EventEmitter standard). */
|
|
487
|
+
fire(eventName, ...args) {
|
|
488
|
+
return super.emit(eventName, ...args);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Émet et attend chaque listener en séquence (`await Reflect.apply` un par
|
|
492
|
+
* un). Différent de `emit` qui appelle synchroniquement sans attendre les
|
|
493
|
+
* Promises retournées.
|
|
494
|
+
*
|
|
495
|
+
* @returns tableau des valeurs résolues par chaque listener (ordre d'append),
|
|
496
|
+
* ou `false` si aucun listener n'est attaché.
|
|
497
|
+
* @remarks Séquentiel par design — si tu veux Promise.all, fais un wrapper
|
|
498
|
+
* au-dessus. La séquence garantit l'ordre prévisible des side-effects.
|
|
499
|
+
*/
|
|
500
|
+
async emitAsync(eventName, ...args) {
|
|
501
|
+
if (this.listenerCount(eventName) === 0) return false;
|
|
502
|
+
const handlers = this.rawListeners(eventName);
|
|
503
|
+
const result = [];
|
|
504
|
+
for (const handler of handlers) {
|
|
505
|
+
const r = Reflect.apply(handler, this, args);
|
|
506
|
+
result.push(r != null && typeof r.then === "function" ? await r : r);
|
|
507
|
+
}
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
/** Alias `emitAsync`. */
|
|
511
|
+
async fireAsync(eventName, ...args) {
|
|
512
|
+
return this.emitAsync(eventName, ...args);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Variante **gardée** de {@link emitAsync} : émet les listeners en SÉRIE (ordre
|
|
516
|
+
* préservé) mais isole chacun par un `try/catch` + un `timeout` optionnel, et
|
|
517
|
+
* COLLECTE les échecs au lieu de laisser le premier rejet faire sauter les
|
|
518
|
+
* suivants (ou un listener figé geler tout le reste).
|
|
519
|
+
*
|
|
520
|
+
* Ne décide d'AUCUNE politique (log, criticité, propagation) : c'est l'appelant
|
|
521
|
+
* qui tranche via `onListenerError` (continuer / arrêter) et `onListenerSlow`.
|
|
522
|
+
* Cette séparation MÉCANIQUE / POLITIQUE permet de réutiliser la garde hors boot
|
|
523
|
+
* en toute connaissance de cause.
|
|
524
|
+
*
|
|
525
|
+
* 🚨 **Coût** : quand `timeoutMs > 0`, 1 timer + 1 Promise de course PAR listener.
|
|
526
|
+
* Réservé au **boot / lifecycle / jobs** (cf `Kernel.fireLifecycle`) — appelé
|
|
527
|
+
* ≪ 1×/process. **JAMAIS dans le hot path HTTP/WS** : celui-ci garde `emitAsync`
|
|
528
|
+
* nu (aucun timer, aucune alloc par requête).
|
|
529
|
+
*
|
|
530
|
+
* @param eventName - événement à émettre.
|
|
531
|
+
* @param options - garde (timeout/seuil de lenteur) + callbacks de politique.
|
|
532
|
+
* @param args - arguments passés à chaque listener.
|
|
533
|
+
* @returns `{ results, errors, stopped }` (cf {@link IGuardedEmitResult}).
|
|
534
|
+
*/
|
|
535
|
+
async emitAsyncGuarded(eventName, options = {}, ...args) {
|
|
536
|
+
const results = [];
|
|
537
|
+
const errors = [];
|
|
538
|
+
if (this.listenerCount(eventName) === 0) return {
|
|
539
|
+
results,
|
|
540
|
+
errors,
|
|
541
|
+
stopped: false
|
|
542
|
+
};
|
|
543
|
+
const handlers = this.rawListeners(eventName);
|
|
544
|
+
const timeoutOption = options.timeoutMs ?? 0;
|
|
545
|
+
const perListener = typeof timeoutOption === "function";
|
|
546
|
+
const warnMs = options.warnMs ?? 0;
|
|
547
|
+
const measure = warnMs > 0;
|
|
548
|
+
for (let index = 0; index < handlers.length; index += 1) {
|
|
549
|
+
const handler = handlers[index];
|
|
550
|
+
const timeoutMs = perListener ? timeoutOption(handler, index) : timeoutOption;
|
|
551
|
+
const startedAt = measure ? Date.now() : 0;
|
|
552
|
+
let timedOut = false;
|
|
553
|
+
try {
|
|
554
|
+
const call = Promise.resolve(Reflect.apply(handler, this, args));
|
|
555
|
+
let value;
|
|
556
|
+
if (timeoutMs > 0) {
|
|
557
|
+
call.catch(() => {});
|
|
558
|
+
let timer;
|
|
559
|
+
try {
|
|
560
|
+
value = await Promise.race([call, new Promise((_, reject) => {
|
|
561
|
+
timer = setTimeout(() => {
|
|
562
|
+
timedOut = true;
|
|
563
|
+
reject(timeoutSentinel);
|
|
564
|
+
}, timeoutMs);
|
|
565
|
+
timer.unref?.();
|
|
566
|
+
})]);
|
|
567
|
+
} finally {
|
|
568
|
+
if (timer) clearTimeout(timer);
|
|
569
|
+
}
|
|
570
|
+
} else value = await call;
|
|
571
|
+
results.push(value);
|
|
572
|
+
if (measure && options.onListenerSlow) {
|
|
573
|
+
const durationMs = Date.now() - startedAt;
|
|
574
|
+
if (durationMs >= warnMs) options.onListenerSlow({
|
|
575
|
+
index,
|
|
576
|
+
listener: handler,
|
|
577
|
+
timedOut: false,
|
|
578
|
+
durationMs
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
} catch (caught) {
|
|
582
|
+
const durationMs = measure ? Date.now() - startedAt : 0;
|
|
583
|
+
const error = timedOut ? /* @__PURE__ */ new Error(`listener timeout après ${timeoutMs}ms`) : caught;
|
|
584
|
+
errors.push({
|
|
585
|
+
index,
|
|
586
|
+
error,
|
|
587
|
+
timedOut
|
|
588
|
+
});
|
|
589
|
+
if (options.onListenerError?.(error, {
|
|
590
|
+
index,
|
|
591
|
+
listener: handler,
|
|
592
|
+
timedOut,
|
|
593
|
+
durationMs
|
|
594
|
+
}) === true) return {
|
|
595
|
+
results,
|
|
596
|
+
errors,
|
|
597
|
+
stopped: true
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return {
|
|
602
|
+
results,
|
|
603
|
+
errors,
|
|
604
|
+
stopped: false
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
//#endregion
|
|
609
|
+
//#region src/syslog/Pdu.ts
|
|
610
|
+
var SysLogSeverity = /* @__PURE__ */ function(SysLogSeverity) {
|
|
611
|
+
SysLogSeverity[SysLogSeverity["EMERGENCY"] = 0] = "EMERGENCY";
|
|
612
|
+
SysLogSeverity[SysLogSeverity["ALERT"] = 1] = "ALERT";
|
|
613
|
+
SysLogSeverity[SysLogSeverity["CRITIC"] = 2] = "CRITIC";
|
|
614
|
+
SysLogSeverity[SysLogSeverity["ERROR"] = 3] = "ERROR";
|
|
615
|
+
SysLogSeverity[SysLogSeverity["WARNING"] = 4] = "WARNING";
|
|
616
|
+
SysLogSeverity[SysLogSeverity["NOTICE"] = 5] = "NOTICE";
|
|
617
|
+
SysLogSeverity[SysLogSeverity["INFO"] = 6] = "INFO";
|
|
618
|
+
SysLogSeverity[SysLogSeverity["DEBUG"] = 7] = "DEBUG";
|
|
619
|
+
return SysLogSeverity;
|
|
620
|
+
}(SysLogSeverity || {});
|
|
621
|
+
const sysLogSeverity$1 = [
|
|
622
|
+
0,
|
|
623
|
+
1,
|
|
624
|
+
2,
|
|
625
|
+
3,
|
|
626
|
+
4,
|
|
627
|
+
5,
|
|
628
|
+
6,
|
|
629
|
+
7
|
|
630
|
+
];
|
|
631
|
+
const translateSeverity = function(severity = "INFO") {
|
|
632
|
+
if (typeof severity === "number") {
|
|
633
|
+
if (sysLogSeverity$1[severity] !== void 0) return sysLogSeverity$1[severity];
|
|
634
|
+
else throw new Error(`Not a valid nodefony syslog severity: ${severity}`);
|
|
635
|
+
} else if (SysLogSeverity[severity] !== void 0) return SysLogSeverity[severity];
|
|
636
|
+
else throw new Error(`Not a valid nodefony syslog severity: ${severity}`);
|
|
637
|
+
};
|
|
638
|
+
const sysLogSeverityObj = Object.entries(SysLogSeverity).reduce((acc, [key, value]) => {
|
|
639
|
+
acc[key] = value;
|
|
640
|
+
return acc;
|
|
641
|
+
}, {});
|
|
642
|
+
const severityNameMap = new Map(Object.entries(SysLogSeverity).filter(([, v]) => typeof v === "number").map(([k, v]) => [v, k]));
|
|
643
|
+
const _gBuffer = globalThis.Buffer;
|
|
644
|
+
const PID = globalThis.process?.pid ?? 0;
|
|
645
|
+
const fastTypeOf = (value) => {
|
|
646
|
+
if (value === null) return null;
|
|
647
|
+
const t = typeof value;
|
|
648
|
+
if (t !== "object") return t;
|
|
649
|
+
if (Array.isArray(value)) return "array";
|
|
650
|
+
if (value instanceof Date) return "date";
|
|
651
|
+
if (value instanceof RegExp) return "RegExp";
|
|
652
|
+
if (value instanceof Error) return "Error";
|
|
653
|
+
if (_gBuffer?.isBuffer(value)) return "buffer";
|
|
654
|
+
return "object";
|
|
655
|
+
};
|
|
656
|
+
/**
|
|
657
|
+
* Process Data Unit — entrée de log unitaire conforme RFC 5424.
|
|
658
|
+
*
|
|
659
|
+
* Une instance représente un événement de log dans le pipeline Syslog.
|
|
660
|
+
* Stockée dans le `CircularBuffer` (O(1)) et diffusée aux transports
|
|
661
|
+
* via l'event `onLog` du {@link Syslog}.
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```ts
|
|
665
|
+
* const pdu = new Pdu("user logged in", "INFO", "AUTH", "USER_LOGIN", "user@example.com");
|
|
666
|
+
* pdu.severity; // 6
|
|
667
|
+
* pdu.severityName; // "INFO"
|
|
668
|
+
* pdu.payload; // "user logged in"
|
|
669
|
+
* ```
|
|
670
|
+
*
|
|
671
|
+
* @remarks `pdu.severity` est numérique (RFC 5424) pour comparaisons rapides.
|
|
672
|
+
* `pdu.severityName` est la string (`"INFO"`, `"CRITIC"` — pas `"CRITICAL"`).
|
|
673
|
+
*/
|
|
674
|
+
let guid = 0;
|
|
675
|
+
var Pdu = class Pdu {
|
|
676
|
+
payload;
|
|
677
|
+
uid;
|
|
678
|
+
severity;
|
|
679
|
+
timeStamp;
|
|
680
|
+
severityName;
|
|
681
|
+
typePayload;
|
|
682
|
+
moduleName;
|
|
683
|
+
msgid;
|
|
684
|
+
msg;
|
|
685
|
+
status;
|
|
686
|
+
/** PID du process émetteur (= procid RFC 5424). Constant, capturé au chargement du module. */
|
|
687
|
+
pid;
|
|
688
|
+
/**
|
|
689
|
+
* Identifiant de la requête en cours (corrélation log↔requête).
|
|
690
|
+
*
|
|
691
|
+
* Présent UNIQUEMENT si le Pdu est créé dans une bulle `RequestContext` active
|
|
692
|
+
* (ALS Node) ET que {@link Pdu.requestIdProvider} a été branché côté Node — voir
|
|
693
|
+
* `src/index.ts` (barrel Node uniquement, isomorphisme préservé : le bundle
|
|
694
|
+
* client/browser ne branche pas, le provider reste `null` → 0 alloc, 0 lecture).
|
|
695
|
+
*
|
|
696
|
+
* Combiné à `pid` (procid RFC 5424), permet la corrélation **complète** :
|
|
697
|
+
* `pid` = quel worker, `requestId` = quelle requête. Voyage dans ring buffer +
|
|
698
|
+
* `nodefony:syslog` + transports JSON (champ public sérialisé naturellement).
|
|
699
|
+
*/
|
|
700
|
+
requestId;
|
|
701
|
+
/**
|
|
702
|
+
* Provider injectable du `requestId` courant (ALS). Branché par le barrel
|
|
703
|
+
* Node (`src/index.ts`) sur `RequestContext.getRequestId`. Reste `null` côté
|
|
704
|
+
* browser/debugbar (le bundle client n'importe pas `node:async_hooks`) et
|
|
705
|
+
* pendant les phases boot pré-Kernel (cohérent : pas de requête en cours).
|
|
706
|
+
*
|
|
707
|
+
* Coût : 1 test de référence par Pdu (~5 ns) quand `null` ; ~50-100 ns quand
|
|
708
|
+
* branché (lecture ALS + accès propriété). Pas d'alloc supplémentaire si
|
|
709
|
+
* `requestId` est `undefined` (le champ reste non-défini sur l'instance).
|
|
710
|
+
*/
|
|
711
|
+
static requestIdProvider = null;
|
|
712
|
+
/**
|
|
713
|
+
* Construit un Pdu prêt à être publié dans le pipeline Syslog.
|
|
714
|
+
*
|
|
715
|
+
* @param pci - payload (string, Error, objet — typé `unknown`, narrower côté lecteur).
|
|
716
|
+
* @param severity - niveau RFC 5424 (string `"INFO"` ou numérique `6`). Défaut `"INFO"`.
|
|
717
|
+
* @param moduleName - nom du module/service qui a produit le log. Défaut `"nodefony"`.
|
|
718
|
+
* @param msgid - catégorie de message (`"AUTH"`, `"ROUTER"`, etc.). Défaut `""`.
|
|
719
|
+
* @param msg - détail libre optionnel. Défaut `""`.
|
|
720
|
+
* @param date - timestamp (number, Date, ou string parsable). Défaut `Date.now()`.
|
|
721
|
+
* @throws Si `severity` n'est pas une valeur valide de {@link SysLogSeverity}.
|
|
722
|
+
*/
|
|
723
|
+
constructor(pci, severity, moduleName = "nodefony", msgid = "", msg = "", date) {
|
|
724
|
+
if (date === void 0) this.timeStamp = Date.now();
|
|
725
|
+
else if (typeof date === "number") this.timeStamp = date;
|
|
726
|
+
else if (date instanceof Date) this.timeStamp = date.getTime();
|
|
727
|
+
else this.timeStamp = new Date(date).getTime();
|
|
728
|
+
this.uid = ++guid;
|
|
729
|
+
this.severity = translateSeverity(severity);
|
|
730
|
+
const sName = severityNameMap.get(this.severity);
|
|
731
|
+
if (sName === void 0) throw new Error(`Invalid severity value: ${this.severity}`);
|
|
732
|
+
this.severityName = sName;
|
|
733
|
+
this.typePayload = fastTypeOf(pci);
|
|
734
|
+
this.payload = pci;
|
|
735
|
+
this.moduleName = moduleName;
|
|
736
|
+
this.msgid = msgid;
|
|
737
|
+
this.msg = msg;
|
|
738
|
+
this.status = "NOTDEFINED";
|
|
739
|
+
this.pid = PID;
|
|
740
|
+
this.requestId = Pdu.requestIdProvider !== null ? Pdu.requestIdProvider() : void 0;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Map bidirectionnelle des sévérités RFC 5424 (`{ INFO: 6, 6: "INFO", ... }`).
|
|
744
|
+
*
|
|
745
|
+
* @returns dictionnaire `{ severityName: severityValue }` plus enum reverse.
|
|
746
|
+
*/
|
|
747
|
+
static sysLogSeverity() {
|
|
748
|
+
return sysLogSeverityObj;
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Convertit une sévérité numérique ou string en son nom canonique.
|
|
752
|
+
*
|
|
753
|
+
* @param severity - valeur numérique (`6`) ou string (`"INFO"` ou `"6"`).
|
|
754
|
+
* @returns nom canonique (`"INFO"`) ou `undefined` si invalide.
|
|
755
|
+
*/
|
|
756
|
+
static severityToString(severity) {
|
|
757
|
+
const numericSeverity = typeof severity === "string" ? parseInt(severity, 10) : severity;
|
|
758
|
+
if (!isNaN(numericSeverity) && SysLogSeverity[numericSeverity] !== void 0) return SysLogSeverity[numericSeverity];
|
|
759
|
+
const severityKey = Pdu.severityToString(SysLogSeverity[severity]);
|
|
760
|
+
return severityKey !== void 0 ? severityKey : void 0;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Retourne le timestamp formaté `HH:MM:SS GMT±HHMM (TZ Name)`.
|
|
764
|
+
*
|
|
765
|
+
* @returns time string lisible par humain.
|
|
766
|
+
*/
|
|
767
|
+
getDate() {
|
|
768
|
+
return new Date(this.timeStamp).toTimeString();
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Sérialise le Pdu en string mono-ligne pour transport console/file.
|
|
772
|
+
*
|
|
773
|
+
* @returns ligne formatée `TimeStamp:... Log:... ModuleName:... SeverityName:... MessageID:... UID:... Message:...`.
|
|
774
|
+
*/
|
|
775
|
+
toString() {
|
|
776
|
+
return `TimeStamp:${this.getDate()} Log:${this.payload} ModuleName:${this.moduleName} SeverityName:${this.severityName} MessageID:${this.msgid} UID:${this.uid} Message:${this.msg}`;
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Réhydrate un Pdu existant à partir d'une string JSON — mute uniquement les
|
|
780
|
+
* clés déjà présentes sur l'instance (filtre `key in this`).
|
|
781
|
+
*
|
|
782
|
+
* @param str - JSON sérialisé d'un Pdu.
|
|
783
|
+
* @returns objet parsé (ou `null` si JSON vide). Mute l'instance courante au passage.
|
|
784
|
+
*/
|
|
785
|
+
parseJson(str) {
|
|
786
|
+
const json = JSON.parse(str);
|
|
787
|
+
Object.entries(json).forEach(([key, value]) => {
|
|
788
|
+
if (key in this) this[key] = value;
|
|
789
|
+
});
|
|
790
|
+
return json;
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
//#endregion
|
|
794
|
+
//#region src/syslog/logColor.ts
|
|
795
|
+
/** Combinaisons `cli-color` réellement utilisées par les loggers Nodefony. */
|
|
796
|
+
const KEYS = [
|
|
797
|
+
"cyan",
|
|
798
|
+
"magenta",
|
|
799
|
+
"red",
|
|
800
|
+
"green",
|
|
801
|
+
"yellow",
|
|
802
|
+
"blue",
|
|
803
|
+
"blackBright",
|
|
804
|
+
"yellowBold",
|
|
805
|
+
"redBold",
|
|
806
|
+
"cyanBold",
|
|
807
|
+
"blueBrightBold",
|
|
808
|
+
"cyanBgBlue",
|
|
809
|
+
"cyanBgBlack"
|
|
810
|
+
];
|
|
811
|
+
const identity = (s) => s;
|
|
812
|
+
/** Implémentation colorée (TTY) — résolue 1× à l'import (chaînage figé). */
|
|
813
|
+
const COLORS = {
|
|
814
|
+
cyan: clc.cyan,
|
|
815
|
+
magenta: clc.magenta,
|
|
816
|
+
red: clc.red,
|
|
817
|
+
green: clc.green,
|
|
818
|
+
yellow: clc.yellow,
|
|
819
|
+
blue: clc.blue,
|
|
820
|
+
blackBright: clc.blackBright,
|
|
821
|
+
yellowBold: clc.yellow.bold,
|
|
822
|
+
redBold: clc.red.bold,
|
|
823
|
+
cyanBold: clc.cyan.bold,
|
|
824
|
+
blueBrightBold: clc.blueBright.bold,
|
|
825
|
+
cyanBgBlue: clc.cyan.bgBlue,
|
|
826
|
+
cyanBgBlack: clc.cyan.bgBlack
|
|
827
|
+
};
|
|
828
|
+
/**
|
|
829
|
+
* Helper de couleur partagé — référence STABLE, propriétés mutées par
|
|
830
|
+
* {@link setLogColor}. Les call-sites font `logColor.cyan("URL")`.
|
|
831
|
+
*/
|
|
832
|
+
const logColor = { ...COLORS };
|
|
833
|
+
let _enabled = false;
|
|
834
|
+
/**
|
|
835
|
+
* Active/désactive la couleur ANSI des logs — à appeler **une fois au boot**.
|
|
836
|
+
* Swap les fonctions des slots ; aucun coût par log ensuite.
|
|
837
|
+
*
|
|
838
|
+
* @param enabled - `true` = couleur (TTY interactif), `false` = brut (pipe/fichier).
|
|
839
|
+
*/
|
|
840
|
+
function setLogColor(enabled) {
|
|
841
|
+
_enabled = enabled;
|
|
842
|
+
for (const k of KEYS) logColor[k] = enabled ? COLORS[k] : identity;
|
|
843
|
+
}
|
|
844
|
+
/** `true` si la couleur ANSI est active (gate boot-time). */
|
|
845
|
+
function isLogColorEnabled() {
|
|
846
|
+
return _enabled;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Applique les conventions d'environnement couleur PAR-DESSUS un signal `isTTY`
|
|
850
|
+
* **déjà résolu** — au boot on passe `Kernel.isTTY` (qui honore déjà `NF_NO_TTY`),
|
|
851
|
+
* sans re-lire `process.stdout`. Conventions :
|
|
852
|
+
*
|
|
853
|
+
* - **`NO_COLOR`** (no-color.org) : présent **et non vide** → couleur OFF, quelle
|
|
854
|
+
* que soit sa valeur. Priorité absolue (refus explicite de l'utilisateur).
|
|
855
|
+
* - **`FORCE_COLOR`** : non vide et ≠ `"0"` → couleur ON (override pipe/non-TTY,
|
|
856
|
+
* ex. CI qui veut des logs colorés capturés).
|
|
857
|
+
* - sinon → couleur = `isTTY`.
|
|
858
|
+
*
|
|
859
|
+
* Isomorphe : `env` lu via `globalThis.process` (navigateur : pas de `process`).
|
|
860
|
+
*
|
|
861
|
+
* @param isTTY - signal TTY déjà résolu (ex. `Kernel.isTTY`, NF_NO_TTY-aware).
|
|
862
|
+
*/
|
|
863
|
+
function resolveColorEnabled(isTTY) {
|
|
864
|
+
const env = globalThis.process?.env ?? {};
|
|
865
|
+
if (typeof env.NO_COLOR === "string" && env.NO_COLOR !== "") return false;
|
|
866
|
+
if (typeof env.FORCE_COLOR === "string" && env.FORCE_COLOR !== "" && env.FORCE_COLOR !== "0") return true;
|
|
867
|
+
return isTTY;
|
|
868
|
+
}
|
|
869
|
+
const _importProc = globalThis.process;
|
|
870
|
+
setLogColor(resolveColorEnabled(_importProc?.env?.NF_NO_TTY ? false : _importProc?.stdout?.isTTY === true));
|
|
871
|
+
//#endregion
|
|
872
|
+
//#region src/syslog/Syslog.ts
|
|
873
|
+
const yellow = (s) => logColor.yellowBold(s);
|
|
874
|
+
const red = (s) => logColor.redBold(s);
|
|
875
|
+
const cyan = (s) => logColor.cyanBold(s);
|
|
876
|
+
const blue = (s) => logColor.blueBrightBold(s);
|
|
877
|
+
const green = (s) => logColor.green(s);
|
|
878
|
+
const _proc = globalThis.process;
|
|
879
|
+
const _stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
880
|
+
let _bufferMode = "auto";
|
|
881
|
+
let _bufferOn = null;
|
|
882
|
+
let _outChunks = null;
|
|
883
|
+
let _outBytes = 0;
|
|
884
|
+
let _flushScheduled = false;
|
|
885
|
+
const FLUSH_BYTES = 65536;
|
|
886
|
+
const _setImmediate = globalThis.setImmediate;
|
|
887
|
+
const _resolveBufferOn = () => {
|
|
888
|
+
if (_bufferOn !== null) return _bufferOn;
|
|
889
|
+
_bufferOn = !_setImmediate ? false : _bufferMode === "on" ? true : _bufferMode === "off" ? false : !_proc?.stdout?.isTTY;
|
|
890
|
+
return _bufferOn;
|
|
891
|
+
};
|
|
892
|
+
const _stdoutSink = {
|
|
893
|
+
name: "stdout",
|
|
894
|
+
writeOut(s) {
|
|
895
|
+
if (_proc?.stdout) _proc.stdout.write(s);
|
|
896
|
+
else console.log(_stripAnsi(s).replace(/\n$/, ""));
|
|
897
|
+
},
|
|
898
|
+
writeErr(s) {
|
|
899
|
+
if (_proc?.stderr) _proc.stderr.write(s);
|
|
900
|
+
else console.error(_stripAnsi(s).replace(/\n$/, ""));
|
|
901
|
+
},
|
|
902
|
+
flushSync() {},
|
|
903
|
+
close() {}
|
|
904
|
+
};
|
|
905
|
+
/** Sink `/dev/null` : noop total (bench — mesure du plafond sans I/O de log). */
|
|
906
|
+
const NULL_LOG_SINK = {
|
|
907
|
+
name: "null",
|
|
908
|
+
writeOut() {},
|
|
909
|
+
writeErr() {},
|
|
910
|
+
flushSync() {},
|
|
911
|
+
close() {}
|
|
912
|
+
};
|
|
913
|
+
let _sink = _stdoutSink;
|
|
914
|
+
let _sinkMuted = false;
|
|
915
|
+
const _writeStdoutNow = (s) => {
|
|
916
|
+
if (!_sinkMuted) _sink.writeOut(s);
|
|
917
|
+
};
|
|
918
|
+
const _writeStderrNow = (s) => {
|
|
919
|
+
if (!_sinkMuted) _sink.writeErr(s);
|
|
920
|
+
};
|
|
921
|
+
const _flushOut = () => {
|
|
922
|
+
_flushScheduled = false;
|
|
923
|
+
if (_outChunks && _outChunks.length > 0) {
|
|
924
|
+
_writeStdoutNow(_outChunks.join(""));
|
|
925
|
+
_outChunks.length = 0;
|
|
926
|
+
_outBytes = 0;
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
const _setBufferMode = (mode) => {
|
|
930
|
+
_flushOut();
|
|
931
|
+
_bufferMode = mode === true ? "on" : mode === false ? "off" : "auto";
|
|
932
|
+
_bufferOn = null;
|
|
933
|
+
};
|
|
934
|
+
const _setLogSink = (sink) => {
|
|
935
|
+
_flushOut();
|
|
936
|
+
if (_sink !== sink && _sink !== _stdoutSink && _sink !== NULL_LOG_SINK) _sink.close();
|
|
937
|
+
_sink = sink ?? _stdoutSink;
|
|
938
|
+
};
|
|
939
|
+
const writeOut = (s) => {
|
|
940
|
+
if (!_resolveBufferOn()) {
|
|
941
|
+
_writeStdoutNow(s);
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (_outChunks === null) _outChunks = [];
|
|
945
|
+
_outChunks.push(s);
|
|
946
|
+
_outBytes += s.length;
|
|
947
|
+
if (_outBytes >= FLUSH_BYTES) {
|
|
948
|
+
_flushOut();
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
if (!_flushScheduled && _setImmediate) {
|
|
952
|
+
_flushScheduled = true;
|
|
953
|
+
_setImmediate(_flushOut);
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
const writeErr = (s) => {
|
|
957
|
+
if (_outChunks && _outChunks.length > 0) _flushOut();
|
|
958
|
+
_writeStderrNow(s);
|
|
959
|
+
};
|
|
960
|
+
if (_proc?.on) {
|
|
961
|
+
const _onExit = () => {
|
|
962
|
+
_flushOut();
|
|
963
|
+
_sink.flushSync();
|
|
964
|
+
};
|
|
965
|
+
_proc.on("exit", _onExit);
|
|
966
|
+
_proc.on("beforeExit", _onExit);
|
|
967
|
+
}
|
|
968
|
+
var CircularBuffer = class {
|
|
969
|
+
buf;
|
|
970
|
+
head = 0;
|
|
971
|
+
_size = 0;
|
|
972
|
+
capacity;
|
|
973
|
+
constructor(capacity) {
|
|
974
|
+
this.capacity = capacity;
|
|
975
|
+
this.buf = new Array(capacity);
|
|
976
|
+
}
|
|
977
|
+
push(item) {
|
|
978
|
+
if (this._size === this.capacity) {
|
|
979
|
+
this.buf[this.head] = item;
|
|
980
|
+
this.head = (this.head + 1) % this.capacity;
|
|
981
|
+
} else {
|
|
982
|
+
const tail = (this.head + this._size) % this.capacity;
|
|
983
|
+
this.buf[tail] = item;
|
|
984
|
+
this._size++;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
get length() {
|
|
988
|
+
return this._size;
|
|
989
|
+
}
|
|
990
|
+
last() {
|
|
991
|
+
if (this._size === 0) return void 0;
|
|
992
|
+
return this.buf[(this.head + this._size - 1) % this.capacity];
|
|
993
|
+
}
|
|
994
|
+
clear() {
|
|
995
|
+
this.head = 0;
|
|
996
|
+
this._size = 0;
|
|
997
|
+
}
|
|
998
|
+
toArray() {
|
|
999
|
+
const result = new Array(this._size);
|
|
1000
|
+
for (let i = 0; i < this._size; i++) result[i] = this.buf[(this.head + i) % this.capacity];
|
|
1001
|
+
return result;
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
const formatDebug = function(debug) {
|
|
1005
|
+
if (typeof debug === "boolean") return debug;
|
|
1006
|
+
if (typeof debug === "string") {
|
|
1007
|
+
if ([
|
|
1008
|
+
"false",
|
|
1009
|
+
"undefined",
|
|
1010
|
+
"null"
|
|
1011
|
+
].includes(debug)) return false;
|
|
1012
|
+
if (debug === "true" || debug === "*") return true;
|
|
1013
|
+
const mytab = debug.split(/,| /);
|
|
1014
|
+
return mytab[0] === "*" ? true : mytab;
|
|
1015
|
+
}
|
|
1016
|
+
if (Array.isArray(debug)) return debug[0] === "*" ? true : debug;
|
|
1017
|
+
return false;
|
|
1018
|
+
};
|
|
1019
|
+
const conditionOptions = function(environment, debug = false) {
|
|
1020
|
+
debug = formatDebug(debug);
|
|
1021
|
+
let obj;
|
|
1022
|
+
if (environment === "development") obj = { severity: {
|
|
1023
|
+
operator: "<=",
|
|
1024
|
+
data: debug === false ? 6 : 7
|
|
1025
|
+
} };
|
|
1026
|
+
else obj = { severity: {
|
|
1027
|
+
operator: "<=",
|
|
1028
|
+
data: debug ? 7 : 6
|
|
1029
|
+
} };
|
|
1030
|
+
if (typeof debug === "object") obj.msgid = {
|
|
1031
|
+
operator: "==",
|
|
1032
|
+
data: debug
|
|
1033
|
+
};
|
|
1034
|
+
return obj;
|
|
1035
|
+
};
|
|
1036
|
+
const defaultSettings = {
|
|
1037
|
+
moduleName: "SYSLOG",
|
|
1038
|
+
msgid: "",
|
|
1039
|
+
maxStack: 100,
|
|
1040
|
+
rateLimit: false,
|
|
1041
|
+
burstLimit: 3,
|
|
1042
|
+
defaultSeverity: "DEBUG",
|
|
1043
|
+
checkConditions: "&&",
|
|
1044
|
+
async: false
|
|
1045
|
+
};
|
|
1046
|
+
const sysLogSeverity = Pdu.sysLogSeverity();
|
|
1047
|
+
const operators = {
|
|
1048
|
+
"<": (ele1, ele2) => ele1 < ele2,
|
|
1049
|
+
">": (ele1, ele2) => ele1 > ele2,
|
|
1050
|
+
"<=": (ele1, ele2) => ele1 <= ele2,
|
|
1051
|
+
">=": (ele1, ele2) => ele1 >= ele2,
|
|
1052
|
+
"==": (ele1, ele2) => ele1 == ele2,
|
|
1053
|
+
"===": (ele1, ele2) => ele1 === ele2,
|
|
1054
|
+
"!=": (ele1, ele2) => ele1 !== ele2,
|
|
1055
|
+
RegExp: (ele1, ele2) => ele2.test(ele1)
|
|
1056
|
+
};
|
|
1057
|
+
const conditionsObj = {
|
|
1058
|
+
severity: (pdu, condition) => {
|
|
1059
|
+
for (const sev in condition.data) if (condition.operator && operators[condition.operator](pdu.severity, condition.data[sev])) return true;
|
|
1060
|
+
return false;
|
|
1061
|
+
},
|
|
1062
|
+
msgid: (pdu, condition) => {
|
|
1063
|
+
if (condition.data instanceof RegExp) return condition.data.test(pdu.msgid);
|
|
1064
|
+
for (const sev in condition.data) if (condition.operator && operators[condition.operator](pdu.msgid, sev)) return true;
|
|
1065
|
+
return false;
|
|
1066
|
+
},
|
|
1067
|
+
date: (pdu, condition) => condition.operator ? operators[condition.operator](pdu.timeStamp, condition.data) : false
|
|
1068
|
+
};
|
|
1069
|
+
const logicCondition = {
|
|
1070
|
+
"&&": (myConditions, pdu) => {
|
|
1071
|
+
let res = false;
|
|
1072
|
+
for (const ele in myConditions) {
|
|
1073
|
+
res = conditionsObj[ele](pdu, myConditions[ele]);
|
|
1074
|
+
if (!res) break;
|
|
1075
|
+
}
|
|
1076
|
+
return res;
|
|
1077
|
+
},
|
|
1078
|
+
"||": (myConditions, pdu) => {
|
|
1079
|
+
let res = false;
|
|
1080
|
+
for (const ele in myConditions) {
|
|
1081
|
+
res = conditionsObj[ele](pdu, myConditions[ele]);
|
|
1082
|
+
if (res) break;
|
|
1083
|
+
}
|
|
1084
|
+
return res;
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
const checkFormatSeverity = (ele) => {
|
|
1088
|
+
let res;
|
|
1089
|
+
switch (typeof ele) {
|
|
1090
|
+
case "object":
|
|
1091
|
+
if (Array.isArray(ele)) res = ele;
|
|
1092
|
+
else throw new Error(`checkFormatSeverity bad format type: object`);
|
|
1093
|
+
break;
|
|
1094
|
+
case "string":
|
|
1095
|
+
res = ele.split(/,| /);
|
|
1096
|
+
break;
|
|
1097
|
+
case "number":
|
|
1098
|
+
res = [ele];
|
|
1099
|
+
break;
|
|
1100
|
+
default: throw new Error(`checkFormatSeverity bad format type : ${typeof ele}`);
|
|
1101
|
+
}
|
|
1102
|
+
return res;
|
|
1103
|
+
};
|
|
1104
|
+
const checkFormatDate = function(ele) {
|
|
1105
|
+
if (ele instanceof Date) return ele.getTime();
|
|
1106
|
+
if (typeof ele === "string") return new Date(ele).getTime();
|
|
1107
|
+
throw new Error(`checkFormatDate bad format : ${String(ele)}`);
|
|
1108
|
+
};
|
|
1109
|
+
const checkFormatMsgId = function(ele) {
|
|
1110
|
+
if (typeof ele === "string") return ele.split(/,| /);
|
|
1111
|
+
if (typeof ele === "number") return [ele];
|
|
1112
|
+
if (ele instanceof RegExp) return ele;
|
|
1113
|
+
if (Array.isArray(ele)) return ele;
|
|
1114
|
+
throw new Error(`checkFormatMsgId bad format ${typeof ele} : ${String(ele)}`);
|
|
1115
|
+
};
|
|
1116
|
+
const wrapperCondition = function(conditions, callback) {
|
|
1117
|
+
let myFuncCondition = () => false;
|
|
1118
|
+
if (conditions.checkConditions && conditions.checkConditions in logicCondition) {
|
|
1119
|
+
myFuncCondition = logicCondition[conditions.checkConditions];
|
|
1120
|
+
delete conditions.checkConditions;
|
|
1121
|
+
} else if (this.settings.checkConditions) myFuncCondition = logicCondition[this.settings.checkConditions];
|
|
1122
|
+
const Conditions = sanitizeConditions(conditions);
|
|
1123
|
+
if (typeof callback === "function") return (pdu) => {
|
|
1124
|
+
if (myFuncCondition(Conditions, pdu)) callback(pdu);
|
|
1125
|
+
};
|
|
1126
|
+
if (Array.isArray(callback)) {
|
|
1127
|
+
const tab = [];
|
|
1128
|
+
for (const pdu of callback) if (myFuncCondition(Conditions, pdu)) tab.push(pdu);
|
|
1129
|
+
return tab;
|
|
1130
|
+
}
|
|
1131
|
+
throw new Error("Bad wrapper");
|
|
1132
|
+
};
|
|
1133
|
+
const sanitizeConditions = function(settingsCondition) {
|
|
1134
|
+
if (typeof settingsCondition !== "object" || settingsCondition === null) return false;
|
|
1135
|
+
for (const ele in settingsCondition) {
|
|
1136
|
+
if (!(ele in conditionsObj)) return false;
|
|
1137
|
+
const condi = settingsCondition[ele];
|
|
1138
|
+
if (condi.operator && !(condi.operator in operators)) throw new Error(`Contitions bad operator : ${condi.operator}`);
|
|
1139
|
+
if (condi.data) switch (ele) {
|
|
1140
|
+
case "severity": {
|
|
1141
|
+
if (!condi.operator) condi.operator = "==";
|
|
1142
|
+
const res = checkFormatSeverity(condi.data);
|
|
1143
|
+
condi.data = {};
|
|
1144
|
+
for (let i = 0; i < res.length; i++) {
|
|
1145
|
+
const mySeverity = Pdu.severityToString(res[i]);
|
|
1146
|
+
if (mySeverity) condi.data[mySeverity] = sysLogSeverity[mySeverity];
|
|
1147
|
+
else return false;
|
|
1148
|
+
}
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
case "msgid": {
|
|
1152
|
+
if (!condi.operator) condi.operator = "==";
|
|
1153
|
+
const res = checkFormatMsgId(condi.data);
|
|
1154
|
+
if (Array.isArray(res)) {
|
|
1155
|
+
condi.data = {};
|
|
1156
|
+
for (let i = 0; i < res.length; i++) condi.data[String(res[i])] = "||";
|
|
1157
|
+
} else condi.data = res;
|
|
1158
|
+
break;
|
|
1159
|
+
}
|
|
1160
|
+
case "date": {
|
|
1161
|
+
const res = checkFormatDate(condi.data);
|
|
1162
|
+
if (res) condi.data = res;
|
|
1163
|
+
else return false;
|
|
1164
|
+
break;
|
|
1165
|
+
}
|
|
1166
|
+
default: return false;
|
|
1167
|
+
}
|
|
1168
|
+
else return false;
|
|
1169
|
+
}
|
|
1170
|
+
return settingsCondition;
|
|
1171
|
+
};
|
|
1172
|
+
const createPDU = function(payload, severity, moduleName, msgid, msg) {
|
|
1173
|
+
return new Pdu(payload, severity || this.settings.defaultSeverity, moduleName, msgid, msg);
|
|
1174
|
+
};
|
|
1175
|
+
(class Syslog extends Event {
|
|
1176
|
+
settings;
|
|
1177
|
+
_ring;
|
|
1178
|
+
burstPrinted;
|
|
1179
|
+
missed;
|
|
1180
|
+
invalid;
|
|
1181
|
+
valid;
|
|
1182
|
+
/**
|
|
1183
|
+
* Cumul monotone des logs de classe ERREUR (sévérité 0–3 : ERROR/CRITIC/ALERT/EMERGENCY)
|
|
1184
|
+
* acceptés depuis la construction. Compteur entier O(1) bumpé dans le seul point de passage
|
|
1185
|
+
* {@link pushStack} (0 alloc) → sonde « erreurs par worker » de la santé
|
|
1186
|
+
* pod (cf `IInstanceErrorHealth`). Débit dérivé côté lecteur (delta `errorTotal`/ts).
|
|
1187
|
+
*/
|
|
1188
|
+
errorTotal;
|
|
1189
|
+
/** Sous-ensemble CRITIQUE (sévérité 0–2 : CRITIC/ALERT/EMERGENCY). Cumul monotone. */
|
|
1190
|
+
criticTotal;
|
|
1191
|
+
start;
|
|
1192
|
+
_async = false;
|
|
1193
|
+
_transports = [];
|
|
1194
|
+
/**
|
|
1195
|
+
* Transports désactivés à chaud (par `setTransportEnabled`) — **lazy** (`null`
|
|
1196
|
+
* tant qu'aucun toggle). Garde la réf hors de `_transports` pour pouvoir la
|
|
1197
|
+
* remonter. Un transport désactivé est PHYSIQUEMENT retiré de la boucle de fire
|
|
1198
|
+
* → **0 surcoût hot path** (pas de test `enabled` par log). Outil dev/diagnostic.
|
|
1199
|
+
*/
|
|
1200
|
+
_disabledTransports = null;
|
|
1201
|
+
/**
|
|
1202
|
+
* Stockage des Pdu dans le ring buffer (relecture mémoire). `false` = on ne
|
|
1203
|
+
* garde plus rien en mémoire (l'Explorer « mémoire » et `buffered` tombent à 0)
|
|
1204
|
+
* — outil avancé perf/mémoire (très haut débit). Les compteurs (valid/error)
|
|
1205
|
+
* restent comptés. Coût hot path : un test booléen par log.
|
|
1206
|
+
*/
|
|
1207
|
+
_ringEnabled = true;
|
|
1208
|
+
/**
|
|
1209
|
+
* Diffusion temps réel active (bus `nodefony:syslog` Studio). `false` = le pont de
|
|
1210
|
+
* diffusion (`createSyslogBridge`) n'accumule ni ne publie rien → l'onglet Live se
|
|
1211
|
+
* grise. N'affecte NI l'écriture (transports/sink) NI la relecture. Coupé = on
|
|
1212
|
+
* cesse juste de POUSSER en live ; les logs continuent d'être générés et écrits.
|
|
1213
|
+
*/
|
|
1214
|
+
_streamEnabled = true;
|
|
1215
|
+
/**
|
|
1216
|
+
* T2 (profil delta vs Express) — gate d'ENTRÉE par sévérité. `null` (défaut) =
|
|
1217
|
+
* pas de gate (comportement historique : tout Pdu est créé + poussé au ring,
|
|
1218
|
+
* le filtrage de sévérité n'a lieu qu'au LISTENER d'impression — un DEBUG en
|
|
1219
|
+
* prod coûtait createPDU + pushStack pour rien, ~1,7 % du profil CPU/req).
|
|
1220
|
+
* Valeur numérique N = un log de sévérité STRICTEMENT supérieure à N (moins
|
|
1221
|
+
* grave) est court-circuité AVANT toute allocation. Posé par {@link init}
|
|
1222
|
+
* (production sans debug → 6 = DEBUG gaté), **re-résoluble à chaud** via
|
|
1223
|
+
* {@link setSeverityThreshold} (vision « audit à chaud » : élever la
|
|
1224
|
+
* verbosité prod sur une fenêtre bornée sans redémarrer). Une sévérité
|
|
1225
|
+
* INCONNUE (`-1`) passe toujours — c'est `createPDU` qui la refuse, et le
|
|
1226
|
+
* gate ne doit pas transformer une erreur d'usage en silence. Compteur
|
|
1227
|
+
* {@link gated} pour l'introspection.
|
|
1228
|
+
*/
|
|
1229
|
+
_severityThreshold = null;
|
|
1230
|
+
/** Pdu singleton retourné par un log gaté (contrat `log(): Pdu`, 1 alloc lazy). */
|
|
1231
|
+
_gatedPdu = null;
|
|
1232
|
+
/** Nombre de logs court-circuités par le gate de sévérité (T2). */
|
|
1233
|
+
gated = 0;
|
|
1234
|
+
/**
|
|
1235
|
+
* Overrides de seuil PAR MODULE (clé = `msgid` du Pdu, qui vaut le nom du
|
|
1236
|
+
* Service émetteur par défaut — cf `Service.log`). `null` par défaut → 0 coût
|
|
1237
|
+
* sur le hot path tant qu'aucun debug ciblé n'est actif (RÈGLE perf : lazy
|
|
1238
|
+
* null). Posé à chaud par {@link setDebugOverride} (env `NF__DEBUG` au boot,
|
|
1239
|
+
* endpoint admin, toggle Studio) : élève la verbosité d'UN module sous gate
|
|
1240
|
+
* prod sans toucher les autres ni redémarrer. Consulté dans {@link log} APRÈS
|
|
1241
|
+
* le gate global, AVANT toute allocation.
|
|
1242
|
+
*/
|
|
1243
|
+
_debugOverrides = null;
|
|
1244
|
+
/**
|
|
1245
|
+
* Timers d'auto-extinction des overrides (clé = même `msgid`). `null` tant
|
|
1246
|
+
* qu'aucun override temporisé n'est armé. Garde-fou anti-oubli : un debug
|
|
1247
|
+
* ciblé ne reste JAMAIS allumé indéfiniment. Timers `unref` (ne tiennent pas
|
|
1248
|
+
* la boucle d'événements en vie) + purgés par {@link clearDebugOverride} /
|
|
1249
|
+
* {@link reset} (RÈGLE perf : pas de timer sans cleanup).
|
|
1250
|
+
*/
|
|
1251
|
+
_debugOverrideTimers = null;
|
|
1252
|
+
/**
|
|
1253
|
+
* Échéance (epoch ms) de chaque override TEMPORISÉ — pour exposer le « s'éteint
|
|
1254
|
+
* dans X » au panneau Studio. `null` tant qu'aucun override temporisé ; un
|
|
1255
|
+
* override permanent (sans ttl) n'y figure pas. Nettoyé en miroir du timer.
|
|
1256
|
+
*/
|
|
1257
|
+
_debugOverrideExpiry = null;
|
|
1258
|
+
/**
|
|
1259
|
+
* Construit le Syslog avec settings (merge default + override user).
|
|
1260
|
+
*
|
|
1261
|
+
* @param settings - config (`moduleName`, `maxStack`, `rateLimit`, `burstLimit`,
|
|
1262
|
+
* `defaultSeverity`, `async`, `overrideConsole`).
|
|
1263
|
+
*/
|
|
1264
|
+
constructor(settings) {
|
|
1265
|
+
super(settings);
|
|
1266
|
+
this.settings = extend({}, defaultSettings, settings || {});
|
|
1267
|
+
this._ring = new CircularBuffer(this.settings.maxStack ?? 100);
|
|
1268
|
+
this.burstPrinted = 0;
|
|
1269
|
+
this.missed = 0;
|
|
1270
|
+
this.invalid = 0;
|
|
1271
|
+
this.valid = 0;
|
|
1272
|
+
this.errorTotal = 0;
|
|
1273
|
+
this.criticTotal = 0;
|
|
1274
|
+
this.start = 0;
|
|
1275
|
+
this._async = this.settings.async || false;
|
|
1276
|
+
if (this.settings.overrideConsole) Syslog.overrideConsole(this);
|
|
1277
|
+
}
|
|
1278
|
+
get ringStack() {
|
|
1279
|
+
return this._ring.toArray();
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Capacité MAX du ring buffer (`settings.maxStack`) — nombre de Pdu que la
|
|
1283
|
+
* mémoire peut relire. `ringStack.length` = remplissage courant ; ce getter =
|
|
1284
|
+
* le plafond. Lecture seule, 0 allocation (introspection data plane Studio).
|
|
1285
|
+
*/
|
|
1286
|
+
get bufferCapacity() {
|
|
1287
|
+
return this._ring.capacity;
|
|
1288
|
+
}
|
|
1289
|
+
/** `true` si les Pdu sont stockés dans le ring (relecture mémoire active). */
|
|
1290
|
+
get ringEnabled() {
|
|
1291
|
+
return this._ringEnabled;
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Active/désactive le stockage mémoire (ring) à chaud — outil avancé perf/mémoire.
|
|
1295
|
+
* Désactiver = l'Explorer « mémoire » et `buffered` retombent à 0 (les logs ne
|
|
1296
|
+
* sont plus gardés en RAM) ; les compteurs santé restent comptés. Vide le ring
|
|
1297
|
+
* quand on coupe (libère la RAM tout de suite). Idempotent.
|
|
1298
|
+
*
|
|
1299
|
+
* @param enabled - `true` = stocker dans le ring ; `false` = ne plus stocker.
|
|
1300
|
+
* @returns `true` si l'état a changé.
|
|
1301
|
+
*/
|
|
1302
|
+
setRingEnabled(enabled) {
|
|
1303
|
+
if (this._ringEnabled === enabled) return false;
|
|
1304
|
+
this._ringEnabled = enabled;
|
|
1305
|
+
if (!enabled) this._ring.clear();
|
|
1306
|
+
return true;
|
|
1307
|
+
}
|
|
1308
|
+
/** `true` si la diffusion temps réel (`nodefony:syslog`) est active. */
|
|
1309
|
+
get streamEnabled() {
|
|
1310
|
+
return this._streamEnabled;
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Active/désactive la diffusion temps réel (bus `nodefony:syslog`) à chaud. Coupé =
|
|
1314
|
+
* le pont Studio cesse de pousser des frames (onglet Live grisé) ; l'écriture et la
|
|
1315
|
+
* relecture froide ne sont PAS touchées. Idempotent.
|
|
1316
|
+
*
|
|
1317
|
+
* @param enabled - `true` = diffuser ; `false` = couper la diffusion live.
|
|
1318
|
+
* @returns `true` si l'état a changé.
|
|
1319
|
+
*/
|
|
1320
|
+
setStreamEnabled(enabled) {
|
|
1321
|
+
if (this._streamEnabled === enabled) return false;
|
|
1322
|
+
this._streamEnabled = enabled;
|
|
1323
|
+
return true;
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Redimensionne le ring buffer (capacité de relecture en mémoire) en
|
|
1327
|
+
* **préservant** les Pdu déjà présents (tronqués aux `max` plus récents si on
|
|
1328
|
+
* rétrécit). Destiné au **boot uniquement** (lu depuis `config.log.maxStack`) —
|
|
1329
|
+
* recrée le buffer, donc à ne pas appeler dans le hot path. No-op si `max`
|
|
1330
|
+
* invalide ou inchangé.
|
|
1331
|
+
*
|
|
1332
|
+
* @param max - nouvelle capacité (> 0).
|
|
1333
|
+
*/
|
|
1334
|
+
setMaxStack(max) {
|
|
1335
|
+
if (!Number.isFinite(max) || max <= 0 || max === this.settings.maxStack) return;
|
|
1336
|
+
const kept = this._ring.toArray().slice(-max);
|
|
1337
|
+
this.settings.maxStack = max;
|
|
1338
|
+
this._ring = new CircularBuffer(max);
|
|
1339
|
+
for (const pdu of kept) this._ring.push(pdu);
|
|
1340
|
+
}
|
|
1341
|
+
static formatDebug(debug) {
|
|
1342
|
+
return formatDebug(debug);
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Initialise le pipeline Syslog selon environnement + debug. Idempotent — purge les
|
|
1346
|
+
* listeners `"onLog"` existants avant d'en ajouter un.
|
|
1347
|
+
*
|
|
1348
|
+
* @param environment - `"development"` / `"production"` / `"test"`.
|
|
1349
|
+
* @param debug - active sévérité DEBUG (`+7`).
|
|
1350
|
+
* @param options - conditions de filtrage Syslog custom (override des conditions par env).
|
|
1351
|
+
*/
|
|
1352
|
+
init(environment, debug, options) {
|
|
1353
|
+
this.removeAllListeners("onLog");
|
|
1354
|
+
this.listenWithConditions(options || conditionOptions(environment, debug), (pdu) => Syslog.normalizeLog(pdu));
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* T2 — résout une sévérité (nom ou numérique) en valeur RFC 5424. Inconnue →
|
|
1358
|
+
* `-1` (passe toujours le gate : fail-open, `createPDU` jettera comme avant).
|
|
1359
|
+
* `sysLogSeverity` est un enum numérique TS → la reverse-map mêle string et
|
|
1360
|
+
* number, d'où le narrowing explicite.
|
|
1361
|
+
*/
|
|
1362
|
+
static toSeverityNumber(severity) {
|
|
1363
|
+
if (typeof severity === "number") return severity;
|
|
1364
|
+
const v = sysLogSeverity[severity];
|
|
1365
|
+
return typeof v === "number" ? v : -1;
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Valide STRICTEMENT une sévérité d'ENTRÉE (nom RFC 5424 ou numérique 0-7) →
|
|
1369
|
+
* numéro, ou `null` si invalide. Pour les surfaces d'entrée (endpoint admin,
|
|
1370
|
+
* env) : un niveau inconnu doit être REJETÉ, jamais silencieusement
|
|
1371
|
+
* réinterprété (≠ {@link toSeverityNumber}, fail-open `-1` pour le hot path).
|
|
1372
|
+
*
|
|
1373
|
+
* @param level - nom (`"DEBUG"`) ou numéro (`7` / `"7"`).
|
|
1374
|
+
* @returns le numéro 0-7, ou `null` si hors plage / nom inconnu.
|
|
1375
|
+
*/
|
|
1376
|
+
static severityFromInput(level) {
|
|
1377
|
+
if (typeof level === "number") return Number.isInteger(level) && level >= 0 && level <= 7 ? level : null;
|
|
1378
|
+
if (typeof level === "string") {
|
|
1379
|
+
if (/^\d+$/.test(level)) {
|
|
1380
|
+
const n = Number(level);
|
|
1381
|
+
return n >= 0 && n <= 7 ? n : null;
|
|
1382
|
+
}
|
|
1383
|
+
const v = sysLogSeverity[level];
|
|
1384
|
+
return typeof v === "number" ? v : null;
|
|
1385
|
+
}
|
|
1386
|
+
return null;
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Parse une spec `NF__DEBUG` (env runtime) en directives de debug ciblé.
|
|
1390
|
+
* Tokens séparés par virgule/espace :
|
|
1391
|
+
* - `*` → debug GLOBAL (lève le gate de sévérité, tout passe) ;
|
|
1392
|
+
* - `MODULE` → override `MODULE` à DEBUG ;
|
|
1393
|
+
* - `MODULE:LEVEL` → override `MODULE` au niveau `LEVEL` (nom/numérique ;
|
|
1394
|
+
* inconnu → DEBUG, tolérant : un typo d'env ne doit pas crasher le boot).
|
|
1395
|
+
*
|
|
1396
|
+
* Pur (statique, sans état) → testable seul ; appliqué par le Kernel au boot
|
|
1397
|
+
* via {@link setSeverityThreshold} / {@link setDebugOverride}.
|
|
1398
|
+
*
|
|
1399
|
+
* @param spec - valeur brute de `NF__DEBUG` (ex. `"FIREWALL,SESSION:NOTICE"`).
|
|
1400
|
+
* @returns `{ global, overrides }`.
|
|
1401
|
+
*/
|
|
1402
|
+
static parseDebugSpec(spec) {
|
|
1403
|
+
const result = {
|
|
1404
|
+
global: false,
|
|
1405
|
+
overrides: []
|
|
1406
|
+
};
|
|
1407
|
+
if (typeof spec !== "string") return result;
|
|
1408
|
+
for (const token of spec.split(/[,\s]+/)) {
|
|
1409
|
+
if (!token) continue;
|
|
1410
|
+
if (token === "*") {
|
|
1411
|
+
result.global = true;
|
|
1412
|
+
continue;
|
|
1413
|
+
}
|
|
1414
|
+
const sep = token.indexOf(":");
|
|
1415
|
+
if (sep === -1) {
|
|
1416
|
+
result.overrides.push({
|
|
1417
|
+
module: token,
|
|
1418
|
+
level: 7
|
|
1419
|
+
});
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
const module = token.slice(0, sep);
|
|
1423
|
+
if (!module) continue;
|
|
1424
|
+
const lvl = Syslog.severityFromInput(token.slice(sep + 1)) ?? 7;
|
|
1425
|
+
result.overrides.push({
|
|
1426
|
+
module,
|
|
1427
|
+
level: lvl
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
return result;
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* T2 — règle (ou lève) le gate d'entrée par sévérité À CHAUD, sans reboot.
|
|
1434
|
+
* `null` = plus de gate (tout est créé/poussé, comportement historique) ;
|
|
1435
|
+
* `"DEBUG"`/7 = tout passe en restant gateable ; `"INFO"`/6 = défaut prod.
|
|
1436
|
+
* Levier de la fenêtre « audit à chaud » : élever temporairement la
|
|
1437
|
+
* verbosité prod puis restaurer.
|
|
1438
|
+
*
|
|
1439
|
+
* @param threshold - sévérité max acceptée (nom ou numérique RFC 5424), ou `null`.
|
|
1440
|
+
*/
|
|
1441
|
+
setSeverityThreshold(threshold) {
|
|
1442
|
+
this._severityThreshold = threshold === null ? null : Syslog.toSeverityNumber(threshold);
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* T2 — un log de cette sévérité franchirait-il le gate d'entrée ? À utiliser
|
|
1446
|
+
* aux call sites du hot path AVANT de construire un message coûteux
|
|
1447
|
+
* (template string, JSON) — pattern L1 « ne jamais formater au-dessus du
|
|
1448
|
+
* niveau actif ».
|
|
1449
|
+
*
|
|
1450
|
+
* @param severity - sévérité à tester (nom ou numérique).
|
|
1451
|
+
* @returns `true` si un log de cette sévérité serait accepté.
|
|
1452
|
+
*/
|
|
1453
|
+
severityEnabled(severity) {
|
|
1454
|
+
if (this._severityThreshold === null) return true;
|
|
1455
|
+
return Syslog.toSeverityNumber(severity) <= this._severityThreshold;
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Élève à chaud le seuil de verbosité d'UN module (debug ciblé), sans reboot et
|
|
1459
|
+
* sans toucher aux autres modules. `module` = `msgid` du Pdu (par défaut le nom
|
|
1460
|
+
* du Service émetteur, cf `Service.log`). Effet : tant que l'override est actif,
|
|
1461
|
+
* un log de ce module passe le gate d'entrée jusqu'à `level` (ex. `"DEBUG"`)
|
|
1462
|
+
* alors que le reste reste au seuil global (ex. `"INFO"` en prod).
|
|
1463
|
+
*
|
|
1464
|
+
* Garde-fou : si `ttlMs > 0`, l'override s'auto-éteint après ce délai (timer
|
|
1465
|
+
* `unref`). (Re)poser le même module ré-arme proprement le timer. Sans gate
|
|
1466
|
+
* global actif (`_severityThreshold === null`, ex. dev) l'override est sans
|
|
1467
|
+
* effet — tout passe déjà.
|
|
1468
|
+
*
|
|
1469
|
+
* @param module - identité du module (`msgid` / nom du Service).
|
|
1470
|
+
* @param level - sévérité max laissée passer pour ce module (nom ou numérique).
|
|
1471
|
+
* @param ttlMs - durée de vie en ms (auto-extinction). Omis/≤0 = permanent (déconseillé en prod).
|
|
1472
|
+
*/
|
|
1473
|
+
setDebugOverride(module, level, ttlMs) {
|
|
1474
|
+
if (this._debugOverrides === null) this._debugOverrides = /* @__PURE__ */ new Map();
|
|
1475
|
+
this._debugOverrides.set(module, Syslog.toSeverityNumber(level));
|
|
1476
|
+
this.clearOverrideTimer(module);
|
|
1477
|
+
if (ttlMs !== void 0 && ttlMs > 0) {
|
|
1478
|
+
if (this._debugOverrideTimers === null) this._debugOverrideTimers = /* @__PURE__ */ new Map();
|
|
1479
|
+
const timer = setTimeout(() => {
|
|
1480
|
+
this.clearDebugOverride(module);
|
|
1481
|
+
}, ttlMs);
|
|
1482
|
+
timer.unref();
|
|
1483
|
+
this._debugOverrideTimers.set(module, timer);
|
|
1484
|
+
if (this._debugOverrideExpiry === null) this._debugOverrideExpiry = /* @__PURE__ */ new Map();
|
|
1485
|
+
this._debugOverrideExpiry.set(module, Date.now() + ttlMs);
|
|
1486
|
+
} else if (this._debugOverrideExpiry !== null) {
|
|
1487
|
+
this._debugOverrideExpiry.delete(module);
|
|
1488
|
+
if (this._debugOverrideExpiry.size === 0) this._debugOverrideExpiry = null;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Retire l'override de debug ciblé d'un module (et son timer d'auto-extinction).
|
|
1493
|
+
* Retombe à `null` quand le dernier override part (RÈGLE perf : 0 coût hot path).
|
|
1494
|
+
*
|
|
1495
|
+
* @param module - identité du module (`msgid`).
|
|
1496
|
+
* @returns `true` si un override existait et a été retiré.
|
|
1497
|
+
*/
|
|
1498
|
+
clearDebugOverride(module) {
|
|
1499
|
+
this.clearOverrideTimer(module);
|
|
1500
|
+
if (this._debugOverrideExpiry !== null) {
|
|
1501
|
+
this._debugOverrideExpiry.delete(module);
|
|
1502
|
+
if (this._debugOverrideExpiry.size === 0) this._debugOverrideExpiry = null;
|
|
1503
|
+
}
|
|
1504
|
+
if (this._debugOverrides === null) return false;
|
|
1505
|
+
const had = this._debugOverrides.delete(module);
|
|
1506
|
+
if (this._debugOverrides.size === 0) this._debugOverrides = null;
|
|
1507
|
+
return had;
|
|
1508
|
+
}
|
|
1509
|
+
/** Retire TOUS les overrides de debug ciblé + leurs timers (retour à 0 coût). */
|
|
1510
|
+
clearAllDebugOverrides() {
|
|
1511
|
+
if (this._debugOverrideTimers !== null) {
|
|
1512
|
+
for (const timer of this._debugOverrideTimers.values()) clearTimeout(timer);
|
|
1513
|
+
this._debugOverrideTimers = null;
|
|
1514
|
+
}
|
|
1515
|
+
this._debugOverrides = null;
|
|
1516
|
+
this._debugOverrideExpiry = null;
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Snapshot des overrides de debug ciblé actifs (introspection — endpoint admin,
|
|
1520
|
+
* toggle Studio). Cold path. `{}` si aucun.
|
|
1521
|
+
*
|
|
1522
|
+
* @returns map `module → seuil numérique` (copie, pas la structure interne).
|
|
1523
|
+
*/
|
|
1524
|
+
getDebugOverrides() {
|
|
1525
|
+
if (this._debugOverrides === null) return {};
|
|
1526
|
+
const out = {};
|
|
1527
|
+
for (const [module, threshold] of this._debugOverrides) out[module] = threshold;
|
|
1528
|
+
return out;
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Échéances (epoch ms) des overrides TEMPORISÉS (introspection — countdown
|
|
1532
|
+
* Studio « s'éteint dans X »). `{}` si aucun ; un override permanent (sans ttl)
|
|
1533
|
+
* n'y figure pas.
|
|
1534
|
+
*
|
|
1535
|
+
* @returns map `module → epoch ms d'extinction` (copie).
|
|
1536
|
+
*/
|
|
1537
|
+
getDebugOverrideExpiry() {
|
|
1538
|
+
if (this._debugOverrideExpiry === null) return {};
|
|
1539
|
+
const out = {};
|
|
1540
|
+
for (const [module, at] of this._debugOverrideExpiry) out[module] = at;
|
|
1541
|
+
return out;
|
|
1542
|
+
}
|
|
1543
|
+
/** Annule + retire le timer d'auto-extinction d'un module (si présent). */
|
|
1544
|
+
clearOverrideTimer(module) {
|
|
1545
|
+
if (this._debugOverrideTimers === null) return;
|
|
1546
|
+
const timer = this._debugOverrideTimers.get(module);
|
|
1547
|
+
if (timer !== void 0) {
|
|
1548
|
+
clearTimeout(timer);
|
|
1549
|
+
this._debugOverrideTimers.delete(module);
|
|
1550
|
+
if (this._debugOverrideTimers.size === 0) this._debugOverrideTimers = null;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
get async() {
|
|
1554
|
+
return this._async;
|
|
1555
|
+
}
|
|
1556
|
+
set async(value) {
|
|
1557
|
+
this._async = value;
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Alias de {@link reset} — purge ring buffer + listeners.
|
|
1561
|
+
*/
|
|
1562
|
+
clean() {
|
|
1563
|
+
return this.reset();
|
|
1564
|
+
}
|
|
1565
|
+
/**
|
|
1566
|
+
* Reset complet — vide le ring buffer ET retire tous les listeners.
|
|
1567
|
+
*
|
|
1568
|
+
* @returns `this` pour chaînage.
|
|
1569
|
+
*/
|
|
1570
|
+
reset() {
|
|
1571
|
+
this._ring.clear();
|
|
1572
|
+
this.removeAllListeners();
|
|
1573
|
+
this.clearAllDebugOverrides();
|
|
1574
|
+
return this;
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Vide uniquement le ring buffer (conserve les listeners attachés).
|
|
1578
|
+
*/
|
|
1579
|
+
clearLogStack() {
|
|
1580
|
+
this._ring.clear();
|
|
1581
|
+
}
|
|
1582
|
+
/**
|
|
1583
|
+
* Push manuel d'un Pdu dans le ring buffer + incrémente compteur `valid`.
|
|
1584
|
+
*
|
|
1585
|
+
* @param pdu - Pdu à enregistrer.
|
|
1586
|
+
* @returns nouvelle taille du ring buffer après push.
|
|
1587
|
+
*/
|
|
1588
|
+
pushStack(pdu) {
|
|
1589
|
+
if (this._ringEnabled) this._ring.push(pdu);
|
|
1590
|
+
this.valid++;
|
|
1591
|
+
const sev = pdu.severity;
|
|
1592
|
+
if (sev >= 0 && sev <= 3) {
|
|
1593
|
+
this.errorTotal++;
|
|
1594
|
+
if (sev <= 2) this.criticTotal++;
|
|
1595
|
+
}
|
|
1596
|
+
return this._ring.length;
|
|
1597
|
+
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Crée un Pdu et le diffuse dans le pipeline (rate-limit → push → fire `"onLog"`).
|
|
1600
|
+
*
|
|
1601
|
+
* **Protection rate limit** : si `settings.rateLimit > 0`, ne fire `"onLog"` que pour les
|
|
1602
|
+
* `burstLimit` premiers Pdu de la fenêtre. Les suivants incrémentent `missed`.
|
|
1603
|
+
*
|
|
1604
|
+
* **Mode async** : si `this.async === true`, fire `"onLog"` sur `setImmediate()` (libère
|
|
1605
|
+
* le hot path du caller).
|
|
1606
|
+
*
|
|
1607
|
+
* @param payload - contenu (string, Error, objet — narrower côté lecteur).
|
|
1608
|
+
* @param severity - sévérité RFC 5424 (`"INFO"`, `"ERROR"`, ...) ou numérique (6, 3, ...).
|
|
1609
|
+
* @param msgid - catégorie de message (`"AUTH"`, `"ROUTER"`). Défaut = `settings.msgid`.
|
|
1610
|
+
* @param msg - détail libre optionnel.
|
|
1611
|
+
* @returns le `Pdu` créé (utile pour audit/tests).
|
|
1612
|
+
*/
|
|
1613
|
+
log(payload, severity, msgid, msg) {
|
|
1614
|
+
if (this._severityThreshold !== null) {
|
|
1615
|
+
const sev = payload instanceof Pdu ? payload.severity : Syslog.toSeverityNumber(severity ?? this.settings.defaultSeverity ?? "DEBUG");
|
|
1616
|
+
let threshold = this._severityThreshold;
|
|
1617
|
+
if (this._debugOverrides !== null) {
|
|
1618
|
+
const key = payload instanceof Pdu ? payload.msgid : msgid || this.settings.msgid;
|
|
1619
|
+
const eff = this._debugOverrides.get(key) ?? this._debugOverrides.get("*");
|
|
1620
|
+
if (eff !== void 0) threshold = eff;
|
|
1621
|
+
}
|
|
1622
|
+
if (sev > threshold) {
|
|
1623
|
+
this.gated++;
|
|
1624
|
+
if (this._gatedPdu === null) {
|
|
1625
|
+
this._gatedPdu = createPDU.call(this, "GATED", "DEBUG", this.settings.moduleName, msgid || this.settings.msgid);
|
|
1626
|
+
this._gatedPdu.status = "DROPPED";
|
|
1627
|
+
}
|
|
1628
|
+
return this._gatedPdu;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
let pdu;
|
|
1632
|
+
if (this.settings.rateLimit !== false) {
|
|
1633
|
+
const rate = this.settings.rateLimit;
|
|
1634
|
+
const now = Date.now();
|
|
1635
|
+
this.start = this.start || now;
|
|
1636
|
+
if (now > this.start + rate) {
|
|
1637
|
+
this.burstPrinted = 0;
|
|
1638
|
+
this.missed = 0;
|
|
1639
|
+
this.start = 0;
|
|
1640
|
+
}
|
|
1641
|
+
if (this.settings.burstLimit && this.settings.burstLimit > this.burstPrinted) {
|
|
1642
|
+
try {
|
|
1643
|
+
pdu = payload instanceof Pdu ? payload : createPDU.call(this, payload, severity, this.settings.moduleName, msgid || this.settings.msgid, msg);
|
|
1644
|
+
} catch (e) {
|
|
1645
|
+
console.error(e);
|
|
1646
|
+
this.invalid++;
|
|
1647
|
+
pdu = pdu ?? createPDU.call(this, e, "ERROR");
|
|
1648
|
+
pdu.status = "INVALID";
|
|
1649
|
+
return pdu;
|
|
1650
|
+
}
|
|
1651
|
+
this.pushStack(pdu);
|
|
1652
|
+
pdu.status = "ACCEPTED";
|
|
1653
|
+
if (this.listenerCount("onLog") > 0) this.fire("onLog", pdu);
|
|
1654
|
+
if (this._transports.length > 0) this._fireTransports(pdu);
|
|
1655
|
+
this.burstPrinted++;
|
|
1656
|
+
return pdu;
|
|
1657
|
+
}
|
|
1658
|
+
this.missed++;
|
|
1659
|
+
pdu = pdu ?? createPDU.call(this, "DROPPED", "WARNING");
|
|
1660
|
+
pdu.status = "DROPPED";
|
|
1661
|
+
return pdu;
|
|
1662
|
+
}
|
|
1663
|
+
try {
|
|
1664
|
+
pdu = payload instanceof Pdu ? payload : createPDU.call(this, payload, severity, this.settings.moduleName, msgid || this.settings.msgid, msg);
|
|
1665
|
+
} catch (e) {
|
|
1666
|
+
console.error(e);
|
|
1667
|
+
this.invalid++;
|
|
1668
|
+
pdu = pdu ?? createPDU.call(this, e, "ERROR");
|
|
1669
|
+
pdu.status = "INVALID";
|
|
1670
|
+
return pdu;
|
|
1671
|
+
}
|
|
1672
|
+
this.pushStack(pdu);
|
|
1673
|
+
pdu.status = "ACCEPTED";
|
|
1674
|
+
if (this.listenerCount("onLog") > 0) this.fire("onLog", pdu);
|
|
1675
|
+
if (this._transports.length > 0) this._fireTransports(pdu);
|
|
1676
|
+
return pdu;
|
|
1677
|
+
}
|
|
1678
|
+
getLogStack(start, end, condition) {
|
|
1679
|
+
if (arguments.length === 0) return this._ring.last();
|
|
1680
|
+
let stack;
|
|
1681
|
+
if (condition) stack = this.getLogs(condition);
|
|
1682
|
+
else stack = this.ringStack;
|
|
1683
|
+
if (!end) return stack.slice(start);
|
|
1684
|
+
if (start === end) return stack[stack.length - start - 1];
|
|
1685
|
+
return stack.slice(start, end);
|
|
1686
|
+
}
|
|
1687
|
+
getLogs(conditions, stack = null) {
|
|
1688
|
+
if (conditions) return wrapperCondition.call(this, conditions, stack || this.ringStack);
|
|
1689
|
+
return this.ringStack;
|
|
1690
|
+
}
|
|
1691
|
+
logToJson(conditions, stack = null) {
|
|
1692
|
+
const res = conditions ? this.getLogs(conditions, stack) : this.ringStack;
|
|
1693
|
+
return JSON.stringify(res);
|
|
1694
|
+
}
|
|
1695
|
+
loadStack(stack, doEvent = false, beforeConditions = null) {
|
|
1696
|
+
if (!stack) throw new Error("syslog loadStack : not stack in arguments ");
|
|
1697
|
+
if (typeof stack === "string") return this.loadStack(JSON.parse(stack), doEvent, beforeConditions);
|
|
1698
|
+
if (Array.isArray(stack) || typeof stack === "object") {
|
|
1699
|
+
for (const stackItem of stack) {
|
|
1700
|
+
const pdu = new Pdu(stackItem.payload, stackItem.severity, stackItem.moduleName || this.settings.moduleName, stackItem.msgid, stackItem.msg, stackItem.timeStamp);
|
|
1701
|
+
this.pushStack(pdu);
|
|
1702
|
+
if (doEvent) {
|
|
1703
|
+
if (beforeConditions) beforeConditions.call(this, pdu, stackItem);
|
|
1704
|
+
this.fire("onLog", pdu);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
return stack;
|
|
1708
|
+
}
|
|
1709
|
+
throw new Error("syslog loadStack : bad stack in arguments type");
|
|
1710
|
+
}
|
|
1711
|
+
filter(conditions, callback) {
|
|
1712
|
+
if (!conditions) throw new Error("filter conditions not found ");
|
|
1713
|
+
conditions = extend(true, {}, conditions);
|
|
1714
|
+
const wrapper = wrapperCondition.call(this, conditions, callback);
|
|
1715
|
+
if (wrapper) super.on("onLog", wrapper);
|
|
1716
|
+
}
|
|
1717
|
+
listenWithConditions(conditions, callback) {
|
|
1718
|
+
return this.filter(conditions, callback);
|
|
1719
|
+
}
|
|
1720
|
+
error(data) {
|
|
1721
|
+
return this.log(data, "ERROR");
|
|
1722
|
+
}
|
|
1723
|
+
warn(data) {
|
|
1724
|
+
return this.log(data, "WARNING");
|
|
1725
|
+
}
|
|
1726
|
+
info(data) {
|
|
1727
|
+
return this.log(data, "INFO");
|
|
1728
|
+
}
|
|
1729
|
+
debug(data) {
|
|
1730
|
+
return this.log(data, "DEBUG");
|
|
1731
|
+
}
|
|
1732
|
+
trace(data, ...args) {
|
|
1733
|
+
return this.log(data, "NOTICE", ...args);
|
|
1734
|
+
}
|
|
1735
|
+
print(...args) {
|
|
1736
|
+
const payload = args.length === 1 ? args[0] : args;
|
|
1737
|
+
return this.log(payload, this.settings.defaultSeverity);
|
|
1738
|
+
}
|
|
1739
|
+
logMultiple(severity, ...args) {
|
|
1740
|
+
const payload = args.length === 1 ? args[0] : args;
|
|
1741
|
+
return this.log(payload, severity);
|
|
1742
|
+
}
|
|
1743
|
+
addTransport(transport) {
|
|
1744
|
+
const idx = this._transports.findIndex((t) => t.name === transport.name);
|
|
1745
|
+
if (idx === -1) this._transports.push(transport);
|
|
1746
|
+
else if (this._transports[idx] !== transport) this._transports[idx] = transport;
|
|
1747
|
+
return this;
|
|
1748
|
+
}
|
|
1749
|
+
removeTransport(transport) {
|
|
1750
|
+
const idx = this._transports.indexOf(transport);
|
|
1751
|
+
if (idx !== -1) this._transports.splice(idx, 1);
|
|
1752
|
+
return this;
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Nombre de transports d'écriture branchés (introspection — data plane Studio,
|
|
1756
|
+
* tests d'idempotence). Lecture seule, 0 allocation.
|
|
1757
|
+
*/
|
|
1758
|
+
get transportCount() {
|
|
1759
|
+
return this._transports.length;
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Liste polymorphe des transports d'écriture — chaque entrée porte le `name` de
|
|
1763
|
+
* l'`ITransport` (`console`, `file`, `loki`, `syslog`…) et son état `enabled`.
|
|
1764
|
+
* C'est l'axe **WRITE** du Log Backplane : l'écriture est un **fan-out** (1 log →
|
|
1765
|
+
* N transports actifs), orthogonal à l'axe READ (1 driver queryable). Sert au data
|
|
1766
|
+
* plane Studio pour afficher les vraies destinations (et non les inférer des drivers
|
|
1767
|
+
* de relecture, ce qui masquait les transports write-only console/syslog/http).
|
|
1768
|
+
*
|
|
1769
|
+
* Inclut les transports désactivés à chaud (`enabled:false`) pour que l'UI puisse
|
|
1770
|
+
* les ré-activer. Chemin FROID (introspection admin) : alloue à l'appel, jamais
|
|
1771
|
+
* dans le hot path du log.
|
|
1772
|
+
*
|
|
1773
|
+
* @returns un tableau `{ name, enabled }` (montés `true` d'abord, puis désactivés).
|
|
1774
|
+
*/
|
|
1775
|
+
listTransports() {
|
|
1776
|
+
const out = this._transports.map((t) => ({
|
|
1777
|
+
name: t.name,
|
|
1778
|
+
enabled: true
|
|
1779
|
+
}));
|
|
1780
|
+
if (this._disabledTransports) for (const name of this._disabledTransports.keys()) out.push({
|
|
1781
|
+
name,
|
|
1782
|
+
enabled: false
|
|
1783
|
+
});
|
|
1784
|
+
return out;
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Active/désactive un transport d'écriture **à chaud, par nom** (outil dev /
|
|
1788
|
+
* diagnostic — ex. couper la console pour un bench, ou remonter un transport).
|
|
1789
|
+
* Désactiver = retirer le transport de la boucle de fire (réf gardée dans
|
|
1790
|
+
* {@link _disabledTransports}) → **0 surcoût hot path**. Activer = le remonter.
|
|
1791
|
+
*
|
|
1792
|
+
* Réversible et idempotent : un toggle vers l'état déjà courant renvoie `false`.
|
|
1793
|
+
* N'instancie RIEN : ne peut réactiver qu'un transport préalablement désactivé
|
|
1794
|
+
* (un transport jamais monté — ex. `loki` sans URL — exige sa config, pas ce toggle).
|
|
1795
|
+
*
|
|
1796
|
+
* @param name - `ITransport.name` ciblé.
|
|
1797
|
+
* @param enabled - `true` = remonter, `false` = retirer.
|
|
1798
|
+
* @returns `true` si l'état a changé, `false` sinon (déjà dans l'état / introuvable).
|
|
1799
|
+
*/
|
|
1800
|
+
setTransportEnabled(name, enabled) {
|
|
1801
|
+
if (enabled) {
|
|
1802
|
+
const t = this._disabledTransports?.get(name);
|
|
1803
|
+
if (!t) return false;
|
|
1804
|
+
this._disabledTransports.delete(name);
|
|
1805
|
+
if (this._disabledTransports.size === 0) this._disabledTransports = null;
|
|
1806
|
+
this.addTransport(t);
|
|
1807
|
+
return true;
|
|
1808
|
+
}
|
|
1809
|
+
const idx = this._transports.findIndex((t) => t.name === name);
|
|
1810
|
+
if (idx === -1) return false;
|
|
1811
|
+
const [t] = this._transports.splice(idx, 1);
|
|
1812
|
+
(this._disabledTransports ??= /* @__PURE__ */ new Map()).set(name, t);
|
|
1813
|
+
return true;
|
|
1814
|
+
}
|
|
1815
|
+
_fireTransports(pdu) {
|
|
1816
|
+
for (const t of this._transports) t.send(pdu).catch((err) => this.fire("onTransportError", err, pdu));
|
|
1817
|
+
}
|
|
1818
|
+
static _nativeConsole = {
|
|
1819
|
+
log: console.log.bind(console),
|
|
1820
|
+
info: console.info.bind(console),
|
|
1821
|
+
warn: console.warn.bind(console),
|
|
1822
|
+
error: console.error.bind(console),
|
|
1823
|
+
debug: console.debug.bind(console),
|
|
1824
|
+
trace: console.trace.bind(console),
|
|
1825
|
+
table: console.table.bind(console),
|
|
1826
|
+
dir: console.dir.bind(console)
|
|
1827
|
+
};
|
|
1828
|
+
static _savedConsole = null;
|
|
1829
|
+
/** Largeur fixe du champ `severityName` — couvre `WARNING` (7). */
|
|
1830
|
+
static SEVERITY_WIDTH = 7;
|
|
1831
|
+
/** Largeur fixe du champ `msgid` — couvre 95% des cas, déborde proprement pour les longs. */
|
|
1832
|
+
static MSGID_WIDTH = 18;
|
|
1833
|
+
static wrapper(pdu) {
|
|
1834
|
+
if (!pdu) throw new Error("Syslog pdu not defined");
|
|
1835
|
+
const d = new Date(pdu.timeStamp);
|
|
1836
|
+
const dateStr = `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}.${String(d.getMilliseconds()).padStart(3, "0")}`;
|
|
1837
|
+
const sev = pdu.severityName.padEnd(Syslog.SEVERITY_WIDTH);
|
|
1838
|
+
const id = pdu.msgid.padEnd(Syslog.MSGID_WIDTH);
|
|
1839
|
+
const msgid = green(id);
|
|
1840
|
+
switch (pdu.severity) {
|
|
1841
|
+
case 0:
|
|
1842
|
+
case 1:
|
|
1843
|
+
case 2:
|
|
1844
|
+
case 3: return {
|
|
1845
|
+
logger: Syslog._nativeConsole.error,
|
|
1846
|
+
text: `${dateStr} ${red(sev)} ${msgid} : `
|
|
1847
|
+
};
|
|
1848
|
+
case 4: return {
|
|
1849
|
+
logger: Syslog._nativeConsole.warn,
|
|
1850
|
+
text: `${dateStr} ${yellow(sev)} ${msgid} : `
|
|
1851
|
+
};
|
|
1852
|
+
case 5: return {
|
|
1853
|
+
logger: Syslog._nativeConsole.log,
|
|
1854
|
+
text: `${dateStr} ${red(sev)} ${msgid} : `
|
|
1855
|
+
};
|
|
1856
|
+
case 6: return {
|
|
1857
|
+
logger: Syslog._nativeConsole.info,
|
|
1858
|
+
text: `${dateStr} ${blue(sev)} ${msgid} : `
|
|
1859
|
+
};
|
|
1860
|
+
case 7: return {
|
|
1861
|
+
logger: Syslog._nativeConsole.debug,
|
|
1862
|
+
text: `${dateStr} ${cyan(sev)} ${msgid} : `
|
|
1863
|
+
};
|
|
1864
|
+
default: return {
|
|
1865
|
+
logger: Syslog._nativeConsole.log,
|
|
1866
|
+
text: `${dateStr} ${cyan(sev)} ${msgid} : `
|
|
1867
|
+
};
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Transport console par défaut — formate un Pdu et l'écrit vers `process.stdout` ou
|
|
1872
|
+
* `process.stderr` selon sévérité (ERROR+ vers stderr).
|
|
1873
|
+
*
|
|
1874
|
+
* Format : `HH:MM:SS.mmm SEVERITY MSGID : payload` avec coloration ANSI.
|
|
1875
|
+
*
|
|
1876
|
+
* @param pdu - Pdu à imprimer.
|
|
1877
|
+
* @param pid - PID préfixé (vide en dev mono-process pour réduire le bruit).
|
|
1878
|
+
* @returns le Pdu (chaînable).
|
|
1879
|
+
*/
|
|
1880
|
+
static normalizeLog(pdu, pid = "") {
|
|
1881
|
+
if (pdu.payload === "" || pdu.payload === void 0) {
|
|
1882
|
+
Syslog._nativeConsole.warn(`${pdu.severityName} ${pdu.msgid} : logger message empty !!!!`);
|
|
1883
|
+
Syslog._nativeConsole.trace(pdu);
|
|
1884
|
+
return pdu;
|
|
1885
|
+
}
|
|
1886
|
+
const message = pdu.payload;
|
|
1887
|
+
const wrap = Syslog.wrapper(pdu);
|
|
1888
|
+
const prefix = pid ? `${pid} ` : "";
|
|
1889
|
+
wrap.logger(`${prefix}${wrap.text}`, message);
|
|
1890
|
+
return pdu;
|
|
1891
|
+
}
|
|
1892
|
+
static rawLog(pdu, pid = "") {
|
|
1893
|
+
if (pdu.payload === "" || pdu.payload === void 0) return pdu;
|
|
1894
|
+
const write = pdu.severity <= 3 ? writeErr : writeOut;
|
|
1895
|
+
const { text } = Syslog.wrapper(pdu);
|
|
1896
|
+
const msg = typeof pdu.payload === "string" || typeof pdu.payload === "number" ? String(pdu.payload) : inspect(pdu.payload, {
|
|
1897
|
+
depth: 3,
|
|
1898
|
+
colors: isLogColorEnabled(),
|
|
1899
|
+
breakLength: Infinity
|
|
1900
|
+
});
|
|
1901
|
+
write(`${pid ? `${pid} ` : ""}${text}${msg}\n`);
|
|
1902
|
+
return pdu;
|
|
1903
|
+
}
|
|
1904
|
+
/**
|
|
1905
|
+
* Mode de bufférisation de la sortie console — **process-global** (un seul
|
|
1906
|
+
* `process.stdout`). Câblé par {@link Kernel.initializeLog} depuis `config.log.buffered`.
|
|
1907
|
+
*
|
|
1908
|
+
* - `"auto"` (défaut) : bufférise si stdout n'est PAS un TTY (pipe/fichier =
|
|
1909
|
+
* prod/collecteur → débit) ; immédiat sur TTY (dev interactif → feedback + spinner).
|
|
1910
|
+
* - `true` : toujours bufférisé (ex. bench dans un terminal).
|
|
1911
|
+
* - `false` : jamais (ex. `tail -f` non bufférisé en debug prod).
|
|
1912
|
+
*
|
|
1913
|
+
* Bufférisé = coalesce les écritures d'un même tick en 1 `write()` (1 syscall).
|
|
1914
|
+
* stderr (ERROR+) reste TOUJOURS immédiat. Flush les lignes en attente avant de switcher.
|
|
1915
|
+
*
|
|
1916
|
+
* @param mode - `true` | `false` | `"auto"`.
|
|
1917
|
+
*/
|
|
1918
|
+
static setOutputBuffering(mode) {
|
|
1919
|
+
_setBufferMode(mode);
|
|
1920
|
+
}
|
|
1921
|
+
/** Vide immédiatement (synchrone) le buffer stdout en attente. Idempotent. */
|
|
1922
|
+
static flushOutput() {
|
|
1923
|
+
_flushOut();
|
|
1924
|
+
}
|
|
1925
|
+
/**
|
|
1926
|
+
* Bascule le DRIVER de sink (LB.W — où partent les lignes après coalescing).
|
|
1927
|
+
* `null` → stdout (défaut isomorphe). Câblé par {@link Kernel.initializeLog}
|
|
1928
|
+
* depuis `config.log.driver`. Flush + close l'ancien driver avant de switcher.
|
|
1929
|
+
*
|
|
1930
|
+
* @param sink - driver `ILogSink` (ex. `FileSink`, `NULL_LOG_SINK`) ou `null`.
|
|
1931
|
+
*/
|
|
1932
|
+
static setLogSink(sink) {
|
|
1933
|
+
_setLogSink(sink);
|
|
1934
|
+
}
|
|
1935
|
+
/** Nom du driver de sink actif (`"stdout"` | `"null"` | `"file"` | custom). */
|
|
1936
|
+
static get logSinkName() {
|
|
1937
|
+
return _sink.name;
|
|
1938
|
+
}
|
|
1939
|
+
/** `true` si le sink texte écrit (non muté). Coupé = plus de console/fichier .log. */
|
|
1940
|
+
static get sinkEnabled() {
|
|
1941
|
+
return !_sinkMuted;
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1944
|
+
* Mute/démute le sink texte **à chaud, sans changer la config ni le driver**
|
|
1945
|
+
* (outil dev/diagnostic — ex. couper la console en `npx nodefony dev`). Le nom
|
|
1946
|
+
* du sink est préservé ; seul {@link sinkEnabled} bascule. Process-global (un seul
|
|
1947
|
+
* sink texte par process). Idempotent.
|
|
1948
|
+
*
|
|
1949
|
+
* @param enabled - `true` = le sink écrit ; `false` = mute (rien n'est écrit).
|
|
1950
|
+
* @returns `true` si l'état a changé.
|
|
1951
|
+
*/
|
|
1952
|
+
static setSinkEnabled(enabled) {
|
|
1953
|
+
const muted = !enabled;
|
|
1954
|
+
if (_sinkMuted === muted) return false;
|
|
1955
|
+
_sinkMuted = muted;
|
|
1956
|
+
return true;
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* Intercepte `console.log/warn/error/debug/info` → pipe vers le Syslog passé.
|
|
1960
|
+
*
|
|
1961
|
+
* **Side effect global** : modifie l'objet `console` du process. À utiliser avec parcimonie
|
|
1962
|
+
* (un seul appel par process). {@link restoreConsole} restaure les méthodes originales.
|
|
1963
|
+
*
|
|
1964
|
+
* @param instance - Syslog cible (recevra tous les console.* du process).
|
|
1965
|
+
*/
|
|
1966
|
+
static overrideConsole(instance) {
|
|
1967
|
+
if (Syslog._savedConsole !== null) {
|
|
1968
|
+
instance.log("Syslog.overrideConsole: already active", "WARNING");
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
Syslog._savedConsole = {
|
|
1972
|
+
log: console.log.bind(console),
|
|
1973
|
+
info: console.info.bind(console),
|
|
1974
|
+
warn: console.warn.bind(console),
|
|
1975
|
+
error: console.error.bind(console),
|
|
1976
|
+
debug: console.debug.bind(console),
|
|
1977
|
+
trace: console.trace.bind(console),
|
|
1978
|
+
table: console.table.bind(console),
|
|
1979
|
+
dir: console.dir.bind(console)
|
|
1980
|
+
};
|
|
1981
|
+
const con = console;
|
|
1982
|
+
con.log = (...data) => instance.print(...data);
|
|
1983
|
+
con.info = (...data) => instance.logMultiple("INFO", ...data);
|
|
1984
|
+
con.warn = (...data) => instance.logMultiple("WARNING", ...data);
|
|
1985
|
+
con.error = (...data) => instance.logMultiple("ERROR", ...data);
|
|
1986
|
+
con.debug = (...data) => instance.logMultiple("DEBUG", ...data);
|
|
1987
|
+
con.table = (data) => instance.logMultiple("INFO", data);
|
|
1988
|
+
con.dir = (obj) => instance.logMultiple("DEBUG", obj);
|
|
1989
|
+
}
|
|
1990
|
+
/**
|
|
1991
|
+
* Restaure `console.log/warn/error/debug/info` à leurs valeurs originales.
|
|
1992
|
+
* Annule un {@link overrideConsole} précédent.
|
|
1993
|
+
*/
|
|
1994
|
+
static restoreConsole() {
|
|
1995
|
+
if (Syslog._savedConsole === null) return;
|
|
1996
|
+
Object.assign(console, Syslog._savedConsole);
|
|
1997
|
+
Syslog._savedConsole = null;
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
typeof process !== "undefined" && process.env?.NF_PERF_PROBE;
|
|
2001
|
+
//#endregion
|
|
2002
|
+
//#region src/cli/completion.ts
|
|
2003
|
+
/** Chemin du manifest cache — même dossier que le pidfile superviseur. */
|
|
2004
|
+
function cliManifestFile(cwd) {
|
|
2005
|
+
return path.join(cwd, "node_modules", ".cache", "nodefony", "cli-manifest.json");
|
|
2006
|
+
}
|
|
2007
|
+
/** Lit le manifest cache — `null` si absent ou corrompu (jamais de throw). */
|
|
2008
|
+
function readCliManifest(cwd) {
|
|
2009
|
+
try {
|
|
2010
|
+
const raw = readFileSync(cliManifestFile(cwd), "utf8");
|
|
2011
|
+
const parsed = JSON.parse(raw);
|
|
2012
|
+
return Array.isArray(parsed.commands) ? parsed : null;
|
|
2013
|
+
} catch {
|
|
2014
|
+
return null;
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* Calcule les candidats de complétion pour les mots tapés.
|
|
2019
|
+
*
|
|
2020
|
+
* Protocole : `words` = tous les mots APRÈS le nom du binaire, dernier mot inclus
|
|
2021
|
+
* même vide (les scripts shell le transmettent tel quel). Le DERNIER mot est celui
|
|
2022
|
+
* en cours de frappe → la sélection de commande ne regarde que les mots VALIDÉS
|
|
2023
|
+
* (`slice(0, -1)`), et le shell filtre les candidats par le préfixe courant.
|
|
2024
|
+
*
|
|
2025
|
+
* - commande déjà validée → les CHOIX de l'argument positionnel en cours (s'il
|
|
2026
|
+
* en déclare, ex. `create` → `app`) + ses options + les options globales ;
|
|
2027
|
+
* - sinon → noms + alias de toutes les commandes.
|
|
2028
|
+
*/
|
|
2029
|
+
function computeCompletions(manifest, words) {
|
|
2030
|
+
const validated = words.slice(0, -1);
|
|
2031
|
+
for (let i = 0; i < validated.length; i++) {
|
|
2032
|
+
const w = validated[i];
|
|
2033
|
+
if (w.startsWith("-")) continue;
|
|
2034
|
+
const cmd = manifest.commands.find((c) => c.name === w || c.aliases.includes(w));
|
|
2035
|
+
if (cmd) {
|
|
2036
|
+
const after = validated.slice(i + 1);
|
|
2037
|
+
let pos = 0;
|
|
2038
|
+
for (let j = 0; j < after.length; j++) {
|
|
2039
|
+
if (after[j].startsWith("-")) continue;
|
|
2040
|
+
if (j > 0 && after[j - 1].startsWith("-")) continue;
|
|
2041
|
+
pos++;
|
|
2042
|
+
}
|
|
2043
|
+
const last = validated[validated.length - 1] ?? "";
|
|
2044
|
+
const expected = cmd.optionValues?.[last];
|
|
2045
|
+
if (expected) return expected;
|
|
2046
|
+
return [
|
|
2047
|
+
...cmd.args?.[pos] ?? [],
|
|
2048
|
+
...cmd.options,
|
|
2049
|
+
...manifest.globalOptions
|
|
2050
|
+
];
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
return manifest.commands.flatMap((c) => [c.name, ...c.aliases]);
|
|
2054
|
+
}
|
|
2055
|
+
/** Shells supportés par `nodefony completion <shell>`. */
|
|
2056
|
+
const COMPLETION_SHELLS = [
|
|
2057
|
+
"bash",
|
|
2058
|
+
"zsh",
|
|
2059
|
+
"fish"
|
|
2060
|
+
];
|
|
2061
|
+
`${COMPLETION_SHELLS.join("|")}`, `${COMPLETION_SHELLS.join("|")}`;
|
|
2062
|
+
//#endregion
|
|
2063
|
+
//#region src/runtime/engineEnvironment.ts
|
|
2064
|
+
/**
|
|
2065
|
+
* Le mode qu'une ligne de commande EXPRIME — détecté avant tout kernel.
|
|
2066
|
+
*
|
|
2067
|
+
* Pourquoi en amont : commander ne parse la sous-commande qu'au démarrage du
|
|
2068
|
+
* kernel, si bien que `this.environment` reste indéfini pendant les premières
|
|
2069
|
+
* lignes du boot. Plusieurs branches en dépendent, et elles ratent sans cette
|
|
2070
|
+
* pré-détection. Une commande non reconnue rend `undefined`, et le défaut
|
|
2071
|
+
* reprend la main.
|
|
2072
|
+
*
|
|
2073
|
+
* 🔴 **Seuls les mots de COMMANDE sont examinés — ceux qui précèdent la première
|
|
2074
|
+
* option.** La version précédente balayait l'argv ENTIER : n'importe quel mot,
|
|
2075
|
+
* où qu'il soit, décidait du mode. `nodefony doctor --env production` faisait
|
|
2076
|
+
* ainsi basculer tout le processus en production — il chargeait `.env.production`
|
|
2077
|
+
* et les modules de production pour répondre à une question sur le poste, et le
|
|
2078
|
+
* catalogue de l'application, refusant de se construire, retombait en silence
|
|
2079
|
+
* sur une version périmée. Un argument de valeur n'est pas une intention.
|
|
2080
|
+
*
|
|
2081
|
+
* Vit ici plutôt que dans le binaire : ce module est la source unique de « quel
|
|
2082
|
+
* mode », il est importable, et une règle qu'on ne peut pas importer est une
|
|
2083
|
+
* règle qu'on ne peut pas éprouver.
|
|
2084
|
+
*
|
|
2085
|
+
* @param argv - les arguments APRÈS le binaire (`process.argv.slice(2)`).
|
|
2086
|
+
* @returns le mode exprimé par la commande, ou `undefined` si elle n'en exprime aucun.
|
|
2087
|
+
*/
|
|
2088
|
+
function detectEnvironmentFromArgv(argv) {
|
|
2089
|
+
for (const a of argv) {
|
|
2090
|
+
if (a.startsWith("-")) break;
|
|
2091
|
+
if (a === "development" || a === "dev") return "development";
|
|
2092
|
+
if (a === "production" || a === "prod" || a === "start") return "production";
|
|
2093
|
+
if (a === "cluster") return "production";
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
//#endregion
|
|
2097
|
+
//#region src/bin/nodefony.ts
|
|
2098
|
+
/**
|
|
2099
|
+
* Résout le **mode runtime** (dev/prod) AVANT le kernel : `NODE_ENV` (ambiant)
|
|
2100
|
+
* PRIME sur l'intention de la commande (argv).
|
|
2101
|
+
*
|
|
2102
|
+
* ⚠️ **Ce n'est pas « le 12-factor » qui l'impose, et l'écrire était faux.** Sa
|
|
2103
|
+
* section *Config* REJETTE au contraire les groupes d'environnement : « In a
|
|
2104
|
+
* twelve-factor app, env vars are granular controls […] They are never grouped
|
|
2105
|
+
* together as "environments" ». `NODE_ENV` est précisément ce qu'elle
|
|
2106
|
+
* déconseille. Ce qui relève d'elle ici est la seule PRÉCÉDENCE — la
|
|
2107
|
+
* configuration ambiante l'emporte sur ce que la commande croit savoir.
|
|
2108
|
+
*
|
|
2109
|
+
* Ce qui garantit le mode en production est FACTUEL : Node.js le recommande
|
|
2110
|
+
* (« Always run your Node.js with NODE_ENV=production set »), l'image générée
|
|
2111
|
+
* pose `ENV NODE_ENV=production`, et les lanceurs déclarent leur intention. Miroir pur de `Kernel.resolveRuntimeEnv`, mais sans instance (le bin tourne
|
|
2112
|
+
* avant `new CliKernel()`) et autorisé à rendre `undefined` (aucun `.env.<env>` chargé
|
|
2113
|
+
* si ni NODE_ENV ni commande connue — ex. `nodefony frontend:build` hors contexte env).
|
|
2114
|
+
*/
|
|
2115
|
+
function resolveRuntimeEnv(argv) {
|
|
2116
|
+
const node = process.env.NODE_ENV;
|
|
2117
|
+
if (node === "dev" || node === "development") return "development";
|
|
2118
|
+
if (node === "prod" || node === "production") return "production";
|
|
2119
|
+
return detectEnvironmentFromArgv(argv);
|
|
2120
|
+
}
|
|
2121
|
+
/** Trace la décision du lanceur (opt-in `NF_CLI_DEBUG=1`, jamais par défaut). */
|
|
2122
|
+
function traceDecision(decision, selfDir) {
|
|
2123
|
+
if (!process.env[DEBUG_ENV]) return;
|
|
2124
|
+
const target = decision.delegate ?? `${selfDir} (soi-même — ${decision.reason})`;
|
|
2125
|
+
process.stderr.write(`[nodefony] cli → ${target}\n`);
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Boote le CLI de CE paquet. Les imports du core sont **dynamiques** : quand le
|
|
2129
|
+
* lanceur délègue à l'app, le core de ce paquet-ci ne doit jamais être chargé
|
|
2130
|
+
* (sinon deux frameworks en mémoire, et le coût de boot payé deux fois).
|
|
2131
|
+
*/
|
|
2132
|
+
async function runSelf() {
|
|
2133
|
+
if (process.argv[2] === "__complete") try {
|
|
2134
|
+
const cached = readCliManifest(process.cwd());
|
|
2135
|
+
if (cached) {
|
|
2136
|
+
const sep = process.argv.indexOf("--");
|
|
2137
|
+
const candidates = computeCompletions(cached, sep >= 0 ? process.argv.slice(sep + 1) : []);
|
|
2138
|
+
if (candidates.length > 0) process.stdout.write(`${candidates.join("\n")}\n`);
|
|
2139
|
+
return exit(0);
|
|
2140
|
+
}
|
|
2141
|
+
} catch {}
|
|
2142
|
+
const { CliKernel, loadEnv } = await import("nodefony");
|
|
2143
|
+
const runtimeEnv = resolveRuntimeEnv(process.argv.slice(2));
|
|
2144
|
+
const appEnv = process.env.APP_ENV ?? process.env.NF_ENV;
|
|
2145
|
+
if (runtimeEnv) process.env.NODE_ENV = runtimeEnv;
|
|
2146
|
+
loadEnv({
|
|
2147
|
+
runtimeEnv,
|
|
2148
|
+
appEnv
|
|
2149
|
+
});
|
|
2150
|
+
return new CliKernel(runtimeEnv).start().catch((e) => {
|
|
2151
|
+
exit(e.code || 1);
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
/**
|
|
2155
|
+
* Point d'entrée du binaire `nodefony` — **le CLI de l'application prime**.
|
|
2156
|
+
*
|
|
2157
|
+
* Le binaire global (`npm i -g nodefony`) est la porte d'entrée du framework : il
|
|
2158
|
+
* crée les applications. Mais une fois DANS une app, la version qui fait autorité
|
|
2159
|
+
* est celle des `node_modules` du projet : c'est elle qui connaît ses modules, ses
|
|
2160
|
+
* scaffolds et ses commandes. Le lanceur remonte donc au projet et, s'il y trouve
|
|
2161
|
+
* un autre paquet `nodefony` que lui-même, lui passe la main (`import` du binaire
|
|
2162
|
+
* du projet, dans le même process — ni spawn, ni double kernel).
|
|
2163
|
+
*
|
|
2164
|
+
* Une install cassée (paquet présent, binaire absent) échoue **bruyamment** : on ne
|
|
2165
|
+
* pilote pas une app avec une version de framework qu'elle n'a pas choisie.
|
|
2166
|
+
*/
|
|
2167
|
+
const selfDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
2168
|
+
const decision = resolveLocalCli({
|
|
2169
|
+
cwd: process.cwd(),
|
|
2170
|
+
selfDir,
|
|
2171
|
+
env: process.env
|
|
2172
|
+
});
|
|
2173
|
+
traceDecision(decision, selfDir);
|
|
2174
|
+
if (decision.reason === "local-cli-broken") {
|
|
2175
|
+
process.stderr.write(`nodefony: ${decision.detail}\n (projet : ${decision.projectRoot})\n`);
|
|
2176
|
+
exit(1);
|
|
2177
|
+
}
|
|
2178
|
+
let kernel;
|
|
2179
|
+
if (decision.delegate) {
|
|
2180
|
+
process.env[DELEGATED_ENV] = "1";
|
|
2181
|
+
kernel = await import(pathToFileURL(decision.delegate).href);
|
|
2182
|
+
} else kernel = await runSelf();
|
|
2183
|
+
var nodefony_default = kernel;
|
|
2184
|
+
//#endregion
|
|
2185
|
+
export { nodefony_default as default };
|