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.
- package/CHANGELOG.md +14 -199
- package/README.md +87 -30
- package/dist/adapters/AdapterFactory.js +5 -25
- package/dist/adapters/DatabaseAdapter.d.ts +17 -2
- package/dist/adapters/LegacyAdapter.d.ts +2 -1
- package/dist/adapters/LegacyAdapter.js +212 -16
- package/dist/adapters/TablesDBAdapter.d.ts +2 -12
- package/dist/adapters/TablesDBAdapter.js +261 -57
- package/dist/cli/commands/databaseCommands.js +4 -3
- package/dist/cli/commands/functionCommands.js +17 -8
- package/dist/collections/attributes.js +447 -125
- package/dist/collections/methods.js +197 -186
- package/dist/collections/tableOperations.d.ts +86 -0
- package/dist/collections/tableOperations.js +434 -0
- package/dist/collections/transferOperations.d.ts +3 -2
- package/dist/collections/transferOperations.js +93 -12
- package/dist/config/yamlConfig.d.ts +221 -88
- package/dist/examples/yamlTerminologyExample.d.ts +1 -1
- package/dist/examples/yamlTerminologyExample.js +6 -3
- package/dist/functions/fnConfigDiscovery.d.ts +3 -0
- package/dist/functions/fnConfigDiscovery.js +108 -0
- package/dist/interactiveCLI.js +18 -15
- package/dist/main.js +211 -73
- package/dist/migrations/appwriteToX.d.ts +88 -23
- package/dist/migrations/comprehensiveTransfer.d.ts +2 -0
- package/dist/migrations/comprehensiveTransfer.js +83 -6
- package/dist/migrations/dataLoader.d.ts +227 -69
- package/dist/migrations/dataLoader.js +3 -3
- package/dist/migrations/importController.js +3 -3
- package/dist/migrations/relationships.d.ts +8 -2
- package/dist/migrations/services/ImportOrchestrator.js +3 -3
- package/dist/migrations/transfer.js +159 -37
- package/dist/shared/attributeMapper.d.ts +20 -0
- package/dist/shared/attributeMapper.js +203 -0
- package/dist/shared/selectionDialogs.js +8 -4
- package/dist/storage/schemas.d.ts +354 -92
- package/dist/utils/configDiscovery.js +4 -3
- package/dist/utils/versionDetection.d.ts +0 -4
- package/dist/utils/versionDetection.js +41 -173
- package/dist/utils/yamlConverter.js +89 -16
- package/dist/utils/yamlLoader.d.ts +1 -1
- package/dist/utils/yamlLoader.js +6 -2
- package/dist/utilsController.js +56 -19
- package/package.json +4 -4
- package/src/adapters/AdapterFactory.ts +119 -143
- package/src/adapters/DatabaseAdapter.ts +18 -3
- package/src/adapters/LegacyAdapter.ts +236 -105
- package/src/adapters/TablesDBAdapter.ts +773 -643
- package/src/cli/commands/databaseCommands.ts +13 -12
- package/src/cli/commands/functionCommands.ts +23 -14
- package/src/collections/attributes.ts +2054 -1611
- package/src/collections/methods.ts +208 -293
- package/src/collections/tableOperations.ts +506 -0
- package/src/collections/transferOperations.ts +218 -144
- package/src/examples/yamlTerminologyExample.ts +10 -5
- package/src/functions/fnConfigDiscovery.ts +103 -0
- package/src/interactiveCLI.ts +25 -20
- package/src/main.ts +549 -194
- package/src/migrations/comprehensiveTransfer.ts +126 -50
- package/src/migrations/dataLoader.ts +3 -3
- package/src/migrations/importController.ts +3 -3
- package/src/migrations/services/ImportOrchestrator.ts +3 -3
- package/src/migrations/transfer.ts +148 -131
- package/src/shared/attributeMapper.ts +229 -0
- package/src/shared/selectionDialogs.ts +29 -25
- package/src/utils/configDiscovery.ts +9 -3
- package/src/utils/versionDetection.ts +74 -228
- package/src/utils/yamlConverter.ts +94 -17
- package/src/utils/yamlLoader.ts +11 -4
- 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
|
-
|
|
811
|
-
|
|
812
|
-
|
|
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
|
-
|
|
819
|
-
|
|
820
|
-
|
|
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
|