appwrite-utils-cli 0.0.286 → 0.9.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 (109) hide show
  1. package/README.md +162 -96
  2. package/dist/collections/attributes.d.ts +4 -0
  3. package/dist/collections/attributes.js +224 -0
  4. package/dist/collections/indexes.d.ts +4 -0
  5. package/dist/collections/indexes.js +27 -0
  6. package/dist/collections/methods.d.ts +16 -0
  7. package/dist/collections/methods.js +216 -0
  8. package/dist/databases/methods.d.ts +6 -0
  9. package/dist/databases/methods.js +33 -0
  10. package/dist/interactiveCLI.d.ts +19 -0
  11. package/dist/interactiveCLI.js +555 -0
  12. package/dist/main.js +224 -62
  13. package/dist/migrations/afterImportActions.js +37 -40
  14. package/dist/migrations/appwriteToX.d.ts +26 -25
  15. package/dist/migrations/appwriteToX.js +42 -6
  16. package/dist/migrations/attributes.js +21 -20
  17. package/dist/migrations/backup.d.ts +93 -87
  18. package/dist/migrations/collections.d.ts +6 -0
  19. package/dist/migrations/collections.js +149 -20
  20. package/dist/migrations/converters.d.ts +2 -18
  21. package/dist/migrations/converters.js +13 -2
  22. package/dist/migrations/dataLoader.d.ts +276 -161
  23. package/dist/migrations/dataLoader.js +535 -292
  24. package/dist/migrations/databases.js +8 -2
  25. package/dist/migrations/helper.d.ts +3 -0
  26. package/dist/migrations/helper.js +21 -0
  27. package/dist/migrations/importController.d.ts +5 -2
  28. package/dist/migrations/importController.js +125 -88
  29. package/dist/migrations/importDataActions.d.ts +9 -1
  30. package/dist/migrations/importDataActions.js +15 -3
  31. package/dist/migrations/indexes.js +3 -2
  32. package/dist/migrations/logging.js +20 -8
  33. package/dist/migrations/migrationHelper.d.ts +9 -4
  34. package/dist/migrations/migrationHelper.js +6 -5
  35. package/dist/migrations/openapi.d.ts +1 -1
  36. package/dist/migrations/openapi.js +33 -18
  37. package/dist/migrations/queue.js +3 -2
  38. package/dist/migrations/relationships.d.ts +2 -2
  39. package/dist/migrations/schemaStrings.js +53 -41
  40. package/dist/migrations/setupDatabase.d.ts +2 -4
  41. package/dist/migrations/setupDatabase.js +24 -105
  42. package/dist/migrations/storage.d.ts +3 -1
  43. package/dist/migrations/storage.js +110 -16
  44. package/dist/migrations/transfer.d.ts +30 -0
  45. package/dist/migrations/transfer.js +337 -0
  46. package/dist/migrations/users.d.ts +2 -1
  47. package/dist/migrations/users.js +78 -43
  48. package/dist/schemas/authUser.d.ts +2 -2
  49. package/dist/storage/methods.d.ts +15 -0
  50. package/dist/storage/methods.js +207 -0
  51. package/dist/storage/schemas.d.ts +687 -0
  52. package/dist/storage/schemas.js +175 -0
  53. package/dist/utils/getClientFromConfig.d.ts +4 -0
  54. package/dist/utils/getClientFromConfig.js +16 -0
  55. package/dist/utils/helperFunctions.d.ts +11 -1
  56. package/dist/utils/helperFunctions.js +38 -0
  57. package/dist/utils/retryFailedPromises.d.ts +2 -0
  58. package/dist/utils/retryFailedPromises.js +21 -0
  59. package/dist/utils/schemaStrings.d.ts +13 -0
  60. package/dist/utils/schemaStrings.js +403 -0
  61. package/dist/utils/setupFiles.js +110 -61
  62. package/dist/utilsController.d.ts +40 -22
  63. package/dist/utilsController.js +164 -84
  64. package/package.json +13 -15
  65. package/src/collections/attributes.ts +483 -0
  66. package/src/collections/indexes.ts +53 -0
  67. package/src/collections/methods.ts +331 -0
  68. package/src/databases/methods.ts +47 -0
  69. package/src/init.ts +64 -64
  70. package/src/interactiveCLI.ts +767 -0
  71. package/src/main.ts +289 -83
  72. package/src/migrations/afterImportActions.ts +553 -490
  73. package/src/migrations/appwriteToX.ts +237 -174
  74. package/src/migrations/attributes.ts +483 -422
  75. package/src/migrations/backup.ts +205 -205
  76. package/src/migrations/collections.ts +545 -300
  77. package/src/migrations/converters.ts +161 -150
  78. package/src/migrations/dataLoader.ts +1615 -1304
  79. package/src/migrations/databases.ts +44 -25
  80. package/src/migrations/dbHelpers.ts +92 -92
  81. package/src/migrations/helper.ts +40 -0
  82. package/src/migrations/importController.ts +448 -384
  83. package/src/migrations/importDataActions.ts +315 -307
  84. package/src/migrations/indexes.ts +40 -37
  85. package/src/migrations/logging.ts +29 -16
  86. package/src/migrations/migrationHelper.ts +207 -201
  87. package/src/migrations/openapi.ts +83 -70
  88. package/src/migrations/queue.ts +118 -119
  89. package/src/migrations/relationships.ts +324 -324
  90. package/src/migrations/schemaStrings.ts +472 -460
  91. package/src/migrations/setupDatabase.ts +118 -219
  92. package/src/migrations/storage.ts +538 -358
  93. package/src/migrations/transfer.ts +608 -0
  94. package/src/migrations/users.ts +362 -285
  95. package/src/migrations/validationRules.ts +63 -63
  96. package/src/schemas/authUser.ts +23 -23
  97. package/src/setup.ts +8 -8
  98. package/src/storage/methods.ts +371 -0
  99. package/src/storage/schemas.ts +205 -0
  100. package/src/types.ts +9 -9
  101. package/src/utils/getClientFromConfig.ts +17 -0
  102. package/src/utils/helperFunctions.ts +181 -127
  103. package/src/utils/index.ts +2 -2
  104. package/src/utils/loadConfigs.ts +59 -59
  105. package/src/utils/retryFailedPromises.ts +27 -0
  106. package/src/utils/schemaStrings.ts +473 -0
  107. package/src/utils/setupFiles.ts +228 -182
  108. package/src/utilsController.ts +325 -194
  109. package/tsconfig.json +37 -37
@@ -1,37 +1,40 @@
1
- import { indexSchema, type Index } from "appwrite-utils";
2
- import { Databases, Query, type Models } from "node-appwrite";
3
- // import {}
4
-
5
- export const createOrUpdateIndex = async (
6
- dbId: string,
7
- db: Databases,
8
- collectionId: string,
9
- index: Index
10
- ) => {
11
- const existingIndex = await db.listIndexes(dbId, collectionId, [
12
- Query.equal("key", index.key),
13
- ]);
14
- if (existingIndex.total > 0) {
15
- await db.deleteIndex(dbId, collectionId, existingIndex.indexes[0].key);
16
- }
17
- const newIndex = await db.createIndex(
18
- dbId,
19
- collectionId,
20
- index.key,
21
- index.type,
22
- index.attributes,
23
- index.orders
24
- );
25
- return newIndex;
26
- };
27
-
28
- export const createOrUpdateIndexes = async (
29
- dbId: string,
30
- db: Databases,
31
- collectionId: string,
32
- indexes: Index[]
33
- ) => {
34
- for (const index of indexes) {
35
- await createOrUpdateIndex(dbId, db, collectionId, index);
36
- }
37
- };
1
+ import { indexSchema, type Index } from "appwrite-utils";
2
+ import { Databases, IndexType, Query, type Models } from "node-appwrite";
3
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
4
+ // import {}
5
+
6
+ export const createOrUpdateIndex = async (
7
+ dbId: string,
8
+ db: Databases,
9
+ collectionId: string,
10
+ index: Index
11
+ ) => {
12
+ const existingIndex = await db.listIndexes(dbId, collectionId, [
13
+ Query.equal("key", index.key),
14
+ ]);
15
+ if (existingIndex.total > 0) {
16
+ await db.deleteIndex(dbId, collectionId, existingIndex.indexes[0].key);
17
+ }
18
+ const newIndex = await db.createIndex(
19
+ dbId,
20
+ collectionId,
21
+ index.key,
22
+ index.type as IndexType,
23
+ index.attributes,
24
+ index.orders
25
+ );
26
+ return newIndex;
27
+ };
28
+
29
+ export const createOrUpdateIndexes = async (
30
+ dbId: string,
31
+ db: Databases,
32
+ collectionId: string,
33
+ indexes: Index[]
34
+ ) => {
35
+ for (const index of indexes) {
36
+ await tryAwaitWithRetry(
37
+ async () => await createOrUpdateIndex(dbId, db, collectionId, index)
38
+ );
39
+ }
40
+ };
@@ -1,16 +1,29 @@
1
- import winston from "winston";
2
-
3
- export const logger = winston.createLogger({
4
- level: "info",
5
- format: winston.format.json({ space: 2 }),
6
- defaultMeta: { service: "appwrite-utils-cli" },
7
- transports: [
8
- //
9
- // - Write all logs with importance level of `error` or less to `error.log`
10
- // - Write all logs with importance level of `info` or less to `combined.log`
11
- //
12
- new winston.transports.File({ filename: "error.log", level: "error" }),
13
- new winston.transports.File({ filename: "warn.log", level: "warn" }),
14
- new winston.transports.File({ filename: "combined.log" }),
15
- ],
16
- });
1
+ import winston from "winston";
2
+ import fs from "fs";
3
+ import path from "path";
4
+
5
+ // Ensure the logs directory exists
6
+ const logDir = path.join(process.cwd(), "zlogs");
7
+ if (!fs.existsSync(logDir)) {
8
+ fs.mkdirSync(logDir);
9
+ }
10
+
11
+ export const logger = winston.createLogger({
12
+ level: "debug",
13
+ format: winston.format.json({ space: 2 }),
14
+ defaultMeta: { service: "appwrite-utils-cli" },
15
+ transports: [
16
+ new winston.transports.File({
17
+ filename: path.join(logDir, "error.log"),
18
+ level: "error",
19
+ }),
20
+ new winston.transports.File({
21
+ filename: path.join(logDir, "warn.log"),
22
+ level: "warn",
23
+ }),
24
+ new winston.transports.File({
25
+ filename: path.join(logDir, "info.log"),
26
+ level: "info",
27
+ }),
28
+ ],
29
+ });
@@ -1,201 +1,207 @@
1
- import { ID, Query, type Databases } from "node-appwrite";
2
- import { BatchSchema, OperationSchema, type Operation } from "./backup.js";
3
- import { AttributeMappingsSchema } from "appwrite-utils";
4
- import { z } from "zod";
5
- import { logger } from "./logging.js";
6
-
7
- /**
8
- * Object that contains the context for an action that needs to be executed after import
9
- * Used in the afterImportActionsDefinitions
10
- * @type {ContextObject}
11
- * @typedef {Object} ContextObject
12
- * @property {string} collectionId - The ID of the collection
13
- * @property {any} finalItem - The final item that was imported
14
- * @property {string} action - The name of the action
15
- * @property {string[]} params - The parameters for the action
16
- * @property {Object} context - The context object for the action (all the data of this specific item)
17
- */
18
- export const ContextObject = z.object({
19
- dbId: z.string(),
20
- collectionId: z.string(),
21
- finalItem: z.any(),
22
- attributeMappings: AttributeMappingsSchema,
23
- context: z.any(),
24
- });
25
-
26
- export type ContextObject = z.infer<typeof ContextObject>;
27
-
28
- export const createOrFindAfterImportOperation = async (
29
- database: Databases,
30
- collectionId: string,
31
- context: ContextObject
32
- ) => {
33
- let operation = await findOrCreateOperation(
34
- database,
35
- collectionId,
36
- "afterImportAction"
37
- );
38
- if (!operation.batches) {
39
- operation.batches = [];
40
- }
41
-
42
- // Directly create a new batch for the context without checking for an existing batch
43
- const contextData = JSON.stringify(context);
44
- // Create a new batch with the contextData
45
- const newBatchId = await addBatch(database, contextData);
46
- // Update the operation with the new batch's $id
47
- operation.batches = [...operation.batches, newBatchId];
48
- await database.updateDocument(
49
- "migrations",
50
- "currentOperations",
51
- operation.$id,
52
- { batches: operation.batches }
53
- );
54
- };
55
-
56
- export const addBatch = async (database: Databases, data: string) => {
57
- const batch = await database.createDocument(
58
- "migrations",
59
- "batches",
60
- ID.unique(),
61
- {
62
- data,
63
- processed: false,
64
- }
65
- );
66
- return batch.$id;
67
- };
68
-
69
- export const getAfterImportOperations = async (
70
- database: Databases,
71
- collectionId: string
72
- ) => {
73
- let lastDocumentId: string | undefined;
74
- const allOperations = [];
75
- let total = 0;
76
-
77
- do {
78
- const query = [
79
- Query.equal("collectionId", collectionId),
80
- Query.equal("operationType", "afterImportAction"),
81
- Query.limit(100),
82
- ];
83
-
84
- if (lastDocumentId) {
85
- query.push(Query.cursorAfter(lastDocumentId));
86
- }
87
-
88
- const operations = await database.listDocuments(
89
- "migrations",
90
- "currentOperations",
91
- query
92
- );
93
- total = operations.total; // Update total with the latest fetch
94
- allOperations.push(...operations.documents);
95
-
96
- if (operations.documents.length > 0 && operations.documents.length >= 100) {
97
- lastDocumentId =
98
- operations.documents[operations.documents.length - 1].$id;
99
- }
100
- } while (allOperations.length < total);
101
-
102
- const allOps = allOperations.map((op) => OperationSchema.parse(op));
103
- return allOps;
104
- };
105
-
106
- export const findOrCreateOperation = async (
107
- database: Databases,
108
- collectionId: string,
109
- operationType: string,
110
- additionalQueries?: string[]
111
- ) => {
112
- const operations = await database.listDocuments(
113
- "migrations",
114
- "currentOperations",
115
- [
116
- Query.equal("collectionId", collectionId),
117
- Query.equal("operationType", operationType),
118
- Query.equal("status", "pending"),
119
- ...(additionalQueries || []),
120
- ]
121
- );
122
-
123
- if (operations.documents.length > 0) {
124
- return OperationSchema.parse(operations.documents[0]); // Assuming the first document is the operation we want
125
- } else {
126
- // Create a new operation document
127
- const op = await database.createDocument(
128
- "migrations",
129
- "currentOperations",
130
- ID.unique(),
131
- {
132
- operationType,
133
- collectionId,
134
- status: "pending",
135
- batches: [],
136
- progress: 0,
137
- total: 0,
138
- error: "",
139
- }
140
- );
141
-
142
- return OperationSchema.parse(op);
143
- }
144
- };
145
-
146
- export const updateOperation = async (
147
- database: Databases,
148
- operationId: string,
149
- updateFields: any
150
- ) => {
151
- await database.updateDocument(
152
- "migrations",
153
- "currentOperations",
154
- operationId,
155
- updateFields
156
- );
157
- };
158
-
159
- // Actual max 1073741824
160
- export const maxDataLength = 1073741820;
161
- export const maxBatchItems = 25;
162
-
163
- export const splitIntoBatches = (data: any[]): any[][] => {
164
- let batches = [];
165
- let currentBatch: any[] = [];
166
- let currentBatchLength = 0;
167
- let currentBatchItemCount = 0;
168
-
169
- data.forEach((item, index) => {
170
- const itemLength = JSON.stringify(item).length;
171
- if (itemLength > maxDataLength) {
172
- console.log(
173
- item,
174
- `Large item found at index ${index} with length ${itemLength}:`
175
- );
176
- }
177
- // Check if adding the current item would exceed the max length or max items per batch
178
- if (
179
- currentBatchLength + itemLength >= maxDataLength ||
180
- currentBatchItemCount >= maxBatchItems
181
- ) {
182
- // If so, start a new batch
183
- batches.push(currentBatch);
184
- currentBatch = [item];
185
- currentBatchLength = itemLength;
186
- currentBatchItemCount = 1; // Reset item count for the new batch
187
- } else {
188
- // Otherwise, add the item to the current batch
189
- currentBatch.push(item);
190
- currentBatchLength += itemLength;
191
- currentBatchItemCount++;
192
- }
193
- });
194
-
195
- // Don't forget to add the last batch if it's not empty
196
- if (currentBatch.length > 0) {
197
- batches.push(currentBatch);
198
- }
199
-
200
- return batches;
201
- };
1
+ import { ID, Query, type Databases } from "node-appwrite";
2
+ import { BatchSchema, OperationSchema, type Operation } from "./backup.js";
3
+ import { AttributeMappingsSchema } from "appwrite-utils";
4
+ import { z } from "zod";
5
+ import { logger } from "./logging.js";
6
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
7
+
8
+ /**
9
+ * Object that contains the context for an action that needs to be executed after import
10
+ * Used in the afterImportActionsDefinitions
11
+ * @type {ContextObject}
12
+ * @typedef {Object} ContextObject
13
+ * @property {string} collectionId - The ID of the collection
14
+ * @property {any} finalItem - The final item that was imported
15
+ * @property {string} action - The name of the action
16
+ * @property {string[]} params - The parameters for the action
17
+ * @property {Object} context - The context object for the action (all the data of this specific item)
18
+ */
19
+ export const ContextObject = z.object({
20
+ dbId: z.string(),
21
+ collectionId: z.string(),
22
+ finalItem: z.any(),
23
+ attributeMappings: AttributeMappingsSchema,
24
+ context: z.any(),
25
+ });
26
+
27
+ export type ContextObject = z.infer<typeof ContextObject>;
28
+
29
+ export const createOrFindAfterImportOperation = async (
30
+ database: Databases,
31
+ collectionId: string,
32
+ context: ContextObject
33
+ ) => {
34
+ let operation = await findOrCreateOperation(
35
+ database,
36
+ collectionId,
37
+ "afterImportAction"
38
+ );
39
+ if (!operation.batches) {
40
+ operation.batches = [];
41
+ }
42
+
43
+ // Directly create a new batch for the context without checking for an existing batch
44
+ const contextData = JSON.stringify(context);
45
+ // Create a new batch with the contextData
46
+ const newBatchId = await addBatch(database, contextData);
47
+ // Update the operation with the new batch's $id
48
+ operation.batches = [...operation.batches, newBatchId];
49
+ await database.updateDocument(
50
+ "migrations",
51
+ "currentOperations",
52
+ operation.$id,
53
+ { batches: operation.batches }
54
+ );
55
+ };
56
+
57
+ export const addBatch = async (database: Databases, data: string) => {
58
+ const batch = await database.createDocument(
59
+ "migrations",
60
+ "batches",
61
+ ID.unique(),
62
+ {
63
+ data,
64
+ processed: false,
65
+ }
66
+ );
67
+ return batch.$id;
68
+ };
69
+
70
+ export const getAfterImportOperations = async (
71
+ database: Databases,
72
+ collectionId: string
73
+ ) => {
74
+ let lastDocumentId: string | undefined;
75
+ const allOperations = [];
76
+ let total = 0;
77
+
78
+ do {
79
+ const query = [
80
+ Query.equal("collectionId", collectionId),
81
+ Query.equal("operationType", "afterImportAction"),
82
+ Query.limit(100),
83
+ ];
84
+
85
+ if (lastDocumentId) {
86
+ query.push(Query.cursorAfter(lastDocumentId));
87
+ }
88
+
89
+ const operations = await database.listDocuments(
90
+ "migrations",
91
+ "currentOperations",
92
+ query
93
+ );
94
+ total = operations.total; // Update total with the latest fetch
95
+ allOperations.push(...operations.documents);
96
+
97
+ if (operations.documents.length > 0 && operations.documents.length >= 100) {
98
+ lastDocumentId =
99
+ operations.documents[operations.documents.length - 1].$id;
100
+ }
101
+ } while (allOperations.length < total);
102
+
103
+ const allOps = allOperations.map((op) => OperationSchema.parse(op));
104
+ return allOps;
105
+ };
106
+
107
+ export const findOrCreateOperation = async (
108
+ database: Databases,
109
+ collectionId: string,
110
+ operationType: string,
111
+ additionalQueries?: string[]
112
+ ) => {
113
+ const operations = await tryAwaitWithRetry(
114
+ async () =>
115
+ await database.listDocuments("migrations", "currentOperations", [
116
+ Query.equal("collectionId", collectionId),
117
+ Query.equal("operationType", operationType),
118
+ Query.equal("status", "pending"),
119
+ ...(additionalQueries || []),
120
+ ])
121
+ );
122
+
123
+ if (operations.documents.length > 0) {
124
+ return OperationSchema.parse(operations.documents[0]); // Assuming the first document is the operation we want
125
+ } else {
126
+ // Create a new operation document
127
+ const op = await tryAwaitWithRetry(
128
+ async () =>
129
+ await database.createDocument(
130
+ "migrations",
131
+ "currentOperations",
132
+ ID.unique(),
133
+ {
134
+ operationType,
135
+ collectionId,
136
+ status: "pending",
137
+ batches: [],
138
+ progress: 0,
139
+ total: 0,
140
+ error: "",
141
+ }
142
+ )
143
+ );
144
+
145
+ return OperationSchema.parse(op);
146
+ }
147
+ };
148
+
149
+ export const updateOperation = async (
150
+ database: Databases,
151
+ operationId: string,
152
+ updateFields: any
153
+ ) => {
154
+ await tryAwaitWithRetry(
155
+ async () =>
156
+ await database.updateDocument(
157
+ "migrations",
158
+ "currentOperations",
159
+ operationId,
160
+ updateFields
161
+ )
162
+ );
163
+ };
164
+
165
+ // Actual max 1073741824
166
+ export const maxDataLength = 1073741820;
167
+ export const maxBatchItems = 25;
168
+
169
+ export const splitIntoBatches = (data: any[]): any[][] => {
170
+ let batches = [];
171
+ let currentBatch: any[] = [];
172
+ let currentBatchLength = 0;
173
+ let currentBatchItemCount = 0;
174
+
175
+ data.forEach((item, index) => {
176
+ const itemLength = JSON.stringify(item).length;
177
+ if (itemLength > maxDataLength) {
178
+ console.log(
179
+ item,
180
+ `Large item found at index ${index} with length ${itemLength}:`
181
+ );
182
+ }
183
+ // Check if adding the current item would exceed the max length or max items per batch
184
+ if (
185
+ currentBatchLength + itemLength >= maxDataLength ||
186
+ currentBatchItemCount >= maxBatchItems
187
+ ) {
188
+ // If so, start a new batch
189
+ batches.push(currentBatch);
190
+ currentBatch = [item];
191
+ currentBatchLength = itemLength;
192
+ currentBatchItemCount = 1; // Reset item count for the new batch
193
+ } else {
194
+ // Otherwise, add the item to the current batch
195
+ currentBatch.push(item);
196
+ currentBatchLength += itemLength;
197
+ currentBatchItemCount++;
198
+ }
199
+ });
200
+
201
+ // Don't forget to add the last batch if it's not empty
202
+ if (currentBatch.length > 0) {
203
+ batches.push(currentBatch);
204
+ }
205
+
206
+ return batches;
207
+ };