[{"data":1,"prerenderedAt":615},["ShallowReactive",2],{"docs-nav:en":3,"docs:\u002Fdocs\u002Fbusiness\u002Fcollectors":134},[4],{"title":5,"path":6,"stem":7,"children":8},"Docs","\u002Fdocs","docs",[9,12,16,20,24,42,63,92,113],{"title":10,"path":6,"stem":11},"What is Fougere","docs\u002Findex",{"title":13,"path":14,"stem":15},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started",{"title":17,"path":18,"stem":19},"Existing Nuxt app","\u002Fdocs\u002Fexisting-app","docs\u002F02.existing-app",{"title":21,"path":22,"stem":23},"The CLI","\u002Fdocs\u002Fcli","docs\u002F03.cli",{"title":25,"path":26,"stem":27,"children":28,"page":41},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F2.concepts",[29,33,37],{"title":30,"path":31,"stem":32},"Philosophy","\u002Fdocs\u002Fconcepts\u002Fphilosophy","docs\u002F2.concepts\u002F1.philosophy",{"title":34,"path":35,"stem":36},"The Frond","\u002Fdocs\u002Fconcepts\u002Ffrond","docs\u002F2.concepts\u002F2.frond",{"title":38,"path":39,"stem":40},"The shortest path","\u002Fdocs\u002Fconcepts\u002Fshortest-path","docs\u002F2.concepts\u002F3.shortest-path",false,{"title":43,"path":44,"stem":45,"children":46,"page":41},"Schema","\u002Fdocs\u002Fschema","docs\u002F3.schema",[47,51,55,59],{"title":48,"path":49,"stem":50},"Entities","\u002Fdocs\u002Fschema\u002Fentities","docs\u002F3.schema\u002F1.entities",{"title":52,"path":53,"stem":54},"Views","\u002Fdocs\u002Fschema\u002Fviews","docs\u002F3.schema\u002F2.views",{"title":56,"path":57,"stem":58},"The identity card","\u002Fdocs\u002Fschema\u002Fcard","docs\u002F3.schema\u002F3.card",{"title":60,"path":61,"stem":62},"Standard Schema","\u002Fdocs\u002Fschema\u002Fstandard-schema","docs\u002F3.schema\u002F4.standard-schema",{"title":64,"path":65,"stem":66,"children":67,"page":41},"Business","\u002Fdocs\u002Fbusiness","docs\u002F4.business",[68,72,76,80,84,88],{"title":69,"path":70,"stem":71},"Handlers","\u002Fdocs\u002Fbusiness\u002Fhandlers","docs\u002F4.business\u002F1.handlers",{"title":73,"path":74,"stem":75},"Presenters","\u002Fdocs\u002Fbusiness\u002Fpresenters","docs\u002F4.business\u002F2.presenters",{"title":77,"path":78,"stem":79},"Collectors","\u002Fdocs\u002Fbusiness\u002Fcollectors","docs\u002F4.business\u002F3.collectors",{"title":81,"path":82,"stem":83},"Errors","\u002Fdocs\u002Fbusiness\u002Ferrors","docs\u002F4.business\u002F4.errors",{"title":85,"path":86,"stem":87},"Seeds","\u002Fdocs\u002Fbusiness\u002Fseeds","docs\u002F4.business\u002F5.seeds",{"title":89,"path":90,"stem":91},"Facts","\u002Fdocs\u002Fbusiness\u002Ffacts","docs\u002F4.business\u002F6.facts",{"title":93,"path":94,"stem":95,"children":96,"page":41},"Client","\u002Fdocs\u002Fclient","docs\u002F5.client",[97,101,105,109],{"title":98,"path":99,"stem":100},"Queries & commands","\u002Fdocs\u002Fclient\u002Fqueries-commands","docs\u002F5.client\u002F1.queries-commands",{"title":102,"path":103,"stem":104},"Forms","\u002Fdocs\u002Fclient\u002Fforms","docs\u002F5.client\u002F2.forms",{"title":106,"path":107,"stem":108},"Session","\u002Fdocs\u002Fclient\u002Fsession","docs\u002F5.client\u002F3.session",{"title":110,"path":111,"stem":112},"invoke","\u002Fdocs\u002Fclient\u002Finvoke","docs\u002F5.client\u002F4.invoke",{"title":114,"path":115,"stem":116,"children":117,"page":41},"Infrastructure","\u002Fdocs\u002Finfra","docs\u002F6.infra",[118,122,126,130],{"title":119,"path":120,"stem":121},"The gradient","\u002Fdocs\u002Finfra\u002Fgradient","docs\u002F6.infra\u002F1.gradient",{"title":123,"path":124,"stem":125},"Surfaces — REST & GraphQL","\u002Fdocs\u002Finfra\u002Fsurfaces","docs\u002F6.infra\u002F2.surfaces",{"title":127,"path":128,"stem":129},"Deployment","\u002Fdocs\u002Finfra\u002Fdeployment","docs\u002F6.infra\u002F3.deployment",{"title":131,"path":132,"stem":133},"Hosts","\u002Fdocs\u002Finfra\u002Fhosts","docs\u002F6.infra\u002F4.hosts",{"id":135,"title":77,"body":136,"description":610,"extension":611,"meta":612,"navigation":249,"path":78,"seo":613,"stem":79,"__hash__":614},"docs_en\u002Fdocs\u002F4.business\u002F3.collectors.md",{"type":137,"value":138,"toc":605},"minimark",[139,143,152,393,396,476,481,525,529,539,543,546,575,588,594,601],[140,141,77],"h1",{"id":142},"collectors",[144,145,146,147,151],"p",{},"A collector resolves a handler parameter ",[148,149,150],"strong",{},"by its type"," from the invocation context.\nOperations declaring that parameter receive the value automatically.",[153,154,159],"pre",{"className":155,"code":156,"language":157,"meta":158,"style":158},"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 * The auth middleware puts the session user on ctx.state.user —\n * this surfaces it to any handler that declares `user: User | null`.\n *\u002F\nexport default class CurrentUserCollector extends Collector(User) {\n  async collect(ctx: InvocationContext) {\n    return (ctx.state.user ?? null) as User | null;\n  }\n}\n","ts","",[160,161,162,199,224,244,251,258,264,270,276,305,334,381,387],"code",{"__ignoreMap":158},[163,164,167,171,175,179,182,185,189,193,196],"span",{"class":165,"line":166},"line",1,[163,168,170],{"class":169},"sVHd0","import",[163,172,174],{"class":173},"sP7_E"," {",[163,176,178],{"class":177},"su5hD"," Collector",[163,180,181],{"class":173}," }",[163,183,184],{"class":169}," from",[163,186,188],{"class":187},"sjJ54"," '",[163,190,192],{"class":191},"s_sjI","@fougere\u002Fcore",[163,194,195],{"class":187},"'",[163,197,198],{"class":173},";\n",[163,200,202,204,207,209,212,214,216,218,220,222],{"class":165,"line":201},2,[163,203,170],{"class":169},[163,205,206],{"class":169}," type",[163,208,174],{"class":173},[163,210,211],{"class":177}," InvocationContext",[163,213,181],{"class":173},[163,215,184],{"class":169},[163,217,188],{"class":187},[163,219,192],{"class":191},[163,221,195],{"class":187},[163,223,198],{"class":173},[163,225,227,229,232,235,237,240,242],{"class":165,"line":226},3,[163,228,170],{"class":169},[163,230,231],{"class":177}," User ",[163,233,234],{"class":169},"from",[163,236,188],{"class":187},[163,238,239],{"class":191},"..\u002F..\u002Fuser\u002Fentities\u002FUser.js",[163,241,195],{"class":187},[163,243,198],{"class":173},[163,245,247],{"class":165,"line":246},4,[163,248,250],{"emptyLinePlaceholder":249},true,"\n",[163,252,254],{"class":165,"line":253},5,[163,255,257],{"class":256},"sutJx","\u002F**\n",[163,259,261],{"class":165,"line":260},6,[163,262,263],{"class":256}," * The auth middleware puts the session user on ctx.state.user —\n",[163,265,267],{"class":165,"line":266},7,[163,268,269],{"class":256}," * this surfaces it to any handler that declares `user: User | null`.\n",[163,271,273],{"class":165,"line":272},8,[163,274,275],{"class":256}," *\u002F\n",[163,277,279,282,285,289,293,296,299,302],{"class":165,"line":278},9,[163,280,281],{"class":169},"export",[163,283,284],{"class":169}," default",[163,286,288],{"class":287},"sbsja"," class",[163,290,292],{"class":291},"sbgvK"," CurrentUserCollector",[163,294,295],{"class":287}," extends",[163,297,178],{"class":298},"sGLFI",[163,300,301],{"class":177},"(User) ",[163,303,304],{"class":173},"{\n",[163,306,308,311,315,318,322,326,328,331],{"class":165,"line":307},10,[163,309,310],{"class":287},"  async",[163,312,314],{"class":313},"sVXei"," collect",[163,316,317],{"class":173},"(",[163,319,321],{"class":320},"s99_P","ctx",[163,323,325],{"class":324},"smGrS",":",[163,327,211],{"class":291},[163,329,330],{"class":173},")",[163,332,333],{"class":173}," {\n",[163,335,337,340,344,346,349,352,354,357,360,364,367,370,373,376,379],{"class":165,"line":336},11,[163,338,339],{"class":169},"    return",[163,341,343],{"class":342},"skxfh"," (",[163,345,321],{"class":177},[163,347,348],{"class":173},".",[163,350,351],{"class":177},"state",[163,353,348],{"class":173},[163,355,356],{"class":177},"user",[163,358,359],{"class":324}," ??",[163,361,363],{"class":362},"s39Yj"," null",[163,365,366],{"class":342},") ",[163,368,369],{"class":169},"as",[163,371,372],{"class":291}," User",[163,374,375],{"class":324}," |",[163,377,363],{"class":378},"sZMiF",[163,380,198],{"class":173},[163,382,384],{"class":165,"line":383},12,[163,385,386],{"class":173},"  }\n",[163,388,390],{"class":165,"line":389},13,[163,391,392],{"class":173},"}\n",[144,394,395],{},"From then on, in any handler of the Frond:",[153,397,399],{"className":155,"code":398,"language":157,"meta":158,"style":158},"async mine(user: User | null): Promise\u003CPost[]> { … }\nasync publish(id: string, user: User | null): Promise\u003CPost> { … }\n",[160,400,401,439],{"__ignoreMap":158},[163,402,403,406,409,412,415,417,420,423,426,429,432,434,437],{"class":165,"line":166},[163,404,405],{"class":177},"async ",[163,407,408],{"class":298},"mine",[163,410,411],{"class":177},"(user: User ",[163,413,414],{"class":324},"|",[163,416,363],{"class":362},[163,418,419],{"class":177},"): ",[163,421,422],{"class":378},"Promise",[163,424,425],{"class":324},"\u003C",[163,427,428],{"class":177},"Post[]",[163,430,431],{"class":324},">",[163,433,174],{"class":173},[163,435,436],{"class":177}," … ",[163,438,392],{"class":173},[163,440,441,443,446,449,452,455,457,459,461,463,465,468,470,472,474],{"class":165,"line":201},[163,442,405],{"class":177},[163,444,445],{"class":298},"publish",[163,447,448],{"class":177},"(id: string",[163,450,451],{"class":173},",",[163,453,454],{"class":177}," user: User ",[163,456,414],{"class":324},[163,458,363],{"class":362},[163,460,419],{"class":177},[163,462,422],{"class":378},[163,464,425],{"class":324},[163,466,467],{"class":177},"Post",[163,469,431],{"class":324},[163,471,174],{"class":173},[163,473,436],{"class":177},[163,475,392],{"class":173},[477,478,480],"h2",{"id":479},"resolution-rules","Resolution rules",[482,483,484,508,522],"ul",{},[485,486,487,488,491,492,495,496,499,500,503,504,507],"li",{},"The match is ",[148,489,490],{},"by entity type name",": ",[160,493,494],{},"Collector(User)"," resolves parameters typed\n",[160,497,498],{},"User | null"," (or ",[160,501,502],{},"User","). The class is registered as ",[160,505,506],{},"UserCollector"," by convention.",[485,509,510,513,514,517,518,521],{},[148,511,512],{},"Spell the union out."," The signature parser is AST-only: ",[160,515,516],{},"user: User | null"," matches,\na type alias (",[160,519,520],{},"user: CurrentUser",") is invisible and binds nothing.",[485,523,524],{},"Collectors are DI-injectable classes — declare constructor dependencies as usual.",[477,526,528],{"id":527},"state-and-the-gradient","State and the gradient",[144,530,531,534,535,538],{},[160,532,533],{},"ctx.state"," is the request state built by the consuming application, for example from the\nsession. During a remote call, this state is sent with the invocation, so the collector\nreceives the same ",[160,536,537],{},"ctx.state.user"," as it would locally.",[477,540,542],{"id":541},"a-collector-does-not-cross-a-frond-boundary","A collector does not cross a Frond boundary",[144,544,545],{},"Keep the collector in each Frond that consumes it. What happens otherwise deserves to be\nsaid precisely, because it is neither \"later\" nor \"nothing\":",[482,547,548,559],{},[485,549,550,553,554,558],{},[148,551,552],{},"it is not at the split."," The binding is decided at boot, in a single process, from\nthe collectors ",[555,556,557],"em",{},"of that Frond itself",";",[485,560,561,564,565,568,569,572,573,348],{},[148,562,563],{},"the parameter is not empty."," A type the Frond cannot resolve falls into the fourth\nbinding rule, ",[160,566,567],{},"body",". So the handler receives ",[148,570,571],{},"the request body"," where it expects a\n",[160,574,502],{},[144,576,577,578,580,581,583,584,587],{},"Put plainly: ",[160,579,516],{}," declared in a Frond that has no ",[160,582,506],{}," receives\nwhatever the client sent. A handler judging on ",[160,585,586],{},"user.role"," judges a caller-supplied value.",[589,590,591],"blockquote",{},[144,592,593],{},"An earlier version of this page said the collector was \"lost after a process split\".\nThat was wrong twice, and the truth is less comfortable.",[144,595,596,597,600],{},"Next: ",[598,599,81],"a",{"href":82}," — typed errors across layers.",[602,603,604],"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 .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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":158,"searchDepth":201,"depth":201,"links":606},[607,608,609],{"id":479,"depth":201,"text":480},{"id":527,"depth":201,"text":528},{"id":541,"depth":201,"text":542},"Resolving handler parameters by type from the invocation context.","md",{},{"title":77,"description":610},"KEcVtTeiWbt4HgUE6SwPHHmyALle1wWph6j1j8Br5jg",1786637819135]