appwrite-utils-cli 1.7.9 → 1.8.2

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 (70) hide show
  1. package/CHANGELOG.md +14 -199
  2. package/README.md +87 -30
  3. package/dist/adapters/AdapterFactory.js +5 -25
  4. package/dist/adapters/DatabaseAdapter.d.ts +17 -2
  5. package/dist/adapters/LegacyAdapter.d.ts +2 -1
  6. package/dist/adapters/LegacyAdapter.js +212 -16
  7. package/dist/adapters/TablesDBAdapter.d.ts +2 -12
  8. package/dist/adapters/TablesDBAdapter.js +261 -57
  9. package/dist/cli/commands/databaseCommands.js +4 -3
  10. package/dist/cli/commands/functionCommands.js +17 -8
  11. package/dist/collections/attributes.js +447 -125
  12. package/dist/collections/methods.js +197 -186
  13. package/dist/collections/tableOperations.d.ts +86 -0
  14. package/dist/collections/tableOperations.js +434 -0
  15. package/dist/collections/transferOperations.d.ts +3 -2
  16. package/dist/collections/transferOperations.js +93 -12
  17. package/dist/config/yamlConfig.d.ts +221 -88
  18. package/dist/examples/yamlTerminologyExample.d.ts +1 -1
  19. package/dist/examples/yamlTerminologyExample.js +6 -3
  20. package/dist/functions/fnConfigDiscovery.d.ts +3 -0
  21. package/dist/functions/fnConfigDiscovery.js +108 -0
  22. package/dist/interactiveCLI.js +18 -15
  23. package/dist/main.js +211 -73
  24. package/dist/migrations/appwriteToX.d.ts +88 -23
  25. package/dist/migrations/comprehensiveTransfer.d.ts +2 -0
  26. package/dist/migrations/comprehensiveTransfer.js +83 -6
  27. package/dist/migrations/dataLoader.d.ts +227 -69
  28. package/dist/migrations/dataLoader.js +3 -3
  29. package/dist/migrations/importController.js +3 -3
  30. package/dist/migrations/relationships.d.ts +8 -2
  31. package/dist/migrations/services/ImportOrchestrator.js +3 -3
  32. package/dist/migrations/transfer.js +159 -37
  33. package/dist/shared/attributeMapper.d.ts +20 -0
  34. package/dist/shared/attributeMapper.js +203 -0
  35. package/dist/shared/selectionDialogs.js +8 -4
  36. package/dist/storage/schemas.d.ts +354 -92
  37. package/dist/utils/configDiscovery.js +4 -3
  38. package/dist/utils/versionDetection.d.ts +0 -4
  39. package/dist/utils/versionDetection.js +41 -173
  40. package/dist/utils/yamlConverter.js +89 -16
  41. package/dist/utils/yamlLoader.d.ts +1 -1
  42. package/dist/utils/yamlLoader.js +6 -2
  43. package/dist/utilsController.js +56 -19
  44. package/package.json +4 -4
  45. package/src/adapters/AdapterFactory.ts +119 -143
  46. package/src/adapters/DatabaseAdapter.ts +18 -3
  47. package/src/adapters/LegacyAdapter.ts +236 -105
  48. package/src/adapters/TablesDBAdapter.ts +773 -643
  49. package/src/cli/commands/databaseCommands.ts +13 -12
  50. package/src/cli/commands/functionCommands.ts +23 -14
  51. package/src/collections/attributes.ts +2054 -1611
  52. package/src/collections/methods.ts +208 -293
  53. package/src/collections/tableOperations.ts +506 -0
  54. package/src/collections/transferOperations.ts +218 -144
  55. package/src/examples/yamlTerminologyExample.ts +10 -5
  56. package/src/functions/fnConfigDiscovery.ts +103 -0
  57. package/src/interactiveCLI.ts +25 -20
  58. package/src/main.ts +549 -194
  59. package/src/migrations/comprehensiveTransfer.ts +126 -50
  60. package/src/migrations/dataLoader.ts +3 -3
  61. package/src/migrations/importController.ts +3 -3
  62. package/src/migrations/services/ImportOrchestrator.ts +3 -3
  63. package/src/migrations/transfer.ts +148 -131
  64. package/src/shared/attributeMapper.ts +229 -0
  65. package/src/shared/selectionDialogs.ts +29 -25
  66. package/src/utils/configDiscovery.ts +9 -3
  67. package/src/utils/versionDetection.ts +74 -228
  68. package/src/utils/yamlConverter.ts +94 -17
  69. package/src/utils/yamlLoader.ts +11 -4
  70. package/src/utilsController.ts +80 -30
@@ -8,94 +8,159 @@ export declare class AppwriteToX {
8
8
  updatedConfig: AppwriteConfig;
9
9
  collToAttributeMap: Map<string, ({
10
10
  key: string;
11
+ required: boolean;
11
12
  type: "string";
12
13
  size: number;
13
- error?: string | undefined;
14
- required?: boolean | undefined;
15
14
  array?: boolean | undefined;
15
+ format?: string | undefined;
16
+ status?: string | undefined;
17
+ attributes?: string[] | undefined;
18
+ orders?: string[] | undefined;
19
+ $createdAt?: string | undefined;
20
+ $updatedAt?: string | undefined;
21
+ error?: string | undefined;
16
22
  xdefault?: string | null | undefined;
17
23
  encrypted?: boolean | undefined;
18
- format?: string | null | undefined;
19
24
  } | {
20
25
  key: string;
26
+ required: boolean;
21
27
  type: "integer";
22
- error?: string | undefined;
23
- required?: boolean | undefined;
24
28
  array?: boolean | undefined;
29
+ format?: string | undefined;
30
+ status?: string | undefined;
31
+ attributes?: string[] | undefined;
32
+ orders?: string[] | undefined;
33
+ $createdAt?: string | undefined;
34
+ $updatedAt?: string | undefined;
35
+ error?: string | undefined;
25
36
  min?: number | undefined;
26
37
  max?: number | undefined;
27
38
  xdefault?: number | null | undefined;
28
39
  } | {
29
40
  key: string;
41
+ required: boolean;
30
42
  type: "double";
31
- error?: string | undefined;
32
- required?: boolean | undefined;
33
43
  array?: boolean | undefined;
44
+ format?: string | undefined;
45
+ status?: string | undefined;
46
+ attributes?: string[] | undefined;
47
+ orders?: string[] | undefined;
48
+ $createdAt?: string | undefined;
49
+ $updatedAt?: string | undefined;
50
+ error?: string | undefined;
34
51
  min?: number | undefined;
35
52
  max?: number | undefined;
36
53
  xdefault?: number | null | undefined;
37
54
  } | {
38
55
  key: string;
56
+ required: boolean;
39
57
  type: "float";
40
- error?: string | undefined;
41
- required?: boolean | undefined;
42
58
  array?: boolean | undefined;
59
+ format?: string | undefined;
60
+ status?: string | undefined;
61
+ attributes?: string[] | undefined;
62
+ orders?: string[] | undefined;
63
+ $createdAt?: string | undefined;
64
+ $updatedAt?: string | undefined;
65
+ error?: string | undefined;
43
66
  min?: number | undefined;
44
67
  max?: number | undefined;
45
68
  xdefault?: number | null | undefined;
46
69
  } | {
47
70
  key: string;
71
+ required: boolean;
48
72
  type: "boolean";
49
- error?: string | undefined;
50
- required?: boolean | undefined;
51
73
  array?: boolean | undefined;
74
+ format?: string | undefined;
75
+ status?: string | undefined;
76
+ attributes?: string[] | undefined;
77
+ orders?: string[] | undefined;
78
+ $createdAt?: string | undefined;
79
+ $updatedAt?: string | undefined;
80
+ error?: string | undefined;
52
81
  xdefault?: boolean | null | undefined;
53
82
  } | {
54
83
  key: string;
84
+ required: boolean;
55
85
  type: "datetime";
56
- error?: string | undefined;
57
- required?: boolean | undefined;
58
86
  array?: boolean | undefined;
87
+ format?: string | undefined;
88
+ status?: string | undefined;
89
+ attributes?: string[] | undefined;
90
+ orders?: string[] | undefined;
91
+ $createdAt?: string | undefined;
92
+ $updatedAt?: string | undefined;
93
+ error?: string | undefined;
59
94
  xdefault?: string | null | undefined;
60
95
  } | {
61
96
  key: string;
97
+ required: boolean;
62
98
  type: "email";
63
- error?: string | undefined;
64
- required?: boolean | undefined;
65
99
  array?: boolean | undefined;
100
+ format?: string | undefined;
101
+ status?: string | undefined;
102
+ attributes?: string[] | undefined;
103
+ orders?: string[] | undefined;
104
+ $createdAt?: string | undefined;
105
+ $updatedAt?: string | undefined;
106
+ error?: string | undefined;
66
107
  xdefault?: string | null | undefined;
67
108
  } | {
68
109
  key: string;
110
+ required: boolean;
69
111
  type: "ip";
70
- error?: string | undefined;
71
- required?: boolean | undefined;
72
112
  array?: boolean | undefined;
113
+ format?: string | undefined;
114
+ status?: string | undefined;
115
+ attributes?: string[] | undefined;
116
+ orders?: string[] | undefined;
117
+ $createdAt?: string | undefined;
118
+ $updatedAt?: string | undefined;
119
+ error?: string | undefined;
73
120
  xdefault?: string | null | undefined;
74
121
  } | {
75
122
  key: string;
123
+ required: boolean;
76
124
  type: "url";
77
- error?: string | undefined;
78
- required?: boolean | undefined;
79
125
  array?: boolean | undefined;
126
+ format?: string | undefined;
127
+ status?: string | undefined;
128
+ attributes?: string[] | undefined;
129
+ orders?: string[] | undefined;
130
+ $createdAt?: string | undefined;
131
+ $updatedAt?: string | undefined;
132
+ error?: string | undefined;
80
133
  xdefault?: string | null | undefined;
81
134
  } | {
82
135
  key: string;
136
+ required: boolean;
83
137
  type: "enum";
84
138
  elements: string[];
85
- error?: string | undefined;
86
- required?: boolean | undefined;
87
139
  array?: boolean | undefined;
140
+ format?: string | undefined;
141
+ status?: string | undefined;
142
+ attributes?: string[] | undefined;
143
+ orders?: string[] | undefined;
144
+ $createdAt?: string | undefined;
145
+ $updatedAt?: string | undefined;
146
+ error?: string | undefined;
88
147
  xdefault?: string | null | undefined;
89
148
  } | {
90
149
  key: string;
150
+ required: boolean;
91
151
  type: "relationship";
92
152
  relatedCollection: string;
93
153
  relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
94
154
  twoWay: boolean;
95
155
  onDelete: "setNull" | "cascade" | "restrict";
96
- error?: string | undefined;
97
- required?: boolean | undefined;
98
156
  array?: boolean | undefined;
157
+ format?: string | undefined;
158
+ status?: string | undefined;
159
+ attributes?: string[] | undefined;
160
+ orders?: string[] | undefined;
161
+ $createdAt?: string | undefined;
162
+ $updatedAt?: string | undefined;
163
+ error?: string | undefined;
99
164
  twoWayKey?: string | undefined;
100
165
  side?: "parent" | "child" | undefined;
101
166
  importMapping?: {
@@ -62,6 +62,8 @@ export declare class ComprehensiveTransfer {
62
62
  private startTime;
63
63
  private tempDir;
64
64
  private cachedMaxFileSize?;
65
+ private sourceAdapter?;
66
+ private targetAdapter?;
65
67
  constructor(options: ComprehensiveTransferOptions);
66
68
  execute(): Promise<TransferResults>;
67
69
  private transferAllUsers;
@@ -12,6 +12,8 @@ import pLimit from "p-limit";
12
12
  import chalk from "chalk";
13
13
  import { join } from "node:path";
14
14
  import fs from "node:fs";
15
+ import { getAdapter } from "../utils/getClientFromConfig.js";
16
+ import { mapToCreateAttributeParams } from "../shared/attributeMapper.js";
15
17
  export class ComprehensiveTransfer {
16
18
  options;
17
19
  sourceClient;
@@ -33,6 +35,8 @@ export class ComprehensiveTransfer {
33
35
  startTime;
34
36
  tempDir;
35
37
  cachedMaxFileSize; // Cache successful maximumFileSize for subsequent buckets
38
+ sourceAdapter;
39
+ targetAdapter;
36
40
  constructor(options) {
37
41
  this.options = options;
38
42
  this.sourceClient = getClient(options.sourceEndpoint, options.sourceProject, options.sourceKey);
@@ -70,6 +74,11 @@ export class ComprehensiveTransfer {
70
74
  MessageFormatter.info("Starting comprehensive transfer", {
71
75
  prefix: "Transfer",
72
76
  });
77
+ // Initialize adapters for unified API (TablesDB or legacy via adapter)
78
+ const source = await getAdapter(this.options.sourceEndpoint, this.options.sourceProject, this.options.sourceKey, 'auto');
79
+ const target = await getAdapter(this.options.targetEndpoint, this.options.targetProject, this.options.targetKey, 'auto');
80
+ this.sourceAdapter = source.adapter;
81
+ this.targetAdapter = target.adapter;
73
82
  if (this.options.dryRun) {
74
83
  MessageFormatter.info("DRY RUN MODE - No actual changes will be made", {
75
84
  prefix: "Transfer",
@@ -807,17 +816,85 @@ export class ComprehensiveTransfer {
807
816
  * Helper method to create collection attributes with status checking
808
817
  */
809
818
  async createCollectionAttributesWithStatusCheck(databases, dbId, collection, attributes) {
810
- // Import the enhanced attribute creation function
811
- const { createUpdateCollectionAttributesWithStatusCheck } = await import("../collections/attributes.js");
812
- return await createUpdateCollectionAttributesWithStatusCheck(databases, dbId, collection, attributes);
819
+ if (!this.targetAdapter) {
820
+ throw new Error('Target adapter not initialized');
821
+ }
822
+ try {
823
+ // Create non-relationship attributes first
824
+ const nonRel = (attributes || []).filter((a) => a.type !== 'relationship');
825
+ for (const attr of nonRel) {
826
+ const params = mapToCreateAttributeParams(attr, { databaseId: dbId, tableId: collection.$id });
827
+ await this.targetAdapter.createAttribute(params);
828
+ // Small delay between creations
829
+ await new Promise((r) => setTimeout(r, 150));
830
+ }
831
+ // Wait for attributes to become available
832
+ for (const attr of nonRel) {
833
+ const maxWait = 60000; // 60s
834
+ const start = Date.now();
835
+ let lastStatus = '';
836
+ while (Date.now() - start < maxWait) {
837
+ try {
838
+ const tableRes = await this.targetAdapter.getTable({ databaseId: dbId, tableId: collection.$id });
839
+ const cols = tableRes.attributes || tableRes.columns || [];
840
+ const col = cols.find((c) => c.key === attr.key);
841
+ if (col) {
842
+ if (col.status === 'available')
843
+ break;
844
+ if (col.status === 'failed' || col.status === 'stuck') {
845
+ throw new Error(col.error || `Attribute ${attr.key} failed`);
846
+ }
847
+ lastStatus = col.status;
848
+ }
849
+ await new Promise((r) => setTimeout(r, 2000));
850
+ }
851
+ catch {
852
+ await new Promise((r) => setTimeout(r, 2000));
853
+ }
854
+ }
855
+ if (Date.now() - start >= maxWait) {
856
+ MessageFormatter.warning(`Attribute ${attr.key} did not become available within 60s (last status: ${lastStatus})`, { prefix: 'Attributes' });
857
+ }
858
+ }
859
+ // Create relationship attributes
860
+ const rels = (attributes || []).filter((a) => a.type === 'relationship');
861
+ for (const attr of rels) {
862
+ const params = mapToCreateAttributeParams(attr, { databaseId: dbId, tableId: collection.$id });
863
+ await this.targetAdapter.createAttribute(params);
864
+ await new Promise((r) => setTimeout(r, 150));
865
+ }
866
+ return true;
867
+ }
868
+ catch (e) {
869
+ MessageFormatter.error('Failed creating attributes via adapter', e instanceof Error ? e : new Error(String(e)), { prefix: 'Attributes' });
870
+ return false;
871
+ }
813
872
  }
814
873
  /**
815
874
  * Helper method to create collection indexes with status checking
816
875
  */
817
876
  async createCollectionIndexesWithStatusCheck(dbId, databases, collectionId, collection, indexes) {
818
- // Import the enhanced index creation function
819
- const { createOrUpdateIndexesWithStatusCheck } = await import("../collections/indexes.js");
820
- return await createOrUpdateIndexesWithStatusCheck(dbId, databases, collectionId, collection, indexes);
877
+ if (!this.targetAdapter) {
878
+ throw new Error('Target adapter not initialized');
879
+ }
880
+ try {
881
+ for (const idx of indexes || []) {
882
+ await this.targetAdapter.createIndex({
883
+ databaseId: dbId,
884
+ tableId: collectionId,
885
+ key: idx.key,
886
+ type: idx.type,
887
+ attributes: idx.attributes,
888
+ orders: idx.orders || []
889
+ });
890
+ await new Promise((r) => setTimeout(r, 150));
891
+ }
892
+ return true;
893
+ }
894
+ catch (e) {
895
+ MessageFormatter.error('Failed creating indexes via adapter', e instanceof Error ? e : new Error(String(e)), { prefix: 'Indexes' });
896
+ return false;
897
+ }
821
898
  }
822
899
  /**
823
900
  * Helper method to transfer documents between databases using bulk operations with content and permission-based filtering