[{"data":1,"prerenderedAt":1959},["ShallowReactive",2],{"fougere:post.list:{}":3,"docs:\u002Fdocs\u002Fextending\u002Fsource-adapter":6,"docs-uses":1649,"docs-nav":1821},{"items":4,"hasMore":5},[],false,{"id":7,"title":8,"body":9,"description":1640,"extension":1641,"forms":1642,"kind":1643,"meta":1644,"navigation":166,"path":1645,"seo":1646,"stem":1647,"step":1642,"uses":1642,"__hash__":1648},"docs\u002Fdocs\u002F8.extending\u002F7.source-adapter.md","Write a source adapter",{"type":10,"value":11,"toc":1631},"minimark",[12,57,856,859,905,915,933,938,941,1013,1025,1033,1039,1043,1248,1252,1265,1385,1395,1401,1468,1476,1486,1490,1500,1553,1556,1573,1577,1588,1594,1603,1618,1627],[13,14,15,16,20,21,24,25,24,28,31,32,24,35,38,39,42,43,46,47,52,53,56],"p",{},"An adapter hands Fougere a ",[17,18,19],"code",{},"Store"," — five gestures over a keyed collection (",[17,22,23],{},"get",", ",[17,26,27],{},"has",[17,29,30],{},"set",",\n",[17,33,34],{},"delete",[17,36,37],{},"all",") and its ",[17,40,41],{},"client"," — and ",[17,44,45],{},"storageOver"," derives every gesture of the\n",[48,49,51],"a",{"href":50},"#the-gestures","storage"," from them: pages, criteria and lifecycle stamps are written once, in core.\n",[17,54,55],{},"@fougere\u002Fadapter-memory"," is this, and little more:",[58,59,64],"pre",{"className":60,"code":61,"language":62,"meta":63,"style":63},"language-ts shiki shiki-themes material-theme-lighter fougere-pastel material-theme-palenight","import { Format, type Accepted } from '@fougere\u002Fschema';\nimport { Sources, storageOver, type Store, type Values, type Source } from '@fougere\u002Fcore';\n\nfunction mapStore(): Store {\n  const map = new Map\u003Cstring, Values>();\n\n  return {\n    client: map,\n    get: async (key) => map.get(key),\n    has: async (key) => map.has(key),\n    set: async (key, values) => { map.set(key, values); },\n    delete: async (key) => map.delete(key),\n    all: async () => [...map.values()],\n  };\n}\n\nfunction createMemorySource(): Source {\n  const stores = new Map\u003Cstring, Store>();\n  const storageFactory = storageOver((_entity, name) => {\n    const store = stores.get(name) ?? mapStore();\n    stores.set(name, store);\n\n    return store;\n  });\n\n  return { storageFactory, name: 'memory' };\n}\n\nconst MEMORY = Format.of('source\u002Fmemory').key('type', Format.tokens(['memory'])).needs('type').closed();\n\ndeclare module '@fougere\u002Fcore' {\n  interface FougereSources {\n    memory: Accepted\u003Ctypeof MEMORY>;\n  }\n}\n\nSources.register('memory', { format: MEMORY, open: () => createMemorySource() });\n","ts","",[17,65,66,112,161,168,188,226,231,239,253,294,326,373,405,439,445,451,456,470,498,528,561,583,588,598,608,613,638,643,648,737,742,759,770,789,795,800,805],{"__ignoreMap":63},[67,68,71,75,79,83,86,89,92,95,98,102,106,109],"span",{"class":69,"line":70},"line",1,[67,72,74],{"class":73},"sK6XW","import",[67,76,78],{"class":77},"s15xx"," {",[67,80,82],{"class":81},"sPEhv"," Format",[67,84,85],{"class":77},",",[67,87,88],{"class":73}," type",[67,90,91],{"class":81}," Accepted",[67,93,94],{"class":77}," }",[67,96,97],{"class":73}," from",[67,99,101],{"class":100},"sDDC1"," '",[67,103,105],{"class":104},"sN-8n","@fougere\u002Fschema",[67,107,108],{"class":100},"'",[67,110,111],{"class":77},";\n",[67,113,115,117,119,122,124,127,129,131,134,136,138,141,143,145,148,150,152,154,157,159],{"class":69,"line":114},2,[67,116,74],{"class":73},[67,118,78],{"class":77},[67,120,121],{"class":81}," Sources",[67,123,85],{"class":77},[67,125,126],{"class":81}," storageOver",[67,128,85],{"class":77},[67,130,88],{"class":73},[67,132,133],{"class":81}," Store",[67,135,85],{"class":77},[67,137,88],{"class":73},[67,139,140],{"class":81}," Values",[67,142,85],{"class":77},[67,144,88],{"class":73},[67,146,147],{"class":81}," Source",[67,149,94],{"class":77},[67,151,97],{"class":73},[67,153,101],{"class":100},[67,155,156],{"class":104},"@fougere\u002Fcore",[67,158,108],{"class":100},[67,160,111],{"class":77},[67,162,164],{"class":69,"line":163},3,[67,165,167],{"emptyLinePlaceholder":166},true,"\n",[67,169,171,175,179,182,185],{"class":69,"line":170},4,[67,172,174],{"class":173},"s76I7","function",[67,176,178],{"class":177},"s4mR9"," mapStore",[67,180,181],{"class":77},"():",[67,183,133],{"class":184},"sBZYL",[67,186,187],{"class":77}," {\n",[67,189,191,194,197,200,203,207,210,213,215,217,220,224],{"class":69,"line":190},5,[67,192,193],{"class":173},"  const",[67,195,196],{"class":81}," map",[67,198,199],{"class":77}," =",[67,201,202],{"class":77}," new",[67,204,206],{"class":205},"sgjsB"," Map",[67,208,209],{"class":77},"\u003C",[67,211,212],{"class":184},"string",[67,214,85],{"class":77},[67,216,140],{"class":184},[67,218,219],{"class":77},">",[67,221,223],{"class":222},"spAFX","()",[67,225,111],{"class":77},[67,227,229],{"class":69,"line":228},6,[67,230,167],{"emptyLinePlaceholder":166},[67,232,234,237],{"class":69,"line":233},7,[67,235,236],{"class":73},"  return",[67,238,187],{"class":77},[67,240,242,246,249,251],{"class":69,"line":241},8,[67,243,245],{"class":244},"sHtqg","    client",[67,247,248],{"class":77},":",[67,250,196],{"class":81},[67,252,31],{"class":77},[67,254,256,259,261,264,267,271,274,278,280,283,285,288,290,292],{"class":69,"line":255},9,[67,257,258],{"class":177},"    get",[67,260,248],{"class":77},[67,262,263],{"class":173}," async",[67,265,266],{"class":77}," (",[67,268,270],{"class":269},"shDUQ","key",[67,272,273],{"class":77},")",[67,275,277],{"class":276},"scTuO"," =>",[67,279,196],{"class":81},[67,281,282],{"class":77},".",[67,284,23],{"class":177},[67,286,287],{"class":222},"(",[67,289,270],{"class":81},[67,291,273],{"class":222},[67,293,31],{"class":77},[67,295,297,300,302,304,306,308,310,312,314,316,318,320,322,324],{"class":69,"line":296},10,[67,298,299],{"class":177},"    has",[67,301,248],{"class":77},[67,303,263],{"class":173},[67,305,266],{"class":77},[67,307,270],{"class":269},[67,309,273],{"class":77},[67,311,277],{"class":276},[67,313,196],{"class":81},[67,315,282],{"class":77},[67,317,27],{"class":177},[67,319,287],{"class":222},[67,321,270],{"class":81},[67,323,273],{"class":222},[67,325,31],{"class":77},[67,327,329,332,334,336,338,340,342,345,347,349,351,353,355,357,359,361,363,365,367,370],{"class":69,"line":328},11,[67,330,331],{"class":177},"    set",[67,333,248],{"class":77},[67,335,263],{"class":173},[67,337,266],{"class":77},[67,339,270],{"class":269},[67,341,85],{"class":77},[67,343,344],{"class":269}," values",[67,346,273],{"class":77},[67,348,277],{"class":276},[67,350,78],{"class":77},[67,352,196],{"class":81},[67,354,282],{"class":77},[67,356,30],{"class":177},[67,358,287],{"class":222},[67,360,270],{"class":81},[67,362,85],{"class":77},[67,364,344],{"class":81},[67,366,273],{"class":222},[67,368,369],{"class":77},";",[67,371,372],{"class":77}," },\n",[67,374,376,379,381,383,385,387,389,391,393,395,397,399,401,403],{"class":69,"line":375},12,[67,377,378],{"class":177},"    delete",[67,380,248],{"class":77},[67,382,263],{"class":173},[67,384,266],{"class":77},[67,386,270],{"class":269},[67,388,273],{"class":77},[67,390,277],{"class":276},[67,392,196],{"class":81},[67,394,282],{"class":77},[67,396,34],{"class":177},[67,398,287],{"class":222},[67,400,270],{"class":81},[67,402,273],{"class":222},[67,404,31],{"class":77},[67,406,408,411,413,415,418,420,423,426,429,431,434,437],{"class":69,"line":407},13,[67,409,410],{"class":177},"    all",[67,412,248],{"class":77},[67,414,263],{"class":173},[67,416,417],{"class":77}," ()",[67,419,277],{"class":276},[67,421,422],{"class":222}," [",[67,424,425],{"class":77},"...",[67,427,428],{"class":81},"map",[67,430,282],{"class":77},[67,432,433],{"class":177},"values",[67,435,436],{"class":222},"()]",[67,438,31],{"class":77},[67,440,442],{"class":69,"line":441},14,[67,443,444],{"class":77},"  };\n",[67,446,448],{"class":69,"line":447},15,[67,449,450],{"class":77},"}\n",[67,452,454],{"class":69,"line":453},16,[67,455,167],{"emptyLinePlaceholder":166},[67,457,459,461,464,466,468],{"class":69,"line":458},17,[67,460,174],{"class":173},[67,462,463],{"class":177}," createMemorySource",[67,465,181],{"class":77},[67,467,147],{"class":184},[67,469,187],{"class":77},[67,471,473,475,478,480,482,484,486,488,490,492,494,496],{"class":69,"line":472},18,[67,474,193],{"class":173},[67,476,477],{"class":81}," stores",[67,479,199],{"class":77},[67,481,202],{"class":77},[67,483,206],{"class":205},[67,485,209],{"class":77},[67,487,212],{"class":184},[67,489,85],{"class":77},[67,491,133],{"class":184},[67,493,219],{"class":77},[67,495,223],{"class":222},[67,497,111],{"class":77},[67,499,501,503,506,508,510,512,514,517,519,522,524,526],{"class":69,"line":500},19,[67,502,193],{"class":173},[67,504,505],{"class":81}," storageFactory",[67,507,199],{"class":77},[67,509,126],{"class":177},[67,511,287],{"class":222},[67,513,287],{"class":77},[67,515,516],{"class":269},"_entity",[67,518,85],{"class":77},[67,520,521],{"class":269}," name",[67,523,273],{"class":77},[67,525,277],{"class":276},[67,527,187],{"class":77},[67,529,531,534,537,539,541,543,545,547,550,552,555,557,559],{"class":69,"line":530},20,[67,532,533],{"class":173},"    const",[67,535,536],{"class":81}," store",[67,538,199],{"class":77},[67,540,477],{"class":81},[67,542,282],{"class":77},[67,544,23],{"class":177},[67,546,287],{"class":222},[67,548,549],{"class":81},"name",[67,551,273],{"class":222},[67,553,554],{"class":77}," ??",[67,556,178],{"class":177},[67,558,223],{"class":222},[67,560,111],{"class":77},[67,562,564,567,569,571,573,575,577,579,581],{"class":69,"line":563},21,[67,565,566],{"class":81},"    stores",[67,568,282],{"class":77},[67,570,30],{"class":177},[67,572,287],{"class":222},[67,574,549],{"class":81},[67,576,85],{"class":77},[67,578,536],{"class":81},[67,580,273],{"class":222},[67,582,111],{"class":77},[67,584,586],{"class":69,"line":585},22,[67,587,167],{"emptyLinePlaceholder":166},[67,589,591,594,596],{"class":69,"line":590},23,[67,592,593],{"class":73},"    return",[67,595,536],{"class":81},[67,597,111],{"class":77},[67,599,601,604,606],{"class":69,"line":600},24,[67,602,603],{"class":77},"  }",[67,605,273],{"class":222},[67,607,111],{"class":77},[67,609,611],{"class":69,"line":610},25,[67,612,167],{"emptyLinePlaceholder":166},[67,614,616,618,620,622,624,626,628,630,633,635],{"class":69,"line":615},26,[67,617,236],{"class":73},[67,619,78],{"class":77},[67,621,505],{"class":81},[67,623,85],{"class":77},[67,625,521],{"class":244},[67,627,248],{"class":77},[67,629,101],{"class":100},[67,631,632],{"class":104},"memory",[67,634,108],{"class":100},[67,636,637],{"class":77}," };\n",[67,639,641],{"class":69,"line":640},27,[67,642,450],{"class":77},[67,644,646],{"class":69,"line":645},28,[67,647,167],{"emptyLinePlaceholder":166},[67,649,651,654,657,660,662,664,667,670,672,675,677,679,681,683,685,687,690,692,694,696,698,701,704,706,708,710,713,715,718,720,722,724,726,728,730,733,735],{"class":69,"line":650},29,[67,652,653],{"class":173},"const",[67,655,656],{"class":81}," MEMORY ",[67,658,659],{"class":77},"=",[67,661,82],{"class":81},[67,663,282],{"class":77},[67,665,666],{"class":177},"of",[67,668,287],{"class":669},"srlTG",[67,671,108],{"class":100},[67,673,674],{"class":104},"source\u002Fmemory",[67,676,108],{"class":100},[67,678,273],{"class":669},[67,680,282],{"class":77},[67,682,270],{"class":177},[67,684,287],{"class":669},[67,686,108],{"class":100},[67,688,689],{"class":104},"type",[67,691,108],{"class":100},[67,693,85],{"class":77},[67,695,82],{"class":81},[67,697,282],{"class":77},[67,699,700],{"class":177},"tokens",[67,702,703],{"class":669},"([",[67,705,108],{"class":100},[67,707,632],{"class":104},[67,709,108],{"class":100},[67,711,712],{"class":669},"]))",[67,714,282],{"class":77},[67,716,717],{"class":177},"needs",[67,719,287],{"class":669},[67,721,108],{"class":100},[67,723,689],{"class":104},[67,725,108],{"class":100},[67,727,273],{"class":669},[67,729,282],{"class":77},[67,731,732],{"class":177},"closed",[67,734,223],{"class":669},[67,736,111],{"class":77},[67,738,740],{"class":69,"line":739},30,[67,741,167],{"emptyLinePlaceholder":166},[67,743,745,748,751,753,755,757],{"class":69,"line":744},31,[67,746,747],{"class":173},"declare",[67,749,750],{"class":173}," module",[67,752,101],{"class":100},[67,754,156],{"class":104},[67,756,108],{"class":100},[67,758,187],{"class":77},[67,760,762,765,768],{"class":69,"line":761},32,[67,763,764],{"class":173},"  interface",[67,766,767],{"class":184}," FougereSources",[67,769,187],{"class":77},[67,771,773,776,778,780,783,786],{"class":69,"line":772},33,[67,774,775],{"class":244},"    memory",[67,777,248],{"class":77},[67,779,91],{"class":184},[67,781,782],{"class":77},"\u003Ctypeof",[67,784,785],{"class":81}," MEMORY",[67,787,788],{"class":77},">;\n",[67,790,792],{"class":69,"line":791},34,[67,793,794],{"class":77},"  }\n",[67,796,798],{"class":69,"line":797},35,[67,799,450],{"class":77},[67,801,803],{"class":69,"line":802},36,[67,804,167],{"emptyLinePlaceholder":166},[67,806,808,811,813,816,818,820,822,824,826,828,831,833,835,837,840,842,844,846,848,850,852,854],{"class":69,"line":807},37,[67,809,810],{"class":81},"Sources",[67,812,282],{"class":77},[67,814,815],{"class":177},"register",[67,817,287],{"class":669},[67,819,108],{"class":100},[67,821,632],{"class":104},[67,823,108],{"class":100},[67,825,85],{"class":77},[67,827,78],{"class":77},[67,829,830],{"class":244}," format",[67,832,248],{"class":77},[67,834,785],{"class":81},[67,836,85],{"class":77},[67,838,839],{"class":177}," open",[67,841,248],{"class":77},[67,843,417],{"class":77},[67,845,277],{"class":276},[67,847,463],{"class":177},[67,849,223],{"class":669},[67,851,94],{"class":77},[67,853,273],{"class":669},[67,855,111],{"class":77},[13,857,858],{},"Three things make the type exist:",[860,861,862,874,889],"ul",{},[863,864,865,869,870,873],"li",{},[866,867,868],"strong",{},"the format"," says what an entry of this type may hold. The editor reads it as a type, through\n",[17,871,872],{},"FougereSources",", and the boot judges each entry by it — a misspelled key is refused in both;",[863,875,876,881,882,885,886,369],{},[866,877,878],{},[17,879,880],{},"Sources.register"," gives the type its name and its ",[17,883,884],{},"open",", called once per entry of\n",[17,887,888],{},"sources:",[863,890,891,896,897,900,901,904],{},[866,892,893],{},[17,894,895],{},"sideEffects"," in the package's ",[17,898,899],{},"package.json"," — ",[17,902,903],{},"[\".\u002Fdist\u002Findex.js\"]"," — keeps the import. An\napp imports the adapter only for its registration, and a bundler drops an import it believes\nunused. List the entry the app imports and the file that registers.",[13,906,907,908,910,911,914],{},"One ",[17,909,19],{}," per entity name, as here: two fronds declaring ",[17,912,913],{},"Author"," in this source then read the same\nrows, as they would one SQL table.",[13,916,917,920,921,924,925,928,929,932],{},[17,918,919],{},"all()"," reads everything, which is what bounds such a source: a ",[17,922,923],{},"list"," with a ",[17,926,927],{},"where"," or an\n",[17,930,931],{},"orderBy"," filters in memory. Right for rows kept for their durability, wrong on a hot read path.",[934,935,937],"h2",{"id":936},"what-a-source-states","What a source states",[13,939,940],{},"A source states five things, and only the first is required:",[942,943,944,955],"table",{},[945,946,947],"thead",{},[948,949,950,953],"tr",{},[951,952],"th",{},[951,954],{},[956,957,958,969,979,993,1003],"tbody",{},[948,959,960,966],{},[961,962,963],"td",{},[17,964,965],{},"storageFactory",[961,967,968],{},"build the storage of an entity that lives here",[948,970,971,976],{},[961,972,973],{},[17,974,975],{},"pending?",[961,977,978],{},"what the entities ask for and this source does not hold yet — read, never written; the boot refuses when it is not empty",[948,980,981,986],{},[961,982,983],{},[17,984,985],{},"migrate?",[961,987,988,989,992],{},"bring what lives here up to date — run by ",[17,990,991],{},"fougere migrate --apply",", never by a boot",[948,994,995,1000],{},[961,996,997],{},[17,998,999],{},"transacted?",[961,1001,1002],{},"run one unit of work",[948,1004,1005,1010],{},[961,1006,1007],{},[17,1008,1009],{},"close?",[961,1011,1012],{},"release",[13,1014,1015,1016,1019,1020,1024],{},"A source with no ",[17,1017,1018],{},"transacted"," is not a lesser one: a ",[48,1021,1023],{"href":1022},"\u002Fdocs\u002Fdata\u002Ftogether","frame"," over it\ncompensates instead of transacting, and the boot says which it built:",[58,1026,1031],{"className":1027,"code":1029,"language":1030},[1028],"language-text","Together\u003C[RateCard, Ledger], [RateMirror]> — compensated: rateCard in 'archive', ledger in 'main' — no isolation\nTogether\u003C[Account, Ledger]>                 — transaction, source 'main'\n","text",[17,1032,1029],{"__ignoreMap":63},[13,1034,1035,1036,282],{},"A source may also be an engine you built: any other Kysely dialect — libSQL, PGlite, Neon — is\nhanded in with ",[17,1037,1038],{},"createKyselySource(dialect, 'sqlite')",[934,1040,1042],{"id":1041},"the-gestures","The gestures",[942,1044,1045,1053],{},[945,1046,1047],{},[948,1048,1049,1051],{},[951,1050],{},[951,1052],{},[956,1054,1055,1090,1103,1117,1133,1151,1161,1171,1181,1191,1203,1224,1239],{},[948,1056,1057,1062],{},[961,1058,1059],{},[17,1060,1061],{},"list(options?)",[961,1063,1064,1065,24,1067,24,1069,24,1072,24,1075,24,1078,24,1081,24,1084,24,1087],{},"a page, with ",[17,1066,927],{},[17,1068,931],{},[17,1070,1071],{},"order",[17,1073,1074],{},"limit",[17,1076,1077],{},"offset",[17,1079,1080],{},"page",[17,1082,1083],{},"after",[17,1085,1086],{},"count",[17,1088,1089],{},"select",[948,1091,1092,1097],{},[961,1093,1094],{},[17,1095,1096],{},"findById(id)",[961,1098,1099,1100],{},"one row, or ",[17,1101,1102],{},"undefined",[948,1104,1105,1114],{},[961,1106,1107,1110,1111],{},[17,1108,1109],{},"findBy(criteria)"," \u002F ",[17,1112,1113],{},"findAllBy(criteria)",[961,1115,1116],{},"one row, or all of them, matching by equality",[948,1118,1119,1124],{},[961,1120,1121],{},[17,1122,1123],{},"findByKeys(ids)",[961,1125,1126,1127,1129,1130],{},"a ",[866,1128,30],{}," of rows by key, as a ",[17,1131,1132],{},"Map",[948,1134,1135,1140],{},[961,1136,1137],{},[17,1138,1139],{},"findAllByKeys(field, keys)",[961,1141,1142,1143,1147,1148,1150],{},"the other way: the rows pointing ",[1144,1145,1146],"em",{},"at"," each key, as a ",[17,1149,1132],{}," of lists",[948,1152,1153,1158],{},[961,1154,1155],{},[17,1156,1157],{},"create(input)",[961,1159,1160],{},"insert, and hand back the complete row",[948,1162,1163,1168],{},[961,1164,1165],{},[17,1166,1167],{},"createAll(inputs)",[961,1169,1170],{},"several rows in one statement, each handed back whole, in the order given; one conflict writes none",[948,1172,1173,1178],{},[961,1174,1175],{},[17,1176,1177],{},"upsert(input)",[961,1179,1180],{},"write the row, or make the existing one look like this",[948,1182,1183,1188],{},[961,1184,1185],{},[17,1186,1187],{},"upsertAll(inputs)",[961,1189,1190],{},"a whole page in one statement, answering how many were written",[948,1192,1193,1198],{},[961,1194,1195],{},[17,1196,1197],{},"updateByKeys(ids, change)",[961,1199,1126,1200,1202],{},[866,1201,30],{}," of rows changed from what they hold, all held at once, in key order",[948,1204,1205,1213],{},[961,1206,1207,1110,1210],{},[17,1208,1209],{},"update(id, input)",[17,1211,1212],{},"delete(id)",[961,1214,1215,1216,1219,1220,273],{},"by key — ",[17,1217,1218],{},"input"," may be a function of the row, read and written with no other write in between (",[48,1221,1223],{"href":1222},"\u002Fdocs\u002Fdata\u002Ftogether#a-value-computed-from-what-is-there","how",[948,1225,1226,1231],{},[961,1227,1228],{},[17,1229,1230],{},"output(view)",[961,1232,1233,1234,1238],{},"a scoped storage whose reads are restricted to a ",[48,1235,1237],{"href":1236},"\u002Fdocs\u002Fconcepts\u002Fentity","view","'s fields",[948,1240,1241,1245],{},[961,1242,1243],{},[17,1244,41],{},[961,1246,1247],{},"what the port wraps — see the warning below",[934,1249,1251],{"id":1250},"reading-a-set-not-a-row-at-a-time","Reading a set, not a row at a time",[13,1253,1254,1257,1258,1260,1261,1264],{},[17,1255,1256],{},"findAllBy"," compares with ",[17,1259,659],{},", so it takes no list of ids. Reading N rows by key is ",[17,1262,1263],{},"findByKeys",",\nin one query — not the whole table filtered afterwards, which goes unnoticed on a local file and\ncosts the whole table the day the rows are far away.",[58,1266,1268],{"className":60,"code":1267,"language":62,"meta":63,"style":63},"const authors = await authorStorage.findByKeys(posts.map((p) => p.authorId));\nreturn posts.map((post) => ({ ...post, author: authors.get(post.authorId) }));\n",[17,1269,1270,1322],{"__ignoreMap":63},[67,1271,1272,1274,1277,1279,1282,1285,1287,1289,1291,1294,1296,1298,1300,1302,1304,1306,1308,1311,1313,1317,1320],{"class":69,"line":70},[67,1273,653],{"class":173},[67,1275,1276],{"class":81}," authors ",[67,1278,659],{"class":77},[67,1280,1281],{"class":73}," await",[67,1283,1284],{"class":81}," authorStorage",[67,1286,282],{"class":77},[67,1288,1263],{"class":177},[67,1290,287],{"class":669},[67,1292,1293],{"class":81},"posts",[67,1295,282],{"class":77},[67,1297,428],{"class":177},[67,1299,287],{"class":669},[67,1301,287],{"class":77},[67,1303,13],{"class":269},[67,1305,273],{"class":77},[67,1307,277],{"class":276},[67,1309,1310],{"class":81}," p",[67,1312,282],{"class":77},[67,1314,1316],{"class":1315},"sy9f4","authorId",[67,1318,1319],{"class":669},"))",[67,1321,111],{"class":77},[67,1323,1324,1327,1330,1332,1334,1336,1338,1341,1343,1345,1347,1350,1353,1355,1357,1360,1362,1365,1367,1369,1371,1373,1375,1377,1379,1381,1383],{"class":69,"line":114},[67,1325,1326],{"class":73},"return",[67,1328,1329],{"class":81}," posts",[67,1331,282],{"class":77},[67,1333,428],{"class":177},[67,1335,287],{"class":669},[67,1337,287],{"class":77},[67,1339,1340],{"class":269},"post",[67,1342,273],{"class":77},[67,1344,277],{"class":276},[67,1346,266],{"class":669},[67,1348,1349],{"class":77},"{",[67,1351,1352],{"class":77}," ...",[67,1354,1340],{"class":81},[67,1356,85],{"class":77},[67,1358,1359],{"class":244}," author",[67,1361,248],{"class":77},[67,1363,1364],{"class":81}," authors",[67,1366,282],{"class":77},[67,1368,23],{"class":177},[67,1370,287],{"class":669},[67,1372,1340],{"class":81},[67,1374,282],{"class":77},[67,1376,1316],{"class":1315},[67,1378,273],{"class":669},[67,1380,94],{"class":77},[67,1382,1319],{"class":669},[67,1384,111],{"class":77},[13,1386,1387,1388,1390,1391,1394],{},"It answers a ",[866,1389,1132],{},", because the caller holds keys, not positions: a missing row is a missing\nkey, a repeated key is one entry, and a page matches each row with ",[17,1392,1393],{},"get(row.authorId)",". A list\nwould shift every later position the moment one row is missing.",[13,1396,1397,1400],{},[17,1398,1399],{},"findAllByKeys"," is the other direction of the same relation:",[58,1402,1404],{"className":60,"code":1403,"language":62,"meta":63,"style":63},"\u002F\u002F every comment of every post on this page, in one query\nconst byPost = await commentStorage.findAllByKeys('postId', posts.map((p) => p.id));\n",[17,1405,1406,1412],{"__ignoreMap":63},[67,1407,1408],{"class":69,"line":70},[67,1409,1411],{"class":1410},"skXKP","\u002F\u002F every comment of every post on this page, in one query\n",[67,1413,1414,1416,1419,1421,1423,1426,1428,1430,1432,1434,1437,1439,1441,1443,1445,1447,1449,1451,1453,1455,1457,1459,1461,1464,1466],{"class":69,"line":114},[67,1415,653],{"class":173},[67,1417,1418],{"class":81}," byPost ",[67,1420,659],{"class":77},[67,1422,1281],{"class":73},[67,1424,1425],{"class":81}," commentStorage",[67,1427,282],{"class":77},[67,1429,1399],{"class":177},[67,1431,287],{"class":669},[67,1433,108],{"class":100},[67,1435,1436],{"class":104},"postId",[67,1438,108],{"class":100},[67,1440,85],{"class":77},[67,1442,1329],{"class":81},[67,1444,282],{"class":77},[67,1446,428],{"class":177},[67,1448,287],{"class":669},[67,1450,287],{"class":77},[67,1452,13],{"class":269},[67,1454,273],{"class":77},[67,1456,277],{"class":276},[67,1458,1310],{"class":81},[67,1460,282],{"class":77},[67,1462,1463],{"class":1315},"id",[67,1465,1319],{"class":669},[67,1467,111],{"class":77},[13,1469,1470,1471,1475],{},"A key with no rows is simply absent. Together the two cover both sides of a relation, each\nin one query — which is what lets a ",[48,1472,1474],{"href":1473},"\u002Fdocs\u002Fdata\u002Fcomputed-field","presenter"," receive the page\nand issue one read for it.",[1477,1478,1479],"warning",{},[13,1480,1481,1482,1485],{},"The shape forces the query, not the body. ",[17,1483,1484],{},"Promise.all(rows.map(...))"," inside a computed\nfield still issues one read per row, and nothing says so.",[934,1487,1489],{"id":1488},"writing-a-page","Writing a page",[13,1491,1492,1495,1496,1499],{},[17,1493,1494],{},"create"," refuses a row whose key exists. ",[17,1497,1498],{},"upsert"," writes the row, or makes the existing one look\nlike this, in one statement:",[58,1501,1503],{"className":60,"code":1502,"language":62,"meta":63,"style":63},"await storage.upsert({ id: 'isbn-9782070423200', title: 'La Peste' });\n",[17,1504,1505],{"__ignoreMap":63},[67,1506,1507,1510,1513,1515,1517,1519,1521,1524,1526,1528,1531,1533,1535,1538,1540,1542,1545,1547,1549,1551],{"class":69,"line":70},[67,1508,1509],{"class":73},"await",[67,1511,1512],{"class":81}," storage",[67,1514,282],{"class":77},[67,1516,1498],{"class":177},[67,1518,287],{"class":669},[67,1520,1349],{"class":77},[67,1522,1523],{"class":244}," id",[67,1525,248],{"class":77},[67,1527,101],{"class":100},[67,1529,1530],{"class":104},"isbn-9782070423200",[67,1532,108],{"class":100},[67,1534,85],{"class":77},[67,1536,1537],{"class":244}," title",[67,1539,248],{"class":77},[67,1541,101],{"class":100},[67,1543,1544],{"class":104},"La Peste",[67,1546,108],{"class":100},[67,1548,94],{"class":77},[67,1550,273],{"class":669},[67,1552,111],{"class":77},[13,1554,1555],{},"The key and the creation stamps survive an overwrite — a row keeps the moment it appeared.\nAn engine with no upsert clause refuses by name rather than emulating one with a read in\nfront, which would promise an atomicity it has not got.",[13,1557,1558,1561,1562,1565,1566,1572],{},[17,1559,1560],{},"upsertAll"," takes a page and answers ",[866,1563,1564],{},"how many rows were written",", not the rows: an import does\nnothing with them. It is what ",[48,1567,1569],{"href":1568},"\u002Fdocs\u002Fdata\u002Fmirror",[17,1570,1571],{},"Mirror"," writes through.",[934,1574,1576],{"id":1575},"every-write-through-the-port-is-validated","Every write through the port is validated",[13,1578,1579,1580,1583,1584,1587],{},"A handler writes without the client's checks, since it is the author, but not around the entity: a\nvalue the entity forbids is refused here as it is at the door. Lifecycle rules are realized on\nthe way in — ",[17,1581,1582],{},"created()"," is stamped, ",[17,1585,1586],{},"update: 'forbidden'"," is enforced — so a handler never\nfills those by hand.",[934,1589,1591,1593],{"id":1590},"client-and-what-it-costs",[17,1592,41],{}," — and what it costs",[13,1595,1596,1598,1599,1602],{},[17,1597,41],{}," is the underlying instance: the Kysely one for the SQL adapter, something else\nelsewhere. It is typed ",[17,1600,1601],{},"unknown",": narrowing it is you saying which engine you rely on.",[1477,1604,1605],{},[13,1606,1607,1610,1611,1613,1614,1617],{},[866,1608,1609],{},"Every validator sits on the port's own methods."," A statement issued through ",[17,1612,41],{}," meets\nnone of them: a value the entity refuses lands in the table without a word. Nor is it scoped:\n",[17,1615,1616],{},"productStorage.client"," is the Kysely instance of the whole database, not of the products.",[13,1619,1620,1621,1626],{},"For \"debit A and credit B, or neither\", use ",[48,1622,1623],{"href":1022},[17,1624,1625],{},"Together",": the same checks,\nwith a block as its unit instead of a statement.",[1628,1629,1630],"style",{},"html pre.shiki code .sK6XW, html code.shiki .sK6XW{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#8FCF86;--shiki-default-font-style:inherit;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s15xx, html code.shiki .s15xx{--shiki-light:#39ADB5;--shiki-default:#A3B0A5;--shiki-dark:#89DDFF}html pre.shiki code .sPEhv, html code.shiki .sPEhv{--shiki-light:#90A4AE;--shiki-default:#DDE5DA;--shiki-dark:#BABED8}html pre.shiki code .sDDC1, html code.shiki .sDDC1{--shiki-light:#39ADB5;--shiki-default:#EE9F6B;--shiki-dark:#89DDFF}html pre.shiki code .sN-8n, html code.shiki .sN-8n{--shiki-light:#91B859;--shiki-default:#EE9F6B;--shiki-dark:#C3E88D}html pre.shiki code .s76I7, html code.shiki .s76I7{--shiki-light:#9C3EDA;--shiki-default:#8FCF86;--shiki-dark:#C792EA}html pre.shiki code .s4mR9, html code.shiki .s4mR9{--shiki-light:#6182B8;--shiki-default:#C9B6EA;--shiki-dark:#82AAFF}html pre.shiki code .sBZYL, html code.shiki .sBZYL{--shiki-light:#E2931D;--shiki-default:#EFCD8F;--shiki-dark:#FFCB6B}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 .sHtqg, html code.shiki .sHtqg{--shiki-light:#E53935;--shiki-default:#93CFC0;--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 .scTuO, html code.shiki .scTuO{--shiki-light:#9C3EDA;--shiki-default:#A3B0A5;--shiki-dark:#C792EA}html pre.shiki code .srlTG, html code.shiki .srlTG{--shiki-light:#90A4AE;--shiki-default:#A3B0A5;--shiki-dark:#BABED8}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 .sy9f4, html code.shiki .sy9f4{--shiki-light:#90A4AE;--shiki-default:#93CFC0;--shiki-dark:#BABED8}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}",{"title":63,"searchDepth":114,"depth":114,"links":1632},[1633,1634,1635,1636,1637,1638],{"id":936,"depth":114,"text":937},{"id":1041,"depth":114,"text":1042},{"id":1250,"depth":114,"text":1251},{"id":1488,"depth":114,"text":1489},{"id":1575,"depth":114,"text":1576},{"id":1590,"depth":114,"text":1639},"client — and what it costs","Five gestures of a store, and the storage derived from them.","md",null,"extending",{},"\u002Fdocs\u002Fextending\u002Fsource-adapter",{"title":8,"description":1640},"docs\u002F8.extending\u002F7.source-adapter","a4jVd8BKpm3gn3UYO-rblUi2WARBTcxGJnMLJNf4Vsc",[1650,1652,1655,1658,1661,1664,1667,1670,1673,1679,1685,1690,1694,1697,1701,1705,1709,1713,1716,1720,1725,1729,1734,1738,1742,1746,1750,1754,1758,1762,1766,1770,1774,1778,1782,1786,1790,1793,1796,1799,1802,1805,1808,1811,1812,1815,1818],{"path":1236,"title":1651,"uses":1642},"Entity",{"path":1653,"title":1654,"uses":1642},"\u002Fdocs\u002Fconcepts\u002Fhandler","Handler",{"path":1656,"title":1657,"uses":1642},"\u002Fdocs\u002Fconcepts\u002Frepository","Repository",{"path":1659,"title":1660,"uses":1642},"\u002Fdocs\u002Fconcepts\u002Ffrond","Frond",{"path":1662,"title":1663,"uses":1642},"\u002Fdocs\u002Fconcepts\u002Ffacade","Facade",{"path":1665,"title":1666,"uses":1642},"\u002Fdocs\u002Fconcepts\u002Ffact","Fact",{"path":1668,"title":1669,"uses":1642},"\u002Fdocs\u002Fconcepts\u002Fport","Port",{"path":1671,"title":1672,"uses":1642},"\u002Fdocs\u002Fconcepts\u002Fconfiguration","Configuration",{"path":1674,"title":1675,"uses":1676},"\u002Fdocs\u002Faccess\u002Fauthentication","Authentication",[1677,1678],"port","frond",{"path":1680,"title":1681,"uses":1682},"\u002Fdocs\u002Faccess\u002Fstate","Keep a caller's state",[1683,1684],"configuration","handler",{"path":1686,"title":1687,"uses":1688},"\u002Fdocs\u002Fdata\u002Fsql","SQLite or Postgres",[1689,1683],"entity",{"path":1691,"title":1692,"uses":1693},"\u002Fdocs\u002Fdata\u002Fseveral-databases","Several databases",[1683,1689],{"path":1473,"title":1695,"uses":1696},"A computed field",[1689,1677],{"path":1698,"title":1699,"uses":1700},"\u002Fdocs\u002Fdata\u002Fevolve","Evolve a schema",[1689],{"path":1702,"title":1703,"uses":1704},"\u002Fdocs\u002Fdata\u002Fseeds","Seed data",[1689],{"path":1706,"title":1707,"uses":1708},"\u002Fdocs\u002Fdata\u002Fvalues","Read settings and secrets",[1689,1683],{"path":1568,"title":1710,"uses":1711},"Mirror a source you cannot query",[1712],"repository",{"path":1022,"title":1714,"uses":1715},"Two writes as one",[1712],{"path":1717,"title":1718,"uses":1719},"\u002Fdocs\u002Fbehaviour\u002Faround-every-call","Around every call",[1677,1678],{"path":1721,"title":1722,"uses":1723},"\u002Fdocs\u002Fbehaviour\u002Ffinish-a-fact","Finish a fact",[1724],"fact",{"path":1726,"title":1727,"uses":1728},"\u002Fdocs\u002Fserve\u002Frest-graphql","REST, OpenAPI, GraphQL",[1684,1683],{"path":1730,"title":1731,"uses":1732},"\u002Fdocs\u002Fserve\u002Fpages","Pages: queries and commands",[1684,1733],"facade",{"path":1735,"title":1736,"uses":1737},"\u002Fdocs\u002Fserve\u002Fforms","A form",[1689],{"path":1739,"title":1740,"uses":1741},"\u002Fdocs\u002Fserve\u002Fadmin","An admin panel",[1684],{"path":1743,"title":1744,"uses":1745},"\u002Fdocs\u002Frun\u002Fdeploy","Deploy a split",[1683,1678],{"path":1747,"title":1748,"uses":1749},"\u002Fdocs\u002Frun\u002Fsecure","Secure calls between processes",[1683,1678],{"path":1751,"title":1752,"uses":1753},"\u002Fdocs\u002Frun\u002Flifecycle","Reload and shut down",[1683],{"path":1755,"title":1756,"uses":1757},"\u002Fdocs\u002Frun\u002Fobserve","Observe",[1683,1684],{"path":1759,"title":1760,"uses":1761},"\u002Fdocs\u002Frun\u002Fdev-panel","The dev panel",[1684],{"path":1763,"title":1764,"uses":1765},"\u002Fdocs\u002Frun\u002Ftest","Test",[1689,1677],{"path":1767,"title":1768,"uses":1769},"\u002Fdocs\u002Fadopt\u002Fnew-project","Start a project",[1678,1683],{"path":1771,"title":1772,"uses":1773},"\u002Fdocs\u002Fadopt\u002Fexisting-app","Add Fougere to an existing app",[1678,1683],{"path":1775,"title":1776,"uses":1777},"\u002Fdocs\u002Fadopt\u002Fbring-your-schema","Bring your schema",[1689],{"path":1779,"title":1780,"uses":1781},"\u002Fdocs\u002Fadopt\u002Fhosts","Pick a host",[1683],{"path":1783,"title":1784,"uses":1785},"\u002Fdocs\u002Fadopt\u002Fanother-repository","A frond from another repository",[1733,1678],{"path":1787,"title":1788,"uses":1789},"\u002Fdocs\u002Fadopt\u002Fdemos","Demos",[],{"path":1791,"title":1792,"uses":1642},"\u002Fdocs\u002Fextending\u002Fscan","How the scan reads a project",{"path":1794,"title":1795,"uses":1642},"\u002Fdocs\u002Fextending\u002Fwithout-compiler","Boot without the compiler",{"path":1797,"title":1798,"uses":1642},"\u002Fdocs\u002Fextending\u002Fboot","The boot, step by step",{"path":1800,"title":1801,"uses":1642},"\u002Fdocs\u002Fextending\u002Fcard-and-wire","The card and the wire",{"path":1803,"title":1804,"uses":1642},"\u002Fdocs\u002Fextending\u002Fextension-points","Registries and extension points",{"path":1806,"title":1807,"uses":1642},"\u002Fdocs\u002Fextending\u002Fvocabulary","Teach a word",{"path":1809,"title":1810,"uses":1642},"\u002Fdocs\u002Fextending\u002Fextensions","Run code at boot and shutdown",{"path":1645,"title":8,"uses":1642},{"path":1813,"title":1814,"uses":1642},"\u002Fdocs\u002Fextending\u002Fsurface","Write a surface",{"path":1816,"title":1817,"uses":1642},"\u002Fdocs\u002Fextending\u002Fforeign-frond","A frond in another language",{"path":1819,"title":1820,"uses":1642},"\u002Fdocs","What is Fougere",[1822],{"title":1823,"path":1819,"stem":1824,"children":1825,"page":-1},"Docs","docs",[1826,1828,1849,1858,1879,1888,1901,1918,1935],{"title":1820,"path":1819,"stem":1827},"docs\u002Findex",{"title":1829,"path":1830,"stem":1831,"children":1832,"page":5},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F1.concepts",[1833,1835,1837,1839,1841,1843,1845,1847],{"title":1651,"path":1236,"stem":1834},"docs\u002F1.concepts\u002F1.entity",{"title":1654,"path":1653,"stem":1836},"docs\u002F1.concepts\u002F2.handler",{"title":1657,"path":1656,"stem":1838},"docs\u002F1.concepts\u002F3.repository",{"title":1660,"path":1659,"stem":1840},"docs\u002F1.concepts\u002F4.frond",{"title":1663,"path":1662,"stem":1842},"docs\u002F1.concepts\u002F5.facade",{"title":1666,"path":1665,"stem":1844},"docs\u002F1.concepts\u002F6.fact",{"title":1669,"path":1668,"stem":1846},"docs\u002F1.concepts\u002F7.port",{"title":1672,"path":1671,"stem":1848},"docs\u002F1.concepts\u002F8.configuration",{"title":1850,"path":1851,"stem":1852,"children":1853,"page":5},"Access","\u002Fdocs\u002Faccess","docs\u002F2.access",[1854,1856],{"title":1675,"path":1674,"stem":1855},"docs\u002F2.access\u002F1.authentication",{"title":1681,"path":1680,"stem":1857},"docs\u002F2.access\u002F2.state",{"title":1859,"path":1860,"stem":1861,"children":1862,"page":5},"Data","\u002Fdocs\u002Fdata","docs\u002F3.data",[1863,1865,1867,1869,1871,1873,1875,1877],{"title":1687,"path":1686,"stem":1864},"docs\u002F3.data\u002F1.sql",{"title":1692,"path":1691,"stem":1866},"docs\u002F3.data\u002F2.several-databases",{"title":1695,"path":1473,"stem":1868},"docs\u002F3.data\u002F3.computed-field",{"title":1699,"path":1698,"stem":1870},"docs\u002F3.data\u002F4.evolve",{"title":1703,"path":1702,"stem":1872},"docs\u002F3.data\u002F5.seeds",{"title":1707,"path":1706,"stem":1874},"docs\u002F3.data\u002F6.values",{"title":1710,"path":1568,"stem":1876},"docs\u002F3.data\u002F7.mirror",{"title":1714,"path":1022,"stem":1878},"docs\u002F3.data\u002F8.together",{"title":1880,"path":1881,"stem":1882,"children":1883,"page":5},"Behaviour","\u002Fdocs\u002Fbehaviour","docs\u002F4.behaviour",[1884,1886],{"title":1718,"path":1717,"stem":1885},"docs\u002F4.behaviour\u002F1.around-every-call",{"title":1722,"path":1721,"stem":1887},"docs\u002F4.behaviour\u002F2.finish-a-fact",{"title":1889,"path":1890,"stem":1891,"children":1892,"page":5},"Serve","\u002Fdocs\u002Fserve","docs\u002F5.serve",[1893,1895,1897,1899],{"title":1727,"path":1726,"stem":1894},"docs\u002F5.serve\u002F1.rest-graphql",{"title":1731,"path":1730,"stem":1896},"docs\u002F5.serve\u002F2.pages",{"title":1736,"path":1735,"stem":1898},"docs\u002F5.serve\u002F3.forms",{"title":1740,"path":1739,"stem":1900},"docs\u002F5.serve\u002F4.admin",{"title":1902,"path":1903,"stem":1904,"children":1905,"page":5},"Run","\u002Fdocs\u002Frun","docs\u002F6.run",[1906,1908,1910,1912,1914,1916],{"title":1744,"path":1743,"stem":1907},"docs\u002F6.run\u002F1.deploy",{"title":1748,"path":1747,"stem":1909},"docs\u002F6.run\u002F2.secure",{"title":1752,"path":1751,"stem":1911},"docs\u002F6.run\u002F3.lifecycle",{"title":1756,"path":1755,"stem":1913},"docs\u002F6.run\u002F4.observe",{"title":1760,"path":1759,"stem":1915},"docs\u002F6.run\u002F5.dev-panel",{"title":1764,"path":1763,"stem":1917},"docs\u002F6.run\u002F6.test",{"title":1919,"path":1920,"stem":1921,"children":1922,"page":5},"Adopt","\u002Fdocs\u002Fadopt","docs\u002F7.adopt",[1923,1925,1927,1929,1931,1933],{"title":1768,"path":1767,"stem":1924},"docs\u002F7.adopt\u002F1.new-project",{"title":1772,"path":1771,"stem":1926},"docs\u002F7.adopt\u002F2.existing-app",{"title":1776,"path":1775,"stem":1928},"docs\u002F7.adopt\u002F3.bring-your-schema",{"title":1780,"path":1779,"stem":1930},"docs\u002F7.adopt\u002F4.hosts",{"title":1784,"path":1783,"stem":1932},"docs\u002F7.adopt\u002F5.another-repository",{"title":1788,"path":1787,"stem":1934},"docs\u002F7.adopt\u002F6.demos",{"title":1936,"path":1937,"stem":1938,"children":1939,"page":5},"Extending","\u002Fdocs\u002Fextending","docs\u002F8.extending",[1940,1942,1944,1946,1948,1950,1952,1954,1955,1957],{"title":1792,"path":1791,"stem":1941},"docs\u002F8.extending\u002F1.scan",{"title":1795,"path":1794,"stem":1943},"docs\u002F8.extending\u002F10.without-compiler",{"title":1798,"path":1797,"stem":1945},"docs\u002F8.extending\u002F2.boot",{"title":1801,"path":1800,"stem":1947},"docs\u002F8.extending\u002F3.card-and-wire",{"title":1804,"path":1803,"stem":1949},"docs\u002F8.extending\u002F4.extension-points",{"title":1807,"path":1806,"stem":1951},"docs\u002F8.extending\u002F5.vocabulary",{"title":1810,"path":1809,"stem":1953},"docs\u002F8.extending\u002F6.extensions",{"title":8,"path":1645,"stem":1647},{"title":1814,"path":1813,"stem":1956},"docs\u002F8.extending\u002F8.surface",{"title":1817,"path":1816,"stem":1958},"docs\u002F8.extending\u002F9.foreign-frond",1794396615353]