[{"data":1,"prerenderedAt":851},["ShallowReactive",2],{"docs:\u002Fdocs":3,"docs-nav:en":725},{"id":4,"title":5,"body":6,"description":718,"extension":719,"meta":720,"navigation":190,"path":721,"seo":722,"stem":723,"__hash__":724},"docs_en\u002Fdocs\u002Findex.md","What is Fougere",{"type":7,"value":8,"toc":713},"minimark",[9,13,21,29,80,83,88,103,405,408,411,467,471,485,520,527,530,533,536,557,561,581,646,667,692,709],[10,11,5],"h1",{"id":12},"what-is-fougere",[14,15,16,17],"p",{},"Fougere is a TypeScript framework built on one idea: ",[18,19,20],"strong",{},"you declare the domain, and\neverything else derives from it — down to the process it runs in.",[14,22,23,24,28],{},"Stated in the negative, it becomes checkable: ",[25,26,27],"em",{},"the declaration names nothing outside\nitself."," No table, no protocol, no host, no address appears in it. Two consequences follow,\nand they are ordinarily sold as two separate features:",[30,31,32,48],"table",{},[33,34,35],"thead",{},[36,37,38,42,45],"tr",{},[39,40,41],"th",{},"The declaration does not name…",[39,43,44],{},"so that thing is…",[39,46,47],{},"its usual name",[49,50,51,66],"tbody",{},[36,52,53,57,63],{},[54,55,56],"td",{},"its table, its GraphQL type, its form, its judge",[54,58,59,62],{},[18,60,61],{},"derived"," from it",[54,64,65],{},"single-schema",[36,67,68,71,77],{},[54,69,70],{},"its host, its storage, its door, its address",[54,72,73,76],{},[18,74,75],{},"chosen outside"," it",[54,78,79],{},"the gradient",[14,81,82],{},"One rule read in two directions — what a declaration produces, and what it may be\nsurrounded by. The rest of this page is those two readings.",[84,85,87],"h2",{"id":86},"what-is-derived-from-it","What is derived from it",[14,89,90,93,94,98,99,102],{},[18,91,92],{},"Single-schema."," One entity class declares your data once — and judges its own input:\nthe same ",[95,96,97],"code",{},"validate()"," runs in the browser and at the façade. That judge is itself a\nprojection, derived from the shape axis, but a normative one shipped with the class:\nevery other projection must agree with it, and it cannot drift on its own. SQLite tables,\nGraphQL types, form contracts and API surfaces are ",[25,100,101],{},"projections"," of that declaration —\nnothing is written twice.",[104,105,110],"pre",{"className":106,"code":107,"language":108,"meta":109,"style":109},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","import { entity, primary, text, created, oneOf, date, readOnly, optional } from '@fougere\u002Fschema';\n\nexport default class Post extends entity({\n  id: primary(),\n  title: text({ min: 1, max: 160 }),\n  body: optional(text()),\n  createdAt: created(),\n  status: readOnly(oneOf('draft', 'published', { default: 'draft' })),\n  publishedAt: readOnly(optional(date())),\n}) {}\n","ts","",[95,111,112,185,192,221,239,280,300,314,368,393],{"__ignoreMap":109},[113,114,117,121,125,129,132,135,137,140,142,145,147,150,152,155,157,160,162,165,168,171,175,179,182],"span",{"class":115,"line":116},"line",1,[113,118,120],{"class":119},"sVHd0","import",[113,122,124],{"class":123},"sP7_E"," {",[113,126,128],{"class":127},"su5hD"," entity",[113,130,131],{"class":123},",",[113,133,134],{"class":127}," primary",[113,136,131],{"class":123},[113,138,139],{"class":127}," text",[113,141,131],{"class":123},[113,143,144],{"class":127}," created",[113,146,131],{"class":123},[113,148,149],{"class":127}," oneOf",[113,151,131],{"class":123},[113,153,154],{"class":127}," date",[113,156,131],{"class":123},[113,158,159],{"class":127}," readOnly",[113,161,131],{"class":123},[113,163,164],{"class":127}," optional",[113,166,167],{"class":123}," }",[113,169,170],{"class":119}," from",[113,172,174],{"class":173},"sjJ54"," '",[113,176,178],{"class":177},"s_sjI","@fougere\u002Fschema",[113,180,181],{"class":173},"'",[113,183,184],{"class":123},";\n",[113,186,188],{"class":115,"line":187},2,[113,189,191],{"emptyLinePlaceholder":190},true,"\n",[113,193,195,198,201,205,209,212,215,218],{"class":115,"line":194},3,[113,196,197],{"class":119},"export",[113,199,200],{"class":119}," default",[113,202,204],{"class":203},"sbsja"," class",[113,206,208],{"class":207},"sbgvK"," Post",[113,210,211],{"class":203}," extends",[113,213,128],{"class":214},"sGLFI",[113,216,217],{"class":127},"(",[113,219,220],{"class":123},"{\n",[113,222,224,228,231,233,236],{"class":115,"line":223},4,[113,225,227],{"class":226},"skxfh","  id",[113,229,230],{"class":123},":",[113,232,134],{"class":214},[113,234,235],{"class":127},"()",[113,237,238],{"class":123},",\n",[113,240,242,245,247,249,251,254,257,259,263,265,268,270,273,275,278],{"class":115,"line":241},5,[113,243,244],{"class":226},"  title",[113,246,230],{"class":123},[113,248,139],{"class":214},[113,250,217],{"class":127},[113,252,253],{"class":123},"{",[113,255,256],{"class":226}," min",[113,258,230],{"class":123},[113,260,262],{"class":261},"srdBf"," 1",[113,264,131],{"class":123},[113,266,267],{"class":226}," max",[113,269,230],{"class":123},[113,271,272],{"class":261}," 160",[113,274,167],{"class":123},[113,276,277],{"class":127},")",[113,279,238],{"class":123},[113,281,283,286,288,290,292,295,298],{"class":115,"line":282},6,[113,284,285],{"class":226},"  body",[113,287,230],{"class":123},[113,289,164],{"class":214},[113,291,217],{"class":127},[113,293,294],{"class":214},"text",[113,296,297],{"class":127},"())",[113,299,238],{"class":123},[113,301,303,306,308,310,312],{"class":115,"line":302},7,[113,304,305],{"class":226},"  createdAt",[113,307,230],{"class":123},[113,309,144],{"class":214},[113,311,235],{"class":127},[113,313,238],{"class":123},[113,315,317,320,322,324,326,329,331,333,336,338,340,342,345,347,349,351,353,355,357,359,361,363,366],{"class":115,"line":316},8,[113,318,319],{"class":226},"  status",[113,321,230],{"class":123},[113,323,159],{"class":214},[113,325,217],{"class":127},[113,327,328],{"class":214},"oneOf",[113,330,217],{"class":127},[113,332,181],{"class":173},[113,334,335],{"class":177},"draft",[113,337,181],{"class":173},[113,339,131],{"class":123},[113,341,174],{"class":173},[113,343,344],{"class":177},"published",[113,346,181],{"class":173},[113,348,131],{"class":123},[113,350,124],{"class":123},[113,352,200],{"class":226},[113,354,230],{"class":123},[113,356,174],{"class":173},[113,358,335],{"class":177},[113,360,181],{"class":173},[113,362,167],{"class":123},[113,364,365],{"class":127},"))",[113,367,238],{"class":123},[113,369,371,374,376,378,380,383,385,388,391],{"class":115,"line":370},9,[113,372,373],{"class":226},"  publishedAt",[113,375,230],{"class":123},[113,377,159],{"class":214},[113,379,217],{"class":127},[113,381,382],{"class":214},"optional",[113,384,217],{"class":127},[113,386,387],{"class":214},"date",[113,389,390],{"class":127},"()))",[113,392,238],{"class":123},[113,394,396,399,402],{"class":115,"line":395},10,[113,397,398],{"class":123},"}",[113,400,401],{"class":127},") ",[113,403,404],{"class":123},"{}\n",[406,407],"derivation-diagram",{},[14,409,410],{},"That single class is simultaneously:",[412,413,414,430,439,448,457],"ul",{},[415,416,417,418,421,422,425,426,429],"li",{},"the ",[18,419,420],{},"TypeScript type"," of a row (",[95,423,424],{},"function render(p: Post)"," — no ",[95,427,428],{},"Infer\u003Ctypeof …>","),",[415,431,417,432,435,436,429],{},[18,433,434],{},"validator"," of client input (",[95,437,438],{},"Post.validate(input)",[415,440,417,441,444,445,429],{},[18,442,443],{},"metadata"," every adapter reads (",[95,446,447],{},"Post.getFields()",[415,449,417,450,453,454,429],{},[18,451,452],{},"designation"," pages use to call operations (",[95,455,456],{},"useQuery(Post, 'list')",[415,458,417,459,462,463,466],{},[18,460,461],{},"nominal type"," dependency injection matches in handler signatures (",[95,464,465],{},"user?: User",").",[84,468,470],{"id":469},"what-is-chosen-outside-it","What is chosen outside it",[14,472,473,476,477,480,481,484],{},[18,474,475],{},"The gradient."," Business logic lives in ",[25,478,479],{},"Fronds"," — self-contained modules of entities,\nhandlers, collectors and seeds. A Frond runs in-process today and in its own process\ntomorrow, behind JSON-RPC 2.0, with ",[18,482,483],{},"identical user code",". The entire topology statement\nis one line of config:",[104,486,488],{"className":106,"code":487,"language":108,"meta":109,"style":109},"\u002F\u002F fougere.config.ts\nremotes: { blog: 'http:\u002F\u002F127.0.0.1:4100' }\n",[95,489,490,496],{"__ignoreMap":109},[113,491,492],{"class":115,"line":116},[113,493,495],{"class":494},"sutJx","\u002F\u002F fougere.config.ts\n",[113,497,498,501,503,505,508,510,512,515,517],{"class":115,"line":187},[113,499,500],{"class":207},"remotes",[113,502,230],{"class":123},[113,504,124],{"class":123},[113,506,507],{"class":207}," blog",[113,509,230],{"class":123},[113,511,174],{"class":173},[113,513,514],{"class":177},"http:\u002F\u002F127.0.0.1:4100",[113,516,181],{"class":173},[113,518,519],{"class":123}," }\n",[14,521,522,523,526],{},"There is no RPC without travel: a call is a value ",[95,524,525],{},"(entity, operation, invocation)","; the\nrunner executes it directly in memory when the Frond is local and frames it onto the wire\nwhen it is remote. Transports move the value — they never reshape it.",[14,528,529],{},"So the split costs the hop and the JSON that rides it, and nothing else: no serialization\nthe local path avoids, no framework tax layered on top of the network.",[14,531,532],{},"The four families the rule refuses to name, drawn — the gradient being the fourth one read\nas a movement rather than a list:",[534,535],"agnostic-core",{},[14,537,538,539,542,543,546,547,550,551,556],{},"And it is checkable with ",[95,540,541],{},"diff",": the five demos that serve this same blog under Next,\nTanStack Start, React Router, SvelteKit and Express share a ",[95,544,545],{},"fronds\u002F"," directory that is\nidentical byte for byte, and three of those hosts need no Fougere package at all. So\n",[25,548,549],{},"progressive"," here means only this — each step outward\n",[552,553,555],"a",{"href":554},"\u002Fdocs\u002Finfra\u002Fgradient#five-rungs-and-the-price-of-each","states its price",", and none of them\nasks you to rewrite what you wrote.",[84,558,560],{"id":559},"reading-order","Reading order",[14,562,563,566,567,571,572,576,577],{},[18,564,565],{},"Concepts"," — ",[552,568,570],{"href":569},"\u002Fdocs\u002Fconcepts\u002Fphilosophy","Philosophy"," · ",[552,573,575],{"href":574},"\u002Fdocs\u002Fconcepts\u002Ffrond","The Frond"," ·\n",[552,578,580],{"href":579},"\u002Fdocs\u002Fconcepts\u002Fthe-base","The base",[14,582,583,566,586,576,590,571,594,576,598,576,602,571,606,576,610,571,614,576,618,571,622,571,626,571,630,576,634,571,638,571,642],{},[18,584,585],{},"Server side",[552,587,589],{"href":588},"\u002Fdocs\u002Fexisting-app","An app you already have",[552,591,593],{"href":592},"\u002Fdocs\u002Fbring-your-schema","Bring your schema",[552,595,597],{"href":596},"\u002Fdocs\u002Fgetting-started","Getting started",[552,599,601],{"href":600},"\u002Fdocs\u002Fcli","The CLI",[552,603,605],{"href":604},"\u002Fdocs\u002Fschema\u002Fentities","Entities",[552,607,609],{"href":608},"\u002Fdocs\u002Fschema\u002Fviews","Views",[552,611,613],{"href":612},"\u002Fdocs\u002Fschema\u002Fstandard-schema","Standard Schema",[552,615,617],{"href":616},"\u002Fdocs\u002Fbusiness\u002Fhandlers","Handlers",[552,619,621],{"href":620},"\u002Fdocs\u002Fbusiness\u002Fpresenters","Presenters",[552,623,625],{"href":624},"\u002Fdocs\u002Fbusiness\u002Fcollectors","Collectors",[552,627,629],{"href":628},"\u002Fdocs\u002Fbusiness\u002Ferrors","Errors",[552,631,633],{"href":632},"\u002Fdocs\u002Fbusiness\u002Fseeds","Seeds",[552,635,637],{"href":636},"\u002Fdocs\u002Fbusiness\u002Ffacts","Facts",[552,639,641],{"href":640},"\u002Fdocs\u002Fbusiness\u002Fstorage","Storage",[552,643,645],{"href":644},"\u002Fdocs\u002Fbusiness\u002Frepositories","Repositories",[14,647,648,566,651,576,655,571,659,571,663],{},[18,649,650],{},"Client side",[552,652,654],{"href":653},"\u002Fdocs\u002Fclient\u002Fqueries-commands","Queries & commands",[552,656,658],{"href":657},"\u002Fdocs\u002Fclient\u002Fforms","Forms",[552,660,662],{"href":661},"\u002Fdocs\u002Fclient\u002Fsession","Session",[552,664,666],{"href":665},"\u002Fdocs\u002Fclient\u002Finvoke","invoke",[14,668,669,566,672,571,676,576,680,571,684,576,688],{},[18,670,671],{},"Topology",[552,673,675],{"href":674},"\u002Fdocs\u002Finfra\u002Fgradient","The gradient",[552,677,679],{"href":678},"\u002Fdocs\u002Finfra\u002Fsurfaces","Surfaces",[552,681,683],{"href":682},"\u002Fdocs\u002Finfra\u002Fdeployment","Deployment",[552,685,687],{"href":686},"\u002Fdocs\u002Finfra\u002Fhosts","Hosts",[552,689,691],{"href":690},"\u002Fdocs\u002Finfra\u002Fsources","Sources",[693,694,695],"blockquote",{},[14,696,697,700,701,704,705,708],{},[18,698,699],{},"Status."," Fougere is in alpha: the ",[95,702,703],{},"@fougere\u002F*"," packages are on npm under the ",[95,706,707],{},"alpha","\ntag, and this documentation describes the API as it exists in the repository today.\nThis site runs on it.",[710,711,712],"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 .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 .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--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);}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}",{"title":109,"searchDepth":187,"depth":187,"links":714},[715,716,717],{"id":86,"depth":187,"text":87},{"id":469,"depth":187,"text":470},{"id":559,"depth":187,"text":560},"One idea — you declare the domain, and everything else derives from it, down to the process it runs in.","md",{},"\u002Fdocs",{"title":5,"description":718},"docs\u002Findex","SKRSz2PNwAUFuFB706bqHDXzBl3iXtaT5LLkReBIndo",[726],{"title":727,"path":721,"stem":728,"children":729,"page":-1},"Docs","docs",[730,731,733,735,737,739,754,773,802,819],{"title":5,"path":721,"stem":723},{"title":597,"path":596,"stem":732},"docs\u002F01.getting-started",{"title":589,"path":588,"stem":734},"docs\u002F02.existing-app",{"title":593,"path":592,"stem":736},"docs\u002F03.bring-your-schema",{"title":601,"path":600,"stem":738},"docs\u002F04.cli",{"title":565,"path":740,"stem":741,"children":742,"page":753},"\u002Fdocs\u002Fconcepts","docs\u002F2.concepts",[743,745,747,751],{"title":570,"path":569,"stem":744},"docs\u002F2.concepts\u002F1.philosophy",{"title":575,"path":574,"stem":746},"docs\u002F2.concepts\u002F2.frond",{"title":748,"path":749,"stem":750},"The shortest path","\u002Fdocs\u002Fconcepts\u002Fshortest-path","docs\u002F2.concepts\u002F3.shortest-path",{"title":580,"path":579,"stem":752},"docs\u002F2.concepts\u002F4.the-base",false,{"title":755,"path":756,"stem":757,"children":758,"page":753},"Schema","\u002Fdocs\u002Fschema","docs\u002F3.schema",[759,761,763,767,769],{"title":605,"path":604,"stem":760},"docs\u002F3.schema\u002F1.entities",{"title":609,"path":608,"stem":762},"docs\u002F3.schema\u002F2.views",{"title":764,"path":765,"stem":766},"The identity card","\u002Fdocs\u002Fschema\u002Fcard","docs\u002F3.schema\u002F3.card",{"title":613,"path":612,"stem":768},"docs\u002F3.schema\u002F4.standard-schema",{"title":770,"path":771,"stem":772},"How a schema moves","\u002Fdocs\u002Fschema\u002Fevolution","docs\u002F3.schema\u002F5.evolution",{"title":774,"path":775,"stem":776,"children":777,"page":753},"Business","\u002Fdocs\u002Fbusiness","docs\u002F4.business",[778,780,784,786,788,790,792,794,796,800],{"title":617,"path":616,"stem":779},"docs\u002F4.business\u002F1.handlers",{"title":781,"path":782,"stem":783},"Ports","\u002Fdocs\u002Fbusiness\u002Fports","docs\u002F4.business\u002F10.ports",{"title":621,"path":620,"stem":785},"docs\u002F4.business\u002F2.presenters",{"title":625,"path":624,"stem":787},"docs\u002F4.business\u002F3.collectors",{"title":629,"path":628,"stem":789},"docs\u002F4.business\u002F4.errors",{"title":633,"path":632,"stem":791},"docs\u002F4.business\u002F5.seeds",{"title":637,"path":636,"stem":793},"docs\u002F4.business\u002F6.facts",{"title":641,"path":640,"stem":795},"docs\u002F4.business\u002F7.storage",{"title":797,"path":798,"stem":799},"Writes that stand or fall as one","\u002Fdocs\u002Fbusiness\u002Ftogether","docs\u002F4.business\u002F8.together",{"title":645,"path":644,"stem":801},"docs\u002F4.business\u002F9.repositories",{"title":803,"path":804,"stem":805,"children":806,"page":753},"Client","\u002Fdocs\u002Fclient","docs\u002F5.client",[807,809,811,813,815],{"title":654,"path":653,"stem":808},"docs\u002F5.client\u002F1.queries-commands",{"title":658,"path":657,"stem":810},"docs\u002F5.client\u002F2.forms",{"title":662,"path":661,"stem":812},"docs\u002F5.client\u002F3.session",{"title":666,"path":665,"stem":814},"docs\u002F5.client\u002F4.invoke",{"title":816,"path":817,"stem":818},"Back-office","\u002Fdocs\u002Fclient\u002Fadmin","docs\u002F5.client\u002F5.admin",{"title":820,"path":821,"stem":822,"children":823,"page":753},"Infrastructure","\u002Fdocs\u002Finfra","docs\u002F6.infra",[824,826,829,831,833,835,839,843,847],{"title":675,"path":674,"stem":825},"docs\u002F6.infra\u002F1.gradient",{"title":827,"path":678,"stem":828},"Surfaces — REST & GraphQL","docs\u002F6.infra\u002F2.surfaces",{"title":683,"path":682,"stem":830},"docs\u002F6.infra\u002F3.deployment",{"title":687,"path":686,"stem":832},"docs\u002F6.infra\u002F4.hosts",{"title":691,"path":690,"stem":834},"docs\u002F6.infra\u002F5.sources",{"title":836,"path":837,"stem":838},"Lifecycle","\u002Fdocs\u002Finfra\u002Flifecycle","docs\u002F6.infra\u002F6.lifecycle",{"title":840,"path":841,"stem":842},"Identity across Fronds","\u002Fdocs\u002Finfra\u002Fidentity","docs\u002F6.infra\u002F7.identity",{"title":844,"path":845,"stem":846},"Observability","\u002Fdocs\u002Finfra\u002Fobservability","docs\u002F6.infra\u002F8.observability",{"title":848,"path":849,"stem":850},"Testing","\u002Fdocs\u002Finfra\u002Ftesting","docs\u002F6.infra\u002F9.testing",1788560229821]