appwrite-utils-cli 0.10.85 → 1.0.1
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/.appwrite/.yaml_schemas/appwrite-config.schema.json +380 -0
- package/.appwrite/.yaml_schemas/collection.schema.json +255 -0
- package/.appwrite/collections/Categories.yaml +182 -0
- package/.appwrite/collections/ExampleCollection.yaml +36 -0
- package/.appwrite/collections/Posts.yaml +227 -0
- package/.appwrite/collections/Users.yaml +149 -0
- package/.appwrite/config.yaml +109 -0
- package/.appwrite/import/README.md +148 -0
- package/.appwrite/import/categories-import.yaml +129 -0
- package/.appwrite/import/posts-import.yaml +208 -0
- package/.appwrite/import/users-import.yaml +130 -0
- package/.appwrite/importData/categories.json +194 -0
- package/.appwrite/importData/posts.json +270 -0
- package/.appwrite/importData/users.json +220 -0
- package/.appwrite/schemas/categories.json +128 -0
- package/.appwrite/schemas/exampleCollection.json +52 -0
- package/.appwrite/schemas/posts.json +173 -0
- package/.appwrite/schemas/users.json +125 -0
- package/README.md +261 -33
- package/dist/collections/attributes.js +3 -2
- package/dist/collections/methods.js +56 -38
- package/dist/config/yamlConfig.d.ts +501 -0
- package/dist/config/yamlConfig.js +452 -0
- package/dist/databases/setup.d.ts +6 -0
- package/dist/databases/setup.js +119 -0
- package/dist/functions/methods.d.ts +1 -1
- package/dist/functions/methods.js +5 -2
- package/dist/functions/openapi.d.ts +4 -0
- package/dist/functions/openapi.js +60 -0
- package/dist/interactiveCLI.d.ts +5 -0
- package/dist/interactiveCLI.js +196 -52
- package/dist/main.js +91 -30
- package/dist/migrations/afterImportActions.js +2 -2
- package/dist/migrations/appwriteToX.d.ts +10 -0
- package/dist/migrations/appwriteToX.js +15 -4
- package/dist/migrations/backup.d.ts +16 -16
- package/dist/migrations/dataLoader.d.ts +83 -1
- package/dist/migrations/dataLoader.js +4 -4
- package/dist/migrations/importController.js +25 -18
- package/dist/migrations/importDataActions.js +2 -2
- package/dist/migrations/logging.d.ts +9 -1
- package/dist/migrations/logging.js +41 -22
- package/dist/migrations/migrationHelper.d.ts +4 -4
- package/dist/migrations/relationships.js +1 -1
- package/dist/migrations/services/DataTransformationService.d.ts +55 -0
- package/dist/migrations/services/DataTransformationService.js +158 -0
- package/dist/migrations/services/FileHandlerService.d.ts +75 -0
- package/dist/migrations/services/FileHandlerService.js +236 -0
- package/dist/migrations/services/ImportOrchestrator.d.ts +97 -0
- package/dist/migrations/services/ImportOrchestrator.js +488 -0
- package/dist/migrations/services/RateLimitManager.d.ts +138 -0
- package/dist/migrations/services/RateLimitManager.js +279 -0
- package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
- package/dist/migrations/services/RelationshipResolver.js +332 -0
- package/dist/migrations/services/UserMappingService.d.ts +109 -0
- package/dist/migrations/services/UserMappingService.js +277 -0
- package/dist/migrations/services/ValidationService.d.ts +74 -0
- package/dist/migrations/services/ValidationService.js +260 -0
- package/dist/migrations/transfer.d.ts +0 -6
- package/dist/migrations/transfer.js +16 -132
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +384 -0
- package/dist/migrations/yaml/YamlImportConfigLoader.js +375 -0
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +87 -0
- package/dist/migrations/yaml/YamlImportIntegration.js +330 -0
- package/dist/migrations/yaml/generateImportSchemas.d.ts +17 -0
- package/dist/migrations/yaml/generateImportSchemas.js +575 -0
- package/dist/schemas/authUser.d.ts +9 -9
- package/dist/shared/attributeManager.d.ts +17 -0
- package/dist/shared/attributeManager.js +273 -0
- package/dist/shared/confirmationDialogs.d.ts +75 -0
- package/dist/shared/confirmationDialogs.js +236 -0
- package/dist/shared/functionManager.d.ts +48 -0
- package/dist/shared/functionManager.js +322 -0
- package/dist/shared/indexManager.d.ts +24 -0
- package/dist/shared/indexManager.js +150 -0
- package/dist/shared/jsonSchemaGenerator.d.ts +51 -0
- package/dist/shared/jsonSchemaGenerator.js +313 -0
- package/dist/shared/logging.d.ts +10 -0
- package/dist/shared/logging.js +46 -0
- package/dist/shared/messageFormatter.d.ts +37 -0
- package/dist/shared/messageFormatter.js +152 -0
- package/dist/shared/migrationHelpers.d.ts +173 -0
- package/dist/shared/migrationHelpers.js +142 -0
- package/dist/shared/operationLogger.d.ts +3 -0
- package/dist/shared/operationLogger.js +25 -0
- package/dist/shared/operationQueue.d.ts +13 -0
- package/dist/shared/operationQueue.js +79 -0
- package/dist/shared/progressManager.d.ts +62 -0
- package/dist/shared/progressManager.js +215 -0
- package/dist/shared/schemaGenerator.d.ts +18 -0
- package/dist/shared/schemaGenerator.js +523 -0
- package/dist/storage/methods.d.ts +3 -1
- package/dist/storage/methods.js +144 -55
- package/dist/storage/schemas.d.ts +56 -16
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/users/methods.d.ts +16 -0
- package/dist/users/methods.js +276 -0
- package/dist/utils/configMigration.d.ts +1 -0
- package/dist/utils/configMigration.js +156 -0
- package/dist/utils/dataConverters.d.ts +46 -0
- package/dist/utils/dataConverters.js +139 -0
- package/dist/utils/loadConfigs.d.ts +15 -4
- package/dist/utils/loadConfigs.js +377 -51
- package/dist/utils/schemaStrings.js +2 -1
- package/dist/utils/setupFiles.d.ts +2 -1
- package/dist/utils/setupFiles.js +723 -28
- package/dist/utils/validationRules.d.ts +43 -0
- package/dist/utils/validationRules.js +42 -0
- package/dist/utils/yamlConverter.d.ts +48 -0
- package/dist/utils/yamlConverter.js +98 -0
- package/dist/utilsController.js +65 -43
- package/package.json +19 -15
- package/src/collections/attributes.ts +3 -2
- package/src/collections/methods.ts +85 -51
- package/src/config/yamlConfig.ts +488 -0
- package/src/{migrations/setupDatabase.ts → databases/setup.ts} +11 -5
- package/src/functions/methods.ts +8 -4
- package/src/functions/templates/count-docs-in-collection/package.json +25 -0
- package/src/functions/templates/count-docs-in-collection/tsconfig.json +28 -0
- package/src/functions/templates/typescript-node/package.json +24 -0
- package/src/functions/templates/typescript-node/tsconfig.json +28 -0
- package/src/functions/templates/uv/README.md +31 -0
- package/src/functions/templates/uv/pyproject.toml +29 -0
- package/src/interactiveCLI.ts +230 -63
- package/src/main.ts +111 -37
- package/src/migrations/afterImportActions.ts +2 -2
- package/src/migrations/appwriteToX.ts +17 -4
- package/src/migrations/dataLoader.ts +4 -4
- package/src/migrations/importController.ts +30 -22
- package/src/migrations/importDataActions.ts +2 -2
- package/src/migrations/relationships.ts +1 -1
- package/src/migrations/services/DataTransformationService.ts +196 -0
- package/src/migrations/services/FileHandlerService.ts +311 -0
- package/src/migrations/services/ImportOrchestrator.ts +669 -0
- package/src/migrations/services/RateLimitManager.ts +363 -0
- package/src/migrations/services/RelationshipResolver.ts +461 -0
- package/src/migrations/services/UserMappingService.ts +345 -0
- package/src/migrations/services/ValidationService.ts +349 -0
- package/src/migrations/transfer.ts +22 -228
- package/src/migrations/yaml/YamlImportConfigLoader.ts +427 -0
- package/src/migrations/yaml/YamlImportIntegration.ts +419 -0
- package/src/migrations/yaml/generateImportSchemas.ts +589 -0
- package/src/shared/attributeManager.ts +429 -0
- package/src/shared/confirmationDialogs.ts +327 -0
- package/src/shared/functionManager.ts +515 -0
- package/src/shared/indexManager.ts +253 -0
- package/src/shared/jsonSchemaGenerator.ts +403 -0
- package/src/shared/logging.ts +74 -0
- package/src/shared/messageFormatter.ts +195 -0
- package/src/{migrations/migrationHelper.ts → shared/migrationHelpers.ts} +22 -4
- package/src/{migrations/helper.ts → shared/operationLogger.ts} +7 -2
- package/src/{migrations/queue.ts → shared/operationQueue.ts} +1 -1
- package/src/shared/progressManager.ts +278 -0
- package/src/{migrations/schemaStrings.ts → shared/schemaGenerator.ts} +71 -17
- package/src/storage/methods.ts +199 -78
- package/src/types.ts +2 -2
- package/src/{migrations/users.ts → users/methods.ts} +2 -2
- package/src/utils/configMigration.ts +212 -0
- package/src/utils/loadConfigs.ts +414 -52
- package/src/utils/schemaStrings.ts +2 -1
- package/src/utils/setupFiles.ts +742 -40
- package/src/{migrations → utils}/validationRules.ts +1 -1
- package/src/utils/yamlConverter.ts +131 -0
- package/src/utilsController.ts +75 -54
- package/src/functions/templates/poetry/README.md +0 -30
- package/src/functions/templates/poetry/pyproject.toml +0 -16
- package/src/migrations/attributes.ts +0 -561
- package/src/migrations/backup.ts +0 -205
- package/src/migrations/databases.ts +0 -39
- package/src/migrations/dbHelpers.ts +0 -92
- package/src/migrations/indexes.ts +0 -40
- package/src/migrations/logging.ts +0 -29
- package/src/migrations/storage.ts +0 -538
- /package/src/{migrations → functions}/openapi.ts +0 -0
- /package/src/functions/templates/{poetry → uv}/src/__init__.py +0 -0
- /package/src/functions/templates/{poetry → uv}/src/index.py +0 -0
- /package/src/{migrations/converters.ts → utils/dataConverters.ts} +0 -0
@@ -0,0 +1,488 @@
|
|
1
|
+
import { z } from "zod";
|
2
|
+
import yaml from "js-yaml";
|
3
|
+
import fs from "fs";
|
4
|
+
import path from "path";
|
5
|
+
import { AppwriteConfigSchema, type AppwriteConfig, RuntimeSchema, FunctionScopes, FunctionSpecifications, permissionsSchema, PermissionToAppwritePermission, type AppwriteFunction } from "appwrite-utils";
|
6
|
+
|
7
|
+
const YamlConfigSchema = z.object({
|
8
|
+
appwrite: z.object({
|
9
|
+
endpoint: z.string().default("https://cloud.appwrite.io/v1"),
|
10
|
+
project: z.string(),
|
11
|
+
key: z.string(),
|
12
|
+
}),
|
13
|
+
logging: z
|
14
|
+
.object({
|
15
|
+
enabled: z.boolean().default(false),
|
16
|
+
level: z.enum(["error", "warn", "info", "debug"]).default("info"),
|
17
|
+
directory: z.string().optional(),
|
18
|
+
console: z.boolean().default(false),
|
19
|
+
})
|
20
|
+
.optional()
|
21
|
+
.default({ enabled: false, level: "info", console: false }),
|
22
|
+
backups: z
|
23
|
+
.object({
|
24
|
+
enabled: z.boolean().default(true),
|
25
|
+
interval: z.number().default(3600),
|
26
|
+
retention: z.number().default(30),
|
27
|
+
cleanup: z.boolean().default(true),
|
28
|
+
})
|
29
|
+
.optional()
|
30
|
+
.default({ enabled: true, interval: 3600, retention: 30, cleanup: true }),
|
31
|
+
data: z
|
32
|
+
.object({
|
33
|
+
enableMockData: z.boolean().default(false),
|
34
|
+
documentBucketId: z.string().default("documents"),
|
35
|
+
usersCollectionName: z.string().default("Members"),
|
36
|
+
importDirectory: z.string().default("importData"),
|
37
|
+
})
|
38
|
+
.optional()
|
39
|
+
.default({
|
40
|
+
enableMockData: false,
|
41
|
+
documentBucketId: "documents",
|
42
|
+
usersCollectionName: "Members",
|
43
|
+
importDirectory: "importData",
|
44
|
+
}),
|
45
|
+
schemas: z
|
46
|
+
.object({
|
47
|
+
outputDirectory: z.string().default("schemas"),
|
48
|
+
yamlSchemaDirectory: z.string().default(".yaml_schemas"),
|
49
|
+
})
|
50
|
+
.optional()
|
51
|
+
.default({
|
52
|
+
outputDirectory: "schemas",
|
53
|
+
yamlSchemaDirectory: ".yaml_schemas",
|
54
|
+
}),
|
55
|
+
migrations: z
|
56
|
+
.object({
|
57
|
+
enabled: z.boolean().default(true),
|
58
|
+
})
|
59
|
+
.optional()
|
60
|
+
.default({
|
61
|
+
enabled: true,
|
62
|
+
}),
|
63
|
+
databases: z
|
64
|
+
.array(
|
65
|
+
z.object({
|
66
|
+
id: z.string(),
|
67
|
+
name: z.string(),
|
68
|
+
bucket: z
|
69
|
+
.object({
|
70
|
+
id: z.string(),
|
71
|
+
name: z.string(),
|
72
|
+
permissions: permissionsSchema,
|
73
|
+
fileSecurity: z.boolean().optional(),
|
74
|
+
enabled: z.boolean().optional(),
|
75
|
+
maximumFileSize: z.number().optional(),
|
76
|
+
allowedFileExtensions: z.array(z.string()).optional(),
|
77
|
+
compression: z.enum(["none", "gzip", "zstd"]).optional(),
|
78
|
+
encryption: z.boolean().optional(),
|
79
|
+
antivirus: z.boolean().optional(),
|
80
|
+
})
|
81
|
+
.optional(),
|
82
|
+
})
|
83
|
+
)
|
84
|
+
.optional()
|
85
|
+
.default([
|
86
|
+
{ id: "dev", name: "Development" },
|
87
|
+
{ id: "main", name: "Main" },
|
88
|
+
{ id: "staging", name: "Staging" },
|
89
|
+
]),
|
90
|
+
buckets: z
|
91
|
+
.array(
|
92
|
+
z.object({
|
93
|
+
id: z.string(),
|
94
|
+
name: z.string(),
|
95
|
+
permissions: permissionsSchema,
|
96
|
+
fileSecurity: z.boolean().optional(),
|
97
|
+
enabled: z.boolean().optional(),
|
98
|
+
maximumFileSize: z.number().optional(),
|
99
|
+
allowedFileExtensions: z.array(z.string()).optional(),
|
100
|
+
compression: z.enum(["none", "gzip", "zstd"]).optional(),
|
101
|
+
encryption: z.boolean().optional(),
|
102
|
+
antivirus: z.boolean().optional(),
|
103
|
+
})
|
104
|
+
)
|
105
|
+
.optional()
|
106
|
+
.default([]),
|
107
|
+
functions: z
|
108
|
+
.array(
|
109
|
+
z.object({
|
110
|
+
id: z.string(),
|
111
|
+
name: z.string(),
|
112
|
+
runtime: RuntimeSchema,
|
113
|
+
execute: z.array(z.string()).optional(),
|
114
|
+
events: z.array(z.string()).optional(),
|
115
|
+
schedule: z.string().optional(),
|
116
|
+
timeout: z.number().optional(),
|
117
|
+
enabled: z.boolean().optional(),
|
118
|
+
logging: z.boolean().optional(),
|
119
|
+
entrypoint: z.string().optional(),
|
120
|
+
commands: z.string().optional(),
|
121
|
+
scopes: z.array(FunctionScopes).optional(),
|
122
|
+
installationId: z.string().optional(),
|
123
|
+
providerRepositoryId: z.string().optional(),
|
124
|
+
providerBranch: z.string().optional(),
|
125
|
+
providerSilentMode: z.boolean().optional(),
|
126
|
+
providerRootDirectory: z.string().optional(),
|
127
|
+
templateRepository: z.string().optional(),
|
128
|
+
templateOwner: z.string().optional(),
|
129
|
+
templateRootDirectory: z.string().optional(),
|
130
|
+
templateBranch: z.string().optional(),
|
131
|
+
specification: FunctionSpecifications.optional(),
|
132
|
+
})
|
133
|
+
)
|
134
|
+
.optional()
|
135
|
+
.default([]),
|
136
|
+
});
|
137
|
+
|
138
|
+
export type YamlConfig = z.infer<typeof YamlConfigSchema>;
|
139
|
+
|
140
|
+
export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteConfig => {
|
141
|
+
const appwriteConfig: AppwriteConfig = {
|
142
|
+
appwriteEndpoint: yamlConfig.appwrite.endpoint,
|
143
|
+
appwriteProject: yamlConfig.appwrite.project,
|
144
|
+
appwriteKey: yamlConfig.appwrite.key,
|
145
|
+
appwriteClient: null,
|
146
|
+
logging: {
|
147
|
+
enabled: yamlConfig.logging.enabled,
|
148
|
+
level: yamlConfig.logging.level,
|
149
|
+
logDirectory: yamlConfig.logging.directory,
|
150
|
+
console: yamlConfig.logging.console,
|
151
|
+
},
|
152
|
+
enableBackups: yamlConfig.backups.enabled,
|
153
|
+
backupInterval: yamlConfig.backups.interval,
|
154
|
+
backupRetention: yamlConfig.backups.retention,
|
155
|
+
enableBackupCleanup: yamlConfig.backups.cleanup,
|
156
|
+
enableMockData: yamlConfig.data.enableMockData,
|
157
|
+
documentBucketId: yamlConfig.data.documentBucketId,
|
158
|
+
usersCollectionName: yamlConfig.data.usersCollectionName,
|
159
|
+
useMigrations: yamlConfig.migrations.enabled,
|
160
|
+
schemaConfig: {
|
161
|
+
outputDirectory: yamlConfig.schemas.outputDirectory,
|
162
|
+
yamlSchemaDirectory: yamlConfig.schemas.yamlSchemaDirectory,
|
163
|
+
importDirectory: yamlConfig.data.importDirectory,
|
164
|
+
},
|
165
|
+
databases: yamlConfig.databases.map((db) => ({
|
166
|
+
$id: db.id,
|
167
|
+
name: db.name,
|
168
|
+
bucket: db.bucket
|
169
|
+
? {
|
170
|
+
$id: db.bucket.id,
|
171
|
+
name: db.bucket.name,
|
172
|
+
$permissions: PermissionToAppwritePermission(db.bucket.permissions),
|
173
|
+
fileSecurity: db.bucket.fileSecurity || false,
|
174
|
+
enabled: db.bucket.enabled || true,
|
175
|
+
maximumFileSize: db.bucket.maximumFileSize || 30000000,
|
176
|
+
allowedFileExtensions: db.bucket.allowedFileExtensions || [],
|
177
|
+
compression: (db.bucket.compression as "none" | "gzip" | "zstd") || "none",
|
178
|
+
encryption: db.bucket.encryption || false,
|
179
|
+
antivirus: db.bucket.antivirus || false,
|
180
|
+
}
|
181
|
+
: undefined,
|
182
|
+
})),
|
183
|
+
buckets: yamlConfig.buckets.map((bucket) => ({
|
184
|
+
$id: bucket.id,
|
185
|
+
name: bucket.name,
|
186
|
+
$permissions: PermissionToAppwritePermission(bucket.permissions),
|
187
|
+
fileSecurity: bucket.fileSecurity || false,
|
188
|
+
enabled: bucket.enabled || true,
|
189
|
+
maximumFileSize: bucket.maximumFileSize || 30000000,
|
190
|
+
allowedFileExtensions: bucket.allowedFileExtensions || [],
|
191
|
+
compression: (bucket.compression as "none" | "gzip" | "zstd") || "none",
|
192
|
+
encryption: bucket.encryption || false,
|
193
|
+
antivirus: bucket.antivirus || false,
|
194
|
+
})),
|
195
|
+
functions: yamlConfig.functions?.map((func) => ({
|
196
|
+
$id: func.id,
|
197
|
+
name: func.name,
|
198
|
+
runtime: func.runtime,
|
199
|
+
execute: func.execute || [],
|
200
|
+
events: func.events || [],
|
201
|
+
schedule: func.schedule || "",
|
202
|
+
timeout: func.timeout || 15,
|
203
|
+
enabled: func.enabled || true,
|
204
|
+
logging: func.logging || true,
|
205
|
+
entrypoint: func.entrypoint || "",
|
206
|
+
commands: func.commands || "",
|
207
|
+
scopes: func.scopes || [],
|
208
|
+
installationId: func.installationId || "",
|
209
|
+
providerRepositoryId: func.providerRepositoryId || "",
|
210
|
+
providerBranch: func.providerBranch || "",
|
211
|
+
providerSilentMode: func.providerSilentMode || false,
|
212
|
+
providerRootDirectory: func.providerRootDirectory || "",
|
213
|
+
templateRepository: func.templateRepository || "",
|
214
|
+
templateOwner: func.templateOwner || "",
|
215
|
+
templateRootDirectory: func.templateRootDirectory || "",
|
216
|
+
templateBranch: func.templateBranch || "",
|
217
|
+
specification: func.specification || "s-0.5vcpu-512mb",
|
218
|
+
})),
|
219
|
+
collections: [],
|
220
|
+
};
|
221
|
+
|
222
|
+
return appwriteConfig;
|
223
|
+
};
|
224
|
+
|
225
|
+
export const loadYamlConfig = async (configPath: string): Promise<AppwriteConfig | null> => {
|
226
|
+
try {
|
227
|
+
const fileContent = fs.readFileSync(configPath, "utf8");
|
228
|
+
const yamlData = yaml.load(fileContent) as unknown;
|
229
|
+
|
230
|
+
const yamlConfig = YamlConfigSchema.parse(yamlData);
|
231
|
+
return convertYamlToAppwriteConfig(yamlConfig);
|
232
|
+
} catch (error) {
|
233
|
+
if (error instanceof z.ZodError) {
|
234
|
+
console.error("❌ YAML config validation failed:");
|
235
|
+
error.errors.forEach((err) => {
|
236
|
+
console.error(` ${err.path.join('.')} → ${err.message}`);
|
237
|
+
});
|
238
|
+
} else {
|
239
|
+
console.error("❌ Error loading YAML config:", error instanceof Error ? error.message : error);
|
240
|
+
if (error instanceof Error && error.stack) {
|
241
|
+
console.error("Stack trace:", error.stack);
|
242
|
+
}
|
243
|
+
}
|
244
|
+
return null;
|
245
|
+
}
|
246
|
+
};
|
247
|
+
|
248
|
+
export const findYamlConfig = (startDir: string): string | null => {
|
249
|
+
// First check current directory for YAML configs
|
250
|
+
const possiblePaths = [
|
251
|
+
path.join(startDir, ".appwrite", "appwriteConfig.yaml"),
|
252
|
+
path.join(startDir, ".appwrite", "appwriteConfig.yml"),
|
253
|
+
path.join(startDir, ".appwrite", "config.yaml"),
|
254
|
+
path.join(startDir, ".appwrite", "config.yml"),
|
255
|
+
path.join(startDir, "appwrite.yaml"),
|
256
|
+
path.join(startDir, "appwrite.yml"),
|
257
|
+
];
|
258
|
+
|
259
|
+
for (const configPath of possiblePaths) {
|
260
|
+
if (fs.existsSync(configPath)) {
|
261
|
+
return configPath;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
// Recursively search subdirectories for .appwrite folders
|
266
|
+
const yamlConfigInSubdirs = findYamlConfigRecursive(startDir);
|
267
|
+
if (yamlConfigInSubdirs) {
|
268
|
+
return yamlConfigInSubdirs;
|
269
|
+
}
|
270
|
+
|
271
|
+
// Only check one level up to avoid infinite traversal
|
272
|
+
const parentDir = path.dirname(startDir);
|
273
|
+
if (parentDir !== startDir && path.basename(parentDir) !== 'node_modules') {
|
274
|
+
const parentPossiblePaths = [
|
275
|
+
path.join(parentDir, ".appwrite", "appwriteConfig.yaml"),
|
276
|
+
path.join(parentDir, ".appwrite", "appwriteConfig.yml"),
|
277
|
+
path.join(parentDir, "appwrite.yaml"),
|
278
|
+
path.join(parentDir, "appwrite.yml"),
|
279
|
+
];
|
280
|
+
|
281
|
+
for (const configPath of parentPossiblePaths) {
|
282
|
+
if (fs.existsSync(configPath)) {
|
283
|
+
return configPath;
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
return null;
|
289
|
+
};
|
290
|
+
|
291
|
+
const shouldIgnoreDirectory = (dirName: string): boolean => {
|
292
|
+
const ignoredDirs = [
|
293
|
+
'node_modules',
|
294
|
+
'dist',
|
295
|
+
'build',
|
296
|
+
'coverage',
|
297
|
+
'.next',
|
298
|
+
'.nuxt',
|
299
|
+
'.cache',
|
300
|
+
'.git',
|
301
|
+
'.svn',
|
302
|
+
'.hg',
|
303
|
+
'__pycache__',
|
304
|
+
'.pytest_cache',
|
305
|
+
'.mypy_cache',
|
306
|
+
'venv',
|
307
|
+
'.venv',
|
308
|
+
'env',
|
309
|
+
'.env',
|
310
|
+
'target',
|
311
|
+
'out',
|
312
|
+
'bin',
|
313
|
+
'obj',
|
314
|
+
'.vs',
|
315
|
+
'.vscode',
|
316
|
+
'.idea',
|
317
|
+
'temp',
|
318
|
+
'tmp',
|
319
|
+
'.tmp',
|
320
|
+
'logs',
|
321
|
+
'log',
|
322
|
+
'.DS_Store',
|
323
|
+
'Thumbs.db'
|
324
|
+
];
|
325
|
+
|
326
|
+
return ignoredDirs.includes(dirName) ||
|
327
|
+
dirName.startsWith('.git') ||
|
328
|
+
dirName.startsWith('node_modules') ||
|
329
|
+
dirName.startsWith('.');
|
330
|
+
};
|
331
|
+
|
332
|
+
const findYamlConfigRecursive = (dir: string, depth: number = 0): string | null => {
|
333
|
+
// Limit search depth to prevent infinite recursion
|
334
|
+
if (depth > 5) {
|
335
|
+
return null;
|
336
|
+
}
|
337
|
+
|
338
|
+
if (shouldIgnoreDirectory(path.basename(dir))) {
|
339
|
+
return null;
|
340
|
+
}
|
341
|
+
|
342
|
+
try {
|
343
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
344
|
+
|
345
|
+
for (const entry of entries) {
|
346
|
+
if (entry.isDirectory() && !shouldIgnoreDirectory(entry.name)) {
|
347
|
+
const fullPath = path.join(dir, entry.name);
|
348
|
+
|
349
|
+
// Check if this is an .appwrite directory
|
350
|
+
if (entry.name === ".appwrite") {
|
351
|
+
const configPaths = [
|
352
|
+
path.join(fullPath, "appwriteConfig.yaml"),
|
353
|
+
path.join(fullPath, "appwriteConfig.yml"),
|
354
|
+
path.join(fullPath, "config.yaml"),
|
355
|
+
path.join(fullPath, "config.yml"),
|
356
|
+
];
|
357
|
+
|
358
|
+
for (const configPath of configPaths) {
|
359
|
+
if (fs.existsSync(configPath)) {
|
360
|
+
return configPath;
|
361
|
+
}
|
362
|
+
}
|
363
|
+
}
|
364
|
+
|
365
|
+
// Recurse into other directories with increased depth
|
366
|
+
const result = findYamlConfigRecursive(fullPath, depth + 1);
|
367
|
+
if (result) return result;
|
368
|
+
}
|
369
|
+
}
|
370
|
+
} catch (error) {
|
371
|
+
// Ignore directory access errors
|
372
|
+
}
|
373
|
+
|
374
|
+
return null;
|
375
|
+
};
|
376
|
+
|
377
|
+
export const generateYamlConfigTemplate = (outputPath: string) => {
|
378
|
+
const template: YamlConfig = {
|
379
|
+
appwrite: {
|
380
|
+
endpoint: "https://cloud.appwrite.io/v1",
|
381
|
+
project: "YOUR_PROJECT_ID",
|
382
|
+
key: "YOUR_API_KEY",
|
383
|
+
},
|
384
|
+
logging: {
|
385
|
+
enabled: false,
|
386
|
+
level: "info",
|
387
|
+
console: false,
|
388
|
+
},
|
389
|
+
backups: {
|
390
|
+
enabled: true,
|
391
|
+
interval: 3600,
|
392
|
+
retention: 30,
|
393
|
+
cleanup: true,
|
394
|
+
},
|
395
|
+
data: {
|
396
|
+
enableMockData: false,
|
397
|
+
documentBucketId: "documents",
|
398
|
+
usersCollectionName: "Members",
|
399
|
+
importDirectory: "importData",
|
400
|
+
},
|
401
|
+
schemas: {
|
402
|
+
outputDirectory: "schemas",
|
403
|
+
yamlSchemaDirectory: ".yaml_schemas",
|
404
|
+
},
|
405
|
+
migrations: {
|
406
|
+
enabled: true,
|
407
|
+
},
|
408
|
+
databases: [
|
409
|
+
{ id: "dev", name: "Development" },
|
410
|
+
{ id: "main", name: "Main" },
|
411
|
+
{ id: "staging", name: "Staging" },
|
412
|
+
],
|
413
|
+
buckets: [],
|
414
|
+
functions: [],
|
415
|
+
};
|
416
|
+
|
417
|
+
const yamlContent = yaml.dump(template, {
|
418
|
+
indent: 2,
|
419
|
+
lineWidth: 120,
|
420
|
+
sortKeys: false,
|
421
|
+
});
|
422
|
+
|
423
|
+
// Add schema reference header
|
424
|
+
const schemaReference = "# yaml-language-server: $schema=./.yaml_schemas/appwrite-config.schema.json\n";
|
425
|
+
const finalContent = schemaReference + "# Appwrite Project Configuration\n" + yamlContent;
|
426
|
+
|
427
|
+
fs.writeFileSync(outputPath, finalContent, "utf8");
|
428
|
+
};
|
429
|
+
|
430
|
+
/**
|
431
|
+
* Adds a new function to the YAML config file
|
432
|
+
* @param configPath Path to the YAML config file
|
433
|
+
* @param newFunction The function configuration to add
|
434
|
+
*/
|
435
|
+
export const addFunctionToYamlConfig = async (configPath: string, newFunction: AppwriteFunction): Promise<void> => {
|
436
|
+
try {
|
437
|
+
// Read current config
|
438
|
+
const fileContent = fs.readFileSync(configPath, "utf8");
|
439
|
+
const yamlData = yaml.load(fileContent) as any;
|
440
|
+
|
441
|
+
// Initialize functions array if it doesn't exist
|
442
|
+
if (!yamlData.functions) {
|
443
|
+
yamlData.functions = [];
|
444
|
+
}
|
445
|
+
|
446
|
+
// Convert AppwriteFunction to YAML format
|
447
|
+
const yamlFunction = {
|
448
|
+
id: newFunction.$id,
|
449
|
+
name: newFunction.name,
|
450
|
+
runtime: newFunction.runtime,
|
451
|
+
execute: newFunction.execute || ["any"],
|
452
|
+
events: newFunction.events || [],
|
453
|
+
schedule: newFunction.schedule || "",
|
454
|
+
timeout: newFunction.timeout || 15,
|
455
|
+
enabled: newFunction.enabled !== false,
|
456
|
+
logging: newFunction.logging !== false,
|
457
|
+
entrypoint: newFunction.entrypoint || "",
|
458
|
+
commands: newFunction.commands || "",
|
459
|
+
scopes: newFunction.scopes || [],
|
460
|
+
specification: newFunction.specification || "s-0.5vcpu-512mb"
|
461
|
+
};
|
462
|
+
|
463
|
+
// Add new function
|
464
|
+
yamlData.functions.push(yamlFunction);
|
465
|
+
|
466
|
+
// Write back to file
|
467
|
+
const updatedYamlContent = yaml.dump(yamlData, {
|
468
|
+
indent: 2,
|
469
|
+
lineWidth: 120,
|
470
|
+
sortKeys: false,
|
471
|
+
});
|
472
|
+
|
473
|
+
// Preserve schema reference if it exists
|
474
|
+
const lines = fileContent.split('\n');
|
475
|
+
const schemaLine = lines.find(line => line.startsWith('# yaml-language-server:'));
|
476
|
+
let finalContent = updatedYamlContent;
|
477
|
+
|
478
|
+
if (schemaLine) {
|
479
|
+
finalContent = schemaLine + '\n' + updatedYamlContent;
|
480
|
+
}
|
481
|
+
|
482
|
+
fs.writeFileSync(configPath, finalContent, "utf8");
|
483
|
+
console.log(`✅ Added function "${newFunction.name}" to YAML config`);
|
484
|
+
} catch (error) {
|
485
|
+
console.error("❌ Error adding function to YAML config:", error instanceof Error ? error.message : error);
|
486
|
+
throw error;
|
487
|
+
}
|
488
|
+
};
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { Databases, Query, type Models } from "node-appwrite";
|
2
2
|
import { createOrUpdateAttribute } from "../collections/attributes.js";
|
3
|
-
import { getMigrationCollectionSchemas } from "
|
3
|
+
import { getMigrationCollectionSchemas } from "../storage/schemas.js";
|
4
4
|
import {
|
5
5
|
areCollectionNamesSame,
|
6
6
|
delay,
|
@@ -11,6 +11,11 @@ import { type AppwriteConfig } from "appwrite-utils";
|
|
11
11
|
import { ulid } from "ulidx";
|
12
12
|
|
13
13
|
export const setupMigrationDatabase = async (config: AppwriteConfig) => {
|
14
|
+
if (!config.useMigrations) {
|
15
|
+
console.log("Migrations database disabled, skipping setup");
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
|
14
19
|
console.log("---------------------------------");
|
15
20
|
console.log("Starting Migrations Setup");
|
16
21
|
console.log("---------------------------------");
|
@@ -125,8 +130,8 @@ export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEn
|
|
125
130
|
const migrationsDatabase = existingDatabases.databases.find(
|
126
131
|
(d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"
|
127
132
|
);
|
128
|
-
if (existingDatabases.databases.length !== 0 && migrationsDatabase) {
|
129
|
-
console.log("Creating all databases
|
133
|
+
if (config.useMigrations && existingDatabases.databases.length !== 0 && migrationsDatabase) {
|
134
|
+
console.log("Creating all databases including migrations");
|
130
135
|
databasesToCreate.push(migrationsDatabase);
|
131
136
|
}
|
132
137
|
|
@@ -142,7 +147,8 @@ export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEn
|
|
142
147
|
|
143
148
|
export const wipeOtherDatabases = async (
|
144
149
|
database: Databases,
|
145
|
-
databasesToKeep: Models.Database[]
|
150
|
+
databasesToKeep: Models.Database[],
|
151
|
+
useMigrations: boolean = true
|
146
152
|
) => {
|
147
153
|
console.log(`Databases to keep: ${databasesToKeep.map(db => db.name).join(", ")}`);
|
148
154
|
const allDatabases = await tryAwaitWithRetry(
|
@@ -151,7 +157,7 @@ export const wipeOtherDatabases = async (
|
|
151
157
|
const migrationsDatabase = allDatabases.databases.find(
|
152
158
|
(d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"
|
153
159
|
);
|
154
|
-
if (allDatabases.databases.length !== 0 && migrationsDatabase) {
|
160
|
+
if (useMigrations && allDatabases.databases.length !== 0 && migrationsDatabase) {
|
155
161
|
console.log("Wiping all databases except migrations");
|
156
162
|
databasesToKeep.push(migrationsDatabase);
|
157
163
|
}
|
package/src/functions/methods.ts
CHANGED
@@ -5,12 +5,14 @@ import {
|
|
5
5
|
Query,
|
6
6
|
Runtime,
|
7
7
|
} from "node-appwrite";
|
8
|
-
import { join } from "node:path";
|
8
|
+
import { join, dirname } from "node:path";
|
9
|
+
import { fileURLToPath } from "node:url";
|
9
10
|
import fs from "node:fs";
|
10
11
|
import {
|
11
12
|
type AppwriteFunction,
|
12
13
|
type FunctionScope,
|
13
14
|
type Specification,
|
15
|
+
type Runtime as AppwriteUtilsRuntime,
|
14
16
|
} from "appwrite-utils";
|
15
17
|
import chalk from "chalk";
|
16
18
|
import { extract as extractTar } from "tar";
|
@@ -136,7 +138,7 @@ export const updateFunctionSpecifications = async (
|
|
136
138
|
try {
|
137
139
|
const functionResponse = await updateFunction(client, {
|
138
140
|
...functionFound,
|
139
|
-
runtime: functionFound.runtime as
|
141
|
+
runtime: functionFound.runtime as AppwriteUtilsRuntime,
|
140
142
|
scopes: functionFound.scopes as FunctionScope[],
|
141
143
|
specification: specification,
|
142
144
|
});
|
@@ -193,12 +195,14 @@ export const updateFunction = async (
|
|
193
195
|
};
|
194
196
|
|
195
197
|
export const createFunctionTemplate = async (
|
196
|
-
templateType: "typescript-node" | "
|
198
|
+
templateType: "typescript-node" | "uv" | "count-docs-in-collection",
|
197
199
|
functionName: string,
|
198
200
|
basePath: string = "./functions"
|
199
201
|
) => {
|
200
202
|
const functionPath = join(basePath, functionName);
|
201
|
-
const
|
203
|
+
const currentFileUrl = import.meta.url;
|
204
|
+
const currentDir = dirname(fileURLToPath(currentFileUrl));
|
205
|
+
const templatesPath = join(currentDir, "templates", templateType);
|
202
206
|
|
203
207
|
// Create function directory
|
204
208
|
await fs.promises.mkdir(functionPath, { recursive: true });
|
@@ -0,0 +1,25 @@
|
|
1
|
+
{
|
2
|
+
"name": "{{functionName}}",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "Appwrite function to count documents in a collection",
|
5
|
+
"main": "src/main.ts",
|
6
|
+
"type": "module",
|
7
|
+
"scripts": {
|
8
|
+
"build": "tsc",
|
9
|
+
"start": "node dist/main.js",
|
10
|
+
"dev": "tsx src/main.ts"
|
11
|
+
},
|
12
|
+
"dependencies": {
|
13
|
+
"node-appwrite": "^13.0.0",
|
14
|
+
"appwrite-utils": "latest",
|
15
|
+
"zod": "^3.23.0"
|
16
|
+
},
|
17
|
+
"devDependencies": {
|
18
|
+
"@types/node": "^20.0.0",
|
19
|
+
"typescript": "^5.0.0",
|
20
|
+
"tsx": "^4.0.0"
|
21
|
+
},
|
22
|
+
"engines": {
|
23
|
+
"node": ">=18.0.0"
|
24
|
+
}
|
25
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"target": "ES2022",
|
4
|
+
"module": "ESNext",
|
5
|
+
"moduleResolution": "node",
|
6
|
+
"allowSyntheticDefaultImports": true,
|
7
|
+
"esModuleInterop": true,
|
8
|
+
"allowJs": true,
|
9
|
+
"checkJs": false,
|
10
|
+
"outDir": "./dist",
|
11
|
+
"rootDir": "./src",
|
12
|
+
"strict": true,
|
13
|
+
"noImplicitAny": true,
|
14
|
+
"strictNullChecks": true,
|
15
|
+
"strictFunctionTypes": true,
|
16
|
+
"noImplicitThis": true,
|
17
|
+
"noImplicitReturns": true,
|
18
|
+
"noFallthroughCasesInSwitch": true,
|
19
|
+
"moduleDetection": "force",
|
20
|
+
"resolveJsonModule": true,
|
21
|
+
"isolatedModules": true,
|
22
|
+
"verbatimModuleSyntax": false,
|
23
|
+
"skipLibCheck": true,
|
24
|
+
"forceConsistentCasingInFileNames": true
|
25
|
+
},
|
26
|
+
"include": ["src/**/*"],
|
27
|
+
"exclude": ["node_modules", "dist"]
|
28
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"name": "{{functionName}}",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "Appwrite TypeScript Node.js function",
|
5
|
+
"main": "src/index.ts",
|
6
|
+
"type": "module",
|
7
|
+
"scripts": {
|
8
|
+
"build": "tsc",
|
9
|
+
"start": "node dist/index.js",
|
10
|
+
"dev": "tsx src/index.ts"
|
11
|
+
},
|
12
|
+
"dependencies": {
|
13
|
+
"node-appwrite": "^13.0.0",
|
14
|
+
"appwrite-utils": "latest"
|
15
|
+
},
|
16
|
+
"devDependencies": {
|
17
|
+
"@types/node": "^20.0.0",
|
18
|
+
"typescript": "^5.0.0",
|
19
|
+
"tsx": "^4.0.0"
|
20
|
+
},
|
21
|
+
"engines": {
|
22
|
+
"node": ">=18.0.0"
|
23
|
+
}
|
24
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"target": "ES2022",
|
4
|
+
"module": "ESNext",
|
5
|
+
"moduleResolution": "node",
|
6
|
+
"allowSyntheticDefaultImports": true,
|
7
|
+
"esModuleInterop": true,
|
8
|
+
"allowJs": true,
|
9
|
+
"checkJs": false,
|
10
|
+
"outDir": "./dist",
|
11
|
+
"rootDir": "./src",
|
12
|
+
"strict": true,
|
13
|
+
"noImplicitAny": true,
|
14
|
+
"strictNullChecks": true,
|
15
|
+
"strictFunctionTypes": true,
|
16
|
+
"noImplicitThis": true,
|
17
|
+
"noImplicitReturns": true,
|
18
|
+
"noFallthroughCasesInSwitch": true,
|
19
|
+
"moduleDetection": "force",
|
20
|
+
"resolveJsonModule": true,
|
21
|
+
"isolatedModules": true,
|
22
|
+
"verbatimModuleSyntax": false,
|
23
|
+
"skipLibCheck": true,
|
24
|
+
"forceConsistentCasingInFileNames": true
|
25
|
+
},
|
26
|
+
"include": ["src/**/*"],
|
27
|
+
"exclude": ["node_modules", "dist"]
|
28
|
+
}
|