Skip to content

Add CLI multi-file config includes#1493

Merged
ChiragAgg5k merged 14 commits intomasterfrom
feat/cli-multifile-config
May 4, 2026
Merged

Add CLI multi-file config includes#1493
ChiragAgg5k merged 14 commits intomasterfrom
feat/cli-multifile-config

Conversation

@ChiragAgg5k
Copy link
Copy Markdown
Member

@ChiragAgg5k ChiragAgg5k commented May 4, 2026

What

Adds multi-file project config support to the generated CLI SDK. Users can keep appwrite.config.json small by moving large top-level resource arrays into service-specific JSON files and referencing those files from a top-level includes map.

Supported include keys match the generated CLI resource arrays:

  • functions
  • sites
  • databases
  • collections
  • tablesDB
  • tables
  • topics
  • teams
  • buckets
  • webhooks
  • messages

The 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 path values are resolved relative to the file that defines them. In the example above, functions/api resolves 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

  • read merges included resource arrays into the in-memory config so existing CLI flows can keep reading config.functions, config.sites, etc.
  • write preserves the split layout: resources that came from an included file are written back to that included file instead of being flattened into appwrite.config.json.
  • Empty included resource arrays are written as []; 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 public Schema API now resolve function/site paths using the resource file directory.
  • Schema.read(), Schema.write(), Schema.pull(), and Schema.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:

  • must be a non-empty string
  • must end with .json
  • cannot contain null bytes
  • cannot contain # JSON pointer fragments
  • cannot contain .. parent-directory segments
  • cannot be absolute paths
  • cannot be URLs or URL-like schemes
  • must resolve inside the project directory
  • cannot point at a resource that is also defined inline in the root config

This keeps the first version simple and prevents configs from reading or writing outside the project tree.

Why

Large appwrite.config.json files 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 cli
  • composer lint-twig
  • npm --prefix examples/cli run build:types
  • git diff --check

Focused smoke coverage:

  • Zod schema rejects parent-directory include paths, absolute include paths, and accepts project-local .json include paths.
  • Runtime config loading rejects an existing external include path before reading it.
  • Included resources write back to their included file instead of the root config.
  • Empty included resources are written as [] and root include entries are pruned.
  • Delete-then-readd flows in the same process route back to the original included file.
  • writeLocalConfigFile preserves include routing for the public Schema API.
  • resolveLocalConfigResourcePaths resolves function/site paths relative to the include file directory for Schema push flows.

Note: npm --prefix examples/cli run lint still fails on existing generated-code lint issues unrelated to this change.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

Greptile Summary

This PR adds multi-file config support to the generated CLI SDK: a root appwrite.config.json can delegate resource arrays to separate JSON files via an includes map. The implementation is thorough — path-safety validation (null bytes, fragments, .. segments, absolute paths, URL schemes) is applied at both the Zod schema layer and the runtime loading layer, isPathInside is checked unconditionally, Local.clear() writes [] to include files before zeroing state, nextIncludePaths is correctly pruned when arrays go empty, and this.read() is called after every write() to keep in-memory state in sync with disk. Issues flagged in prior reviews all appear to be addressed in this revision.

Confidence Score: 4/5

Safe 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

Filename Overview
templates/cli/lib/config.ts Core multi-file config support: adds readLocalConfigFile, writeLocalConfigFile, resolveLocalConfigResourcePaths, path-safety guards, and Local class overrides for read/write/clear. Issues from prior reviews (isPathInside unconditional check, clear() orphans, nextIncludePaths pruning, includePaths refresh after write) are all addressed.
templates/cli/lib/commands/schema.ts Schema API updated to use multi-file helpers: configPaths WeakMap tracks file→config, withResourceDirectories injects resource dirs for pull, resolveLocalConfigResourcePaths resolves paths before push. Previously flagged type narrowing and pull/push path issues appear resolved.
templates/cli/lib/commands/pull.ts Adds resourceDirectories option to PullOptions; pullResources sets configDirectoryPath per resource type inside a try/finally that always restores the original path. CLI-facing pull commands now set resource: functions/sites when creating pull instances.
templates/cli/lib/commands/push.ts Adds withResolvedResourcePaths helper that resolves function/site paths via localConfig.resolveResourcePath before calling pushResources; applied consistently in pushResources, pushFunction, and pushSite.
templates/cli/lib/commands/init.ts initFunction and initSite now chdir to getResourceDirname output (include-file directory when configured) instead of always using configDirectoryPath; directory is created if it doesn't exist.
templates/cli/lib/commands/run.ts Replaces all path.join(localConfig.getDirname(), func.path) usages with localConfig.resolveResourcePath("functions", func.path).
templates/cli/lib/emulation/docker.ts Same path resolution migration as run.ts — all function directory references now go through resolveResourcePath.
templates/cli/lib/commands/config.ts Adds ConfigIncludePathSchema (Zod) with all path safety checks matching the runtime assertValidIncludePath guards, and ConfigIncludesSchema keyed by CONFIG_RESOURCE_KEYS.
templates/cli/README.md.twig Adds Project configuration section with complete example showing all 11 supported includes keys and a sample included array file.
templates/cli/index.ts Exports new ConfigIncludesType from the public SDK surface.

Reviews (13): Last reviewed commit: "Reuse schema include pull directories" | Re-trigger Greptile

Comment thread templates/cli/lib/config.ts
Comment thread templates/cli/lib/config.ts
Comment thread templates/cli/lib/config.ts
Comment thread templates/cli/README.md.twig
Comment thread templates/cli/lib/config.ts
Comment thread templates/cli/lib/config.ts
Comment thread templates/cli/lib/config.ts
Comment thread templates/cli/lib/commands/schema.ts
Comment thread templates/cli/lib/config.ts Outdated
Comment thread templates/cli/lib/commands/schema.ts
@ChiragAgg5k ChiragAgg5k merged commit c14a723 into master May 4, 2026
57 checks passed
@ChiragAgg5k ChiragAgg5k deleted the feat/cli-multifile-config branch May 4, 2026 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant