[{"data":1,"prerenderedAt":2114},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fcontribute\u002Fapi-design\u002F":3,"docs-nav":1661},{"id":4,"title":5,"body":6,"description":130,"extension":1650,"layout":1651,"meta":1652,"navGroup":1651,"navGroupOrder":1651,"navOrder":1651,"navTitle":1653,"navigation":1004,"originalPath":1654,"path":1655,"redirect":1651,"seo":1656,"stem":1657,"updated":1658,"version":1659,"__hash__":1660},"docs\u002Fdocs\u002Fcontribute\u002Fapi-design.md","HTTP API of the FlowFuse platform",{"type":7,"value":8,"toc":1624},"minimark",[9,13,18,27,40,43,65,68,86,90,97,105,118,124,231,235,240,243,254,258,261,270,274,277,286,290,297,300,307,311,322,413,417,428,433,447,451,458,467,471,484,488,494,497,504,510,611,615,618,667,673,676,693,696,703,709,713,716,720,723,752,755,839,844,859,867,879,884,887,901,911,915,918,925,933,936,939,945,949,952,958,961,1026,1032,1043,1049,1082,1085,1103,1124,1620],[10,11,5],"h1",{"id":12},"http-api-of-the-flowfuse-platform",[14,15,17],"h2",{"id":16},"api-documentation","API documentation",[19,20,21,22,26],"p",{},"All public API routes should include a ",[23,24,25],"code",{},"schema"," as part of their definition. This\nserves a number of purposes:",[28,29,30,34,37],"ul",{},[31,32,33],"li",{},"It will be included in the auto-generated OpenAPI 3.0 spec",[31,35,36],{},"Fastify will validate requests include any required properties",[31,38,39],{},"Fastify will ensure the response object matches the defined schema",[19,41,42],{},"Some general guidance:",[28,44,45,48,55,62],{},[31,46,47],{},"Ensure the routes have an appropriate tag set - this determines where in the\nSwagger UI it gets displayed.",[31,49,50,51,54],{},"Ensure the tag is listed in ",[23,52,53],{},"forge\u002Froutes\u002Fapi-docs.js"," so it appears in the right place",[31,56,57,58,61],{},"We define view schemas under ",[23,59,60],{},"forge\u002Fdb\u002Fviews\u002F*"," alongside the code that generates the view.\nKeep the naming consistent with other views.",[31,63,64],{},"Learn from the existing schemas - be consistent in style.",[19,66,67],{},"References:",[28,69,70,79],{},[31,71,72],{},[73,74,78],"a",{"href":75,"rel":76},"https:\u002F\u002Ffastify.dev\u002Fdocs\u002Flatest\u002FReference\u002FValidation-and-Serialization",[77],"nofollow","Fastify Validation and Serialization",[31,80,81],{},[73,82,85],{"href":83,"rel":84},"https:\u002F\u002Fswagger.io\u002Fspecification\u002F",[77],"OpenAPI 3.0 spec",[14,87,89],{"id":88},"object-ids","Object Ids",[19,91,92,93,96],{},"Most database models have a primary key of an auto-incrementing integer stored in\nthe ",[23,94,95],{},"id"," column.",[19,98,99,100,104],{},"These ids are internal properties of the models and should ",[101,102,103],"em",{},"not"," be exposed via the\nAPI. This is because they can be guessed and leak information about how many instances\nof any particular model exist.",[19,106,107,108,111,112,114,115,117],{},"All model instances have an auto-generated ",[23,109,110],{},"hashid"," property that is an encoded version\nof the ",[23,113,95],{}," property. This property should be used on the API but aliased as the\n",[23,116,95],{}," property.",[19,119,120,121,123],{},"Each database model has a pair of helper functions to encode and decode hashids\nto\u002Ffrom the true ",[23,122,95],{}," value:",[125,126,131],"pre",{"className":127,"code":128,"language":129,"meta":130,"style":130},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const encodedHashid = app.db.models.User.encodeHashid(123);\nconst objectId = app.db.models.User.decodeHashid(\"edjEbo2K1w\")\n","js","",[23,132,133,188],{"__ignoreMap":130},[134,135,138,142,146,150,153,156,159,161,164,166,169,171,175,178,182,185],"span",{"class":136,"line":137},"line",1,[134,139,141],{"class":140},"spNyl","const",[134,143,145],{"class":144},"sTEyZ"," encodedHashid ",[134,147,149],{"class":148},"sMK4o","=",[134,151,152],{"class":144}," app",[134,154,155],{"class":148},".",[134,157,158],{"class":144},"db",[134,160,155],{"class":148},[134,162,163],{"class":144},"models",[134,165,155],{"class":148},[134,167,168],{"class":144},"User",[134,170,155],{"class":148},[134,172,174],{"class":173},"s2Zo4","encodeHashid",[134,176,177],{"class":144},"(",[134,179,181],{"class":180},"sbssI","123",[134,183,184],{"class":144},")",[134,186,187],{"class":148},";\n",[134,189,191,193,196,198,200,202,204,206,208,210,212,214,217,219,222,226,228],{"class":136,"line":190},2,[134,192,141],{"class":140},[134,194,195],{"class":144}," objectId ",[134,197,149],{"class":148},[134,199,152],{"class":144},[134,201,155],{"class":148},[134,203,158],{"class":144},[134,205,155],{"class":148},[134,207,163],{"class":144},[134,209,155],{"class":148},[134,211,168],{"class":144},[134,213,155],{"class":148},[134,215,216],{"class":173},"decodeHashid",[134,218,177],{"class":144},[134,220,221],{"class":148},"\"",[134,223,225],{"class":224},"sfazB","edjEbo2K1w",[134,227,221],{"class":148},[134,229,230],{"class":144},")\n",[14,232,234],{"id":233},"api-path-design","API Path design",[236,237,239],"h3",{"id":238},"admin-routes","Admin routes",[19,241,242],{},"All admin-only routes exist under:",[125,244,248],{"className":245,"code":246,"language":247,"meta":130,"style":130},"language-txt shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002Fapi\u002Fv1\u002Fadmin\u002F...\n","txt",[23,249,250],{"__ignoreMap":130},[134,251,252],{"class":136,"line":137},[134,253,246],{},[236,255,257],{"id":256},"logged-in-user-routes","Logged-in user routes",[19,259,260],{},"All routes relating to the logged-in user exist under:",[125,262,264],{"className":245,"code":263,"language":247,"meta":130,"style":130},"\u002Fapi\u002Fv1\u002Fuser\u002F...\n",[23,265,266],{"__ignoreMap":130},[134,267,268],{"class":136,"line":137},[134,269,263],{},[236,271,273],{"id":272},"object-collection-routes","Object collection routes",[19,275,276],{},"API routes that are related to objects in collections follow the pattern:",[125,278,280],{"className":245,"code":279,"language":247,"meta":130,"style":130},"\u002Fapi\u002Fv1\u002F\u003Cplural-noun>\u002F\u003Cinstance-id>\u002F...\n",[23,281,282],{"__ignoreMap":130},[134,283,284],{"class":136,"line":137},[134,285,279],{},[14,287,289],{"id":288},"implementing-routes","Implementing routes",[19,291,292,293,296],{},"All API routes exist under ",[23,294,295],{},"forge\u002Froutes\u002Fapi"," in the repository, grouped into\nfiles based on the entity\u002Ffunctionality the api is related to.",[19,298,299],{},"All requests will have already been validated to ensure they are being made with\na valid session for a logged in user, or an access token.",[19,301,302,303,306],{},"If there is a valid session, ",[23,304,305],{},"request.session.User"," will be the requesting user.",[236,308,310],{"id":309},"opening-a-route-to-anonymous-users","Opening a route to anonymous users",[19,312,313,314,317,318,321],{},"In rare cases, a route needs to be accessible to anonymous users. To by-pass\nthe built-in preHandler, you can set ",[23,315,316],{},"allowAnonymous"," on the routes ",[23,319,320],{},"config"," object:",[125,323,325],{"className":127,"code":324,"language":129,"meta":130,"style":130},"app.get('\u002F', { config: { allowAnonymous: true } }, async (request, reply) => {\n     ...\n})\n",[23,326,327,400,405],{"__ignoreMap":130},[134,328,329,332,334,337,339,342,345,347,350,353,357,360,362,365,367,371,374,377,380,383,387,389,392,394,397],{"class":136,"line":137},[134,330,331],{"class":144},"app",[134,333,155],{"class":148},[134,335,336],{"class":173},"get",[134,338,177],{"class":144},[134,340,341],{"class":148},"'",[134,343,344],{"class":224},"\u002F",[134,346,341],{"class":148},[134,348,349],{"class":148},",",[134,351,352],{"class":148}," {",[134,354,356],{"class":355},"swJcz"," config",[134,358,359],{"class":148},":",[134,361,352],{"class":148},[134,363,364],{"class":355}," allowAnonymous",[134,366,359],{"class":148},[134,368,370],{"class":369},"sfNiH"," true",[134,372,373],{"class":148}," }",[134,375,376],{"class":148}," },",[134,378,379],{"class":140}," async",[134,381,382],{"class":148}," (",[134,384,386],{"class":385},"sHdIc","request",[134,388,349],{"class":148},[134,390,391],{"class":385}," reply",[134,393,184],{"class":148},[134,395,396],{"class":140}," =>",[134,398,399],{"class":148}," {\n",[134,401,402],{"class":136,"line":190},[134,403,404],{"class":148},"     ...\n",[134,406,408,411],{"class":136,"line":407},3,[134,409,410],{"class":148},"}",[134,412,230],{"class":144},[236,414,416],{"id":415},"team-routes","Team routes",[19,418,419,420,423,424,427],{},"Routes under ",[23,421,422],{},"forge\u002Froutes\u002Fapi\u002Fteam.js"," that relate to a specific team,\nmust use ",[23,425,426],{},":teamId"," as the placeholder in the route. A request preHandler will\nuse that to ensure the requesting user has permission to access the instance.",[19,429,430,431,359],{},"The following properties will then be available on the ",[23,432,386],{},[28,434,435,441],{},[31,436,437,440],{},[23,438,439],{},"request.team"," - the team",[31,442,443,446],{},[23,444,445],{},"request.teamMembership"," - the requesting user's role on the team",[236,448,450],{"id":449},"project-routes","Project routes",[19,452,453,457],{},[454,455,456],"strong",{},"Note:"," In FlowForge 1.5 we started to replace the Project concept with that of Application\nand Instance. No changes have been made to the underlying APIs - that will be evaluated\nas part of 1.6.",[19,459,419,460,463,464,427],{},[23,461,462],{},"forge\u002Froutes\u002Fapi\u002Fproject.js"," that relate to a specific instance,\nmust use ",[23,465,466],{},":projectId",[19,468,430,469,359],{},[23,470,386],{},[28,472,473,479],{},[31,474,475,478],{},[23,476,477],{},"request.project"," - the instance (previously called \"project\")",[31,480,481,483],{},[23,482,445],{}," - the requesting user's role on the team that owns the instance",[236,485,487],{"id":486},"userrole-permissions","User\u002Frole permissions",[19,489,490,491,155],{},"Permissions are defined in ",[23,492,493],{},"forge\u002Froutes\u002Fauth\u002Fpermissions.js",[19,495,496],{},"Each permission specifies the role a user must have to have that permission.",[19,498,499,500,503],{},"If a route requires a particular permission, it can use ",[23,501,502],{},"app.needsPermission"," to\ngenerate a preHandler function that will ensure any requesting user has that\npermission.",[19,505,506,507,359],{},"For example, to add a user to a team, the requesting user needs to have\n",[23,508,509],{},"\"team:user:add\"",[125,511,513],{"className":127,"code":512,"language":129,"meta":130,"style":130},"app.post('\u002F', { preHandler: app.needsPermission(\"team:user:add\") }, async (request, reply) => {\n    \u002F\u002F This is defined under forge\u002Froutes\u002Fapi\u002FteamMembers.js - and is mounted\n    \u002F\u002F under the path `\u002Fapi\u002Fv1\u002Fteams\u002F:teamId\u002Fmembers\u002F`\n    \u002F\u002F Due to the team route preHandler, this means `request.teamMembership`\n    \u002F\u002F will be defined and will be used by the `needsPermission` handler\n});\n",[23,514,515,579,585,590,596,602],{"__ignoreMap":130},[134,516,517,519,521,524,526,528,530,532,534,536,539,541,543,545,548,550,552,555,557,560,563,565,567,569,571,573,575,577],{"class":136,"line":137},[134,518,331],{"class":144},[134,520,155],{"class":148},[134,522,523],{"class":173},"post",[134,525,177],{"class":144},[134,527,341],{"class":148},[134,529,344],{"class":224},[134,531,341],{"class":148},[134,533,349],{"class":148},[134,535,352],{"class":148},[134,537,538],{"class":355}," preHandler",[134,540,359],{"class":148},[134,542,152],{"class":144},[134,544,155],{"class":148},[134,546,547],{"class":173},"needsPermission",[134,549,177],{"class":144},[134,551,221],{"class":148},[134,553,554],{"class":224},"team:user:add",[134,556,221],{"class":148},[134,558,559],{"class":144},") ",[134,561,562],{"class":148},"},",[134,564,379],{"class":140},[134,566,382],{"class":148},[134,568,386],{"class":385},[134,570,349],{"class":148},[134,572,391],{"class":385},[134,574,184],{"class":148},[134,576,396],{"class":140},[134,578,399],{"class":148},[134,580,581],{"class":136,"line":190},[134,582,584],{"class":583},"sHwdD","    \u002F\u002F This is defined under forge\u002Froutes\u002Fapi\u002FteamMembers.js - and is mounted\n",[134,586,587],{"class":136,"line":407},[134,588,589],{"class":583},"    \u002F\u002F under the path `\u002Fapi\u002Fv1\u002Fteams\u002F:teamId\u002Fmembers\u002F`\n",[134,591,593],{"class":136,"line":592},4,[134,594,595],{"class":583},"    \u002F\u002F Due to the team route preHandler, this means `request.teamMembership`\n",[134,597,599],{"class":136,"line":598},5,[134,600,601],{"class":583},"    \u002F\u002F will be defined and will be used by the `needsPermission` handler\n",[134,603,605,607,609],{"class":136,"line":604},6,[134,606,410],{"class":148},[134,608,184],{"class":144},[134,610,187],{"class":148},[14,612,614],{"id":613},"error-formats","Error formats",[19,616,617],{},"If a route needs to return an error it should respond with a payload in the format:",[125,619,621],{"className":127,"code":620,"language":129,"meta":130,"style":130},"{\n    code: 'error_code',\n    error: 'Human-readable message'\n}\n",[23,622,623,628,647,662],{"__ignoreMap":130},[134,624,625],{"class":136,"line":137},[134,626,627],{"class":148},"{\n",[134,629,630,634,636,639,642,644],{"class":136,"line":190},[134,631,633],{"class":632},"sBMFI","    code",[134,635,359],{"class":148},[134,637,638],{"class":148}," '",[134,640,641],{"class":224},"error_code",[134,643,341],{"class":148},[134,645,646],{"class":148},",\n",[134,648,649,652,654,656,659],{"class":136,"line":407},[134,650,651],{"class":632},"    error",[134,653,359],{"class":148},[134,655,638],{"class":148},[134,657,658],{"class":224},"Human-readable message",[134,660,661],{"class":148},"'\n",[134,663,664],{"class":136,"line":592},[134,665,666],{"class":148},"}\n",[19,668,669,670,672],{},"The ",[23,671,23],{}," property should be a well-defined string that can be used to programmatically\nidentify the error without relying on the human-readable message.",[19,674,675],{},"There is a set of predefined codes that should be used where appropriate:",[28,677,678,683,688],{},[31,679,680],{},[23,681,682],{},"unauthorized",[31,684,685],{},[23,686,687],{},"invalid_request",[31,689,690],{},[23,691,692],{},"unexpected_error",[19,694,695],{},"If the error is related to an invalid option\u002Fparameter\u002Fobject selection, then the code\nshould be:",[28,697,698],{},[31,699,700],{},[23,701,702],{},"invalid_\u003Cname of property>",[19,704,705,706,155],{},"For example: ",[23,707,708],{},"invalid_project_name",[14,710,712],{"id":711},"pagination-search","Pagination & Search",[19,714,715],{},"All routes that return collections of things must use pagination to allow for\nfuture growth, and provide a way to search the collection.",[236,717,719],{"id":718},"pagination","Pagination",[19,721,722],{},"We use a cursor-based approach to our pagination. A cursor is a pointer to an entity\nin the collection and provides the starting point for what should be returned.",[28,724,725,736,746],{},[31,726,727,728,731,732,735],{},"End-points accept ",[23,729,730],{},"cursor"," and ",[23,733,734],{},"limit"," parameters",[31,737,738,739,741,742,745],{},"If ",[23,740,730],{}," is not provided, it returns from the beginning of the collection.\nFor some end-points, this will mean returning the most recent entries -\nthe ",[23,743,744],{},"\u002Fapi\u002Fv1\u002Fprojects\u002F:id\u002Flogs"," for example.",[31,747,748,749,751],{},"Each end-point should have a sensible default for the ",[23,750,734],{}," parameter",[19,753,754],{},"The response object for paginated end-points should have the format:",[125,756,758],{"className":127,"code":757,"language":129,"meta":130,"style":130},"{\n    \"meta\": {\n        \"next_cursor\": \"16416724188790000\",\n    },\n    \"\u003Cobject-type>\": [ ],\n    \"count\": 123\n}\n",[23,759,760,764,779,801,806,820,834],{"__ignoreMap":130},[134,761,762],{"class":136,"line":137},[134,763,627],{"class":148},[134,765,766,769,772,774,777],{"class":136,"line":190},[134,767,768],{"class":148},"    \"",[134,770,771],{"class":224},"meta",[134,773,221],{"class":148},[134,775,776],{"class":355},": ",[134,778,627],{"class":148},[134,780,781,784,787,789,791,794,797,799],{"class":136,"line":407},[134,782,783],{"class":148},"        \"",[134,785,786],{"class":355},"next_cursor",[134,788,221],{"class":148},[134,790,359],{"class":148},[134,792,793],{"class":148}," \"",[134,795,796],{"class":224},"16416724188790000",[134,798,221],{"class":148},[134,800,646],{"class":148},[134,802,803],{"class":136,"line":592},[134,804,805],{"class":148},"    },\n",[134,807,808,810,813,815,818],{"class":136,"line":598},[134,809,768],{"class":148},[134,811,812],{"class":224},"\u003Cobject-type>",[134,814,221],{"class":148},[134,816,817],{"class":355},": [ ]",[134,819,646],{"class":148},[134,821,822,824,827,829,831],{"class":136,"line":604},[134,823,768],{"class":148},[134,825,826],{"class":224},"count",[134,828,221],{"class":148},[134,830,776],{"class":355},[134,832,833],{"class":180},"123\n",[134,835,837],{"class":136,"line":836},7,[134,838,666],{"class":148},[19,840,669,841,843],{},[23,842,771],{}," property contains information to help the client navigate the collection.",[28,845,846,851],{},[31,847,848,850],{},[23,849,786],{}," - if set, provides the cursor to use to get the next page of results",[31,852,853,856,857,155],{},[23,854,855],{},"previous_cursor"," - if set, provides the cursor to use to get the previous page of results. Note\nthat not all end-points need to be navigable in both directions so may never return\n",[23,858,855],{},[19,860,669,861,863,864,155],{},[23,862,812],{}," property should be called the appropriate plural form of what is being returned,\nsuch as ",[23,865,866],{},"projects",[19,868,669,869,871,872,875,876,878],{},[23,870,826],{}," property is optional and indicates the total number of objects in the collection.\nEnd-points ",[101,873,874],{},"should"," include it if the number is known and is of material use. It is ",[101,877,103],{},"\nreturned by end-points used to query logs etc as the total count is a constantly changing\nvalue.",[880,881,883],"h4",{"id":882},"cursor-design","Cursor design",[19,885,886],{},"A cursor should be able to point directly at an entity in the collection. It could\nbe the entity hashid, or a timestamp if it is a time-series collection such as the\nlogs.",[19,888,889,890,892,893,895,896,898,899,155],{},"The cursor should ",[101,891,103],{}," be the internal ",[23,894,95],{}," of the entity in the collection - as we\ndo not expose those ids on the api, use the ",[23,897,110],{}," value as the external ",[23,900,95],{},[19,902,903,904,906,907,910],{},"If an end-point supports navigating the collection in reverse (by returning ",[23,905,855],{},"),\nthe cursor should be prefixed with ",[23,908,909],{},"-"," to indicate the query should be in the opposite\ndirection to the collection's natural order.",[236,912,914],{"id":913},"search-filtering","Search & Filtering",[19,916,917],{},"Search is done as simple case-insensitive text-based queries against string columns\nin the database model. This is a crude but effective way to implement search but\nmay need a more comprehensive approach in the future.",[19,919,920,921,924],{},"The search value is provided via the ",[23,922,923],{},"query"," query parameter.",[125,926,931],{"className":927,"code":929,"language":930},[928],"language-text","\u002Fapi\u002Fv1\u002Fexample?query=something\n","text",[23,932,929],{"__ignoreMap":130},[19,934,935],{},"Filtering can be used to limit the results based on the values of specific columns.",[19,937,938],{},"The Filter value is provided via additional query parameters.",[125,940,943],{"className":941,"code":942,"language":930},[928],"\u002Fapi\u002Fv1\u002Fexample?eventName=foo\n",[23,944,942],{"__ignoreMap":130},[236,946,948],{"id":947},"implementing-pagination-search","Implementing pagination & search",[19,950,951],{},"Two utility functions are provided to help implement pagination and search.",[880,953,955],{"id":954},"appgetpaginationoptions",[23,956,957],{},"app.getPaginationOptions",[19,959,960],{},"This returns an object of pagination options for a given request, with any default\nvalues automatically applied:",[125,962,964],{"className":127,"code":963,"language":129,"meta":130,"style":130},"const paginationOptions = app.getPaginationOptions(request, {limit: 1000})\n\n\u002F\u002F paginationOptions.limit = how many results to return\n\u002F\u002F paginationOptions.cursor = starting cursor\n\u002F\u002F paginationOptions.query = search string to use\n\u002F\u002F paginationOptions.* = any remaining query parameters\n",[23,965,966,1000,1006,1011,1016,1021],{"__ignoreMap":130},[134,967,968,970,973,975,977,979,982,985,987,989,991,993,996,998],{"class":136,"line":137},[134,969,141],{"class":140},[134,971,972],{"class":144}," paginationOptions ",[134,974,149],{"class":148},[134,976,152],{"class":144},[134,978,155],{"class":148},[134,980,981],{"class":173},"getPaginationOptions",[134,983,984],{"class":144},"(request",[134,986,349],{"class":148},[134,988,352],{"class":148},[134,990,734],{"class":355},[134,992,359],{"class":148},[134,994,995],{"class":180}," 1000",[134,997,410],{"class":148},[134,999,230],{"class":144},[134,1001,1002],{"class":136,"line":190},[134,1003,1005],{"emptyLinePlaceholder":1004},true,"\n",[134,1007,1008],{"class":136,"line":407},[134,1009,1010],{"class":583},"\u002F\u002F paginationOptions.limit = how many results to return\n",[134,1012,1013],{"class":136,"line":592},[134,1014,1015],{"class":583},"\u002F\u002F paginationOptions.cursor = starting cursor\n",[134,1017,1018],{"class":136,"line":598},[134,1019,1020],{"class":583},"\u002F\u002F paginationOptions.query = search string to use\n",[134,1022,1023],{"class":136,"line":604},[134,1024,1025],{"class":583},"\u002F\u002F paginationOptions.* = any remaining query parameters\n",[880,1027,1029],{"id":1028},"buildpaginationsearchclause",[23,1030,1031],{},"buildPaginationSearchClause",[19,1033,1034,1035,1038,1039,1042],{},"This takes the pagination options along with model-specific configuration options\nto build a suitable ",[23,1036,1037],{},"where"," clause that can be passed to the database model's ",[23,1040,1041],{},"getAll","\nfunction.",[125,1044,1047],{"className":1045,"code":1046,"language":930},[928],"const where = buildPaginationSearchClause(params, whereClause, searchColumns, filterMap)\n",[23,1048,1046],{"__ignoreMap":130},[28,1050,1051,1060,1066,1076],{},[31,1052,1053,1056,1057,1059],{},[23,1054,1055],{},"params"," - the pagination object returned by ",[23,1058,957],{}," for a given request",[31,1061,1062,1065],{},[23,1063,1064],{},"whereClause"," - (optional) an object containing any additional query clauses that should be applied",[31,1067,1068,1071,1072,1075],{},[23,1069,1070],{},"searchColumns"," - (optional) an array of fully-qualified column names that should be searched when ",[23,1073,1074],{},"query=\u003Cxyz>"," is included in query",[31,1077,1078,1081],{},[23,1079,1080],{},"filterMap"," - (option) a map of filter name to fully-qualified column name that are valid filter parameters",[19,1083,1084],{},"With the filtering option, if a particular filter parameter is specified more than\nonce in the query string, the generated query will apply an Or between the values.",[19,1086,1087,1088,1091,1092,1095,1096,731,1099,1102],{},"For example, lets consider the imaginary ",[23,1089,1090],{},"Thing"," model has a ",[23,1093,1094],{},"name",", ",[23,1097,1098],{},"description",[23,1100,1101],{},"type",".\nThe following will mean:",[28,1104,1105,1116],{},[31,1106,1107,1108,1110,1111,731,1113,1115],{},"any ",[23,1109,1074],{}," parameter will be searched for in the ",[23,1112,1094],{},[23,1114,1098],{}," columns",[31,1117,1107,1118,1121,1122,96],{},[23,1119,1120],{},"type=\u003Cabc>"," parameter will filter on the ",[23,1123,1101],{},[125,1125,1127],{"className":127,"code":1126,"language":129,"meta":130,"style":130},"const { buildPaginationSearchClause } = require('..\u002Futils')\n\n...\n\ngetAll: async (pagination = {}, where = {}) => {\n    \u002F\u002F Ensure a sensible default limit for this particular type of thing\n    const limit = parseInt(pagination.limit) || 1000\n\n    \u002F\u002F Decode the cursor from hashid to database id\n    if (pagination.cursor) {\n        pagination.cursor = M.Thing.decodeHashid(pagination.cursor)\n    }\n\n    \u002F\u002F Build the full where query using the buildPaginationSearchClause utility.\n    \u002F\u002F We pass in the list of columns that should be searched against\n    where = buildPaginationSearchClause(\n        pagination,\n        where,\n        ['Thing.name', 'Thing.description'],\n        {\n            type: 'Thing.type'\n        }\n    )\n\n    \u002F\u002F Run the query\n    const { count, rows } = await this.findAndCountAll({\n        where,\n        order: [['id', 'ASC']],\n        limit\n    })\n\n    \u002F\u002F Return the results with the additional metadata\n    return {\n        meta: {\n            next_cursor: rows.length === limit ? rows[rows.length - 1].hashid : undefined\n        },\n        count,\n        things: rows\n    }\n}\n",[23,1128,1129,1157,1161,1166,1170,1199,1204,1233,1238,1244,1263,1296,1302,1307,1313,1319,1333,1340,1348,1375,1381,1396,1402,1408,1413,1419,1451,1458,1489,1495,1503,1508,1514,1522,1532,1585,1591,1599,1610,1615],{"__ignoreMap":130},[134,1130,1131,1133,1135,1138,1140,1143,1146,1148,1150,1153,1155],{"class":136,"line":137},[134,1132,141],{"class":140},[134,1134,352],{"class":148},[134,1136,1137],{"class":144}," buildPaginationSearchClause ",[134,1139,410],{"class":148},[134,1141,1142],{"class":148}," =",[134,1144,1145],{"class":173}," require",[134,1147,177],{"class":144},[134,1149,341],{"class":148},[134,1151,1152],{"class":224},"..\u002Futils",[134,1154,341],{"class":148},[134,1156,230],{"class":144},[134,1158,1159],{"class":136,"line":190},[134,1160,1005],{"emptyLinePlaceholder":1004},[134,1162,1163],{"class":136,"line":407},[134,1164,1165],{"class":148},"...\n",[134,1167,1168],{"class":136,"line":592},[134,1169,1005],{"emptyLinePlaceholder":1004},[134,1171,1172,1174,1176,1178,1180,1182,1184,1187,1190,1192,1195,1197],{"class":136,"line":598},[134,1173,1041],{"class":632},[134,1175,359],{"class":148},[134,1177,379],{"class":140},[134,1179,382],{"class":148},[134,1181,718],{"class":385},[134,1183,1142],{"class":148},[134,1185,1186],{"class":148}," {},",[134,1188,1189],{"class":385}," where",[134,1191,1142],{"class":148},[134,1193,1194],{"class":148}," {})",[134,1196,396],{"class":140},[134,1198,399],{"class":148},[134,1200,1201],{"class":136,"line":604},[134,1202,1203],{"class":583},"    \u002F\u002F Ensure a sensible default limit for this particular type of thing\n",[134,1205,1206,1209,1212,1214,1217,1219,1221,1223,1225,1227,1230],{"class":136,"line":836},[134,1207,1208],{"class":140},"    const",[134,1210,1211],{"class":144}," limit",[134,1213,1142],{"class":148},[134,1215,1216],{"class":173}," parseInt",[134,1218,177],{"class":355},[134,1220,718],{"class":144},[134,1222,155],{"class":148},[134,1224,734],{"class":144},[134,1226,559],{"class":355},[134,1228,1229],{"class":148},"||",[134,1231,1232],{"class":180}," 1000\n",[134,1234,1236],{"class":136,"line":1235},8,[134,1237,1005],{"emptyLinePlaceholder":1004},[134,1239,1241],{"class":136,"line":1240},9,[134,1242,1243],{"class":583},"    \u002F\u002F Decode the cursor from hashid to database id\n",[134,1245,1247,1251,1253,1255,1257,1259,1261],{"class":136,"line":1246},10,[134,1248,1250],{"class":1249},"s7zQu","    if",[134,1252,382],{"class":355},[134,1254,718],{"class":144},[134,1256,155],{"class":148},[134,1258,730],{"class":144},[134,1260,559],{"class":355},[134,1262,627],{"class":148},[134,1264,1266,1269,1271,1273,1275,1278,1280,1282,1284,1286,1288,1290,1292,1294],{"class":136,"line":1265},11,[134,1267,1268],{"class":144},"        pagination",[134,1270,155],{"class":148},[134,1272,730],{"class":144},[134,1274,1142],{"class":148},[134,1276,1277],{"class":144}," M",[134,1279,155],{"class":148},[134,1281,1090],{"class":144},[134,1283,155],{"class":148},[134,1285,216],{"class":173},[134,1287,177],{"class":355},[134,1289,718],{"class":144},[134,1291,155],{"class":148},[134,1293,730],{"class":144},[134,1295,230],{"class":355},[134,1297,1299],{"class":136,"line":1298},12,[134,1300,1301],{"class":148},"    }\n",[134,1303,1305],{"class":136,"line":1304},13,[134,1306,1005],{"emptyLinePlaceholder":1004},[134,1308,1310],{"class":136,"line":1309},14,[134,1311,1312],{"class":583},"    \u002F\u002F Build the full where query using the buildPaginationSearchClause utility.\n",[134,1314,1316],{"class":136,"line":1315},15,[134,1317,1318],{"class":583},"    \u002F\u002F We pass in the list of columns that should be searched against\n",[134,1320,1322,1325,1327,1330],{"class":136,"line":1321},16,[134,1323,1324],{"class":144},"    where",[134,1326,1142],{"class":148},[134,1328,1329],{"class":173}," buildPaginationSearchClause",[134,1331,1332],{"class":355},"(\n",[134,1334,1336,1338],{"class":136,"line":1335},17,[134,1337,1268],{"class":144},[134,1339,646],{"class":148},[134,1341,1343,1346],{"class":136,"line":1342},18,[134,1344,1345],{"class":144},"        where",[134,1347,646],{"class":148},[134,1349,1351,1354,1356,1359,1361,1363,1365,1368,1370,1373],{"class":136,"line":1350},19,[134,1352,1353],{"class":355},"        [",[134,1355,341],{"class":148},[134,1357,1358],{"class":224},"Thing.name",[134,1360,341],{"class":148},[134,1362,349],{"class":148},[134,1364,638],{"class":148},[134,1366,1367],{"class":224},"Thing.description",[134,1369,341],{"class":148},[134,1371,1372],{"class":355},"]",[134,1374,646],{"class":148},[134,1376,1378],{"class":136,"line":1377},20,[134,1379,1380],{"class":148},"        {\n",[134,1382,1384,1387,1389,1391,1394],{"class":136,"line":1383},21,[134,1385,1386],{"class":355},"            type",[134,1388,359],{"class":148},[134,1390,638],{"class":148},[134,1392,1393],{"class":224},"Thing.type",[134,1395,661],{"class":148},[134,1397,1399],{"class":136,"line":1398},22,[134,1400,1401],{"class":148},"        }\n",[134,1403,1405],{"class":136,"line":1404},23,[134,1406,1407],{"class":355},"    )\n",[134,1409,1411],{"class":136,"line":1410},24,[134,1412,1005],{"emptyLinePlaceholder":1004},[134,1414,1416],{"class":136,"line":1415},25,[134,1417,1418],{"class":583},"    \u002F\u002F Run the query\n",[134,1420,1422,1424,1426,1429,1431,1434,1436,1438,1441,1444,1447,1449],{"class":136,"line":1421},26,[134,1423,1208],{"class":140},[134,1425,352],{"class":148},[134,1427,1428],{"class":144}," count",[134,1430,349],{"class":148},[134,1432,1433],{"class":144}," rows",[134,1435,373],{"class":148},[134,1437,1142],{"class":148},[134,1439,1440],{"class":1249}," await",[134,1442,1443],{"class":148}," this.",[134,1445,1446],{"class":173},"findAndCountAll",[134,1448,177],{"class":355},[134,1450,627],{"class":148},[134,1452,1454,1456],{"class":136,"line":1453},27,[134,1455,1345],{"class":144},[134,1457,646],{"class":148},[134,1459,1461,1464,1466,1469,1471,1473,1475,1477,1479,1482,1484,1487],{"class":136,"line":1460},28,[134,1462,1463],{"class":355},"        order",[134,1465,359],{"class":148},[134,1467,1468],{"class":355}," [[",[134,1470,341],{"class":148},[134,1472,95],{"class":224},[134,1474,341],{"class":148},[134,1476,349],{"class":148},[134,1478,638],{"class":148},[134,1480,1481],{"class":224},"ASC",[134,1483,341],{"class":148},[134,1485,1486],{"class":355},"]]",[134,1488,646],{"class":148},[134,1490,1492],{"class":136,"line":1491},29,[134,1493,1494],{"class":144},"        limit\n",[134,1496,1498,1501],{"class":136,"line":1497},30,[134,1499,1500],{"class":148},"    }",[134,1502,230],{"class":355},[134,1504,1506],{"class":136,"line":1505},31,[134,1507,1005],{"emptyLinePlaceholder":1004},[134,1509,1511],{"class":136,"line":1510},32,[134,1512,1513],{"class":583},"    \u002F\u002F Return the results with the additional metadata\n",[134,1515,1517,1520],{"class":136,"line":1516},33,[134,1518,1519],{"class":1249},"    return",[134,1521,399],{"class":148},[134,1523,1525,1528,1530],{"class":136,"line":1524},34,[134,1526,1527],{"class":355},"        meta",[134,1529,359],{"class":148},[134,1531,399],{"class":148},[134,1533,1535,1538,1540,1542,1544,1547,1550,1552,1555,1557,1560,1563,1565,1567,1570,1573,1575,1577,1579,1582],{"class":136,"line":1534},35,[134,1536,1537],{"class":355},"            next_cursor",[134,1539,359],{"class":148},[134,1541,1433],{"class":144},[134,1543,155],{"class":148},[134,1545,1546],{"class":144},"length",[134,1548,1549],{"class":148}," ===",[134,1551,1211],{"class":144},[134,1553,1554],{"class":148}," ?",[134,1556,1433],{"class":144},[134,1558,1559],{"class":355},"[",[134,1561,1562],{"class":144},"rows",[134,1564,155],{"class":148},[134,1566,1546],{"class":144},[134,1568,1569],{"class":148}," -",[134,1571,1572],{"class":180}," 1",[134,1574,1372],{"class":355},[134,1576,155],{"class":148},[134,1578,110],{"class":144},[134,1580,1581],{"class":148}," :",[134,1583,1584],{"class":148}," undefined\n",[134,1586,1588],{"class":136,"line":1587},36,[134,1589,1590],{"class":148},"        },\n",[134,1592,1594,1597],{"class":136,"line":1593},37,[134,1595,1596],{"class":144},"        count",[134,1598,646],{"class":148},[134,1600,1602,1605,1607],{"class":136,"line":1601},38,[134,1603,1604],{"class":355},"        things",[134,1606,359],{"class":148},[134,1608,1609],{"class":144}," rows\n",[134,1611,1613],{"class":136,"line":1612},39,[134,1614,1301],{"class":148},[134,1616,1618],{"class":136,"line":1617},40,[134,1619,666],{"class":148},[1621,1622,1623],"style",{},"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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}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}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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}",{"title":130,"searchDepth":592,"depth":592,"links":1625},[1626,1627,1628,1633,1639,1640],{"id":16,"depth":190,"text":17},{"id":88,"depth":190,"text":89},{"id":233,"depth":190,"text":234,"children":1629},[1630,1631,1632],{"id":238,"depth":407,"text":239},{"id":256,"depth":407,"text":257},{"id":272,"depth":407,"text":273},{"id":288,"depth":190,"text":289,"children":1634},[1635,1636,1637,1638],{"id":309,"depth":407,"text":310},{"id":415,"depth":407,"text":416},{"id":449,"depth":407,"text":450},{"id":486,"depth":407,"text":487},{"id":613,"depth":190,"text":614},{"id":711,"depth":190,"text":712,"children":1641},[1642,1645,1646],{"id":718,"depth":407,"text":719,"children":1643},[1644],{"id":882,"depth":592,"text":883},{"id":913,"depth":407,"text":914},{"id":947,"depth":407,"text":948,"children":1647},[1648,1649],{"id":954,"depth":592,"text":957},{"id":1028,"depth":592,"text":1031},"md",null,{},"API Design","contribute\u002Fapi-design.md","\u002Fdocs\u002Fcontribute\u002Fapi-design",{"title":5,"description":130},"docs\u002Fcontribute\u002Fapi-design","2024-07-19 20:33:52 +0530","2.33.2","9Eqx_xRFq2fdTdsRo0QYX5yvzS3-mNiNhoXYmEFt3Sw",[1662,1669,1688,1699],{"name":1663,"order":137,"children":1664},"FlowFuse User Manuals",[1665],{"title":1666,"path":1667,"group":1663,"groupOrder":137,"order":190,"children":1668},"FlowFuse API","\u002Fdocs\u002Fapi",[],{"name":1670,"order":592,"children":1671},"FlowFuse Self-Hosted",[1672,1676],{"title":1673,"path":1674,"group":1670,"groupOrder":592,"order":137,"children":1675},"Quick Start","\u002Fdocs\u002Fquick-start",[],{"title":1677,"path":1678,"group":1670,"groupOrder":592,"order":407,"children":1679},"Upgrading FlowFuse","\u002Fdocs\u002Fupgrade",[1680,1684],{"title":1681,"path":1682,"order":1651,"children":1683},"Installing a license","\u002Fdocs\u002Fupgrade\u002Fopen-source-to-premium",[],{"title":1685,"path":1686,"order":1651,"children":1687},"Upgrading the Node-RED version","\u002Fdocs\u002Fupgrade\u002Fnodered-version",[],{"name":1689,"order":598,"children":1690},"Support",[1691,1695],{"title":1692,"path":1693,"group":1689,"groupOrder":598,"order":407,"children":1694},"Premium Support","\u002Fdocs\u002Fpremium-support",[],{"title":1696,"path":1697,"group":1689,"groupOrder":598,"order":1651,"children":1698},"Debugging Node-RED issues","\u002Fdocs\u002Fdebugging",[],{"name":1700,"order":1651,"children":1701},"Other",[1702,1750,1762,1839,1887,1906,1980,1991],{"title":1703,"path":1704,"order":1651,"children":1705},"admin","\u002Fdocs\u002Fadmin",[1706,1710,1722,1730,1734,1738,1742,1746],{"title":1707,"path":1708,"order":137,"children":1709},"Administering FlowFuse","\u002Fdocs\u002Fadmin\u002Fintroduction",[],{"title":1711,"path":1712,"order":1651,"children":1713},"Configuring Single Sign-On (SSO)","\u002Fdocs\u002Fadmin\u002Fsso",[1714,1718],{"title":1715,"path":1716,"order":1651,"children":1717},"LDAP SSO","\u002Fdocs\u002Fadmin\u002Fsso\u002Fldap",[],{"title":1719,"path":1720,"order":1651,"children":1721},"SAML SSO","\u002Fdocs\u002Fadmin\u002Fsso\u002Fsaml",[],{"title":1723,"path":1724,"order":1651,"children":1725},"hardening","\u002Fdocs\u002Fadmin\u002Fhardening",[1726],{"title":1727,"path":1728,"order":1651,"children":1729},"Kubernetes Hardening","\u002Fdocs\u002Fadmin\u002Fhardening\u002Fkubernetes",[],{"title":1731,"path":1732,"order":1651,"children":1733},"Monitoring","\u002Fdocs\u002Fadmin\u002Fmonitoring",[],{"title":1735,"path":1736,"order":1651,"children":1737},"Observability","\u002Fdocs\u002Fadmin\u002Fobservability",[],{"title":1739,"path":1740,"order":1651,"children":1741},"Soft Launch Enablement","\u002Fdocs\u002Fadmin\u002Ffeature-flags",[],{"title":1743,"path":1744,"order":1651,"children":1745},"Telemetry","\u002Fdocs\u002Fadmin\u002Ftelemetry",[],{"title":1747,"path":1748,"order":1651,"children":1749},"User Management","\u002Fdocs\u002Fadmin\u002Fuser-management",[],{"title":1751,"path":1752,"order":1651,"children":1753},"cloud","\u002Fdocs\u002Fcloud",[1754,1758],{"title":1755,"path":1756,"order":137,"children":1757},"Introduction","\u002Fdocs\u002Fcloud\u002Fintroduction",[],{"title":1759,"path":1760,"order":1651,"children":1761},"FlowFuse Cloud Billing","\u002Fdocs\u002Fcloud\u002Fbilling",[],{"title":1763,"path":1764,"order":1651,"children":1765},"contribute","\u002Fdocs\u002Fcontribute",[1766,1769,1773,1775,1779,1783,1787,1795,1831,1835],{"title":1755,"path":1767,"order":137,"children":1768},"\u002Fdocs\u002Fcontribute\u002Fintroduction",[],{"title":1770,"path":1771,"order":1651,"children":1772},"Adding Template Settings","\u002Fdocs\u002Fcontribute\u002Fadding-template-settings",[],{"title":1653,"path":1655,"order":1651,"children":1774},[],{"title":1776,"path":1777,"order":1651,"children":1778},"Creating debug stack containers","\u002Fdocs\u002Fcontribute\u002Fcreating-debug-stack-containers",[],{"title":1780,"path":1781,"order":1651,"children":1782},"Database migrations","\u002Fdocs\u002Fcontribute\u002Fdb-migrations",[],{"title":1784,"path":1785,"order":1651,"children":1786},"FlowFuse Architecture","\u002Fdocs\u002Fcontribute\u002Farchitecture",[],{"title":1788,"path":1789,"order":1651,"children":1790},"Local Install","\u002Fdocs\u002Fcontribute\u002Flocal",[1791],{"title":1792,"path":1793,"order":1651,"children":1794},"Local Stacks","\u002Fdocs\u002Fcontribute\u002Flocal\u002Fstacks",[],{"title":1796,"path":1797,"order":1651,"children":1798},"State Flows","\u002Fdocs\u002Fcontribute\u002Fworkflows",[1799,1803,1807,1811,1815,1819,1823,1827],{"title":1800,"path":1801,"order":1651,"children":1802},"Device Editor","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fdevice-editor",[],{"title":1804,"path":1805,"order":1651,"children":1806},"Instance states","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fproject-states",[],{"title":1808,"path":1809,"order":1651,"children":1810},"Invite External Users","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Finvite-external-user",[],{"title":1812,"path":1813,"order":1651,"children":1814},"Project Creation","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fproject-create",[],{"title":1816,"path":1817,"order":1651,"children":1818},"Reset Password Flow","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fpassword-reset",[],{"title":1820,"path":1821,"order":1651,"children":1822},"Team creation Flow","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fteam-create",[],{"title":1824,"path":1825,"order":1651,"children":1826},"User Login Flows","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Flogin",[],{"title":1828,"path":1829,"order":1651,"children":1830},"User Sign up Flow","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fsignup",[],{"title":1832,"path":1833,"order":1651,"children":1834},"Team Broker","\u002Fdocs\u002Fcontribute\u002Fteam-broker",[],{"title":1836,"path":1837,"order":1651,"children":1838},"Working with Feature Flags","\u002Fdocs\u002Fcontribute\u002Ffeature-flags",[],{"title":1840,"path":1841,"order":1651,"children":1842},"device-agent","\u002Fdocs\u002Fdevice-agent",[1843,1847,1850,1854,1858,1862],{"title":1844,"path":1845,"order":137,"children":1846},"FlowFuse Device Agent Introduction","\u002Fdocs\u002Fdevice-agent\u002Fintroduction",[],{"title":1673,"path":1848,"order":190,"children":1849},"\u002Fdocs\u002Fdevice-agent\u002Fquickstart",[],{"title":1851,"path":1852,"order":592,"children":1853},"Register your Remote Instance","\u002Fdocs\u002Fdevice-agent\u002Fregister",[],{"title":1855,"path":1856,"order":598,"children":1857},"Running the Agent","\u002Fdocs\u002Fdevice-agent\u002Frunning",[],{"title":1859,"path":1860,"order":604,"children":1861},"Deploying your Flows","\u002Fdocs\u002Fdevice-agent\u002Fdeploy",[],{"title":1863,"path":1864,"order":1651,"children":1865},"install","\u002Fdocs\u002Fdevice-agent\u002Finstall",[1866,1871,1875,1879,1883],{"title":1867,"path":1868,"group":1869,"order":137,"children":1870},"Overview","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Foverview","DeviceAgentInstallation",[],{"title":1872,"path":1873,"group":1869,"order":190,"children":1874},"Device Agent Installer","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Fdevice-agent-installer",[],{"title":1876,"path":1877,"group":1869,"order":407,"children":1878},"Docker Install","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Fdocker",[],{"title":1880,"path":1881,"group":1869,"order":592,"children":1882},"Kubernetes Install","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Fkubernetes",[],{"title":1884,"path":1885,"group":1869,"order":598,"children":1886},"Manual Install with NPM","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Fmanual",[],{"title":1888,"path":1889,"order":1651,"children":1890},"hardware","\u002Fdocs\u002Fhardware",[1891,1894,1898,1902],{"title":1867,"path":1892,"order":137,"children":1893},"\u002Fdocs\u002Fhardware\u002Fintroduction",[],{"title":1895,"path":1896,"order":190,"children":1897},"ctrlX - Node-RED","\u002Fdocs\u002Fhardware\u002Fctrlx-node-red",[],{"title":1899,"path":1900,"order":407,"children":1901},"ctrlX - Device Agent","\u002Fdocs\u002Fhardware\u002Fctrlx-device-agent",[],{"title":1903,"path":1904,"order":407,"children":1905},"Raspberry Pi with Raspbian","\u002Fdocs\u002Fhardware\u002Fraspbian",[],{"title":1863,"path":1907,"order":1651,"children":1908},"\u002Fdocs\u002Finstall",[1909,1912,1916,1920,1940,1944,1948,1952],{"title":1867,"path":1910,"order":137,"children":1911},"\u002Fdocs\u002Finstall\u002Fintroduction",[],{"title":1913,"path":1914,"order":1651,"children":1915},"Configuring FlowFuse","\u002Fdocs\u002Finstall\u002Fconfiguration",[],{"title":1917,"path":1918,"order":1651,"children":1919},"DNS Setup","\u002Fdocs\u002Finstall\u002Fdns-setup",[],{"title":1921,"path":1922,"order":1651,"children":1923},"Docker install","\u002Fdocs\u002Finstall\u002Fdocker",[1924,1928,1932,1936],{"title":1925,"path":1926,"order":1651,"children":1927},"Add Project Stacks on Docker","\u002Fdocs\u002Finstall\u002Fdocker\u002Fstacks",[],{"title":1929,"path":1930,"order":1651,"children":1931},"Docker Engine on Windows","\u002Fdocs\u002Finstall\u002Fdocker\u002Fwindows-docker-ce",[],{"title":1933,"path":1934,"order":1651,"children":1935},"Docker from AWS Market Place","\u002Fdocs\u002Finstall\u002Fdocker\u002Faws-marketplace",[],{"title":1937,"path":1938,"order":1651,"children":1939},"Docker on Digital Ocean","\u002Fdocs\u002Finstall\u002Fdocker\u002Fdigital-ocean",[],{"title":1941,"path":1942,"order":1651,"children":1943},"Email configuration","\u002Fdocs\u002Finstall\u002Femail-providers",[],{"title":1945,"path":1946,"order":1651,"children":1947},"First Run Setup","\u002Fdocs\u002Finstall\u002Ffirst-run",[],{"title":1949,"path":1950,"order":1651,"children":1951},"FlowFuse File Storage","\u002Fdocs\u002Finstall\u002Ffile-storage",[],{"title":1953,"path":1954,"order":1651,"children":1955},"Install FlowFuse on Kubernetes","\u002Fdocs\u002Finstall\u002Fkubernetes",[1956,1960,1964,1968,1972,1976],{"title":1957,"path":1958,"order":1651,"children":1959},"AWS EKS Installation","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Faws",[],{"title":1961,"path":1962,"order":1651,"children":1963},"AWS EKS Installation with Terraform and Helm","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Faws-terraform",[],{"title":1965,"path":1966,"order":1651,"children":1967},"Digital Ocean Kubernetes Installation","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Fdigital-ocean",[],{"title":1969,"path":1970,"order":1651,"children":1971},"Ingress Controller Migration","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Fingress-controller-migration",[],{"title":1973,"path":1974,"order":1651,"children":1975},"Kubernetes Project Stacks","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Fstacks",[],{"title":1977,"path":1978,"order":1651,"children":1979},"OpenShift Installation","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Fopenshift",[],{"title":1981,"path":1982,"order":1651,"children":1983},"migration","\u002Fdocs\u002Fmigration",[1984,1987],{"title":1755,"path":1985,"order":137,"children":1986},"\u002Fdocs\u002Fmigration\u002Fintroduction",[],{"title":1988,"path":1989,"order":1651,"children":1990},"Node-RED Tools plugin","\u002Fdocs\u002Fmigration\u002Fnode-red-tools",[],{"title":1992,"path":1993,"order":1651,"children":1994},"user","\u002Fdocs\u002Fuser",[1995,1999,2003,2007,2011,2015,2019,2023,2027,2031,2035,2039,2051,2055,2059,2063,2067,2071,2075,2079,2083,2087,2091,2095,2099,2103,2106,2110],{"title":1996,"path":1997,"order":137,"children":1998},"Getting Started","\u002Fdocs\u002Fuser\u002Fintroduction",[],{"title":2000,"path":2001,"order":137,"children":2002},"Static asset service","\u002Fdocs\u002Fuser\u002Fstatic-asset-service",[],{"title":2004,"path":2005,"order":190,"children":2006},"Bill of Materials","\u002Fdocs\u002Fuser\u002Fbill-of-materials",[],{"title":2008,"path":2009,"order":190,"children":2010},"FlowFuse Concepts","\u002Fdocs\u002Fuser\u002Fconcepts",[],{"title":2012,"path":2013,"order":1246,"children":2014},"Instance States","\u002Fdocs\u002Fuser\u002Finstance-states",[],{"title":2016,"path":2017,"order":1651,"children":2018},"Changing the Stack","\u002Fdocs\u002Fuser\u002Fchangestack",[],{"title":2020,"path":2021,"order":1651,"children":2022},"Custom Hostnames","\u002Fdocs\u002Fuser\u002Fcustom-hostnames",[],{"title":2024,"path":2025,"order":1651,"children":2026},"Custom Node Packages","\u002Fdocs\u002Fuser\u002Fcustom-npm-packages",[],{"title":2028,"path":2029,"order":1651,"children":2030},"Dashboards","\u002Fdocs\u002Fuser\u002Fdashboards",[],{"title":2032,"path":2033,"order":1651,"children":2034},"DevOps Pipelines","\u002Fdocs\u002Fuser\u002Fdevops-pipelines",[],{"title":2036,"path":2037,"order":1651,"children":2038},"Environment Variables","\u002Fdocs\u002Fuser\u002Fenvvar",[],{"title":2040,"path":2041,"order":1651,"children":2042},"FlowFuse Expert","\u002Fdocs\u002Fuser\u002Fexpert",[2043,2047],{"title":2044,"path":2045,"order":1651,"children":2046},"AI in Node-RED","\u002Fdocs\u002Fuser\u002Fexpert\u002Fnode-red-embedded-ai",[],{"title":2048,"path":2049,"order":1651,"children":2050},"Chat Interface","\u002Fdocs\u002Fuser\u002Fexpert\u002Fchat",[],{"title":2052,"path":2053,"order":1651,"children":2054},"FlowFuse File Nodes","\u002Fdocs\u002Fuser\u002Ffilenodes",[],{"title":2056,"path":2057,"order":1651,"children":2058},"FlowFuse MQTT Nodes","\u002Fdocs\u002Fuser\u002Fmqtt-nodes",[],{"title":2060,"path":2061,"order":1651,"children":2062},"FlowFuse Persistent Context","\u002Fdocs\u002Fuser\u002Fpersistent-context",[],{"title":2064,"path":2065,"order":1651,"children":2066},"FlowFuse Project Nodes","\u002Fdocs\u002Fuser\u002Fprojectnodes",[],{"title":2068,"path":2069,"order":1651,"children":2070},"FlowFuse Tables","\u002Fdocs\u002Fuser\u002Fff-tables",[],{"title":2072,"path":2073,"order":1651,"children":2074},"Groups","\u002Fdocs\u002Fuser\u002Fdevice-groups",[],{"title":2076,"path":2077,"order":1651,"children":2078},"High Availability mode","\u002Fdocs\u002Fuser\u002Fhigh-availability",[],{"title":2080,"path":2081,"order":1651,"children":2082},"HTTP Access Tokens","\u002Fdocs\u002Fuser\u002Fhttp-access-tokens",[],{"title":2084,"path":2085,"order":1651,"children":2086},"Instance Settings","\u002Fdocs\u002Fuser\u002Finstance-settings",[],{"title":2088,"path":2089,"order":1651,"children":2090},"Logging","\u002Fdocs\u002Fuser\u002Flogs",[],{"title":2092,"path":2093,"order":1651,"children":2094},"Role-Based Access Control","\u002Fdocs\u002Fuser\u002Frole-based-access-control",[],{"title":2096,"path":2097,"order":1651,"children":2098},"Shared Team Library","\u002Fdocs\u002Fuser\u002Fshared-library",[],{"title":2100,"path":2101,"order":1651,"children":2102},"Snapshots","\u002Fdocs\u002Fuser\u002Fsnapshots",[],{"title":1832,"path":2104,"order":1651,"children":2105},"\u002Fdocs\u002Fuser\u002Fteambroker",[],{"title":2107,"path":2108,"order":1651,"children":2109},"Teams","\u002Fdocs\u002Fuser\u002Fteam",[],{"title":2111,"path":2112,"order":1651,"children":2113},"User Settings","\u002Fdocs\u002Fuser\u002Fuser-settings",[],1786546037415]