[{"data":1,"prerenderedAt":663},["ShallowReactive",2],{"docs-nav:fr":3,"docs:\u002Ffr\u002Fdocs\u002Fbusiness\u002Fcollectors":189},[4],{"title":5,"path":6,"stem":7,"children":8,"page":52},"Fr","\u002Ffr","fr",[9],{"title":10,"path":11,"stem":12,"children":13},"Qu'est-ce que Fougere","\u002Ffr\u002Fdocs","fr\u002Fdocs\u002Findex",[14,15,19,23,27,31,53,78,123,148],{"title":10,"path":11,"stem":12},{"title":16,"path":17,"stem":18},"Démarrer","\u002Ffr\u002Fdocs\u002Fgetting-started","fr\u002Fdocs\u002F01.getting-started",{"title":20,"path":21,"stem":22},"Une app que vous avez déjà","\u002Ffr\u002Fdocs\u002Fexisting-app","fr\u002Fdocs\u002F02.existing-app",{"title":24,"path":25,"stem":26},"Apportez votre schéma","\u002Ffr\u002Fdocs\u002Fbring-your-schema","fr\u002Fdocs\u002F03.bring-your-schema",{"title":28,"path":29,"stem":30},"La CLI","\u002Ffr\u002Fdocs\u002Fcli","fr\u002Fdocs\u002F04.cli",{"title":32,"path":33,"stem":34,"children":35,"page":52},"Concepts","\u002Ffr\u002Fdocs\u002Fconcepts","fr\u002Fdocs\u002F2.concepts",[36,40,44,48],{"title":37,"path":38,"stem":39},"Philosophie","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fphilosophy","fr\u002Fdocs\u002F2.concepts\u002F1.philosophy",{"title":41,"path":42,"stem":43},"La Frond","\u002Ffr\u002Fdocs\u002Fconcepts\u002Ffrond","fr\u002Fdocs\u002F2.concepts\u002F2.frond",{"title":45,"path":46,"stem":47},"Le chemin le plus court","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fshortest-path","fr\u002Fdocs\u002F2.concepts\u002F3.shortest-path",{"title":49,"path":50,"stem":51},"Le socle","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fthe-base","fr\u002Fdocs\u002F2.concepts\u002F4.the-base",false,{"title":54,"path":55,"stem":56,"children":57,"page":52},"Schéma","\u002Ffr\u002Fdocs\u002Fschema","fr\u002Fdocs\u002F3.schema",[58,62,66,70,74],{"title":59,"path":60,"stem":61},"Entités","\u002Ffr\u002Fdocs\u002Fschema\u002Fentities","fr\u002Fdocs\u002F3.schema\u002F1.entities",{"title":63,"path":64,"stem":65},"Vues","\u002Ffr\u002Fdocs\u002Fschema\u002Fviews","fr\u002Fdocs\u002F3.schema\u002F2.views",{"title":67,"path":68,"stem":69},"La carte d'identité","\u002Ffr\u002Fdocs\u002Fschema\u002Fcard","fr\u002Fdocs\u002F3.schema\u002F3.card",{"title":71,"path":72,"stem":73},"Standard Schema","\u002Ffr\u002Fdocs\u002Fschema\u002Fstandard-schema","fr\u002Fdocs\u002F3.schema\u002F4.standard-schema",{"title":75,"path":76,"stem":77},"Comment un schéma bouge","\u002Ffr\u002Fdocs\u002Fschema\u002Fevolution","fr\u002Fdocs\u002F3.schema\u002F5.evolution",{"title":79,"path":80,"stem":81,"children":82,"page":52},"Métier","\u002Ffr\u002Fdocs\u002Fbusiness","fr\u002Fdocs\u002F4.business",[83,87,91,95,99,103,107,111,115,119],{"title":84,"path":85,"stem":86},"Handlers","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fhandlers","fr\u002Fdocs\u002F4.business\u002F1.handlers",{"title":88,"path":89,"stem":90},"Les ports","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fports","fr\u002Fdocs\u002F4.business\u002F10.ports",{"title":92,"path":93,"stem":94},"Presenters","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fpresenters","fr\u002Fdocs\u002F4.business\u002F2.presenters",{"title":96,"path":97,"stem":98},"Collectors","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fcollectors","fr\u002Fdocs\u002F4.business\u002F3.collectors",{"title":100,"path":101,"stem":102},"Erreurs","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ferrors","fr\u002Fdocs\u002F4.business\u002F4.errors",{"title":104,"path":105,"stem":106},"Seeds","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fseeds","fr\u002Fdocs\u002F4.business\u002F5.seeds",{"title":108,"path":109,"stem":110},"Les faits","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ffacts","fr\u002Fdocs\u002F4.business\u002F6.facts",{"title":112,"path":113,"stem":114},"Le port Storage","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fstorage","fr\u002Fdocs\u002F4.business\u002F7.storage",{"title":116,"path":117,"stem":118},"Des écritures qui tiennent ou tombent ensemble","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ftogether","fr\u002Fdocs\u002F4.business\u002F8.together",{"title":120,"path":121,"stem":122},"Les repositories","\u002Ffr\u002Fdocs\u002Fbusiness\u002Frepositories","fr\u002Fdocs\u002F4.business\u002F9.repositories",{"title":124,"path":125,"stem":126,"children":127,"page":52},"Client","\u002Ffr\u002Fdocs\u002Fclient","fr\u002Fdocs\u002F5.client",[128,132,136,140,144],{"title":129,"path":130,"stem":131},"Queries & commands","\u002Ffr\u002Fdocs\u002Fclient\u002Fqueries-commands","fr\u002Fdocs\u002F5.client\u002F1.queries-commands",{"title":133,"path":134,"stem":135},"Formulaires","\u002Ffr\u002Fdocs\u002Fclient\u002Fforms","fr\u002Fdocs\u002F5.client\u002F2.forms",{"title":137,"path":138,"stem":139},"Session","\u002Ffr\u002Fdocs\u002Fclient\u002Fsession","fr\u002Fdocs\u002F5.client\u002F3.session",{"title":141,"path":142,"stem":143},"invoke","\u002Ffr\u002Fdocs\u002Fclient\u002Finvoke","fr\u002Fdocs\u002F5.client\u002F4.invoke",{"title":145,"path":146,"stem":147},"Back-office","\u002Ffr\u002Fdocs\u002Fclient\u002Fadmin","fr\u002Fdocs\u002F5.client\u002F5.admin",{"title":149,"path":150,"stem":151,"children":152,"page":52},"Infrastructure","\u002Ffr\u002Fdocs\u002Finfra","fr\u002Fdocs\u002F6.infra",[153,157,161,165,169,173,177,181,185],{"title":154,"path":155,"stem":156},"Le gradient","\u002Ffr\u002Fdocs\u002Finfra\u002Fgradient","fr\u002Fdocs\u002F6.infra\u002F1.gradient",{"title":158,"path":159,"stem":160},"Surfaces — REST & GraphQL","\u002Ffr\u002Fdocs\u002Finfra\u002Fsurfaces","fr\u002Fdocs\u002F6.infra\u002F2.surfaces",{"title":162,"path":163,"stem":164},"Déploiement","\u002Ffr\u002Fdocs\u002Finfra\u002Fdeployment","fr\u002Fdocs\u002F6.infra\u002F3.deployment",{"title":166,"path":167,"stem":168},"Hôtes","\u002Ffr\u002Fdocs\u002Finfra\u002Fhosts","fr\u002Fdocs\u002F6.infra\u002F4.hosts",{"title":170,"path":171,"stem":172},"Les sources","\u002Ffr\u002Fdocs\u002Finfra\u002Fsources","fr\u002Fdocs\u002F6.infra\u002F5.sources",{"title":174,"path":175,"stem":176},"Le cycle de vie","\u002Ffr\u002Fdocs\u002Finfra\u002Flifecycle","fr\u002Fdocs\u002F6.infra\u002F6.lifecycle",{"title":178,"path":179,"stem":180},"L'identité entre Fronds","\u002Ffr\u002Fdocs\u002Finfra\u002Fidentity","fr\u002Fdocs\u002F6.infra\u002F7.identity",{"title":182,"path":183,"stem":184},"Observabilité","\u002Ffr\u002Fdocs\u002Finfra\u002Fobservability","fr\u002Fdocs\u002F6.infra\u002F8.observability",{"title":186,"path":187,"stem":188},"Tests","\u002Ffr\u002Fdocs\u002Finfra\u002Ftesting","fr\u002Fdocs\u002F6.infra\u002F9.testing",{"id":190,"title":96,"body":191,"description":658,"extension":659,"meta":660,"navigation":304,"path":97,"seo":661,"stem":98,"__hash__":662},"docs_fr\u002Ffr\u002Fdocs\u002F4.business\u002F3.collectors.md",{"type":192,"value":193,"toc":653},"minimark",[194,198,207,436,439,515,520,572,576,586,590,593,623,636,642,649],[195,196,96],"h1",{"id":197},"collectors",[199,200,201,202,206],"p",{},"Un collector résout un paramètre de handler ",[203,204,205],"strong",{},"par son type"," à partir du contexte\nd'invocation. Les opérations qui déclarent ce paramètre reçoivent la valeur automatiquement.",[208,209,214],"pre",{"className":210,"code":211,"language":212,"meta":213,"style":213},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","import { Collector } from '@fougere\u002Fcore';\nimport type { InvocationContext } from '@fougere\u002Fcore';\nimport User from '..\u002F..\u002Fuser\u002Fentities\u002FUser.js';\n\n\u002F**\n * Le middleware auth pose l'user de session sur ctx.state.user —\n * ceci le fait remonter à tout handler qui déclare `user?: User`.\n *\u002F\nexport default class CurrentUserCollector extends Collector(User) {\n  async collect(ctx: InvocationContext) {\n    return ctx.state.user as User | undefined;\n  }\n}\n","ts","",[215,216,217,254,279,299,306,313,319,325,331,360,389,424,430],"code",{"__ignoreMap":213},[218,219,222,226,230,234,237,240,244,248,251],"span",{"class":220,"line":221},"line",1,[218,223,225],{"class":224},"sVHd0","import",[218,227,229],{"class":228},"sP7_E"," {",[218,231,233],{"class":232},"su5hD"," Collector",[218,235,236],{"class":228}," }",[218,238,239],{"class":224}," from",[218,241,243],{"class":242},"sjJ54"," '",[218,245,247],{"class":246},"s_sjI","@fougere\u002Fcore",[218,249,250],{"class":242},"'",[218,252,253],{"class":228},";\n",[218,255,257,259,262,264,267,269,271,273,275,277],{"class":220,"line":256},2,[218,258,225],{"class":224},[218,260,261],{"class":224}," type",[218,263,229],{"class":228},[218,265,266],{"class":232}," InvocationContext",[218,268,236],{"class":228},[218,270,239],{"class":224},[218,272,243],{"class":242},[218,274,247],{"class":246},[218,276,250],{"class":242},[218,278,253],{"class":228},[218,280,282,284,287,290,292,295,297],{"class":220,"line":281},3,[218,283,225],{"class":224},[218,285,286],{"class":232}," User ",[218,288,289],{"class":224},"from",[218,291,243],{"class":242},[218,293,294],{"class":246},"..\u002F..\u002Fuser\u002Fentities\u002FUser.js",[218,296,250],{"class":242},[218,298,253],{"class":228},[218,300,302],{"class":220,"line":301},4,[218,303,305],{"emptyLinePlaceholder":304},true,"\n",[218,307,309],{"class":220,"line":308},5,[218,310,312],{"class":311},"sutJx","\u002F**\n",[218,314,316],{"class":220,"line":315},6,[218,317,318],{"class":311}," * Le middleware auth pose l'user de session sur ctx.state.user —\n",[218,320,322],{"class":220,"line":321},7,[218,323,324],{"class":311}," * ceci le fait remonter à tout handler qui déclare `user?: User`.\n",[218,326,328],{"class":220,"line":327},8,[218,329,330],{"class":311}," *\u002F\n",[218,332,334,337,340,344,348,351,354,357],{"class":220,"line":333},9,[218,335,336],{"class":224},"export",[218,338,339],{"class":224}," default",[218,341,343],{"class":342},"sbsja"," class",[218,345,347],{"class":346},"sbgvK"," CurrentUserCollector",[218,349,350],{"class":342}," extends",[218,352,233],{"class":353},"sGLFI",[218,355,356],{"class":232},"(User) ",[218,358,359],{"class":228},"{\n",[218,361,363,366,370,373,377,381,383,386],{"class":220,"line":362},10,[218,364,365],{"class":342},"  async",[218,367,369],{"class":368},"sVXei"," collect",[218,371,372],{"class":228},"(",[218,374,376],{"class":375},"s99_P","ctx",[218,378,380],{"class":379},"smGrS",":",[218,382,266],{"class":346},[218,384,385],{"class":228},")",[218,387,388],{"class":228}," {\n",[218,390,392,395,398,401,404,406,409,412,415,418,422],{"class":220,"line":391},11,[218,393,394],{"class":224},"    return",[218,396,397],{"class":232}," ctx",[218,399,400],{"class":228},".",[218,402,403],{"class":232},"state",[218,405,400],{"class":228},[218,407,408],{"class":232},"user",[218,410,411],{"class":224}," as",[218,413,414],{"class":346}," User",[218,416,417],{"class":379}," |",[218,419,421],{"class":420},"sZMiF"," undefined",[218,423,253],{"class":228},[218,425,427],{"class":220,"line":426},12,[218,428,429],{"class":228},"  }\n",[218,431,433],{"class":220,"line":432},13,[218,434,435],{"class":228},"}\n",[199,437,438],{},"Dès lors, dans n'importe quel handler de la Frond :",[208,440,442],{"className":210,"code":441,"language":212,"meta":213,"style":213},"async mine(user?: User): Promise\u003CPost[]> { … }\nasync publish(id: string, user?: User): Promise\u003CPost> { … }\n",[215,443,444,480],{"__ignoreMap":213},[218,445,446,449,452,455,458,461,464,467,470,473,475,478],{"class":220,"line":221},[218,447,448],{"class":232},"async ",[218,450,451],{"class":353},"mine",[218,453,454],{"class":232},"(user",[218,456,457],{"class":379},"?:",[218,459,460],{"class":232}," User): ",[218,462,463],{"class":420},"Promise",[218,465,466],{"class":379},"\u003C",[218,468,469],{"class":232},"Post[]",[218,471,472],{"class":379},">",[218,474,229],{"class":228},[218,476,477],{"class":232}," … ",[218,479,435],{"class":228},[218,481,482,484,487,490,493,496,498,500,502,504,507,509,511,513],{"class":220,"line":256},[218,483,448],{"class":232},[218,485,486],{"class":353},"publish",[218,488,489],{"class":232},"(id: string",[218,491,492],{"class":228},",",[218,494,495],{"class":232}," user",[218,497,457],{"class":379},[218,499,460],{"class":232},[218,501,463],{"class":420},[218,503,466],{"class":379},[218,505,506],{"class":232},"Post",[218,508,472],{"class":379},[218,510,229],{"class":228},[218,512,477],{"class":232},[218,514,435],{"class":228},[516,517,519],"h2",{"id":518},"règles-de-résolution","Règles de résolution",[521,522,523,547,554,569],"ul",{},[524,525,526,527,530,531,534,535,538,539,542,543,546],"li",{},"Le match est ",[203,528,529],{},"par type résolu"," : ",[215,532,533],{},"Collector(User)"," résout ",[215,536,537],{},"user?: User",",\n",[215,540,541],{},"user: User | undefined"," et les alias qui ont le même sens. La classe s'enregistre\ncomme ",[215,544,545],{},"UserCollector"," par convention.",[524,548,549,550,553],{},"La cible n'a pas besoin de schéma. Rien ne lit ses champs, donc une classe ordinaire\nsuffit — ",[215,551,552],{},"Collector(Ability)"," pour une valeur construite depuis l'état à chaque appel.",[524,555,556,562,563,565,566,400],{},[203,557,558,559,400],{},"L'absence est ",[215,560,561],{},"undefined"," Préférez la forme concise ",[215,564,537],{},". Le type checker\nrésout aussi un alias comme ",[215,567,568],{},"type CurrentUser = User | undefined",[524,570,571],{},"Les collectors sont des classes injectables — déclarez des dépendances de constructeur\ncomme d'habitude.",[516,573,575],{"id":574},"le-state-et-le-gradient","Le state et le gradient",[199,577,578,581,582,585],{},[215,579,580],{},"ctx.state"," est l'état de requête construit par l'application consommatrice, par exemple à\npartir de la session. Lors d'un appel distant, cet état est transmis avec l'invocation :\nle collector reçoit le même ",[215,583,584],{},"ctx.state.user"," qu'en local.",[516,587,589],{"id":588},"un-collector-ne-franchit-pas-la-frontière-dune-frond","Un collector ne franchit pas la frontière d'une Frond",[199,591,592],{},"Placez le collector dans chaque Frond qui le consomme. Ce qui arrive sinon mérite d'être\ndit précisément, parce que ce n'est ni « plus tard » ni « rien » :",[521,594,595,606],{},[524,596,597,600,601,605],{},[203,598,599],{},"ce n'est pas au moment du split."," La liaison est décidée au démarrage, dans un seul\nprocessus, à partir des collectors ",[602,603,604],"em",{},"de la Frond elle-même"," ;",[524,607,608,611,612,615,616,619,620,400],{},[203,609,610],{},"le paramètre n'est pas vide."," Un type que la Frond ne sait pas résoudre tombe dans la\nquatrième règle de binding, ",[215,613,614],{},"body",". Le handler reçoit donc ",[203,617,618],{},"le corps de la requête"," là\noù il attend un ",[215,621,622],{},"User",[199,624,625,626,628,629,631,632,635],{},"Autrement dit, ",[215,627,537],{}," déclaré dans une Frond qui n'a pas de ",[215,630,545],{},"\nreçoit ce que le client a envoyé. Un handler qui juge sur ",[215,633,634],{},"user.role"," juge sur une valeur\nfournie par l'appelant.",[637,638,639],"blockquote",{},[199,640,641],{},"Une version précédente de cette page disait que le collector était « perdu après une\nséparation de processus ». C'était faux deux fois, et la réalité est moins confortable.",[199,643,644,645,648],{},"Suite : ",[646,647,100],"a",{"href":101}," — les erreurs typées entre les couches.",[650,651,652],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":213,"searchDepth":256,"depth":256,"links":654},[655,656,657],{"id":518,"depth":256,"text":519},{"id":574,"depth":256,"text":575},{"id":588,"depth":256,"text":589},"Résoudre les paramètres de handler par type depuis le contexte d'invocation.","md",{},{"title":96,"description":658},"6rBd4Oq_oMSWPc_qlB5-_Lmx3jE0wWzY1xPmNlhaMTY",1788598419239]