[{"data":1,"prerenderedAt":3253},["ShallowReactive",2],{"navigation_docs":3,"-getting-started-writing-a-module":153,"-getting-started-writing-a-module-surround":3248},[4,35,50,59,144],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting started",false,"\u002Fgetting-started","1.getting-started",[10,15,20,25,30],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F2.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Local Development","\u002Fgetting-started\u002Flocal-development","1.getting-started\u002F3.local-development","i-lucide-terminal",{"title":21,"path":22,"stem":23,"icon":24},"Publishing Packages","\u002Fgetting-started\u002Fpublishing","1.getting-started\u002F4.publishing","i-lucide-package-check",{"title":26,"path":27,"stem":28,"icon":29},"Writing a Module","\u002Fgetting-started\u002Fwriting-a-module","1.getting-started\u002F5.writing-a-module","i-lucide-puzzle",{"title":31,"path":32,"stem":33,"icon":34},"UX Patterns","\u002Fgetting-started\u002Fux-patterns","1.getting-started\u002F6.ux-patterns","i-lucide-layout-template",{"title":36,"path":37,"stem":38,"children":39},"Applications","\u002Fapplications","2.applications",[40,45],{"title":41,"path":42,"stem":43,"icon":44},"Website","\u002Fapplications\u002Fwebsite","2.applications\u002F1.website","i-lucide-layout-dashboard",{"title":46,"path":47,"stem":48,"icon":49},"Docs","\u002Fapplications\u002Fdocs","2.applications\u002F2.docs","i-lucide-book-open",{"title":51,"path":52,"stem":53,"children":54},"Layers","\u002Flayers","3.layers",[55],{"title":56,"path":57,"stem":58},"Base Layer","\u002Flayers\u002Fbase","3.layers\u002F1.base",{"title":60,"path":61,"stem":62,"children":63},"Modules","\u002Fmodules","4.modules",[64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140],{"title":65,"path":66,"stem":67},"Account","\u002Fmodules\u002Faccount","4.modules\u002F01.account",{"title":69,"path":70,"stem":71},"Admin","\u002Fmodules\u002Fadmin","4.modules\u002F02.admin",{"title":73,"path":74,"stem":75},"Auth","\u002Fmodules\u002Fauth","4.modules\u002F03.auth",{"title":77,"path":78,"stem":79},"Authorization","\u002Fmodules\u002Fauthorization","4.modules\u002F04.authorization",{"title":81,"path":82,"stem":83},"Cookie Consent","\u002Fmodules\u002Fcookie-consent","4.modules\u002F05.cookie-consent",{"title":85,"path":86,"stem":87},"Events","\u002Fmodules\u002Fevents","4.modules\u002F06.events",{"title":89,"path":90,"stem":91},"Forms","\u002Fmodules\u002Fforms","4.modules\u002F07.forms",{"title":93,"path":94,"stem":95},"MCP","\u002Fmodules\u002Fmcp","4.modules\u002F08.mcp",{"title":97,"path":98,"stem":99},"Menu","\u002Fmodules\u002Fmenu","4.modules\u002F09.menu",{"title":101,"path":102,"stem":103},"Module Kit","\u002Fmodules\u002Fmodule-kit","4.modules\u002F10.module-kit",{"title":105,"path":106,"stem":107},"Notify","\u002Fmodules\u002Fnotify","4.modules\u002F11.notify",{"title":109,"path":110,"stem":111},"OAuth Server","\u002Fmodules\u002Foauth-server","4.modules\u002F12.oauth-server",{"title":113,"path":114,"stem":115},"Payments","\u002Fmodules\u002Fpayments","4.modules\u002F13.payments",{"title":117,"path":118,"stem":119},"Preferences","\u002Fmodules\u002Fpreferences","4.modules\u002F14.preferences",{"title":121,"path":122,"stem":123},"Stripe","\u002Fmodules\u002Fstripe","4.modules\u002F15.stripe",{"title":125,"path":126,"stem":127},"Subscriptions","\u002Fmodules\u002Fsubscriptions","4.modules\u002F16.subscriptions",{"title":129,"path":130,"stem":131},"UI","\u002Fmodules\u002Fui","4.modules\u002F17.ui",{"title":133,"path":134,"stem":135},"Users","\u002Fmodules\u002Fusers","4.modules\u002F18.users",{"title":137,"path":138,"stem":139},"Widget","\u002Fmodules\u002Fwidget","4.modules\u002F19.widget",{"title":141,"path":142,"stem":143},"Email Templates","\u002Fmodules\u002Femail-templates","4.modules\u002F20.email-templates",{"title":145,"path":146,"stem":147,"children":148},"Packages","\u002Fpackages","5.packages",[149],{"title":150,"path":151,"stem":152},"CLI","\u002Fpackages\u002Fcli","5.packages\u002F4.cli",{"id":154,"title":26,"body":155,"description":3241,"extension":3242,"links":3243,"meta":3244,"navigation":3245,"path":27,"seo":3246,"stem":28,"__hash__":3247},"docs\u002F1.getting-started\u002F5.writing-a-module.md",{"type":156,"value":157,"toc":3227},"minimark",[158,186,191,194,230,252,256,264,282,288,303,921,925,932,1147,1264,1314,1321,1324,1993,1996,2056,2060,2063,2194,2303,2310,2313,2435,2439,2446,2505,2585,2595,2599,2606,2764,3011,3014,3043,3048,3063,3132,3163,3167,3223],[159,160,161,162,169,170,174,175,178,179,182,183,185],"p",{},"A Frigear module is a ",[163,164,168],"a",{"href":165,"rel":166},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fguide\u002Fmodules",[167],"nofollow","Nuxt module"," under ",[171,172,173],"code",{},"packages\u002F\u003Cname>",", published as\n",[171,176,177],{},"@frigear-nu\u002F\u003Cname>",". It ships its own pages, server routes, translations and database tables, and a host application\nturns it on with one entry in ",[171,180,181],{},"modules",". This page is the path from an empty folder to a released module; the helpers it\nuses are described in ",[163,184,101],{"href":102},".",[187,188,190],"h2",{"id":189},"scaffold-the-package","Scaffold the package",[159,192,193],{},"From the repository root:",[195,196,201],"pre",{"className":197,"code":198,"language":199,"meta":200,"style":200},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm cli module:create my-module\npnpm install\n","bash","",[171,202,203,222],{"__ignoreMap":200},[204,205,208,212,216,219],"span",{"class":206,"line":207},"line",1,[204,209,211],{"class":210},"sBMFI","pnpm",[204,213,215],{"class":214},"sfazB"," cli",[204,217,218],{"class":214}," module:create",[204,220,221],{"class":214}," my-module\n",[204,223,225,227],{"class":206,"line":224},2,[204,226,211],{"class":210},[204,228,229],{"class":214}," install\n",[159,231,232,233,236,237,240,241,244,245,248,249,251],{},"The command downloads a starter into ",[171,234,235],{},"packages\u002Fmy-module"," and names the package ",[171,238,239],{},"@frigear-nu\u002Fmy-module",". It only\ncreates the package, so finish the job by matching the structure of a sibling such as ",[171,242,243],{},"packages\u002Fevents"," or\n",[171,246,247],{},"packages\u002Fcookie-consent",". See ",[163,250,150],{"href":151}," for the options and the checklist that follows.",[187,253,255],{"id":254},"folder-layout","Folder layout",[195,257,262],{"className":258,"code":260,"language":261,"meta":200},[259],"language-text","packages\u002Fmy-module\u002F\n├── src\u002F\n│   ├── module.ts            the Nuxt module: meta, moduleDependencies, setup()\n│   ├── types.ts             ModuleOptions and the other public types\n│   └── runtime\u002F\n│       ├── app\u002F             components, composables, pages (client and SSR code)\n│       ├── server\u002F          routes, plugins, utils\n│       │   └── db\u002F          schema.sqlite.ts and schema.postgresql.ts\n│       ├── i18n\u002Flang\u002F       da.json and en.json\n│       └── utils\u002Findex.ts   the `\u002Futils` export: helpers other modules call in their setup()\n├── test\u002F\n│   ├── fixtures\u002F\u003Cname>\u002F     a tiny Nuxt app that installs the module (nuxt.config.ts, app.vue)\n│   └── *.test.ts\n├── playground\u002F              an app for `pnpm dev` in this package\n├── .release-it.json\n└── package.json\n","text",[171,263,260],{"__ignoreMap":200},[159,265,266,267,270,271,274,275,278,279,185],{},"Only the built ",[171,268,269],{},"dist\u002F"," is published (",[171,272,273],{},"files: [\"dist\"]",", produced by the module builder). Keep everything a host needs\nunder ",[171,276,277],{},"src\u002Fruntime",": it ends up in ",[171,280,281],{},"dist\u002Fruntime",[187,283,285],{"id":284},"packagejson",[171,286,287],{},"package.json",[159,289,290,291,294,295,298,299,302],{},"Workspace consumers resolve the TypeScript source directly, and ",[171,292,293],{},"publishConfig"," swaps in the built files when the\npackage is published. Add the ",[171,296,297],{},".\u002Futils"," export whenever other modules import helpers from yours, and mirror every\nentry in ",[171,300,301],{},"typesVersions"," so TypeScript with classic module resolution finds the types too.",[195,304,308],{"className":305,"code":306,"language":307,"meta":200,"style":200},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"name\": \"@frigear-nu\u002Fmy-module\",\n  \"type\": \"module\",\n  \"main\": \".\u002Fsrc\u002Fmodule.ts\",\n  \"exports\": {\n    \".\": { \"types\": \".\u002Fsrc\u002Fmodule.ts\", \"import\": \".\u002Fsrc\u002Fmodule.ts\", \"default\": \".\u002Fsrc\u002Fmodule.ts\" },\n    \".\u002Futils\": {\n      \"types\": \".\u002Fsrc\u002Fruntime\u002Futils\u002Findex.ts\",\n      \"import\": \".\u002Fsrc\u002Fruntime\u002Futils\u002Findex.ts\",\n      \"default\": \".\u002Fsrc\u002Fruntime\u002Futils\u002Findex.ts\"\n    }\n  },\n  \"typesVersions\": {\n    \"*\": { \".\": [\".\u002Fsrc\u002Fmodule.ts\"], \"utils\": [\".\u002Fsrc\u002Fruntime\u002Futils\u002Findex.ts\"] }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": { \"types\": \".\u002Fdist\u002Ftypes.d.mts\", \"import\": \".\u002Fdist\u002Fmodule.mjs\", \"default\": \".\u002Fdist\u002Fmodule.mjs\" },\n      \".\u002Futils\": {\n        \"types\": \".\u002Fdist\u002Fruntime\u002Futils\u002Findex.d.ts\",\n        \"import\": \".\u002Fdist\u002Fruntime\u002Futils\u002Findex.js\",\n        \"default\": \".\u002Fdist\u002Fruntime\u002Futils\u002Findex.js\"\n      }\n    },\n    \"main\": \".\u002Fdist\u002Fmodule.mjs\",\n    \"typesVersions\": {\n      \"*\": { \".\": [\".\u002Fdist\u002Ftypes.d.mts\"], \"utils\": [\".\u002Fdist\u002Fruntime\u002Futils\u002Findex.d.ts\"] }\n    }\n  },\n  \"files\": [\"dist\"]\n}\n","json",[171,309,310,316,341,362,383,398,467,480,501,520,538,544,550,563,620,625,638,651,715,728,749,769,786,792,798,817,830,881,886,891,915],{"__ignoreMap":200},[204,311,312],{"class":206,"line":207},[204,313,315],{"class":314},"sMK4o","{\n",[204,317,318,321,325,328,331,334,336,338],{"class":206,"line":224},[204,319,320],{"class":314},"  \"",[204,322,324],{"class":323},"spNyl","name",[204,326,327],{"class":314},"\"",[204,329,330],{"class":314},":",[204,332,333],{"class":314}," \"",[204,335,239],{"class":214},[204,337,327],{"class":314},[204,339,340],{"class":314},",\n",[204,342,344,346,349,351,353,355,358,360],{"class":206,"line":343},3,[204,345,320],{"class":314},[204,347,348],{"class":323},"type",[204,350,327],{"class":314},[204,352,330],{"class":314},[204,354,333],{"class":314},[204,356,357],{"class":214},"module",[204,359,327],{"class":314},[204,361,340],{"class":314},[204,363,365,367,370,372,374,376,379,381],{"class":206,"line":364},4,[204,366,320],{"class":314},[204,368,369],{"class":323},"main",[204,371,327],{"class":314},[204,373,330],{"class":314},[204,375,333],{"class":314},[204,377,378],{"class":214},".\u002Fsrc\u002Fmodule.ts",[204,380,327],{"class":314},[204,382,340],{"class":314},[204,384,386,388,391,393,395],{"class":206,"line":385},5,[204,387,320],{"class":314},[204,389,390],{"class":323},"exports",[204,392,327],{"class":314},[204,394,330],{"class":314},[204,396,397],{"class":314}," {\n",[204,399,401,404,406,408,410,413,415,419,421,423,425,427,429,432,434,437,439,441,443,445,447,449,451,454,456,458,460,462,464],{"class":206,"line":400},6,[204,402,403],{"class":314},"    \"",[204,405,185],{"class":210},[204,407,327],{"class":314},[204,409,330],{"class":314},[204,411,412],{"class":314}," {",[204,414,333],{"class":314},[204,416,418],{"class":417},"sbssI","types",[204,420,327],{"class":314},[204,422,330],{"class":314},[204,424,333],{"class":314},[204,426,378],{"class":214},[204,428,327],{"class":314},[204,430,431],{"class":314},",",[204,433,333],{"class":314},[204,435,436],{"class":417},"import",[204,438,327],{"class":314},[204,440,330],{"class":314},[204,442,333],{"class":314},[204,444,378],{"class":214},[204,446,327],{"class":314},[204,448,431],{"class":314},[204,450,333],{"class":314},[204,452,453],{"class":417},"default",[204,455,327],{"class":314},[204,457,330],{"class":314},[204,459,333],{"class":314},[204,461,378],{"class":214},[204,463,327],{"class":314},[204,465,466],{"class":314}," },\n",[204,468,470,472,474,476,478],{"class":206,"line":469},7,[204,471,403],{"class":314},[204,473,297],{"class":210},[204,475,327],{"class":314},[204,477,330],{"class":314},[204,479,397],{"class":314},[204,481,483,486,488,490,492,494,497,499],{"class":206,"line":482},8,[204,484,485],{"class":314},"      \"",[204,487,418],{"class":417},[204,489,327],{"class":314},[204,491,330],{"class":314},[204,493,333],{"class":314},[204,495,496],{"class":214},".\u002Fsrc\u002Fruntime\u002Futils\u002Findex.ts",[204,498,327],{"class":314},[204,500,340],{"class":314},[204,502,504,506,508,510,512,514,516,518],{"class":206,"line":503},9,[204,505,485],{"class":314},[204,507,436],{"class":417},[204,509,327],{"class":314},[204,511,330],{"class":314},[204,513,333],{"class":314},[204,515,496],{"class":214},[204,517,327],{"class":314},[204,519,340],{"class":314},[204,521,523,525,527,529,531,533,535],{"class":206,"line":522},10,[204,524,485],{"class":314},[204,526,453],{"class":417},[204,528,327],{"class":314},[204,530,330],{"class":314},[204,532,333],{"class":314},[204,534,496],{"class":214},[204,536,537],{"class":314},"\"\n",[204,539,541],{"class":206,"line":540},11,[204,542,543],{"class":314},"    }\n",[204,545,547],{"class":206,"line":546},12,[204,548,549],{"class":314},"  },\n",[204,551,553,555,557,559,561],{"class":206,"line":552},13,[204,554,320],{"class":314},[204,556,301],{"class":323},[204,558,327],{"class":314},[204,560,330],{"class":314},[204,562,397],{"class":314},[204,564,566,568,571,573,575,577,579,581,583,585,588,590,592,594,597,599,602,604,606,608,610,612,614,617],{"class":206,"line":565},14,[204,567,403],{"class":314},[204,569,570],{"class":210},"*",[204,572,327],{"class":314},[204,574,330],{"class":314},[204,576,412],{"class":314},[204,578,333],{"class":314},[204,580,185],{"class":417},[204,582,327],{"class":314},[204,584,330],{"class":314},[204,586,587],{"class":314}," [",[204,589,327],{"class":314},[204,591,378],{"class":214},[204,593,327],{"class":314},[204,595,596],{"class":314},"],",[204,598,333],{"class":314},[204,600,601],{"class":417},"utils",[204,603,327],{"class":314},[204,605,330],{"class":314},[204,607,587],{"class":314},[204,609,327],{"class":314},[204,611,496],{"class":214},[204,613,327],{"class":314},[204,615,616],{"class":314},"]",[204,618,619],{"class":314}," }\n",[204,621,623],{"class":206,"line":622},15,[204,624,549],{"class":314},[204,626,628,630,632,634,636],{"class":206,"line":627},16,[204,629,320],{"class":314},[204,631,293],{"class":323},[204,633,327],{"class":314},[204,635,330],{"class":314},[204,637,397],{"class":314},[204,639,641,643,645,647,649],{"class":206,"line":640},17,[204,642,403],{"class":314},[204,644,390],{"class":210},[204,646,327],{"class":314},[204,648,330],{"class":314},[204,650,397],{"class":314},[204,652,654,656,658,660,662,664,666,669,671,673,675,678,680,682,684,686,688,690,692,695,697,699,701,703,705,707,709,711,713],{"class":206,"line":653},18,[204,655,485],{"class":314},[204,657,185],{"class":417},[204,659,327],{"class":314},[204,661,330],{"class":314},[204,663,412],{"class":314},[204,665,333],{"class":314},[204,667,418],{"class":668},"swJcz",[204,670,327],{"class":314},[204,672,330],{"class":314},[204,674,333],{"class":314},[204,676,677],{"class":214},".\u002Fdist\u002Ftypes.d.mts",[204,679,327],{"class":314},[204,681,431],{"class":314},[204,683,333],{"class":314},[204,685,436],{"class":668},[204,687,327],{"class":314},[204,689,330],{"class":314},[204,691,333],{"class":314},[204,693,694],{"class":214},".\u002Fdist\u002Fmodule.mjs",[204,696,327],{"class":314},[204,698,431],{"class":314},[204,700,333],{"class":314},[204,702,453],{"class":668},[204,704,327],{"class":314},[204,706,330],{"class":314},[204,708,333],{"class":314},[204,710,694],{"class":214},[204,712,327],{"class":314},[204,714,466],{"class":314},[204,716,718,720,722,724,726],{"class":206,"line":717},19,[204,719,485],{"class":314},[204,721,297],{"class":417},[204,723,327],{"class":314},[204,725,330],{"class":314},[204,727,397],{"class":314},[204,729,731,734,736,738,740,742,745,747],{"class":206,"line":730},20,[204,732,733],{"class":314},"        \"",[204,735,418],{"class":668},[204,737,327],{"class":314},[204,739,330],{"class":314},[204,741,333],{"class":314},[204,743,744],{"class":214},".\u002Fdist\u002Fruntime\u002Futils\u002Findex.d.ts",[204,746,327],{"class":314},[204,748,340],{"class":314},[204,750,752,754,756,758,760,762,765,767],{"class":206,"line":751},21,[204,753,733],{"class":314},[204,755,436],{"class":668},[204,757,327],{"class":314},[204,759,330],{"class":314},[204,761,333],{"class":314},[204,763,764],{"class":214},".\u002Fdist\u002Fruntime\u002Futils\u002Findex.js",[204,766,327],{"class":314},[204,768,340],{"class":314},[204,770,772,774,776,778,780,782,784],{"class":206,"line":771},22,[204,773,733],{"class":314},[204,775,453],{"class":668},[204,777,327],{"class":314},[204,779,330],{"class":314},[204,781,333],{"class":314},[204,783,764],{"class":214},[204,785,537],{"class":314},[204,787,789],{"class":206,"line":788},23,[204,790,791],{"class":314},"      }\n",[204,793,795],{"class":206,"line":794},24,[204,796,797],{"class":314},"    },\n",[204,799,801,803,805,807,809,811,813,815],{"class":206,"line":800},25,[204,802,403],{"class":314},[204,804,369],{"class":210},[204,806,327],{"class":314},[204,808,330],{"class":314},[204,810,333],{"class":314},[204,812,694],{"class":214},[204,814,327],{"class":314},[204,816,340],{"class":314},[204,818,820,822,824,826,828],{"class":206,"line":819},26,[204,821,403],{"class":314},[204,823,301],{"class":210},[204,825,327],{"class":314},[204,827,330],{"class":314},[204,829,397],{"class":314},[204,831,833,835,837,839,841,843,845,847,849,851,853,855,857,859,861,863,865,867,869,871,873,875,877,879],{"class":206,"line":832},27,[204,834,485],{"class":314},[204,836,570],{"class":417},[204,838,327],{"class":314},[204,840,330],{"class":314},[204,842,412],{"class":314},[204,844,333],{"class":314},[204,846,185],{"class":668},[204,848,327],{"class":314},[204,850,330],{"class":314},[204,852,587],{"class":314},[204,854,327],{"class":314},[204,856,677],{"class":214},[204,858,327],{"class":314},[204,860,596],{"class":314},[204,862,333],{"class":314},[204,864,601],{"class":668},[204,866,327],{"class":314},[204,868,330],{"class":314},[204,870,587],{"class":314},[204,872,327],{"class":314},[204,874,744],{"class":214},[204,876,327],{"class":314},[204,878,616],{"class":314},[204,880,619],{"class":314},[204,882,884],{"class":206,"line":883},28,[204,885,543],{"class":314},[204,887,889],{"class":206,"line":888},29,[204,890,549],{"class":314},[204,892,894,896,899,901,903,905,907,910,912],{"class":206,"line":893},30,[204,895,320],{"class":314},[204,897,898],{"class":323},"files",[204,900,327],{"class":314},[204,902,330],{"class":314},[204,904,587],{"class":314},[204,906,327],{"class":314},[204,908,909],{"class":214},"dist",[204,911,327],{"class":314},[204,913,914],{"class":314},"]\n",[204,916,918],{"class":206,"line":917},31,[204,919,920],{"class":314},"}\n",[187,922,924],{"id":923},"declare-dependencies","Declare dependencies",[159,926,927,928,931],{},"List every module yours needs in ",[171,929,930],{},"moduleDependencies",". Nuxt then installs and orders them, so the host lists only your\nmodule.",[195,933,937],{"className":934,"code":935,"language":936,"meta":200,"style":200},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtModule\u003CModuleOptions>({\n  meta: { name: '@frigear-nu\u002Fmy-module', configKey: 'myModule' },\n  moduleDependencies: {\n    '@nuxthub\u002Fcore': { version: '>=0.10' },\n    '@frigear-nu\u002Fmodule-kit': { version: '>=0.0.1' },\n    '@frigear-nu\u002Fauth': { version: '>=0.0.1' },\n    '@frigear-nu\u002Fmenu': { version: '>=0.0.1', optional: true },\n  },\n  \u002F\u002F ...\n})\n","ts",[171,938,939,967,1005,1014,1042,1068,1093,1129,1133,1139],{"__ignoreMap":200},[204,940,941,945,948,952,955,958,961,965],{"class":206,"line":207},[204,942,944],{"class":943},"s7zQu","export",[204,946,947],{"class":943}," default",[204,949,951],{"class":950},"s2Zo4"," defineNuxtModule",[204,953,954],{"class":314},"\u003C",[204,956,957],{"class":210},"ModuleOptions",[204,959,960],{"class":314},">",[204,962,964],{"class":963},"sTEyZ","(",[204,966,315],{"class":314},[204,968,969,972,974,976,979,981,984,986,989,991,994,996,998,1001,1003],{"class":206,"line":224},[204,970,971],{"class":668},"  meta",[204,973,330],{"class":314},[204,975,412],{"class":314},[204,977,978],{"class":668}," name",[204,980,330],{"class":314},[204,982,983],{"class":314}," '",[204,985,239],{"class":214},[204,987,988],{"class":314},"'",[204,990,431],{"class":314},[204,992,993],{"class":668}," configKey",[204,995,330],{"class":314},[204,997,983],{"class":314},[204,999,1000],{"class":214},"myModule",[204,1002,988],{"class":314},[204,1004,466],{"class":314},[204,1006,1007,1010,1012],{"class":206,"line":343},[204,1008,1009],{"class":668},"  moduleDependencies",[204,1011,330],{"class":314},[204,1013,397],{"class":314},[204,1015,1016,1019,1022,1024,1026,1028,1031,1033,1035,1038,1040],{"class":206,"line":364},[204,1017,1018],{"class":314},"    '",[204,1020,1021],{"class":668},"@nuxthub\u002Fcore",[204,1023,988],{"class":314},[204,1025,330],{"class":314},[204,1027,412],{"class":314},[204,1029,1030],{"class":668}," version",[204,1032,330],{"class":314},[204,1034,983],{"class":314},[204,1036,1037],{"class":214},">=0.10",[204,1039,988],{"class":314},[204,1041,466],{"class":314},[204,1043,1044,1046,1049,1051,1053,1055,1057,1059,1061,1064,1066],{"class":206,"line":385},[204,1045,1018],{"class":314},[204,1047,1048],{"class":668},"@frigear-nu\u002Fmodule-kit",[204,1050,988],{"class":314},[204,1052,330],{"class":314},[204,1054,412],{"class":314},[204,1056,1030],{"class":668},[204,1058,330],{"class":314},[204,1060,983],{"class":314},[204,1062,1063],{"class":214},">=0.0.1",[204,1065,988],{"class":314},[204,1067,466],{"class":314},[204,1069,1070,1072,1075,1077,1079,1081,1083,1085,1087,1089,1091],{"class":206,"line":400},[204,1071,1018],{"class":314},[204,1073,1074],{"class":668},"@frigear-nu\u002Fauth",[204,1076,988],{"class":314},[204,1078,330],{"class":314},[204,1080,412],{"class":314},[204,1082,1030],{"class":668},[204,1084,330],{"class":314},[204,1086,983],{"class":314},[204,1088,1063],{"class":214},[204,1090,988],{"class":314},[204,1092,466],{"class":314},[204,1094,1095,1097,1100,1102,1104,1106,1108,1110,1112,1114,1116,1118,1121,1123,1127],{"class":206,"line":469},[204,1096,1018],{"class":314},[204,1098,1099],{"class":668},"@frigear-nu\u002Fmenu",[204,1101,988],{"class":314},[204,1103,330],{"class":314},[204,1105,412],{"class":314},[204,1107,1030],{"class":668},[204,1109,330],{"class":314},[204,1111,983],{"class":314},[204,1113,1063],{"class":214},[204,1115,988],{"class":314},[204,1117,431],{"class":314},[204,1119,1120],{"class":668}," optional",[204,1122,330],{"class":314},[204,1124,1126],{"class":1125},"sfNiH"," true",[204,1128,466],{"class":314},[204,1130,1131],{"class":206,"line":482},[204,1132,549],{"class":314},[204,1134,1135],{"class":206,"line":503},[204,1136,1138],{"class":1137},"sHwdD","  \u002F\u002F ...\n",[204,1140,1141,1144],{"class":206,"line":522},[204,1142,1143],{"class":314},"}",[204,1145,1146],{"class":963},")\n",[1148,1149,1150,1169],"table",{},[1151,1152,1153],"thead",{},[1154,1155,1156,1160,1165],"tr",{},[1157,1158,1159],"th",{},"Kind",[1157,1161,1162,1163],{},"In ",[171,1164,930],{},[1157,1166,1162,1167],{},[171,1168,287],{},[1170,1171,1172,1192,1217],"tbody",{},[1154,1173,1174,1178,1183],{},[1175,1176,1177],"td",{},"Required",[1175,1179,1180],{},[171,1181,1182],{},"{ version: '>=0.0.1' }",[1175,1184,1185,1188,1189,185],{},[171,1186,1187],{},"dependencies"," with ",[171,1190,1191],{},"workspace:*",[1154,1193,1194,1197,1202],{},[1175,1195,1196],{},"Optional",[1175,1198,1199],{},[171,1200,1201],{},"{ version: '>=0.0.1', optional: true }",[1175,1203,1204,1205,1208,1209,1212,1213,1216],{},"An optional ",[171,1206,1207],{},"peerDependencies"," entry (with ",[171,1210,1211],{},"peerDependenciesMeta",") and a ",[171,1214,1215],{},"devDependencies"," entry, so tests can use it.",[1154,1218,1219,1247,1250],{},[1175,1220,1221,1222,1225,1226,1225,1229,1225,1232,1225,1235,1225,1237,1225,1240,1225,1243,1246],{},"Nuxt toolchain (",[171,1223,1224],{},"nuxt",", ",[171,1227,1228],{},"@nuxt\u002Fkit",[171,1230,1231],{},"@nuxt\u002Fschema",[171,1233,1234],{},"@nuxt\u002Fui",[171,1236,1021],{},[171,1238,1239],{},"drizzle-orm",[171,1241,1242],{},"vitest",[171,1244,1245],{},"typescript",", ...)",[1175,1248,1249],{},"-",[1175,1251,1252,1255,1256,1259,1260,1263],{},[171,1253,1254],{},"catalog:",", from the ",[171,1257,1258],{},"catalog"," in the root ",[171,1261,1262],{},"pnpm-workspace.yaml",", so the whole workspace shares one copy of each (a version of its own per package multiplies the installed Nuxt copies and slows every boot).",[1265,1266,1267,1281,1302],"ul",{},[1268,1269,1270,1271,1273,1274,1277,1278,1280],"li",{},"Depend on ",[171,1272,1048],{}," always: the entry is what provides the ",[171,1275,1276],{},"useModuleT"," auto-import. Add\n",[171,1279,1021],{}," only when the module has database tables.",[1268,1282,1283,1284,1287,1288,1291,1292,1294,1295,1298,1299,185],{},"An optional module is set up first when it is installed, so ",[171,1285,1286],{},"hasNuxtModule('@frigear-nu\u002Fmenu')"," in ",[171,1289,1290],{},"setup()"," does not\ndepend on the order of the host's ",[171,1293,181],{},". Guard every use of it, and load its helpers with a dynamic ",[171,1296,1297],{},"import()","\ninside the guard, for example ",[171,1300,1301],{},"await import('@frigear-nu\u002Fwidget\u002Futils')",[1268,1303,1304,1306,1307,1309,1310,1313],{},[171,1305,930],{}," may be a function of ",[171,1308,1224],{}," when a dependency depends on options, as ",[171,1311,1312],{},"@frigear-nu\u002Fusers"," does for\nMCP.",[187,1315,1317,1318,1320],{"id":1316},"the-setup-checklist","The ",[171,1319,1290],{}," checklist",[159,1322,1323],{},"Most modules call the same helpers, in this order:",[195,1325,1327],{"className":934,"code":1326,"language":936,"meta":200,"style":200},"import { addServerHandler, addServerImportsDir, createResolver, defineNuxtModule } from '@nuxt\u002Fkit'\nimport {\n  addModulePages,\n  inlineModuleRuntime,\n  moduleApiUrl,\n  registerDatabaseTable,\n  registerLocales,\n  registerModule,\n  registerTailwindSource,\n  resolvePagePath,\n} from '@frigear-nu\u002Fmodule-kit\u002Futils'\n\nconst MODULE_NAME = '@frigear-nu\u002Fmy-module'\n\nexport default defineNuxtModule\u003CModuleOptions>({\n  \u002F\u002F meta, defaults, moduleDependencies ...\n  setup(options, nuxt) {\n    const resolver = createResolver(import.meta.url)\n\n    \u002F\u002F 1. Make the module known to the rest of the app.\n    registerModule(MODULE_NAME, nuxt)\n\n    \u002F\u002F 2. Classes used in the module's components must be generated by Tailwind.\n    registerTailwindSource(nuxt, resolver.resolve('.\u002Fruntime\u002Fapp'))\n\n    \u002F\u002F 3. Translations: da.json and en.json, namespaced by module.\n    registerLocales(nuxt, resolver.resolve('.\u002Fruntime\u002Fi18n\u002Flang'))\n\n    \u002F\u002F 4. Pages are opt-in or overridable through settings.pages.*.\n    addModulePages(MODULE_NAME, resolver, [\n      {\n        name: 'my-module',\n        path: resolvePagePath(options.settings?.pages?.index, '\u002Fmy-module'),\n        file: '.\u002Fruntime\u002Fapp\u002Fpages\u002Findex.vue',\n      },\n    ])\n\n    \u002F\u002F 5. Server routes, auto-imports and bundling of the runtime.\n    addServerImportsDir(resolver.resolve('.\u002Fruntime\u002Fserver\u002Futils'))\n    inlineModuleRuntime(nuxt, resolver)\n    addServerHandler({\n      route: moduleApiUrl('my-module', 'things'),\n      method: 'get',\n      handler: resolver.resolve('.\u002Fruntime\u002Fserver\u002Froutes\u002Fthings.get'),\n    })\n\n    \u002F\u002F 6. Tables: a plain drizzle file per dialect. No `name`, nothing to await.\n    registerDatabaseTable(nuxt, {\n      resolver,\n      schema: dialect => `.\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.${dialect}`,\n    })\n  },\n})\n",[171,1328,1329,1365,1371,1378,1385,1392,1399,1406,1413,1420,1427,1440,1446,1463,1467,1485,1490,1511,1540,1544,1549,1565,1569,1574,1604,1608,1613,1641,1645,1650,1668,1673,1690,1734,1751,1757,1763,1768,1774,1800,1816,1826,1858,1875,1902,1910,1915,1921,1935,1943,1974,1981,1986],{"__ignoreMap":200},[204,1330,1331,1333,1335,1338,1340,1343,1345,1348,1350,1352,1355,1358,1360,1362],{"class":206,"line":207},[204,1332,436],{"class":943},[204,1334,412],{"class":314},[204,1336,1337],{"class":963}," addServerHandler",[204,1339,431],{"class":314},[204,1341,1342],{"class":963}," addServerImportsDir",[204,1344,431],{"class":314},[204,1346,1347],{"class":963}," createResolver",[204,1349,431],{"class":314},[204,1351,951],{"class":963},[204,1353,1354],{"class":314}," }",[204,1356,1357],{"class":943}," from",[204,1359,983],{"class":314},[204,1361,1228],{"class":214},[204,1363,1364],{"class":314},"'\n",[204,1366,1367,1369],{"class":206,"line":224},[204,1368,436],{"class":943},[204,1370,397],{"class":314},[204,1372,1373,1376],{"class":206,"line":343},[204,1374,1375],{"class":963},"  addModulePages",[204,1377,340],{"class":314},[204,1379,1380,1383],{"class":206,"line":364},[204,1381,1382],{"class":963},"  inlineModuleRuntime",[204,1384,340],{"class":314},[204,1386,1387,1390],{"class":206,"line":385},[204,1388,1389],{"class":963},"  moduleApiUrl",[204,1391,340],{"class":314},[204,1393,1394,1397],{"class":206,"line":400},[204,1395,1396],{"class":963},"  registerDatabaseTable",[204,1398,340],{"class":314},[204,1400,1401,1404],{"class":206,"line":469},[204,1402,1403],{"class":963},"  registerLocales",[204,1405,340],{"class":314},[204,1407,1408,1411],{"class":206,"line":482},[204,1409,1410],{"class":963},"  registerModule",[204,1412,340],{"class":314},[204,1414,1415,1418],{"class":206,"line":503},[204,1416,1417],{"class":963},"  registerTailwindSource",[204,1419,340],{"class":314},[204,1421,1422,1425],{"class":206,"line":522},[204,1423,1424],{"class":963},"  resolvePagePath",[204,1426,340],{"class":314},[204,1428,1429,1431,1433,1435,1438],{"class":206,"line":540},[204,1430,1143],{"class":314},[204,1432,1357],{"class":943},[204,1434,983],{"class":314},[204,1436,1437],{"class":214},"@frigear-nu\u002Fmodule-kit\u002Futils",[204,1439,1364],{"class":314},[204,1441,1442],{"class":206,"line":546},[204,1443,1445],{"emptyLinePlaceholder":1444},true,"\n",[204,1447,1448,1451,1454,1457,1459,1461],{"class":206,"line":552},[204,1449,1450],{"class":323},"const",[204,1452,1453],{"class":963}," MODULE_NAME ",[204,1455,1456],{"class":314},"=",[204,1458,983],{"class":314},[204,1460,239],{"class":214},[204,1462,1364],{"class":314},[204,1464,1465],{"class":206,"line":565},[204,1466,1445],{"emptyLinePlaceholder":1444},[204,1468,1469,1471,1473,1475,1477,1479,1481,1483],{"class":206,"line":622},[204,1470,944],{"class":943},[204,1472,947],{"class":943},[204,1474,951],{"class":950},[204,1476,954],{"class":314},[204,1478,957],{"class":210},[204,1480,960],{"class":314},[204,1482,964],{"class":963},[204,1484,315],{"class":314},[204,1486,1487],{"class":206,"line":627},[204,1488,1489],{"class":1137},"  \u002F\u002F meta, defaults, moduleDependencies ...\n",[204,1491,1492,1495,1497,1501,1503,1506,1509],{"class":206,"line":640},[204,1493,1494],{"class":668},"  setup",[204,1496,964],{"class":314},[204,1498,1500],{"class":1499},"sHdIc","options",[204,1502,431],{"class":314},[204,1504,1505],{"class":1499}," nuxt",[204,1507,1508],{"class":314},")",[204,1510,397],{"class":314},[204,1512,1513,1516,1519,1522,1524,1526,1528,1530,1533,1535,1538],{"class":206,"line":653},[204,1514,1515],{"class":323},"    const",[204,1517,1518],{"class":963}," resolver",[204,1520,1521],{"class":314}," =",[204,1523,1347],{"class":950},[204,1525,964],{"class":668},[204,1527,436],{"class":943},[204,1529,185],{"class":314},[204,1531,1532],{"class":963},"meta",[204,1534,185],{"class":314},[204,1536,1537],{"class":963},"url",[204,1539,1146],{"class":668},[204,1541,1542],{"class":206,"line":717},[204,1543,1445],{"emptyLinePlaceholder":1444},[204,1545,1546],{"class":206,"line":730},[204,1547,1548],{"class":1137},"    \u002F\u002F 1. Make the module known to the rest of the app.\n",[204,1550,1551,1554,1556,1559,1561,1563],{"class":206,"line":751},[204,1552,1553],{"class":950},"    registerModule",[204,1555,964],{"class":668},[204,1557,1558],{"class":963},"MODULE_NAME",[204,1560,431],{"class":314},[204,1562,1505],{"class":963},[204,1564,1146],{"class":668},[204,1566,1567],{"class":206,"line":771},[204,1568,1445],{"emptyLinePlaceholder":1444},[204,1570,1571],{"class":206,"line":788},[204,1572,1573],{"class":1137},"    \u002F\u002F 2. Classes used in the module's components must be generated by Tailwind.\n",[204,1575,1576,1579,1581,1583,1585,1587,1589,1592,1594,1596,1599,1601],{"class":206,"line":794},[204,1577,1578],{"class":950},"    registerTailwindSource",[204,1580,964],{"class":668},[204,1582,1224],{"class":963},[204,1584,431],{"class":314},[204,1586,1518],{"class":963},[204,1588,185],{"class":314},[204,1590,1591],{"class":950},"resolve",[204,1593,964],{"class":668},[204,1595,988],{"class":314},[204,1597,1598],{"class":214},".\u002Fruntime\u002Fapp",[204,1600,988],{"class":314},[204,1602,1603],{"class":668},"))\n",[204,1605,1606],{"class":206,"line":800},[204,1607,1445],{"emptyLinePlaceholder":1444},[204,1609,1610],{"class":206,"line":819},[204,1611,1612],{"class":1137},"    \u002F\u002F 3. Translations: da.json and en.json, namespaced by module.\n",[204,1614,1615,1618,1620,1622,1624,1626,1628,1630,1632,1634,1637,1639],{"class":206,"line":832},[204,1616,1617],{"class":950},"    registerLocales",[204,1619,964],{"class":668},[204,1621,1224],{"class":963},[204,1623,431],{"class":314},[204,1625,1518],{"class":963},[204,1627,185],{"class":314},[204,1629,1591],{"class":950},[204,1631,964],{"class":668},[204,1633,988],{"class":314},[204,1635,1636],{"class":214},".\u002Fruntime\u002Fi18n\u002Flang",[204,1638,988],{"class":314},[204,1640,1603],{"class":668},[204,1642,1643],{"class":206,"line":883},[204,1644,1445],{"emptyLinePlaceholder":1444},[204,1646,1647],{"class":206,"line":888},[204,1648,1649],{"class":1137},"    \u002F\u002F 4. Pages are opt-in or overridable through settings.pages.*.\n",[204,1651,1652,1655,1657,1659,1661,1663,1665],{"class":206,"line":893},[204,1653,1654],{"class":950},"    addModulePages",[204,1656,964],{"class":668},[204,1658,1558],{"class":963},[204,1660,431],{"class":314},[204,1662,1518],{"class":963},[204,1664,431],{"class":314},[204,1666,1667],{"class":668}," [\n",[204,1669,1670],{"class":206,"line":917},[204,1671,1672],{"class":314},"      {\n",[204,1674,1676,1679,1681,1683,1686,1688],{"class":206,"line":1675},32,[204,1677,1678],{"class":668},"        name",[204,1680,330],{"class":314},[204,1682,983],{"class":314},[204,1684,1685],{"class":214},"my-module",[204,1687,988],{"class":314},[204,1689,340],{"class":314},[204,1691,1693,1696,1698,1701,1703,1705,1707,1710,1713,1716,1718,1721,1723,1725,1728,1730,1732],{"class":206,"line":1692},33,[204,1694,1695],{"class":668},"        path",[204,1697,330],{"class":314},[204,1699,1700],{"class":950}," resolvePagePath",[204,1702,964],{"class":668},[204,1704,1500],{"class":963},[204,1706,185],{"class":314},[204,1708,1709],{"class":963},"settings",[204,1711,1712],{"class":314},"?.",[204,1714,1715],{"class":963},"pages",[204,1717,1712],{"class":314},[204,1719,1720],{"class":963},"index",[204,1722,431],{"class":314},[204,1724,983],{"class":314},[204,1726,1727],{"class":214},"\u002Fmy-module",[204,1729,988],{"class":314},[204,1731,1508],{"class":668},[204,1733,340],{"class":314},[204,1735,1737,1740,1742,1744,1747,1749],{"class":206,"line":1736},34,[204,1738,1739],{"class":668},"        file",[204,1741,330],{"class":314},[204,1743,983],{"class":314},[204,1745,1746],{"class":214},".\u002Fruntime\u002Fapp\u002Fpages\u002Findex.vue",[204,1748,988],{"class":314},[204,1750,340],{"class":314},[204,1752,1754],{"class":206,"line":1753},35,[204,1755,1756],{"class":314},"      },\n",[204,1758,1760],{"class":206,"line":1759},36,[204,1761,1762],{"class":668},"    ])\n",[204,1764,1766],{"class":206,"line":1765},37,[204,1767,1445],{"emptyLinePlaceholder":1444},[204,1769,1771],{"class":206,"line":1770},38,[204,1772,1773],{"class":1137},"    \u002F\u002F 5. Server routes, auto-imports and bundling of the runtime.\n",[204,1775,1777,1780,1782,1785,1787,1789,1791,1793,1796,1798],{"class":206,"line":1776},39,[204,1778,1779],{"class":950},"    addServerImportsDir",[204,1781,964],{"class":668},[204,1783,1784],{"class":963},"resolver",[204,1786,185],{"class":314},[204,1788,1591],{"class":950},[204,1790,964],{"class":668},[204,1792,988],{"class":314},[204,1794,1795],{"class":214},".\u002Fruntime\u002Fserver\u002Futils",[204,1797,988],{"class":314},[204,1799,1603],{"class":668},[204,1801,1803,1806,1808,1810,1812,1814],{"class":206,"line":1802},40,[204,1804,1805],{"class":950},"    inlineModuleRuntime",[204,1807,964],{"class":668},[204,1809,1224],{"class":963},[204,1811,431],{"class":314},[204,1813,1518],{"class":963},[204,1815,1146],{"class":668},[204,1817,1819,1822,1824],{"class":206,"line":1818},41,[204,1820,1821],{"class":950},"    addServerHandler",[204,1823,964],{"class":668},[204,1825,315],{"class":314},[204,1827,1829,1832,1834,1837,1839,1841,1843,1845,1847,1849,1852,1854,1856],{"class":206,"line":1828},42,[204,1830,1831],{"class":668},"      route",[204,1833,330],{"class":314},[204,1835,1836],{"class":950}," moduleApiUrl",[204,1838,964],{"class":668},[204,1840,988],{"class":314},[204,1842,1685],{"class":214},[204,1844,988],{"class":314},[204,1846,431],{"class":314},[204,1848,983],{"class":314},[204,1850,1851],{"class":214},"things",[204,1853,988],{"class":314},[204,1855,1508],{"class":668},[204,1857,340],{"class":314},[204,1859,1861,1864,1866,1868,1871,1873],{"class":206,"line":1860},43,[204,1862,1863],{"class":668},"      method",[204,1865,330],{"class":314},[204,1867,983],{"class":314},[204,1869,1870],{"class":214},"get",[204,1872,988],{"class":314},[204,1874,340],{"class":314},[204,1876,1878,1881,1883,1885,1887,1889,1891,1893,1896,1898,1900],{"class":206,"line":1877},44,[204,1879,1880],{"class":668},"      handler",[204,1882,330],{"class":314},[204,1884,1518],{"class":963},[204,1886,185],{"class":314},[204,1888,1591],{"class":950},[204,1890,964],{"class":668},[204,1892,988],{"class":314},[204,1894,1895],{"class":214},".\u002Fruntime\u002Fserver\u002Froutes\u002Fthings.get",[204,1897,988],{"class":314},[204,1899,1508],{"class":668},[204,1901,340],{"class":314},[204,1903,1905,1908],{"class":206,"line":1904},45,[204,1906,1907],{"class":314},"    }",[204,1909,1146],{"class":668},[204,1911,1913],{"class":206,"line":1912},46,[204,1914,1445],{"emptyLinePlaceholder":1444},[204,1916,1918],{"class":206,"line":1917},47,[204,1919,1920],{"class":1137},"    \u002F\u002F 6. Tables: a plain drizzle file per dialect. No `name`, nothing to await.\n",[204,1922,1924,1927,1929,1931,1933],{"class":206,"line":1923},48,[204,1925,1926],{"class":950},"    registerDatabaseTable",[204,1928,964],{"class":668},[204,1930,1224],{"class":963},[204,1932,431],{"class":314},[204,1934,397],{"class":314},[204,1936,1938,1941],{"class":206,"line":1937},49,[204,1939,1940],{"class":963},"      resolver",[204,1942,340],{"class":314},[204,1944,1946,1949,1951,1954,1957,1960,1963,1966,1969,1972],{"class":206,"line":1945},50,[204,1947,1948],{"class":950},"      schema",[204,1950,330],{"class":314},[204,1952,1953],{"class":1499}," dialect",[204,1955,1956],{"class":323}," =>",[204,1958,1959],{"class":314}," `",[204,1961,1962],{"class":214},".\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.",[204,1964,1965],{"class":314},"${",[204,1967,1968],{"class":963},"dialect",[204,1970,1971],{"class":314},"}`",[204,1973,340],{"class":314},[204,1975,1977,1979],{"class":206,"line":1976},51,[204,1978,1907],{"class":314},[204,1980,1146],{"class":668},[204,1982,1984],{"class":206,"line":1983},52,[204,1985,549],{"class":314},[204,1987,1989,1991],{"class":206,"line":1988},53,[204,1990,1143],{"class":314},[204,1992,1146],{"class":963},[159,1994,1995],{},"Notes on the choices above:",[1265,1997,1998,2016,2027,2046],{},[1268,1999,2000,2003,2004,2007,2008,2011,2012,2015],{},[171,2001,2002],{},"registerModule"," takes the full package name; ",[171,2005,2006],{},"moduleUrl"," and ",[171,2009,2010],{},"moduleApiUrl"," take the short name (",[171,2013,2014],{},"'my-module'","),\nwhich they kebab-case into the path.",[1268,2017,2018,2019,2022,2023,2026],{},"Call ",[171,2020,2021],{},"inlineModuleRuntime"," next to ",[171,2024,2025],{},"addServerImportsDir",". Without it the server auto-imports and virtual modules of an\ninstalled module do not resolve in the host app.",[1268,2028,2029,2030,2033,2034,2036,2037,2040,2041,1287,2043,2045],{},"Authenticate server routes with ",[171,2031,2032],{},"requireAuth"," from ",[171,2035,1074],{}," rather than the session helpers (see the\nrepository ",[171,2038,2039],{},"AGENTS.md","), and declare ",[171,2042,1074],{},[171,2044,930],{}," when you do.",[1268,2047,2048,2049,2052,2053,185],{},"Menus, widgets and admin pages belong to optional modules: use ",[171,2050,2051],{},"addOptionalMenuSource"," and the guarded imports\ndescribed in ",[163,2054,101],{"href":2055},"\u002Fmodules\u002Fmodule-kit#menu-helpers",[187,2057,2059],{"id":2058},"add-a-database-table","Add a database table",[159,2061,2062],{},"Write the schema twice, once per dialect, as plain drizzle tables:",[195,2064,2066],{"className":934,"code":2065,"language":936,"meta":200,"style":200},"\u002F\u002F src\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.sqlite.ts\nimport { sqliteTable, text, integer } from 'drizzle-orm\u002Fsqlite-core'\n\nexport const things = sqliteTable('things', {\n  id: integer().primaryKey({ autoIncrement: true }),\n  name: text().notNull(),\n})\n",[171,2067,2068,2073,2103,2107,2133,2168,2188],{"__ignoreMap":200},[204,2069,2070],{"class":206,"line":207},[204,2071,2072],{"class":1137},"\u002F\u002F src\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.sqlite.ts\n",[204,2074,2075,2077,2079,2082,2084,2087,2089,2092,2094,2096,2098,2101],{"class":206,"line":224},[204,2076,436],{"class":943},[204,2078,412],{"class":314},[204,2080,2081],{"class":963}," sqliteTable",[204,2083,431],{"class":314},[204,2085,2086],{"class":963}," text",[204,2088,431],{"class":314},[204,2090,2091],{"class":963}," integer",[204,2093,1354],{"class":314},[204,2095,1357],{"class":943},[204,2097,983],{"class":314},[204,2099,2100],{"class":214},"drizzle-orm\u002Fsqlite-core",[204,2102,1364],{"class":314},[204,2104,2105],{"class":206,"line":343},[204,2106,1445],{"emptyLinePlaceholder":1444},[204,2108,2109,2111,2114,2117,2119,2121,2123,2125,2127,2129,2131],{"class":206,"line":364},[204,2110,944],{"class":943},[204,2112,2113],{"class":323}," const",[204,2115,2116],{"class":963}," things ",[204,2118,1456],{"class":314},[204,2120,2081],{"class":950},[204,2122,964],{"class":963},[204,2124,988],{"class":314},[204,2126,1851],{"class":214},[204,2128,988],{"class":314},[204,2130,431],{"class":314},[204,2132,397],{"class":314},[204,2134,2135,2138,2140,2142,2145,2147,2150,2152,2155,2158,2160,2162,2164,2166],{"class":206,"line":385},[204,2136,2137],{"class":668},"  id",[204,2139,330],{"class":314},[204,2141,2091],{"class":950},[204,2143,2144],{"class":963},"()",[204,2146,185],{"class":314},[204,2148,2149],{"class":950},"primaryKey",[204,2151,964],{"class":963},[204,2153,2154],{"class":314},"{",[204,2156,2157],{"class":668}," autoIncrement",[204,2159,330],{"class":314},[204,2161,1126],{"class":1125},[204,2163,1354],{"class":314},[204,2165,1508],{"class":963},[204,2167,340],{"class":314},[204,2169,2170,2173,2175,2177,2179,2181,2184,2186],{"class":206,"line":400},[204,2171,2172],{"class":668},"  name",[204,2174,330],{"class":314},[204,2176,2086],{"class":950},[204,2178,2144],{"class":963},[204,2180,185],{"class":314},[204,2182,2183],{"class":950},"notNull",[204,2185,2144],{"class":963},[204,2187,340],{"class":314},[204,2189,2190,2192],{"class":206,"line":469},[204,2191,1143],{"class":314},[204,2193,1146],{"class":963},[195,2195,2197],{"className":934,"code":2196,"language":936,"meta":200,"style":200},"\u002F\u002F src\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.postgresql.ts\nimport { pgTable, text, serial } from 'drizzle-orm\u002Fpg-core'\n\nexport const things = pgTable('things', {\n  id: serial().primaryKey(),\n  name: text().notNull(),\n})\n",[171,2198,2199,2204,2233,2237,2261,2279,2297],{"__ignoreMap":200},[204,2200,2201],{"class":206,"line":207},[204,2202,2203],{"class":1137},"\u002F\u002F src\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.postgresql.ts\n",[204,2205,2206,2208,2210,2213,2215,2217,2219,2222,2224,2226,2228,2231],{"class":206,"line":224},[204,2207,436],{"class":943},[204,2209,412],{"class":314},[204,2211,2212],{"class":963}," pgTable",[204,2214,431],{"class":314},[204,2216,2086],{"class":963},[204,2218,431],{"class":314},[204,2220,2221],{"class":963}," serial",[204,2223,1354],{"class":314},[204,2225,1357],{"class":943},[204,2227,983],{"class":314},[204,2229,2230],{"class":214},"drizzle-orm\u002Fpg-core",[204,2232,1364],{"class":314},[204,2234,2235],{"class":206,"line":343},[204,2236,1445],{"emptyLinePlaceholder":1444},[204,2238,2239,2241,2243,2245,2247,2249,2251,2253,2255,2257,2259],{"class":206,"line":364},[204,2240,944],{"class":943},[204,2242,2113],{"class":323},[204,2244,2116],{"class":963},[204,2246,1456],{"class":314},[204,2248,2212],{"class":950},[204,2250,964],{"class":963},[204,2252,988],{"class":314},[204,2254,1851],{"class":214},[204,2256,988],{"class":314},[204,2258,431],{"class":314},[204,2260,397],{"class":314},[204,2262,2263,2265,2267,2269,2271,2273,2275,2277],{"class":206,"line":385},[204,2264,2137],{"class":668},[204,2266,330],{"class":314},[204,2268,2221],{"class":950},[204,2270,2144],{"class":963},[204,2272,185],{"class":314},[204,2274,2149],{"class":950},[204,2276,2144],{"class":963},[204,2278,340],{"class":314},[204,2280,2281,2283,2285,2287,2289,2291,2293,2295],{"class":206,"line":400},[204,2282,2172],{"class":668},[204,2284,330],{"class":314},[204,2286,2086],{"class":950},[204,2288,2144],{"class":963},[204,2290,185],{"class":314},[204,2292,2183],{"class":950},[204,2294,2144],{"class":963},[204,2296,340],{"class":314},[204,2298,2299,2301],{"class":206,"line":469},[204,2300,1143],{"class":314},[204,2302,1146],{"class":963},[159,2304,2305,2306,185],{},"Register the file as in the checklist above. Every table export is picked up. The files are parsed as text, so keep\nthem to imports and table calls, as described under\n",[163,2307,2309],{"href":2308},"\u002Fmodules\u002Fmodule-kit#constraints-of-schema-files","Constraints of schema files",[159,2311,2312],{},"Add a parity test, so the dialects cannot drift:",[195,2314,2316],{"className":934,"code":2315,"language":936,"meta":200,"style":200},"import { it } from 'vitest'\nimport { expectSchemaParity } from '@frigear-nu\u002Fmodule-kit\u002Ftesting'\nimport * as sqlite from '..\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.sqlite'\nimport * as postgresql from '..\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.postgresql'\n\nit('schema.postgresql matches schema.sqlite', () => expectSchemaParity(sqlite, postgresql))\n",[171,2317,2318,2337,2357,2380,2400,2404],{"__ignoreMap":200},[204,2319,2320,2322,2324,2327,2329,2331,2333,2335],{"class":206,"line":207},[204,2321,436],{"class":943},[204,2323,412],{"class":314},[204,2325,2326],{"class":963}," it",[204,2328,1354],{"class":314},[204,2330,1357],{"class":943},[204,2332,983],{"class":314},[204,2334,1242],{"class":214},[204,2336,1364],{"class":314},[204,2338,2339,2341,2343,2346,2348,2350,2352,2355],{"class":206,"line":224},[204,2340,436],{"class":943},[204,2342,412],{"class":314},[204,2344,2345],{"class":963}," expectSchemaParity",[204,2347,1354],{"class":314},[204,2349,1357],{"class":943},[204,2351,983],{"class":314},[204,2353,2354],{"class":214},"@frigear-nu\u002Fmodule-kit\u002Ftesting",[204,2356,1364],{"class":314},[204,2358,2359,2361,2364,2367,2370,2373,2375,2378],{"class":206,"line":343},[204,2360,436],{"class":943},[204,2362,2363],{"class":314}," *",[204,2365,2366],{"class":943}," as",[204,2368,2369],{"class":963}," sqlite ",[204,2371,2372],{"class":943},"from",[204,2374,983],{"class":314},[204,2376,2377],{"class":214},"..\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.sqlite",[204,2379,1364],{"class":314},[204,2381,2382,2384,2386,2388,2391,2393,2395,2398],{"class":206,"line":364},[204,2383,436],{"class":943},[204,2385,2363],{"class":314},[204,2387,2366],{"class":943},[204,2389,2390],{"class":963}," postgresql ",[204,2392,2372],{"class":943},[204,2394,983],{"class":314},[204,2396,2397],{"class":214},"..\u002Fsrc\u002Fruntime\u002Fserver\u002Fdb\u002Fschema.postgresql",[204,2399,1364],{"class":314},[204,2401,2402],{"class":206,"line":385},[204,2403,1445],{"emptyLinePlaceholder":1444},[204,2405,2406,2409,2411,2413,2416,2418,2420,2423,2425,2427,2430,2432],{"class":206,"line":400},[204,2407,2408],{"class":950},"it",[204,2410,964],{"class":963},[204,2412,988],{"class":314},[204,2414,2415],{"class":214},"schema.postgresql matches schema.sqlite",[204,2417,988],{"class":314},[204,2419,431],{"class":314},[204,2421,2422],{"class":314}," ()",[204,2424,1956],{"class":323},[204,2426,2345],{"class":950},[204,2428,2429],{"class":963},"(sqlite",[204,2431,431],{"class":314},[204,2433,2434],{"class":963}," postgresql))\n",[187,2436,2438],{"id":2437},"extend-another-modules-table","Extend another module's table",[159,2440,2441,2442,2445],{},"To add columns to a table that another module owns, for example ",[171,2443,2444],{},"users",", ship the columns as an exported table of the\nsame name and register the file. The columns arrive in every app that installs both modules, and nothing happens when\nthe owner is absent:",[195,2447,2449],{"className":934,"code":2448,"language":936,"meta":200,"style":200},"\u002F\u002F in setup()\nextendDatabaseTable(nuxt, {\n  resolver,\n  file: dialect => `.\u002Fruntime\u002Fserver\u002Fdb\u002Fusers.${dialect}`,\n})\n",[171,2450,2451,2456,2468,2475,2499],{"__ignoreMap":200},[204,2452,2453],{"class":206,"line":207},[204,2454,2455],{"class":1137},"\u002F\u002F in setup()\n",[204,2457,2458,2461,2464,2466],{"class":206,"line":224},[204,2459,2460],{"class":950},"extendDatabaseTable",[204,2462,2463],{"class":963},"(nuxt",[204,2465,431],{"class":314},[204,2467,397],{"class":314},[204,2469,2470,2473],{"class":206,"line":343},[204,2471,2472],{"class":963},"  resolver",[204,2474,340],{"class":314},[204,2476,2477,2480,2482,2484,2486,2488,2491,2493,2495,2497],{"class":206,"line":364},[204,2478,2479],{"class":950},"  file",[204,2481,330],{"class":314},[204,2483,1953],{"class":1499},[204,2485,1956],{"class":323},[204,2487,1959],{"class":314},[204,2489,2490],{"class":214},".\u002Fruntime\u002Fserver\u002Fdb\u002Fusers.",[204,2492,1965],{"class":314},[204,2494,1968],{"class":963},[204,2496,1971],{"class":314},[204,2498,340],{"class":314},[204,2500,2501,2503],{"class":206,"line":385},[204,2502,1143],{"class":314},[204,2504,1146],{"class":963},[195,2506,2508],{"className":934,"code":2507,"language":936,"meta":200,"style":200},"\u002F\u002F src\u002Fruntime\u002Fserver\u002Fdb\u002Fusers.sqlite.ts\nimport { sqliteTable, text } from 'drizzle-orm\u002Fsqlite-core'\n\nexport const users = sqliteTable('users', {\n  nickname: text(),\n})\n",[171,2509,2510,2515,2537,2541,2566,2579],{"__ignoreMap":200},[204,2511,2512],{"class":206,"line":207},[204,2513,2514],{"class":1137},"\u002F\u002F src\u002Fruntime\u002Fserver\u002Fdb\u002Fusers.sqlite.ts\n",[204,2516,2517,2519,2521,2523,2525,2527,2529,2531,2533,2535],{"class":206,"line":224},[204,2518,436],{"class":943},[204,2520,412],{"class":314},[204,2522,2081],{"class":963},[204,2524,431],{"class":314},[204,2526,2086],{"class":963},[204,2528,1354],{"class":314},[204,2530,1357],{"class":943},[204,2532,983],{"class":314},[204,2534,2100],{"class":214},[204,2536,1364],{"class":314},[204,2538,2539],{"class":206,"line":343},[204,2540,1445],{"emptyLinePlaceholder":1444},[204,2542,2543,2545,2547,2550,2552,2554,2556,2558,2560,2562,2564],{"class":206,"line":364},[204,2544,944],{"class":943},[204,2546,2113],{"class":323},[204,2548,2549],{"class":963}," users ",[204,2551,1456],{"class":314},[204,2553,2081],{"class":950},[204,2555,964],{"class":963},[204,2557,988],{"class":314},[204,2559,2444],{"class":214},[204,2561,988],{"class":314},[204,2563,431],{"class":314},[204,2565,397],{"class":314},[204,2567,2568,2571,2573,2575,2577],{"class":206,"line":385},[204,2569,2570],{"class":668},"  nickname",[204,2572,330],{"class":314},[204,2574,2086],{"class":950},[204,2576,2144],{"class":963},[204,2578,340],{"class":314},[204,2580,2581,2583],{"class":206,"line":400},[204,2582,1143],{"class":314},[204,2584,1146],{"class":963},[159,2586,2587,2588,2591,2592,2594],{},"Ship a ",[171,2589,2590],{},"users.postgresql.ts"," too. Because ",[171,2593,2460],{}," only changes the generated schema, document that host\napps must generate and commit a migration; your own fixtures need one as well (next section).",[187,2596,2598],{"id":2597},"test-the-module","Test the module",[159,2600,2601,2602,2605],{},"Tests run with Vitest and ",[171,2603,2604],{},"@nuxt\u002Ftest-utils",". A fixture is a minimal Nuxt app that installs the module from source:",[195,2607,2609],{"className":934,"code":2608,"language":936,"meta":200,"style":200},"\u002F\u002F test\u002Ffixtures\u002Fbasic\u002Fnuxt.config.ts\nimport MyModule from '..\u002F..\u002F..\u002Fsrc\u002Fmodule'\n\nexport default defineNuxtConfig({\n  modules: ['@nuxthub\u002Fcore', MyModule],\n  runtimeConfig: { session: { password: 'a-test-only-session-password-at-least-32-chars' } },\n  hub: { db: { dialect: 'sqlite', driver: 'libsql', applyMigrationsDuringBuild: false } },\n})\n",[171,2610,2611,2616,2632,2636,2649,2671,2703,2758],{"__ignoreMap":200},[204,2612,2613],{"class":206,"line":207},[204,2614,2615],{"class":1137},"\u002F\u002F test\u002Ffixtures\u002Fbasic\u002Fnuxt.config.ts\n",[204,2617,2618,2620,2623,2625,2627,2630],{"class":206,"line":224},[204,2619,436],{"class":943},[204,2621,2622],{"class":963}," MyModule ",[204,2624,2372],{"class":943},[204,2626,983],{"class":314},[204,2628,2629],{"class":214},"..\u002F..\u002F..\u002Fsrc\u002Fmodule",[204,2631,1364],{"class":314},[204,2633,2634],{"class":206,"line":343},[204,2635,1445],{"emptyLinePlaceholder":1444},[204,2637,2638,2640,2642,2645,2647],{"class":206,"line":364},[204,2639,944],{"class":943},[204,2641,947],{"class":943},[204,2643,2644],{"class":950}," defineNuxtConfig",[204,2646,964],{"class":963},[204,2648,315],{"class":314},[204,2650,2651,2654,2656,2658,2660,2662,2664,2666,2669],{"class":206,"line":385},[204,2652,2653],{"class":668},"  modules",[204,2655,330],{"class":314},[204,2657,587],{"class":963},[204,2659,988],{"class":314},[204,2661,1021],{"class":214},[204,2663,988],{"class":314},[204,2665,431],{"class":314},[204,2667,2668],{"class":963}," MyModule]",[204,2670,340],{"class":314},[204,2672,2673,2676,2678,2680,2683,2685,2687,2690,2692,2694,2697,2699,2701],{"class":206,"line":400},[204,2674,2675],{"class":668},"  runtimeConfig",[204,2677,330],{"class":314},[204,2679,412],{"class":314},[204,2681,2682],{"class":668}," session",[204,2684,330],{"class":314},[204,2686,412],{"class":314},[204,2688,2689],{"class":668}," password",[204,2691,330],{"class":314},[204,2693,983],{"class":314},[204,2695,2696],{"class":214},"a-test-only-session-password-at-least-32-chars",[204,2698,988],{"class":314},[204,2700,1354],{"class":314},[204,2702,466],{"class":314},[204,2704,2705,2708,2710,2712,2715,2717,2719,2721,2723,2725,2728,2730,2732,2735,2737,2739,2742,2744,2746,2749,2751,2754,2756],{"class":206,"line":469},[204,2706,2707],{"class":668},"  hub",[204,2709,330],{"class":314},[204,2711,412],{"class":314},[204,2713,2714],{"class":668}," db",[204,2716,330],{"class":314},[204,2718,412],{"class":314},[204,2720,1953],{"class":668},[204,2722,330],{"class":314},[204,2724,983],{"class":314},[204,2726,2727],{"class":214},"sqlite",[204,2729,988],{"class":314},[204,2731,431],{"class":314},[204,2733,2734],{"class":668}," driver",[204,2736,330],{"class":314},[204,2738,983],{"class":314},[204,2740,2741],{"class":214},"libsql",[204,2743,988],{"class":314},[204,2745,431],{"class":314},[204,2747,2748],{"class":668}," applyMigrationsDuringBuild",[204,2750,330],{"class":314},[204,2752,2753],{"class":1125}," false",[204,2755,1354],{"class":314},[204,2757,466],{"class":314},[204,2759,2760,2762],{"class":206,"line":482},[204,2761,1143],{"class":314},[204,2763,1146],{"class":963},[195,2765,2767],{"className":934,"code":2766,"language":936,"meta":200,"style":200},"\u002F\u002F test\u002Fbasic.test.ts\nimport { fileURLToPath } from 'node:url'\nimport { describe, expect, it } from 'vitest'\nimport { $fetch, setup } from '@nuxt\u002Ftest-utils\u002Fe2e'\n\ndescribe('my-module', async () => {\n  await setup({ rootDir: fileURLToPath(new URL('.\u002Ffixtures\u002Fbasic', import.meta.url)) })\n\n  it('renders', async () => {\n    expect(await $fetch('\u002F')).toContain('basic')\n  })\n})\n",[171,2768,2769,2774,2794,2822,2847,2851,2875,2930,2934,2958,2998,3005],{"__ignoreMap":200},[204,2770,2771],{"class":206,"line":207},[204,2772,2773],{"class":1137},"\u002F\u002F test\u002Fbasic.test.ts\n",[204,2775,2776,2778,2780,2783,2785,2787,2789,2792],{"class":206,"line":224},[204,2777,436],{"class":943},[204,2779,412],{"class":314},[204,2781,2782],{"class":963}," fileURLToPath",[204,2784,1354],{"class":314},[204,2786,1357],{"class":943},[204,2788,983],{"class":314},[204,2790,2791],{"class":214},"node:url",[204,2793,1364],{"class":314},[204,2795,2796,2798,2800,2803,2805,2808,2810,2812,2814,2816,2818,2820],{"class":206,"line":343},[204,2797,436],{"class":943},[204,2799,412],{"class":314},[204,2801,2802],{"class":963}," describe",[204,2804,431],{"class":314},[204,2806,2807],{"class":963}," expect",[204,2809,431],{"class":314},[204,2811,2326],{"class":963},[204,2813,1354],{"class":314},[204,2815,1357],{"class":943},[204,2817,983],{"class":314},[204,2819,1242],{"class":214},[204,2821,1364],{"class":314},[204,2823,2824,2826,2828,2831,2833,2836,2838,2840,2842,2845],{"class":206,"line":364},[204,2825,436],{"class":943},[204,2827,412],{"class":314},[204,2829,2830],{"class":963}," $fetch",[204,2832,431],{"class":314},[204,2834,2835],{"class":963}," setup",[204,2837,1354],{"class":314},[204,2839,1357],{"class":943},[204,2841,983],{"class":314},[204,2843,2844],{"class":214},"@nuxt\u002Ftest-utils\u002Fe2e",[204,2846,1364],{"class":314},[204,2848,2849],{"class":206,"line":385},[204,2850,1445],{"emptyLinePlaceholder":1444},[204,2852,2853,2856,2858,2860,2862,2864,2866,2869,2871,2873],{"class":206,"line":400},[204,2854,2855],{"class":950},"describe",[204,2857,964],{"class":963},[204,2859,988],{"class":314},[204,2861,1685],{"class":214},[204,2863,988],{"class":314},[204,2865,431],{"class":314},[204,2867,2868],{"class":323}," async",[204,2870,2422],{"class":314},[204,2872,1956],{"class":323},[204,2874,397],{"class":314},[204,2876,2877,2880,2882,2884,2886,2889,2891,2893,2895,2898,2901,2903,2905,2908,2910,2912,2915,2917,2919,2921,2923,2926,2928],{"class":206,"line":469},[204,2878,2879],{"class":943},"  await",[204,2881,2835],{"class":950},[204,2883,964],{"class":668},[204,2885,2154],{"class":314},[204,2887,2888],{"class":668}," rootDir",[204,2890,330],{"class":314},[204,2892,2782],{"class":950},[204,2894,964],{"class":668},[204,2896,2897],{"class":314},"new",[204,2899,2900],{"class":950}," URL",[204,2902,964],{"class":668},[204,2904,988],{"class":314},[204,2906,2907],{"class":214},".\u002Ffixtures\u002Fbasic",[204,2909,988],{"class":314},[204,2911,431],{"class":314},[204,2913,2914],{"class":943}," import",[204,2916,185],{"class":314},[204,2918,1532],{"class":963},[204,2920,185],{"class":314},[204,2922,1537],{"class":963},[204,2924,2925],{"class":668},")) ",[204,2927,1143],{"class":314},[204,2929,1146],{"class":668},[204,2931,2932],{"class":206,"line":482},[204,2933,1445],{"emptyLinePlaceholder":1444},[204,2935,2936,2939,2941,2943,2946,2948,2950,2952,2954,2956],{"class":206,"line":503},[204,2937,2938],{"class":950},"  it",[204,2940,964],{"class":668},[204,2942,988],{"class":314},[204,2944,2945],{"class":214},"renders",[204,2947,988],{"class":314},[204,2949,431],{"class":314},[204,2951,2868],{"class":323},[204,2953,2422],{"class":314},[204,2955,1956],{"class":323},[204,2957,397],{"class":314},[204,2959,2960,2963,2965,2968,2970,2972,2974,2977,2979,2982,2984,2987,2989,2991,2994,2996],{"class":206,"line":522},[204,2961,2962],{"class":950},"    expect",[204,2964,964],{"class":668},[204,2966,2967],{"class":943},"await",[204,2969,2830],{"class":950},[204,2971,964],{"class":668},[204,2973,988],{"class":314},[204,2975,2976],{"class":214},"\u002F",[204,2978,988],{"class":314},[204,2980,2981],{"class":668},"))",[204,2983,185],{"class":314},[204,2985,2986],{"class":950},"toContain",[204,2988,964],{"class":668},[204,2990,988],{"class":314},[204,2992,2993],{"class":214},"basic",[204,2995,988],{"class":314},[204,2997,1146],{"class":668},[204,2999,3000,3003],{"class":206,"line":540},[204,3001,3002],{"class":314},"  }",[204,3004,1146],{"class":668},[204,3006,3007,3009],{"class":206,"line":546},[204,3008,1143],{"class":314},[204,3010,1146],{"class":963},[159,3012,3013],{},"Run from the repository root, never from inside the package:",[195,3015,3017],{"className":197,"code":3016,"language":199,"meta":200,"style":200},"pnpm --filter @frigear-nu\u002Fmy-module lint\npnpm --filter @frigear-nu\u002Fmy-module test\n",[171,3018,3019,3032],{"__ignoreMap":200},[204,3020,3021,3023,3026,3029],{"class":206,"line":207},[204,3022,211],{"class":210},[204,3024,3025],{"class":214}," --filter",[204,3027,3028],{"class":214}," @frigear-nu\u002Fmy-module",[204,3030,3031],{"class":214}," lint\n",[204,3033,3034,3036,3038,3040],{"class":206,"line":224},[204,3035,211],{"class":210},[204,3037,3025],{"class":214},[204,3039,3028],{"class":214},[204,3041,3042],{"class":214}," test\n",[3044,3045,3047],"h3",{"id":3046},"fixtures-with-a-database","Fixtures with a database",[159,3049,3050,3051,3055,3056,3059,3060,3062],{},"A fixture whose tests touch the database needs committed migrations for the ",[3052,3053,3054],"strong",{},"merged"," schema: your tables plus the\ncolumns every extending module adds, and the ",[171,3057,3058],{},"auth_user_tokens"," table when the fixture includes a module that uses\n",[171,3061,2032],{},". The recipe:",[3064,3065,3066,3073,3112,3125],"ol",{},[1268,3067,3068,3069,3072],{},"Add the modules to the fixture's ",[171,3070,3071],{},"nuxt.config.ts"," (test-only session password, local libsql database).",[1268,3074,3075,3076],{},"Generate the migrations, review them and commit the SQL together with the snapshot and journal:",[195,3077,3079],{"className":197,"code":3078,"language":199,"meta":200,"style":200},"pnpm --filter @frigear-nu\u002Fmy-module exec nuxt db generate --cwd \"$PWD\u002Fpackages\u002Fmy-module\u002Ftest\u002Ffixtures\u002F\u003Cfixture>\"\n",[171,3080,3081],{"__ignoreMap":200},[204,3082,3083,3085,3087,3089,3092,3094,3096,3099,3102,3104,3107,3110],{"class":206,"line":207},[204,3084,211],{"class":210},[204,3086,3025],{"class":214},[204,3088,3028],{"class":214},[204,3090,3091],{"class":214}," exec",[204,3093,1505],{"class":214},[204,3095,2714],{"class":214},[204,3097,3098],{"class":214}," generate",[204,3100,3101],{"class":214}," --cwd",[204,3103,333],{"class":314},[204,3105,3106],{"class":963},"$PWD",[204,3108,3109],{"class":214},"\u002Fpackages\u002Fmy-module\u002Ftest\u002Ffixtures\u002F\u003Cfixture>",[204,3111,537],{"class":314},[1268,3113,3114,3115,1287,3118,3120,3121,3124],{},"Run the suite with ",[171,3116,3117],{},"dev: true",[171,3119,1290],{}," so NuxtHub applies the migrations on startup, and delete the fixture's\n",[171,3122,3123],{},".data"," directory before and after.",[1268,3126,3127,3128,3131],{},"After any schema change, run the same command again. ",[171,3129,3130],{},"No schema changes, nothing to migrate"," means the fixture is in\nsync.",[159,3133,3134,3135,3138,3139,3142,3143,1225,3146,2007,3149,3152,3153,2007,3156,3159,3160,185],{},"The command, its ",[171,3136,3137],{},"--cwd"," rule, how to name a migration and the fixture requirements are in\n",[163,3140,101],{"href":3141},"\u002Fmodules\u002Fmodule-kit#migrations-and-database-backed-module-tests",". Working examples are the\n",[171,3144,3145],{},"self-service",[171,3147,3148],{},"admin-db",[171,3150,3151],{},"magic-link-db"," fixtures of ",[171,3154,3155],{},"packages\u002Fusers",[171,3157,3158],{},"auth-db"," of ",[171,3161,3162],{},"packages\u002Fauth",[187,3164,3166],{"id":3165},"document-and-release","Document and release",[1265,3168,3169,3188,3203],{},[1268,3170,3171,3172,3175,3176,3181,3182,3184,3185,185],{},"Add a page under ",[171,3173,3174],{},"apps\u002Fdocs\u002Fcontent\u002F4.modules\u002F"," using the module page layout from the\n",[163,3177,3180],{"href":3178,"rel":3179},"https:\u002F\u002Fgithub.com\u002FFrigear-nu\u002Ffrigear-nu\u002Fblob\u002Fmain\u002Fapps\u002Fdocs\u002FREADME.md#documentation-conventions",[167],"docs README",", and\na row in ",[163,3183,60],{"href":61}," and the root ",[171,3186,3187],{},"README.md",[1268,3189,3190,3191,3194,3195,3198,3199,3202],{},"Copy a sibling's ",[171,3192,3193],{},".release-it.json",", change the package name and tag, and add the package to the ",[171,3196,3197],{},"release.yml","\nworkflow. ",[163,3200,3201],{"href":22},"Publishing packages"," covers versioning, the workflow and resuming an\ninterrupted publish.",[1268,3204,3205,3206,1225,3209,2007,3212,3215,3216,3219,3220,3222],{},"Before opening a pull request run ",[171,3207,3208],{},"pnpm lint",[171,3210,3211],{},"pnpm typecheck",[171,3213,3214],{},"pnpm test"," from the repository root, and\n",[171,3217,3218],{},"pnpm build"," for anything that touches ",[171,3221,390],{}," or build tooling.",[3224,3225,3226],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":200,"searchDepth":224,"depth":224,"links":3228},[3229,3230,3231,3232,3233,3235,3236,3237,3240],{"id":189,"depth":224,"text":190},{"id":254,"depth":224,"text":255},{"id":284,"depth":224,"text":287},{"id":923,"depth":224,"text":924},{"id":1316,"depth":224,"text":3234},"The setup() checklist",{"id":2058,"depth":224,"text":2059},{"id":2437,"depth":224,"text":2438},{"id":2597,"depth":224,"text":2598,"children":3238},[3239],{"id":3046,"depth":343,"text":3047},{"id":3165,"depth":224,"text":3166},"Scaffold a new Frigear Nuxt module, wire it into the workspace with module-kit, give it a database table, test it and release it.","md",null,{},{"icon":29},{"title":26,"description":3241},"Zjo6Xc8yKN2ZLEt2pba4TFJSOw9FdPC1A_cr4WKi8BI",[3249,3251],{"title":21,"path":22,"stem":23,"description":3250,"icon":24,"children":-1},"Release a workspace package to npm with release-it or the Release workflow, and resume an interrupted publish.",{"title":31,"path":32,"stem":33,"description":3252,"icon":34,"children":-1},"How screens are built so the app stays predictable as modules are added - the layouts, list and detail pages, forms, destructive actions and text conventions.",1792824490890]