[{"data":1,"prerenderedAt":865},["ShallowReactive",2],{"docs:navigation":3,"docs:page:\u002Fdocs\u002Fconfiguration":115},[4],{"title":5,"path":6,"stem":7,"children":8,"icon":10},"Introduction","\u002Fdocs","docs\u002F1.index",[9,11,16,21,38,95,110],{"title":5,"path":6,"stem":7,"icon":10},"i-lucide-house",{"title":12,"path":13,"stem":14,"icon":15},"Quickstart","\u002Fdocs\u002Fquickstart","docs\u002F2.quickstart","i-lucide-rocket",{"title":17,"path":18,"stem":19,"icon":20},"Essentials","\u002Fdocs\u002Fconfiguration","docs\u002F3.configuration","i-lucide-book-open",{"title":22,"path":23,"stem":24,"children":25,"icon":27},"Authentication","\u002Fdocs\u002Fauthentication","docs\u002F4.authentication\u002Findex",[26,28,33],{"title":22,"path":23,"stem":24,"icon":27},"i-lucide-shield-check",{"title":29,"path":30,"stem":31,"icon":32},"Protect User Data","\u002Fdocs\u002Fauthentication\u002Fuser-data","docs\u002F4.authentication\u002F1.user-data","i-lucide-user-lock",{"title":34,"path":35,"stem":36,"icon":37},"Two-Factor Verification","\u002Fdocs\u002Fauthentication\u002Ftwo-factor","docs\u002F4.authentication\u002F2.two-factor","i-lucide-key-round",{"title":39,"path":40,"stem":41,"children":42,"icon":44},"Deployment","\u002Fdocs\u002Fdeployment","docs\u002F5.deployment\u002Findex",[43,45,50,55,60,65,70,75,80,85,90],{"title":39,"path":40,"stem":41,"icon":44},"i-lucide-cloud-upload",{"title":46,"path":47,"stem":48,"icon":49},"Deploy to Cloudflare","\u002Fdocs\u002Fdeployment\u002Fcloudflare","docs\u002F5.deployment\u002F1.cloudflare","i-simple-icons-cloudflare",{"title":51,"path":52,"stem":53,"icon":54},"Platform Support","\u002Fdocs\u002Fdeployment\u002Fsupport","docs\u002F5.deployment\u002F10.support","i-lucide-list-checks",{"title":56,"path":57,"stem":58,"icon":59},"Deploy to Vercel","\u002Fdocs\u002Fdeployment\u002Fvercel","docs\u002F5.deployment\u002F2.vercel","i-simple-icons-vercel",{"title":61,"path":62,"stem":63,"icon":64},"Deploy to Azure","\u002Fdocs\u002Fdeployment\u002Fazure","docs\u002F5.deployment\u002F3.azure","i-simple-icons-microsoftazure",{"title":66,"path":67,"stem":68,"icon":69},"Switch Hosts","\u002Fdocs\u002Fdeployment\u002Fswitch-hosts","docs\u002F5.deployment\u002F4.switch-hosts","i-lucide-arrow-right-left",{"title":71,"path":72,"stem":73,"icon":74},"Database and File Storage","\u002Fdocs\u002Fdeployment\u002Fdata-services","docs\u002F5.deployment\u002F5.data-services","i-lucide-database",{"title":76,"path":77,"stem":78,"icon":79},"Domains and Secrets","\u002Fdocs\u002Fdeployment\u002Fsettings","docs\u002F5.deployment\u002F6.settings","i-lucide-settings",{"title":81,"path":82,"stem":83,"icon":84},"Troubleshoot Deployment","\u002Fdocs\u002Fdeployment\u002Ftroubleshooting","docs\u002F5.deployment\u002F7.troubleshooting","i-lucide-wrench",{"title":86,"path":87,"stem":88,"icon":89},"Deploy Agents","\u002Fdocs\u002Fdeployment\u002Fagents","docs\u002F5.deployment\u002F8.agents","i-lucide-bot",{"title":91,"path":92,"stem":93,"icon":94},"Deploy Automations","\u002Fdocs\u002Fdeployment\u002Fautomations","docs\u002F5.deployment\u002F9.automations","i-lucide-workflow",{"title":96,"path":97,"stem":98,"children":99,"icon":101},"Connect Accounts","\u002Fdocs\u002Fconnect","docs\u002F6.connect\u002Findex",[100,102,106],{"title":96,"path":97,"stem":98,"icon":101},"i-lucide-plug",{"title":103,"path":104,"stem":105,"icon":37},"Connection Credentials","\u002Fdocs\u002Fconnect\u002Fcredentials","docs\u002F6.connect\u002F1.credentials",{"title":107,"path":108,"stem":109,"icon":84},"Connect MCP Servers","\u002Fdocs\u002Fconnect\u002Fmcp","docs\u002F6.connect\u002F2.mcp",{"title":111,"path":112,"stem":113,"icon":114},"Project Reference","\u002Fdocs\u002Freference","docs\u002F7.reference","i-lucide-terminal",{"page":116,"surround":860},{"id":117,"title":17,"body":118,"description":853,"extension":854,"links":855,"meta":856,"navigation":857,"path":18,"seo":858,"stem":19,"__hash__":859},"docs\u002Fdocs\u002F3.configuration.md",{"type":119,"value":120,"toc":847},"minimark",[121,129,132,137,140,229,244,247,338,341,363,366,391,394,416,420,423,603,615,618,622,625,739,745,789,792,819,823,830,836,843],[122,123,124,125,128],"p",{},"The ",[126,127,12],"a",{"href":13}," gave you a running blog API. This guide builds\non that project: first define a post, then decide which posts visitors can see,\nand finally read them from your application.",[122,130,131],{},"The snippets below belong inside the generated config unless an import is shown.",[133,134,136],"h2",{"id":135},"describe-the-data-your-app-stores","Describe the Data Your App Stores",[122,138,139],{},"A model gives a resource a name and a set of fields:",[141,142,148],"pre",{"className":143,"code":144,"filename":145,"language":146,"meta":147,"style":147},"language-ts shiki shiki-themes github-light github-light github-dark","post: model({\n  title: t.text().required(),\n  body: t.textarea(),\n  published: t.boolean().default(false),\n})\n","cloud.config.ts","ts","",[149,150,151,170,188,199,223],"code",{"__ignoreMap":147},[152,153,156,160,164,167],"span",{"class":154,"line":155},"line",1,[152,157,159],{"class":158},"snPdu","post",[152,161,163],{"class":162},"sxrX7",": ",[152,165,166],{"class":158},"model",[152,168,169],{"class":162},"({\n",[152,171,173,176,179,182,185],{"class":154,"line":172},2,[152,174,175],{"class":162},"  title: t.",[152,177,178],{"class":158},"text",[152,180,181],{"class":162},"().",[152,183,184],{"class":158},"required",[152,186,187],{"class":162},"(),\n",[152,189,191,194,197],{"class":154,"line":190},3,[152,192,193],{"class":162},"  body: t.",[152,195,196],{"class":158},"textarea",[152,198,187],{"class":162},[152,200,202,205,208,210,213,216,220],{"class":154,"line":201},4,[152,203,204],{"class":162},"  published: t.",[152,206,207],{"class":158},"boolean",[152,209,181],{"class":162},[152,211,212],{"class":158},"default",[152,214,215],{"class":162},"(",[152,217,219],{"class":218},"sBjJW","false",[152,221,222],{"class":162},"),\n",[152,224,226],{"class":154,"line":225},5,[152,227,228],{"class":162},"})\n",[122,230,231,232,235,236,239,240,243],{},"This creates the ",[149,233,234],{},"posts"," table and the ",[149,237,238],{},"\u002Fapi\u002Fposts"," REST resource. CloudConfig\nalso adds an ",[149,241,242],{},"id"," and timestamps.",[122,245,246],{},"Use field builders to describe the values your application accepts:",[141,248,250],{"className":143,"code":249,"language":146,"meta":147,"style":147},"title: t.text().required()\nbody: t.textarea()\npublished: t.boolean().default(false)\npublishedAt: t.date()\ncategory: t.select(['news', 'guide'])\n",[149,251,252,269,280,300,312],{"__ignoreMap":147},[152,253,254,257,260,262,264,266],{"class":154,"line":155},[152,255,256],{"class":158},"title",[152,258,259],{"class":162},": t.",[152,261,178],{"class":158},[152,263,181],{"class":162},[152,265,184],{"class":158},[152,267,268],{"class":162},"()\n",[152,270,271,274,276,278],{"class":154,"line":172},[152,272,273],{"class":158},"body",[152,275,259],{"class":162},[152,277,196],{"class":158},[152,279,268],{"class":162},[152,281,282,285,287,289,291,293,295,297],{"class":154,"line":190},[152,283,284],{"class":158},"published",[152,286,259],{"class":162},[152,288,207],{"class":158},[152,290,181],{"class":162},[152,292,212],{"class":158},[152,294,215],{"class":162},[152,296,219],{"class":218},[152,298,299],{"class":162},")\n",[152,301,302,305,307,310],{"class":154,"line":201},[152,303,304],{"class":158},"publishedAt",[152,306,259],{"class":162},[152,308,309],{"class":158},"date",[152,311,268],{"class":162},[152,313,314,317,319,322,325,329,332,335],{"class":154,"line":225},[152,315,316],{"class":158},"category",[152,318,259],{"class":162},[152,320,321],{"class":158},"select",[152,323,324],{"class":162},"([",[152,326,328],{"class":327},"sIIMD","'news'",[152,330,331],{"class":162},", ",[152,333,334],{"class":327},"'guide'",[152,336,337],{"class":162},"])\n",[122,339,340],{},"Add a relation when one resource belongs to another:",[141,342,344],{"className":143,"code":343,"language":146,"meta":147,"style":147},"author: t.relation('user')\n",[149,345,346],{"__ignoreMap":147},[152,347,348,351,353,356,358,361],{"class":154,"line":155},[152,349,350],{"class":158},"author",[152,352,259],{"class":162},[152,354,355],{"class":158},"relation",[152,357,215],{"class":162},[152,359,360],{"class":327},"'user'",[152,362,299],{"class":162},[122,364,365],{},"Add an index to a relation your lists filter on:",[141,367,369],{"className":143,"code":368,"language":146,"meta":147,"style":147},"author: t.relation('user').index()\n",[149,370,371],{"__ignoreMap":147},[152,372,373,375,377,379,381,383,386,389],{"class":154,"line":155},[152,374,350],{"class":158},[152,376,259],{"class":162},[152,378,355],{"class":158},[152,380,215],{"class":162},[152,382,360],{"class":327},[152,384,385],{"class":162},").",[152,387,388],{"class":158},"index",[152,390,268],{"class":162},[122,392,393],{},"After changing fields, relations, or indexes, update the database:",[141,395,399],{"className":396,"code":397,"language":398,"meta":147,"style":147},"language-bash shiki shiki-themes github-light github-light github-dark","pnpm db:generate\npnpm db:migrate\n","bash",[149,400,401,409],{"__ignoreMap":147},[152,402,403,406],{"class":154,"line":155},[152,404,405],{"class":158},"pnpm",[152,407,408],{"class":327}," db:generate\n",[152,410,411,413],{"class":154,"line":172},[152,412,405],{"class":158},[152,414,415],{"class":327}," db:migrate\n",[133,417,419],{"id":418},"decide-who-can-read-and-change-data","Decide Who Can Read and Change Data",[122,421,422],{},"CloudConfig denies an operation unless an access rule allows it. Keeping the\nrule beside the model makes the policy visible where the data is defined:",[141,424,426],{"className":143,"code":425,"language":146,"meta":147,"style":147},"post: model(\n  {\n    title: t.text().required(),\n    published: t.boolean().default(false),\n  },\n  {\n    access: {\n      list: ({ where }) => where('published', 'eq', true),\n      read: ({ where }) => where('published', 'eq', true),\n      create: ({ user }) => user != null,\n    },\n  },\n)\n",[149,427,428,439,444,457,474,479,484,490,530,560,587,593,598],{"__ignoreMap":147},[152,429,430,432,434,436],{"class":154,"line":155},[152,431,159],{"class":158},[152,433,163],{"class":162},[152,435,166],{"class":158},[152,437,438],{"class":162},"(\n",[152,440,441],{"class":154,"line":172},[152,442,443],{"class":162},"  {\n",[152,445,446,449,451,453,455],{"class":154,"line":190},[152,447,448],{"class":162},"    title: t.",[152,450,178],{"class":158},[152,452,181],{"class":162},[152,454,184],{"class":158},[152,456,187],{"class":162},[152,458,459,462,464,466,468,470,472],{"class":154,"line":201},[152,460,461],{"class":162},"    published: t.",[152,463,207],{"class":158},[152,465,181],{"class":162},[152,467,212],{"class":158},[152,469,215],{"class":162},[152,471,219],{"class":218},[152,473,222],{"class":162},[152,475,476],{"class":154,"line":225},[152,477,478],{"class":162},"  },\n",[152,480,482],{"class":154,"line":481},6,[152,483,443],{"class":162},[152,485,487],{"class":154,"line":486},7,[152,488,489],{"class":162},"    access: {\n",[152,491,493,496,499,503,506,510,513,515,518,520,523,525,528],{"class":154,"line":492},8,[152,494,495],{"class":158},"      list",[152,497,498],{"class":162},": ({ ",[152,500,502],{"class":501},"sP4rz","where",[152,504,505],{"class":162}," }) ",[152,507,509],{"class":508},"s8jYJ","=>",[152,511,512],{"class":158}," where",[152,514,215],{"class":162},[152,516,517],{"class":327},"'published'",[152,519,331],{"class":162},[152,521,522],{"class":327},"'eq'",[152,524,331],{"class":162},[152,526,527],{"class":218},"true",[152,529,222],{"class":162},[152,531,533,536,538,540,542,544,546,548,550,552,554,556,558],{"class":154,"line":532},9,[152,534,535],{"class":158},"      read",[152,537,498],{"class":162},[152,539,502],{"class":501},[152,541,505],{"class":162},[152,543,509],{"class":508},[152,545,512],{"class":158},[152,547,215],{"class":162},[152,549,517],{"class":327},[152,551,331],{"class":162},[152,553,522],{"class":327},[152,555,331],{"class":162},[152,557,527],{"class":218},[152,559,222],{"class":162},[152,561,563,566,568,571,573,575,578,581,584],{"class":154,"line":562},10,[152,564,565],{"class":158},"      create",[152,567,498],{"class":162},[152,569,570],{"class":501},"user",[152,572,505],{"class":162},[152,574,509],{"class":508},[152,576,577],{"class":162}," user ",[152,579,580],{"class":508},"!=",[152,582,583],{"class":218}," null",[152,585,586],{"class":162},",\n",[152,588,590],{"class":154,"line":589},11,[152,591,592],{"class":162},"    },\n",[152,594,596],{"class":154,"line":595},12,[152,597,478],{"class":162},[152,599,601],{"class":154,"line":600},13,[152,602,299],{"class":162},[122,604,605,606,331,608,610,611,614],{},"A rule can return ",[149,607,527],{},[149,609,219],{},", or a ",[149,612,613],{},"where(...)"," condition. The same rule is\nused by REST requests and the typed client.",[122,616,617],{},"This example allows signed-in users to create posts. Updates and deletions remain\ndenied. The authentication guide shows how to restrict private rows to their\nowner when your application needs that behavior.",[133,619,621],{"id":620},"call-the-api-with-types","Call the API with Types",[122,623,624],{},"The client derives its types from your config. It does not need generated TypeScript\nfiles:",[141,626,628],{"className":143,"code":627,"language":146,"meta":147,"style":147},"import { createClient } from '@cloudconfig\u002Fcore\u002Fclient'\nimport type { config } from '.\u002Fcloud.config'\n\nconst api = createClient\u003Ctypeof config>({\n  baseUrl: 'http:\u002F\u002Flocalhost:3000\u002Fapi',\n})\n\nconst posts = await api.post.list({ page: 1, pageSize: 20 })\n",[149,629,630,644,659,665,688,698,702,706],{"__ignoreMap":147},[152,631,632,635,638,641],{"class":154,"line":155},[152,633,634],{"class":508},"import",[152,636,637],{"class":162}," { createClient } ",[152,639,640],{"class":508},"from",[152,642,643],{"class":327}," '@cloudconfig\u002Fcore\u002Fclient'\n",[152,645,646,648,651,654,656],{"class":154,"line":172},[152,647,634],{"class":508},[152,649,650],{"class":508}," type",[152,652,653],{"class":162}," { config } ",[152,655,640],{"class":508},[152,657,658],{"class":327}," '.\u002Fcloud.config'\n",[152,660,661],{"class":154,"line":190},[152,662,664],{"emptyLinePlaceholder":663},true,"\n",[152,666,667,670,673,676,679,682,685],{"class":154,"line":201},[152,668,669],{"class":508},"const",[152,671,672],{"class":218}," api",[152,674,675],{"class":508}," =",[152,677,678],{"class":158}," createClient",[152,680,681],{"class":162},"\u003C",[152,683,684],{"class":508},"typeof",[152,686,687],{"class":162}," config>({\n",[152,689,690,693,696],{"class":154,"line":225},[152,691,692],{"class":162},"  baseUrl: ",[152,694,695],{"class":327},"'http:\u002F\u002Flocalhost:3000\u002Fapi'",[152,697,586],{"class":162},[152,699,700],{"class":154,"line":481},[152,701,228],{"class":162},[152,703,704],{"class":154,"line":486},[152,705,664],{"emptyLinePlaceholder":663},[152,707,708,710,713,715,718,721,724,727,730,733,736],{"class":154,"line":492},[152,709,669],{"class":508},[152,711,712],{"class":218}," posts",[152,714,675],{"class":508},[152,716,717],{"class":508}," await",[152,719,720],{"class":162}," api.post.",[152,722,723],{"class":158},"list",[152,725,726],{"class":162},"({ page: ",[152,728,729],{"class":218},"1",[152,731,732],{"class":162},", pageSize: ",[152,734,735],{"class":218},"20",[152,737,738],{"class":162}," })\n",[122,740,741,744],{},[149,742,743],{},"list()"," returns pagination information with the rows:",[141,746,748],{"className":143,"code":747,"language":146,"meta":147,"style":147},"const { data, totalCount, page, pageSize, totalPages } = posts\n",[149,749,750],{"__ignoreMap":147},[152,751,752,754,757,760,762,765,767,770,772,775,777,780,783,786],{"class":154,"line":155},[152,753,669],{"class":508},[152,755,756],{"class":162}," { ",[152,758,759],{"class":218},"data",[152,761,331],{"class":162},[152,763,764],{"class":218},"totalCount",[152,766,331],{"class":162},[152,768,769],{"class":218},"page",[152,771,331],{"class":162},[152,773,774],{"class":218},"pageSize",[152,776,331],{"class":162},[152,778,779],{"class":218},"totalPages",[152,781,782],{"class":162}," } ",[152,784,785],{"class":508},"=",[152,787,788],{"class":162}," posts\n",[122,790,791],{},"To load an existing published post, pass its ID:",[141,793,795],{"className":143,"code":794,"language":146,"meta":147,"style":147},"const post = await api.post.get(1)\n",[149,796,797],{"__ignoreMap":147},[152,798,799,801,804,806,808,810,813,815,817],{"class":154,"line":155},[152,800,669],{"class":508},[152,802,803],{"class":218}," post",[152,805,675],{"class":508},[152,807,717],{"class":508},[152,809,720],{"class":162},[152,811,812],{"class":158},"get",[152,814,215],{"class":162},[152,816,729],{"class":218},[152,818,299],{"class":162},[133,820,822],{"id":821},"what-to-build-next","What to Build Next",[122,824,825,826,829],{},"When posts belong to people, add ",[126,827,828],{"href":23},"GitHub sign-in"," so access\nrules can identify the user. Read that guide when you need user accounts.",[122,831,832,833,835],{},"When the app is ready to go online, follow ",[126,834,39],{"href":40}," to\nchoose its host. Local development can continue without a cloud account.",[122,837,838,839,842],{},"For config file conventions and command lookup, use the\n",[126,840,841],{"href":112},"project reference",". You can return to it as needed.",[844,845,846],"style",{},"html pre.shiki code .snPdu, html code.shiki .snPdu{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sxrX7, html code.shiki .sxrX7{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sBjJW, html code.shiki .sBjJW{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sIIMD, html code.shiki .sIIMD{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sP4rz, html code.shiki .sP4rz{--shiki-light:#E36209;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s8jYJ, html code.shiki .s8jYJ{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":147,"searchDepth":172,"depth":172,"links":848},[849,850,851,852],{"id":135,"depth":172,"text":136},{"id":418,"depth":172,"text":419},{"id":620,"depth":172,"text":621},{"id":821,"depth":172,"text":822},"Describe your data, control access, and call the API with types.","md",null,{},{"icon":20},{"title":17,"description":853},"vLAEbQw3Cu8kzayLr9OJ8W8L2FSSFg6fhhnmTLzm11M",[861,863],{"title":12,"path":13,"stem":14,"description":862,"icon":15},"Run a blog API locally, then add a field to its database and API.",{"title":22,"path":23,"stem":24,"description":864,"icon":27},"Let users sign in with GitHub and identify them in your access rules.",1792122403105]