appwrite-ctl 1.0.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 ADDED
@@ -0,0 +1,288 @@
1
+ # Appwrite Ctl
2
+
3
+ A Node.js (ESM) package to manage Appwrite infrastructure via Version Snapshots. Uses the **Appwrite CLI** for schema pull/push operations and the **Appwrite SDK** for data migration scripts.
4
+
5
+ ## Features
6
+
7
+ - **Version Control for Appwrite Schema**: Manage your `appwrite.config.json` snapshots alongside your code.
8
+ - **CLI-based Snapshots**: Uses `appwrite-cli` pull/push for reliable schema synchronization.
9
+ - **Data Migrations**: Execute TypeScript or JavaScript migration scripts (`up` and `down`) using the Node.js SDK.
10
+ - **State Management**: Tracks applied migrations in a dedicated Appwrite collection (`system.migrations`).
11
+ - **Backup Hooks**: Supports executing external backup commands before migration.
12
+ - **Attribute Polling**: Ensures schema attributes are `available` before running data scripts.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install -g appwrite-ctl
18
+ # or
19
+ npm install --save-dev appwrite-ctl
20
+ ```
21
+
22
+ ### From Repository
23
+
24
+ ```bash
25
+ npm install github:bfbechlin/appwrite-ctl
26
+ ```
27
+
28
+ ## Prerequisites
29
+
30
+ - **Node.js**: v18 or higher.
31
+ - **Appwrite CLI**: Installed globally (`npm install -g appwrite-cli`). The tool configures the CLI automatically using API key — no interactive login required.
32
+ - **Environment Variables**:
33
+
34
+ ```env
35
+ APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
36
+ APPWRITE_PROJECT_ID=your_project_id
37
+ APPWRITE_API_KEY=your_api_key
38
+ BACKUP_COMMAND="docker exec appwrite-mariadb mysqldump ..." # Optional
39
+ ```
40
+
41
+ ## Architecture
42
+
43
+ The tool uses a clear separation of concerns:
44
+
45
+ | Operation | Tool | Why |
46
+ | :--------------------------- | :--------------- | :--------------------------------------------------------------------------- |
47
+ | Schema snapshots (pull/push) | **Appwrite CLI** | Has full serialization/deserialization of schemas via `appwrite.config.json` |
48
+ | Data migrations (up/down) | **Appwrite SDK** | Provides programmatic access to databases, documents, etc. |
49
+ | Migration tracking | **Appwrite SDK** | Creates/reads documents in the `system.migrations` collection |
50
+
51
+ ## CLI Usage
52
+
53
+ ```bash
54
+ # Default (uses .env)
55
+ npx appwrite-ctl migrations run
56
+
57
+ # Custom environment file
58
+ npx appwrite-ctl migrations run --env .env.prod
59
+ ```
60
+
61
+ ## Quick Start
62
+
63
+ ### 1. Initialize the Project
64
+
65
+ ```bash
66
+ npx appwrite-ctl init
67
+ ```
68
+
69
+ Creates:
70
+
71
+ - `appwrite/migration/` directory
72
+ - `appwrite/migration/config.json` configuration file
73
+
74
+ ### 2. Setup System Collection
75
+
76
+ ```bash
77
+ npx appwrite-ctl migrations setup
78
+ ```
79
+
80
+ ### 3. Create a Migration
81
+
82
+ ```bash
83
+ npx appwrite-ctl migrations create
84
+ ```
85
+
86
+ This command:
87
+
88
+ 1. Creates `appwrite/migration/vN/` (auto-increments version).
89
+ 2. Generates an `index.ts` file with a boilerplate migration script.
90
+ 3. Copies the current `appwrite.config.json` from the project root (or pulls from Appwrite via CLI if no local snapshot exists).
91
+
92
+ **Folder Structure:**
93
+
94
+ ```
95
+ /appwrite
96
+ schema.md <-- Generated by `docs` command
97
+ /migration
98
+ config.json
99
+ /v1
100
+ index.ts <-- Migration logic (SDK)
101
+ appwrite.config.json <-- Schema snapshot (CLI format)
102
+ schema.md <-- Auto-generated on create/update
103
+ /v2
104
+ index.ts
105
+ appwrite.config.json
106
+ schema.md
107
+ ```
108
+
109
+ ### 4. Edit Migration Logic
110
+
111
+ ```typescript
112
+ import { Migration } from 'appwrite-ctl';
113
+
114
+ const migration: Migration = {
115
+ id: 'uuid-generated-id',
116
+ description: 'Update finance schema',
117
+ requiresBackup: true,
118
+
119
+ up: async ({ client, databases, log }) => {
120
+ log('Seeding initial data...');
121
+ await databases.createDocument('db', 'users', 'unique()', {
122
+ name: 'Admin',
123
+ role: 'admin',
124
+ });
125
+ },
126
+
127
+ down: async ({ client, databases, log }) => {
128
+ // Logic to revert changes
129
+ },
130
+ };
131
+
132
+ export default migration;
133
+ ```
134
+
135
+ ### 5. Update a Snapshot
136
+
137
+ After making schema changes in the Appwrite console, update a migration version's snapshot:
138
+
139
+ ```bash
140
+ npx appwrite-ctl migrations update v1
141
+ ```
142
+
143
+ This pulls the current state from Appwrite via CLI and saves it as the version's `appwrite.config.json`.
144
+
145
+ ### 6. Run Migrations
146
+
147
+ ```bash
148
+ npx appwrite-ctl migrations run
149
+ ```
150
+
151
+ The runner performs these steps for each pending version:
152
+
153
+ 1. **Configure CLI**: Sets endpoint, project-id, and API key on appwrite-cli.
154
+ 2. **Backup**: Runs `BACKUP_COMMAND` if `requiresBackup` is true.
155
+ 3. **Schema Push**: Pushes the version's `appwrite.config.json` via CLI (settings, tables, buckets, teams, topics).
156
+ 4. **Polling**: Waits for all schema attributes to become `available` (via SDK).
157
+ 5. **Execution**: Runs the `up` function defined in `index.ts` (via SDK).
158
+ 6. **Finalization**: Records the migration as applied.
159
+
160
+ ### 7. Check Status
161
+
162
+ ```bash
163
+ npx appwrite-ctl migrations status
164
+ ```
165
+
166
+ ### 8. Generate Schema Docs
167
+
168
+ ```bash
169
+ # Generate from latest version → appwrite/schema.md
170
+ npx appwrite-ctl migrations docs
171
+
172
+ # Generate from a specific version
173
+ npx appwrite-ctl migrations docs v1
174
+ ```
175
+
176
+ Generates a Markdown file with:
177
+
178
+ - **ER diagrams** (Mermaid) for each database (system database excluded)
179
+ - **Collection details**: columns, types, defaults, indexes, permissions, relationships
180
+ - **Buckets**: storage configuration summary
181
+
182
+ > **Note:** Schema docs are also auto-generated inside the version folder (`vN/schema.md`) when running `migrations create` or `migrations update`.
183
+
184
+ ## Configuration (`appwrite/migration/config.json`)
185
+
186
+ ```json
187
+ {
188
+ "collection": "migrations",
189
+ "database": "system"
190
+ }
191
+ ```
192
+
193
+ ## CI/CD & Automated Deployment
194
+
195
+ 1. Install Appwrite CLI: `npm install -g appwrite-cli`
196
+ 2. Set environment variables: `APPWRITE_ENDPOINT`, `APPWRITE_PROJECT_ID`, `APPWRITE_API_KEY`
197
+ 3. The tool automatically configures the CLI via `appwrite client --key` — no login required.
198
+
199
+ **Required API Key Scopes:**
200
+
201
+ - `collections.read`, `collections.write`
202
+ - `documents.read`, `documents.write`
203
+ - `attributes.read`, `attributes.write`
204
+ - `indexes.read`, `indexes.write`
205
+
206
+ ## CLI Commands
207
+
208
+ | Command | Description |
209
+ | :---------------------------- | :----------------------------------------------------------------------------------- |
210
+ | `init` | Initialize the project folder structure and config. |
211
+ | `migrations setup` | Create the `system` database and `migrations` collection. |
212
+ | `migrations create` | Create a new migration version pulling the latest snapshot from Appwrite via CLI. |
213
+ | `migrations update <version>` | Update a version's snapshot by pulling from Appwrite via CLI. |
214
+ | `migrations run` | Execute all pending migrations in order. |
215
+ | `migrations status` | List applied and pending migrations. |
216
+ | `migrations docs` | Pull current schema state from Appwrite and generate documentation with ER diagrams. |
217
+
218
+ # AI Rules
219
+
220
+ ## Understanding the Data Models Layer
221
+
222
+ 📌 `schema.md` — The Source of Truth
223
+
224
+ The most important file for understanding the application's **data model** is:
225
+
226
+ ```
227
+ appwrite/schema.md
228
+ ```
229
+
230
+ This is an **auto-generated** Markdown file that documents the **current state** of every database, collection, attribute, relationship, index, and storage bucket in the Appwrite project. It is generated from the latest `appwrite.config.json` snapshot via the `migrations docs` command.
231
+
232
+ **When you need to understand the data model — always read `appwrite/schema.md` first.**
233
+
234
+ It contains:
235
+
236
+ - **ER Diagrams** (Mermaid) — visual representation of collection relationships per database.
237
+ - **Collections** — complete list of every collection with:
238
+ - Column names, types, required flags, defaults, and constraints.
239
+ - Relationships: type (`oneToMany`, `manyToOne`, etc.), related collection, on-delete behavior, and two-way configuration.
240
+ - Indexes: type (unique, key, fulltext), columns, and sort orders.
241
+ - Permissions: read/write/create/delete access rules.
242
+ - **Buckets** — storage buckets with max file size, extensions, compression, encryption, and antivirus settings.
243
+
244
+ ## Migration Commands
245
+
246
+ This project uses `appwrite-ctl` to manage schema migrations. The available commands are:
247
+
248
+ | Command | Description |
249
+ | :----------------------------------------- | :------------------------------------------------------------------------------------ |
250
+ | `appwrite-ctl migrations create` | Create a new migration version pulling the latest snapshot from Appwrite via CLI. |
251
+ | `appwrite-ctl migrations update <version>` | Pull the current Appwrite state and update a version's snapshot. |
252
+ | `appwrite-ctl migrations run` | Execute all pending migrations in order (push schema → poll attributes → run script). |
253
+ | `appwrite-ctl migrations status` | List applied and pending migrations. |
254
+ | `appwrite-ctl migrations docs` | Pull current schema state from Appwrite and generate/regenerate `schema.md`. |
255
+
256
+ Each migration version lives in `appwrite/migration/vN/` and contains:
257
+
258
+ - **`appwrite.config.json`** — the schema snapshot (Appwrite CLI format).
259
+ - **`index.ts`** — the migration script with `up` (and optional `down`) functions.
260
+ - **`schema.md`** — auto-generated docs for that version's snapshot.
261
+
262
+ ## How to Handle Data Model Changes
263
+
264
+ When a change to the data model is needed (e.g. adding a collection, modifying attributes, creating indexes), follow these steps:
265
+
266
+ 1. **Create a new migration version:**
267
+
268
+ ```bash
269
+ npx appwrite-ctl migrations create
270
+ ```
271
+
272
+ This creates `appwrite/migration/vN/` and automatically pulls the current schema snapshot from Appwrite into `appwrite.config.json` via the CLI.
273
+
274
+ 2. **Edit the snapshot (`appwrite.config.json`)** inside the new version folder. Apply the desired schema changes directly to this JSON file — add/remove/modify collections, attributes, indexes, relationships, or buckets.
275
+
276
+ 3. **Write the migration script** in `appwrite/migration/vN/index.ts` if data manipulation is needed (e.g. seeding data, transforming existing documents). If the change is schema-only, the default empty `up` function is sufficient.
277
+
278
+ 4. **Regenerate the schema docs:**
279
+
280
+ ```bash
281
+ npx appwrite-ctl migrations docs
282
+ ```
283
+
284
+ This updates both `appwrite/migration/vN/schema.md` and the root `appwrite/schema.md`.
285
+
286
+ 5. **Verify** the updated `appwrite/schema.md` to confirm the changes are correct.
287
+
288
+ > ⚠️ **Never edit `schema.md` files manually** — they are auto-generated. Always modify the `appwrite.config.json` snapshot and run `migrations docs` to regenerate.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { v4 as uuidv4 } from 'uuid';
6
+ import chalk from 'chalk';
7
+ import { runMigrations } from '../lib/runner.js';
8
+ import { loadConfig } from '../lib/config.js';
9
+ import { createAppwriteClient, ensureMigrationCollection, getAppliedMigrations, } from '../lib/appwrite.js';
10
+ import { configureClient, pullSnapshot, getSnapshotFilename } from '../lib/cli.js';
11
+ import { generateSchemaDoc } from '../lib/diagram.js';
12
+ const program = new Command();
13
+ const generateDocs = (snapshotPath, version, outputDir) => {
14
+ if (!fs.existsSync(snapshotPath))
15
+ return;
16
+ const markdown = generateSchemaDoc(snapshotPath, version);
17
+ if (!fs.existsSync(outputDir)) {
18
+ fs.mkdirSync(outputDir, { recursive: true });
19
+ }
20
+ const outputPath = path.join(outputDir, 'schema.md');
21
+ fs.writeFileSync(outputPath, markdown);
22
+ console.log(chalk.green(`Schema docs updated at ${outputPath}`));
23
+ };
24
+ program
25
+ .name('appwrite-ctl')
26
+ .description('Appwrite CLI for managing migrations and other operations');
27
+ program.option('-e, --env <path>', 'Path to environment file', '.env');
28
+ program
29
+ .command('init')
30
+ .description('Initialize the project structure')
31
+ .action(async () => {
32
+ const rootDir = process.cwd();
33
+ const appwriteDir = path.join(rootDir, 'appwrite');
34
+ const migrationDir = path.join(appwriteDir, 'migration');
35
+ const configPath = path.join(migrationDir, 'config.json');
36
+ if (!fs.existsSync(appwriteDir))
37
+ fs.mkdirSync(appwriteDir);
38
+ if (!fs.existsSync(migrationDir))
39
+ fs.mkdirSync(migrationDir);
40
+ if (!fs.existsSync(configPath)) {
41
+ const config = {
42
+ collection: 'migrations',
43
+ database: 'system',
44
+ };
45
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
46
+ console.log(chalk.green('Created appwrite/migration/config.json'));
47
+ }
48
+ else {
49
+ console.log(chalk.yellow('Config file already exists.'));
50
+ }
51
+ console.log(chalk.green('Initialization complete.'));
52
+ });
53
+ const migrations = program.command('migrations').description('Manage Appwrite migrations');
54
+ migrations
55
+ .command('setup')
56
+ .description('Create the system database and migrations collection in Appwrite')
57
+ .action(async () => {
58
+ try {
59
+ const options = program.opts();
60
+ const config = loadConfig(options.env);
61
+ const { databases } = createAppwriteClient(config);
62
+ await ensureMigrationCollection(databases, config);
63
+ console.log(chalk.green(`System database '${config.database}' and collection '${config.migrationCollectionId}' ensured.`));
64
+ }
65
+ catch (error) {
66
+ console.error(chalk.red('Setup failed:'), error.message);
67
+ process.exit(1);
68
+ }
69
+ });
70
+ migrations
71
+ .command('create')
72
+ .description('Create a new migration version')
73
+ .action(async () => {
74
+ const migrationsDir = path.join(process.cwd(), 'appwrite', 'migration');
75
+ if (!fs.existsSync(migrationsDir)) {
76
+ fs.mkdirSync(migrationsDir, { recursive: true });
77
+ }
78
+ const snapshotFilename = getSnapshotFilename();
79
+ // Find next version number
80
+ const versionDirs = fs
81
+ .readdirSync(migrationsDir)
82
+ .filter((dir) => dir.startsWith('v') && fs.statSync(path.join(migrationsDir, dir)).isDirectory())
83
+ .map((d) => parseInt(d.substring(1)))
84
+ .sort((a, b) => a - b);
85
+ const nextVersion = (versionDirs.length > 0 ? versionDirs[versionDirs.length - 1] : 0) + 1;
86
+ const versionPath = path.join(migrationsDir, `v${nextVersion}`);
87
+ const name = `migration_v${nextVersion}`;
88
+ fs.mkdirSync(versionPath);
89
+ const indexContent = `import { Migration } from "appwrite-ctl";
90
+
91
+ const migration: Migration = {
92
+ id: "${uuidv4()}",
93
+ description: "${name}",
94
+ requiresBackup: false,
95
+ up: async ({ client, databases, log, error }) => {
96
+ log("Executing up migration for ${name}");
97
+ // Write your migration logic here
98
+ },
99
+ down: async ({ client, databases, log, error }) => {
100
+ log("Executing down migration for ${name}");
101
+ }
102
+ };
103
+
104
+ export default migration;
105
+ `;
106
+ fs.writeFileSync(path.join(versionPath, 'index.ts'), indexContent);
107
+ // Snapshot logic: always pull from Appwrite via CLI for a new migration.
108
+ console.log(chalk.blue('Pulling latest schema from Appwrite via CLI...'));
109
+ try {
110
+ const options = program.opts();
111
+ const config = loadConfig(options.env);
112
+ await configureClient(config);
113
+ await pullSnapshot(versionPath);
114
+ console.log(chalk.green('Successfully pulled snapshot from Appwrite.'));
115
+ }
116
+ catch (error) {
117
+ console.error(chalk.red(`Failed to pull snapshot: ${error.message}`));
118
+ console.warn(chalk.yellow('Creating empty snapshot placeholder.'));
119
+ const emptySnapshot = {
120
+ projectId: '',
121
+ projectName: '',
122
+ settings: {},
123
+ tablesDB: [],
124
+ tables: [],
125
+ buckets: [],
126
+ teams: [],
127
+ topics: [],
128
+ };
129
+ fs.writeFileSync(path.join(versionPath, snapshotFilename), JSON.stringify(emptySnapshot, null, 2));
130
+ }
131
+ console.log(chalk.green(`Created migration v${nextVersion} at ${versionPath}`));
132
+ generateDocs(path.join(versionPath, snapshotFilename), `v${nextVersion}`, versionPath);
133
+ generateDocs(path.join(versionPath, snapshotFilename), `v${nextVersion}`, path.join(process.cwd(), 'appwrite'));
134
+ });
135
+ migrations
136
+ .command('update <version>')
137
+ .description('Update snapshot for a version by pulling current state from Appwrite via CLI')
138
+ .action(async (version) => {
139
+ const migrationsDir = path.join(process.cwd(), 'appwrite', 'migration');
140
+ const versionPath = path.join(migrationsDir, version);
141
+ if (!fs.existsSync(versionPath)) {
142
+ console.error(chalk.red(`Version directory ${version} not found.`));
143
+ process.exit(1);
144
+ }
145
+ console.log(chalk.blue(`Updating snapshot for ${version} via CLI pull...`));
146
+ try {
147
+ const options = program.opts();
148
+ const config = loadConfig(options.env);
149
+ await configureClient(config);
150
+ await pullSnapshot(versionPath);
151
+ console.log(chalk.green(`Successfully updated snapshot for ${version}`));
152
+ const snapshotFilename = getSnapshotFilename();
153
+ generateDocs(path.join(versionPath, snapshotFilename), version, versionPath);
154
+ console.log(chalk.green(`Successfully updated schema.md for ${version}`));
155
+ }
156
+ catch (error) {
157
+ console.error(chalk.red(`Failed to update snapshot: ${error.message}`));
158
+ process.exit(1);
159
+ }
160
+ });
161
+ migrations
162
+ .command('run')
163
+ .description('Execute pending migrations')
164
+ .action(async () => {
165
+ try {
166
+ const options = program.opts();
167
+ await runMigrations(options.env);
168
+ }
169
+ catch (error) {
170
+ console.error(chalk.red('Migration run failed:'), error.message);
171
+ process.exit(1);
172
+ }
173
+ });
174
+ migrations
175
+ .command('status')
176
+ .description('List migration status')
177
+ .action(async () => {
178
+ try {
179
+ const options = program.opts();
180
+ const config = loadConfig(options.env);
181
+ const { databases } = createAppwriteClient(config);
182
+ const appliedIds = await getAppliedMigrations(databases, config);
183
+ const appliedSet = new Set(appliedIds);
184
+ const migrationsDir = path.join(process.cwd(), 'appwrite', 'migration');
185
+ if (!fs.existsSync(migrationsDir)) {
186
+ console.log('No migrations directory found.');
187
+ return;
188
+ }
189
+ const versionDirs = fs
190
+ .readdirSync(migrationsDir)
191
+ .filter((dir) => dir.startsWith('v') && fs.statSync(path.join(migrationsDir, dir)).isDirectory())
192
+ .sort((a, b) => parseInt(a.substring(1)) - parseInt(b.substring(1)));
193
+ console.log(chalk.bold.underline('\nMigration Status:\n'));
194
+ for (const version of versionDirs) {
195
+ const indexPath = path.join(migrationsDir, version, 'index.ts');
196
+ let id = 'unknown';
197
+ if (fs.existsSync(indexPath)) {
198
+ const content = fs.readFileSync(indexPath, 'utf8');
199
+ const match = content.match(/id:\s*["']([^"']+)["']/);
200
+ if (match)
201
+ id = match[1];
202
+ }
203
+ const status = appliedSet.has(id) ? chalk.green('APPLIED') : chalk.yellow('PENDING');
204
+ console.log(`${version.padEnd(10)} [${id}] ${status}`);
205
+ }
206
+ console.log('');
207
+ }
208
+ catch (error) {
209
+ console.error(chalk.red('Status check failed:'), error.message);
210
+ process.exit(1);
211
+ }
212
+ });
213
+ migrations
214
+ .command('docs')
215
+ .description('Pull current state from Appwrite and generate schema documentation with ER diagrams')
216
+ .action(async () => {
217
+ try {
218
+ const options = program.opts();
219
+ const config = loadConfig(options.env);
220
+ console.log(chalk.blue(`Pulling latest schema from Appwrite to project root...`));
221
+ await configureClient(config);
222
+ const snapshotPath = await pullSnapshot();
223
+ console.log(chalk.blue('Generating documentation...'));
224
+ const appwriteDir = path.join(process.cwd(), 'appwrite');
225
+ generateDocs(snapshotPath, 'latest', appwriteDir);
226
+ // Cleanup the temporary snapshot pulled to root
227
+ if (fs.existsSync(snapshotPath)) {
228
+ fs.unlinkSync(snapshotPath);
229
+ }
230
+ }
231
+ catch (error) {
232
+ console.error(chalk.red('Docs generation failed:'), error.message);
233
+ process.exit(1);
234
+ }
235
+ });
236
+ program.parse();
@@ -0,0 +1,5 @@
1
+ export * from './types/index.js';
2
+ export * from './lib/appwrite.js';
3
+ export * from './lib/config.js';
4
+ export * from './lib/cli.js';
5
+ export * from './lib/runner.js';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './types/index.js';
2
+ export * from './lib/appwrite.js';
3
+ export * from './lib/config.js';
4
+ export * from './lib/cli.js';
5
+ export * from './lib/runner.js';
@@ -0,0 +1,21 @@
1
+ import { Client, Databases } from 'node-appwrite';
2
+ import { AppConfig } from './config.js';
3
+ /**
4
+ * Create Appwrite Client and Databases instance.
5
+ */
6
+ export declare const createAppwriteClient: (config: AppConfig) => {
7
+ client: Client;
8
+ databases: Databases;
9
+ };
10
+ /**
11
+ * Ensure the system database and migrations collection exist.
12
+ */
13
+ export declare const ensureMigrationCollection: (databases: Databases, config: AppConfig) => Promise<void>;
14
+ /**
15
+ * Get list of applied migration IDs.
16
+ */
17
+ export declare const getAppliedMigrations: (databases: Databases, config: AppConfig) => Promise<string[]>;
18
+ /**
19
+ * Record a successfully applied migration.
20
+ */
21
+ export declare const recordMigration: (databases: Databases, config: AppConfig, migrationId: string, name: string) => Promise<void>;
@@ -0,0 +1,72 @@
1
+ import { Client, Databases, Query } from 'node-appwrite';
2
+ /**
3
+ * Create Appwrite Client and Databases instance.
4
+ */
5
+ export const createAppwriteClient = (config) => {
6
+ const client = new Client()
7
+ .setEndpoint(config.endpoint)
8
+ .setProject(config.projectId)
9
+ .setKey(config.apiKey);
10
+ const databases = new Databases(client);
11
+ return { client, databases };
12
+ };
13
+ /**
14
+ * Ensure the system database and migrations collection exist.
15
+ */
16
+ export const ensureMigrationCollection = async (databases, config) => {
17
+ // Ensure the system database exists.
18
+ try {
19
+ await databases.get(config.database);
20
+ }
21
+ catch (error) {
22
+ if (error.code === 404) {
23
+ console.log(`Creating system database '${config.database}'...`);
24
+ await databases.create(config.database, config.database);
25
+ }
26
+ else {
27
+ throw error;
28
+ }
29
+ }
30
+ // Ensure the migration collection exists within the system database.
31
+ try {
32
+ await databases.getCollection(config.database, config.migrationCollectionId);
33
+ }
34
+ catch (error) {
35
+ if (error.code === 404) {
36
+ console.log(`Creating migration collection '${config.migrationCollectionId}'...`);
37
+ await databases.createCollection(config.database, config.migrationCollectionId, config.migrationCollectionId);
38
+ await databases.createStringAttribute(config.database, config.migrationCollectionId, 'name', 255, true);
39
+ await databases.createDatetimeAttribute(config.database, config.migrationCollectionId, 'appliedAt', true);
40
+ }
41
+ else {
42
+ throw error;
43
+ }
44
+ }
45
+ };
46
+ /**
47
+ * Get list of applied migration IDs.
48
+ */
49
+ export const getAppliedMigrations = async (databases, config) => {
50
+ try {
51
+ const response = await databases.listDocuments(config.database, config.migrationCollectionId, [
52
+ Query.limit(5000),
53
+ ]);
54
+ return response.documents.map((doc) => doc.$id);
55
+ }
56
+ catch (error) {
57
+ if (error.code === 404) {
58
+ // If DB or Collection unavailable, no migrations applied.
59
+ return [];
60
+ }
61
+ throw error;
62
+ }
63
+ };
64
+ /**
65
+ * Record a successfully applied migration.
66
+ */
67
+ export const recordMigration = async (databases, config, migrationId, name) => {
68
+ await databases.createDocument(config.database, config.migrationCollectionId, migrationId, {
69
+ name,
70
+ appliedAt: new Date().toISOString(),
71
+ });
72
+ };
@@ -0,0 +1,28 @@
1
+ import { AppConfig } from './config.js';
2
+ /**
3
+ * Configure the Appwrite CLI client for non-interactive use via API key.
4
+ */
5
+ export declare const configureClient: (config: AppConfig) => Promise<void>;
6
+ /**
7
+ * Pull a full snapshot from Appwrite into a target directory.
8
+ * Uses individual `appwrite pull <resource>` commands for non-interactive operation.
9
+ *
10
+ * The operation works in the project root (where appwrite.config.json lives).
11
+ * If a targetDir is provided, it copies the resulting file to the target directory and cleans up the root.
12
+ */
13
+ export declare const pullSnapshot: (targetDir?: string) => Promise<string>;
14
+ /**
15
+ * Push a snapshot from a version directory to the Appwrite project.
16
+ * Copies the version's appwrite.config.json to the project root,
17
+ * then runs individual `appwrite push <resource> --all --force` commands.
18
+ *
19
+ * The `projectId` in the snapshot is rewritten to match the current config,
20
+ * allowing the same snapshot to be pushed to any environment.
21
+ *
22
+ * `--all` auto-selects all resources, `--force` auto-confirms changes.
23
+ */
24
+ export declare const pushSnapshot: (snapshotPath: string, config: AppConfig) => Promise<void>;
25
+ /**
26
+ * Get the snapshot filename used for versioned snapshots.
27
+ */
28
+ export declare const getSnapshotFilename: () => string;