appwrite-utils-cli 0.0.261 → 0.0.263
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 +24 -5
- package/dist/main.js +6 -0
- package/dist/migrations/afterImportActions.d.ts +3 -1
- package/dist/migrations/afterImportActions.js +2 -2
- package/dist/migrations/appwriteToX.d.ts +109 -0
- package/dist/migrations/appwriteToX.js +88 -0
- package/dist/migrations/backup.d.ts +4 -4
- package/dist/migrations/converters.js +1 -1
- package/dist/migrations/dataLoader.d.ts +19 -18
- package/dist/migrations/dataLoader.js +65 -84
- package/dist/migrations/databases.d.ts +2 -0
- package/dist/migrations/databases.js +23 -0
- package/dist/migrations/importController.js +3 -0
- package/dist/migrations/importDataActions.d.ts +1 -1
- package/dist/migrations/importDataActions.js +1 -1
- package/dist/migrations/schema.d.ts +363 -32
- package/dist/migrations/schema.js +48 -28
- package/dist/migrations/schemaStrings.d.ts +1 -0
- package/dist/migrations/schemaStrings.js +10 -0
- package/dist/setup.js +0 -0
- package/dist/utils/helperFunctions.d.ts +3 -0
- package/dist/utils/helperFunctions.js +8 -0
- package/dist/utilsController.d.ts +1 -0
- package/dist/utilsController.js +7 -0
- package/package.json +1 -1
- package/src/main.ts +6 -0
- package/src/migrations/afterImportActions.ts +2 -2
- package/src/migrations/appwriteToX.ts +122 -0
- package/src/migrations/converters.ts +2 -2
- package/src/migrations/dataLoader.ts +87 -95
- package/src/migrations/databases.ts +25 -0
- package/src/migrations/importController.ts +3 -0
- package/src/migrations/importDataActions.ts +1 -1
- package/src/migrations/schema.ts +65 -36
- package/src/migrations/schemaStrings.ts +11 -0
- package/src/utils/helperFunctions.ts +17 -0
- package/src/utilsController.ts +9 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
import { Databases, Query, type Models } from "node-appwrite";
|
2
|
+
|
3
|
+
export const fetchAllDatabases = async (
|
4
|
+
database: Databases
|
5
|
+
): Promise<Models.Database[]> => {
|
6
|
+
const databases = await database.list([Query.limit(25)]);
|
7
|
+
const allDatabases = databases.databases;
|
8
|
+
let lastDatabaseId = allDatabases[allDatabases.length - 1].$id;
|
9
|
+
if (databases.databases.length < 25) {
|
10
|
+
return allDatabases;
|
11
|
+
} else {
|
12
|
+
while (lastDatabaseId) {
|
13
|
+
const databases = await database.list([
|
14
|
+
Query.limit(25),
|
15
|
+
Query.cursorAfter(lastDatabaseId),
|
16
|
+
]);
|
17
|
+
allDatabases.push(...databases.databases);
|
18
|
+
if (databases.databases.length < 25) {
|
19
|
+
break;
|
20
|
+
}
|
21
|
+
lastDatabaseId = databases.databases[databases.databases.length - 1].$id;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
return allDatabases;
|
25
|
+
};
|
@@ -236,6 +236,9 @@ export class ImportController {
|
|
236
236
|
if (item.finalData.hasOwnProperty("docId")) {
|
237
237
|
delete item.finalData.docId;
|
238
238
|
}
|
239
|
+
if (!item.finalData) {
|
240
|
+
return Promise.resolve();
|
241
|
+
}
|
239
242
|
return this.database
|
240
243
|
.createDocument(db.$id, collection.$id, id, item.finalData)
|
241
244
|
.then(() => {
|
@@ -45,7 +45,7 @@ export class ImportDataActions {
|
|
45
45
|
this.afterImportActionsDefinitions = afterImportActionsDefinitions;
|
46
46
|
}
|
47
47
|
|
48
|
-
|
48
|
+
runConverterFunctions(item: any, attributeMappings: AttributeMappings) {
|
49
49
|
const conversionSchema = attributeMappings.reduce((schema, mapping) => {
|
50
50
|
schema[mapping.targetKey] = (originalValue: any) => {
|
51
51
|
return mapping.converters.reduce((value, converterName) => {
|
package/src/migrations/schema.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ID, IndexType } from "node-appwrite";
|
1
|
+
import { ID, IndexType, Permission } from "node-appwrite";
|
2
2
|
import { z } from "zod";
|
3
3
|
|
4
4
|
const stringAttributeSchema = z.object({
|
@@ -376,6 +376,8 @@ export const indexSchema = z.object({
|
|
376
376
|
orders: z.array(z.string()).optional(),
|
377
377
|
});
|
378
378
|
|
379
|
+
export const indexesSchema = z.array(indexSchema);
|
380
|
+
|
379
381
|
export type Index = z.infer<typeof indexSchema>;
|
380
382
|
|
381
383
|
export const AttributeMappingsSchema = z.array(
|
@@ -435,6 +437,28 @@ export const AttributeMappingsSchema = z.array(
|
|
435
437
|
})
|
436
438
|
);
|
437
439
|
|
440
|
+
export const idMappingSchema = z.array(
|
441
|
+
z.object({
|
442
|
+
sourceField: z
|
443
|
+
.string()
|
444
|
+
.describe(
|
445
|
+
"The key of the data in the import data to match in the current data"
|
446
|
+
),
|
447
|
+
fieldToSet: z
|
448
|
+
.string()
|
449
|
+
.optional()
|
450
|
+
.describe(
|
451
|
+
"The field to set in the target collection, if different from sourceField"
|
452
|
+
),
|
453
|
+
targetField: z
|
454
|
+
.string()
|
455
|
+
.describe(
|
456
|
+
"The field in the target collection to match with sourceField that will then be updated"
|
457
|
+
),
|
458
|
+
targetCollection: z.string().describe("The collection to search"),
|
459
|
+
})
|
460
|
+
);
|
461
|
+
|
438
462
|
export const importDefSchema = z
|
439
463
|
.object({
|
440
464
|
type: z
|
@@ -457,28 +481,7 @@ export const importDefSchema = z
|
|
457
481
|
.describe(
|
458
482
|
"The field in the import data representing the primary key for this import data (if any)"
|
459
483
|
),
|
460
|
-
idMappings:
|
461
|
-
.array(
|
462
|
-
z.object({
|
463
|
-
sourceField: z
|
464
|
-
.string()
|
465
|
-
.describe(
|
466
|
-
"The key of the data in the import data to match in the current data"
|
467
|
-
),
|
468
|
-
fieldToSet: z
|
469
|
-
.string()
|
470
|
-
.optional()
|
471
|
-
.describe(
|
472
|
-
"The field to set in the target collection, if different from sourceField"
|
473
|
-
),
|
474
|
-
targetField: z
|
475
|
-
.string()
|
476
|
-
.describe(
|
477
|
-
"The field in the target collection to match with sourceField that will then be updated"
|
478
|
-
),
|
479
|
-
targetCollection: z.string().describe("The collection to search"),
|
480
|
-
})
|
481
|
-
)
|
484
|
+
idMappings: idMappingSchema
|
482
485
|
.optional()
|
483
486
|
.describe("The id mappings for the attribute to map ID's to"),
|
484
487
|
updateMapping: z
|
@@ -509,12 +512,45 @@ export const importDefSchemas = z
|
|
509
512
|
.default([])
|
510
513
|
.describe("The import definitions for the database");
|
511
514
|
|
515
|
+
export const permissionSchema = z
|
516
|
+
.object({
|
517
|
+
permission: z.string(),
|
518
|
+
target: z.string(),
|
519
|
+
})
|
520
|
+
.or(
|
521
|
+
z.string().transform((val) => {
|
522
|
+
const trimmedVal = val.trim();
|
523
|
+
// Adjusted regex to match double quotes
|
524
|
+
const match = trimmedVal.match(/^(\w+)\("([^"]+)"\)$/);
|
525
|
+
if (!match) {
|
526
|
+
throw new Error(`Invalid permission format: ${trimmedVal}`);
|
527
|
+
}
|
528
|
+
return {
|
529
|
+
permission: match[1],
|
530
|
+
target: match[2],
|
531
|
+
};
|
532
|
+
})
|
533
|
+
);
|
534
|
+
|
535
|
+
export const permissionsSchema = z.array(permissionSchema).optional();
|
536
|
+
|
537
|
+
export const attributesSchema = z.array(attributeSchema).default([]);
|
538
|
+
|
512
539
|
export const collectionSchema = z.object({
|
540
|
+
name: z.string().describe("The name of the collection"),
|
513
541
|
$id: z
|
514
542
|
.string()
|
515
543
|
.optional()
|
516
544
|
.default(ID.unique())
|
517
545
|
.describe("The ID of the collection, auto generated if not provided"),
|
546
|
+
enabled: z
|
547
|
+
.boolean()
|
548
|
+
.default(true)
|
549
|
+
.describe("Whether the collection is enabled or not"),
|
550
|
+
documentSecurity: z
|
551
|
+
.boolean()
|
552
|
+
.default(false)
|
553
|
+
.describe("Whether document security is enabled or not"),
|
518
554
|
$createdAt: z.string(),
|
519
555
|
$updatedAt: z.string(),
|
520
556
|
$permissions: z
|
@@ -526,19 +562,6 @@ export const collectionSchema = z.object({
|
|
526
562
|
)
|
527
563
|
.default([])
|
528
564
|
.describe("The permissions of the collection"),
|
529
|
-
databaseId: z
|
530
|
-
.string()
|
531
|
-
.optional()
|
532
|
-
.describe("The ID of the database the collection belongs to"),
|
533
|
-
name: z.string().describe("The name of the collection"),
|
534
|
-
enabled: z
|
535
|
-
.boolean()
|
536
|
-
.default(true)
|
537
|
-
.describe("Whether the collection is enabled or not"),
|
538
|
-
documentSecurity: z
|
539
|
-
.boolean()
|
540
|
-
.default(false)
|
541
|
-
.describe("Whether document security is enabled or not"),
|
542
565
|
attributes: z
|
543
566
|
.array(attributeSchema)
|
544
567
|
.default([])
|
@@ -548,6 +571,10 @@ export const collectionSchema = z.object({
|
|
548
571
|
.default([])
|
549
572
|
.describe("The indexes of the collection"),
|
550
573
|
importDefs: importDefSchemas,
|
574
|
+
databaseId: z
|
575
|
+
.string()
|
576
|
+
.optional()
|
577
|
+
.describe("The ID of the database the collection belongs to"),
|
551
578
|
});
|
552
579
|
|
553
580
|
export const CollectionCreateSchema = collectionSchema.omit({
|
@@ -622,5 +649,7 @@ export type ConfigDatabases = AppwriteConfig["databases"];
|
|
622
649
|
export type ConfigDatabase = ConfigDatabases[number];
|
623
650
|
export type ImportDefs = z.infer<typeof importDefSchemas>;
|
624
651
|
export type ImportDef = z.infer<typeof importDefSchema>;
|
652
|
+
export type IdMappings = z.infer<typeof idMappingSchema>;
|
653
|
+
export type IdMapping = IdMappings[number];
|
625
654
|
export type AttributeMappings = z.infer<typeof AttributeMappingsSchema>;
|
626
655
|
export type AttributeMapping = AttributeMappings[number];
|
@@ -7,6 +7,7 @@ import type {
|
|
7
7
|
import { z } from "zod";
|
8
8
|
import fs from "fs";
|
9
9
|
import path from "path";
|
10
|
+
import { dump } from "js-yaml";
|
10
11
|
|
11
12
|
interface RelationshipDetail {
|
12
13
|
parentCollection: string;
|
@@ -28,6 +29,16 @@ export class SchemaGenerator {
|
|
28
29
|
this.extractRelationships();
|
29
30
|
}
|
30
31
|
|
32
|
+
public updateYamlSchemas(): void {
|
33
|
+
// Output this.config to a YAML file at appwriteFolderPath/appwriteConfig.yaml
|
34
|
+
let finalConfig = this.config;
|
35
|
+
finalConfig.appwriteClient = null;
|
36
|
+
const yamlConfig = finalConfig;
|
37
|
+
const yamlPath = path.join(this.appwriteFolderPath, "appwriteConfig.yaml");
|
38
|
+
fs.writeFileSync(yamlPath, dump(yamlConfig), { encoding: "utf-8" });
|
39
|
+
console.log(`YAML written to ${yamlPath}`);
|
40
|
+
}
|
41
|
+
|
31
42
|
private extractRelationships(): void {
|
32
43
|
this.config.collections.forEach((collection) => {
|
33
44
|
collection.attributes.forEach((attr) => {
|
@@ -2,6 +2,8 @@ import type { AppwriteConfig } from "../types.js";
|
|
2
2
|
import type { Models, Storage } from "node-appwrite";
|
3
3
|
import fs from "node:fs";
|
4
4
|
import path from "node:path";
|
5
|
+
import type { CollectionImportData } from "src/migrations/dataLoader.js";
|
6
|
+
import type { ConfigCollection } from "src/migrations/schema.js";
|
5
7
|
|
6
8
|
export const toPascalCase = (str: string): string => {
|
7
9
|
return (
|
@@ -109,3 +111,18 @@ export const getFileDownloadUrl = (
|
|
109
111
|
jwt ? `&jwt=${jwt.jwt}` : ""
|
110
112
|
}`;
|
111
113
|
};
|
114
|
+
|
115
|
+
export const finalizeByAttributeMap = async (
|
116
|
+
appwriteFolderPath: string,
|
117
|
+
collection: ConfigCollection,
|
118
|
+
item: CollectionImportData["data"][number]
|
119
|
+
) => {
|
120
|
+
const schemaFolderPath = path.join(appwriteFolderPath, "schemas");
|
121
|
+
const zodSchema = await import(
|
122
|
+
`${schemaFolderPath}/${toCamelCase(collection.name)}.ts`
|
123
|
+
);
|
124
|
+
return zodSchema.parse({
|
125
|
+
...item.context,
|
126
|
+
...item.finalData,
|
127
|
+
});
|
128
|
+
};
|
package/src/utilsController.ts
CHANGED
@@ -23,6 +23,7 @@ import {
|
|
23
23
|
} from "./migrations/validationRules.js";
|
24
24
|
import { ImportController } from "./migrations/importController.js";
|
25
25
|
import _ from "lodash";
|
26
|
+
import { AppwriteToX } from "./migrations/appwriteToX.js";
|
26
27
|
|
27
28
|
async function loadConfig(configPath: string) {
|
28
29
|
if (!fs.existsSync(configPath)) {
|
@@ -35,6 +36,7 @@ async function loadConfig(configPath: string) {
|
|
35
36
|
}
|
36
37
|
|
37
38
|
export interface SetupOptions {
|
39
|
+
sync: boolean;
|
38
40
|
runProd: boolean;
|
39
41
|
runStaging: boolean;
|
40
42
|
runDev: boolean;
|
@@ -127,6 +129,13 @@ export class UtilsController {
|
|
127
129
|
throw new Error("Database or storage not initialized");
|
128
130
|
}
|
129
131
|
|
132
|
+
if (options.sync) {
|
133
|
+
console.log("Starting synchronization with server...");
|
134
|
+
const appwriteToX = new AppwriteToX(this.config, this.appwriteFolderPath);
|
135
|
+
await appwriteToX.toSchemas();
|
136
|
+
console.log("Synchronization complete, YAML and Schemas updated");
|
137
|
+
}
|
138
|
+
|
130
139
|
// Start the setup
|
131
140
|
console.log(
|
132
141
|
"Starting setup, this step sets up migrations, runs backup, wipes databases, and updates schemas (depending on your options)..."
|