[{"data":1,"prerenderedAt":1772},["ShallowReactive",2],{"fougere:post.list:{}":3,"docs:\u002Fdocs\u002Fguides\u002Fdata":5,"docs-nav":1575},{"items":4},[],{"id":6,"title":7,"body":8,"description":1568,"extension":1569,"meta":1570,"navigation":112,"path":1571,"seo":1572,"stem":1573,"__hash__":1574},"docs\u002Fdocs\u002F1.guides\u002F2.data.md","Store your data",{"type":9,"value":10,"toc":1560},"minimark",[11,15,25,30,38,241,248,270,349,355,359,362,370,380,383,488,493,512,531,537,541,544,702,709,893,898,902,908,1209,1217,1222,1226,1233,1307,1395,1405,1466,1477,1483,1487,1490,1528,1549,1556],[12,13,7],"h1",{"id":14},"store-your-data",[16,17,18,19,24],"p",{},"The shop from ",[20,21,23],"a",{"href":22},"\u002Fdocs\u002Fguides\u002Fbusiness-logic","the first guide"," returns a total written in\nthe code. This guide stores real products: an entity, a repository, a form to add them, and the\nsame products over REST and GraphQL.",[26,27,29],"h2",{"id":28},"entities","Entities",[16,31,32,33,37],{},"An entity is a class in ",[34,35,36],"code",{},"entities\u002F"," that describes one kind of data:",[39,40,45],"pre",{"className":41,"code":42,"language":43,"meta":44,"style":44},"language-ts shiki shiki-themes material-theme-lighter fougere-pastel material-theme-palenight","\u002F\u002F fronds\u002Fshop\u002Fentities\u002FProduct.ts\nimport { entity, primary, text, number } from '@fougere\u002Fschema';\n\nexport default class Product extends entity({\n  id: primary(),\n  title: text({ min: 1, max: 200 }),\n  cents: number({ min: 0 }),\n}) {}\n","ts","",[34,46,47,56,107,114,144,162,203,230],{"__ignoreMap":44},[48,49,52],"span",{"class":50,"line":51},"line",1,[48,53,55],{"class":54},"skXKP","\u002F\u002F fronds\u002Fshop\u002Fentities\u002FProduct.ts\n",[48,57,59,63,67,71,74,77,79,82,84,87,90,93,97,101,104],{"class":50,"line":58},2,[48,60,62],{"class":61},"sK6XW","import",[48,64,66],{"class":65},"s15xx"," {",[48,68,70],{"class":69},"sPEhv"," entity",[48,72,73],{"class":65},",",[48,75,76],{"class":69}," primary",[48,78,73],{"class":65},[48,80,81],{"class":69}," text",[48,83,73],{"class":65},[48,85,86],{"class":69}," number",[48,88,89],{"class":65}," }",[48,91,92],{"class":61}," from",[48,94,96],{"class":95},"sDDC1"," '",[48,98,100],{"class":99},"sN-8n","@fougere\u002Fschema",[48,102,103],{"class":95},"'",[48,105,106],{"class":65},";\n",[48,108,110],{"class":50,"line":109},3,[48,111,113],{"emptyLinePlaceholder":112},true,"\n",[48,115,117,120,123,127,131,134,137,141],{"class":50,"line":116},4,[48,118,119],{"class":61},"export",[48,121,122],{"class":61}," default",[48,124,126],{"class":125},"s76I7"," class",[48,128,130],{"class":129},"sBZYL"," Product",[48,132,133],{"class":125}," extends",[48,135,70],{"class":136},"s4mR9",[48,138,140],{"class":139},"srlTG","(",[48,142,143],{"class":65},"{\n",[48,145,147,151,154,156,159],{"class":50,"line":146},5,[48,148,150],{"class":149},"sHtqg","  id",[48,152,153],{"class":65},":",[48,155,76],{"class":136},[48,157,158],{"class":139},"()",[48,160,161],{"class":65},",\n",[48,163,165,168,170,172,174,177,180,182,186,188,191,193,196,198,201],{"class":50,"line":164},6,[48,166,167],{"class":149},"  title",[48,169,153],{"class":65},[48,171,81],{"class":136},[48,173,140],{"class":139},[48,175,176],{"class":65},"{",[48,178,179],{"class":149}," min",[48,181,153],{"class":65},[48,183,185],{"class":184},"s3dPA"," 1",[48,187,73],{"class":65},[48,189,190],{"class":149}," max",[48,192,153],{"class":65},[48,194,195],{"class":184}," 200",[48,197,89],{"class":65},[48,199,200],{"class":139},")",[48,202,161],{"class":65},[48,204,206,209,211,213,215,217,219,221,224,226,228],{"class":50,"line":205},7,[48,207,208],{"class":149},"  cents",[48,210,153],{"class":65},[48,212,86],{"class":136},[48,214,140],{"class":139},[48,216,176],{"class":65},[48,218,179],{"class":149},[48,220,153],{"class":65},[48,222,223],{"class":184}," 0",[48,225,89],{"class":65},[48,227,200],{"class":139},[48,229,161],{"class":65},[48,231,233,236,238],{"class":50,"line":232},8,[48,234,235],{"class":65},"}",[48,237,200],{"class":139},[48,239,240],{"class":65}," {}\n",[16,242,243,244,247],{},"From this class Fougere builds the ",[34,245,246],{},"products"," table, the validation of every input, the\nfields of a form, and the REST and GraphQL types.",[16,249,250,253,254,257,258,257,261,161,264,257,267,153],{},[34,251,252],{},"Crud(Product)"," gives a handler the five usual operations — ",[34,255,256],{},"list",", ",[34,259,260],{},"findById",[34,262,263],{},"create",[34,265,266],{},"update",[34,268,269],{},"delete",[39,271,273],{"className":41,"code":272,"language":43,"meta":44,"style":44},"\u002F\u002F fronds\u002Fshop\u002Fhandlers\u002FProductHandler.ts\nimport { Crud } from '@fougere\u002Fcore';\nimport Product from '..\u002Fentities\u002FProduct.js';\n\nexport default class ProductHandler extends Crud(Product) {}\n",[34,274,275,280,302,321,325],{"__ignoreMap":44},[48,276,277],{"class":50,"line":51},[48,278,279],{"class":54},"\u002F\u002F fronds\u002Fshop\u002Fhandlers\u002FProductHandler.ts\n",[48,281,282,284,286,289,291,293,295,298,300],{"class":50,"line":58},[48,283,62],{"class":61},[48,285,66],{"class":65},[48,287,288],{"class":69}," Crud",[48,290,89],{"class":65},[48,292,92],{"class":61},[48,294,96],{"class":95},[48,296,297],{"class":99},"@fougere\u002Fcore",[48,299,103],{"class":95},[48,301,106],{"class":65},[48,303,304,306,309,312,314,317,319],{"class":50,"line":109},[48,305,62],{"class":61},[48,307,308],{"class":69}," Product ",[48,310,311],{"class":61},"from",[48,313,96],{"class":95},[48,315,316],{"class":99},"..\u002Fentities\u002FProduct.js",[48,318,103],{"class":95},[48,320,106],{"class":65},[48,322,323],{"class":50,"line":116},[48,324,113],{"emptyLinePlaceholder":112},[48,326,327,329,331,333,336,338,340,342,345,347],{"class":50,"line":146},[48,328,119],{"class":61},[48,330,122],{"class":61},[48,332,126],{"class":125},[48,334,335],{"class":129}," ProductHandler",[48,337,133],{"class":125},[48,339,288],{"class":136},[48,341,140],{"class":139},[48,343,344],{"class":69},"Product",[48,346,200],{"class":139},[48,348,240],{"class":65},[16,350,351,352],{},"→ ",[20,353,29],{"href":354},"\u002Fdocs\u002Fschema\u002Fentities",[26,356,358],{"id":357},"migrations","Migrations",[16,360,361],{},"The table does not exist yet, and the app does not create it for you: it refuses to start,\nand says what is missing.",[39,363,368],{"className":364,"code":366,"language":367},[365],"language-text","Fougere boot refused: the database is missing 1 change(s) from the entities:\n  products — no table\n  On your machine: fougere migrate --latest --apply\n  On a shared database: fougere freeze, then fougere migrate --apply\n","text",[34,369,366],{"__ignoreMap":44},[16,371,372,375,376,379],{},[34,373,374],{},"npm run migrate"," — ",[34,377,378],{},"fougere migrate --latest --apply"," — creates it on your database. Run it each\ntime an entity gains a field; the boot tells you when.",[16,381,382],{},"A rename is declared on the entity, and the rows follow:",[39,384,386],{"className":41,"code":385,"language":43,"meta":44,"style":44},"export default class Product extends entity(\n  { id: primary(), name: text(), cents: number({ min: 0 }) },\n  { previous: { name: 'title' } },\n) {}\n",[34,387,388,405,456,482],{"__ignoreMap":44},[48,389,390,392,394,396,398,400,402],{"class":50,"line":51},[48,391,119],{"class":61},[48,393,122],{"class":61},[48,395,126],{"class":125},[48,397,130],{"class":129},[48,399,133],{"class":125},[48,401,70],{"class":136},[48,403,404],{"class":139},"(\n",[48,406,407,410,413,415,417,419,421,424,426,428,430,432,435,437,439,441,443,445,447,449,451,453],{"class":50,"line":58},[48,408,409],{"class":65},"  {",[48,411,412],{"class":149}," id",[48,414,153],{"class":65},[48,416,76],{"class":136},[48,418,158],{"class":139},[48,420,73],{"class":65},[48,422,423],{"class":149}," name",[48,425,153],{"class":65},[48,427,81],{"class":136},[48,429,158],{"class":139},[48,431,73],{"class":65},[48,433,434],{"class":149}," cents",[48,436,153],{"class":65},[48,438,86],{"class":136},[48,440,140],{"class":139},[48,442,176],{"class":65},[48,444,179],{"class":149},[48,446,153],{"class":65},[48,448,223],{"class":184},[48,450,89],{"class":65},[48,452,200],{"class":139},[48,454,455],{"class":65}," },\n",[48,457,458,460,463,465,467,469,471,473,476,478,480],{"class":50,"line":109},[48,459,409],{"class":65},[48,461,462],{"class":149}," previous",[48,464,153],{"class":65},[48,466,66],{"class":65},[48,468,423],{"class":149},[48,470,153],{"class":65},[48,472,96],{"class":95},[48,474,475],{"class":99},"title",[48,477,103],{"class":95},[48,479,89],{"class":65},[48,481,455],{"class":65},[48,483,484,486],{"class":50,"line":116},[48,485,200],{"class":139},[48,487,240],{"class":65},[16,489,490,492],{},[34,491,374],{}," renames the column on your database. Before the change leaves it, freeze it:",[39,494,498],{"className":495,"code":496,"language":497,"meta":44,"style":44},"language-bash shiki shiki-themes material-theme-lighter fougere-pastel material-theme-palenight","fougere freeze v2\n","bash",[34,499,500],{"__ignoreMap":44},[48,501,502,506,509],{"class":50,"line":51},[48,503,505],{"class":504},"sV8pK","fougere",[48,507,508],{"class":99}," freeze",[48,510,511],{"class":99}," v2\n",[16,513,514,515,518,519,522,523,526,527,530],{},"A deployment runs ",[34,516,517],{},"fougere migrate --apply",", which applies only what was frozen — a change\nnobody froze is refused there, by name. A field that left with no ",[34,520,521],{},"previous:"," is a drop:\n",[34,524,525],{},"fougere freeze"," warns that its column goes at the next ",[34,528,529],{},"migrate",", and its data with it.",[16,532,351,533],{},[20,534,536],{"href":535},"\u002Fdocs\u002Fschema\u002Fevolution","How a schema moves",[26,538,540],{"id":539},"repositories","Repositories",[16,542,543],{},"A repository is where an entity's rows are read and written. Every entity has one already;\nwrite the class when a query deserves a name:",[39,545,547],{"className":41,"code":546,"language":43,"meta":44,"style":44},"\u002F\u002F fronds\u002Fshop\u002Frepositories\u002FProductRepository.ts\nimport { Repository } from '@fougere\u002Fcore';\nimport Product from '..\u002Fentities\u002FProduct.js';\n\nexport default class ProductRepository extends Repository(Product) {\n  cheapest(): Promise\u003CProduct[]> {\n    return this.list({ orderBy: 'cents', limit: 5 });\n  }\n}\n",[34,548,549,554,575,591,595,619,644,691,696],{"__ignoreMap":44},[48,550,551],{"class":50,"line":51},[48,552,553],{"class":54},"\u002F\u002F fronds\u002Fshop\u002Frepositories\u002FProductRepository.ts\n",[48,555,556,558,560,563,565,567,569,571,573],{"class":50,"line":58},[48,557,62],{"class":61},[48,559,66],{"class":65},[48,561,562],{"class":69}," Repository",[48,564,89],{"class":65},[48,566,92],{"class":61},[48,568,96],{"class":95},[48,570,297],{"class":99},[48,572,103],{"class":95},[48,574,106],{"class":65},[48,576,577,579,581,583,585,587,589],{"class":50,"line":109},[48,578,62],{"class":61},[48,580,308],{"class":69},[48,582,311],{"class":61},[48,584,96],{"class":95},[48,586,316],{"class":99},[48,588,103],{"class":95},[48,590,106],{"class":65},[48,592,593],{"class":50,"line":116},[48,594,113],{"emptyLinePlaceholder":112},[48,596,597,599,601,603,606,608,610,612,614,616],{"class":50,"line":146},[48,598,119],{"class":61},[48,600,122],{"class":61},[48,602,126],{"class":125},[48,604,605],{"class":129}," ProductRepository",[48,607,133],{"class":125},[48,609,562],{"class":136},[48,611,140],{"class":139},[48,613,344],{"class":69},[48,615,200],{"class":139},[48,617,618],{"class":65}," {\n",[48,620,621,625,628,631,634,636,639,642],{"class":50,"line":164},[48,622,624],{"class":623},"shDkW","  cheapest",[48,626,627],{"class":65},"():",[48,629,630],{"class":129}," Promise",[48,632,633],{"class":65},"\u003C",[48,635,344],{"class":129},[48,637,638],{"class":139},"[]",[48,640,641],{"class":65},">",[48,643,618],{"class":65},[48,645,646,649,653,656,658,661,663,666,668,670,673,675,677,680,682,685,687,689],{"class":50,"line":205},[48,647,648],{"class":61},"    return",[48,650,652],{"class":651},"sxG60"," this",[48,654,655],{"class":65},".",[48,657,256],{"class":136},[48,659,140],{"class":660},"spAFX",[48,662,176],{"class":65},[48,664,665],{"class":149}," orderBy",[48,667,153],{"class":65},[48,669,96],{"class":95},[48,671,672],{"class":99},"cents",[48,674,103],{"class":95},[48,676,73],{"class":65},[48,678,679],{"class":149}," limit",[48,681,153],{"class":65},[48,683,684],{"class":184}," 5",[48,686,89],{"class":65},[48,688,200],{"class":660},[48,690,106],{"class":65},[48,692,693],{"class":50,"line":232},[48,694,695],{"class":65},"  }\n",[48,697,699],{"class":50,"line":698},9,[48,700,701],{"class":65},"}\n",[16,703,704,705,708],{},"A repository is a service like ",[34,706,707],{},"Payment",": a handler asks for it by type.",[39,710,712],{"className":41,"code":711,"language":43,"meta":44,"style":44},"\u002F\u002F fronds\u002Fshop\u002Fhandlers\u002FCartHandler.ts\nimport ProductRepository from '..\u002Frepositories\u002FProductRepository.js';\n\nexport default class CartHandler {\n  constructor(private products: ProductRepository) {}\n\n  async getTotal(): Promise\u003Cnumber> {\n    const products = await this.products.list();\n\n    return products.reduce((sum, product) => sum + product.cents, 0);\n  }\n}\n",[34,713,714,719,737,741,754,776,780,801,829,833,883,888],{"__ignoreMap":44},[48,715,716],{"class":50,"line":51},[48,717,718],{"class":54},"\u002F\u002F fronds\u002Fshop\u002Fhandlers\u002FCartHandler.ts\n",[48,720,721,723,726,728,730,733,735],{"class":50,"line":58},[48,722,62],{"class":61},[48,724,725],{"class":69}," ProductRepository ",[48,727,311],{"class":61},[48,729,96],{"class":95},[48,731,732],{"class":99},"..\u002Frepositories\u002FProductRepository.js",[48,734,103],{"class":95},[48,736,106],{"class":65},[48,738,739],{"class":50,"line":109},[48,740,113],{"emptyLinePlaceholder":112},[48,742,743,745,747,749,752],{"class":50,"line":116},[48,744,119],{"class":61},[48,746,122],{"class":61},[48,748,126],{"class":125},[48,750,751],{"class":129}," CartHandler",[48,753,618],{"class":65},[48,755,756,759,761,764,768,770,772,774],{"class":50,"line":146},[48,757,758],{"class":125},"  constructor",[48,760,140],{"class":65},[48,762,763],{"class":125},"private",[48,765,767],{"class":766},"shDUQ"," products",[48,769,153],{"class":65},[48,771,605],{"class":129},[48,773,200],{"class":65},[48,775,240],{"class":65},[48,777,778],{"class":50,"line":164},[48,779,113],{"emptyLinePlaceholder":112},[48,781,782,785,788,790,792,794,797,799],{"class":50,"line":205},[48,783,784],{"class":125},"  async",[48,786,787],{"class":623}," getTotal",[48,789,627],{"class":65},[48,791,630],{"class":129},[48,793,633],{"class":65},[48,795,796],{"class":129},"number",[48,798,641],{"class":65},[48,800,618],{"class":65},[48,802,803,806,808,811,814,816,818,821,823,825,827],{"class":50,"line":232},[48,804,805],{"class":125},"    const",[48,807,767],{"class":69},[48,809,810],{"class":65}," =",[48,812,813],{"class":61}," await",[48,815,652],{"class":651},[48,817,655],{"class":65},[48,819,246],{"class":820},"sy9f4",[48,822,655],{"class":65},[48,824,256],{"class":136},[48,826,158],{"class":660},[48,828,106],{"class":65},[48,830,831],{"class":50,"line":698},[48,832,113],{"emptyLinePlaceholder":112},[48,834,836,838,840,842,845,847,849,852,854,857,859,863,866,869,871,873,875,877,879,881],{"class":50,"line":835},10,[48,837,648],{"class":61},[48,839,767],{"class":69},[48,841,655],{"class":65},[48,843,844],{"class":136},"reduce",[48,846,140],{"class":660},[48,848,140],{"class":65},[48,850,851],{"class":766},"sum",[48,853,73],{"class":65},[48,855,856],{"class":766}," product",[48,858,200],{"class":65},[48,860,862],{"class":861},"scTuO"," =>",[48,864,865],{"class":69}," sum",[48,867,868],{"class":65}," +",[48,870,856],{"class":69},[48,872,655],{"class":65},[48,874,672],{"class":820},[48,876,73],{"class":65},[48,878,223],{"class":184},[48,880,200],{"class":660},[48,882,106],{"class":65},[48,884,886],{"class":50,"line":885},11,[48,887,695],{"class":65},[48,889,891],{"class":50,"line":890},12,[48,892,701],{"class":65},[16,894,351,895],{},[20,896,540],{"href":897},"\u002Fdocs\u002Fbusiness\u002Frepositories",[26,899,901],{"id":900},"forms","Forms",[16,903,904,907],{},[34,905,906],{},"useFormFor"," builds a form's state from the entity. It checks in the browser what the\nserver checks, so an empty title or a negative price is refused before anything is sent:",[39,909,913],{"className":910,"code":911,"language":912,"meta":44,"style":44},"language-vue shiki shiki-themes material-theme-lighter fougere-pastel material-theme-palenight","\u003Cscript setup lang=\"ts\">\nimport Product from '@fronds\u002Fshop\u002Fentities\u002FProduct.js';\n\nconst { values, errors, submit, loading } = useFormFor(Product);\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cform @submit.prevent=\"submit\">\n    \u003Cinput v-model=\"values.title\" \u002F>\n    \u003Cp v-if=\"errors.title\">{{ errors.title }}\u003C\u002Fp>\n    \u003Cinput v-model.number=\"values.cents\" type=\"number\" \u002F>\n    \u003Cp v-if=\"errors.cents\">{{ errors.cents }}\u003C\u002Fp>\n    \u003Cbutton :disabled=\"loading\">Add\u003C\u002Fbutton>\n  \u003C\u002Fform>\n\u003C\u002Ftemplate>\n","vue",[34,914,915,943,960,964,1004,1013,1017,1026,1048,1071,1100,1131,1159,1190,1200],{"__ignoreMap":44},[48,916,917,919,923,927,930,933,936,938,940],{"class":50,"line":51},[48,918,633],{"class":65},[48,920,922],{"class":921},"s687E","script",[48,924,926],{"class":925},"s8ClO"," setup",[48,928,929],{"class":925}," lang",[48,931,932],{"class":65},"=",[48,934,935],{"class":95},"\"",[48,937,43],{"class":99},[48,939,935],{"class":95},[48,941,942],{"class":65},">\n",[48,944,945,947,949,951,953,956,958],{"class":50,"line":58},[48,946,62],{"class":61},[48,948,308],{"class":69},[48,950,311],{"class":61},[48,952,96],{"class":95},[48,954,955],{"class":99},"@fronds\u002Fshop\u002Fentities\u002FProduct.js",[48,957,103],{"class":95},[48,959,106],{"class":65},[48,961,962],{"class":50,"line":109},[48,963,113],{"emptyLinePlaceholder":112},[48,965,966,969,971,974,976,979,981,984,986,989,991,993,996,998,1000,1002],{"class":50,"line":116},[48,967,968],{"class":125},"const",[48,970,66],{"class":65},[48,972,973],{"class":69}," values",[48,975,73],{"class":65},[48,977,978],{"class":69}," errors",[48,980,73],{"class":65},[48,982,983],{"class":69}," submit",[48,985,73],{"class":65},[48,987,988],{"class":69}," loading ",[48,990,235],{"class":65},[48,992,810],{"class":65},[48,994,995],{"class":136}," useFormFor",[48,997,140],{"class":139},[48,999,344],{"class":69},[48,1001,200],{"class":139},[48,1003,106],{"class":65},[48,1005,1006,1009,1011],{"class":50,"line":146},[48,1007,1008],{"class":65},"\u003C\u002F",[48,1010,922],{"class":921},[48,1012,942],{"class":65},[48,1014,1015],{"class":50,"line":164},[48,1016,113],{"emptyLinePlaceholder":112},[48,1018,1019,1021,1024],{"class":50,"line":205},[48,1020,633],{"class":65},[48,1022,1023],{"class":921},"template",[48,1025,942],{"class":65},[48,1027,1028,1031,1034,1037,1039,1041,1044,1046],{"class":50,"line":232},[48,1029,1030],{"class":65},"  \u003C",[48,1032,1033],{"class":921},"form",[48,1035,1036],{"class":925}," @submit.prevent",[48,1038,932],{"class":65},[48,1040,935],{"class":95},[48,1042,1043],{"class":99},"submit",[48,1045,935],{"class":95},[48,1047,942],{"class":65},[48,1049,1050,1053,1056,1059,1061,1063,1066,1068],{"class":50,"line":698},[48,1051,1052],{"class":65},"    \u003C",[48,1054,1055],{"class":921},"input",[48,1057,1058],{"class":925}," v-model",[48,1060,932],{"class":65},[48,1062,935],{"class":95},[48,1064,1065],{"class":99},"values.title",[48,1067,935],{"class":95},[48,1069,1070],{"class":65}," \u002F>\n",[48,1072,1073,1075,1077,1080,1082,1084,1087,1089,1091,1094,1096,1098],{"class":50,"line":835},[48,1074,1052],{"class":65},[48,1076,16],{"class":921},[48,1078,1079],{"class":925}," v-if",[48,1081,932],{"class":65},[48,1083,935],{"class":95},[48,1085,1086],{"class":99},"errors.title",[48,1088,935],{"class":95},[48,1090,641],{"class":65},[48,1092,1093],{"class":69},"{{ errors.title }}",[48,1095,1008],{"class":65},[48,1097,16],{"class":921},[48,1099,942],{"class":65},[48,1101,1102,1104,1106,1109,1111,1113,1116,1118,1121,1123,1125,1127,1129],{"class":50,"line":885},[48,1103,1052],{"class":65},[48,1105,1055],{"class":921},[48,1107,1108],{"class":925}," v-model.number",[48,1110,932],{"class":65},[48,1112,935],{"class":95},[48,1114,1115],{"class":99},"values.cents",[48,1117,935],{"class":95},[48,1119,1120],{"class":925}," type",[48,1122,932],{"class":65},[48,1124,935],{"class":95},[48,1126,796],{"class":99},[48,1128,935],{"class":95},[48,1130,1070],{"class":65},[48,1132,1133,1135,1137,1139,1141,1143,1146,1148,1150,1153,1155,1157],{"class":50,"line":890},[48,1134,1052],{"class":65},[48,1136,16],{"class":921},[48,1138,1079],{"class":925},[48,1140,932],{"class":65},[48,1142,935],{"class":95},[48,1144,1145],{"class":99},"errors.cents",[48,1147,935],{"class":95},[48,1149,641],{"class":65},[48,1151,1152],{"class":69},"{{ errors.cents }}",[48,1154,1008],{"class":65},[48,1156,16],{"class":921},[48,1158,942],{"class":65},[48,1160,1162,1164,1167,1170,1172,1174,1177,1179,1181,1184,1186,1188],{"class":50,"line":1161},13,[48,1163,1052],{"class":65},[48,1165,1166],{"class":921},"button",[48,1168,1169],{"class":925}," :disabled",[48,1171,932],{"class":65},[48,1173,935],{"class":95},[48,1175,1176],{"class":99},"loading",[48,1178,935],{"class":95},[48,1180,641],{"class":65},[48,1182,1183],{"class":69},"Add",[48,1185,1008],{"class":65},[48,1187,1166],{"class":921},[48,1189,942],{"class":65},[48,1191,1193,1196,1198],{"class":50,"line":1192},14,[48,1194,1195],{"class":65},"  \u003C\u002F",[48,1197,1033],{"class":921},[48,1199,942],{"class":65},[48,1201,1203,1205,1207],{"class":50,"line":1202},15,[48,1204,1008],{"class":65},[48,1206,1023],{"class":921},[48,1208,942],{"class":65},[16,1210,1211,1213,1214,1216],{},[34,1212,1043],{}," calls ",[34,1215,263],{},". After it succeeds, every page listing products refreshes on its\nown.",[16,1218,351,1219],{},[20,1220,901],{"href":1221},"\u002Fdocs\u002Fclient\u002Fforms",[26,1223,1225],{"id":1224},"rest-and-graphql","REST and GraphQL",[16,1227,1228,1229,1232],{},"The same products are served over REST and GraphQL when the config says so. Each is a\npackage of its own: the config imports it, and names it under ",[34,1230,1231],{},"protocols:"," to serve it.",[1234,1235,1239,1258,1275,1291],"code-group",{"className":1236,"sync":1238},[1237],"managers","pm",[39,1240,1243],{"className":495,"code":1241,"filename":1242,"language":497,"meta":44,"style":44},"npm install @fougere\u002Fadapter-rest @fougere\u002Fadapter-graphql\n","npm",[34,1244,1245],{"__ignoreMap":44},[48,1246,1247,1249,1252,1255],{"class":50,"line":51},[48,1248,1242],{"class":504},[48,1250,1251],{"class":99}," install",[48,1253,1254],{"class":99}," @fougere\u002Fadapter-rest",[48,1256,1257],{"class":99}," @fougere\u002Fadapter-graphql\n",[39,1259,1262],{"className":495,"code":1260,"filename":1261,"language":497,"meta":44,"style":44},"pnpm add @fougere\u002Fadapter-rest @fougere\u002Fadapter-graphql\n","pnpm",[34,1263,1264],{"__ignoreMap":44},[48,1265,1266,1268,1271,1273],{"class":50,"line":51},[48,1267,1261],{"class":504},[48,1269,1270],{"class":99}," add",[48,1272,1254],{"class":99},[48,1274,1257],{"class":99},[39,1276,1279],{"className":495,"code":1277,"filename":1278,"language":497,"meta":44,"style":44},"bun add @fougere\u002Fadapter-rest @fougere\u002Fadapter-graphql\n","bun",[34,1280,1281],{"__ignoreMap":44},[48,1282,1283,1285,1287,1289],{"class":50,"line":51},[48,1284,1278],{"class":504},[48,1286,1270],{"class":99},[48,1288,1254],{"class":99},[48,1290,1257],{"class":99},[39,1292,1295],{"className":495,"code":1293,"filename":1294,"language":497,"meta":44,"style":44},"yarn add @fougere\u002Fadapter-rest @fougere\u002Fadapter-graphql\n","yarn",[34,1296,1297],{"__ignoreMap":44},[48,1298,1299,1301,1303,1305],{"class":50,"line":51},[48,1300,1294],{"class":504},[48,1302,1270],{"class":99},[48,1304,1254],{"class":99},[48,1306,1257],{"class":99},[39,1308,1310],{"className":41,"code":1309,"language":43,"meta":44,"style":44},"\u002F\u002F fougere.config.ts\nimport '@fougere\u002Fadapter-rest';\nimport '@fougere\u002Fadapter-graphql';\n\nexport default defineFougere({\n  protocols: { rest: {}, graphql: {} },\n});\n",[34,1311,1312,1317,1330,1343,1347,1360,1387],{"__ignoreMap":44},[48,1313,1314],{"class":50,"line":51},[48,1315,1316],{"class":54},"\u002F\u002F fougere.config.ts\n",[48,1318,1319,1321,1323,1326,1328],{"class":50,"line":58},[48,1320,62],{"class":61},[48,1322,96],{"class":95},[48,1324,1325],{"class":99},"@fougere\u002Fadapter-rest",[48,1327,103],{"class":95},[48,1329,106],{"class":65},[48,1331,1332,1334,1336,1339,1341],{"class":50,"line":109},[48,1333,62],{"class":61},[48,1335,96],{"class":95},[48,1337,1338],{"class":99},"@fougere\u002Fadapter-graphql",[48,1340,103],{"class":95},[48,1342,106],{"class":65},[48,1344,1345],{"class":50,"line":116},[48,1346,113],{"emptyLinePlaceholder":112},[48,1348,1349,1351,1353,1356,1358],{"class":50,"line":146},[48,1350,119],{"class":61},[48,1352,122],{"class":61},[48,1354,1355],{"class":136}," defineFougere",[48,1357,140],{"class":139},[48,1359,143],{"class":65},[48,1361,1362,1365,1367,1369,1372,1374,1377,1380,1382,1385],{"class":50,"line":164},[48,1363,1364],{"class":149},"  protocols",[48,1366,153],{"class":65},[48,1368,66],{"class":65},[48,1370,1371],{"class":149}," rest",[48,1373,153],{"class":65},[48,1375,1376],{"class":65}," {},",[48,1378,1379],{"class":149}," graphql",[48,1381,153],{"class":65},[48,1383,1384],{"class":65}," {}",[48,1386,455],{"class":65},[48,1388,1389,1391,1393],{"class":50,"line":205},[48,1390,235],{"class":65},[48,1392,200],{"class":139},[48,1394,106],{"class":65},[16,1396,1397,1398,1401,1402,153],{},"The REST path is ",[34,1399,1400],{},"\u002Fapi\u002F{frond}\u002F{address, plural}",", and GraphQL answers on ",[34,1403,1404],{},"\u002Fgraphql",[39,1406,1408],{"className":495,"code":1407,"language":497,"meta":44,"style":44},"curl http:\u002F\u002Flocalhost:3000\u002Fapi\u002Fshop\u002Fproducts\n\ncurl -X POST http:\u002F\u002Flocalhost:3000\u002Fgraphql \\\n  -H 'content-type: application\u002Fjson' \\\n  -d '{\"query\":\"{ products { items { title cents } } }\"}'\n",[34,1409,1410,1418,1422,1439,1453],{"__ignoreMap":44},[48,1411,1412,1415],{"class":50,"line":51},[48,1413,1414],{"class":504},"curl",[48,1416,1417],{"class":99}," http:\u002F\u002Flocalhost:3000\u002Fapi\u002Fshop\u002Fproducts\n",[48,1419,1420],{"class":50,"line":58},[48,1421,113],{"emptyLinePlaceholder":112},[48,1423,1424,1426,1430,1433,1436],{"class":50,"line":109},[48,1425,1414],{"class":504},[48,1427,1429],{"class":1428},"svHQO"," -X",[48,1431,1432],{"class":99}," POST",[48,1434,1435],{"class":99}," http:\u002F\u002Flocalhost:3000\u002Fgraphql",[48,1437,1438],{"class":69}," \\\n",[48,1440,1441,1444,1446,1449,1451],{"class":50,"line":116},[48,1442,1443],{"class":1428},"  -H",[48,1445,96],{"class":95},[48,1447,1448],{"class":99},"content-type: application\u002Fjson",[48,1450,103],{"class":95},[48,1452,1438],{"class":69},[48,1454,1455,1458,1460,1463],{"class":50,"line":146},[48,1456,1457],{"class":1428},"  -d",[48,1459,96],{"class":95},[48,1461,1462],{"class":99},"{\"query\":\"{ products { items { title cents } } }\"}",[48,1464,1465],{"class":95},"'\n",[16,1467,1468,1469,1472,1473,1476],{},"A list is a page on both: the rows are in ",[34,1470,1471],{},"items",". ",[34,1474,1475],{},"npx get-graphql-schema http:\u002F\u002Flocalhost:3000\u002Fgraphql"," prints the whole schema.",[16,1478,351,1479],{},[20,1480,1482],{"href":1481},"\u002Fdocs\u002Finfra\u002Fsurfaces","Surfaces",[26,1484,1486],{"id":1485},"one-more-field","One more field",[16,1488,1489],{},"Add a field to the entity:",[39,1491,1493],{"className":41,"code":1492,"language":43,"meta":44,"style":44},"description: optional(text({ max: 500 })),\n",[34,1494,1495],{"__ignoreMap":44},[48,1496,1497,1501,1503,1506,1508,1510,1512,1514,1516,1518,1521,1523,1526],{"class":50,"line":51},[48,1498,1500],{"class":1499},"sWI7z","description",[48,1502,153],{"class":65},[48,1504,1505],{"class":136}," optional",[48,1507,140],{"class":139},[48,1509,367],{"class":136},[48,1511,140],{"class":139},[48,1513,176],{"class":65},[48,1515,190],{"class":149},[48,1517,153],{"class":65},[48,1519,1520],{"class":184}," 500",[48,1522,89],{"class":65},[48,1524,1525],{"class":139},"))",[48,1527,161],{"class":65},[16,1529,1530,1531,1533,1534,1536,1537,1540,1541,1544,1545,1548],{},"and run ",[34,1532,374],{},". The column is in the table, ",[34,1535,1500],{}," is in every REST answer,\nin the GraphQL type and in ",[34,1538,1539],{},"createProduct"," and ",[34,1542,1543],{},"updateProduct",", and a form that loops over\n",[34,1546,1547],{},"useFormFor(Product).fields"," shows it. 501 characters are refused in the browser, in REST\nand in GraphQL, by the same rule. You wrote one line; nothing else could fall behind it.",[16,1550,1551,1552,655],{},"Next: ",[20,1553,1555],{"href":1554},"\u002Fdocs\u002Fguides\u002Ftopology","Shape your topology",[1557,1558,1559],"style",{},"html pre.shiki code .skXKP, html code.shiki .skXKP{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7D8C80;--shiki-default-font-style:inherit;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sK6XW, html code.shiki .sK6XW{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#8FCF86;--shiki-default-font-style:inherit;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s15xx, html code.shiki .s15xx{--shiki-light:#39ADB5;--shiki-default:#A3B0A5;--shiki-dark:#89DDFF}html pre.shiki code .sPEhv, html code.shiki .sPEhv{--shiki-light:#90A4AE;--shiki-default:#DDE5DA;--shiki-dark:#BABED8}html pre.shiki code .sDDC1, html code.shiki .sDDC1{--shiki-light:#39ADB5;--shiki-default:#EE9F6B;--shiki-dark:#89DDFF}html pre.shiki code .sN-8n, html code.shiki .sN-8n{--shiki-light:#91B859;--shiki-default:#EE9F6B;--shiki-dark:#C3E88D}html pre.shiki code .s76I7, html code.shiki .s76I7{--shiki-light:#9C3EDA;--shiki-default:#8FCF86;--shiki-dark:#C792EA}html pre.shiki code .sBZYL, html code.shiki .sBZYL{--shiki-light:#E2931D;--shiki-default:#EFCD8F;--shiki-dark:#FFCB6B}html pre.shiki code .s4mR9, html code.shiki .s4mR9{--shiki-light:#6182B8;--shiki-default:#C9B6EA;--shiki-dark:#82AAFF}html pre.shiki code .srlTG, html code.shiki .srlTG{--shiki-light:#90A4AE;--shiki-default:#A3B0A5;--shiki-dark:#BABED8}html pre.shiki code .sHtqg, html code.shiki .sHtqg{--shiki-light:#E53935;--shiki-default:#93CFC0;--shiki-dark:#F07178}html pre.shiki code .s3dPA, html code.shiki .s3dPA{--shiki-light:#F76D47;--shiki-default:#EE9F6B;--shiki-dark:#F78C6C}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 .sV8pK, html code.shiki .sV8pK{--shiki-light:#E2931D;--shiki-default:#C9B6EA;--shiki-dark:#FFCB6B}html pre.shiki code .shDkW, html code.shiki .shDkW{--shiki-light:#E53935;--shiki-default:#C9B6EA;--shiki-dark:#F07178}html pre.shiki code .sxG60, html code.shiki .sxG60{--shiki-light:#39ADB5;--shiki-light-font-style:inherit;--shiki-default:#8FCF86;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:inherit}html pre.shiki code .spAFX, html code.shiki .spAFX{--shiki-light:#E53935;--shiki-default:#A3B0A5;--shiki-dark:#F07178}html pre.shiki code .shDUQ, html code.shiki .shDUQ{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#DDE5DA;--shiki-default-font-style:inherit;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sy9f4, html code.shiki .sy9f4{--shiki-light:#90A4AE;--shiki-default:#93CFC0;--shiki-dark:#BABED8}html pre.shiki code .scTuO, html code.shiki .scTuO{--shiki-light:#9C3EDA;--shiki-default:#A3B0A5;--shiki-dark:#C792EA}html pre.shiki code .s687E, html code.shiki .s687E{--shiki-light:#E53935;--shiki-default:#8FCF86;--shiki-dark:#F07178}html pre.shiki code .s8ClO, html code.shiki .s8ClO{--shiki-light:#9C3EDA;--shiki-default:#93CFC0;--shiki-dark:#C792EA}html pre.shiki code .svHQO, html code.shiki .svHQO{--shiki-light:#91B859;--shiki-default:#8FCF86;--shiki-dark:#C3E88D}html pre.shiki code .sWI7z, html code.shiki .sWI7z{--shiki-light:#E2931D;--shiki-default:#93CFC0;--shiki-dark:#FFCB6B}",{"title":44,"searchDepth":58,"depth":58,"links":1561},[1562,1563,1564,1565,1566,1567],{"id":28,"depth":58,"text":29},{"id":357,"depth":58,"text":358},{"id":539,"depth":58,"text":540},{"id":900,"depth":58,"text":901},{"id":1224,"depth":58,"text":1225},{"id":1485,"depth":58,"text":1486},"An entity, the repository that holds its rows, a form built from it, and the same rows over REST and GraphQL.","md",{},"\u002Fdocs\u002Fguides\u002Fdata",{"title":7,"description":1568},"docs\u002F1.guides\u002F2.data","H4MH2HpyyrSs_24IcSzX_DztzXn_0lky_yuAWbq-T8E",[1576],{"title":1577,"path":1578,"stem":1579,"children":1580,"page":-1},"Docs","\u002Fdocs","docs",[1581,1584,1588,1592,1596,1600,1604,1620,1641,1662,1709,1732],{"title":1582,"path":1578,"stem":1583},"What is Fougere","docs\u002Findex",{"title":1585,"path":1586,"stem":1587},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started",{"title":1589,"path":1590,"stem":1591},"An app you already have","\u002Fdocs\u002Fexisting-app","docs\u002F02.existing-app",{"title":1593,"path":1594,"stem":1595},"Bring your schema","\u002Fdocs\u002Fbring-your-schema","docs\u002F03.bring-your-schema",{"title":1597,"path":1598,"stem":1599},"The CLI","\u002Fdocs\u002Fcli","docs\u002F04.cli",{"title":1601,"path":1602,"stem":1603},"Demos","\u002Fdocs\u002Fdemos","docs\u002F05.demos",{"title":1605,"path":1606,"stem":1607,"children":1608,"page":1619},"Guides","\u002Fdocs\u002Fguides","docs\u002F1.guides",[1609,1612,1613,1615],{"title":1610,"path":22,"stem":1611},"Handle your business logic","docs\u002F1.guides\u002F1.business-logic",{"title":7,"path":1571,"stem":1573},{"title":1555,"path":1554,"stem":1614},"docs\u002F1.guides\u002F3.topology",{"title":1616,"path":1617,"stem":1618},"Choose how it runs","\u002Fdocs\u002Fguides\u002Fconfig","docs\u002F1.guides\u002F4.config",false,{"title":1621,"path":1622,"stem":1623,"children":1624,"page":1619},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F2.concepts",[1625,1629,1633,1637],{"title":1626,"path":1627,"stem":1628},"Philosophy","\u002Fdocs\u002Fconcepts\u002Fphilosophy","docs\u002F2.concepts\u002F1.philosophy",{"title":1630,"path":1631,"stem":1632},"The Frond","\u002Fdocs\u002Fconcepts\u002Ffrond","docs\u002F2.concepts\u002F2.frond",{"title":1634,"path":1635,"stem":1636},"The shortest path","\u002Fdocs\u002Fconcepts\u002Fshortest-path","docs\u002F2.concepts\u002F3.shortest-path",{"title":1638,"path":1639,"stem":1640},"The base","\u002Fdocs\u002Fconcepts\u002Fthe-base","docs\u002F2.concepts\u002F4.the-base",{"title":1642,"path":1643,"stem":1644,"children":1645,"page":1619},"Schema","\u002Fdocs\u002Fschema","docs\u002F3.schema",[1646,1648,1652,1656,1660],{"title":29,"path":354,"stem":1647},"docs\u002F3.schema\u002F1.entities",{"title":1649,"path":1650,"stem":1651},"Views","\u002Fdocs\u002Fschema\u002Fviews","docs\u002F3.schema\u002F2.views",{"title":1653,"path":1654,"stem":1655},"The identity card","\u002Fdocs\u002Fschema\u002Fcard","docs\u002F3.schema\u002F3.card",{"title":1657,"path":1658,"stem":1659},"Standard Schema","\u002Fdocs\u002Fschema\u002Fstandard-schema","docs\u002F3.schema\u002F4.standard-schema",{"title":536,"path":535,"stem":1661},"docs\u002F3.schema\u002F5.evolution",{"title":1663,"path":1664,"stem":1665,"children":1666,"page":1619},"Business","\u002Fdocs\u002Fbusiness","docs\u002F4.business",[1667,1671,1675,1679,1683,1687,1691,1695,1699,1703,1707],{"title":1668,"path":1669,"stem":1670},"Handlers","\u002Fdocs\u002Fbusiness\u002Fhandlers","docs\u002F4.business\u002F1.handlers",{"title":1672,"path":1673,"stem":1674},"Ports","\u002Fdocs\u002Fbusiness\u002Fports","docs\u002F4.business\u002F10.ports",{"title":1676,"path":1677,"stem":1678},"Caller state","\u002Fdocs\u002Fbusiness\u002Fstate","docs\u002F4.business\u002F11.state",{"title":1680,"path":1681,"stem":1682},"Presenters","\u002Fdocs\u002Fbusiness\u002Fpresenters","docs\u002F4.business\u002F2.presenters",{"title":1684,"path":1685,"stem":1686},"Collectors","\u002Fdocs\u002Fbusiness\u002Fcollectors","docs\u002F4.business\u002F3.collectors",{"title":1688,"path":1689,"stem":1690},"Errors","\u002Fdocs\u002Fbusiness\u002Ferrors","docs\u002F4.business\u002F4.errors",{"title":1692,"path":1693,"stem":1694},"Seeds","\u002Fdocs\u002Fbusiness\u002Fseeds","docs\u002F4.business\u002F5.seeds",{"title":1696,"path":1697,"stem":1698},"Facts","\u002Fdocs\u002Fbusiness\u002Ffacts","docs\u002F4.business\u002F6.facts",{"title":1700,"path":1701,"stem":1702},"Storage","\u002Fdocs\u002Fbusiness\u002Fstorage","docs\u002F4.business\u002F7.storage",{"title":1704,"path":1705,"stem":1706},"Writes that stand or fall as one","\u002Fdocs\u002Fbusiness\u002Ftogether","docs\u002F4.business\u002F8.together",{"title":540,"path":897,"stem":1708},"docs\u002F4.business\u002F9.repositories",{"title":1710,"path":1711,"stem":1712,"children":1713,"page":1619},"Client","\u002Fdocs\u002Fclient","docs\u002F5.client",[1714,1718,1720,1724,1728],{"title":1715,"path":1716,"stem":1717},"Queries & commands","\u002Fdocs\u002Fclient\u002Fqueries-commands","docs\u002F5.client\u002F1.queries-commands",{"title":901,"path":1221,"stem":1719},"docs\u002F5.client\u002F2.forms",{"title":1721,"path":1722,"stem":1723},"Session","\u002Fdocs\u002Fclient\u002Fsession","docs\u002F5.client\u002F3.session",{"title":1725,"path":1726,"stem":1727},"invoke","\u002Fdocs\u002Fclient\u002Finvoke","docs\u002F5.client\u002F4.invoke",{"title":1729,"path":1730,"stem":1731},"Back-office","\u002Fdocs\u002Fclient\u002Fadmin","docs\u002F5.client\u002F5.admin",{"title":1733,"path":1734,"stem":1735,"children":1736,"page":1619},"Infrastructure","\u002Fdocs\u002Finfra","docs\u002F6.infra",[1737,1741,1744,1748,1752,1756,1760,1764,1768],{"title":1738,"path":1739,"stem":1740},"The gradient","\u002Fdocs\u002Finfra\u002Fgradient","docs\u002F6.infra\u002F1.gradient",{"title":1742,"path":1481,"stem":1743},"Surfaces — REST & GraphQL","docs\u002F6.infra\u002F2.surfaces",{"title":1745,"path":1746,"stem":1747},"Deployment","\u002Fdocs\u002Finfra\u002Fdeployment","docs\u002F6.infra\u002F3.deployment",{"title":1749,"path":1750,"stem":1751},"Hosts","\u002Fdocs\u002Finfra\u002Fhosts","docs\u002F6.infra\u002F4.hosts",{"title":1753,"path":1754,"stem":1755},"Sources","\u002Fdocs\u002Finfra\u002Fsources","docs\u002F6.infra\u002F5.sources",{"title":1757,"path":1758,"stem":1759},"Lifecycle","\u002Fdocs\u002Finfra\u002Flifecycle","docs\u002F6.infra\u002F6.lifecycle",{"title":1761,"path":1762,"stem":1763},"Identity across Fronds","\u002Fdocs\u002Finfra\u002Fidentity","docs\u002F6.infra\u002F7.identity",{"title":1765,"path":1766,"stem":1767},"Observability","\u002Fdocs\u002Finfra\u002Fobservability","docs\u002F6.infra\u002F8.observability",{"title":1769,"path":1770,"stem":1771},"Testing","\u002Fdocs\u002Finfra\u002Ftesting","docs\u002F6.infra\u002F9.testing",1792704168333]