[{"data":1,"prerenderedAt":1879},["ShallowReactive",2],{"fougere:post.list:{}":3,"docs:\u002Fdocs\u002Fconcepts\u002Fport":6,"docs-uses":1576,"docs-nav":1741},{"items":4,"hasMore":5},[],false,{"id":7,"title":8,"body":9,"description":1567,"extension":1568,"forms":1569,"kind":1570,"meta":1571,"navigation":107,"path":1572,"seo":1573,"stem":1574,"step":66,"uses":1569,"__hash__":1575},"docs\u002Fdocs\u002F1.concepts\u002F7.port.md","Port",{"type":10,"value":11,"toc":1557},"minimark",[12,21,305,332,337,432,460,466,470,476,484,487,578,619,642,646,649,837,862,865,921,947,963,967,970,1086,1102,1107,1112,1261,1264,1268,1276,1462,1481,1495,1511,1521,1525,1528,1550,1553],[13,14,15,16,20],"p",{},"A port is a capability your code asks for without naming who provides it. A handler that writes\n",[17,18,19],"code",{},"constructor(private payment: StripePayment)"," has named its provider, and its tests, its sandbox\nand the day you change payment provider all pay for that line. Ask for the capability instead:",[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 services\u002FPayment.ts — the port. It names no provider.\nexport default abstract class Payment {\n  abstract charge(amountCents: number): Charge;\n}\n\n\u002F\u002F services\u002FStripePayment.ts — what answers it.\nexport default class StripePayment extends Payment {\n  charge(amountCents: number) { return { provider: 'stripe', amountCents }; }\n}\n\n\u002F\u002F handlers\u002FCheckoutHandler.ts — asks for the port.\nexport default class CheckoutHandler {\n  constructor(private payment: Payment) {}\n\n  \u002F** Charge the cart. *\u002F\n  async pay() { return this.payment.charge(4990); }\n}\n","ts","",[17,29,30,39,64,96,102,109,115,134,189,194,199,205,219,242,247,253,300],{"__ignoreMap":27},[31,32,35],"span",{"class":33,"line":34},"line",1,[31,36,38],{"class":37},"skXKP","\u002F\u002F services\u002FPayment.ts — the port. It names no provider.\n",[31,40,42,46,49,53,56,60],{"class":33,"line":41},2,[31,43,45],{"class":44},"sK6XW","export",[31,47,48],{"class":44}," default",[31,50,52],{"class":51},"s76I7"," abstract",[31,54,55],{"class":51}," class",[31,57,59],{"class":58},"sBZYL"," Payment",[31,61,63],{"class":62},"s15xx"," {\n",[31,65,67,70,74,77,81,84,87,90,93],{"class":33,"line":66},3,[31,68,69],{"class":51},"  abstract",[31,71,73],{"class":72},"shDkW"," charge",[31,75,76],{"class":62},"(",[31,78,80],{"class":79},"shDUQ","amountCents",[31,82,83],{"class":62},":",[31,85,86],{"class":58}," number",[31,88,89],{"class":62},"):",[31,91,92],{"class":58}," Charge",[31,94,95],{"class":62},";\n",[31,97,99],{"class":33,"line":98},4,[31,100,101],{"class":62},"}\n",[31,103,105],{"class":33,"line":104},5,[31,106,108],{"emptyLinePlaceholder":107},true,"\n",[31,110,112],{"class":33,"line":111},6,[31,113,114],{"class":37},"\u002F\u002F services\u002FStripePayment.ts — what answers it.\n",[31,116,118,120,122,124,127,130,132],{"class":33,"line":117},7,[31,119,45],{"class":44},[31,121,48],{"class":44},[31,123,55],{"class":51},[31,125,126],{"class":58}," StripePayment",[31,128,129],{"class":51}," extends",[31,131,59],{"class":58},[31,133,63],{"class":62},[31,135,137,140,142,144,146,148,151,154,157,159,163,165,169,173,176,179,183,186],{"class":33,"line":136},8,[31,138,139],{"class":72},"  charge",[31,141,76],{"class":62},[31,143,80],{"class":79},[31,145,83],{"class":62},[31,147,86],{"class":58},[31,149,150],{"class":62},")",[31,152,153],{"class":62}," {",[31,155,156],{"class":44}," return",[31,158,153],{"class":62},[31,160,162],{"class":161},"sHtqg"," provider",[31,164,83],{"class":62},[31,166,168],{"class":167},"sDDC1"," '",[31,170,172],{"class":171},"sN-8n","stripe",[31,174,175],{"class":167},"'",[31,177,178],{"class":62},",",[31,180,182],{"class":181},"sPEhv"," amountCents",[31,184,185],{"class":62}," };",[31,187,188],{"class":62}," }\n",[31,190,192],{"class":33,"line":191},9,[31,193,101],{"class":62},[31,195,197],{"class":33,"line":196},10,[31,198,108],{"emptyLinePlaceholder":107},[31,200,202],{"class":33,"line":201},11,[31,203,204],{"class":37},"\u002F\u002F handlers\u002FCheckoutHandler.ts — asks for the port.\n",[31,206,208,210,212,214,217],{"class":33,"line":207},12,[31,209,45],{"class":44},[31,211,48],{"class":44},[31,213,55],{"class":51},[31,215,216],{"class":58}," CheckoutHandler",[31,218,63],{"class":62},[31,220,222,225,227,230,233,235,237,239],{"class":33,"line":221},13,[31,223,224],{"class":51},"  constructor",[31,226,76],{"class":62},[31,228,229],{"class":51},"private",[31,231,232],{"class":79}," payment",[31,234,83],{"class":62},[31,236,59],{"class":58},[31,238,150],{"class":62},[31,240,241],{"class":62}," {}\n",[31,243,245],{"class":33,"line":244},14,[31,246,108],{"emptyLinePlaceholder":107},[31,248,250],{"class":33,"line":249},15,[31,251,252],{"class":37},"  \u002F** Charge the cart. *\u002F\n",[31,254,256,259,262,265,267,269,273,276,280,282,286,289,293,295,298],{"class":33,"line":255},16,[31,257,258],{"class":51},"  async",[31,260,261],{"class":72}," pay",[31,263,264],{"class":62},"()",[31,266,153],{"class":62},[31,268,156],{"class":44},[31,270,272],{"class":271},"sxG60"," this",[31,274,275],{"class":62},".",[31,277,279],{"class":278},"sy9f4","payment",[31,281,275],{"class":62},[31,283,285],{"class":284},"s4mR9","charge",[31,287,76],{"class":288},"spAFX",[31,290,292],{"class":291},"s3dPA","4990",[31,294,150],{"class":288},[31,296,297],{"class":62},";",[31,299,188],{"class":62},[31,301,303],{"class":33,"line":302},17,[31,304,101],{"class":62},[13,306,307,310,311,314,315,319,320,323,324,327,328,331],{},[17,308,309],{},"this.payment"," is a ",[17,312,313],{},"StripePayment",", and ",[316,317,318],"strong",{},"nothing declares that",": ",[17,321,322],{},"extends"," is the whole\nregistration. There is no ",[17,325,326],{},"ports\u002F"," directory and no factory — a class in ",[17,329,330],{},"services\u002F"," becomes a\nport the moment another class extends it.",[333,334,336],"h2",{"id":335},"three-words","Three words",[22,338,340],{"className":24,"code":339,"language":26,"meta":27,"style":27},"abstract class Payment { … }                   \u002F\u002F the PORT — what a class asks for\nclass StripePayment extends Payment { … }      \u002F\u002F the REALIZATION — what answers it\nclass Auditing implements Partial\u003CPayment> {   \u002F\u002F a LINK — what stands in front of it\n  constructor(private inner: Payment) {}\n}\n",[17,341,342,362,382,409,428],{"__ignoreMap":27},[31,343,344,347,349,351,353,356,359],{"class":33,"line":34},[31,345,346],{"class":51},"abstract",[31,348,55],{"class":51},[31,350,59],{"class":58},[31,352,153],{"class":62},[31,354,355],{"class":181}," … ",[31,357,358],{"class":62},"}",[31,360,361],{"class":37},"                   \u002F\u002F the PORT — what a class asks for\n",[31,363,364,367,369,371,373,375,377,379],{"class":33,"line":41},[31,365,366],{"class":51},"class",[31,368,126],{"class":58},[31,370,129],{"class":51},[31,372,59],{"class":58},[31,374,153],{"class":62},[31,376,355],{"class":181},[31,378,358],{"class":62},[31,380,381],{"class":37},"      \u002F\u002F the REALIZATION — what answers it\n",[31,383,384,386,389,392,395,398,401,404,406],{"class":33,"line":66},[31,385,366],{"class":51},[31,387,388],{"class":58}," Auditing",[31,390,391],{"class":51}," implements",[31,393,394],{"class":58}," Partial",[31,396,397],{"class":62},"\u003C",[31,399,400],{"class":58},"Payment",[31,402,403],{"class":62},">",[31,405,153],{"class":62},[31,407,408],{"class":37},"   \u002F\u002F a LINK — what stands in front of it\n",[31,410,411,413,415,417,420,422,424,426],{"class":33,"line":98},[31,412,224],{"class":51},[31,414,76],{"class":62},[31,416,229],{"class":51},[31,418,419],{"class":79}," inner",[31,421,83],{"class":62},[31,423,59],{"class":58},[31,425,150],{"class":62},[31,427,241],{"class":62},[31,429,430],{"class":33,"line":104},[31,431,101],{"class":62},[433,434,435,442,450],"ul",{},[436,437,438,441],"li",{},[316,439,440],{},"The port"," is what is asked for.",[436,443,444,447,448,275],{},[316,445,446],{},"The realization"," answers it: one class, written with ",[17,449,322],{},[436,451,452,455,456,459],{},[316,453,454],{},"A link"," stands in front of it, and passes the call on to its ",[17,457,458],{},"inner",". There may be none, one\nor several.",[13,461,462,465],{},[17,463,464],{},"fougere ports"," prints every port of the app: its links in order, then the realization they reach.",[333,467,469],{"id":468},"two-realizations","Two realizations",[13,471,472,473,475],{},"Which provider a deployment uses changes between development and production, so it is not a\nfact about the code. When two classes extend ",[17,474,400],{},", the boot refuses to guess:",[22,477,482],{"className":478,"code":480,"language":481},[479],"language-text","Fougere boot refused: 1 declaration(s) that do not hold:\n  [port-implemented-twice] Payment\n    OgonePayment and StripePayment both extend Payment. Pick one in fougere.config.ts: ports: { Payment: 'OgonePayment' }.\n","text",[17,483,480],{"__ignoreMap":27},[13,485,486],{},"Keeping one silently would depend on the order files are read in, and the app would charge the\nwrong provider without a word. The choice goes in the config:",[22,488,490],{"className":24,"code":489,"language":26,"meta":27,"style":27},"\u002F\u002F fougere.config.ts\nexport default defineFougere({\n  ports: { Payment: process.env.PSP === 'ogone' ? 'OgonePayment' : 'StripePayment' },\n});\n",[17,491,492,497,512,570],{"__ignoreMap":27},[31,493,494],{"class":33,"line":34},[31,495,496],{"class":37},"\u002F\u002F fougere.config.ts\n",[31,498,499,501,503,506,509],{"class":33,"line":41},[31,500,45],{"class":44},[31,502,48],{"class":44},[31,504,505],{"class":284}," defineFougere",[31,507,76],{"class":508},"srlTG",[31,510,511],{"class":62},"{\n",[31,513,514,517,519,521,523,525,528,530,533,535,538,541,543,546,548,551,553,556,558,561,563,565,567],{"class":33,"line":66},[31,515,516],{"class":161},"  ports",[31,518,83],{"class":62},[31,520,153],{"class":62},[31,522,59],{"class":161},[31,524,83],{"class":62},[31,526,527],{"class":181}," process",[31,529,275],{"class":62},[31,531,532],{"class":278},"env",[31,534,275],{"class":62},[31,536,537],{"class":278},"PSP",[31,539,540],{"class":62}," ===",[31,542,168],{"class":167},[31,544,545],{"class":171},"ogone",[31,547,175],{"class":167},[31,549,550],{"class":62}," ?",[31,552,168],{"class":167},[31,554,555],{"class":171},"OgonePayment",[31,557,175],{"class":167},[31,559,560],{"class":62}," :",[31,562,168],{"class":167},[31,564,313],{"class":171},[31,566,175],{"class":167},[31,568,569],{"class":62}," },\n",[31,571,572,574,576],{"class":33,"line":98},[31,573,358],{"class":62},[31,575,150],{"class":508},[31,577,95],{"class":62},[13,579,580,583,584,587,588,319,591,593,594,597,598,600,601,604,605,607,608,611,612,615,616,618],{},[17,581,582],{},"ports:"," sits beside ",[17,585,586],{},"fronds:"," and ",[17,589,590],{},"sources:",[17,592,586],{}," says where a ",[316,595,596],{},"call"," goes, ",[17,599,590],{},"\nwhere a ",[316,602,603],{},"row"," is, ",[17,606,582],{}," who performs an ",[316,609,610],{},"action",". None belongs inside a frond, which\ndescribes itself and not its deployment. Delete ",[17,613,614],{},"OgonePayment.ts"," and the line can go: with one\nrealization there is nothing to choose. A ",[17,617,582],{}," key that matches no port is reported at boot.",[13,620,621,622,625,626,628,629,632,633,635,636,638,639,641],{},"A port can sit under a port. With ",[17,623,624],{},"StripePayment extends CardPayment extends Payment",", a class\nasking for ",[17,627,400],{}," and one asking for ",[17,630,631],{},"CardPayment"," both receive ",[17,634,313],{},". An ",[17,637,346],{},"\nclass in between is never picked; a concrete one is a second candidate, and the boot asks\n",[17,640,582],{}," to choose.",[333,643,645],{"id":644},"links","Links",[13,647,648],{},"A link stands in front of a port to add something — an audit line, a timing, a fallback — while\nthe handler and the realization stay as they are. Write only what you change, and pass the call on:",[22,650,652],{"className":24,"code":651,"language":26,"meta":27,"style":27},"\u002F\u002F services\u002FAuditPayment.ts\nexport default class AuditPayment implements Partial\u003CPayment> {\n  constructor(private inner: Payment, private ledger: Ledger) {}\n\n  charge(amountCents: number) {\n    const charge = this.inner.charge(amountCents);\n    this.ledger.record(`${charge.reference} ${charge.amountCents}`);\n\n    return charge;\n  }\n  \u002F\u002F refund() is not written: it goes to the inner as it is\n}\n",[17,653,654,659,682,713,717,733,761,810,814,823,828,833],{"__ignoreMap":27},[31,655,656],{"class":33,"line":34},[31,657,658],{"class":37},"\u002F\u002F services\u002FAuditPayment.ts\n",[31,660,661,663,665,667,670,672,674,676,678,680],{"class":33,"line":41},[31,662,45],{"class":44},[31,664,48],{"class":44},[31,666,55],{"class":51},[31,668,669],{"class":58}," AuditPayment",[31,671,391],{"class":51},[31,673,394],{"class":58},[31,675,397],{"class":62},[31,677,400],{"class":58},[31,679,403],{"class":62},[31,681,63],{"class":62},[31,683,684,686,688,690,692,694,696,698,701,704,706,709,711],{"class":33,"line":66},[31,685,224],{"class":51},[31,687,76],{"class":62},[31,689,229],{"class":51},[31,691,419],{"class":79},[31,693,83],{"class":62},[31,695,59],{"class":58},[31,697,178],{"class":62},[31,699,700],{"class":51}," private",[31,702,703],{"class":79}," ledger",[31,705,83],{"class":62},[31,707,708],{"class":58}," Ledger",[31,710,150],{"class":62},[31,712,241],{"class":62},[31,714,715],{"class":33,"line":98},[31,716,108],{"emptyLinePlaceholder":107},[31,718,719,721,723,725,727,729,731],{"class":33,"line":104},[31,720,139],{"class":72},[31,722,76],{"class":62},[31,724,80],{"class":79},[31,726,83],{"class":62},[31,728,86],{"class":58},[31,730,150],{"class":62},[31,732,63],{"class":62},[31,734,735,738,740,743,745,747,749,751,753,755,757,759],{"class":33,"line":111},[31,736,737],{"class":51},"    const",[31,739,73],{"class":181},[31,741,742],{"class":62}," =",[31,744,272],{"class":271},[31,746,275],{"class":62},[31,748,458],{"class":278},[31,750,275],{"class":62},[31,752,285],{"class":284},[31,754,76],{"class":288},[31,756,80],{"class":181},[31,758,150],{"class":288},[31,760,95],{"class":62},[31,762,763,766,768,771,773,776,778,781,784,786,788,791,793,796,798,800,802,804,806,808],{"class":33,"line":117},[31,764,765],{"class":271},"    this",[31,767,275],{"class":62},[31,769,770],{"class":278},"ledger",[31,772,275],{"class":62},[31,774,775],{"class":284},"record",[31,777,76],{"class":288},[31,779,780],{"class":167},"`",[31,782,783],{"class":62},"${",[31,785,285],{"class":181},[31,787,275],{"class":62},[31,789,790],{"class":278},"reference",[31,792,358],{"class":62},[31,794,795],{"class":62}," ${",[31,797,285],{"class":181},[31,799,275],{"class":62},[31,801,80],{"class":278},[31,803,358],{"class":62},[31,805,780],{"class":167},[31,807,150],{"class":288},[31,809,95],{"class":62},[31,811,812],{"class":33,"line":136},[31,813,108],{"emptyLinePlaceholder":107},[31,815,816,819,821],{"class":33,"line":191},[31,817,818],{"class":44},"    return",[31,820,73],{"class":181},[31,822,95],{"class":62},[31,824,825],{"class":33,"line":196},[31,826,827],{"class":62},"  }\n",[31,829,830],{"class":33,"line":201},[31,831,832],{"class":37},"  \u002F\u002F refund() is not written: it goes to the inner as it is\n",[31,834,835],{"class":33,"line":207},[31,836,101],{"class":62},[13,838,839,840,843,844,847,848,850,851,854,855,858,859,275],{},"A class is a link because it says so: ",[17,841,842],{},"implements Partial\u003CPayment>"," and an ",[17,845,846],{},"inner: Payment",".\nWithout the clause, a class asking for a ",[17,849,400],{}," is an ordinary service. TypeScript erases\n",[17,852,853],{},"implements",", so the scan reads it; a ",[17,856,857],{},"frond()"," written by hand states it —\n",[17,860,861],{},"{ ctor: AuditPayment, deps: ['Payment'], implements: ['Payment'] }",[13,863,864],{},"One link needs nothing more. Two need an order, outside in, and the boot refuses them without one:",[22,866,868],{"className":24,"code":867,"language":26,"meta":27,"style":27},"ports: { Payment: ['AuditPayment', 'TimingPayment', 'StripePayment'] }\n\u002F\u002F       → audit(timing(stripe))\n",[17,869,870,916],{"__ignoreMap":27},[31,871,872,876,878,880,882,884,887,889,892,894,896,898,901,903,905,907,909,911,914],{"class":33,"line":34},[31,873,875],{"class":874},"sWI7z","ports",[31,877,83],{"class":62},[31,879,153],{"class":62},[31,881,59],{"class":874},[31,883,83],{"class":62},[31,885,886],{"class":288}," [",[31,888,175],{"class":167},[31,890,891],{"class":171},"AuditPayment",[31,893,175],{"class":167},[31,895,178],{"class":62},[31,897,168],{"class":167},[31,899,900],{"class":171},"TimingPayment",[31,902,175],{"class":167},[31,904,178],{"class":62},[31,906,168],{"class":167},[31,908,313],{"class":171},[31,910,175],{"class":167},[31,912,913],{"class":288},"]",[31,915,188],{"class":62},[31,917,918],{"class":33,"line":41},[31,919,920],{"class":37},"\u002F\u002F       → audit(timing(stripe))\n",[13,922,923,924,927,928,931,932,935,936,939,940,943,944,946],{},"A link may also ",[316,925,926],{},"extend"," the port and hand its inner to ",[17,929,930],{},"super"," — ",[17,933,934],{},"constructor(inner: Payment) { super(inner); }",". The difference is what you leave out. Implemented, it goes to the inner\nuntouched. Extended, the port's own code runs through your methods: a ",[17,937,938],{},"chargeTwice()"," that the\nport writes over ",[17,941,942],{},"this.charge"," would pass through your ",[17,945,285],{}," twice.",[13,948,949,950,957,958,960,961,275],{},"A retry is not a link's job. Whether a failure is worth asking again, and whether asking again\nis safe, is known where the call crosses — the transport between two fronds\n(",[951,952,956],"a",{"href":953,"rel":954},"https:\u002F\u002Fgithub.com\u002Fchok\u002Ffougere\u002Ftree\u002Fmain\u002Fdemos\u002Ftransport-chain",[955],"nofollow","transport-chain",") or the HTTP\nclient inside ",[17,959,313],{}," — and neither reaches ",[17,962,285],{},[333,964,966],{"id":965},"the-ports-fougere-opens","The ports Fougere opens",[13,968,969],{},"The same mechanism changes what the framework does. Fougere answers these itself, and you stand\nin front of them the same way:",[971,972,973,985],"table",{},[974,975,976],"thead",{},[977,978,979,982],"tr",{},[980,981,8],"th",{},[980,983,984],{},"Where it stands",[986,987,988,1007,1024,1038,1052,1066,1076],"tbody",{},[977,989,990,1000],{},[991,992,993,996,997],"td",{},[17,994,995],{},"Dispatcher"," · ",[17,998,999],{},"Dispatcher\u003CPostHandler>",[991,1001,1002,1003],{},"around every call of a frond · of one handler — see ",[951,1004,1006],{"href":1005},"\u002Fdocs\u002Fbehaviour\u002Faround-every-call","Around every call",[977,1008,1009,1017],{},[991,1010,1011,996,1014],{},[17,1012,1013],{},"Rest",[17,1015,1016],{},"Rest\u003CPostHandler>",[991,1018,1019,1020],{},"around a REST request — see ",[951,1021,1023],{"href":1022},"\u002Fdocs\u002Fserve\u002Frest-graphql","REST",[977,1025,1026,1031],{},[991,1027,1028],{},[17,1029,1030],{},"Collect\u003CUser>",[991,1032,1033,1034],{},"where a parameter is filled — see ",[951,1035,1037],{"href":1036},"\u002Fdocs\u002Faccess\u002Fauthentication","Authentication",[977,1039,1040,1045],{},[991,1041,1042],{},[17,1043,1044],{},"Present\u003CPost>",[991,1046,1047,1048],{},"where fields are added to an answer — see ",[951,1049,1051],{"href":1050},"\u002Fdocs\u002Fdata\u002Fcomputed-field","A computed field",[977,1053,1054,1059],{},[991,1055,1056],{},[17,1057,1058],{},"Env\u003CMeili>",[991,1060,1061,1062],{},"where a value is read — see ",[951,1063,1065],{"href":1064},"\u002Fdocs\u002Fdata\u002Fvalues","Values",[977,1067,1068,1073],{},[991,1069,1070],{},[17,1071,1072],{},"Storage",[991,1074,1075],{},"in front of the rows — below",[977,1077,1078,1083],{},[991,1079,1080],{},[17,1081,1082],{},"Logger",[991,1084,1085],{},"every line a class writes — below",[13,1087,1088,1089,1091,1092,1095,1096,1098,1099,275],{},"A port about something names it as it is written — ",[17,1090,1016],{},", ",[17,1093,1094],{},"Repository\u003CPost>",",\n",[17,1097,1058],{}," — so no class name can take its place. The full list is in the\n",[951,1100,790],{"href":1101},"\u002Freference\u002Fports",[1103,1104,1106],"h3",{"id":1105},"in-front-of-the-rows","In front of the rows",[13,1108,1109,1111],{},[17,1110,1072],{}," is a class as well as an interface. A link extends it, asks for one, and writes only\nthe gestures it changes:",[22,1113,1115],{"className":24,"code":1114,"language":26,"meta":27,"style":27},"\u002F\u002F services\u002FAuditing.ts\nexport default class Auditing extends Storage {\n  constructor(private inner: Storage) { super(inner); }\n\n  override async create(row: Record\u003Cstring, unknown>) {\n    await ship(row);\n\n    return this.inner.create(row);\n  }\n}\n",[17,1116,1117,1122,1139,1171,1175,1210,1226,1230,1253,1257],{"__ignoreMap":27},[31,1118,1119],{"class":33,"line":34},[31,1120,1121],{"class":37},"\u002F\u002F services\u002FAuditing.ts\n",[31,1123,1124,1126,1128,1130,1132,1134,1137],{"class":33,"line":41},[31,1125,45],{"class":44},[31,1127,48],{"class":44},[31,1129,55],{"class":51},[31,1131,388],{"class":58},[31,1133,129],{"class":51},[31,1135,1136],{"class":58}," Storage",[31,1138,63],{"class":62},[31,1140,1141,1143,1145,1147,1149,1151,1153,1155,1157,1161,1163,1165,1167,1169],{"class":33,"line":66},[31,1142,224],{"class":51},[31,1144,76],{"class":62},[31,1146,229],{"class":51},[31,1148,419],{"class":79},[31,1150,83],{"class":62},[31,1152,1136],{"class":58},[31,1154,150],{"class":62},[31,1156,153],{"class":62},[31,1158,1160],{"class":1159},"sTljH"," super",[31,1162,76],{"class":288},[31,1164,458],{"class":181},[31,1166,150],{"class":288},[31,1168,297],{"class":62},[31,1170,188],{"class":62},[31,1172,1173],{"class":33,"line":98},[31,1174,108],{"emptyLinePlaceholder":107},[31,1176,1177,1180,1183,1186,1188,1190,1192,1195,1197,1200,1202,1205,1208],{"class":33,"line":104},[31,1178,1179],{"class":51},"  override",[31,1181,1182],{"class":51}," async",[31,1184,1185],{"class":72}," create",[31,1187,76],{"class":62},[31,1189,603],{"class":79},[31,1191,83],{"class":62},[31,1193,1194],{"class":58}," Record",[31,1196,397],{"class":62},[31,1198,1199],{"class":58},"string",[31,1201,178],{"class":62},[31,1203,1204],{"class":58}," unknown",[31,1206,1207],{"class":62},">)",[31,1209,63],{"class":62},[31,1211,1212,1215,1218,1220,1222,1224],{"class":33,"line":111},[31,1213,1214],{"class":44},"    await",[31,1216,1217],{"class":284}," ship",[31,1219,76],{"class":288},[31,1221,603],{"class":181},[31,1223,150],{"class":288},[31,1225,95],{"class":62},[31,1227,1228],{"class":33,"line":117},[31,1229,108],{"emptyLinePlaceholder":107},[31,1231,1232,1234,1236,1238,1240,1242,1245,1247,1249,1251],{"class":33,"line":136},[31,1233,818],{"class":44},[31,1235,272],{"class":271},[31,1237,275],{"class":62},[31,1239,458],{"class":278},[31,1241,275],{"class":62},[31,1243,1244],{"class":284},"create",[31,1246,76],{"class":288},[31,1248,603],{"class":181},[31,1250,150],{"class":288},[31,1252,95],{"class":62},[31,1254,1255],{"class":33,"line":191},[31,1256,827],{"class":62},[31,1258,1259],{"class":33,"line":196},[31,1260,101],{"class":62},[13,1262,1263],{},"It covers every entity of its frond.",[1103,1265,1267],{"id":1266},"the-logger","The logger",[13,1269,1270,1272,1273,1275],{},[17,1271,1082],{}," is a port like ",[17,1274,400],{},", and a class extending it takes the frond's logger over:",[22,1277,1279],{"className":24,"code":1278,"language":26,"meta":27,"style":27},"\u002F\u002F services\u002FRedactingLogger.ts\nexport default class RedactingLogger extends Logger {\n  constructor(inner: Logger) { super(inner); }\n\n  info(message: string, ...args: unknown[]) {\n    super.info(message.replace(\u002Ftoken=\\S+\u002Fg, 'token=***'), ...args);\n  }\n}\n\n\u002F\u002F any handler, unchanged\nconstructor(private logger: Logger) {}   \u002F\u002F receives RedactingLogger\n",[17,1280,1281,1286,1304,1332,1336,1370,1427,1431,1435,1439,1444],{"__ignoreMap":27},[31,1282,1283],{"class":33,"line":34},[31,1284,1285],{"class":37},"\u002F\u002F services\u002FRedactingLogger.ts\n",[31,1287,1288,1290,1292,1294,1297,1299,1302],{"class":33,"line":41},[31,1289,45],{"class":44},[31,1291,48],{"class":44},[31,1293,55],{"class":51},[31,1295,1296],{"class":58}," RedactingLogger",[31,1298,129],{"class":51},[31,1300,1301],{"class":58}," Logger",[31,1303,63],{"class":62},[31,1305,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324,1326,1328,1330],{"class":33,"line":66},[31,1307,224],{"class":51},[31,1309,76],{"class":62},[31,1311,458],{"class":79},[31,1313,83],{"class":62},[31,1315,1301],{"class":58},[31,1317,150],{"class":62},[31,1319,153],{"class":62},[31,1321,1160],{"class":1159},[31,1323,76],{"class":288},[31,1325,458],{"class":181},[31,1327,150],{"class":288},[31,1329,297],{"class":62},[31,1331,188],{"class":62},[31,1333,1334],{"class":33,"line":98},[31,1335,108],{"emptyLinePlaceholder":107},[31,1337,1338,1341,1343,1346,1348,1351,1353,1356,1359,1361,1363,1366,1368],{"class":33,"line":104},[31,1339,1340],{"class":72},"  info",[31,1342,76],{"class":62},[31,1344,1345],{"class":79},"message",[31,1347,83],{"class":62},[31,1349,1350],{"class":58}," string",[31,1352,178],{"class":62},[31,1354,1355],{"class":62}," ...",[31,1357,1358],{"class":79},"args",[31,1360,83],{"class":62},[31,1362,1204],{"class":58},[31,1364,1365],{"class":508},"[]",[31,1367,150],{"class":62},[31,1369,63],{"class":62},[31,1371,1372,1375,1377,1380,1382,1384,1386,1389,1391,1394,1397,1400,1402,1406,1408,1410,1413,1415,1417,1419,1421,1423,1425],{"class":33,"line":111},[31,1373,1374],{"class":1159},"    super",[31,1376,275],{"class":62},[31,1378,1379],{"class":284},"info",[31,1381,76],{"class":288},[31,1383,1345],{"class":181},[31,1385,275],{"class":62},[31,1387,1388],{"class":284},"replace",[31,1390,76],{"class":288},[31,1392,1393],{"class":167},"\u002F",[31,1395,1396],{"class":171},"token=\\S",[31,1398,1399],{"class":62},"+",[31,1401,1393],{"class":167},[31,1403,1405],{"class":1404},"sWPpw","g",[31,1407,178],{"class":62},[31,1409,168],{"class":167},[31,1411,1412],{"class":171},"token=***",[31,1414,175],{"class":167},[31,1416,150],{"class":288},[31,1418,178],{"class":62},[31,1420,1355],{"class":62},[31,1422,1358],{"class":181},[31,1424,150],{"class":288},[31,1426,95],{"class":62},[31,1428,1429],{"class":33,"line":117},[31,1430,827],{"class":62},[31,1432,1433],{"class":33,"line":136},[31,1434,101],{"class":62},[31,1436,1437],{"class":33,"line":191},[31,1438,108],{"emptyLinePlaceholder":107},[31,1440,1441],{"class":33,"line":196},[31,1442,1443],{"class":37},"\u002F\u002F any handler, unchanged\n",[31,1445,1446,1449,1451,1454,1456,1459],{"class":33,"line":201},[31,1447,1448],{"class":284},"constructor",[31,1450,76],{"class":508},[31,1452,1453],{"class":181},"private logger: Logger",[31,1455,150],{"class":508},[31,1457,1458],{"class":62}," {}",[31,1460,1461],{"class":37},"   \u002F\u002F receives RedactingLogger\n",[13,1463,1464,1467,1468,1472,1473,1476,1477,1480],{},[17,1465,1466],{},"super(inner)"," is what keeps the line whole: the inner is the logger the app built, so the\nwrapper writes with its name, its ",[951,1469,1471],{"href":1470},"\u002Fdocs\u002Frun\u002Fobserve#sending-it","destinations"," and the\noperation it runs in, and what it leaves out — ",[17,1474,1475],{},"warn"," here — still arrives everywhere.\n",[17,1478,1479],{},"child()"," returns a child of the real logger, which skips the wrapper.",[1482,1483,1484],"warning",{},[13,1485,1486,1487,1489,1490,1492,1493,275],{},"A subclass that asks for no ",[17,1488,458],{}," is a second logger built with no arguments. It still prints\nto the terminal, but sends nothing to your destinations and no longer knows the operation.\nNothing fails: the lines just stop arriving elsewhere. Ask for ",[17,1491,458],{}," and hand it to ",[17,1494,930],{},[13,1496,1497,1498,1501,1502,1505,1506,1510],{},"Without a subclass, each class gets a logger named after it: a line written in\n",[17,1499,1500],{},"PricingService"," reads ",[17,1503,1504],{},"app:blog:PricingService",". A level change reaches every logger, children\nincluded, without rebuilding them (",[951,1507,1509],{"href":1508},"\u002Fdocs\u002Frun\u002Flifecycle","lifecycle",").",[13,1512,1513,1514,1516,1517,275],{},"A repository is not a port in this sense: extending ",[17,1515,1094],{}," seats a class on Post's\nrows — see ",[951,1518,1520],{"href":1519},"\u002Fdocs\u002Fconcepts\u002Frepository","Repository",[333,1522,1524],{"id":1523},"port-or-frond","Port or frond?",[13,1526,1527],{},"A frond placed elsewhere also changes what answers, and it moves the process too. The line is easy\nto check:",[433,1529,1530,1540],{},[436,1531,1532,1533,1536,1537,1539],{},"the collaborator ",[316,1534,1535],{},"owns data"," — entities, tables, seeds → it is a frond, and ",[17,1538,586],{}," places it;",[436,1541,1542,1543,1546,1547,1549],{},"it only ",[316,1544,1545],{},"acts on the outside world"," — a payment provider, a mailer, a file store → it is a\nport, and ",[17,1548,582],{}," chooses it.",[13,1551,1552],{},"A port lets you write a seam. It does not tell you where the seams are: cutting a domain into\ncollaborators stays your decision.",[1554,1555,1556],"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 .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 .s15xx, html code.shiki .s15xx{--shiki-light:#39ADB5;--shiki-default:#A3B0A5;--shiki-dark:#89DDFF}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 .sHtqg, html code.shiki .sHtqg{--shiki-light:#E53935;--shiki-default:#93CFC0;--shiki-dark:#F07178}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 .sPEhv, html code.shiki .sPEhv{--shiki-light:#90A4AE;--shiki-default:#DDE5DA;--shiki-dark:#BABED8}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 .sy9f4, html code.shiki .sy9f4{--shiki-light:#90A4AE;--shiki-default:#93CFC0;--shiki-dark:#BABED8}html pre.shiki code .s4mR9, html code.shiki .s4mR9{--shiki-light:#6182B8;--shiki-default:#C9B6EA;--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 .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 .srlTG, html code.shiki .srlTG{--shiki-light:#90A4AE;--shiki-default:#A3B0A5;--shiki-dark:#BABED8}html pre.shiki code .sWI7z, html code.shiki .sWI7z{--shiki-light:#E2931D;--shiki-default:#93CFC0;--shiki-dark:#FFCB6B}html pre.shiki code .sTljH, html code.shiki .sTljH{--shiki-light:#90A4AE;--shiki-light-font-style:inherit;--shiki-default:#8FCF86;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:inherit}html pre.shiki code .sWPpw, html code.shiki .sWPpw{--shiki-light:#F76D47;--shiki-default:#8FCF86;--shiki-dark:#F78C6C}",{"title":27,"searchDepth":41,"depth":41,"links":1558},[1559,1560,1561,1562,1566],{"id":335,"depth":41,"text":336},{"id":468,"depth":41,"text":469},{"id":644,"depth":41,"text":645},{"id":965,"depth":41,"text":966,"children":1563},[1564,1565],{"id":1105,"depth":66,"text":1106},{"id":1266,"depth":66,"text":1267},{"id":1523,"depth":41,"text":1524},"A capability, not a provider: the handler asks for it, a class extending it answers.","md",null,"concept",{},"\u002Fdocs\u002Fconcepts\u002Fport",{"title":8,"description":1567},"docs\u002F1.concepts\u002F7.port","M8izM4M5DX4l4EiW7e7SrP2AUyvdDcFweTr-lQM-etg",[1577,1580,1583,1584,1587,1590,1593,1594,1597,1601,1607,1612,1616,1618,1622,1626,1629,1634,1638,1640,1645,1648,1653,1657,1661,1665,1669,1672,1676,1680,1684,1688,1692,1696,1700,1704,1708,1711,1714,1717,1720,1723,1726,1729,1732,1735,1738],{"path":1578,"title":1579,"uses":1569},"\u002Fdocs\u002Fconcepts\u002Fentity","Entity",{"path":1581,"title":1582,"uses":1569},"\u002Fdocs\u002Fconcepts\u002Fhandler","Handler",{"path":1519,"title":1520,"uses":1569},{"path":1585,"title":1586,"uses":1569},"\u002Fdocs\u002Fconcepts\u002Ffrond","Frond",{"path":1588,"title":1589,"uses":1569},"\u002Fdocs\u002Fconcepts\u002Ffacade","Facade",{"path":1591,"title":1592,"uses":1569},"\u002Fdocs\u002Fconcepts\u002Ffact","Fact",{"path":1572,"title":8,"uses":1569},{"path":1595,"title":1596,"uses":1569},"\u002Fdocs\u002Fconcepts\u002Fconfiguration","Configuration",{"path":1036,"title":1037,"uses":1598},[1599,1600],"port","frond",{"path":1602,"title":1603,"uses":1604},"\u002Fdocs\u002Faccess\u002Fstate","Keep a caller's state",[1605,1606],"configuration","handler",{"path":1608,"title":1609,"uses":1610},"\u002Fdocs\u002Fdata\u002Fsql","SQLite or Postgres",[1611,1605],"entity",{"path":1613,"title":1614,"uses":1615},"\u002Fdocs\u002Fdata\u002Fseveral-databases","Several databases",[1605,1611],{"path":1050,"title":1051,"uses":1617},[1611,1599],{"path":1619,"title":1620,"uses":1621},"\u002Fdocs\u002Fdata\u002Fevolve","Evolve a schema",[1611],{"path":1623,"title":1624,"uses":1625},"\u002Fdocs\u002Fdata\u002Fseeds","Seed data",[1611],{"path":1064,"title":1627,"uses":1628},"Read settings and secrets",[1611,1605],{"path":1630,"title":1631,"uses":1632},"\u002Fdocs\u002Fdata\u002Fmirror","Mirror a source you cannot query",[1633],"repository",{"path":1635,"title":1636,"uses":1637},"\u002Fdocs\u002Fdata\u002Ftogether","Two writes as one",[1633],{"path":1005,"title":1006,"uses":1639},[1599,1600],{"path":1641,"title":1642,"uses":1643},"\u002Fdocs\u002Fbehaviour\u002Ffinish-a-fact","Finish a fact",[1644],"fact",{"path":1022,"title":1646,"uses":1647},"REST, OpenAPI, GraphQL",[1606,1605],{"path":1649,"title":1650,"uses":1651},"\u002Fdocs\u002Fserve\u002Fpages","Pages: queries and commands",[1606,1652],"facade",{"path":1654,"title":1655,"uses":1656},"\u002Fdocs\u002Fserve\u002Fforms","A form",[1611],{"path":1658,"title":1659,"uses":1660},"\u002Fdocs\u002Fserve\u002Fadmin","An admin panel",[1606],{"path":1662,"title":1663,"uses":1664},"\u002Fdocs\u002Frun\u002Fdeploy","Deploy a split",[1605,1600],{"path":1666,"title":1667,"uses":1668},"\u002Fdocs\u002Frun\u002Fsecure","Secure calls between processes",[1605,1600],{"path":1508,"title":1670,"uses":1671},"Reload and shut down",[1605],{"path":1673,"title":1674,"uses":1675},"\u002Fdocs\u002Frun\u002Fobserve","Observe",[1605,1606],{"path":1677,"title":1678,"uses":1679},"\u002Fdocs\u002Frun\u002Fdev-panel","The dev panel",[1606],{"path":1681,"title":1682,"uses":1683},"\u002Fdocs\u002Frun\u002Ftest","Test",[1611,1599],{"path":1685,"title":1686,"uses":1687},"\u002Fdocs\u002Fadopt\u002Fnew-project","Start a project",[1600,1605],{"path":1689,"title":1690,"uses":1691},"\u002Fdocs\u002Fadopt\u002Fexisting-app","Add Fougere to an existing app",[1600,1605],{"path":1693,"title":1694,"uses":1695},"\u002Fdocs\u002Fadopt\u002Fbring-your-schema","Bring your schema",[1611],{"path":1697,"title":1698,"uses":1699},"\u002Fdocs\u002Fadopt\u002Fhosts","Pick a host",[1605],{"path":1701,"title":1702,"uses":1703},"\u002Fdocs\u002Fadopt\u002Fanother-repository","A frond from another repository",[1652,1600],{"path":1705,"title":1706,"uses":1707},"\u002Fdocs\u002Fadopt\u002Fdemos","Demos",[],{"path":1709,"title":1710,"uses":1569},"\u002Fdocs\u002Fextending\u002Fscan","How the scan reads a project",{"path":1712,"title":1713,"uses":1569},"\u002Fdocs\u002Fextending\u002Fwithout-compiler","Boot without the compiler",{"path":1715,"title":1716,"uses":1569},"\u002Fdocs\u002Fextending\u002Fboot","The boot, step by step",{"path":1718,"title":1719,"uses":1569},"\u002Fdocs\u002Fextending\u002Fcard-and-wire","The card and the wire",{"path":1721,"title":1722,"uses":1569},"\u002Fdocs\u002Fextending\u002Fextension-points","Registries and extension points",{"path":1724,"title":1725,"uses":1569},"\u002Fdocs\u002Fextending\u002Fvocabulary","Teach a word",{"path":1727,"title":1728,"uses":1569},"\u002Fdocs\u002Fextending\u002Fextensions","Run code at boot and shutdown",{"path":1730,"title":1731,"uses":1569},"\u002Fdocs\u002Fextending\u002Fsource-adapter","Write a source adapter",{"path":1733,"title":1734,"uses":1569},"\u002Fdocs\u002Fextending\u002Fsurface","Write a surface",{"path":1736,"title":1737,"uses":1569},"\u002Fdocs\u002Fextending\u002Fforeign-frond","A frond in another language",{"path":1739,"title":1740,"uses":1569},"\u002Fdocs","What is Fougere",[1742],{"title":1743,"path":1739,"stem":1744,"children":1745,"page":-1},"Docs","docs",[1746,1748,1768,1777,1798,1807,1820,1837,1854],{"title":1740,"path":1739,"stem":1747},"docs\u002Findex",{"title":1749,"path":1750,"stem":1751,"children":1752,"page":5},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F1.concepts",[1753,1755,1757,1759,1761,1763,1765,1766],{"title":1579,"path":1578,"stem":1754},"docs\u002F1.concepts\u002F1.entity",{"title":1582,"path":1581,"stem":1756},"docs\u002F1.concepts\u002F2.handler",{"title":1520,"path":1519,"stem":1758},"docs\u002F1.concepts\u002F3.repository",{"title":1586,"path":1585,"stem":1760},"docs\u002F1.concepts\u002F4.frond",{"title":1589,"path":1588,"stem":1762},"docs\u002F1.concepts\u002F5.facade",{"title":1592,"path":1591,"stem":1764},"docs\u002F1.concepts\u002F6.fact",{"title":8,"path":1572,"stem":1574},{"title":1596,"path":1595,"stem":1767},"docs\u002F1.concepts\u002F8.configuration",{"title":1769,"path":1770,"stem":1771,"children":1772,"page":5},"Access","\u002Fdocs\u002Faccess","docs\u002F2.access",[1773,1775],{"title":1037,"path":1036,"stem":1774},"docs\u002F2.access\u002F1.authentication",{"title":1603,"path":1602,"stem":1776},"docs\u002F2.access\u002F2.state",{"title":1778,"path":1779,"stem":1780,"children":1781,"page":5},"Data","\u002Fdocs\u002Fdata","docs\u002F3.data",[1782,1784,1786,1788,1790,1792,1794,1796],{"title":1609,"path":1608,"stem":1783},"docs\u002F3.data\u002F1.sql",{"title":1614,"path":1613,"stem":1785},"docs\u002F3.data\u002F2.several-databases",{"title":1051,"path":1050,"stem":1787},"docs\u002F3.data\u002F3.computed-field",{"title":1620,"path":1619,"stem":1789},"docs\u002F3.data\u002F4.evolve",{"title":1624,"path":1623,"stem":1791},"docs\u002F3.data\u002F5.seeds",{"title":1627,"path":1064,"stem":1793},"docs\u002F3.data\u002F6.values",{"title":1631,"path":1630,"stem":1795},"docs\u002F3.data\u002F7.mirror",{"title":1636,"path":1635,"stem":1797},"docs\u002F3.data\u002F8.together",{"title":1799,"path":1800,"stem":1801,"children":1802,"page":5},"Behaviour","\u002Fdocs\u002Fbehaviour","docs\u002F4.behaviour",[1803,1805],{"title":1006,"path":1005,"stem":1804},"docs\u002F4.behaviour\u002F1.around-every-call",{"title":1642,"path":1641,"stem":1806},"docs\u002F4.behaviour\u002F2.finish-a-fact",{"title":1808,"path":1809,"stem":1810,"children":1811,"page":5},"Serve","\u002Fdocs\u002Fserve","docs\u002F5.serve",[1812,1814,1816,1818],{"title":1646,"path":1022,"stem":1813},"docs\u002F5.serve\u002F1.rest-graphql",{"title":1650,"path":1649,"stem":1815},"docs\u002F5.serve\u002F2.pages",{"title":1655,"path":1654,"stem":1817},"docs\u002F5.serve\u002F3.forms",{"title":1659,"path":1658,"stem":1819},"docs\u002F5.serve\u002F4.admin",{"title":1821,"path":1822,"stem":1823,"children":1824,"page":5},"Run","\u002Fdocs\u002Frun","docs\u002F6.run",[1825,1827,1829,1831,1833,1835],{"title":1663,"path":1662,"stem":1826},"docs\u002F6.run\u002F1.deploy",{"title":1667,"path":1666,"stem":1828},"docs\u002F6.run\u002F2.secure",{"title":1670,"path":1508,"stem":1830},"docs\u002F6.run\u002F3.lifecycle",{"title":1674,"path":1673,"stem":1832},"docs\u002F6.run\u002F4.observe",{"title":1678,"path":1677,"stem":1834},"docs\u002F6.run\u002F5.dev-panel",{"title":1682,"path":1681,"stem":1836},"docs\u002F6.run\u002F6.test",{"title":1838,"path":1839,"stem":1840,"children":1841,"page":5},"Adopt","\u002Fdocs\u002Fadopt","docs\u002F7.adopt",[1842,1844,1846,1848,1850,1852],{"title":1686,"path":1685,"stem":1843},"docs\u002F7.adopt\u002F1.new-project",{"title":1690,"path":1689,"stem":1845},"docs\u002F7.adopt\u002F2.existing-app",{"title":1694,"path":1693,"stem":1847},"docs\u002F7.adopt\u002F3.bring-your-schema",{"title":1698,"path":1697,"stem":1849},"docs\u002F7.adopt\u002F4.hosts",{"title":1702,"path":1701,"stem":1851},"docs\u002F7.adopt\u002F5.another-repository",{"title":1706,"path":1705,"stem":1853},"docs\u002F7.adopt\u002F6.demos",{"title":1855,"path":1856,"stem":1857,"children":1858,"page":5},"Extending","\u002Fdocs\u002Fextending","docs\u002F8.extending",[1859,1861,1863,1865,1867,1869,1871,1873,1875,1877],{"title":1710,"path":1709,"stem":1860},"docs\u002F8.extending\u002F1.scan",{"title":1713,"path":1712,"stem":1862},"docs\u002F8.extending\u002F10.without-compiler",{"title":1716,"path":1715,"stem":1864},"docs\u002F8.extending\u002F2.boot",{"title":1719,"path":1718,"stem":1866},"docs\u002F8.extending\u002F3.card-and-wire",{"title":1722,"path":1721,"stem":1868},"docs\u002F8.extending\u002F4.extension-points",{"title":1725,"path":1724,"stem":1870},"docs\u002F8.extending\u002F5.vocabulary",{"title":1728,"path":1727,"stem":1872},"docs\u002F8.extending\u002F6.extensions",{"title":1731,"path":1730,"stem":1874},"docs\u002F8.extending\u002F7.source-adapter",{"title":1734,"path":1733,"stem":1876},"docs\u002F8.extending\u002F8.surface",{"title":1737,"path":1736,"stem":1878},"docs\u002F8.extending\u002F9.foreign-frond",1794396614343]