Add CLI multi-file config includes#1493
Conversation
Greptile SummaryThis PR adds multi-file config support to the generated CLI SDK: a root Confidence Score: 4/5Safe to merge; no new P1 or P0 issues found, and previously flagged P1s appear resolved. The change is large and touches several interacting subsystems (config read/write, push, pull, run, docker emulation, Schema API). All previously flagged P1 issues — path traversal, clear() orphaning, nextIncludePaths mutation, isPathInside unconditional check, type narrowing in schema.ts, and silent-pull directory routing — appear to be addressed in this revision. Only two P2 style observations remain. Score is 4 rather than 5 due to the complexity of the feature and the history of multiple P1 findings in earlier iterations. templates/cli/lib/config.ts and templates/cli/lib/commands/schema.ts carry the most surface area for edge cases in multi-file routing. Important Files Changed
Reviews (13): Last reviewed commit: "Reuse schema include pull directories" | Re-trigger Greptile |
What
Adds multi-file project config support to the generated CLI SDK. Users can keep
appwrite.config.jsonsmall by moving large top-level resource arrays into service-specific JSON files and referencing those files from a top-levelincludesmap.Supported include keys match the generated CLI resource arrays:
functionssitesdatabasescollectionstablesDBtablestopicsteamsbucketswebhooksmessagesThe default single-file config shape continues to work unchanged.
Example Usage
Root
appwrite.config.json:{ "projectId": "my-project", "projectName": "My Project", "endpoint": "https://cloud.appwrite.io/v1", "includes": { "functions": "./appwrite/functions.json", "sites": "./appwrite/sites.json", "buckets": "./appwrite/buckets.json", "teams": "./appwrite/teams.json", "topics": "./appwrite/topics.json" }, "settings": { "services": { "account": true, "databases": true, "storage": true, "teams": true, "sites": true } } }Included
./appwrite/functions.json:[ { "$id": "api", "name": "API", "runtime": "node-22", "path": "functions/api", "entrypoint": "src/main.js", "commands": "npm install", "execute": [], "events": [], "schedule": "", "timeout": 15, "enabled": true, "logging": true, "ignore": ["node_modules", ".git"], "scopes": [], "vars": [] } ]Included
./appwrite/buckets.json:[ { "$id": "assets", "name": "Assets", "permissions": [], "fileSecurity": false, "enabled": true, "maximumFileSize": 30000000, "allowedFileExtensions": [], "compression": "none", "encryption": true, "antivirus": true } ]With this layout, function and site
pathvalues are resolved relative to the file that defines them. In the example above,functions/apiresolves from./appwrite/functions.json, not from the root config directory. This allows teams to keep function/site definitions and local source paths together in a nested package, workspace, or submodule inside the project tree.Behavior
readmerges included resource arrays into the in-memory config so existing CLI flows can keep readingconfig.functions,config.sites, etc.writepreserves the split layout: resources that came from an included file are written back to that included file instead of being flattened intoappwrite.config.json.[]; empty include entries are pruned from the root config, while the current process keeps enough include-path state to route a delete-then-readd flow back to the included file.clear()clears included resource files before clearing the root config, so split files are not left with stale resources.push,pull,run, Docker emulation, init flows, and the publicSchemaAPI now resolve function/site paths using the resource file directory.Schema.read(),Schema.write(),Schema.pull(), andSchema.push()use the same multi-file read/write helpers as the CLI paths.Validation And Safety
Include paths are intentionally plain local JSON file paths. The CLI validates them at both the Zod schema layer and runtime config loading layer:
.json#JSON pointer fragments..parent-directory segmentsThis keeps the first version simple and prevents configs from reading or writing outside the project tree.
Why
Large
appwrite.config.jsonfiles become difficult to review and maintain when every service and resource lives in one file. Splitting resource arrays by service keeps the root config focused on project-level settings while allowing service owners to manage smaller, targeted files.Testing
Local verification:
docker run --rm -v $(pwd):/app -w /app php:8.3-cli php example.php clicomposer lint-twignpm --prefix examples/cli run build:typesgit diff --checkFocused smoke coverage:
.jsoninclude paths.[]and root include entries are pruned.writeLocalConfigFilepreserves include routing for the public Schema API.resolveLocalConfigResourcePathsresolves function/site paths relative to the include file directory for Schema push flows.Note:
npm --prefix examples/cli run lintstill fails on existing generated-code lint issues unrelated to this change.