community-ff-mcp 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +300 -0
- package/build/api/flutterflow.d.ts +11 -0
- package/build/api/flutterflow.js +61 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +78 -0
- package/build/prompts/dev-workflow.d.ts +2 -0
- package/build/prompts/dev-workflow.js +68 -0
- package/build/prompts/generate-page.d.ts +2 -0
- package/build/prompts/generate-page.js +37 -0
- package/build/prompts/inspect-project.d.ts +2 -0
- package/build/prompts/inspect-project.js +30 -0
- package/build/prompts/modify-component.d.ts +2 -0
- package/build/prompts/modify-component.js +40 -0
- package/build/resources/docs.d.ts +2 -0
- package/build/resources/docs.js +76 -0
- package/build/resources/projects.d.ts +3 -0
- package/build/resources/projects.js +60 -0
- package/build/tools/find-component-usages.d.ts +21 -0
- package/build/tools/find-component-usages.js +216 -0
- package/build/tools/find-page-navigations.d.ts +26 -0
- package/build/tools/find-page-navigations.js +220 -0
- package/build/tools/get-api-endpoints.d.ts +2 -0
- package/build/tools/get-api-endpoints.js +126 -0
- package/build/tools/get-app-settings.d.ts +2 -0
- package/build/tools/get-app-settings.js +169 -0
- package/build/tools/get-app-state.d.ts +2 -0
- package/build/tools/get-app-state.js +96 -0
- package/build/tools/get-component-summary.d.ts +22 -0
- package/build/tools/get-component-summary.js +195 -0
- package/build/tools/get-custom-code.d.ts +2 -0
- package/build/tools/get-custom-code.js +380 -0
- package/build/tools/get-data-models.d.ts +2 -0
- package/build/tools/get-data-models.js +266 -0
- package/build/tools/get-editing-guide.d.ts +7 -0
- package/build/tools/get-editing-guide.js +185 -0
- package/build/tools/get-general-settings.d.ts +2 -0
- package/build/tools/get-general-settings.js +116 -0
- package/build/tools/get-in-app-purchases.d.ts +2 -0
- package/build/tools/get-in-app-purchases.js +51 -0
- package/build/tools/get-integrations.d.ts +2 -0
- package/build/tools/get-integrations.js +137 -0
- package/build/tools/get-page-by-name.d.ts +3 -0
- package/build/tools/get-page-by-name.js +56 -0
- package/build/tools/get-page-summary.d.ts +22 -0
- package/build/tools/get-page-summary.js +205 -0
- package/build/tools/get-project-config.d.ts +2 -0
- package/build/tools/get-project-config.js +216 -0
- package/build/tools/get-project-setup.d.ts +2 -0
- package/build/tools/get-project-setup.js +212 -0
- package/build/tools/get-theme.d.ts +2 -0
- package/build/tools/get-theme.js +199 -0
- package/build/tools/get-yaml-docs.d.ts +6 -0
- package/build/tools/get-yaml-docs.js +116 -0
- package/build/tools/get-yaml.d.ts +2 -0
- package/build/tools/get-yaml.js +53 -0
- package/build/tools/list-files.d.ts +3 -0
- package/build/tools/list-files.js +49 -0
- package/build/tools/list-pages.d.ts +25 -0
- package/build/tools/list-pages.js +101 -0
- package/build/tools/list-projects.d.ts +3 -0
- package/build/tools/list-projects.js +23 -0
- package/build/tools/search-project-files.d.ts +2 -0
- package/build/tools/search-project-files.js +69 -0
- package/build/tools/sync-project.d.ts +3 -0
- package/build/tools/sync-project.js +147 -0
- package/build/tools/update-yaml.d.ts +3 -0
- package/build/tools/update-yaml.js +24 -0
- package/build/tools/validate-yaml.d.ts +3 -0
- package/build/tools/validate-yaml.js +39 -0
- package/build/utils/batch-process.d.ts +2 -0
- package/build/utils/batch-process.js +10 -0
- package/build/utils/cache.d.ts +58 -0
- package/build/utils/cache.js +199 -0
- package/build/utils/decode-yaml.d.ts +7 -0
- package/build/utils/decode-yaml.js +31 -0
- package/build/utils/page-summary/action-summarizer.d.ts +24 -0
- package/build/utils/page-summary/action-summarizer.js +291 -0
- package/build/utils/page-summary/formatter.d.ts +13 -0
- package/build/utils/page-summary/formatter.js +129 -0
- package/build/utils/page-summary/node-extractor.d.ts +24 -0
- package/build/utils/page-summary/node-extractor.js +227 -0
- package/build/utils/page-summary/tree-walker.d.ts +6 -0
- package/build/utils/page-summary/tree-walker.js +55 -0
- package/build/utils/page-summary/types.d.ts +58 -0
- package/build/utils/page-summary/types.js +4 -0
- package/build/utils/parse-folders.d.ts +9 -0
- package/build/utils/parse-folders.js +29 -0
- package/build/utils/resolve-data-type.d.ts +2 -0
- package/build/utils/resolve-data-type.js +18 -0
- package/build/utils/topic-map.d.ts +7 -0
- package/build/utils/topic-map.js +122 -0
- package/docs/ff-yaml/00-overview.md +166 -0
- package/docs/ff-yaml/01-project-files.md +2309 -0
- package/docs/ff-yaml/02-pages.md +572 -0
- package/docs/ff-yaml/03-components.md +784 -0
- package/docs/ff-yaml/04-widgets/README.md +122 -0
- package/docs/ff-yaml/04-widgets/button.md +444 -0
- package/docs/ff-yaml/04-widgets/container.md +358 -0
- package/docs/ff-yaml/04-widgets/dropdown.md +579 -0
- package/docs/ff-yaml/04-widgets/form.md +256 -0
- package/docs/ff-yaml/04-widgets/image.md +276 -0
- package/docs/ff-yaml/04-widgets/layout.md +355 -0
- package/docs/ff-yaml/04-widgets/misc.md +553 -0
- package/docs/ff-yaml/04-widgets/text-field.md +326 -0
- package/docs/ff-yaml/04-widgets/text.md +302 -0
- package/docs/ff-yaml/05-actions.md +953 -0
- package/docs/ff-yaml/06-variables.md +849 -0
- package/docs/ff-yaml/07-data.md +591 -0
- package/docs/ff-yaml/08-custom-code.md +736 -0
- package/docs/ff-yaml/09-theming.md +638 -0
- package/docs/ff-yaml/10-editing-guide.md +497 -0
- package/docs/ff-yaml/README.md +105 -0
- package/package.json +59 -0
- package/skills/community-ff-mcp/SKILL.md +201 -0
- package/skills/ff-widget-patterns.md +141 -0
- package/skills/ff-yaml-dev.md +70 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a page-widget-tree-outline YAML into a recursive OutlineNode tree.
|
|
3
|
+
*
|
|
4
|
+
* The outline YAML has a `node` root with named slots (body, appBar, header,
|
|
5
|
+
* collapsed, expanded) and `children` arrays. Each entry has a `key` field.
|
|
6
|
+
*/
|
|
7
|
+
import YAML from "yaml";
|
|
8
|
+
/** Named slots that can appear on a node alongside `children`. */
|
|
9
|
+
const SLOT_KEYS = [
|
|
10
|
+
"body",
|
|
11
|
+
"appBar",
|
|
12
|
+
"title",
|
|
13
|
+
"header",
|
|
14
|
+
"collapsed",
|
|
15
|
+
"expanded",
|
|
16
|
+
"floatingActionButton",
|
|
17
|
+
"drawer",
|
|
18
|
+
"endDrawer",
|
|
19
|
+
"bottomNavigationBar",
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Parse a raw outline node (from YAML) into an OutlineNode.
|
|
23
|
+
* `slot` indicates how this node was referenced by its parent.
|
|
24
|
+
*/
|
|
25
|
+
function parseNode(raw, slot) {
|
|
26
|
+
const key = raw.key ?? "unknown";
|
|
27
|
+
const children = [];
|
|
28
|
+
// Named slots
|
|
29
|
+
for (const s of SLOT_KEYS) {
|
|
30
|
+
const child = raw[s];
|
|
31
|
+
if (child && typeof child === "object" && child.key) {
|
|
32
|
+
children.push(parseNode(child, s));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Explicit children array
|
|
36
|
+
const rawChildren = raw.children;
|
|
37
|
+
if (Array.isArray(rawChildren)) {
|
|
38
|
+
for (const child of rawChildren) {
|
|
39
|
+
children.push(parseNode(child, "children"));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { key, slot, children };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parse the page-widget-tree-outline YAML string into an OutlineNode tree.
|
|
46
|
+
* Returns the root node (typically the Scaffold).
|
|
47
|
+
*/
|
|
48
|
+
export function parseTreeOutline(yamlContent) {
|
|
49
|
+
const doc = YAML.parse(yamlContent);
|
|
50
|
+
const root = doc.node;
|
|
51
|
+
if (!root || !root.key) {
|
|
52
|
+
throw new Error("Invalid tree outline: missing root node");
|
|
53
|
+
}
|
|
54
|
+
return parseNode(root, "root");
|
|
55
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the page summary tool.
|
|
3
|
+
*/
|
|
4
|
+
/** Summary of a single action in a trigger chain. */
|
|
5
|
+
export interface ActionSummary {
|
|
6
|
+
type: string;
|
|
7
|
+
detail: string;
|
|
8
|
+
}
|
|
9
|
+
/** Summary of a trigger (event handler) on a widget. */
|
|
10
|
+
export interface TriggerSummary {
|
|
11
|
+
trigger: string;
|
|
12
|
+
actions: ActionSummary[];
|
|
13
|
+
}
|
|
14
|
+
/** A node in the summarized widget tree. */
|
|
15
|
+
export interface SummaryNode {
|
|
16
|
+
key: string;
|
|
17
|
+
type: string;
|
|
18
|
+
name: string;
|
|
19
|
+
slot: string;
|
|
20
|
+
detail: string;
|
|
21
|
+
componentRef?: string;
|
|
22
|
+
componentId?: string;
|
|
23
|
+
triggers: TriggerSummary[];
|
|
24
|
+
children: SummaryNode[];
|
|
25
|
+
}
|
|
26
|
+
/** Parameter metadata from the top-level page YAML. */
|
|
27
|
+
export interface ParamInfo {
|
|
28
|
+
name: string;
|
|
29
|
+
dataType: string;
|
|
30
|
+
defaultValue?: string;
|
|
31
|
+
}
|
|
32
|
+
/** State field metadata from the top-level page YAML. */
|
|
33
|
+
export interface StateFieldInfo {
|
|
34
|
+
name: string;
|
|
35
|
+
dataType: string;
|
|
36
|
+
defaultValue?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Top-level page metadata. */
|
|
39
|
+
export interface PageMeta {
|
|
40
|
+
pageName: string;
|
|
41
|
+
scaffoldId: string;
|
|
42
|
+
folder: string;
|
|
43
|
+
params: ParamInfo[];
|
|
44
|
+
stateFields: StateFieldInfo[];
|
|
45
|
+
}
|
|
46
|
+
/** Top-level component metadata. */
|
|
47
|
+
export interface ComponentMeta {
|
|
48
|
+
componentName: string;
|
|
49
|
+
containerId: string;
|
|
50
|
+
description: string;
|
|
51
|
+
params: ParamInfo[];
|
|
52
|
+
}
|
|
53
|
+
/** Raw tree node from the widget tree outline YAML. */
|
|
54
|
+
export interface OutlineNode {
|
|
55
|
+
key: string;
|
|
56
|
+
slot: string;
|
|
57
|
+
children: OutlineNode[];
|
|
58
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the FlutterFlow `folders` YAML file to build a
|
|
3
|
+
* scaffoldId → folderName mapping.
|
|
4
|
+
*
|
|
5
|
+
* The file has two sections:
|
|
6
|
+
* rootFolders: (nested tree of { key, name, children })
|
|
7
|
+
* widgetClassKeyToFolderKey: (flat Scaffold_XXX: folderKey)
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseFolderMapping(foldersYaml: string): Record<string, string>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the FlutterFlow `folders` YAML file to build a
|
|
3
|
+
* scaffoldId → folderName mapping.
|
|
4
|
+
*
|
|
5
|
+
* The file has two sections:
|
|
6
|
+
* rootFolders: (nested tree of { key, name, children })
|
|
7
|
+
* widgetClassKeyToFolderKey: (flat Scaffold_XXX: folderKey)
|
|
8
|
+
*/
|
|
9
|
+
export function parseFolderMapping(foldersYaml) {
|
|
10
|
+
// 1. Build folderKey → name from the rootFolders tree
|
|
11
|
+
const keyToName = {};
|
|
12
|
+
const keyNameRegex = /key:\s*(\w+)\s*\n\s*name:\s*(.+)/g;
|
|
13
|
+
let match;
|
|
14
|
+
while ((match = keyNameRegex.exec(foldersYaml)) !== null) {
|
|
15
|
+
keyToName[match[1]] = match[2].trim();
|
|
16
|
+
}
|
|
17
|
+
// 2. Build scaffoldId → folderName from widgetClassKeyToFolderKey
|
|
18
|
+
const scaffoldToFolder = {};
|
|
19
|
+
const widgetSection = foldersYaml.split("widgetClassKeyToFolderKey:")[1];
|
|
20
|
+
if (widgetSection) {
|
|
21
|
+
const mappingRegex = /\s+(Scaffold_\w+):\s*(\w+)/g;
|
|
22
|
+
while ((match = mappingRegex.exec(widgetSection)) !== null) {
|
|
23
|
+
const scaffoldId = match[1];
|
|
24
|
+
const folderKey = match[2];
|
|
25
|
+
scaffoldToFolder[scaffoldId] = keyToName[folderKey] || folderKey;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return scaffoldToFolder;
|
|
29
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Resolve a scalar/list data type to a readable string. */
|
|
2
|
+
export function resolveDataType(dt) {
|
|
3
|
+
if (dt.listType) {
|
|
4
|
+
const inner = dt.listType;
|
|
5
|
+
return `List<${inner.scalarType || "unknown"}>`;
|
|
6
|
+
}
|
|
7
|
+
if (dt.scalarType === "DataStruct") {
|
|
8
|
+
const sub = dt.subType;
|
|
9
|
+
const dsi = sub?.dataStructIdentifier;
|
|
10
|
+
return dsi?.name ? `DataStruct:${dsi.name}` : "DataStruct";
|
|
11
|
+
}
|
|
12
|
+
if (dt.enumType) {
|
|
13
|
+
const en = dt.enumType;
|
|
14
|
+
const eid = en.enumIdentifier;
|
|
15
|
+
return eid?.name ? `Enum:${eid.name}` : "Enum";
|
|
16
|
+
}
|
|
17
|
+
return dt.scalarType || "unknown";
|
|
18
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DOCS_DIR: string;
|
|
2
|
+
/** Topic-to-file mapping for fuzzy search. */
|
|
3
|
+
export declare const TOPIC_MAP: Record<string, string>;
|
|
4
|
+
/** List all doc files recursively. */
|
|
5
|
+
export declare function listDocFiles(dir: string, prefix?: string): string[];
|
|
6
|
+
/** Read a doc file. Returns null if not found. */
|
|
7
|
+
export declare function readDoc(relPath: string): string | null;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TOPIC_MAP, DOCS_DIR, and doc-reading helpers.
|
|
3
|
+
* Used by get_yaml_docs and get_editing_guide tools.
|
|
4
|
+
*/
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
export const DOCS_DIR = path.resolve(__dirname, "../../docs/ff-yaml");
|
|
11
|
+
/** Topic-to-file mapping for fuzzy search. */
|
|
12
|
+
export const TOPIC_MAP = {
|
|
13
|
+
// Widgets
|
|
14
|
+
button: "04-widgets/button.md",
|
|
15
|
+
iconbutton: "04-widgets/button.md",
|
|
16
|
+
text: "04-widgets/text.md",
|
|
17
|
+
richtext: "04-widgets/text.md",
|
|
18
|
+
richtextspan: "04-widgets/text.md",
|
|
19
|
+
textfield: "04-widgets/text-field.md",
|
|
20
|
+
"text-field": "04-widgets/text-field.md",
|
|
21
|
+
input: "04-widgets/text-field.md",
|
|
22
|
+
container: "04-widgets/container.md",
|
|
23
|
+
boxdecoration: "04-widgets/container.md",
|
|
24
|
+
column: "04-widgets/layout.md",
|
|
25
|
+
row: "04-widgets/layout.md",
|
|
26
|
+
stack: "04-widgets/layout.md",
|
|
27
|
+
wrap: "04-widgets/layout.md",
|
|
28
|
+
layout: "04-widgets/layout.md",
|
|
29
|
+
image: "04-widgets/image.md",
|
|
30
|
+
form: "04-widgets/form.md",
|
|
31
|
+
validation: "04-widgets/form.md",
|
|
32
|
+
dropdown: "04-widgets/dropdown.md",
|
|
33
|
+
choicechips: "04-widgets/dropdown.md",
|
|
34
|
+
icon: "04-widgets/misc.md",
|
|
35
|
+
progressbar: "04-widgets/misc.md",
|
|
36
|
+
appbar: "04-widgets/misc.md",
|
|
37
|
+
conditionalbuilder: "04-widgets/misc.md",
|
|
38
|
+
widget: "04-widgets/README.md",
|
|
39
|
+
widgets: "04-widgets/README.md",
|
|
40
|
+
// Non-widget topics
|
|
41
|
+
actions: "05-actions.md",
|
|
42
|
+
action: "05-actions.md",
|
|
43
|
+
trigger: "05-actions.md",
|
|
44
|
+
navigate: "05-actions.md",
|
|
45
|
+
navigation: "05-actions.md",
|
|
46
|
+
ontap: "05-actions.md",
|
|
47
|
+
variables: "06-variables.md",
|
|
48
|
+
variable: "06-variables.md",
|
|
49
|
+
binding: "06-variables.md",
|
|
50
|
+
"data-binding": "06-variables.md",
|
|
51
|
+
data: "07-data.md",
|
|
52
|
+
collections: "07-data.md",
|
|
53
|
+
firestore: "07-data.md",
|
|
54
|
+
api: "07-data.md",
|
|
55
|
+
custom: "08-custom-code.md",
|
|
56
|
+
dart: "08-custom-code.md",
|
|
57
|
+
"custom-code": "08-custom-code.md",
|
|
58
|
+
theme: "09-theming.md",
|
|
59
|
+
theming: "09-theming.md",
|
|
60
|
+
color: "09-theming.md",
|
|
61
|
+
colors: "09-theming.md",
|
|
62
|
+
font: "09-theming.md",
|
|
63
|
+
typography: "09-theming.md",
|
|
64
|
+
editing: "10-editing-guide.md",
|
|
65
|
+
workflow: "10-editing-guide.md",
|
|
66
|
+
"editing-guide": "10-editing-guide.md",
|
|
67
|
+
push: "10-editing-guide.md",
|
|
68
|
+
overview: "00-overview.md",
|
|
69
|
+
structure: "00-overview.md",
|
|
70
|
+
"project-files": "01-project-files.md",
|
|
71
|
+
config: "01-project-files.md",
|
|
72
|
+
settings: "01-project-files.md",
|
|
73
|
+
pages: "02-pages.md",
|
|
74
|
+
page: "02-pages.md",
|
|
75
|
+
scaffold: "02-pages.md",
|
|
76
|
+
components: "03-components.md",
|
|
77
|
+
component: "03-components.md",
|
|
78
|
+
createcomponent: "03-components.md",
|
|
79
|
+
refactor: "03-components.md",
|
|
80
|
+
refactoring: "03-components.md",
|
|
81
|
+
isdummyroot: "03-components.md",
|
|
82
|
+
dummyroot: "03-components.md",
|
|
83
|
+
componentclasskeyref: "03-components.md",
|
|
84
|
+
parametervalues: "03-components.md",
|
|
85
|
+
callback: "03-components.md",
|
|
86
|
+
executecallbackaction: "03-components.md",
|
|
87
|
+
// Internationalization
|
|
88
|
+
translation: "01-project-files.md",
|
|
89
|
+
translations: "01-project-files.md",
|
|
90
|
+
i18n: "01-project-files.md",
|
|
91
|
+
localization: "01-project-files.md",
|
|
92
|
+
translatabletext: "01-project-files.md",
|
|
93
|
+
languages: "01-project-files.md",
|
|
94
|
+
// Universal patterns
|
|
95
|
+
inputvalue: "README.md",
|
|
96
|
+
mostrecentinputvalue: "README.md",
|
|
97
|
+
padding: "README.md",
|
|
98
|
+
"border-radius": "README.md",
|
|
99
|
+
};
|
|
100
|
+
/** List all doc files recursively. */
|
|
101
|
+
export function listDocFiles(dir, prefix = "") {
|
|
102
|
+
const results = [];
|
|
103
|
+
if (!fs.existsSync(dir))
|
|
104
|
+
return results;
|
|
105
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
106
|
+
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
107
|
+
if (entry.isDirectory()) {
|
|
108
|
+
results.push(...listDocFiles(path.join(dir, entry.name), relPath));
|
|
109
|
+
}
|
|
110
|
+
else if (entry.name.endsWith(".md")) {
|
|
111
|
+
results.push(relPath);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return results;
|
|
115
|
+
}
|
|
116
|
+
/** Read a doc file. Returns null if not found. */
|
|
117
|
+
export function readDoc(relPath) {
|
|
118
|
+
const filePath = path.join(DOCS_DIR, relPath);
|
|
119
|
+
if (!fs.existsSync(filePath))
|
|
120
|
+
return null;
|
|
121
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
122
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# FlutterFlow Project Structure
|
|
2
|
+
|
|
3
|
+
Every FlutterFlow project is a collection of YAML files accessed via file keys. This document maps every file type and explains how file keys work.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## File taxonomy
|
|
8
|
+
|
|
9
|
+
| File key pattern | Purpose |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `app-details` | App metadata: name, routing config, initial page, auth pages, theme mode, platform settings |
|
|
12
|
+
| `authentication` | Firebase/Supabase auth configuration, providers, login/signup page refs |
|
|
13
|
+
| `theme` | Typography definitions, color palette, breakpoints, widget defaults |
|
|
14
|
+
| `theme/color-scheme` | Full color palette: core, background, text, accent, semantic colors with dark mode variants |
|
|
15
|
+
| `folders` | Page and component folder organization (scaffold-to-folder mapping) |
|
|
16
|
+
| `app-state` | App-wide persisted state variables (shared across all pages) |
|
|
17
|
+
| `app-constants` | Read-only constants available app-wide |
|
|
18
|
+
| `app-assets` | Uploaded asset references (images, fonts, files) |
|
|
19
|
+
| `nav-bar` | Bottom navigation bar configuration (pages, icons, labels) |
|
|
20
|
+
| `app-bar` | App bar configuration |
|
|
21
|
+
| `permissions` | Platform permission declarations (CAMERA, LOCATION, etc.) — abstraction layer that FF maps to AndroidManifest.xml and Info.plist at build time |
|
|
22
|
+
| `revenue-cat` | RevenueCat paywall and entitlement configuration |
|
|
23
|
+
| `languages` | Internationalization strings and locale mappings |
|
|
24
|
+
| `page/id-Scaffold_XXX` | Page metadata: name, params, classModel (state fields), route config |
|
|
25
|
+
| `page/id-Scaffold_XXX/page-widget-tree-outline` | Widget tree hierarchy for the page (key refs only, no props) |
|
|
26
|
+
| `page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Widget_YYY` | Individual widget node: type, props, parameterValues, valueKey |
|
|
27
|
+
| `page/.../node/id-Widget_YYY/trigger_actions/id-TRIGGER/action/id-ZZZ` | Action definition attached to a widget trigger |
|
|
28
|
+
| `component/id-Container_XXX` | Component metadata: name, params, classModel |
|
|
29
|
+
| `component/id-Container_XXX/component-widget-tree-outline` | Component widget tree hierarchy |
|
|
30
|
+
| `component/id-Container_XXX/component-widget-tree-outline/node/id-Widget_YYY` | Component widget node |
|
|
31
|
+
| `api-endpoint/id-XXX` | API endpoint: URL, method, headers, body, response schema |
|
|
32
|
+
| `custom-actions/id-XXX` | Custom Dart action: name, params, return type, code |
|
|
33
|
+
| `custom-functions/id-XXX` | Custom Dart function: name, params, return type, code |
|
|
34
|
+
| `custom-widgets/id-XXX` | Custom Flutter widget: name, params, code |
|
|
35
|
+
| `data-structs/id-XXX` | Data structure (struct/class) definition with typed fields |
|
|
36
|
+
| `enums/id-XXX` | Enum definition with named values |
|
|
37
|
+
| `collections/id-XXX` | Firestore collection schema: fields, types, subcollections |
|
|
38
|
+
| `agent/id-XXX` | AI agent configuration |
|
|
39
|
+
| `custom-file/id-<TYPE>` | Custom file configs for native platform files. Known types: `MAIN` (main.dart startup actions), `ANDROID_MANIFEST` (XML injection hooks for AndroidManifest.xml), `INFO_PLIST` (plist property injection for Info.plist), `ENTITLEMENTS` (iOS capability entitlements for Runner.entitlements), `APP_DELEGATE` (Swift code injection for AppDelegate.swift), `PROGUARD` (ProGuard rule injection for proguard-rules.pro), `BUILD_GRADLE` (Gradle plugin/dependency/repository injection for build.gradle). Only appear after enabled in FF editor. Sub-file `custom-file/id-<TYPE>/custom-file-code.dart` contains generated source. |
|
|
40
|
+
| `environment-settings` | Per-environment configuration values (API URLs, keys) |
|
|
41
|
+
| `dependencies` | FlutterFlow library package dependencies |
|
|
42
|
+
| `custom-code-dependencies` | Dart/Flutter pub dependencies for custom code |
|
|
43
|
+
| `supabase` | Supabase connection config and database schema |
|
|
44
|
+
| `firebase-analytics` | Firebase Analytics settings |
|
|
45
|
+
| `firebase-crashlytics` | Firebase Crashlytics settings |
|
|
46
|
+
| `firebase-performance-monitoring` | Firebase Performance Monitoring settings |
|
|
47
|
+
| `firebase-app-check` | Firebase App Check configuration and debug token |
|
|
48
|
+
| `firebase-remote-config` | Firebase Remote Config — field definitions with default values |
|
|
49
|
+
| `firestore-settings` | Firestore security rules (per-collection CRUD permissions), storage rules, validation hashes |
|
|
50
|
+
| `push-notifications` | Push notification configuration |
|
|
51
|
+
| `google-maps` | Google Maps API keys per platform |
|
|
52
|
+
| `ad-mob` | AdMob advertising configuration |
|
|
53
|
+
| `algolia` | Algolia search integration — app ID, API key, indexed collections |
|
|
54
|
+
| `app-assets` | App icon, splash screen, error image settings |
|
|
55
|
+
| `platforms` | Platform enablement flags (web, etc.) |
|
|
56
|
+
| `mobile-deployment` | Codemagic CI/CD settings — App Store Connect credentials, build version/number, Play Store track, signing config |
|
|
57
|
+
| `web-publishing` | Web platform settings — SEO description, page title, status bar color, orientation |
|
|
58
|
+
| `library-values` | Values passed to FlutterFlow library dependencies |
|
|
59
|
+
| `library-configurations/id-<projectId>` | Route overrides for library pages |
|
|
60
|
+
| `download-code-settings` | Code download/GitHub push settings |
|
|
61
|
+
| `tests` | FlutterFlow test runner configuration |
|
|
62
|
+
| `app-query-cache` | Named database request cache managers |
|
|
63
|
+
| `date-picker` | Date picker style toggle (legacy vs modern Material date picker) |
|
|
64
|
+
| `material-theme` | Material Design version toggle (Material 2 vs Material 3) |
|
|
65
|
+
| `storyboard` | Editor-only page positions on the FF storyboard canvas (no functional impact) |
|
|
66
|
+
| `miscellaneous` | Misc app-level settings and feature flags |
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## File key patterns
|
|
71
|
+
|
|
72
|
+
File keys are hierarchical paths used with the `get_project_yaml` and `update_project_yaml` MCP tools.
|
|
73
|
+
|
|
74
|
+
### Anatomy of a file key
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
page/id-Scaffold_tjgkshke/page-widget-tree-outline/node/id-Button_7c3kwr61
|
|
78
|
+
| | | | |
|
|
79
|
+
| | | | └─ Widget ID
|
|
80
|
+
| | | └─ node segment (fixed)
|
|
81
|
+
| | └─ Sub-file type
|
|
82
|
+
| └─ Page scaffold ID (prefixed with id-)
|
|
83
|
+
└─ Top-level category
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Depth levels
|
|
87
|
+
|
|
88
|
+
| Level | Example key | What it returns |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| 0 | `app-details` | Entire config file |
|
|
91
|
+
| 1 | `page/id-Scaffold_XXX` | Page metadata only (name, params, state, route) |
|
|
92
|
+
| 2 | `page/id-Scaffold_XXX/page-widget-tree-outline` | Widget tree structure (key refs, no props) |
|
|
93
|
+
| 3 | `page/.../page-widget-tree-outline/node/id-Widget_YYY` | Single widget with all props |
|
|
94
|
+
| 4 | `page/.../node/id-Widget_YYY/trigger_actions/id-ON_TAP/action/id-ZZZ` | Single action definition |
|
|
95
|
+
|
|
96
|
+
### Component keys follow the same pattern
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
component/id-Container_XXX
|
|
100
|
+
component/id-Container_XXX/component-widget-tree-outline
|
|
101
|
+
component/id-Container_XXX/component-widget-tree-outline/node/id-Widget_YYY
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Note: Components use `component-widget-tree-outline` (not `page-widget-tree-outline`).
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Critical rule: Node-level files
|
|
109
|
+
|
|
110
|
+
Widget children **must** be pushed as individual node files. They cannot be embedded inline in the page-level YAML.
|
|
111
|
+
|
|
112
|
+
### Why
|
|
113
|
+
|
|
114
|
+
The FlutterFlow API strips inline children from `page/id-Scaffold_XXX`. The page file only stores metadata (name, params, classModel, route). Widget data lives exclusively in the widget tree outline and node sub-files.
|
|
115
|
+
|
|
116
|
+
### What this means in practice
|
|
117
|
+
|
|
118
|
+
To add or modify widgets, you always push **multiple files** in a single `update_project_yaml` call:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
update_project_yaml(projectId, {
|
|
122
|
+
"page/id-Scaffold_XXX/page-widget-tree-outline": <tree outline YAML>,
|
|
123
|
+
"page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Column_YYY": <column node YAML>,
|
|
124
|
+
"page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Text_ZZZ": <text node YAML>,
|
|
125
|
+
"page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Button_AAA": <button node YAML>
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Tree outline format
|
|
130
|
+
|
|
131
|
+
The widget tree outline defines hierarchy via key references:
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
node:
|
|
135
|
+
key: Scaffold_XXX
|
|
136
|
+
body:
|
|
137
|
+
key: Column_YYY
|
|
138
|
+
children:
|
|
139
|
+
- key: Text_ZZZ
|
|
140
|
+
- key: Button_AAA
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Each `key` referenced here must have a corresponding `node/id-<key>` file pushed alongside it.
|
|
144
|
+
|
|
145
|
+
### Validation shortcut
|
|
146
|
+
|
|
147
|
+
Call `validate_yaml` on the tree outline first. It returns `"File is referenced but is empty"` for any node that is referenced but has no corresponding file -- telling you exactly which node files you need to create.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## ID generation
|
|
152
|
+
|
|
153
|
+
When creating new widgets, pages, or other entities, generate IDs following this pattern:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
<TypePrefix>_<8 lowercase alphanumeric characters>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Examples:
|
|
160
|
+
- `Scaffold_k7m2x9p1`
|
|
161
|
+
- `Column_ab3def45`
|
|
162
|
+
- `Button_zz9wq2r8`
|
|
163
|
+
- `Text_mn4kp7s6`
|
|
164
|
+
- `Container_xy1abc23`
|
|
165
|
+
|
|
166
|
+
The prefix must match the widget/entity type exactly. The suffix should be unique within the project.
|