[{"data":1,"prerenderedAt":2158},["ShallowReactive",2],{"fougere:post.list:{}":3,"docs:\u002Fdocs\u002Faccess\u002Fauthentication":6,"docs-uses":1849,"docs-nav":2020},{"items":4,"hasMore":5},[],false,{"id":7,"title":8,"body":9,"description":1835,"extension":1836,"forms":1837,"kind":1839,"meta":1840,"navigation":100,"path":1841,"seo":1842,"stem":1843,"step":1844,"uses":1845,"__hash__":1848},"docs\u002Fdocs\u002F2.access\u002F1.authentication.md","Authentication",{"type":10,"value":11,"toc":1825},"minimark",[12,16,21,313,358,379,383,394,546,560,564,567,736,747,789,899,902,906,921,1153,1156,1257,1294,1297,1347,1350,1354,1571,1576,1579,1599,1602,1697,1712,1716,1735,1789,1792,1806,1821],[13,14,15],"p",{},"Signing in is the job of an auth frond, built on better-auth. Your operations never handle a cookie:\nthey ask who calls by the type of a parameter, and the answer reaches them in this process or\nanother.",[17,18,20],"h2",{"id":19},"add-the-auth-frond","Add the auth frond",[22,23,28],"pre",{"className":24,"code":25,"language":26,"meta":27,"style":27},"language-ts shiki shiki-themes material-theme-lighter fougere-pastel material-theme-palenight","\u002F\u002F fougere.config.ts\nimport { betterAuth } from '@fougere\u002Fauth-better';\nimport User from '.\u002Ffronds\u002Fuser\u002Fentities\u002FUser';\n\nexport default defineFougere({\n  fronds: {\n    auth: betterAuth({\n      user: User,\n      secret: process.env.AUTH_SECRET!,          \u002F\u002F 32+ characters\n      baseUrl: process.env.SITE_URL ?? 'http:\u002F\u002Flocalhost:3000',\n      basePath: '\u002Fauth',                         \u002F\u002F mounts \u002Fauth\u002F** — sign-in, sign-up, sign-out…\n      providers: { credential: { minPasswordLength: 8, autoSignIn: true } },\n    }),\n  },\n});\n","ts","",[29,30,31,40,75,95,102,122,135,149,163,192,223,244,286,297,303],"code",{"__ignoreMap":27},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"skXKP","\u002F\u002F fougere.config.ts\n",[32,41,43,47,51,55,58,61,65,69,72],{"class":34,"line":42},2,[32,44,46],{"class":45},"sK6XW","import",[32,48,50],{"class":49},"s15xx"," {",[32,52,54],{"class":53},"sPEhv"," betterAuth",[32,56,57],{"class":49}," }",[32,59,60],{"class":45}," from",[32,62,64],{"class":63},"sDDC1"," '",[32,66,68],{"class":67},"sN-8n","@fougere\u002Fauth-better",[32,70,71],{"class":63},"'",[32,73,74],{"class":49},";\n",[32,76,78,80,83,86,88,91,93],{"class":34,"line":77},3,[32,79,46],{"class":45},[32,81,82],{"class":53}," User ",[32,84,85],{"class":45},"from",[32,87,64],{"class":63},[32,89,90],{"class":67},".\u002Ffronds\u002Fuser\u002Fentities\u002FUser",[32,92,71],{"class":63},[32,94,74],{"class":49},[32,96,98],{"class":34,"line":97},4,[32,99,101],{"emptyLinePlaceholder":100},true,"\n",[32,103,105,108,111,115,119],{"class":34,"line":104},5,[32,106,107],{"class":45},"export",[32,109,110],{"class":45}," default",[32,112,114],{"class":113},"s4mR9"," defineFougere",[32,116,118],{"class":117},"srlTG","(",[32,120,121],{"class":49},"{\n",[32,123,125,129,132],{"class":34,"line":124},6,[32,126,128],{"class":127},"sHtqg","  fronds",[32,130,131],{"class":49},":",[32,133,134],{"class":49}," {\n",[32,136,138,141,143,145,147],{"class":34,"line":137},7,[32,139,140],{"class":127},"    auth",[32,142,131],{"class":49},[32,144,54],{"class":113},[32,146,118],{"class":117},[32,148,121],{"class":49},[32,150,152,155,157,160],{"class":34,"line":151},8,[32,153,154],{"class":127},"      user",[32,156,131],{"class":49},[32,158,159],{"class":53}," User",[32,161,162],{"class":49},",\n",[32,164,166,169,171,174,177,181,183,186,189],{"class":34,"line":165},9,[32,167,168],{"class":127},"      secret",[32,170,131],{"class":49},[32,172,173],{"class":53}," process",[32,175,176],{"class":49},".",[32,178,180],{"class":179},"sy9f4","env",[32,182,176],{"class":49},[32,184,185],{"class":179},"AUTH_SECRET",[32,187,188],{"class":49},"!,",[32,190,191],{"class":38},"          \u002F\u002F 32+ characters\n",[32,193,195,198,200,202,204,206,208,211,214,216,219,221],{"class":34,"line":194},10,[32,196,197],{"class":127},"      baseUrl",[32,199,131],{"class":49},[32,201,173],{"class":53},[32,203,176],{"class":49},[32,205,180],{"class":179},[32,207,176],{"class":49},[32,209,210],{"class":179},"SITE_URL",[32,212,213],{"class":49}," ??",[32,215,64],{"class":63},[32,217,218],{"class":67},"http:\u002F\u002Flocalhost:3000",[32,220,71],{"class":63},[32,222,162],{"class":49},[32,224,226,229,231,233,236,238,241],{"class":34,"line":225},11,[32,227,228],{"class":127},"      basePath",[32,230,131],{"class":49},[32,232,64],{"class":63},[32,234,235],{"class":67},"\u002Fauth",[32,237,71],{"class":63},[32,239,240],{"class":49},",",[32,242,243],{"class":38},"                         \u002F\u002F mounts \u002Fauth\u002F** — sign-in, sign-up, sign-out…\n",[32,245,247,250,252,254,257,259,261,264,266,270,272,275,277,281,283],{"class":34,"line":246},12,[32,248,249],{"class":127},"      providers",[32,251,131],{"class":49},[32,253,50],{"class":49},[32,255,256],{"class":127}," credential",[32,258,131],{"class":49},[32,260,50],{"class":49},[32,262,263],{"class":127}," minPasswordLength",[32,265,131],{"class":49},[32,267,269],{"class":268},"s3dPA"," 8",[32,271,240],{"class":49},[32,273,274],{"class":127}," autoSignIn",[32,276,131],{"class":49},[32,278,280],{"class":279},"slmMI"," true",[32,282,57],{"class":49},[32,284,285],{"class":49}," },\n",[32,287,289,292,295],{"class":34,"line":288},13,[32,290,291],{"class":49},"    }",[32,293,294],{"class":117},")",[32,296,162],{"class":49},[32,298,300],{"class":34,"line":299},14,[32,301,302],{"class":49},"  },\n",[32,304,306,309,311],{"class":34,"line":305},15,[32,307,308],{"class":49},"}",[32,310,294],{"class":117},[32,312,74],{"class":49},[13,314,315,318,319,322,323,326,327,330,331,334,335,338,339,342,343,348,349,330,351,353,354,357],{},[29,316,317],{},"betterAuth()"," is a frond named ",[29,320,321],{},"auth",". It holds the ",[29,324,325],{},"session",", ",[29,328,329],{},"account"," and ",[29,332,333],{},"verification","\ntables — and ",[29,336,337],{},"user"," when you name none — so ",[29,340,341],{},"fougere migrate"," creates them and their writes are\nchecked like any frond's. Its ",[344,345,347],"a",{"href":346},"\u002Fdocs\u002Frun\u002Flifecycle","extension"," rises only in the process that serves\nthe frond: it puts ",[29,350,337],{},[29,352,325],{}," on each call's state and mounts the better-auth endpoints. A\nprocess that leaves the frond out with ",[29,355,356],{},"only:"," starts no auth engine.",[359,360,361],"note",{},[13,362,363,364,367,368,371,372,330,375,378],{},"Do not put pages under ",[29,365,366],{},"basePath",": the server answers everything under ",[29,369,370],{},"\u002Fauth\u002F**",". This site serves\nits forms at ",[29,373,374],{},"\u002Flogin",[29,376,377],{},"\u002Fregister"," for that reason.",[17,380,382],{"id":381},"your-user","Your user",[13,384,385,386,389,390,393],{},"Your ",[29,387,388],{},"User"," extends ",[29,391,392],{},"AuthUser"," — better-auth's fields, plus yours:",[22,395,397],{"className":24,"code":396,"language":26,"meta":27,"style":27},"\u002F\u002F fronds\u002Fuser\u002Fentities\u002FUser.ts\nimport { AuthUser } from '@fougere\u002Fauth-better';\nimport { oneOf, optional } from '@fougere\u002Fschema';\n\nexport default class User extends AuthUser.extend({\n  role: optional(oneOf('admin', 'editor', 'reader')),\n}).anchor() {}\n",[29,398,399,404,425,452,456,483,529],{"__ignoreMap":27},[32,400,401],{"class":34,"line":35},[32,402,403],{"class":38},"\u002F\u002F fronds\u002Fuser\u002Fentities\u002FUser.ts\n",[32,405,406,408,410,413,415,417,419,421,423],{"class":34,"line":42},[32,407,46],{"class":45},[32,409,50],{"class":49},[32,411,412],{"class":53}," AuthUser",[32,414,57],{"class":49},[32,416,60],{"class":45},[32,418,64],{"class":63},[32,420,68],{"class":67},[32,422,71],{"class":63},[32,424,74],{"class":49},[32,426,427,429,431,434,436,439,441,443,445,448,450],{"class":34,"line":77},[32,428,46],{"class":45},[32,430,50],{"class":49},[32,432,433],{"class":53}," oneOf",[32,435,240],{"class":49},[32,437,438],{"class":53}," optional",[32,440,57],{"class":49},[32,442,60],{"class":45},[32,444,64],{"class":63},[32,446,447],{"class":67},"@fougere\u002Fschema",[32,449,71],{"class":63},[32,451,74],{"class":49},[32,453,454],{"class":34,"line":97},[32,455,101],{"emptyLinePlaceholder":100},[32,457,458,460,462,466,469,472,474,476,479,481],{"class":34,"line":104},[32,459,107],{"class":45},[32,461,110],{"class":45},[32,463,465],{"class":464},"s76I7"," class",[32,467,159],{"class":468},"sBZYL",[32,470,471],{"class":464}," extends",[32,473,412],{"class":53},[32,475,176],{"class":49},[32,477,478],{"class":113},"extend",[32,480,118],{"class":117},[32,482,121],{"class":49},[32,484,485,488,490,492,494,497,499,501,504,506,508,510,513,515,517,519,522,524,527],{"class":34,"line":124},[32,486,487],{"class":127},"  role",[32,489,131],{"class":49},[32,491,438],{"class":113},[32,493,118],{"class":117},[32,495,496],{"class":113},"oneOf",[32,498,118],{"class":117},[32,500,71],{"class":63},[32,502,503],{"class":67},"admin",[32,505,71],{"class":63},[32,507,240],{"class":49},[32,509,64],{"class":63},[32,511,512],{"class":67},"editor",[32,514,71],{"class":63},[32,516,240],{"class":49},[32,518,64],{"class":63},[32,520,521],{"class":67},"reader",[32,523,71],{"class":63},[32,525,526],{"class":117},"))",[32,528,162],{"class":49},[32,530,531,533,535,537,540,543],{"class":34,"line":137},[32,532,308],{"class":49},[32,534,294],{"class":117},[32,536,176],{"class":49},[32,538,539],{"class":113},"anchor",[32,541,542],{"class":117},"()",[32,544,545],{"class":49}," {}\n",[13,547,548,549,551,552,555,556,559],{},"The named class matters: the entity is registered as ",[29,550,388],{},", and a parameter ",[29,553,554],{},"user: User"," is matched\nby that type. ",[29,557,558],{},".anchor()"," gives the view its own rows.",[17,561,563],{"id":562},"sign-in-from-a-page","Sign in from a page",[13,565,566],{},"The pages call better-auth's endpoints directly:",[22,568,570],{"className":24,"code":569,"language":26,"meta":27,"style":27},"await $fetch('\u002Fauth\u002Fsign-up\u002Femail', { method: 'POST', body: { name, email, password } });\nawait $fetch('\u002Fauth\u002Fsign-in\u002Femail', { method: 'POST', body: { email, password } });\nawait $fetch('\u002Fauth\u002Fsign-out',      { method: 'POST', body: {} });\n\u002F\u002F then: await refresh()\n",[29,571,572,635,686,731],{"__ignoreMap":27},[32,573,574,577,580,582,584,587,589,591,593,596,598,600,603,605,607,610,612,614,617,619,622,624,627,629,631,633],{"class":34,"line":35},[32,575,576],{"class":45},"await",[32,578,579],{"class":113}," $fetch",[32,581,118],{"class":117},[32,583,71],{"class":63},[32,585,586],{"class":67},"\u002Fauth\u002Fsign-up\u002Femail",[32,588,71],{"class":63},[32,590,240],{"class":49},[32,592,50],{"class":49},[32,594,595],{"class":127}," method",[32,597,131],{"class":49},[32,599,64],{"class":63},[32,601,602],{"class":67},"POST",[32,604,71],{"class":63},[32,606,240],{"class":49},[32,608,609],{"class":127}," body",[32,611,131],{"class":49},[32,613,50],{"class":49},[32,615,616],{"class":53}," name",[32,618,240],{"class":49},[32,620,621],{"class":53}," email",[32,623,240],{"class":49},[32,625,626],{"class":53}," password ",[32,628,308],{"class":49},[32,630,57],{"class":49},[32,632,294],{"class":117},[32,634,74],{"class":49},[32,636,637,639,641,643,645,648,650,652,654,656,658,660,662,664,666,668,670,672,674,676,678,680,682,684],{"class":34,"line":42},[32,638,576],{"class":45},[32,640,579],{"class":113},[32,642,118],{"class":117},[32,644,71],{"class":63},[32,646,647],{"class":67},"\u002Fauth\u002Fsign-in\u002Femail",[32,649,71],{"class":63},[32,651,240],{"class":49},[32,653,50],{"class":49},[32,655,595],{"class":127},[32,657,131],{"class":49},[32,659,64],{"class":63},[32,661,602],{"class":67},[32,663,71],{"class":63},[32,665,240],{"class":49},[32,667,609],{"class":127},[32,669,131],{"class":49},[32,671,50],{"class":49},[32,673,621],{"class":53},[32,675,240],{"class":49},[32,677,626],{"class":53},[32,679,308],{"class":49},[32,681,57],{"class":49},[32,683,294],{"class":117},[32,685,74],{"class":49},[32,687,688,690,692,694,696,699,701,703,706,708,710,712,714,716,718,720,722,725,727,729],{"class":34,"line":77},[32,689,576],{"class":45},[32,691,579],{"class":113},[32,693,118],{"class":117},[32,695,71],{"class":63},[32,697,698],{"class":67},"\u002Fauth\u002Fsign-out",[32,700,71],{"class":63},[32,702,240],{"class":49},[32,704,705],{"class":49},"      {",[32,707,595],{"class":127},[32,709,131],{"class":49},[32,711,64],{"class":63},[32,713,602],{"class":67},[32,715,71],{"class":63},[32,717,240],{"class":49},[32,719,609],{"class":127},[32,721,131],{"class":49},[32,723,724],{"class":49}," {}",[32,726,57],{"class":49},[32,728,294],{"class":117},[32,730,74],{"class":49},[32,732,733],{"class":34,"line":97},[32,734,735],{"class":38},"\u002F\u002F then: await refresh()\n",[13,737,738,739,742,743,746],{},"Who is signed in is an operation of the auth frond, ",[29,740,741],{},"session.get",". ",[29,744,745],{},"useCurrentUser()"," asks it once\nwhile the page renders on the server, and the answer is sent with the page — no request from the\nbrowser:",[22,748,750],{"className":24,"code":749,"language":26,"meta":27,"style":27},"const { user, refresh } = useCurrentUser();\n\u002F\u002F user:    Ref\u003CUser | null>\n\u002F\u002F refresh: () => Promise\u003Cvoid> — read it again after signing in or out\n",[29,751,752,779,784],{"__ignoreMap":27},[32,753,754,757,759,762,764,767,769,772,775,777],{"class":34,"line":35},[32,755,756],{"class":464},"const",[32,758,50],{"class":49},[32,760,761],{"class":53}," user",[32,763,240],{"class":49},[32,765,766],{"class":53}," refresh ",[32,768,308],{"class":49},[32,770,771],{"class":49}," =",[32,773,774],{"class":113}," useCurrentUser",[32,776,542],{"class":117},[32,778,74],{"class":49},[32,780,781],{"class":34,"line":42},[32,782,783],{"class":38},"\u002F\u002F user:    Ref\u003CUser | null>\n",[32,785,786],{"class":34,"line":77},[32,787,788],{"class":38},"\u002F\u002F refresh: () => Promise\u003Cvoid> — read it again after signing in or out\n",[22,790,794],{"className":791,"code":792,"language":793,"meta":27,"style":27},"language-vue shiki shiki-themes material-theme-lighter fougere-pastel material-theme-palenight","\u003Ctemplate>\n  \u003CUButton v-if=\"user\" :to=\"localePath('\u002Fblog\u002Fnew')\" :label=\"$t('nav.write')\" \u002F>\n  \u003CUButton v-else :to=\"localePath('\u002Flogin')\" :label=\"$t('nav.signIn')\" \u002F>\n\u003C\u002Ftemplate>\n","vue",[29,795,796,808,857,890],{"__ignoreMap":27},[32,797,798,801,805],{"class":34,"line":35},[32,799,800],{"class":49},"\u003C",[32,802,804],{"class":803},"s687E","template",[32,806,807],{"class":49},">\n",[32,809,810,813,816,820,823,826,828,830,833,835,837,840,842,845,847,849,852,854],{"class":34,"line":42},[32,811,812],{"class":49},"  \u003C",[32,814,815],{"class":803},"UButton",[32,817,819],{"class":818},"s8ClO"," v-if",[32,821,822],{"class":49},"=",[32,824,825],{"class":63},"\"",[32,827,337],{"class":67},[32,829,825],{"class":63},[32,831,832],{"class":818}," :to",[32,834,822],{"class":49},[32,836,825],{"class":63},[32,838,839],{"class":67},"localePath('\u002Fblog\u002Fnew')",[32,841,825],{"class":63},[32,843,844],{"class":818}," :label",[32,846,822],{"class":49},[32,848,825],{"class":63},[32,850,851],{"class":67},"$t('nav.write')",[32,853,825],{"class":63},[32,855,856],{"class":49}," \u002F>\n",[32,858,859,861,863,866,868,870,872,875,877,879,881,883,886,888],{"class":34,"line":77},[32,860,812],{"class":49},[32,862,815],{"class":803},[32,864,865],{"class":818}," v-else",[32,867,832],{"class":818},[32,869,822],{"class":49},[32,871,825],{"class":63},[32,873,874],{"class":67},"localePath('\u002Flogin')",[32,876,825],{"class":63},[32,878,844],{"class":818},[32,880,822],{"class":49},[32,882,825],{"class":63},[32,884,885],{"class":67},"$t('nav.signIn')",[32,887,825],{"class":63},[32,889,856],{"class":49},[32,891,892,895,897],{"class":34,"line":97},[32,893,894],{"class":49},"\u003C\u002F",[32,896,804],{"class":803},[32,898,807],{"class":49},[13,900,901],{},"What of the user reaches the page is what its entity lets out. Protecting a route is an ordinary\nmiddleware of your host reading the same session; Fougere adds no guard system of its own.",[17,903,905],{"id":904},"know-who-calls","Know who calls",[13,907,908,909,913,914,917,918,131],{},"An operation asks for the user as a parameter. A ",[910,911,912],"strong",{},"collector"," fills it — a class extending\n",[29,915,916],{},"Collect\u003CUser>",", in the frond's ",[29,919,920],{},"services\u002F",[22,922,924],{"className":24,"code":923,"language":26,"meta":27,"style":27},"\u002F\u002F fronds\u002Fblog\u002Fservices\u002FCurrentUserCollector.ts\nimport { Collect, FougereError, ErrorCode, type InvocationContext } from '@fougere\u002Fcore';\nimport User from '@fronds\u002Fuser\u002Fentities\u002FUser.js';\n\nexport default class CurrentUserCollector extends Collect\u003CUser> {\n  async collect(ctx: InvocationContext) {\n    return ctx.state.user as User | undefined;     \u002F\u002F put there by the auth frond\n  }\n\n  missing(): never {\n    throw new FougereError({ code: ErrorCode.UNAUTHORIZED, message: 'Sign in first' });\n  }\n}\n",[29,925,926,931,971,988,992,1016,1039,1073,1078,1082,1095,1144,1148],{"__ignoreMap":27},[32,927,928],{"class":34,"line":35},[32,929,930],{"class":38},"\u002F\u002F fronds\u002Fblog\u002Fservices\u002FCurrentUserCollector.ts\n",[32,932,933,935,937,940,942,945,947,950,952,955,958,960,962,964,967,969],{"class":34,"line":42},[32,934,46],{"class":45},[32,936,50],{"class":49},[32,938,939],{"class":53}," Collect",[32,941,240],{"class":49},[32,943,944],{"class":53}," FougereError",[32,946,240],{"class":49},[32,948,949],{"class":53}," ErrorCode",[32,951,240],{"class":49},[32,953,954],{"class":45}," type",[32,956,957],{"class":53}," InvocationContext",[32,959,57],{"class":49},[32,961,60],{"class":45},[32,963,64],{"class":63},[32,965,966],{"class":67},"@fougere\u002Fcore",[32,968,71],{"class":63},[32,970,74],{"class":49},[32,972,973,975,977,979,981,984,986],{"class":34,"line":77},[32,974,46],{"class":45},[32,976,82],{"class":53},[32,978,85],{"class":45},[32,980,64],{"class":63},[32,982,983],{"class":67},"@fronds\u002Fuser\u002Fentities\u002FUser.js",[32,985,71],{"class":63},[32,987,74],{"class":49},[32,989,990],{"class":34,"line":97},[32,991,101],{"emptyLinePlaceholder":100},[32,993,994,996,998,1000,1003,1005,1007,1009,1011,1014],{"class":34,"line":104},[32,995,107],{"class":45},[32,997,110],{"class":45},[32,999,465],{"class":464},[32,1001,1002],{"class":468}," CurrentUserCollector",[32,1004,471],{"class":464},[32,1006,939],{"class":468},[32,1008,800],{"class":49},[32,1010,388],{"class":468},[32,1012,1013],{"class":49},">",[32,1015,134],{"class":49},[32,1017,1018,1021,1025,1027,1031,1033,1035,1037],{"class":34,"line":124},[32,1019,1020],{"class":464},"  async",[32,1022,1024],{"class":1023},"shDkW"," collect",[32,1026,118],{"class":49},[32,1028,1030],{"class":1029},"shDUQ","ctx",[32,1032,131],{"class":49},[32,1034,957],{"class":468},[32,1036,294],{"class":49},[32,1038,134],{"class":49},[32,1040,1041,1044,1047,1049,1052,1054,1056,1059,1061,1064,1067,1070],{"class":34,"line":137},[32,1042,1043],{"class":45},"    return",[32,1045,1046],{"class":53}," ctx",[32,1048,176],{"class":49},[32,1050,1051],{"class":179},"state",[32,1053,176],{"class":49},[32,1055,337],{"class":179},[32,1057,1058],{"class":45}," as",[32,1060,159],{"class":468},[32,1062,1063],{"class":49}," |",[32,1065,1066],{"class":468}," undefined",[32,1068,1069],{"class":49},";",[32,1071,1072],{"class":38},"     \u002F\u002F put there by the auth frond\n",[32,1074,1075],{"class":34,"line":151},[32,1076,1077],{"class":49},"  }\n",[32,1079,1080],{"class":34,"line":165},[32,1081,101],{"emptyLinePlaceholder":100},[32,1083,1084,1087,1090,1093],{"class":34,"line":194},[32,1085,1086],{"class":1023},"  missing",[32,1088,1089],{"class":49},"():",[32,1091,1092],{"class":468}," never",[32,1094,134],{"class":49},[32,1096,1097,1100,1103,1106,1109,1112,1115,1117,1119,1121,1124,1126,1129,1131,1133,1136,1138,1140,1142],{"class":34,"line":225},[32,1098,1099],{"class":45},"    throw",[32,1101,1102],{"class":49}," new",[32,1104,944],{"class":1105},"sgjsB",[32,1107,118],{"class":1108},"spAFX",[32,1110,1111],{"class":49},"{",[32,1113,1114],{"class":127}," code",[32,1116,131],{"class":49},[32,1118,949],{"class":53},[32,1120,176],{"class":49},[32,1122,1123],{"class":179},"UNAUTHORIZED",[32,1125,240],{"class":49},[32,1127,1128],{"class":127}," message",[32,1130,131],{"class":49},[32,1132,64],{"class":63},[32,1134,1135],{"class":67},"Sign in first",[32,1137,71],{"class":63},[32,1139,57],{"class":49},[32,1141,294],{"class":1108},[32,1143,74],{"class":49},[32,1145,1146],{"class":34,"line":246},[32,1147,1077],{"class":49},[32,1149,1150],{"class":34,"line":288},[32,1151,1152],{"class":49},"}\n",[13,1154,1155],{},"Then, in any handler of that frond:",[22,1157,1159],{"className":24,"code":1158,"language":26,"meta":27,"style":27},"async mine(user?: User): Promise\u003CPost[]> { … }                  \u002F\u002F nobody signed in: user is undefined\nasync publish(id: Post['id'], user: User): Promise\u003CPost> { … }  \u002F\u002F nobody signed in: refused\n",[29,1160,1161,1206],{"__ignoreMap":27},[32,1162,1163,1166,1169,1171,1173,1176,1178,1180,1183,1186,1188,1191,1194,1196,1198,1201,1203],{"class":34,"line":35},[32,1164,1165],{"class":53},"async ",[32,1167,1168],{"class":113},"mine",[32,1170,118],{"class":117},[32,1172,337],{"class":53},[32,1174,1175],{"class":49},"?:",[32,1177,159],{"class":53},[32,1179,294],{"class":117},[32,1181,1182],{"class":53},": ",[32,1184,1185],{"class":468},"Promise",[32,1187,800],{"class":49},[32,1189,1190],{"class":53},"Post",[32,1192,1193],{"class":117},"[]",[32,1195,1013],{"class":49},[32,1197,50],{"class":49},[32,1199,1200],{"class":53}," … ",[32,1202,308],{"class":49},[32,1204,1205],{"class":38},"                  \u002F\u002F nobody signed in: user is undefined\n",[32,1207,1208,1210,1213,1215,1218,1221,1223,1226,1228,1231,1233,1236,1238,1240,1242,1244,1246,1248,1250,1252,1254],{"class":34,"line":42},[32,1209,1165],{"class":53},[32,1211,1212],{"class":113},"publish",[32,1214,118],{"class":117},[32,1216,1217],{"class":53},"id: Post",[32,1219,1220],{"class":117},"[",[32,1222,71],{"class":63},[32,1224,1225],{"class":67},"id",[32,1227,71],{"class":63},[32,1229,1230],{"class":117},"]",[32,1232,240],{"class":49},[32,1234,1235],{"class":53}," user: User",[32,1237,294],{"class":117},[32,1239,1182],{"class":53},[32,1241,1185],{"class":468},[32,1243,800],{"class":49},[32,1245,1190],{"class":53},[32,1247,1013],{"class":49},[32,1249,50],{"class":49},[32,1251,1200],{"class":53},[32,1253,308],{"class":49},[32,1255,1256],{"class":38},"  \u002F\u002F nobody signed in: refused\n",[13,1258,1259,1260,1266,1267,1270,1271,1274,1275,1278,1279,1281,1282,1284,1285,1287,1288,742,1291,1293],{},"A parameter ",[910,1261,1262,1263],{},"without ",[29,1264,1265],{},"?"," that nothing filled is refused before the method runs, with what\n",[29,1268,1269],{},"missing()"," throws — here ",[29,1272,1273],{},"401",". The handler writes no ",[29,1276,1277],{},"if (!user) throw",", and the operation's\ncontract still promises the ",[29,1280,1273],{},": the scan reads it from ",[29,1283,1269],{},". Without ",[29,1286,1269],{},", the\nrefusal is ",[29,1289,1290],{},"422 user: Required",[29,1292,1269],{}," receives the call, so it can tell nobody signed in from\na session that expired.",[13,1295,1296],{},"The same user reaches every reader:",[1298,1299,1300,1313],"table",{},[1301,1302,1303],"thead",{},[1304,1305,1306,1310],"tr",{},[1307,1308,1309],"th",{},"Reader",[1307,1311,1312],{},"How the user arrives",[1314,1315,1316,1329,1339],"tbody",{},[1304,1317,1318,1322],{},[1319,1320,1321],"td",{},"a page",[1319,1323,1324,1326,1327],{},[29,1325,741],{},", asked while rendering on the server — ",[29,1328,745],{},[1304,1330,1331,1334],{},[1319,1332,1333],{},"a handler",[1319,1335,1336,1337],{},"the call's state → the collector fills ",[29,1338,554],{},[1304,1340,1341,1344],{},[1319,1342,1343],{},"a frond in another process",[1319,1345,1346],{},"the state travels with the call — its collector receives the same user",[13,1348,1349],{},"The browser cannot write this state: it is built on the server from the request.",[17,1351,1353],{"id":1352},"the-rules-of-a-collector","The rules of a collector",[1355,1356,1357,1374,1383,1397,1403],"ul",{},[1358,1359,1360,1363,1364,1366,1367,326,1370,1373],"li",{},[910,1361,1362],{},"It matches by type."," ",[29,1365,916],{}," fills ",[29,1368,1369],{},"user?: User",[29,1371,1372],{},"user: User | undefined",", and any\nalias meaning the same.",[1358,1375,1376,1363,1379,1382],{},[910,1377,1378],{},"Its target needs no schema.",[29,1380,1381],{},"Collect\u003CAbility>"," works for a value you build from the state at\neach call.",[1358,1384,1385,1388,1389,1393,1394,176],{},[910,1386,1387],{},"It runs for a call that comes through a door"," — a page, REST, GraphQL. Code calling another\nfrond's ",[344,1390,1392],{"href":1391},"\u002Fdocs\u002Fconcepts\u002Ffacade","facade"," already holds the user and passes it: ",[29,1395,1396],{},"publish(id, user)",[1358,1398,1399,1402],{},[910,1400,1401],{},"It takes dependencies"," in its constructor, like any class.",[1358,1404,1405,1408,1409,1560,1563,1564,1566,1567,1570],{},[910,1406,1407],{},"It is a port."," A link may stand in front of it — a cache, an audit:",[22,1410,1412],{"className":24,"code":1411,"language":26,"meta":27,"style":27},"export default class CachedUser implements Partial\u003CCollect\u003CUser>> {\n  constructor(private inner: Collect\u003CUser>, private cache: SessionCache) {}\n\n  async collect(ctx: InvocationContext) {\n    return this.cache.get(ctx) ?? this.inner.collect(ctx);\n  }\n}\n",[29,1413,1414,1445,1484,1488,1506,1552,1556],{"__ignoreMap":27},[32,1415,1416,1418,1420,1422,1425,1428,1431,1433,1436,1438,1440,1443],{"class":34,"line":35},[32,1417,107],{"class":45},[32,1419,110],{"class":45},[32,1421,465],{"class":464},[32,1423,1424],{"class":468}," CachedUser",[32,1426,1427],{"class":464}," implements",[32,1429,1430],{"class":468}," Partial",[32,1432,800],{"class":49},[32,1434,1435],{"class":468},"Collect",[32,1437,800],{"class":49},[32,1439,388],{"class":468},[32,1441,1442],{"class":49},">>",[32,1444,134],{"class":49},[32,1446,1447,1450,1452,1455,1458,1460,1462,1464,1466,1469,1472,1475,1477,1480,1482],{"class":34,"line":42},[32,1448,1449],{"class":464},"  constructor",[32,1451,118],{"class":49},[32,1453,1454],{"class":464},"private",[32,1456,1457],{"class":1029}," inner",[32,1459,131],{"class":49},[32,1461,939],{"class":468},[32,1463,800],{"class":49},[32,1465,388],{"class":468},[32,1467,1468],{"class":49},">,",[32,1470,1471],{"class":464}," private",[32,1473,1474],{"class":1029}," cache",[32,1476,131],{"class":49},[32,1478,1479],{"class":468}," SessionCache",[32,1481,294],{"class":49},[32,1483,545],{"class":49},[32,1485,1486],{"class":34,"line":77},[32,1487,101],{"emptyLinePlaceholder":100},[32,1489,1490,1492,1494,1496,1498,1500,1502,1504],{"class":34,"line":97},[32,1491,1020],{"class":464},[32,1493,1024],{"class":1023},[32,1495,118],{"class":49},[32,1497,1030],{"class":1029},[32,1499,131],{"class":49},[32,1501,957],{"class":468},[32,1503,294],{"class":49},[32,1505,134],{"class":49},[32,1507,1508,1510,1514,1516,1519,1521,1524,1526,1528,1530,1532,1534,1536,1539,1541,1544,1546,1548,1550],{"class":34,"line":104},[32,1509,1043],{"class":45},[32,1511,1513],{"class":1512},"sxG60"," this",[32,1515,176],{"class":49},[32,1517,1518],{"class":179},"cache",[32,1520,176],{"class":49},[32,1522,1523],{"class":113},"get",[32,1525,118],{"class":1108},[32,1527,1030],{"class":53},[32,1529,294],{"class":1108},[32,1531,213],{"class":49},[32,1533,1513],{"class":1512},[32,1535,176],{"class":49},[32,1537,1538],{"class":179},"inner",[32,1540,176],{"class":49},[32,1542,1543],{"class":113},"collect",[32,1545,118],{"class":1108},[32,1547,1030],{"class":53},[32,1549,294],{"class":1108},[32,1551,74],{"class":49},[32,1553,1554],{"class":34,"line":124},[32,1555,1077],{"class":49},[32,1557,1558],{"class":34,"line":137},[32,1559,1152],{"class":49},[1561,1562],"br",{},"What it leaves out, ",[29,1565,1269],{}," included, is the collector's. Two collectors of one type refuse the\nboot; ",[29,1568,1569],{},"ports: { 'Collect\u003CUser>': 'CurrentUserCollector' }"," says which answers.",[1572,1573,1575],"h3",{"id":1574},"it-does-not-cross-a-frond","It does not cross a frond",[13,1577,1578],{},"A collector fills parameters in its own frond, and in the fronds that extend it — nowhere else. Keep\none in each frond that needs it, or in the frond they all extend.",[1355,1580,1581,1592],{},[1358,1582,1583,1584,1587,1588,1591],{},"A collector for that type in ",[910,1585,1586],{},"another"," frond is not used: the parameter is read from the\nrequest, and the boot warns ",[29,1589,1590],{},"collector-in-another-frond",", with both ways out.",[1358,1593,1594,1595,1598],{},"With ",[910,1596,1597],{},"no"," collector for that type anywhere, the parameter is an ordinary input, read from the body.",[13,1600,1601],{},"When reading it from the request is what you mean, say so for that parameter:",[22,1603,1605],{"className":24,"code":1604,"language":26,"meta":27,"style":27},"\u002F\u002F fronds\u002Fadmin\u002Ffrond.config.ts — the invited user comes from the request\nexport default {\n  operations: { 'invite.inviteUser': { binding: [{ name: 'user', source: { kind: 'input' } }] } },\n};\n",[29,1606,1607,1612,1620,1692],{"__ignoreMap":27},[32,1608,1609],{"class":34,"line":35},[32,1610,1611],{"class":38},"\u002F\u002F fronds\u002Fadmin\u002Ffrond.config.ts — the invited user comes from the request\n",[32,1613,1614,1616,1618],{"class":34,"line":42},[32,1615,107],{"class":45},[32,1617,110],{"class":45},[32,1619,134],{"class":49},[32,1621,1622,1625,1627,1629,1631,1635,1637,1639,1641,1644,1646,1649,1651,1653,1655,1657,1659,1661,1663,1666,1668,1670,1673,1675,1677,1680,1682,1684,1686,1688,1690],{"class":34,"line":77},[32,1623,1624],{"class":127},"  operations",[32,1626,131],{"class":49},[32,1628,50],{"class":49},[32,1630,64],{"class":63},[32,1632,1634],{"class":1633},"sK7Y8","invite.inviteUser",[32,1636,71],{"class":63},[32,1638,131],{"class":49},[32,1640,50],{"class":49},[32,1642,1643],{"class":127}," binding",[32,1645,131],{"class":49},[32,1647,1648],{"class":117}," [",[32,1650,1111],{"class":49},[32,1652,616],{"class":127},[32,1654,131],{"class":49},[32,1656,64],{"class":63},[32,1658,337],{"class":67},[32,1660,71],{"class":63},[32,1662,240],{"class":49},[32,1664,1665],{"class":127}," source",[32,1667,131],{"class":49},[32,1669,50],{"class":49},[32,1671,1672],{"class":127}," kind",[32,1674,131],{"class":49},[32,1676,64],{"class":63},[32,1678,1679],{"class":67},"input",[32,1681,71],{"class":63},[32,1683,57],{"class":49},[32,1685,57],{"class":49},[32,1687,1230],{"class":117},[32,1689,57],{"class":49},[32,1691,285],{"class":49},[32,1693,1694],{"class":34,"line":97},[32,1695,1696],{"class":49},"};\n",[1698,1699,1700],"warning",{},[13,1701,1702,1704,1705,1707,1708,1711],{},[29,1703,1369],{}," in a project with no ",[29,1706,916],{}," receives whatever the client sent. A handler that\nchecks ",[29,1709,1710],{},"user.role"," would be checking a value the caller chose.",[1572,1713,1715],{"id":1714},"what-the-state-may-hold","What the state may hold",[13,1717,1718,1721,1722,1724,1725,1727,1728,1730,1731,1734],{},[29,1719,1720],{},"ctx.state"," is declared, by the extensions of the process: ",[29,1723,317],{}," declares ",[29,1726,337],{}," and\n",[29,1729,325],{}," (the session without its ",[29,1732,1733],{},"token"," — a process trusts the process that called it, never the\ncookie behind it). Your own extension declares its members with fields:",[22,1736,1738],{"className":24,"code":1737,"language":26,"meta":27,"style":27},"extensions: [{ name: 'tenancy', state: { tenant: text() } }]\n",[29,1739,1740],{"__ignoreMap":27},[32,1741,1742,1746,1748,1750,1752,1754,1756,1758,1761,1763,1765,1768,1770,1772,1775,1777,1780,1782,1784,1786],{"class":34,"line":35},[32,1743,1745],{"class":1744},"sWI7z","extensions",[32,1747,131],{"class":49},[32,1749,1648],{"class":117},[32,1751,1111],{"class":49},[32,1753,616],{"class":127},[32,1755,131],{"class":49},[32,1757,64],{"class":63},[32,1759,1760],{"class":67},"tenancy",[32,1762,71],{"class":63},[32,1764,240],{"class":49},[32,1766,1767],{"class":127}," state",[32,1769,131],{"class":49},[32,1771,50],{"class":49},[32,1773,1774],{"class":127}," tenant",[32,1776,131],{"class":49},[32,1778,1779],{"class":113}," text",[32,1781,542],{"class":117},[32,1783,57],{"class":49},[32,1785,57],{"class":49},[32,1787,1788],{"class":117},"]\n",[13,1790,1791],{},"The state is checked where it entered — in the process whose host filled it, or whose host\nmiddleware wrote a member:",[1355,1793,1794,1800,1803],{},[1358,1795,1796,1797,1069],{},"a member nobody declares is refused: ",[29,1798,1799],{},"state.tenant: Unknown field — this process declares user, session",[1358,1801,1802],{},"two extensions declaring one member refuse the boot;",[1358,1804,1805],{},"a process receiving the call checks nothing more: it was checked where it entered, and the signed\nenvelope proves which process wrote it.",[13,1807,1808,1809,1812,1813,1816,1817,1820],{},"A collector hands on what it read ",[910,1810,1811],{},"as its type",", checked and rebuilt: ",[29,1814,1815],{},"state.user.since"," is a\n",[29,1818,1819],{},"Date"," in this process and across the wire alike, never the string JSON makes of it.",[1822,1823,1824],"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 .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 .sy9f4, html code.shiki .sy9f4{--shiki-light:#90A4AE;--shiki-default:#93CFC0;--shiki-dark:#BABED8}html pre.shiki code .s3dPA, html code.shiki .s3dPA{--shiki-light:#F76D47;--shiki-default:#EE9F6B;--shiki-dark:#F78C6C}html pre.shiki code .slmMI, html code.shiki .slmMI{--shiki-light:#FF5370;--shiki-default:#EE9F6B;--shiki-dark:#FF9CAC}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 .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 .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 .shDkW, html code.shiki .shDkW{--shiki-light:#E53935;--shiki-default:#C9B6EA;--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 .sgjsB, html code.shiki .sgjsB{--shiki-light:#6182B8;--shiki-default:#EFCD8F;--shiki-dark:#82AAFF}html pre.shiki code .spAFX, html code.shiki .spAFX{--shiki-light:#E53935;--shiki-default:#A3B0A5;--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 .sK7Y8, html code.shiki .sK7Y8{--shiki-light:#E53935;--shiki-default:#EE9F6B;--shiki-dark:#F07178}html pre.shiki code .sWI7z, html code.shiki .sWI7z{--shiki-light:#E2931D;--shiki-default:#93CFC0;--shiki-dark:#FFCB6B}",{"title":27,"searchDepth":42,"depth":42,"links":1826},[1827,1828,1829,1830,1831],{"id":19,"depth":42,"text":20},{"id":381,"depth":42,"text":382},{"id":562,"depth":42,"text":563},{"id":904,"depth":42,"text":905},{"id":1352,"depth":42,"text":1353,"children":1832},[1833,1834],{"id":1574,"depth":77,"text":1575},{"id":1714,"depth":77,"text":1715},"Sign-in with better-auth, and an operation that knows who calls.","md",[916,1838],"fronds.auth","task",{},"\u002Fdocs\u002Faccess\u002Fauthentication",{"title":8,"description":1835},"docs\u002F2.access\u002F1.authentication",null,[1846,1847],"port","frond","HchJZN2eVTJOE14fDm4J6zJ46mI1iBjXbZHkUmtxRYk",[1850,1853,1856,1859,1862,1864,1867,1870,1873,1875,1881,1886,1890,1894,1898,1902,1906,1911,1915,1919,1924,1928,1932,1936,1940,1944,1948,1951,1955,1959,1963,1967,1971,1975,1979,1983,1987,1990,1993,1996,1999,2002,2005,2008,2011,2014,2017],{"path":1851,"title":1852,"uses":1844},"\u002Fdocs\u002Fconcepts\u002Fentity","Entity",{"path":1854,"title":1855,"uses":1844},"\u002Fdocs\u002Fconcepts\u002Fhandler","Handler",{"path":1857,"title":1858,"uses":1844},"\u002Fdocs\u002Fconcepts\u002Frepository","Repository",{"path":1860,"title":1861,"uses":1844},"\u002Fdocs\u002Fconcepts\u002Ffrond","Frond",{"path":1391,"title":1863,"uses":1844},"Facade",{"path":1865,"title":1866,"uses":1844},"\u002Fdocs\u002Fconcepts\u002Ffact","Fact",{"path":1868,"title":1869,"uses":1844},"\u002Fdocs\u002Fconcepts\u002Fport","Port",{"path":1871,"title":1872,"uses":1844},"\u002Fdocs\u002Fconcepts\u002Fconfiguration","Configuration",{"path":1841,"title":8,"uses":1874},[1846,1847],{"path":1876,"title":1877,"uses":1878},"\u002Fdocs\u002Faccess\u002Fstate","Keep a caller's state",[1879,1880],"configuration","handler",{"path":1882,"title":1883,"uses":1884},"\u002Fdocs\u002Fdata\u002Fsql","SQLite or Postgres",[1885,1879],"entity",{"path":1887,"title":1888,"uses":1889},"\u002Fdocs\u002Fdata\u002Fseveral-databases","Several databases",[1879,1885],{"path":1891,"title":1892,"uses":1893},"\u002Fdocs\u002Fdata\u002Fcomputed-field","A computed field",[1885,1846],{"path":1895,"title":1896,"uses":1897},"\u002Fdocs\u002Fdata\u002Fevolve","Evolve a schema",[1885],{"path":1899,"title":1900,"uses":1901},"\u002Fdocs\u002Fdata\u002Fseeds","Seed data",[1885],{"path":1903,"title":1904,"uses":1905},"\u002Fdocs\u002Fdata\u002Fvalues","Read settings and secrets",[1885,1879],{"path":1907,"title":1908,"uses":1909},"\u002Fdocs\u002Fdata\u002Fmirror","Mirror a source you cannot query",[1910],"repository",{"path":1912,"title":1913,"uses":1914},"\u002Fdocs\u002Fdata\u002Ftogether","Two writes as one",[1910],{"path":1916,"title":1917,"uses":1918},"\u002Fdocs\u002Fbehaviour\u002Faround-every-call","Around every call",[1846,1847],{"path":1920,"title":1921,"uses":1922},"\u002Fdocs\u002Fbehaviour\u002Ffinish-a-fact","Finish a fact",[1923],"fact",{"path":1925,"title":1926,"uses":1927},"\u002Fdocs\u002Fserve\u002Frest-graphql","REST, OpenAPI, GraphQL",[1880,1879],{"path":1929,"title":1930,"uses":1931},"\u002Fdocs\u002Fserve\u002Fpages","Pages: queries and commands",[1880,1392],{"path":1933,"title":1934,"uses":1935},"\u002Fdocs\u002Fserve\u002Fforms","A form",[1885],{"path":1937,"title":1938,"uses":1939},"\u002Fdocs\u002Fserve\u002Fadmin","An admin panel",[1880],{"path":1941,"title":1942,"uses":1943},"\u002Fdocs\u002Frun\u002Fdeploy","Deploy a split",[1879,1847],{"path":1945,"title":1946,"uses":1947},"\u002Fdocs\u002Frun\u002Fsecure","Secure calls between processes",[1879,1847],{"path":346,"title":1949,"uses":1950},"Reload and shut down",[1879],{"path":1952,"title":1953,"uses":1954},"\u002Fdocs\u002Frun\u002Fobserve","Observe",[1879,1880],{"path":1956,"title":1957,"uses":1958},"\u002Fdocs\u002Frun\u002Fdev-panel","The dev panel",[1880],{"path":1960,"title":1961,"uses":1962},"\u002Fdocs\u002Frun\u002Ftest","Test",[1885,1846],{"path":1964,"title":1965,"uses":1966},"\u002Fdocs\u002Fadopt\u002Fnew-project","Start a project",[1847,1879],{"path":1968,"title":1969,"uses":1970},"\u002Fdocs\u002Fadopt\u002Fexisting-app","Add Fougere to an existing app",[1847,1879],{"path":1972,"title":1973,"uses":1974},"\u002Fdocs\u002Fadopt\u002Fbring-your-schema","Bring your schema",[1885],{"path":1976,"title":1977,"uses":1978},"\u002Fdocs\u002Fadopt\u002Fhosts","Pick a host",[1879],{"path":1980,"title":1981,"uses":1982},"\u002Fdocs\u002Fadopt\u002Fanother-repository","A frond from another repository",[1392,1847],{"path":1984,"title":1985,"uses":1986},"\u002Fdocs\u002Fadopt\u002Fdemos","Demos",[],{"path":1988,"title":1989,"uses":1844},"\u002Fdocs\u002Fextending\u002Fscan","How the scan reads a project",{"path":1991,"title":1992,"uses":1844},"\u002Fdocs\u002Fextending\u002Fwithout-compiler","Boot without the compiler",{"path":1994,"title":1995,"uses":1844},"\u002Fdocs\u002Fextending\u002Fboot","The boot, step by step",{"path":1997,"title":1998,"uses":1844},"\u002Fdocs\u002Fextending\u002Fcard-and-wire","The card and the wire",{"path":2000,"title":2001,"uses":1844},"\u002Fdocs\u002Fextending\u002Fextension-points","Registries and extension points",{"path":2003,"title":2004,"uses":1844},"\u002Fdocs\u002Fextending\u002Fvocabulary","Teach a word",{"path":2006,"title":2007,"uses":1844},"\u002Fdocs\u002Fextending\u002Fextensions","Run code at boot and shutdown",{"path":2009,"title":2010,"uses":1844},"\u002Fdocs\u002Fextending\u002Fsource-adapter","Write a source adapter",{"path":2012,"title":2013,"uses":1844},"\u002Fdocs\u002Fextending\u002Fsurface","Write a surface",{"path":2015,"title":2016,"uses":1844},"\u002Fdocs\u002Fextending\u002Fforeign-frond","A frond in another language",{"path":2018,"title":2019,"uses":1844},"\u002Fdocs","What is Fougere",[2021],{"title":2022,"path":2018,"stem":2023,"children":2024,"page":-1},"Docs","docs",[2025,2027,2048,2056,2077,2086,2099,2116,2133],{"title":2019,"path":2018,"stem":2026},"docs\u002Findex",{"title":2028,"path":2029,"stem":2030,"children":2031,"page":5},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F1.concepts",[2032,2034,2036,2038,2040,2042,2044,2046],{"title":1852,"path":1851,"stem":2033},"docs\u002F1.concepts\u002F1.entity",{"title":1855,"path":1854,"stem":2035},"docs\u002F1.concepts\u002F2.handler",{"title":1858,"path":1857,"stem":2037},"docs\u002F1.concepts\u002F3.repository",{"title":1861,"path":1860,"stem":2039},"docs\u002F1.concepts\u002F4.frond",{"title":1863,"path":1391,"stem":2041},"docs\u002F1.concepts\u002F5.facade",{"title":1866,"path":1865,"stem":2043},"docs\u002F1.concepts\u002F6.fact",{"title":1869,"path":1868,"stem":2045},"docs\u002F1.concepts\u002F7.port",{"title":1872,"path":1871,"stem":2047},"docs\u002F1.concepts\u002F8.configuration",{"title":2049,"path":2050,"stem":2051,"children":2052,"page":5},"Access","\u002Fdocs\u002Faccess","docs\u002F2.access",[2053,2054],{"title":8,"path":1841,"stem":1843},{"title":1877,"path":1876,"stem":2055},"docs\u002F2.access\u002F2.state",{"title":2057,"path":2058,"stem":2059,"children":2060,"page":5},"Data","\u002Fdocs\u002Fdata","docs\u002F3.data",[2061,2063,2065,2067,2069,2071,2073,2075],{"title":1883,"path":1882,"stem":2062},"docs\u002F3.data\u002F1.sql",{"title":1888,"path":1887,"stem":2064},"docs\u002F3.data\u002F2.several-databases",{"title":1892,"path":1891,"stem":2066},"docs\u002F3.data\u002F3.computed-field",{"title":1896,"path":1895,"stem":2068},"docs\u002F3.data\u002F4.evolve",{"title":1900,"path":1899,"stem":2070},"docs\u002F3.data\u002F5.seeds",{"title":1904,"path":1903,"stem":2072},"docs\u002F3.data\u002F6.values",{"title":1908,"path":1907,"stem":2074},"docs\u002F3.data\u002F7.mirror",{"title":1913,"path":1912,"stem":2076},"docs\u002F3.data\u002F8.together",{"title":2078,"path":2079,"stem":2080,"children":2081,"page":5},"Behaviour","\u002Fdocs\u002Fbehaviour","docs\u002F4.behaviour",[2082,2084],{"title":1917,"path":1916,"stem":2083},"docs\u002F4.behaviour\u002F1.around-every-call",{"title":1921,"path":1920,"stem":2085},"docs\u002F4.behaviour\u002F2.finish-a-fact",{"title":2087,"path":2088,"stem":2089,"children":2090,"page":5},"Serve","\u002Fdocs\u002Fserve","docs\u002F5.serve",[2091,2093,2095,2097],{"title":1926,"path":1925,"stem":2092},"docs\u002F5.serve\u002F1.rest-graphql",{"title":1930,"path":1929,"stem":2094},"docs\u002F5.serve\u002F2.pages",{"title":1934,"path":1933,"stem":2096},"docs\u002F5.serve\u002F3.forms",{"title":1938,"path":1937,"stem":2098},"docs\u002F5.serve\u002F4.admin",{"title":2100,"path":2101,"stem":2102,"children":2103,"page":5},"Run","\u002Fdocs\u002Frun","docs\u002F6.run",[2104,2106,2108,2110,2112,2114],{"title":1942,"path":1941,"stem":2105},"docs\u002F6.run\u002F1.deploy",{"title":1946,"path":1945,"stem":2107},"docs\u002F6.run\u002F2.secure",{"title":1949,"path":346,"stem":2109},"docs\u002F6.run\u002F3.lifecycle",{"title":1953,"path":1952,"stem":2111},"docs\u002F6.run\u002F4.observe",{"title":1957,"path":1956,"stem":2113},"docs\u002F6.run\u002F5.dev-panel",{"title":1961,"path":1960,"stem":2115},"docs\u002F6.run\u002F6.test",{"title":2117,"path":2118,"stem":2119,"children":2120,"page":5},"Adopt","\u002Fdocs\u002Fadopt","docs\u002F7.adopt",[2121,2123,2125,2127,2129,2131],{"title":1965,"path":1964,"stem":2122},"docs\u002F7.adopt\u002F1.new-project",{"title":1969,"path":1968,"stem":2124},"docs\u002F7.adopt\u002F2.existing-app",{"title":1973,"path":1972,"stem":2126},"docs\u002F7.adopt\u002F3.bring-your-schema",{"title":1977,"path":1976,"stem":2128},"docs\u002F7.adopt\u002F4.hosts",{"title":1981,"path":1980,"stem":2130},"docs\u002F7.adopt\u002F5.another-repository",{"title":1985,"path":1984,"stem":2132},"docs\u002F7.adopt\u002F6.demos",{"title":2134,"path":2135,"stem":2136,"children":2137,"page":5},"Extending","\u002Fdocs\u002Fextending","docs\u002F8.extending",[2138,2140,2142,2144,2146,2148,2150,2152,2154,2156],{"title":1989,"path":1988,"stem":2139},"docs\u002F8.extending\u002F1.scan",{"title":1992,"path":1991,"stem":2141},"docs\u002F8.extending\u002F10.without-compiler",{"title":1995,"path":1994,"stem":2143},"docs\u002F8.extending\u002F2.boot",{"title":1998,"path":1997,"stem":2145},"docs\u002F8.extending\u002F3.card-and-wire",{"title":2001,"path":2000,"stem":2147},"docs\u002F8.extending\u002F4.extension-points",{"title":2004,"path":2003,"stem":2149},"docs\u002F8.extending\u002F5.vocabulary",{"title":2007,"path":2006,"stem":2151},"docs\u002F8.extending\u002F6.extensions",{"title":2010,"path":2009,"stem":2153},"docs\u002F8.extending\u002F7.source-adapter",{"title":2013,"path":2012,"stem":2155},"docs\u002F8.extending\u002F8.surface",{"title":2016,"path":2015,"stem":2157},"docs\u002F8.extending\u002F9.foreign-frond",1794396614468]