appwrite-cli 12.0.1 → 13.0.0-rc.1

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 (283) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +2 -2
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +145 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/client.d.ts +89 -0
  8. package/dist/lib/client.d.ts.map +1 -0
  9. package/dist/lib/client.js +227 -0
  10. package/dist/lib/client.js.map +1 -0
  11. package/dist/lib/commands/account.d.ts +379 -0
  12. package/dist/lib/commands/account.d.ts.map +1 -0
  13. package/dist/lib/commands/account.js +1228 -0
  14. package/dist/lib/commands/account.js.map +1 -0
  15. package/dist/lib/commands/console.d.ts +20 -0
  16. package/dist/lib/commands/console.d.ts.map +1 -0
  17. package/dist/lib/commands/console.js +78 -0
  18. package/dist/lib/commands/console.js.map +1 -0
  19. package/dist/lib/commands/databases.d.ts +732 -0
  20. package/dist/lib/commands/databases.d.ts.map +1 -0
  21. package/dist/lib/commands/databases.js +2196 -0
  22. package/dist/lib/commands/databases.js.map +1 -0
  23. package/dist/lib/commands/functions.d.ts +310 -0
  24. package/dist/lib/commands/functions.d.ts.map +1 -0
  25. package/dist/lib/commands/functions.js +1100 -0
  26. package/dist/lib/commands/functions.js.map +1 -0
  27. package/dist/lib/commands/generic.d.ts +17 -0
  28. package/dist/lib/commands/generic.d.ts.map +1 -0
  29. package/dist/lib/commands/generic.js +279 -0
  30. package/dist/lib/commands/generic.js.map +1 -0
  31. package/dist/lib/commands/graphql.d.ts +19 -0
  32. package/dist/lib/commands/graphql.d.ts.map +1 -0
  33. package/dist/lib/commands/graphql.js +77 -0
  34. package/dist/lib/commands/graphql.js.map +1 -0
  35. package/dist/lib/commands/health.d.ts +153 -0
  36. package/dist/lib/commands/health.d.ts.map +1 -0
  37. package/dist/lib/commands/health.js +464 -0
  38. package/dist/lib/commands/health.js.map +1 -0
  39. package/dist/lib/commands/init.d.ts +3 -0
  40. package/dist/lib/commands/init.d.ts.map +1 -0
  41. package/dist/lib/commands/init.js +518 -0
  42. package/dist/lib/commands/init.js.map +1 -0
  43. package/dist/lib/commands/locale.d.ts +53 -0
  44. package/dist/lib/commands/locale.d.ts.map +1 -0
  45. package/dist/lib/commands/locale.js +165 -0
  46. package/dist/lib/commands/locale.js.map +1 -0
  47. package/dist/lib/commands/messaging.d.ts +588 -0
  48. package/dist/lib/commands/messaging.d.ts.map +1 -0
  49. package/dist/lib/commands/messaging.js +2042 -0
  50. package/dist/lib/commands/messaging.js.map +1 -0
  51. package/dist/lib/commands/migrations.d.ts +150 -0
  52. package/dist/lib/commands/migrations.d.ts.map +1 -0
  53. package/dist/lib/commands/migrations.js +524 -0
  54. package/dist/lib/commands/migrations.js.map +1 -0
  55. package/dist/lib/commands/organizations.d.ts +11 -0
  56. package/dist/lib/commands/organizations.d.ts.map +1 -0
  57. package/dist/lib/commands/organizations.js +31 -0
  58. package/dist/lib/commands/organizations.js.map +1 -0
  59. package/dist/lib/commands/project.d.ts +53 -0
  60. package/dist/lib/commands/project.d.ts.map +1 -0
  61. package/dist/lib/commands/project.js +176 -0
  62. package/dist/lib/commands/project.js.map +1 -0
  63. package/dist/lib/commands/projects.d.ts +516 -0
  64. package/dist/lib/commands/projects.d.ts.map +1 -0
  65. package/dist/lib/commands/projects.js +1590 -0
  66. package/dist/lib/commands/projects.js.map +1 -0
  67. package/dist/lib/commands/proxy.d.ts +71 -0
  68. package/dist/lib/commands/proxy.d.ts.map +1 -0
  69. package/dist/lib/commands/proxy.js +240 -0
  70. package/dist/lib/commands/proxy.js.map +1 -0
  71. package/dist/lib/commands/pull.d.ts +8 -0
  72. package/dist/lib/commands/pull.d.ts.map +1 -0
  73. package/dist/lib/commands/pull.js +455 -0
  74. package/dist/lib/commands/pull.js.map +1 -0
  75. package/dist/lib/commands/push.d.ts +4 -0
  76. package/dist/lib/commands/push.d.ts.map +1 -0
  77. package/dist/lib/commands/push.js +2154 -0
  78. package/dist/lib/commands/push.js.map +1 -0
  79. package/dist/lib/commands/run.d.ts +3 -0
  80. package/dist/lib/commands/run.d.ts.map +1 -0
  81. package/dist/lib/commands/run.js +287 -0
  82. package/dist/lib/commands/run.js.map +1 -0
  83. package/dist/lib/commands/sites.d.ts +296 -0
  84. package/dist/lib/commands/sites.d.ts.map +1 -0
  85. package/dist/lib/commands/sites.js +1046 -0
  86. package/dist/lib/commands/sites.js.map +1 -0
  87. package/dist/lib/commands/storage.d.ts +170 -0
  88. package/dist/lib/commands/storage.d.ts.map +1 -0
  89. package/dist/lib/commands/storage.js +651 -0
  90. package/dist/lib/commands/storage.js.map +1 -0
  91. package/dist/lib/commands/tables-db.d.ts +728 -0
  92. package/dist/lib/commands/tables-db.d.ts.map +1 -0
  93. package/dist/lib/commands/tables-db.js +2198 -0
  94. package/dist/lib/commands/tables-db.js.map +1 -0
  95. package/dist/lib/commands/teams.d.ts +129 -0
  96. package/dist/lib/commands/teams.d.ts.map +1 -0
  97. package/dist/lib/commands/teams.js +403 -0
  98. package/dist/lib/commands/teams.js.map +1 -0
  99. package/dist/lib/commands/tokens.d.ts +48 -0
  100. package/dist/lib/commands/tokens.d.ts.map +1 -0
  101. package/dist/lib/commands/tokens.js +156 -0
  102. package/dist/lib/commands/tokens.js.map +1 -0
  103. package/dist/lib/commands/types.d.ts +3 -0
  104. package/dist/lib/commands/types.d.ts.map +1 -0
  105. package/dist/lib/commands/types.js +155 -0
  106. package/dist/lib/commands/types.js.map +1 -0
  107. package/dist/lib/commands/update.d.ts +3 -0
  108. package/dist/lib/commands/update.d.ts.map +1 -0
  109. package/dist/lib/commands/update.js +202 -0
  110. package/dist/lib/commands/update.js.map +1 -0
  111. package/dist/lib/commands/users.d.ts +382 -0
  112. package/dist/lib/commands/users.d.ts.map +1 -0
  113. package/dist/lib/commands/users.js +1195 -0
  114. package/dist/lib/commands/users.js.map +1 -0
  115. package/dist/lib/commands/vcs.d.ts +92 -0
  116. package/dist/lib/commands/vcs.d.ts.map +1 -0
  117. package/dist/lib/commands/vcs.js +276 -0
  118. package/dist/lib/commands/vcs.js.map +1 -0
  119. package/dist/lib/config.d.ts +118 -0
  120. package/dist/lib/config.d.ts.map +1 -0
  121. package/{lib → dist/lib}/config.js +204 -325
  122. package/dist/lib/config.js.map +1 -0
  123. package/dist/lib/emulation/docker.d.ts +15 -0
  124. package/dist/lib/emulation/docker.d.ts.map +1 -0
  125. package/dist/lib/emulation/docker.js +220 -0
  126. package/dist/lib/emulation/docker.js.map +1 -0
  127. package/dist/lib/emulation/utils.d.ts +29 -0
  128. package/dist/lib/emulation/utils.d.ts.map +1 -0
  129. package/dist/lib/emulation/utils.js +168 -0
  130. package/dist/lib/emulation/utils.js.map +1 -0
  131. package/dist/lib/exception.d.ts +8 -0
  132. package/dist/lib/exception.d.ts.map +1 -0
  133. package/dist/lib/exception.js +16 -0
  134. package/dist/lib/exception.js.map +1 -0
  135. package/dist/lib/id.d.ts +7 -0
  136. package/dist/lib/id.d.ts.map +1 -0
  137. package/dist/lib/id.js +32 -0
  138. package/dist/lib/id.js.map +1 -0
  139. package/dist/lib/paginate.d.ts +10 -0
  140. package/dist/lib/paginate.d.ts.map +1 -0
  141. package/{lib → dist/lib}/paginate.js +9 -15
  142. package/dist/lib/paginate.js.map +1 -0
  143. package/dist/lib/parser.d.ts +18 -0
  144. package/dist/lib/parser.d.ts.map +1 -0
  145. package/dist/lib/parser.js +237 -0
  146. package/dist/lib/parser.js.map +1 -0
  147. package/dist/lib/questions.d.ts +59 -0
  148. package/dist/lib/questions.d.ts.map +1 -0
  149. package/dist/lib/questions.js +995 -0
  150. package/dist/lib/questions.js.map +1 -0
  151. package/dist/lib/sdks.d.ts +4 -0
  152. package/dist/lib/sdks.d.ts.map +1 -0
  153. package/dist/lib/sdks.js +51 -0
  154. package/dist/lib/sdks.js.map +1 -0
  155. package/dist/lib/spinner.d.ts +28 -0
  156. package/dist/lib/spinner.d.ts.map +1 -0
  157. package/{lib → dist/lib}/spinner.js +34 -45
  158. package/dist/lib/spinner.js.map +1 -0
  159. package/dist/lib/type-generation/attribute.d.ts +17 -0
  160. package/dist/lib/type-generation/attribute.d.ts.map +1 -0
  161. package/dist/lib/type-generation/attribute.js +19 -0
  162. package/dist/lib/type-generation/attribute.js.map +1 -0
  163. package/dist/lib/type-generation/languages/csharp.d.ts +7 -0
  164. package/dist/lib/type-generation/languages/csharp.d.ts.map +1 -0
  165. package/dist/lib/type-generation/languages/csharp.js +180 -0
  166. package/dist/lib/type-generation/languages/csharp.js.map +1 -0
  167. package/dist/lib/type-generation/languages/dart.d.ts +8 -0
  168. package/dist/lib/type-generation/languages/dart.d.ts.map +1 -0
  169. package/dist/lib/type-generation/languages/dart.js +197 -0
  170. package/dist/lib/type-generation/languages/dart.js.map +1 -0
  171. package/dist/lib/type-generation/languages/java.d.ts +7 -0
  172. package/dist/lib/type-generation/languages/java.d.ts.map +1 -0
  173. package/dist/lib/type-generation/languages/java.js +140 -0
  174. package/dist/lib/type-generation/languages/java.js.map +1 -0
  175. package/dist/lib/type-generation/languages/javascript.d.ts +9 -0
  176. package/dist/lib/type-generation/languages/javascript.d.ts.map +1 -0
  177. package/dist/lib/type-generation/languages/javascript.js +108 -0
  178. package/dist/lib/type-generation/languages/javascript.js.map +1 -0
  179. package/dist/lib/type-generation/languages/kotlin.d.ts +7 -0
  180. package/dist/lib/type-generation/languages/kotlin.d.ts.map +1 -0
  181. package/dist/lib/type-generation/languages/kotlin.js +95 -0
  182. package/dist/lib/type-generation/languages/kotlin.js.map +1 -0
  183. package/dist/lib/type-generation/languages/language.d.ts +43 -0
  184. package/dist/lib/type-generation/languages/language.d.ts.map +1 -0
  185. package/dist/lib/type-generation/languages/language.js +82 -0
  186. package/dist/lib/type-generation/languages/language.js.map +1 -0
  187. package/dist/lib/type-generation/languages/php.d.ts +7 -0
  188. package/dist/lib/type-generation/languages/php.d.ts.map +1 -0
  189. package/dist/lib/type-generation/languages/php.js +116 -0
  190. package/dist/lib/type-generation/languages/php.js.map +1 -0
  191. package/dist/lib/type-generation/languages/swift.d.ts +7 -0
  192. package/dist/lib/type-generation/languages/swift.d.ts.map +1 -0
  193. package/dist/lib/type-generation/languages/swift.js +179 -0
  194. package/dist/lib/type-generation/languages/swift.js.map +1 -0
  195. package/dist/lib/type-generation/languages/typescript.d.ts +9 -0
  196. package/dist/lib/type-generation/languages/typescript.d.ts.map +1 -0
  197. package/dist/lib/type-generation/languages/typescript.js +112 -0
  198. package/dist/lib/type-generation/languages/typescript.js.map +1 -0
  199. package/dist/lib/types.d.ts +133 -0
  200. package/dist/lib/types.d.ts.map +1 -0
  201. package/dist/lib/types.js +3 -0
  202. package/dist/lib/types.js.map +1 -0
  203. package/dist/lib/utils.d.ts +15 -0
  204. package/dist/lib/utils.d.ts.map +1 -0
  205. package/{lib → dist/lib}/utils.js +74 -120
  206. package/dist/lib/utils.js.map +1 -0
  207. package/dist/lib/validations.d.ts +2 -0
  208. package/dist/lib/validations.d.ts.map +1 -0
  209. package/dist/lib/validations.js +20 -0
  210. package/dist/lib/validations.js.map +1 -0
  211. package/docs/examples/databases/upsert-document.md +1 -2
  212. package/index.ts +152 -0
  213. package/install.ps1 +2 -5
  214. package/install.sh +1 -2
  215. package/lib/client.ts +259 -0
  216. package/lib/commands/{account.js → account.ts} +408 -662
  217. package/lib/commands/console.ts +112 -0
  218. package/lib/commands/{databases.js → databases.ts} +818 -1136
  219. package/lib/commands/{functions.js → functions.ts} +381 -526
  220. package/lib/commands/{generic.js → generic.ts} +47 -39
  221. package/lib/commands/graphql.ts +110 -0
  222. package/lib/commands/{health.js → health.ts} +168 -284
  223. package/lib/commands/{init.js → init.ts} +68 -66
  224. package/lib/commands/{locale.js → locale.ts} +75 -121
  225. package/lib/commands/{messaging.js → messaging.ts} +699 -937
  226. package/lib/commands/{migrations.js → migrations.ts} +182 -258
  227. package/lib/commands/organizations.ts +46 -0
  228. package/lib/commands/{project.js → project.ts} +75 -111
  229. package/lib/commands/{projects.js → projects.ts} +587 -843
  230. package/lib/commands/{proxy.js → proxy.ts} +94 -140
  231. package/lib/commands/{pull.js → pull.ts} +54 -44
  232. package/lib/commands/{push.js → push.ts} +235 -191
  233. package/lib/commands/{run.js → run.ts} +61 -55
  234. package/lib/commands/{sites.js → sites.ts} +364 -504
  235. package/lib/commands/{storage.js → storage.ts} +216 -292
  236. package/lib/commands/{tables-db.js → tables-db.ts} +817 -1126
  237. package/lib/commands/{teams.js → teams.ts} +162 -236
  238. package/lib/commands/{tokens.js → tokens.ts} +70 -99
  239. package/lib/commands/{types.js → types.ts} +37 -35
  240. package/lib/commands/{update.js → update.ts} +25 -27
  241. package/lib/commands/{users.js → users.ts} +426 -644
  242. package/lib/commands/{vcs.js → vcs.ts} +118 -174
  243. package/lib/config.ts +854 -0
  244. package/lib/emulation/{docker.js → docker.ts} +39 -38
  245. package/lib/emulation/utils.ts +193 -0
  246. package/lib/exception.ts +20 -0
  247. package/lib/{id.js → id.ts} +5 -5
  248. package/lib/paginate.ts +63 -0
  249. package/lib/parser.ts +238 -0
  250. package/lib/{questions.js → questions.ts} +148 -156
  251. package/lib/sdks.ts +55 -0
  252. package/lib/spinner.ts +118 -0
  253. package/lib/type-generation/attribute.ts +17 -0
  254. package/lib/type-generation/languages/{csharp.js → csharp.ts} +59 -57
  255. package/lib/type-generation/languages/{dart.js → dart.ts} +91 -89
  256. package/lib/type-generation/languages/{java.js → java.ts} +58 -56
  257. package/lib/type-generation/languages/javascript.ts +111 -0
  258. package/lib/type-generation/languages/kotlin.ts +96 -0
  259. package/lib/type-generation/languages/language.ts +119 -0
  260. package/lib/type-generation/languages/{php.js → php.ts} +55 -53
  261. package/lib/type-generation/languages/{swift.js → swift.ts} +59 -57
  262. package/lib/type-generation/languages/typescript.ts +116 -0
  263. package/lib/types.ts +150 -0
  264. package/lib/utils.ts +322 -0
  265. package/lib/validations.ts +17 -0
  266. package/package.json +21 -12
  267. package/scoop/appwrite.config.json +3 -3
  268. package/tsconfig.json +30 -0
  269. package/index.js +0 -147
  270. package/lib/client.js +0 -254
  271. package/lib/commands/console.js +0 -127
  272. package/lib/commands/graphql.js +0 -126
  273. package/lib/commands/organizations.js +0 -48
  274. package/lib/emulation/utils.js +0 -186
  275. package/lib/exception.js +0 -9
  276. package/lib/parser.js +0 -250
  277. package/lib/sdks.js +0 -60
  278. package/lib/type-generation/attribute.js +0 -19
  279. package/lib/type-generation/languages/javascript.js +0 -111
  280. package/lib/type-generation/languages/kotlin.js +0 -94
  281. package/lib/type-generation/languages/language.js +0 -125
  282. package/lib/type-generation/languages/typescript.js +0 -116
  283. package/lib/validations.js +0 -17
@@ -0,0 +1,2154 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deploy = exports.push = void 0;
7
+ const fs = require("fs");
8
+ const dotenv_1 = require("dotenv");
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const inquirer_1 = __importDefault(require("inquirer"));
11
+ const json_bigint_1 = __importDefault(require("json-bigint"));
12
+ const commander_1 = require("commander");
13
+ const id_1 = __importDefault(require("../id"));
14
+ const config_1 = require("../config");
15
+ const spinner_1 = require("../spinner");
16
+ const paginate_1 = require("../paginate");
17
+ const questions_1 = require("../questions");
18
+ const parser_1 = require("../parser");
19
+ const proxy_1 = require("./proxy");
20
+ const console_1 = require("./console");
21
+ const sdks_1 = require("../sdks");
22
+ const functions_1 = require("./functions");
23
+ const sites_1 = require("./sites");
24
+ const databases_1 = require("./databases");
25
+ const tables_db_1 = require("./tables-db");
26
+ const storage_1 = require("./storage");
27
+ const messaging_1 = require("./messaging");
28
+ const teams_1 = require("./teams");
29
+ const projects_1 = require("./projects");
30
+ const utils_1 = require("../utils");
31
+ const JSONbigNative = (0, json_bigint_1.default)({ storeAsString: false });
32
+ const STEP_SIZE = 100; // Resources
33
+ const POLL_DEBOUNCE = 2000; // Milliseconds
34
+ const POLL_MAX_DEBOUNCE = 1800; // Times of POLL_DEBOUNCE (1 hour)
35
+ const POLL_DEFAULT_VALUE = 30;
36
+ let pollMaxDebounces = POLL_DEFAULT_VALUE;
37
+ const changeableKeys = ['status', 'required', 'xdefault', 'elements', 'min', 'max', 'default', 'error'];
38
+ const awaitPools = {
39
+ wipeAttributes: async (databaseId, collectionId, iteration = 1) => {
40
+ if (iteration > pollMaxDebounces) {
41
+ return false;
42
+ }
43
+ const { total } = await (0, databases_1.databasesListAttributes)({
44
+ databaseId,
45
+ collectionId,
46
+ queries: [JSON.stringify({ method: 'limit', values: [1] })],
47
+ parseOutput: false
48
+ });
49
+ if (total === 0) {
50
+ return true;
51
+ }
52
+ if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
53
+ let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
54
+ if (steps > 1 && iteration === 1) {
55
+ pollMaxDebounces *= steps;
56
+ (0, parser_1.log)('Found a large number of attributes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes');
57
+ }
58
+ }
59
+ await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
60
+ return await awaitPools.wipeAttributes(databaseId, collectionId, iteration + 1);
61
+ },
62
+ wipeIndexes: async (databaseId, collectionId, iteration = 1) => {
63
+ if (iteration > pollMaxDebounces) {
64
+ return false;
65
+ }
66
+ const { total } = await (0, databases_1.databasesListIndexes)({
67
+ databaseId,
68
+ collectionId,
69
+ queries: [JSON.stringify({ method: 'limit', values: [1] })],
70
+ parseOutput: false
71
+ });
72
+ if (total === 0) {
73
+ return true;
74
+ }
75
+ if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
76
+ let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
77
+ if (steps > 1 && iteration === 1) {
78
+ pollMaxDebounces *= steps;
79
+ (0, parser_1.log)('Found a large number of indexes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes');
80
+ }
81
+ }
82
+ await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
83
+ return await awaitPools.wipeIndexes(databaseId, collectionId, iteration + 1);
84
+ },
85
+ deleteAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
86
+ if (iteration > pollMaxDebounces) {
87
+ return false;
88
+ }
89
+ if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
90
+ let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
91
+ if (steps > 1 && iteration === 1) {
92
+ pollMaxDebounces *= steps;
93
+ (0, parser_1.log)('Found a large number of attributes to be deleted. Increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes');
94
+ }
95
+ }
96
+ const { attributes } = await (0, paginate_1.paginate)(databases_1.databasesListAttributes, {
97
+ databaseId,
98
+ collectionId,
99
+ parseOutput: false
100
+ }, 100, 'attributes');
101
+ const ready = attributeKeys.filter((attribute) => attributes.includes(attribute.key));
102
+ if (ready.length === 0) {
103
+ return true;
104
+ }
105
+ await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
106
+ return await awaitPools.expectAttributes(databaseId, collectionId, attributeKeys, iteration + 1);
107
+ },
108
+ expectAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
109
+ if (iteration > pollMaxDebounces) {
110
+ return false;
111
+ }
112
+ if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
113
+ let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
114
+ if (steps > 1 && iteration === 1) {
115
+ pollMaxDebounces *= steps;
116
+ (0, parser_1.log)('Creating a large number of attributes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes');
117
+ }
118
+ }
119
+ const { attributes } = await (0, paginate_1.paginate)(databases_1.databasesListAttributes, {
120
+ databaseId,
121
+ collectionId,
122
+ parseOutput: false
123
+ }, 100, 'attributes');
124
+ const ready = attributes
125
+ .filter((attribute) => {
126
+ if (attributeKeys.includes(attribute.key)) {
127
+ if (['stuck', 'failed'].includes(attribute.status)) {
128
+ throw new Error(`Attribute '${attribute.key}' failed!`);
129
+ }
130
+ return attribute.status === 'available';
131
+ }
132
+ return false;
133
+ })
134
+ .map((attribute) => attribute.key);
135
+ if (ready.length === attributeKeys.length) {
136
+ return true;
137
+ }
138
+ await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
139
+ return await awaitPools.expectAttributes(databaseId, collectionId, attributeKeys, iteration + 1);
140
+ },
141
+ deleteIndexes: async (databaseId, collectionId, indexesKeys, iteration = 1) => {
142
+ if (iteration > pollMaxDebounces) {
143
+ return false;
144
+ }
145
+ if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
146
+ let steps = Math.max(1, Math.ceil(indexesKeys.length / STEP_SIZE));
147
+ if (steps > 1 && iteration === 1) {
148
+ pollMaxDebounces *= steps;
149
+ (0, parser_1.log)('Found a large number of indexes to be deleted. Increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes');
150
+ }
151
+ }
152
+ const { indexes } = await (0, paginate_1.paginate)(databases_1.databasesListIndexes, {
153
+ databaseId,
154
+ collectionId,
155
+ parseOutput: false
156
+ }, 100, 'indexes');
157
+ const ready = indexesKeys.filter((index) => indexes.includes(index.key));
158
+ if (ready.length === 0) {
159
+ return true;
160
+ }
161
+ await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
162
+ return await awaitPools.expectIndexes(databaseId, collectionId, indexesKeys, iteration + 1);
163
+ },
164
+ expectIndexes: async (databaseId, collectionId, indexKeys, iteration = 1) => {
165
+ if (iteration > pollMaxDebounces) {
166
+ return false;
167
+ }
168
+ if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
169
+ let steps = Math.max(1, Math.ceil(indexKeys.length / STEP_SIZE));
170
+ if (steps > 1 && iteration === 1) {
171
+ pollMaxDebounces *= steps;
172
+ (0, parser_1.log)('Creating a large number of indexes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes');
173
+ }
174
+ }
175
+ const { indexes } = await (0, paginate_1.paginate)(databases_1.databasesListIndexes, {
176
+ databaseId,
177
+ collectionId,
178
+ parseOutput: false
179
+ }, 100, 'indexes');
180
+ const ready = indexes
181
+ .filter((index) => {
182
+ if (indexKeys.includes(index.key)) {
183
+ if (['stuck', 'failed'].includes(index.status)) {
184
+ throw new Error(`Index '${index.key}' failed!`);
185
+ }
186
+ return index.status === 'available';
187
+ }
188
+ return false;
189
+ })
190
+ .map((index) => index.key);
191
+ if (ready.length >= indexKeys.length) {
192
+ return true;
193
+ }
194
+ await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
195
+ return await awaitPools.expectIndexes(databaseId, collectionId, indexKeys, iteration + 1);
196
+ },
197
+ };
198
+ const getConfirmation = async () => {
199
+ if (parser_1.cliConfig.force) {
200
+ return true;
201
+ }
202
+ async function fixConfirmation() {
203
+ const answers = await inquirer_1.default.prompt(questions_1.questionPushChangesConfirmation);
204
+ if (answers.changes !== 'YES' && answers.changes !== 'NO') {
205
+ return await fixConfirmation();
206
+ }
207
+ return answers.changes;
208
+ }
209
+ let answers = await inquirer_1.default.prompt(questions_1.questionPushChanges);
210
+ if (answers.changes !== 'YES' && answers.changes !== 'NO') {
211
+ answers.changes = await fixConfirmation();
212
+ }
213
+ if (answers.changes === 'YES') {
214
+ return true;
215
+ }
216
+ (0, parser_1.warn)('Skipping push action. Changes were not applied.');
217
+ return false;
218
+ };
219
+ const isEmpty = (value) => (value === null || value === undefined || (typeof value === "string" && value.trim().length === 0) || (Array.isArray(value) && value.length === 0));
220
+ const approveChanges = async (resource, resourceGetFunction, keys, resourceName, resourcePlural, skipKeys = [], secondId = '', secondResourceName = '') => {
221
+ (0, parser_1.log)('Checking for changes ...');
222
+ const changes = [];
223
+ await Promise.all(resource.map(async (localResource) => {
224
+ try {
225
+ const options = {
226
+ [resourceName]: localResource['$id'],
227
+ parseOutput: false,
228
+ };
229
+ if (secondId !== '' && secondResourceName !== '') {
230
+ options[secondResourceName] = localResource[secondId];
231
+ }
232
+ const remoteResource = await resourceGetFunction(options);
233
+ for (let [key, value] of Object.entries((0, config_1.whitelistKeys)(remoteResource, keys))) {
234
+ if (skipKeys.includes(key)) {
235
+ continue;
236
+ }
237
+ if (isEmpty(value) && isEmpty(localResource[key])) {
238
+ continue;
239
+ }
240
+ if (Array.isArray(value) && Array.isArray(localResource[key])) {
241
+ if (JSON.stringify(value) !== JSON.stringify(localResource[key])) {
242
+ changes.push({
243
+ id: localResource['$id'],
244
+ key,
245
+ remote: chalk_1.default.red(value.join('\n')),
246
+ local: chalk_1.default.green(localResource[key].join('\n'))
247
+ });
248
+ }
249
+ }
250
+ else if (value !== localResource[key]) {
251
+ changes.push({
252
+ id: localResource['$id'],
253
+ key,
254
+ remote: chalk_1.default.red(value),
255
+ local: chalk_1.default.green(localResource[key])
256
+ });
257
+ }
258
+ }
259
+ }
260
+ catch (e) {
261
+ if (Number(e.code) !== 404) {
262
+ throw e;
263
+ }
264
+ }
265
+ }));
266
+ if (changes.length === 0) {
267
+ return true;
268
+ }
269
+ (0, parser_1.drawTable)(changes);
270
+ if ((await getConfirmation()) === true) {
271
+ return true;
272
+ }
273
+ (0, parser_1.success)(`Successfully pushed 0 ${resourcePlural}.`);
274
+ return false;
275
+ };
276
+ const getObjectChanges = (remote, local, index, what) => {
277
+ const changes = [];
278
+ if (remote[index] && local[index]) {
279
+ for (let [service, status] of Object.entries(remote[index])) {
280
+ const localValue = local[index][service];
281
+ let valuesEqual = false;
282
+ if (Array.isArray(status) && Array.isArray(localValue)) {
283
+ valuesEqual = JSON.stringify(status) === JSON.stringify(localValue);
284
+ }
285
+ else {
286
+ valuesEqual = status === localValue;
287
+ }
288
+ if (!valuesEqual) {
289
+ changes.push({ group: what, setting: service, remote: chalk_1.default.red(status), local: chalk_1.default.green(localValue) });
290
+ }
291
+ }
292
+ }
293
+ return changes;
294
+ };
295
+ const createAttribute = (databaseId, collectionId, attribute) => {
296
+ switch (attribute.type) {
297
+ case 'string':
298
+ switch (attribute.format) {
299
+ case 'email':
300
+ return (0, databases_1.databasesCreateEmailAttribute)({
301
+ databaseId,
302
+ collectionId,
303
+ key: attribute.key,
304
+ required: attribute.required,
305
+ xdefault: attribute.default,
306
+ array: attribute.array,
307
+ parseOutput: false
308
+ });
309
+ case 'url':
310
+ return (0, databases_1.databasesCreateUrlAttribute)({
311
+ databaseId,
312
+ collectionId,
313
+ key: attribute.key,
314
+ required: attribute.required,
315
+ xdefault: attribute.default,
316
+ array: attribute.array,
317
+ parseOutput: false
318
+ });
319
+ case 'ip':
320
+ return (0, databases_1.databasesCreateIpAttribute)({
321
+ databaseId,
322
+ collectionId,
323
+ key: attribute.key,
324
+ required: attribute.required,
325
+ xdefault: attribute.default,
326
+ array: attribute.array,
327
+ parseOutput: false
328
+ });
329
+ case 'enum':
330
+ return (0, databases_1.databasesCreateEnumAttribute)({
331
+ databaseId,
332
+ collectionId,
333
+ key: attribute.key,
334
+ elements: attribute.elements,
335
+ required: attribute.required,
336
+ xdefault: attribute.default,
337
+ array: attribute.array,
338
+ parseOutput: false
339
+ });
340
+ default:
341
+ return (0, databases_1.databasesCreateStringAttribute)({
342
+ databaseId,
343
+ collectionId,
344
+ key: attribute.key,
345
+ size: attribute.size,
346
+ required: attribute.required,
347
+ xdefault: attribute.default,
348
+ array: attribute.array,
349
+ encrypt: attribute.encrypt,
350
+ parseOutput: false
351
+ });
352
+ }
353
+ case 'integer':
354
+ return (0, databases_1.databasesCreateIntegerAttribute)({
355
+ databaseId,
356
+ collectionId,
357
+ key: attribute.key,
358
+ required: attribute.required,
359
+ min: attribute.min,
360
+ max: attribute.max,
361
+ xdefault: attribute.default,
362
+ array: attribute.array,
363
+ parseOutput: false
364
+ });
365
+ case 'double':
366
+ return (0, databases_1.databasesCreateFloatAttribute)({
367
+ databaseId,
368
+ collectionId,
369
+ key: attribute.key,
370
+ required: attribute.required,
371
+ min: attribute.min,
372
+ max: attribute.max,
373
+ xdefault: attribute.default,
374
+ array: attribute.array,
375
+ parseOutput: false
376
+ });
377
+ case 'boolean':
378
+ return (0, databases_1.databasesCreateBooleanAttribute)({
379
+ databaseId,
380
+ collectionId,
381
+ key: attribute.key,
382
+ required: attribute.required,
383
+ xdefault: attribute.default,
384
+ array: attribute.array,
385
+ parseOutput: false
386
+ });
387
+ case 'datetime':
388
+ return (0, databases_1.databasesCreateDatetimeAttribute)({
389
+ databaseId,
390
+ collectionId,
391
+ key: attribute.key,
392
+ required: attribute.required,
393
+ xdefault: attribute.default,
394
+ array: attribute.array,
395
+ parseOutput: false
396
+ });
397
+ case 'relationship':
398
+ return (0, databases_1.databasesCreateRelationshipAttribute)({
399
+ databaseId,
400
+ collectionId,
401
+ relatedCollectionId: attribute.relatedTable ?? attribute.relatedCollection,
402
+ type: attribute.relationType,
403
+ twoWay: attribute.twoWay,
404
+ key: attribute.key,
405
+ twoWayKey: attribute.twoWayKey,
406
+ onDelete: attribute.onDelete,
407
+ parseOutput: false
408
+ });
409
+ case 'point':
410
+ return (0, databases_1.databasesCreatePointAttribute)({
411
+ databaseId,
412
+ collectionId,
413
+ key: attribute.key,
414
+ required: attribute.required,
415
+ xdefault: attribute.default,
416
+ parseOutput: false
417
+ });
418
+ case 'linestring':
419
+ return (0, databases_1.databasesCreateLineAttribute)({
420
+ databaseId,
421
+ collectionId,
422
+ key: attribute.key,
423
+ required: attribute.required,
424
+ xdefault: attribute.default,
425
+ parseOutput: false
426
+ });
427
+ case 'polygon':
428
+ return (0, databases_1.databasesCreatePolygonAttribute)({
429
+ databaseId,
430
+ collectionId,
431
+ key: attribute.key,
432
+ required: attribute.required,
433
+ xdefault: attribute.default,
434
+ parseOutput: false
435
+ });
436
+ default:
437
+ throw new Error(`Unsupported attribute type: ${attribute.type}`);
438
+ }
439
+ };
440
+ const updateAttribute = (databaseId, collectionId, attribute) => {
441
+ switch (attribute.type) {
442
+ case 'string':
443
+ switch (attribute.format) {
444
+ case 'email':
445
+ return (0, databases_1.databasesUpdateEmailAttribute)({
446
+ databaseId,
447
+ collectionId,
448
+ key: attribute.key,
449
+ required: attribute.required,
450
+ xdefault: attribute.default,
451
+ array: attribute.array,
452
+ parseOutput: false
453
+ });
454
+ case 'url':
455
+ return (0, databases_1.databasesUpdateUrlAttribute)({
456
+ databaseId,
457
+ collectionId,
458
+ key: attribute.key,
459
+ required: attribute.required,
460
+ xdefault: attribute.default,
461
+ array: attribute.array,
462
+ parseOutput: false
463
+ });
464
+ case 'ip':
465
+ return (0, databases_1.databasesUpdateIpAttribute)({
466
+ databaseId,
467
+ collectionId,
468
+ key: attribute.key,
469
+ required: attribute.required,
470
+ xdefault: attribute.default,
471
+ array: attribute.array,
472
+ parseOutput: false
473
+ });
474
+ case 'enum':
475
+ return (0, databases_1.databasesUpdateEnumAttribute)({
476
+ databaseId,
477
+ collectionId,
478
+ key: attribute.key,
479
+ elements: attribute.elements,
480
+ required: attribute.required,
481
+ xdefault: attribute.default,
482
+ array: attribute.array,
483
+ parseOutput: false
484
+ });
485
+ default:
486
+ return (0, databases_1.databasesUpdateStringAttribute)({
487
+ databaseId,
488
+ collectionId,
489
+ key: attribute.key,
490
+ size: attribute.size,
491
+ required: attribute.required,
492
+ xdefault: attribute.default,
493
+ array: attribute.array,
494
+ parseOutput: false
495
+ });
496
+ }
497
+ case 'integer':
498
+ return (0, databases_1.databasesUpdateIntegerAttribute)({
499
+ databaseId,
500
+ collectionId,
501
+ key: attribute.key,
502
+ required: attribute.required,
503
+ min: attribute.min,
504
+ max: attribute.max,
505
+ xdefault: attribute.default,
506
+ array: attribute.array,
507
+ parseOutput: false
508
+ });
509
+ case 'double':
510
+ return (0, databases_1.databasesUpdateFloatAttribute)({
511
+ databaseId,
512
+ collectionId,
513
+ key: attribute.key,
514
+ required: attribute.required,
515
+ min: attribute.min,
516
+ max: attribute.max,
517
+ xdefault: attribute.default,
518
+ array: attribute.array,
519
+ parseOutput: false
520
+ });
521
+ case 'boolean':
522
+ return (0, databases_1.databasesUpdateBooleanAttribute)({
523
+ databaseId,
524
+ collectionId,
525
+ key: attribute.key,
526
+ required: attribute.required,
527
+ xdefault: attribute.default,
528
+ array: attribute.array,
529
+ parseOutput: false
530
+ });
531
+ case 'datetime':
532
+ return (0, databases_1.databasesUpdateDatetimeAttribute)({
533
+ databaseId,
534
+ collectionId,
535
+ key: attribute.key,
536
+ required: attribute.required,
537
+ xdefault: attribute.default,
538
+ array: attribute.array,
539
+ parseOutput: false
540
+ });
541
+ case 'relationship':
542
+ return (0, databases_1.databasesUpdateRelationshipAttribute)({
543
+ databaseId,
544
+ collectionId,
545
+ relatedCollectionId: attribute.relatedTable ?? attribute.relatedCollection,
546
+ type: attribute.relationType,
547
+ twoWay: attribute.twoWay,
548
+ key: attribute.key,
549
+ twoWayKey: attribute.twoWayKey,
550
+ onDelete: attribute.onDelete,
551
+ parseOutput: false
552
+ });
553
+ case 'point':
554
+ return (0, databases_1.databasesUpdatePointAttribute)({
555
+ databaseId,
556
+ collectionId,
557
+ key: attribute.key,
558
+ required: attribute.required,
559
+ xdefault: attribute.default,
560
+ parseOutput: false
561
+ });
562
+ case 'linestring':
563
+ return (0, databases_1.databasesUpdateLineAttribute)({
564
+ databaseId,
565
+ collectionId,
566
+ key: attribute.key,
567
+ required: attribute.required,
568
+ xdefault: attribute.default,
569
+ parseOutput: false
570
+ });
571
+ case 'polygon':
572
+ return (0, databases_1.databasesUpdatePolygonAttribute)({
573
+ databaseId,
574
+ collectionId,
575
+ key: attribute.key,
576
+ required: attribute.required,
577
+ xdefault: attribute.default,
578
+ parseOutput: false
579
+ });
580
+ default:
581
+ throw new Error(`Unsupported attribute type: ${attribute.type}`);
582
+ }
583
+ };
584
+ const deleteAttribute = async (collection, attribute, isIndex = false) => {
585
+ (0, parser_1.log)(`Deleting ${isIndex ? 'index' : 'attribute'} ${attribute.key} of ${collection.name} ( ${collection['$id']} )`);
586
+ if (isIndex) {
587
+ await (0, databases_1.databasesDeleteIndex)({
588
+ databaseId: collection['databaseId'],
589
+ collectionId: collection['$id'],
590
+ key: attribute.key,
591
+ parseOutput: false
592
+ });
593
+ return;
594
+ }
595
+ await (0, databases_1.databasesDeleteAttribute)({
596
+ databaseId: collection['databaseId'],
597
+ collectionId: collection['$id'],
598
+ key: attribute.key,
599
+ parseOutput: false
600
+ });
601
+ };
602
+ const isEqual = (a, b) => {
603
+ if (a === b)
604
+ return true;
605
+ if (a && b && typeof a === 'object' && typeof b === 'object') {
606
+ if (a.constructor && a.constructor.name === 'BigNumber' &&
607
+ b.constructor && b.constructor.name === 'BigNumber') {
608
+ return a.eq(b);
609
+ }
610
+ if (typeof a.equals === 'function') {
611
+ return a.equals(b);
612
+ }
613
+ if (typeof a.eq === 'function') {
614
+ return a.eq(b);
615
+ }
616
+ }
617
+ if (typeof a === 'number' && typeof b === 'number') {
618
+ if (isNaN(a) && isNaN(b))
619
+ return true;
620
+ if (!isFinite(a) && !isFinite(b))
621
+ return a === b;
622
+ return Math.abs(a - b) < Number.EPSILON;
623
+ }
624
+ return false;
625
+ };
626
+ const compareAttribute = (remote, local, reason, key) => {
627
+ if (isEmpty(remote) && isEmpty(local)) {
628
+ return reason;
629
+ }
630
+ if (Array.isArray(remote) && Array.isArray(local)) {
631
+ if (JSON.stringify(remote) !== JSON.stringify(local)) {
632
+ const bol = reason === '' ? '' : '\n';
633
+ reason += `${bol}${key} changed from ${chalk_1.default.red(remote)} to ${chalk_1.default.green(local)}`;
634
+ }
635
+ }
636
+ else if (!isEqual(remote, local)) {
637
+ const bol = reason === '' ? '' : '\n';
638
+ reason += `${bol}${key} changed from ${chalk_1.default.red(remote)} to ${chalk_1.default.green(local)}`;
639
+ }
640
+ return reason;
641
+ };
642
+ /**
643
+ * Check if attribute non-changeable fields has been changed
644
+ * If so return the differences as an object.
645
+ */
646
+ const checkAttributeChanges = (remote, local, collection, recreating = true) => {
647
+ if (local === undefined) {
648
+ return undefined;
649
+ }
650
+ const keyName = `${chalk_1.default.yellow(local.key)} in ${collection.name} (${collection['$id']})`;
651
+ const action = chalk_1.default.cyan(recreating ? 'recreating' : 'changing');
652
+ let reason = '';
653
+ let attribute = recreating ? remote : local;
654
+ for (let key of Object.keys(remote)) {
655
+ if (!config_1.KeysAttributes.has(key)) {
656
+ continue;
657
+ }
658
+ if (changeableKeys.includes(key)) {
659
+ if (!recreating) {
660
+ reason = compareAttribute(remote[key], local[key], reason, key);
661
+ }
662
+ continue;
663
+ }
664
+ if (!recreating) {
665
+ continue;
666
+ }
667
+ reason = compareAttribute(remote[key], local[key], reason, key);
668
+ }
669
+ return reason === '' ? undefined : { key: keyName, attribute, reason, action };
670
+ };
671
+ /**
672
+ * Check if attributes contain the given attribute
673
+ */
674
+ const attributesContains = (attribute, attributes) => attributes.find((attr) => attr.key === attribute.key);
675
+ const generateChangesObject = (attribute, collection, isAdding) => {
676
+ return {
677
+ key: `${chalk_1.default.yellow(attribute.key)} in ${collection.name} (${collection['$id']})`,
678
+ attribute: attribute,
679
+ reason: isAdding ? 'Field isn\'t present on the remote server' : 'Field isn\'t present on the appwrite.config.json file',
680
+ action: isAdding ? chalk_1.default.green('adding') : chalk_1.default.red('deleting')
681
+ };
682
+ };
683
+ /**
684
+ * Filter deleted and recreated attributes,
685
+ * return list of attributes to create
686
+ */
687
+ const attributesToCreate = async (remoteAttributes, localAttributes, collection, isIndex = false) => {
688
+ const deleting = remoteAttributes.filter((attribute) => !attributesContains(attribute, localAttributes)).map((attr) => generateChangesObject(attr, collection, false));
689
+ const adding = localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes)).map((attr) => generateChangesObject(attr, collection, true));
690
+ const conflicts = remoteAttributes.map((attribute) => checkAttributeChanges(attribute, attributesContains(attribute, localAttributes), collection)).filter(attribute => attribute !== undefined);
691
+ const changes = remoteAttributes.map((attribute) => checkAttributeChanges(attribute, attributesContains(attribute, localAttributes), collection, false))
692
+ .filter(attribute => attribute !== undefined)
693
+ .filter(attribute => conflicts.filter(attr => attribute.key === attr.key).length !== 1);
694
+ let changedAttributes = [];
695
+ const changing = [...deleting, ...adding, ...conflicts, ...changes];
696
+ if (changing.length === 0) {
697
+ return changedAttributes;
698
+ }
699
+ (0, parser_1.log)(!parser_1.cliConfig.force ? 'There are pending changes in your collection deployment' : 'List of applied changes');
700
+ (0, parser_1.drawTable)(changing.map((change) => {
701
+ return { Key: change.key, Action: change.action, Reason: change.reason, };
702
+ }));
703
+ if (!parser_1.cliConfig.force) {
704
+ if (deleting.length > 0 && !isIndex) {
705
+ console.log(`${chalk_1.default.red('------------------------------------------------------')}`);
706
+ console.log(`${chalk_1.default.red('| WARNING: Attribute deletion may cause loss of data |')}`);
707
+ console.log(`${chalk_1.default.red('------------------------------------------------------')}`);
708
+ console.log();
709
+ }
710
+ if (conflicts.length > 0 && !isIndex) {
711
+ console.log(`${chalk_1.default.red('--------------------------------------------------------')}`);
712
+ console.log(`${chalk_1.default.red('| WARNING: Attribute recreation may cause loss of data |')}`);
713
+ console.log(`${chalk_1.default.red('--------------------------------------------------------')}`);
714
+ console.log();
715
+ }
716
+ if ((await getConfirmation()) !== true) {
717
+ return changedAttributes;
718
+ }
719
+ }
720
+ if (conflicts.length > 0) {
721
+ changedAttributes = conflicts.map((change) => change.attribute);
722
+ await Promise.all(changedAttributes.map((changed) => deleteAttribute(collection, changed, isIndex)));
723
+ remoteAttributes = remoteAttributes.filter((attribute) => !attributesContains(attribute, changedAttributes));
724
+ }
725
+ if (changes.length > 0) {
726
+ changedAttributes = changes.map((change) => change.attribute);
727
+ await Promise.all(changedAttributes.map((changed) => updateAttribute(collection['databaseId'], collection['$id'], changed)));
728
+ }
729
+ const deletingAttributes = deleting.map((change) => change.attribute);
730
+ await Promise.all(deletingAttributes.map((attribute) => deleteAttribute(collection, attribute, isIndex)));
731
+ const attributeKeys = [...remoteAttributes.map((attribute) => attribute.key), ...deletingAttributes.map((attribute) => attribute.key)];
732
+ if (attributeKeys.length) {
733
+ const deleteAttributesPoolStatus = await awaitPools.deleteAttributes(collection['databaseId'], collection['$id'], attributeKeys);
734
+ if (!deleteAttributesPoolStatus) {
735
+ throw new Error("Attribute deletion timed out.");
736
+ }
737
+ }
738
+ return localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes));
739
+ };
740
+ const createIndexes = async (indexes, collection) => {
741
+ (0, parser_1.log)(`Creating indexes ...`);
742
+ for (let index of indexes) {
743
+ await (0, databases_1.databasesCreateIndex)({
744
+ databaseId: collection['databaseId'],
745
+ collectionId: collection['$id'],
746
+ key: index.key,
747
+ type: index.type,
748
+ attributes: index.columns ?? index.attributes,
749
+ orders: index.orders,
750
+ parseOutput: false
751
+ });
752
+ }
753
+ const result = await awaitPools.expectIndexes(collection['databaseId'], collection['$id'], indexes.map((index) => index.key));
754
+ if (!result) {
755
+ throw new Error('Index creation timed out.');
756
+ }
757
+ (0, parser_1.success)(`Created ${indexes.length} indexes`);
758
+ };
759
+ const createAttributes = async (attributes, collection) => {
760
+ for (let attribute of attributes) {
761
+ if (attribute.side !== 'child') {
762
+ await createAttribute(collection['databaseId'], collection['$id'], attribute);
763
+ }
764
+ }
765
+ const result = await awaitPools.expectAttributes(collection['databaseId'], collection['$id'], collection.attributes.filter((attribute) => attribute.side !== 'child').map((attribute) => attribute.key));
766
+ if (!result) {
767
+ throw new Error(`Attribute creation timed out.`);
768
+ }
769
+ (0, parser_1.success)(`Created ${attributes.length} attributes`);
770
+ };
771
+ const createColumns = async (columns, table) => {
772
+ for (let column of columns) {
773
+ if (column.side !== 'child') {
774
+ await createAttribute(table['databaseId'], table['$id'], column);
775
+ }
776
+ }
777
+ const result = await awaitPools.expectAttributes(table['databaseId'], table['$id'], table.columns.filter((column) => column.side !== 'child').map((column) => column.key));
778
+ if (!result) {
779
+ throw new Error(`Column creation timed out.`);
780
+ }
781
+ (0, parser_1.success)(`Created ${columns.length} columns`);
782
+ };
783
+ const pushResources = async () => {
784
+ const actions = {
785
+ settings: pushSettings,
786
+ functions: pushFunction,
787
+ sites: pushSite,
788
+ collections: pushCollection,
789
+ tables: pushTable,
790
+ buckets: pushBucket,
791
+ teams: pushTeam,
792
+ messages: pushMessagingTopic
793
+ };
794
+ if (parser_1.cliConfig.all) {
795
+ for (let action of Object.values(actions)) {
796
+ await action({ returnOnZero: true });
797
+ }
798
+ }
799
+ else {
800
+ const answers = await inquirer_1.default.prompt(questions_1.questionsPushResources[0]);
801
+ const action = actions[answers.resource];
802
+ if (action !== undefined) {
803
+ await action({ returnOnZero: true });
804
+ }
805
+ }
806
+ };
807
+ const pushSettings = async () => {
808
+ (0, utils_1.checkDeployConditions)(config_1.localConfig);
809
+ try {
810
+ let response = await (0, projects_1.projectsGet)({
811
+ parseOutput: false,
812
+ projectId: config_1.localConfig.getProject().projectId
813
+ });
814
+ const remoteSettings = config_1.localConfig.createSettingsObject(response ?? {});
815
+ const localSettings = config_1.localConfig.getProject().projectSettings ?? {};
816
+ (0, parser_1.log)('Checking for changes ...');
817
+ const changes = [];
818
+ changes.push(...(getObjectChanges(remoteSettings, localSettings, 'services', 'Service')));
819
+ changes.push(...(getObjectChanges(remoteSettings['auth'] ?? {}, localSettings['auth'] ?? {}, 'methods', 'Auth method')));
820
+ changes.push(...(getObjectChanges(remoteSettings['auth'] ?? {}, localSettings['auth'] ?? {}, 'security', 'Auth security')));
821
+ if (changes.length > 0) {
822
+ (0, parser_1.drawTable)(changes);
823
+ if ((await getConfirmation()) !== true) {
824
+ (0, parser_1.success)(`Successfully pushed 0 project settings.`);
825
+ return;
826
+ }
827
+ }
828
+ }
829
+ catch (e) {
830
+ }
831
+ try {
832
+ (0, parser_1.log)("Pushing project settings ...");
833
+ const projectId = config_1.localConfig.getProject().projectId;
834
+ const projectName = config_1.localConfig.getProject().projectName;
835
+ const settings = config_1.localConfig.getProject().projectSettings ?? {};
836
+ if (projectName) {
837
+ (0, parser_1.log)("Applying project name ...");
838
+ await (0, projects_1.projectsUpdate)({
839
+ projectId,
840
+ name: projectName,
841
+ parseOutput: false
842
+ });
843
+ }
844
+ if (settings.services) {
845
+ (0, parser_1.log)("Applying service statuses ...");
846
+ for (let [service, status] of Object.entries(settings.services)) {
847
+ await (0, projects_1.projectsUpdateServiceStatus)({
848
+ projectId,
849
+ service,
850
+ status,
851
+ parseOutput: false
852
+ });
853
+ }
854
+ }
855
+ if (settings.auth) {
856
+ if (settings.auth.security) {
857
+ (0, parser_1.log)("Applying auth security settings ...");
858
+ await (0, projects_1.projectsUpdateAuthDuration)({ projectId, duration: settings.auth.security.duration, parseOutput: false });
859
+ await (0, projects_1.projectsUpdateAuthLimit)({ projectId, limit: settings.auth.security.limit, parseOutput: false });
860
+ await (0, projects_1.projectsUpdateAuthSessionsLimit)({ projectId, limit: settings.auth.security.sessionsLimit, parseOutput: false });
861
+ await (0, projects_1.projectsUpdateAuthPasswordDictionary)({ projectId, enabled: settings.auth.security.passwordDictionary, parseOutput: false });
862
+ await (0, projects_1.projectsUpdateAuthPasswordHistory)({ projectId, limit: settings.auth.security.passwordHistory, parseOutput: false });
863
+ await (0, projects_1.projectsUpdatePersonalDataCheck)({ projectId, enabled: settings.auth.security.personalDataCheck, parseOutput: false });
864
+ await (0, projects_1.projectsUpdateSessionAlerts)({ projectId, alerts: settings.auth.security.sessionAlerts, parseOutput: false });
865
+ await (0, projects_1.projectsUpdateMockNumbers)({ projectId, numbers: settings.auth.security.mockNumbers, parseOutput: false });
866
+ }
867
+ if (settings.auth.methods) {
868
+ (0, parser_1.log)("Applying auth methods statuses ...");
869
+ for (let [method, status] of Object.entries(settings.auth.methods)) {
870
+ await (0, projects_1.projectsUpdateAuthStatus)({
871
+ projectId,
872
+ method,
873
+ status,
874
+ parseOutput: false
875
+ });
876
+ }
877
+ }
878
+ }
879
+ (0, parser_1.success)(`Successfully pushed ${chalk_1.default.bold('all')} project settings.`);
880
+ }
881
+ catch (e) {
882
+ throw e;
883
+ }
884
+ };
885
+ const pushSite = async ({ siteId, async: asyncDeploy, code, withVariables } = { returnOnZero: false }) => {
886
+ process.chdir(config_1.localConfig.configDirectoryPath);
887
+ const siteIds = [];
888
+ if (siteId) {
889
+ siteIds.push(siteId);
890
+ }
891
+ else if (parser_1.cliConfig.all) {
892
+ (0, utils_1.checkDeployConditions)(config_1.localConfig);
893
+ const sites = config_1.localConfig.getSites();
894
+ siteIds.push(...sites.map((site) => {
895
+ return site.$id;
896
+ }));
897
+ }
898
+ if (siteIds.length <= 0) {
899
+ const answers = await inquirer_1.default.prompt(questions_1.questionsPushSites[0]);
900
+ if (answers.sites) {
901
+ siteIds.push(...answers.sites);
902
+ }
903
+ }
904
+ if (siteIds.length === 0) {
905
+ (0, parser_1.log)("No sites found.");
906
+ (0, parser_1.hint)("Use 'appwrite pull sites' to synchronize existing one, or use 'appwrite init site' to create a new one.");
907
+ return;
908
+ }
909
+ let sites = siteIds.map((id) => {
910
+ const sites = config_1.localConfig.getSites();
911
+ const site = sites.find((s) => s.$id === id);
912
+ if (!site) {
913
+ throw new Error("Site '" + id + "' not found.");
914
+ }
915
+ return site;
916
+ });
917
+ (0, parser_1.log)('Validating sites ...');
918
+ // Validation is done BEFORE pushing so the deployment process can be run in async with progress update
919
+ for (let site of sites) {
920
+ if (!site.buildCommand) {
921
+ (0, parser_1.log)(`Site ${site.name} is missing build command.`);
922
+ const answers = await inquirer_1.default.prompt(questions_1.questionsGetEntrypoint);
923
+ site.buildCommand = answers.entrypoint;
924
+ config_1.localConfig.addSite(site);
925
+ }
926
+ }
927
+ if (!(await approveChanges(sites, sites_1.sitesGet, config_1.KeysSite, 'siteId', 'sites', ['vars']))) {
928
+ return;
929
+ }
930
+ (0, parser_1.log)('Pushing sites ...');
931
+ spinner_1.Spinner.start(false);
932
+ let successfullyPushed = 0;
933
+ let successfullyDeployed = 0;
934
+ const failedDeployments = [];
935
+ const errors = [];
936
+ await Promise.all(sites.map(async (site) => {
937
+ let response = {};
938
+ const ignore = site.ignore ? 'appwrite.config.json' : '.gitignore';
939
+ let siteExists = false;
940
+ let deploymentCreated = false;
941
+ const updaterRow = new spinner_1.Spinner({ status: '', resource: site.name, id: site['$id'], end: `Ignoring using: ${ignore}` });
942
+ updaterRow.update({ status: 'Getting' }).startSpinner(spinner_1.SPINNER_DOTS);
943
+ try {
944
+ response = await (0, sites_1.sitesGet)({
945
+ siteId: site['$id'],
946
+ parseOutput: false,
947
+ });
948
+ siteExists = true;
949
+ if (response.framework !== site.framework) {
950
+ updaterRow.fail({ errorMessage: `Framework mismatch! (local=${site.framework},remote=${response.framework}) Please delete remote site or update your appwrite.config.json` });
951
+ return;
952
+ }
953
+ updaterRow.update({ status: 'Updating' }).replaceSpinner(spinner_1.SPINNER_ARC);
954
+ response = await (0, sites_1.sitesUpdate)({
955
+ siteId: site['$id'],
956
+ name: site.name,
957
+ framework: site.framework,
958
+ buildRuntime: site.buildRuntime,
959
+ specification: site.specification,
960
+ timeout: site.timeout,
961
+ enabled: site.enabled,
962
+ logging: site.logging,
963
+ adapter: site.adapter,
964
+ buildCommand: site.buildCommand,
965
+ installCommand: site.installCommand,
966
+ outputDirectory: site.outputDirectory,
967
+ fallbackFile: site.fallbackFile,
968
+ vars: JSON.stringify(response.vars),
969
+ parseOutput: false
970
+ });
971
+ }
972
+ catch (e) {
973
+ if (Number(e.code) === 404) {
974
+ siteExists = false;
975
+ }
976
+ else {
977
+ errors.push(e);
978
+ updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' });
979
+ return;
980
+ }
981
+ }
982
+ if (!siteExists) {
983
+ updaterRow.update({ status: 'Creating' }).replaceSpinner(spinner_1.SPINNER_DOTS);
984
+ try {
985
+ response = await (0, sites_1.sitesCreate)({
986
+ siteId: site.$id,
987
+ name: site.name,
988
+ framework: site.framework,
989
+ specification: site.specification,
990
+ buildRuntime: site.buildRuntime,
991
+ buildCommand: site.buildCommand,
992
+ installCommand: site.installCommand,
993
+ outputDirectory: site.outputDirectory,
994
+ fallbackFile: site.fallbackFile,
995
+ adapter: site.adapter,
996
+ timeout: site.timeout,
997
+ enabled: site.enabled,
998
+ logging: site.logging,
999
+ parseOutput: false
1000
+ });
1001
+ let domain = '';
1002
+ try {
1003
+ const variables = await (0, console_1.consoleVariables)({ parseOutput: false, sdk: await (0, sdks_1.sdkForConsole)() });
1004
+ domain = id_1.default.unique() + '.' + variables['_APP_DOMAIN_SITES'];
1005
+ }
1006
+ catch (error) {
1007
+ console.error('Error fetching console variables.');
1008
+ throw error;
1009
+ }
1010
+ try {
1011
+ const rule = await (0, proxy_1.proxyCreateSiteRule)({
1012
+ domain: domain,
1013
+ siteId: site.$id
1014
+ });
1015
+ }
1016
+ catch (error) {
1017
+ console.error('Error creating site rule.');
1018
+ throw error;
1019
+ }
1020
+ updaterRow.update({ status: 'Created' });
1021
+ }
1022
+ catch (e) {
1023
+ errors.push(e);
1024
+ updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' });
1025
+ return;
1026
+ }
1027
+ }
1028
+ if (withVariables) {
1029
+ updaterRow.update({ status: 'Creating variables' }).replaceSpinner(spinner_1.SPINNER_ARC);
1030
+ const { variables } = await (0, paginate_1.paginate)(sites_1.sitesListVariables, {
1031
+ siteId: site['$id'],
1032
+ parseOutput: false
1033
+ }, 100, 'variables');
1034
+ await Promise.all(variables.map(async (variable) => {
1035
+ await (0, sites_1.sitesDeleteVariable)({
1036
+ siteId: site['$id'],
1037
+ variableId: variable['$id'],
1038
+ parseOutput: false
1039
+ });
1040
+ }));
1041
+ const envFileLocation = `${site['path']}/.env`;
1042
+ let envVariables = [];
1043
+ try {
1044
+ if (fs.existsSync(envFileLocation)) {
1045
+ const envObject = (0, dotenv_1.parse)(fs.readFileSync(envFileLocation, 'utf8'));
1046
+ envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
1047
+ }
1048
+ }
1049
+ catch (error) {
1050
+ // Handle parsing errors gracefully
1051
+ envVariables = [];
1052
+ }
1053
+ await Promise.all(envVariables.map(async (variable) => {
1054
+ await (0, sites_1.sitesCreateVariable)({
1055
+ siteId: site['$id'],
1056
+ key: variable.key,
1057
+ value: variable.value,
1058
+ parseOutput: false,
1059
+ secret: false
1060
+ });
1061
+ }));
1062
+ }
1063
+ if (code === false) {
1064
+ successfullyPushed++;
1065
+ successfullyDeployed++;
1066
+ updaterRow.update({ status: 'Pushed' });
1067
+ updaterRow.stopSpinner();
1068
+ return;
1069
+ }
1070
+ try {
1071
+ updaterRow.update({ status: 'Pushing' }).replaceSpinner(spinner_1.SPINNER_ARC);
1072
+ response = await (0, sites_1.sitesCreateDeployment)({
1073
+ siteId: site['$id'],
1074
+ buildCommand: site.buildCommand,
1075
+ installCommand: site.installCommand,
1076
+ outputDirectory: site.outputDirectory,
1077
+ fallbackFile: site.fallbackFile,
1078
+ code: site.path,
1079
+ activate: true,
1080
+ parseOutput: false
1081
+ });
1082
+ updaterRow.update({ status: 'Pushed' });
1083
+ deploymentCreated = true;
1084
+ successfullyPushed++;
1085
+ }
1086
+ catch (e) {
1087
+ errors.push(e);
1088
+ switch (e.code) {
1089
+ case 'ENOENT':
1090
+ updaterRow.fail({ errorMessage: 'Not found in the current directory. Skipping...' });
1091
+ break;
1092
+ default:
1093
+ updaterRow.fail({ errorMessage: e.message ?? 'An unknown error occurred. Please try again.' });
1094
+ }
1095
+ }
1096
+ if (deploymentCreated && !asyncDeploy) {
1097
+ try {
1098
+ const deploymentId = response['$id'];
1099
+ updaterRow.update({ status: 'Deploying', end: 'Checking deployment status...' });
1100
+ let pollChecks = 0;
1101
+ while (true) {
1102
+ response = await (0, sites_1.sitesGetDeployment)({
1103
+ siteId: site['$id'],
1104
+ deploymentId: deploymentId,
1105
+ parseOutput: false
1106
+ });
1107
+ const status = response['status'];
1108
+ if (status === 'ready') {
1109
+ successfullyDeployed++;
1110
+ let url = '';
1111
+ const res = await (0, proxy_1.proxyListRules)({
1112
+ parseOutput: false,
1113
+ queries: [
1114
+ JSON.stringify({ method: 'limit', values: [1] }),
1115
+ JSON.stringify({ method: 'equal', "attribute": "deploymentResourceType", "values": ["site"] }),
1116
+ JSON.stringify({ method: 'equal', "attribute": "deploymentResourceId", "values": [site['$id']] }),
1117
+ JSON.stringify({ method: 'equal', "attribute": "trigger", "values": ["manual"] }),
1118
+ ],
1119
+ });
1120
+ if (Number(res.total) === 1) {
1121
+ url = res.rules[0].domain;
1122
+ }
1123
+ updaterRow.update({ status: 'Deployed', end: url });
1124
+ break;
1125
+ }
1126
+ else if (status === 'failed') {
1127
+ failedDeployments.push({ name: site['name'], $id: site['$id'], deployment: response['$id'] });
1128
+ updaterRow.fail({ errorMessage: `Failed to deploy` });
1129
+ break;
1130
+ }
1131
+ else {
1132
+ updaterRow.update({ status: 'Deploying', end: `Current status: ${status}` });
1133
+ }
1134
+ pollChecks++;
1135
+ await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE * 1.5));
1136
+ }
1137
+ }
1138
+ catch (e) {
1139
+ errors.push(e);
1140
+ updaterRow.fail({ errorMessage: e.message ?? 'Unknown error occurred. Please try again' });
1141
+ }
1142
+ }
1143
+ updaterRow.stopSpinner();
1144
+ }));
1145
+ spinner_1.Spinner.stop();
1146
+ failedDeployments.forEach((failed) => {
1147
+ const { name, deployment, $id } = failed;
1148
+ const failUrl = `${config_1.globalConfig.getEndpoint().slice(0, -3)}/console/project-${config_1.localConfig.getProject().projectId}/sites/site-${$id}/deployments/deployment-${deployment}`;
1149
+ (0, parser_1.error)(`Deployment of ${name} has failed. Check at ${failUrl} for more details\n`);
1150
+ });
1151
+ if (!asyncDeploy) {
1152
+ if (successfullyPushed === 0) {
1153
+ (0, parser_1.error)('No sites were pushed.');
1154
+ }
1155
+ else if (successfullyDeployed !== successfullyPushed) {
1156
+ (0, parser_1.warn)(`Successfully pushed ${successfullyDeployed} of ${successfullyPushed} sites`);
1157
+ }
1158
+ else {
1159
+ (0, parser_1.success)(`Successfully pushed ${successfullyPushed} sites.`);
1160
+ }
1161
+ }
1162
+ else {
1163
+ (0, parser_1.success)(`Successfully pushed ${successfullyPushed} sites.`);
1164
+ }
1165
+ if (parser_1.cliConfig.verbose) {
1166
+ errors.forEach(e => {
1167
+ console.error(e);
1168
+ });
1169
+ }
1170
+ };
1171
+ const pushFunction = async ({ functionId, async: asyncDeploy, code, withVariables } = { returnOnZero: false }) => {
1172
+ process.chdir(config_1.localConfig.configDirectoryPath);
1173
+ const functionIds = [];
1174
+ if (functionId) {
1175
+ functionIds.push(functionId);
1176
+ }
1177
+ else if (parser_1.cliConfig.all) {
1178
+ (0, utils_1.checkDeployConditions)(config_1.localConfig);
1179
+ const functions = config_1.localConfig.getFunctions();
1180
+ functionIds.push(...functions.map((func) => {
1181
+ return func.$id;
1182
+ }));
1183
+ }
1184
+ if (functionIds.length <= 0) {
1185
+ const answers = await inquirer_1.default.prompt(questions_1.questionsPushFunctions[0]);
1186
+ if (answers.functions) {
1187
+ functionIds.push(...answers.functions);
1188
+ }
1189
+ }
1190
+ if (functionIds.length === 0) {
1191
+ (0, parser_1.log)("No functions found.");
1192
+ (0, parser_1.hint)("Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.");
1193
+ return;
1194
+ }
1195
+ let functions = functionIds.map((id) => {
1196
+ const functions = config_1.localConfig.getFunctions();
1197
+ const func = functions.find((f) => f.$id === id);
1198
+ if (!func) {
1199
+ throw new Error("Function '" + id + "' not found.");
1200
+ }
1201
+ return func;
1202
+ });
1203
+ (0, parser_1.log)('Validating functions ...');
1204
+ // Validation is done BEFORE pushing so the deployment process can be run in async with progress update
1205
+ for (let func of functions) {
1206
+ if (!func.entrypoint) {
1207
+ (0, parser_1.log)(`Function ${func.name} is missing an entrypoint.`);
1208
+ const answers = await inquirer_1.default.prompt(questions_1.questionsGetEntrypoint);
1209
+ func.entrypoint = answers.entrypoint;
1210
+ config_1.localConfig.addFunction(func);
1211
+ }
1212
+ }
1213
+ if (!(await approveChanges(functions, functions_1.functionsGet, config_1.KeysFunction, 'functionId', 'functions', ['vars']))) {
1214
+ return;
1215
+ }
1216
+ (0, parser_1.log)('Pushing functions ...');
1217
+ spinner_1.Spinner.start(false);
1218
+ let successfullyPushed = 0;
1219
+ let successfullyDeployed = 0;
1220
+ const failedDeployments = [];
1221
+ const errors = [];
1222
+ await Promise.all(functions.map(async (func) => {
1223
+ let response = {};
1224
+ const ignore = func.ignore ? 'appwrite.config.json' : '.gitignore';
1225
+ let functionExists = false;
1226
+ let deploymentCreated = false;
1227
+ const updaterRow = new spinner_1.Spinner({ status: '', resource: func.name, id: func['$id'], end: `Ignoring using: ${ignore}` });
1228
+ updaterRow.update({ status: 'Getting' }).startSpinner(spinner_1.SPINNER_DOTS);
1229
+ try {
1230
+ response = await (0, functions_1.functionsGet)({
1231
+ functionId: func['$id'],
1232
+ parseOutput: false,
1233
+ });
1234
+ functionExists = true;
1235
+ if (response.runtime !== func.runtime) {
1236
+ updaterRow.fail({ errorMessage: `Runtime mismatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.config.json` });
1237
+ return;
1238
+ }
1239
+ updaterRow.update({ status: 'Updating' }).replaceSpinner(spinner_1.SPINNER_ARC);
1240
+ response = await (0, functions_1.functionsUpdate)({
1241
+ functionId: func['$id'],
1242
+ name: func.name,
1243
+ specification: func.specification,
1244
+ execute: func.execute,
1245
+ events: func.events,
1246
+ schedule: func.schedule,
1247
+ timeout: func.timeout,
1248
+ enabled: func.enabled,
1249
+ logging: func.logging,
1250
+ entrypoint: func.entrypoint,
1251
+ commands: func.commands,
1252
+ scopes: func.scopes,
1253
+ vars: JSON.stringify(response.vars),
1254
+ parseOutput: false
1255
+ });
1256
+ }
1257
+ catch (e) {
1258
+ if (Number(e.code) === 404) {
1259
+ functionExists = false;
1260
+ }
1261
+ else {
1262
+ errors.push(e);
1263
+ updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' });
1264
+ return;
1265
+ }
1266
+ }
1267
+ if (!functionExists) {
1268
+ updaterRow.update({ status: 'Creating' }).replaceSpinner(spinner_1.SPINNER_DOTS);
1269
+ try {
1270
+ response = await (0, functions_1.functionsCreate)({
1271
+ functionId: func.$id,
1272
+ name: func.name,
1273
+ runtime: func.runtime,
1274
+ specification: func.specification,
1275
+ execute: func.execute,
1276
+ events: func.events,
1277
+ schedule: func.schedule,
1278
+ timeout: func.timeout,
1279
+ enabled: func.enabled,
1280
+ logging: func.logging,
1281
+ entrypoint: func.entrypoint,
1282
+ commands: func.commands,
1283
+ scopes: func.scopes,
1284
+ parseOutput: false
1285
+ });
1286
+ let domain = '';
1287
+ try {
1288
+ const variables = await (0, console_1.consoleVariables)({ parseOutput: false, sdk: await (0, sdks_1.sdkForConsole)() });
1289
+ domain = id_1.default.unique() + '.' + variables['_APP_DOMAIN_FUNCTIONS'];
1290
+ }
1291
+ catch (error) {
1292
+ console.error('Error fetching console variables.');
1293
+ throw error;
1294
+ }
1295
+ try {
1296
+ const rule = await (0, proxy_1.proxyCreateFunctionRule)({
1297
+ domain: domain,
1298
+ functionId: func.$id
1299
+ });
1300
+ }
1301
+ catch (error) {
1302
+ console.error('Error creating function rule.');
1303
+ throw error;
1304
+ }
1305
+ updaterRow.update({ status: 'Created' });
1306
+ }
1307
+ catch (e) {
1308
+ errors.push(e);
1309
+ updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' });
1310
+ return;
1311
+ }
1312
+ }
1313
+ if (withVariables) {
1314
+ updaterRow.update({ status: 'Updating variables' }).replaceSpinner(spinner_1.SPINNER_ARC);
1315
+ const { variables } = await (0, paginate_1.paginate)(functions_1.functionsListVariables, {
1316
+ functionId: func['$id'],
1317
+ parseOutput: false
1318
+ }, 100, 'variables');
1319
+ await Promise.all(variables.map(async (variable) => {
1320
+ await (0, functions_1.functionsDeleteVariable)({
1321
+ functionId: func['$id'],
1322
+ variableId: variable['$id'],
1323
+ parseOutput: false
1324
+ });
1325
+ }));
1326
+ const envFileLocation = `${func['path']}/.env`;
1327
+ let envVariables = [];
1328
+ try {
1329
+ if (fs.existsSync(envFileLocation)) {
1330
+ const envObject = (0, dotenv_1.parse)(fs.readFileSync(envFileLocation, 'utf8'));
1331
+ envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
1332
+ }
1333
+ }
1334
+ catch (error) {
1335
+ // Handle parsing errors gracefully
1336
+ envVariables = [];
1337
+ }
1338
+ await Promise.all(envVariables.map(async (variable) => {
1339
+ await (0, functions_1.functionsCreateVariable)({
1340
+ functionId: func['$id'],
1341
+ variableId: id_1.default.unique(),
1342
+ key: variable.key,
1343
+ value: variable.value,
1344
+ parseOutput: false,
1345
+ secret: false
1346
+ });
1347
+ }));
1348
+ }
1349
+ if (code === false) {
1350
+ successfullyPushed++;
1351
+ successfullyDeployed++;
1352
+ updaterRow.update({ status: 'Pushed' });
1353
+ updaterRow.stopSpinner();
1354
+ return;
1355
+ }
1356
+ try {
1357
+ updaterRow.update({ status: 'Pushing' }).replaceSpinner(spinner_1.SPINNER_ARC);
1358
+ response = await (0, functions_1.functionsCreateDeployment)({
1359
+ functionId: func['$id'],
1360
+ entrypoint: func.entrypoint,
1361
+ commands: func.commands,
1362
+ code: func.path,
1363
+ activate: true,
1364
+ parseOutput: false
1365
+ });
1366
+ updaterRow.update({ status: 'Pushed' });
1367
+ deploymentCreated = true;
1368
+ successfullyPushed++;
1369
+ }
1370
+ catch (e) {
1371
+ errors.push(e);
1372
+ switch (e.code) {
1373
+ case 'ENOENT':
1374
+ updaterRow.fail({ errorMessage: 'Not found in the current directory. Skipping...' });
1375
+ break;
1376
+ default:
1377
+ updaterRow.fail({ errorMessage: e.message ?? 'An unknown error occurred. Please try again.' });
1378
+ }
1379
+ }
1380
+ if (deploymentCreated && !asyncDeploy) {
1381
+ try {
1382
+ const deploymentId = response['$id'];
1383
+ updaterRow.update({ status: 'Deploying', end: 'Checking deployment status...' });
1384
+ let pollChecks = 0;
1385
+ while (true) {
1386
+ response = await (0, functions_1.functionsGetDeployment)({
1387
+ functionId: func['$id'],
1388
+ deploymentId: deploymentId,
1389
+ parseOutput: false
1390
+ });
1391
+ const status = response['status'];
1392
+ if (status === 'ready') {
1393
+ successfullyDeployed++;
1394
+ let url = '';
1395
+ const res = await (0, proxy_1.proxyListRules)({
1396
+ parseOutput: false,
1397
+ queries: [
1398
+ JSON.stringify({ method: 'limit', values: [1] }),
1399
+ JSON.stringify({ method: 'equal', "attribute": "deploymentResourceType", "values": ["function"] }),
1400
+ JSON.stringify({ method: 'equal', "attribute": "deploymentResourceId", "values": [func['$id']] }),
1401
+ JSON.stringify({ method: 'equal', "attribute": "trigger", "values": ["manual"] }),
1402
+ ],
1403
+ });
1404
+ if (Number(res.total) === 1) {
1405
+ url = res.rules[0].domain;
1406
+ }
1407
+ updaterRow.update({ status: 'Deployed', end: url });
1408
+ break;
1409
+ }
1410
+ else if (status === 'failed') {
1411
+ failedDeployments.push({ name: func['name'], $id: func['$id'], deployment: response['$id'] });
1412
+ updaterRow.fail({ errorMessage: `Failed to deploy` });
1413
+ break;
1414
+ }
1415
+ else {
1416
+ updaterRow.update({ status: 'Deploying', end: `Current status: ${status}` });
1417
+ }
1418
+ pollChecks++;
1419
+ await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE * 1.5));
1420
+ }
1421
+ }
1422
+ catch (e) {
1423
+ errors.push(e);
1424
+ updaterRow.fail({ errorMessage: e.message ?? 'Unknown error occurred. Please try again' });
1425
+ }
1426
+ }
1427
+ updaterRow.stopSpinner();
1428
+ }));
1429
+ spinner_1.Spinner.stop();
1430
+ failedDeployments.forEach((failed) => {
1431
+ const { name, deployment, $id } = failed;
1432
+ const failUrl = `${config_1.globalConfig.getEndpoint().slice(0, -3)}/console/project-${config_1.localConfig.getProject().projectId}/functions/function-${$id}/deployment-${deployment}`;
1433
+ (0, parser_1.error)(`Deployment of ${name} has failed. Check at ${failUrl} for more details\n`);
1434
+ });
1435
+ if (!asyncDeploy) {
1436
+ if (successfullyPushed === 0) {
1437
+ (0, parser_1.error)('No functions were pushed.');
1438
+ }
1439
+ else if (successfullyDeployed !== successfullyPushed) {
1440
+ (0, parser_1.warn)(`Successfully pushed ${successfullyDeployed} of ${successfullyPushed} functions`);
1441
+ }
1442
+ else {
1443
+ (0, parser_1.success)(`Successfully pushed ${successfullyPushed} functions.`);
1444
+ }
1445
+ }
1446
+ else {
1447
+ (0, parser_1.success)(`Successfully pushed ${successfullyPushed} functions.`);
1448
+ }
1449
+ if (parser_1.cliConfig.verbose) {
1450
+ errors.forEach(e => {
1451
+ console.error(e);
1452
+ });
1453
+ }
1454
+ };
1455
+ const checkAndApplyTablesDBChanges = async () => {
1456
+ (0, parser_1.log)('Checking for tablesDB changes ...');
1457
+ const localTablesDBs = config_1.localConfig.getTablesDBs();
1458
+ const { databases: remoteTablesDBs } = await (0, paginate_1.paginate)(tables_db_1.tablesDBList, { parseOutput: false }, 100, 'databases');
1459
+ if (localTablesDBs.length === 0 && remoteTablesDBs.length === 0) {
1460
+ return { applied: false, resyncNeeded: false };
1461
+ }
1462
+ const changes = [];
1463
+ const toCreate = [];
1464
+ const toUpdate = [];
1465
+ const toDelete = [];
1466
+ // Check for deletions - remote DBs that aren't in local config
1467
+ for (const remoteDB of remoteTablesDBs) {
1468
+ const localDB = localTablesDBs.find((db) => db.$id === remoteDB.$id);
1469
+ if (!localDB) {
1470
+ toDelete.push(remoteDB);
1471
+ changes.push({
1472
+ id: remoteDB.$id,
1473
+ action: chalk_1.default.red('deleting'),
1474
+ key: 'Database',
1475
+ remote: remoteDB.name,
1476
+ local: '(deleted locally)'
1477
+ });
1478
+ }
1479
+ }
1480
+ // Check for additions and updates
1481
+ for (const localDB of localTablesDBs) {
1482
+ const remoteDB = remoteTablesDBs.find((db) => db.$id === localDB.$id);
1483
+ if (!remoteDB) {
1484
+ toCreate.push(localDB);
1485
+ changes.push({
1486
+ id: localDB.$id,
1487
+ action: chalk_1.default.green('creating'),
1488
+ key: 'Database',
1489
+ remote: '(does not exist)',
1490
+ local: localDB.name
1491
+ });
1492
+ }
1493
+ else {
1494
+ let hasChanges = false;
1495
+ if (remoteDB.name !== localDB.name) {
1496
+ hasChanges = true;
1497
+ changes.push({
1498
+ id: localDB.$id,
1499
+ action: chalk_1.default.yellow('updating'),
1500
+ key: 'Name',
1501
+ remote: remoteDB.name,
1502
+ local: localDB.name
1503
+ });
1504
+ }
1505
+ if (remoteDB.enabled !== localDB.enabled) {
1506
+ hasChanges = true;
1507
+ changes.push({
1508
+ id: localDB.$id,
1509
+ action: chalk_1.default.yellow('updating'),
1510
+ key: 'Enabled',
1511
+ remote: remoteDB.enabled,
1512
+ local: localDB.enabled
1513
+ });
1514
+ }
1515
+ if (hasChanges) {
1516
+ toUpdate.push(localDB);
1517
+ }
1518
+ }
1519
+ }
1520
+ if (changes.length === 0) {
1521
+ console.log('No changes found in tablesDB resource');
1522
+ console.log();
1523
+ return { applied: false, resyncNeeded: false };
1524
+ }
1525
+ (0, parser_1.log)('Found changes in tablesDB resource:');
1526
+ (0, parser_1.drawTable)(changes);
1527
+ if (toDelete.length > 0) {
1528
+ console.log(`${chalk_1.default.red('------------------------------------------------------------------')}`);
1529
+ console.log(`${chalk_1.default.red('| WARNING: Database deletion will also delete all related tables |')}`);
1530
+ console.log(`${chalk_1.default.red('------------------------------------------------------------------')}`);
1531
+ console.log();
1532
+ }
1533
+ if ((await getConfirmation()) !== true) {
1534
+ return { applied: false, resyncNeeded: false };
1535
+ }
1536
+ // Apply deletions first
1537
+ let needsResync = false;
1538
+ for (const db of toDelete) {
1539
+ try {
1540
+ (0, parser_1.log)(`Deleting database ${db.name} ( ${db.$id} ) ...`);
1541
+ await (0, tables_db_1.tablesDBDelete)({
1542
+ databaseId: db.$id,
1543
+ parseOutput: false
1544
+ });
1545
+ (0, parser_1.success)(`Deleted ${db.name} ( ${db.$id} )`);
1546
+ needsResync = true;
1547
+ }
1548
+ catch (e) {
1549
+ (0, parser_1.error)(`Failed to delete database ${db.name} ( ${db.$id} ): ${e.message}`);
1550
+ throw new Error(`Database sync failed during deletion of ${db.$id}. Some changes may have been applied.`);
1551
+ }
1552
+ }
1553
+ // Apply creations
1554
+ for (const db of toCreate) {
1555
+ try {
1556
+ (0, parser_1.log)(`Creating database ${db.name} ( ${db.$id} ) ...`);
1557
+ await (0, tables_db_1.tablesDBCreate)({
1558
+ databaseId: db.$id,
1559
+ name: db.name,
1560
+ enabled: db.enabled,
1561
+ parseOutput: false
1562
+ });
1563
+ (0, parser_1.success)(`Created ${db.name} ( ${db.$id} )`);
1564
+ }
1565
+ catch (e) {
1566
+ (0, parser_1.error)(`Failed to create database ${db.name} ( ${db.$id} ): ${e.message}`);
1567
+ throw new Error(`Database sync failed during creation of ${db.$id}. Some changes may have been applied.`);
1568
+ }
1569
+ }
1570
+ // Apply updates
1571
+ for (const db of toUpdate) {
1572
+ try {
1573
+ (0, parser_1.log)(`Updating database ${db.name} ( ${db.$id} ) ...`);
1574
+ await (0, tables_db_1.tablesDBUpdate)({
1575
+ databaseId: db.$id,
1576
+ name: db.name,
1577
+ enabled: db.enabled,
1578
+ parseOutput: false
1579
+ });
1580
+ (0, parser_1.success)(`Updated ${db.name} ( ${db.$id} )`);
1581
+ }
1582
+ catch (e) {
1583
+ (0, parser_1.error)(`Failed to update database ${db.name} ( ${db.$id} ): ${e.message}`);
1584
+ throw new Error(`Database sync failed during update of ${db.$id}. Some changes may have been applied.`);
1585
+ }
1586
+ }
1587
+ if (toDelete.length === 0) {
1588
+ console.log();
1589
+ }
1590
+ return { applied: true, resyncNeeded: needsResync };
1591
+ };
1592
+ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) => {
1593
+ const tables = [];
1594
+ if (attempts) {
1595
+ pollMaxDebounces = attempts;
1596
+ }
1597
+ const { applied: tablesDBApplied, resyncNeeded } = await checkAndApplyTablesDBChanges();
1598
+ if (resyncNeeded) {
1599
+ (0, parser_1.log)('Resyncing configuration due to tablesDB deletions ...');
1600
+ const remoteTablesDBs = (await (0, paginate_1.paginate)(tables_db_1.tablesDBList, { parseOutput: false }, 100, 'databases')).databases;
1601
+ const localTablesDBs = config_1.localConfig.getTablesDBs();
1602
+ const remoteDatabaseIds = new Set(remoteTablesDBs.map((db) => db.$id));
1603
+ const localTables = config_1.localConfig.getTables();
1604
+ const validTables = localTables.filter((table) => remoteDatabaseIds.has(table.databaseId));
1605
+ config_1.localConfig.set('tables', validTables);
1606
+ const validTablesDBs = localTablesDBs.filter((db) => remoteDatabaseIds.has(db.$id));
1607
+ config_1.localConfig.set('tablesDB', validTablesDBs);
1608
+ (0, parser_1.success)('Configuration resynced successfully.');
1609
+ console.log();
1610
+ }
1611
+ (0, parser_1.log)('Checking for deleted tables ...');
1612
+ const localTablesDBs = config_1.localConfig.getTablesDBs();
1613
+ const localTables = config_1.localConfig.getTables();
1614
+ const tablesToDelete = [];
1615
+ for (const db of localTablesDBs) {
1616
+ try {
1617
+ const { tables: remoteTables } = await (0, paginate_1.paginate)(tables_db_1.tablesDBListTables, {
1618
+ databaseId: db.$id,
1619
+ parseOutput: false
1620
+ }, 100, 'tables');
1621
+ for (const remoteTable of remoteTables) {
1622
+ const localTable = localTables.find((t) => t.$id === remoteTable.$id && t.databaseId === db.$id);
1623
+ if (!localTable) {
1624
+ tablesToDelete.push({
1625
+ ...remoteTable,
1626
+ databaseId: db.$id,
1627
+ databaseName: db.name
1628
+ });
1629
+ }
1630
+ }
1631
+ }
1632
+ catch (e) {
1633
+ // Skip if database doesn't exist or other errors
1634
+ }
1635
+ }
1636
+ if (tablesToDelete.length > 0) {
1637
+ (0, parser_1.log)('Found tables that exist remotely but not locally:');
1638
+ const deletionChanges = tablesToDelete.map((table) => ({
1639
+ id: table.$id,
1640
+ action: chalk_1.default.red('deleting'),
1641
+ key: 'Table',
1642
+ database: table.databaseName,
1643
+ remote: table.name,
1644
+ local: '(deleted locally)'
1645
+ }));
1646
+ (0, parser_1.drawTable)(deletionChanges);
1647
+ if ((await getConfirmation()) === true) {
1648
+ for (const table of tablesToDelete) {
1649
+ try {
1650
+ (0, parser_1.log)(`Deleting table ${table.name} ( ${table.$id} ) from database ${table.databaseName} ...`);
1651
+ await (0, tables_db_1.tablesDBDeleteTable)({
1652
+ databaseId: table.databaseId,
1653
+ tableId: table.$id,
1654
+ parseOutput: false
1655
+ });
1656
+ (0, parser_1.success)(`Deleted ${table.name} ( ${table.$id} )`);
1657
+ }
1658
+ catch (e) {
1659
+ (0, parser_1.error)(`Failed to delete table ${table.name} ( ${table.$id} ): ${e.message}`);
1660
+ }
1661
+ }
1662
+ }
1663
+ }
1664
+ else {
1665
+ console.log('No tables found to delete');
1666
+ }
1667
+ console.log();
1668
+ if (parser_1.cliConfig.all) {
1669
+ (0, utils_1.checkDeployConditions)(config_1.localConfig);
1670
+ tables.push(...config_1.localConfig.getTables());
1671
+ }
1672
+ else {
1673
+ const answers = await inquirer_1.default.prompt(questions_1.questionsPushTables);
1674
+ if (answers.tables) {
1675
+ const configTables = new Map();
1676
+ config_1.localConfig.getTables().forEach((c) => {
1677
+ configTables.set(`${c['databaseId']}|${c['$id']}`, c);
1678
+ });
1679
+ answers.tables.forEach((a) => {
1680
+ const table = configTables.get(a);
1681
+ tables.push(table);
1682
+ });
1683
+ }
1684
+ }
1685
+ if (tables.length === 0) {
1686
+ (0, parser_1.log)("No tables found.");
1687
+ (0, parser_1.hint)("Use 'appwrite pull tables' to synchronize existing one, or use 'appwrite init table' to create a new one.");
1688
+ return;
1689
+ }
1690
+ if (!(await approveChanges(tables, tables_db_1.tablesDBGetTable, config_1.KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId'))) {
1691
+ return;
1692
+ }
1693
+ let tablesChanged = new Set();
1694
+ // Parallel tables actions
1695
+ await Promise.all(tables.map(async (table) => {
1696
+ try {
1697
+ const remoteTable = await (0, tables_db_1.tablesDBGetTable)({
1698
+ databaseId: table['databaseId'],
1699
+ tableId: table['$id'],
1700
+ parseOutput: false,
1701
+ });
1702
+ const changes = [];
1703
+ if (remoteTable.name !== table.name)
1704
+ changes.push('name');
1705
+ if (remoteTable.rowSecurity !== table.rowSecurity)
1706
+ changes.push('rowSecurity');
1707
+ if (remoteTable.enabled !== table.enabled)
1708
+ changes.push('enabled');
1709
+ if (JSON.stringify(remoteTable['$permissions']) !== JSON.stringify(table['$permissions']))
1710
+ changes.push('permissions');
1711
+ if (changes.length > 0) {
1712
+ await (0, tables_db_1.tablesDBUpdateTable)({
1713
+ databaseId: table['databaseId'],
1714
+ tableId: table['$id'],
1715
+ name: table.name,
1716
+ parseOutput: false,
1717
+ rowSecurity: table.rowSecurity,
1718
+ permissions: table['$permissions']
1719
+ });
1720
+ (0, parser_1.success)(`Updated ${table.name} ( ${table['$id']} ) - ${changes.join(', ')}`);
1721
+ tablesChanged.add(table['$id']);
1722
+ }
1723
+ table.remoteVersion = remoteTable;
1724
+ table.isExisted = true;
1725
+ }
1726
+ catch (e) {
1727
+ if (Number(e.code) === 404) {
1728
+ (0, parser_1.log)(`Table ${table.name} does not exist in the project. Creating ... `);
1729
+ await (0, tables_db_1.tablesDBCreateTable)({
1730
+ databaseId: table['databaseId'],
1731
+ tableId: table['$id'],
1732
+ name: table.name,
1733
+ rowSecurity: table.rowSecurity,
1734
+ permissions: table['$permissions'],
1735
+ parseOutput: false
1736
+ });
1737
+ (0, parser_1.success)(`Created ${table.name} ( ${table['$id']} )`);
1738
+ tablesChanged.add(table['$id']);
1739
+ }
1740
+ else {
1741
+ throw e;
1742
+ }
1743
+ }
1744
+ }));
1745
+ // Serialize attribute actions
1746
+ for (let table of tables) {
1747
+ let columns = table.columns;
1748
+ let indexes = table.indexes;
1749
+ if (table.isExisted) {
1750
+ columns = await attributesToCreate(table.remoteVersion.columns, table.columns, table);
1751
+ indexes = await attributesToCreate(table.remoteVersion.indexes, table.indexes, table, true);
1752
+ if ((Array.isArray(columns) && columns.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) {
1753
+ continue;
1754
+ }
1755
+ }
1756
+ (0, parser_1.log)(`Pushing table ${table.name} ( ${table['databaseId']} - ${table['$id']} ) attributes`);
1757
+ try {
1758
+ await createColumns(columns, table);
1759
+ }
1760
+ catch (e) {
1761
+ throw e;
1762
+ }
1763
+ try {
1764
+ await createIndexes(indexes, table);
1765
+ }
1766
+ catch (e) {
1767
+ throw e;
1768
+ }
1769
+ tablesChanged.add(table['$id']);
1770
+ (0, parser_1.success)(`Successfully pushed ${table.name} ( ${table['$id']} )`);
1771
+ }
1772
+ (0, parser_1.success)(`Successfully pushed ${tablesChanged.size} tables`);
1773
+ };
1774
+ const pushCollection = async ({ returnOnZero, attempts } = { returnOnZero: false }) => {
1775
+ (0, parser_1.warn)("appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead");
1776
+ const collections = [];
1777
+ if (attempts) {
1778
+ pollMaxDebounces = attempts;
1779
+ }
1780
+ if (parser_1.cliConfig.all) {
1781
+ (0, utils_1.checkDeployConditions)(config_1.localConfig);
1782
+ collections.push(...config_1.localConfig.getCollections());
1783
+ }
1784
+ else {
1785
+ const answers = await inquirer_1.default.prompt(questions_1.questionsPushCollections);
1786
+ if (answers.collections) {
1787
+ const configCollections = new Map();
1788
+ config_1.localConfig.getCollections().forEach((c) => {
1789
+ configCollections.set(`${c['databaseId']}|${c['$id']}`, c);
1790
+ });
1791
+ answers.collections.forEach((a) => {
1792
+ const collection = configCollections.get(a);
1793
+ collections.push(collection);
1794
+ });
1795
+ }
1796
+ }
1797
+ if (collections.length === 0) {
1798
+ (0, parser_1.log)("No collections found.");
1799
+ (0, parser_1.hint)("Use 'appwrite pull collections' to synchronize existing one, or use 'appwrite init collection' to create a new one.");
1800
+ return;
1801
+ }
1802
+ const databases = Array.from(new Set(collections.map((collection) => collection['databaseId'])));
1803
+ // Parallel db actions
1804
+ await Promise.all(databases.map(async (databaseId) => {
1805
+ const localDatabase = config_1.localConfig.getDatabase(databaseId);
1806
+ try {
1807
+ const database = await (0, databases_1.databasesGet)({
1808
+ databaseId: databaseId,
1809
+ parseOutput: false,
1810
+ });
1811
+ if (database.name !== (localDatabase.name ?? databaseId)) {
1812
+ await (0, databases_1.databasesUpdate)({
1813
+ databaseId: databaseId,
1814
+ name: localDatabase.name ?? databaseId,
1815
+ parseOutput: false
1816
+ });
1817
+ (0, parser_1.success)(`Updated ${localDatabase.name} ( ${databaseId} ) name`);
1818
+ }
1819
+ }
1820
+ catch (err) {
1821
+ (0, parser_1.log)(`Database ${databaseId} not found. Creating it now ...`);
1822
+ await (0, databases_1.databasesCreate)({
1823
+ databaseId: databaseId,
1824
+ name: localDatabase.name ?? databaseId,
1825
+ parseOutput: false,
1826
+ });
1827
+ }
1828
+ }));
1829
+ if (!(await approveChanges(collections, databases_1.databasesGetCollection, config_1.KeysCollection, 'collectionId', 'collections', ['attributes', 'indexes'], 'databaseId', 'databaseId'))) {
1830
+ return;
1831
+ }
1832
+ // Parallel collection actions
1833
+ await Promise.all(collections.map(async (collection) => {
1834
+ try {
1835
+ const remoteCollection = await (0, databases_1.databasesGetCollection)({
1836
+ databaseId: collection['databaseId'],
1837
+ collectionId: collection['$id'],
1838
+ parseOutput: false,
1839
+ });
1840
+ if (remoteCollection.name !== collection.name) {
1841
+ await (0, databases_1.databasesUpdateCollection)({
1842
+ databaseId: collection['databaseId'],
1843
+ collectionId: collection['$id'],
1844
+ name: collection.name,
1845
+ parseOutput: false
1846
+ });
1847
+ (0, parser_1.success)(`Updated ${collection.name} ( ${collection['$id']} ) name`);
1848
+ }
1849
+ collection.remoteVersion = remoteCollection;
1850
+ collection.isExisted = true;
1851
+ }
1852
+ catch (e) {
1853
+ if (Number(e.code) === 404) {
1854
+ (0, parser_1.log)(`Collection ${collection.name} does not exist in the project. Creating ... `);
1855
+ await (0, databases_1.databasesCreateCollection)({
1856
+ databaseId: collection['databaseId'],
1857
+ collectionId: collection['$id'],
1858
+ name: collection.name,
1859
+ documentSecurity: collection.documentSecurity,
1860
+ permissions: collection['$permissions'],
1861
+ parseOutput: false
1862
+ });
1863
+ }
1864
+ else {
1865
+ throw e;
1866
+ }
1867
+ }
1868
+ }));
1869
+ let numberOfCollections = 0;
1870
+ // Serialize attribute actions
1871
+ for (let collection of collections) {
1872
+ let attributes = collection.attributes;
1873
+ let indexes = collection.indexes;
1874
+ if (collection.isExisted) {
1875
+ attributes = await attributesToCreate(collection.remoteVersion.attributes, collection.attributes, collection);
1876
+ indexes = await attributesToCreate(collection.remoteVersion.indexes, collection.indexes, collection, true);
1877
+ if ((Array.isArray(attributes) && attributes.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) {
1878
+ continue;
1879
+ }
1880
+ }
1881
+ (0, parser_1.log)(`Pushing collection ${collection.name} ( ${collection['databaseId']} - ${collection['$id']} ) attributes`);
1882
+ try {
1883
+ await createAttributes(attributes, collection);
1884
+ }
1885
+ catch (e) {
1886
+ throw e;
1887
+ }
1888
+ try {
1889
+ await createIndexes(indexes, collection);
1890
+ }
1891
+ catch (e) {
1892
+ throw e;
1893
+ }
1894
+ numberOfCollections++;
1895
+ (0, parser_1.success)(`Successfully pushed ${collection.name} ( ${collection['$id']} )`);
1896
+ }
1897
+ (0, parser_1.success)(`Successfully pushed ${numberOfCollections} collections`);
1898
+ };
1899
+ const pushBucket = async ({ returnOnZero } = { returnOnZero: false }) => {
1900
+ let response = {};
1901
+ let bucketIds = [];
1902
+ const configBuckets = config_1.localConfig.getBuckets();
1903
+ if (parser_1.cliConfig.all) {
1904
+ (0, utils_1.checkDeployConditions)(config_1.localConfig);
1905
+ bucketIds.push(...configBuckets.map((b) => b.$id));
1906
+ }
1907
+ if (bucketIds.length === 0) {
1908
+ const answers = await inquirer_1.default.prompt(questions_1.questionsPushBuckets[0]);
1909
+ if (answers.buckets) {
1910
+ bucketIds.push(...answers.buckets);
1911
+ }
1912
+ }
1913
+ if (bucketIds.length === 0) {
1914
+ (0, parser_1.log)("No buckets found.");
1915
+ (0, parser_1.hint)("Use 'appwrite pull buckets' to synchronize existing one, or use 'appwrite init bucket' to create a new one.");
1916
+ return;
1917
+ }
1918
+ let buckets = [];
1919
+ for (const bucketId of bucketIds) {
1920
+ const idBuckets = configBuckets.filter((b) => b.$id === bucketId);
1921
+ buckets.push(...idBuckets);
1922
+ }
1923
+ if (!(await approveChanges(buckets, storage_1.storageGetBucket, config_1.KeysStorage, 'bucketId', 'buckets'))) {
1924
+ return;
1925
+ }
1926
+ (0, parser_1.log)('Pushing buckets ...');
1927
+ for (let bucket of buckets) {
1928
+ (0, parser_1.log)(`Pushing bucket ${chalk_1.default.bold(bucket['name'])} ...`);
1929
+ try {
1930
+ response = await (0, storage_1.storageGetBucket)({
1931
+ bucketId: bucket['$id'],
1932
+ parseOutput: false,
1933
+ });
1934
+ await (0, storage_1.storageUpdateBucket)({
1935
+ bucketId: bucket['$id'],
1936
+ name: bucket.name,
1937
+ permissions: bucket['$permissions'],
1938
+ fileSecurity: bucket.fileSecurity,
1939
+ enabled: bucket.enabled,
1940
+ maximumFileSize: bucket.maximumFileSize,
1941
+ allowedFileExtensions: bucket.allowedFileExtensions,
1942
+ encryption: bucket.encryption,
1943
+ antivirus: bucket.antivirus,
1944
+ compression: bucket.compression,
1945
+ parseOutput: false
1946
+ });
1947
+ }
1948
+ catch (e) {
1949
+ if (Number(e.code) === 404) {
1950
+ (0, parser_1.log)(`Bucket ${bucket.name} does not exist in the project. Creating ... `);
1951
+ response = await (0, storage_1.storageCreateBucket)({
1952
+ bucketId: bucket['$id'],
1953
+ name: bucket.name,
1954
+ permissions: bucket['$permissions'],
1955
+ fileSecurity: bucket.fileSecurity,
1956
+ enabled: bucket.enabled,
1957
+ maximumFileSize: bucket.maximumFileSize,
1958
+ allowedFileExtensions: bucket.allowedFileExtensions,
1959
+ compression: bucket.compression,
1960
+ encryption: bucket.encryption,
1961
+ antivirus: bucket.antivirus,
1962
+ parseOutput: false
1963
+ });
1964
+ }
1965
+ else {
1966
+ throw e;
1967
+ }
1968
+ }
1969
+ }
1970
+ (0, parser_1.success)(`Successfully pushed ${buckets.length} buckets.`);
1971
+ };
1972
+ const pushTeam = async ({ returnOnZero } = { returnOnZero: false }) => {
1973
+ let response = {};
1974
+ let teamIds = [];
1975
+ const configTeams = config_1.localConfig.getTeams();
1976
+ if (parser_1.cliConfig.all) {
1977
+ (0, utils_1.checkDeployConditions)(config_1.localConfig);
1978
+ teamIds.push(...configTeams.map((t) => t.$id));
1979
+ }
1980
+ if (teamIds.length === 0) {
1981
+ const answers = await inquirer_1.default.prompt(questions_1.questionsPushTeams[0]);
1982
+ if (answers.teams) {
1983
+ teamIds.push(...answers.teams);
1984
+ }
1985
+ }
1986
+ if (teamIds.length === 0) {
1987
+ (0, parser_1.log)("No teams found.");
1988
+ (0, parser_1.hint)("Use 'appwrite pull teams' to synchronize existing one, or use 'appwrite init team' to create a new one.");
1989
+ return;
1990
+ }
1991
+ let teams = [];
1992
+ for (const teamId of teamIds) {
1993
+ const idTeams = configTeams.filter((t) => t.$id === teamId);
1994
+ teams.push(...idTeams);
1995
+ }
1996
+ if (!(await approveChanges(teams, teams_1.teamsGet, config_1.KeysTeams, 'teamId', 'teams'))) {
1997
+ return;
1998
+ }
1999
+ (0, parser_1.log)('Pushing teams ...');
2000
+ for (let team of teams) {
2001
+ (0, parser_1.log)(`Pushing team ${chalk_1.default.bold(team['name'])} ...`);
2002
+ try {
2003
+ response = await (0, teams_1.teamsGet)({
2004
+ teamId: team['$id'],
2005
+ parseOutput: false,
2006
+ });
2007
+ await (0, teams_1.teamsUpdateName)({
2008
+ teamId: team['$id'],
2009
+ name: team.name,
2010
+ parseOutput: false
2011
+ });
2012
+ }
2013
+ catch (e) {
2014
+ if (Number(e.code) === 404) {
2015
+ (0, parser_1.log)(`Team ${team.name} does not exist in the project. Creating ... `);
2016
+ response = await (0, teams_1.teamsCreate)({
2017
+ teamId: team['$id'],
2018
+ name: team.name,
2019
+ parseOutput: false
2020
+ });
2021
+ }
2022
+ else {
2023
+ throw e;
2024
+ }
2025
+ }
2026
+ }
2027
+ (0, parser_1.success)(`Successfully pushed ${teams.length} teams.`);
2028
+ };
2029
+ const pushMessagingTopic = async ({ returnOnZero } = { returnOnZero: false }) => {
2030
+ let response = {};
2031
+ let topicsIds = [];
2032
+ const configTopics = config_1.localConfig.getMessagingTopics();
2033
+ if (parser_1.cliConfig.all) {
2034
+ (0, utils_1.checkDeployConditions)(config_1.localConfig);
2035
+ topicsIds.push(...configTopics.map((b) => b.$id));
2036
+ }
2037
+ if (topicsIds.length === 0) {
2038
+ const answers = await inquirer_1.default.prompt(questions_1.questionsPushMessagingTopics[0]);
2039
+ if (answers.topics) {
2040
+ topicsIds.push(...answers.topics);
2041
+ }
2042
+ }
2043
+ if (topicsIds.length === 0) {
2044
+ (0, parser_1.log)("No topics found.");
2045
+ (0, parser_1.hint)("Use 'appwrite pull topics' to synchronize existing one, or use 'appwrite init topic' to create a new one.");
2046
+ return;
2047
+ }
2048
+ let topics = [];
2049
+ for (const topicId of topicsIds) {
2050
+ const idTopic = configTopics.filter((b) => b.$id === topicId);
2051
+ topics.push(...idTopic);
2052
+ }
2053
+ if (!(await approveChanges(topics, messaging_1.messagingGetTopic, config_1.KeysTopics, 'topicId', 'topics'))) {
2054
+ return;
2055
+ }
2056
+ (0, parser_1.log)('Pushing topics ...');
2057
+ for (let topic of topics) {
2058
+ (0, parser_1.log)(`Pushing topic ${chalk_1.default.bold(topic['name'])} ...`);
2059
+ try {
2060
+ response = await (0, messaging_1.messagingGetTopic)({
2061
+ topicId: topic['$id'],
2062
+ parseOutput: false
2063
+ });
2064
+ (0, parser_1.log)(`Topic ${topic.name} ( ${topic['$id']} ) already exists.`);
2065
+ await (0, messaging_1.messagingUpdateTopic)({
2066
+ topicId: topic['$id'],
2067
+ name: topic.name,
2068
+ subscribe: topic.subscribe,
2069
+ parseOutput: false
2070
+ });
2071
+ }
2072
+ catch (e) {
2073
+ if (Number(e.code) === 404) {
2074
+ (0, parser_1.log)(`Topic ${topic.name} does not exist in the project. Creating ... `);
2075
+ response = await (0, messaging_1.messagingCreateTopic)({
2076
+ topicId: topic['$id'],
2077
+ name: topic.name,
2078
+ subscribe: topic.subscribe,
2079
+ parseOutput: false
2080
+ });
2081
+ (0, parser_1.success)(`Created ${topic.name} ( ${topic['$id']} )`);
2082
+ }
2083
+ else {
2084
+ throw e;
2085
+ }
2086
+ }
2087
+ }
2088
+ (0, parser_1.success)(`Successfully pushed ${topics.length} topics.`);
2089
+ };
2090
+ exports.push = new commander_1.Command("push")
2091
+ .description(parser_1.commandDescriptions['push'])
2092
+ .action((0, parser_1.actionRunner)(pushResources));
2093
+ exports.push
2094
+ .command("all")
2095
+ .description("Push all resource.")
2096
+ .action((0, parser_1.actionRunner)(() => {
2097
+ parser_1.cliConfig.all = true;
2098
+ return pushResources();
2099
+ }));
2100
+ exports.push
2101
+ .command("settings")
2102
+ .description("Push project name, services and auth settings")
2103
+ .action((0, parser_1.actionRunner)(pushSettings));
2104
+ exports.push
2105
+ .command("function")
2106
+ .alias("functions")
2107
+ .description("Push functions in the current directory.")
2108
+ .option(`-f, --function-id <function-id>`, `ID of function to run`)
2109
+ .option(`-A, --async`, `Don't wait for functions deployments status`)
2110
+ .option("--no-code", "Don't push the function's code")
2111
+ .option("--with-variables", `Push function variables.`)
2112
+ .action((0, parser_1.actionRunner)(pushFunction));
2113
+ exports.push
2114
+ .command("site")
2115
+ .alias("sites")
2116
+ .description("Push sites in the current directory.")
2117
+ .option(`-f, --site-id <site-id>`, `ID of site to run`)
2118
+ .option(`-A, --async`, `Don't wait for sites deployments status`)
2119
+ .option("--no-code", "Don't push the site's code")
2120
+ .option("--with-variables", `Push site variables.`)
2121
+ .action((0, parser_1.actionRunner)(pushSite));
2122
+ exports.push
2123
+ .command("collection")
2124
+ .alias("collections")
2125
+ .description("Push collections in the current project. (deprecated, please use 'push tables' instead)")
2126
+ .option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`)
2127
+ .action((0, parser_1.actionRunner)(pushCollection));
2128
+ exports.push
2129
+ .command("table")
2130
+ .alias("tables")
2131
+ .description("Push tables in the current project.")
2132
+ .option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`)
2133
+ .action((0, parser_1.actionRunner)(pushTable));
2134
+ exports.push
2135
+ .command("bucket")
2136
+ .alias("buckets")
2137
+ .description("Push buckets in the current project.")
2138
+ .action((0, parser_1.actionRunner)(pushBucket));
2139
+ exports.push
2140
+ .command("team")
2141
+ .alias("teams")
2142
+ .description("Push teams in the current project.")
2143
+ .action((0, parser_1.actionRunner)(pushTeam));
2144
+ exports.push
2145
+ .command("topic")
2146
+ .alias("topics")
2147
+ .description("Push messaging topics in the current project.")
2148
+ .action((0, parser_1.actionRunner)(pushMessagingTopic));
2149
+ exports.deploy = new commander_1.Command("deploy")
2150
+ .description('Removed. Use appwrite push instead')
2151
+ .action((0, parser_1.actionRunner)(async () => {
2152
+ (0, parser_1.warn)("appwrite deploy has been removed. Please use 'appwrite push' instead");
2153
+ }));
2154
+ //# sourceMappingURL=push.js.map