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.
Files changed (37) hide show
  1. package/README.md +24 -5
  2. package/dist/main.js +6 -0
  3. package/dist/migrations/afterImportActions.d.ts +3 -1
  4. package/dist/migrations/afterImportActions.js +2 -2
  5. package/dist/migrations/appwriteToX.d.ts +109 -0
  6. package/dist/migrations/appwriteToX.js +88 -0
  7. package/dist/migrations/backup.d.ts +4 -4
  8. package/dist/migrations/converters.js +1 -1
  9. package/dist/migrations/dataLoader.d.ts +19 -18
  10. package/dist/migrations/dataLoader.js +65 -84
  11. package/dist/migrations/databases.d.ts +2 -0
  12. package/dist/migrations/databases.js +23 -0
  13. package/dist/migrations/importController.js +3 -0
  14. package/dist/migrations/importDataActions.d.ts +1 -1
  15. package/dist/migrations/importDataActions.js +1 -1
  16. package/dist/migrations/schema.d.ts +363 -32
  17. package/dist/migrations/schema.js +48 -28
  18. package/dist/migrations/schemaStrings.d.ts +1 -0
  19. package/dist/migrations/schemaStrings.js +10 -0
  20. package/dist/setup.js +0 -0
  21. package/dist/utils/helperFunctions.d.ts +3 -0
  22. package/dist/utils/helperFunctions.js +8 -0
  23. package/dist/utilsController.d.ts +1 -0
  24. package/dist/utilsController.js +7 -0
  25. package/package.json +1 -1
  26. package/src/main.ts +6 -0
  27. package/src/migrations/afterImportActions.ts +2 -2
  28. package/src/migrations/appwriteToX.ts +122 -0
  29. package/src/migrations/converters.ts +2 -2
  30. package/src/migrations/dataLoader.ts +87 -95
  31. package/src/migrations/databases.ts +25 -0
  32. package/src/migrations/importController.ts +3 -0
  33. package/src/migrations/importDataActions.ts +1 -1
  34. package/src/migrations/schema.ts +65 -36
  35. package/src/migrations/schemaStrings.ts +11 -0
  36. package/src/utils/helperFunctions.ts +17 -0
  37. 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
- async runConverterFunctions(item: any, attributeMappings: AttributeMappings) {
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) => {
@@ -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: z
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
+ };
@@ -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)..."