appwrite-cli 13.0.0-rc.2 → 13.0.0-rc.3

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 (718) hide show
  1. package/.github/workflows/{npm-publish.yml → publish.yml} +1 -1
  2. package/CHANGELOG.md +106 -101
  3. package/LICENSE.md +2 -2
  4. package/README.md +36 -59
  5. package/cli.ts +152 -0
  6. package/dist/bundle.cjs +4613 -3653
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +145 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/index.d.ts +10 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +7 -142
  14. package/dist/index.js.map +1 -1
  15. package/dist/lib/client.d.ts.map +1 -1
  16. package/dist/lib/client.js +7 -6
  17. package/dist/lib/client.js.map +1 -1
  18. package/dist/lib/commands/config.d.ts +562 -0
  19. package/dist/lib/commands/config.d.ts.map +1 -0
  20. package/dist/lib/commands/config.js +416 -0
  21. package/dist/lib/commands/config.js.map +1 -0
  22. package/dist/lib/commands/db.d.ts +34 -0
  23. package/dist/lib/commands/db.d.ts.map +1 -0
  24. package/dist/lib/commands/db.js +247 -0
  25. package/dist/lib/commands/db.js.map +1 -0
  26. package/dist/lib/commands/errors.d.ts +68 -0
  27. package/dist/lib/commands/errors.d.ts.map +1 -0
  28. package/dist/lib/commands/errors.js +72 -0
  29. package/dist/lib/commands/errors.js.map +1 -0
  30. package/dist/lib/commands/init.d.ts.map +1 -1
  31. package/dist/lib/commands/init.js +15 -14
  32. package/dist/lib/commands/init.js.map +1 -1
  33. package/dist/lib/commands/pull.d.ts +104 -2
  34. package/dist/lib/commands/pull.d.ts.map +1 -1
  35. package/dist/lib/commands/pull.js +470 -281
  36. package/dist/lib/commands/pull.js.map +1 -1
  37. package/dist/lib/commands/push.d.ts +106 -0
  38. package/dist/lib/commands/push.d.ts.map +1 -1
  39. package/dist/lib/commands/push.js +1257 -1628
  40. package/dist/lib/commands/push.js.map +1 -1
  41. package/dist/lib/commands/run.js +1 -1
  42. package/dist/lib/commands/run.js.map +1 -1
  43. package/dist/lib/commands/schema.d.ts +59 -0
  44. package/dist/lib/commands/schema.d.ts.map +1 -0
  45. package/dist/lib/commands/schema.js +86 -0
  46. package/dist/lib/commands/schema.js.map +1 -0
  47. package/dist/lib/commands/services/account.d.ts.map +1 -1
  48. package/dist/lib/commands/services/account.js +86 -64
  49. package/dist/lib/commands/services/account.js.map +1 -1
  50. package/dist/lib/commands/services/console.d.ts.map +1 -1
  51. package/dist/lib/commands/services/console.js +4 -17
  52. package/dist/lib/commands/services/console.js.map +1 -1
  53. package/dist/lib/commands/services/databases.d.ts.map +1 -1
  54. package/dist/lib/commands/services/databases.js +160 -152
  55. package/dist/lib/commands/services/databases.js.map +1 -1
  56. package/dist/lib/commands/services/functions.d.ts.map +1 -1
  57. package/dist/lib/commands/services/functions.js +41 -33
  58. package/dist/lib/commands/services/functions.js.map +1 -1
  59. package/dist/lib/commands/services/graphql.d.ts.map +1 -1
  60. package/dist/lib/commands/services/graphql.js +3 -3
  61. package/dist/lib/commands/services/graphql.js.map +1 -1
  62. package/dist/lib/commands/services/health.d.ts.map +1 -1
  63. package/dist/lib/commands/services/health.js +24 -24
  64. package/dist/lib/commands/services/health.js.map +1 -1
  65. package/dist/lib/commands/services/locale.d.ts.map +1 -1
  66. package/dist/lib/commands/services/locale.js +9 -9
  67. package/dist/lib/commands/services/locale.js.map +1 -1
  68. package/dist/lib/commands/services/messaging.d.ts.map +1 -1
  69. package/dist/lib/commands/services/messaging.js +59 -59
  70. package/dist/lib/commands/services/messaging.js.map +1 -1
  71. package/dist/lib/commands/services/migrations.d.ts.map +1 -1
  72. package/dist/lib/commands/services/migrations.js +19 -19
  73. package/dist/lib/commands/services/migrations.js.map +1 -1
  74. package/dist/lib/commands/services/project.d.ts.map +1 -1
  75. package/dist/lib/commands/services/project.js +8 -8
  76. package/dist/lib/commands/services/project.js.map +1 -1
  77. package/dist/lib/commands/services/projects.d.ts.map +1 -1
  78. package/dist/lib/commands/services/projects.js +64 -64
  79. package/dist/lib/commands/services/projects.js.map +1 -1
  80. package/dist/lib/commands/services/proxy.d.ts.map +1 -1
  81. package/dist/lib/commands/services/proxy.js +11 -11
  82. package/dist/lib/commands/services/proxy.js.map +1 -1
  83. package/dist/lib/commands/services/sites.d.ts.map +1 -1
  84. package/dist/lib/commands/services/sites.js +41 -33
  85. package/dist/lib/commands/services/sites.js.map +1 -1
  86. package/dist/lib/commands/services/storage.d.ts.map +1 -1
  87. package/dist/lib/commands/services/storage.js +38 -16
  88. package/dist/lib/commands/services/storage.js.map +1 -1
  89. package/dist/lib/commands/services/tables-db.d.ts +3 -0
  90. package/dist/lib/commands/services/tables-db.d.ts.map +1 -0
  91. package/dist/lib/commands/services/{tablesdb.js → tables-db.js} +171 -163
  92. package/dist/lib/commands/services/tables-db.js.map +1 -0
  93. package/dist/lib/commands/services/teams.d.ts.map +1 -1
  94. package/dist/lib/commands/services/teams.js +16 -16
  95. package/dist/lib/commands/services/teams.js.map +1 -1
  96. package/dist/lib/commands/services/tokens.d.ts.map +1 -1
  97. package/dist/lib/commands/services/tokens.js +6 -6
  98. package/dist/lib/commands/services/tokens.js.map +1 -1
  99. package/dist/lib/commands/services/users.d.ts.map +1 -1
  100. package/dist/lib/commands/services/users.js +54 -54
  101. package/dist/lib/commands/services/users.js.map +1 -1
  102. package/dist/lib/commands/services/vcs.d.ts.map +1 -1
  103. package/dist/lib/commands/services/vcs.js +13 -13
  104. package/dist/lib/commands/services/vcs.js.map +1 -1
  105. package/dist/lib/commands/types.d.ts.map +1 -1
  106. package/dist/lib/commands/types.js +1 -1
  107. package/dist/lib/commands/types.js.map +1 -1
  108. package/dist/lib/commands/update.d.ts.map +1 -1
  109. package/dist/lib/commands/update.js +9 -8
  110. package/dist/lib/commands/update.js.map +1 -1
  111. package/dist/lib/commands/utils/attributes.d.ts +47 -0
  112. package/dist/lib/commands/utils/attributes.d.ts.map +1 -0
  113. package/dist/lib/commands/utils/attributes.js +514 -0
  114. package/dist/lib/commands/utils/attributes.js.map +1 -0
  115. package/dist/lib/commands/utils/change-approval.d.ts +25 -0
  116. package/dist/lib/commands/utils/change-approval.d.ts.map +1 -0
  117. package/dist/lib/commands/utils/change-approval.js +129 -0
  118. package/dist/lib/commands/utils/change-approval.js.map +1 -0
  119. package/dist/lib/commands/utils/database-sync.d.ts +10 -0
  120. package/dist/lib/commands/utils/database-sync.d.ts.map +1 -0
  121. package/dist/lib/commands/utils/database-sync.js +136 -0
  122. package/dist/lib/commands/utils/database-sync.js.map +1 -0
  123. package/dist/lib/commands/utils/deployment.d.ts +34 -0
  124. package/dist/lib/commands/utils/deployment.d.ts.map +1 -0
  125. package/dist/lib/commands/utils/deployment.js +109 -0
  126. package/dist/lib/commands/utils/deployment.js.map +1 -0
  127. package/dist/lib/commands/utils/error-formatter.d.ts +19 -0
  128. package/dist/lib/commands/utils/error-formatter.d.ts.map +1 -0
  129. package/dist/lib/commands/utils/error-formatter.js +333 -0
  130. package/dist/lib/commands/utils/error-formatter.js.map +1 -0
  131. package/dist/lib/commands/utils/pools.d.ts +16 -0
  132. package/dist/lib/commands/utils/pools.d.ts.map +1 -0
  133. package/dist/lib/commands/utils/pools.js +198 -0
  134. package/dist/lib/commands/utils/pools.js.map +1 -0
  135. package/dist/lib/config.d.ts +27 -26
  136. package/dist/lib/config.d.ts.map +1 -1
  137. package/dist/lib/config.js +8 -45
  138. package/dist/lib/config.js.map +1 -1
  139. package/dist/lib/constants.d.ts +14 -0
  140. package/dist/lib/constants.d.ts.map +1 -0
  141. package/dist/lib/constants.js +19 -0
  142. package/dist/lib/constants.js.map +1 -0
  143. package/dist/lib/emulation/docker.d.ts +4 -4
  144. package/dist/lib/emulation/docker.d.ts.map +1 -1
  145. package/dist/lib/emulation/docker.js +80 -67
  146. package/dist/lib/emulation/docker.js.map +1 -1
  147. package/dist/lib/parser.d.ts.map +1 -1
  148. package/dist/lib/parser.js +11 -10
  149. package/dist/lib/parser.js.map +1 -1
  150. package/dist/lib/questions.d.ts.map +1 -1
  151. package/dist/lib/questions.js +20 -20
  152. package/dist/lib/questions.js.map +1 -1
  153. package/dist/lib/sdks.d.ts.map +1 -1
  154. package/dist/lib/sdks.js +10 -11
  155. package/dist/lib/sdks.js.map +1 -1
  156. package/dist/lib/types.d.ts +0 -214
  157. package/dist/lib/types.d.ts.map +1 -1
  158. package/dist/lib/utils.d.ts +3 -0
  159. package/dist/lib/utils.d.ts.map +1 -1
  160. package/dist/lib/utils.js +42 -2
  161. package/dist/lib/utils.js.map +1 -1
  162. package/dist/package.json +12 -11
  163. package/docs/examples/account/create-anonymous-session.md +1 -0
  164. package/docs/examples/account/create-email-password-session.md +3 -0
  165. package/docs/examples/account/create-email-token.md +3 -0
  166. package/docs/examples/account/create-email-verification.md +2 -0
  167. package/docs/examples/account/create-jwt.md +1 -0
  168. package/docs/examples/account/create-magic-url-token.md +3 -0
  169. package/docs/examples/account/create-mfa-authenticator.md +2 -0
  170. package/docs/examples/account/create-mfa-challenge.md +2 -0
  171. package/docs/examples/account/create-mfa-recovery-codes.md +1 -0
  172. package/docs/examples/account/create-o-auth-2-session.md +2 -0
  173. package/docs/examples/account/create-o-auth-2-token.md +2 -0
  174. package/docs/examples/account/create-phone-token.md +3 -0
  175. package/docs/examples/account/create-phone-verification.md +1 -0
  176. package/docs/examples/account/create-push-target.md +3 -0
  177. package/docs/examples/account/create-recovery.md +3 -0
  178. package/docs/examples/account/create-session.md +3 -0
  179. package/docs/examples/account/create-verification.md +2 -0
  180. package/docs/examples/account/create.md +4 -0
  181. package/docs/examples/account/delete-identity.md +2 -0
  182. package/docs/examples/account/delete-mfa-authenticator.md +2 -0
  183. package/docs/examples/account/delete-push-target.md +2 -0
  184. package/docs/examples/account/delete-session.md +2 -0
  185. package/docs/examples/account/delete-sessions.md +1 -0
  186. package/docs/examples/account/delete.md +1 -0
  187. package/docs/examples/account/get-mfa-recovery-codes.md +1 -0
  188. package/docs/examples/account/get-prefs.md +1 -0
  189. package/docs/examples/account/get-session.md +2 -0
  190. package/docs/examples/account/get.md +1 -0
  191. package/docs/examples/account/list-identities.md +1 -0
  192. package/docs/examples/account/list-logs.md +1 -0
  193. package/docs/examples/account/list-mfa-factors.md +1 -0
  194. package/docs/examples/account/list-sessions.md +1 -0
  195. package/docs/examples/account/update-email-verification.md +3 -0
  196. package/docs/examples/account/update-email.md +3 -0
  197. package/docs/examples/account/update-magic-url-session.md +3 -0
  198. package/docs/examples/account/update-mfa-authenticator.md +3 -0
  199. package/docs/examples/account/update-mfa-challenge.md +3 -0
  200. package/docs/examples/account/update-mfa-recovery-codes.md +1 -0
  201. package/docs/examples/account/update-mfa.md +2 -0
  202. package/docs/examples/account/update-name.md +2 -0
  203. package/docs/examples/account/update-password.md +2 -0
  204. package/docs/examples/account/update-phone-session.md +3 -0
  205. package/docs/examples/account/update-phone-verification.md +3 -0
  206. package/docs/examples/account/update-phone.md +3 -0
  207. package/docs/examples/account/update-prefs.md +2 -0
  208. package/docs/examples/account/update-push-target.md +3 -0
  209. package/docs/examples/account/update-recovery.md +4 -0
  210. package/docs/examples/account/update-session.md +2 -0
  211. package/docs/examples/account/update-status.md +1 -0
  212. package/docs/examples/account/update-verification.md +3 -0
  213. package/docs/examples/console/get-resource.md +3 -0
  214. package/docs/examples/console/variables.md +1 -0
  215. package/docs/examples/databases/create-boolean-attribute.md +5 -0
  216. package/docs/examples/databases/create-collection.md +4 -0
  217. package/docs/examples/databases/create-datetime-attribute.md +5 -0
  218. package/docs/examples/databases/create-document.md +5 -0
  219. package/docs/examples/databases/create-documents.md +4 -0
  220. package/docs/examples/databases/create-email-attribute.md +5 -0
  221. package/docs/examples/databases/create-enum-attribute.md +6 -0
  222. package/docs/examples/databases/create-float-attribute.md +5 -0
  223. package/docs/examples/databases/create-index.md +6 -0
  224. package/docs/examples/databases/create-integer-attribute.md +5 -0
  225. package/docs/examples/databases/create-ip-attribute.md +5 -0
  226. package/docs/examples/databases/create-line-attribute.md +5 -0
  227. package/docs/examples/databases/create-operations.md +2 -0
  228. package/docs/examples/databases/create-point-attribute.md +5 -0
  229. package/docs/examples/databases/create-polygon-attribute.md +5 -0
  230. package/docs/examples/databases/create-relationship-attribute.md +5 -0
  231. package/docs/examples/databases/create-string-attribute.md +6 -0
  232. package/docs/examples/databases/create-transaction.md +1 -0
  233. package/docs/examples/databases/create-url-attribute.md +5 -0
  234. package/docs/examples/databases/create.md +3 -0
  235. package/docs/examples/databases/decrement-document-attribute.md +5 -0
  236. package/docs/examples/databases/delete-attribute.md +4 -0
  237. package/docs/examples/databases/delete-collection.md +3 -0
  238. package/docs/examples/databases/delete-document.md +4 -0
  239. package/docs/examples/databases/delete-documents.md +3 -0
  240. package/docs/examples/databases/delete-index.md +4 -0
  241. package/docs/examples/databases/delete-transaction.md +2 -0
  242. package/docs/examples/databases/delete.md +2 -0
  243. package/docs/examples/databases/get-attribute.md +4 -0
  244. package/docs/examples/databases/get-collection-usage.md +3 -0
  245. package/docs/examples/databases/get-collection.md +3 -0
  246. package/docs/examples/databases/get-document.md +4 -0
  247. package/docs/examples/databases/get-index.md +4 -0
  248. package/docs/examples/databases/get-transaction.md +2 -0
  249. package/docs/examples/databases/get-usage.md +2 -0
  250. package/docs/examples/databases/get.md +2 -0
  251. package/docs/examples/databases/increment-document-attribute.md +5 -0
  252. package/docs/examples/databases/list-attributes.md +3 -0
  253. package/docs/examples/databases/list-collection-logs.md +3 -0
  254. package/docs/examples/databases/list-collections.md +2 -0
  255. package/docs/examples/databases/list-document-logs.md +4 -0
  256. package/docs/examples/databases/list-documents.md +3 -0
  257. package/docs/examples/databases/list-indexes.md +3 -0
  258. package/docs/examples/databases/list-logs.md +2 -0
  259. package/docs/examples/databases/list-transactions.md +1 -0
  260. package/docs/examples/databases/list-usage.md +1 -0
  261. package/docs/examples/databases/list.md +1 -0
  262. package/docs/examples/databases/update-boolean-attribute.md +6 -0
  263. package/docs/examples/databases/update-collection.md +4 -0
  264. package/docs/examples/databases/update-datetime-attribute.md +6 -0
  265. package/docs/examples/databases/update-document.md +4 -0
  266. package/docs/examples/databases/update-documents.md +3 -0
  267. package/docs/examples/databases/update-email-attribute.md +6 -0
  268. package/docs/examples/databases/update-enum-attribute.md +7 -0
  269. package/docs/examples/databases/update-float-attribute.md +6 -0
  270. package/docs/examples/databases/update-integer-attribute.md +6 -0
  271. package/docs/examples/databases/update-ip-attribute.md +6 -0
  272. package/docs/examples/databases/update-line-attribute.md +5 -0
  273. package/docs/examples/databases/update-point-attribute.md +5 -0
  274. package/docs/examples/databases/update-polygon-attribute.md +5 -0
  275. package/docs/examples/databases/update-relationship-attribute.md +4 -0
  276. package/docs/examples/databases/update-string-attribute.md +6 -0
  277. package/docs/examples/databases/update-transaction.md +2 -0
  278. package/docs/examples/databases/update-url-attribute.md +6 -0
  279. package/docs/examples/databases/update.md +3 -0
  280. package/docs/examples/databases/upsert-document.md +4 -0
  281. package/docs/examples/databases/upsert-documents.md +4 -0
  282. package/docs/examples/functions/create-deployment.md +4 -0
  283. package/docs/examples/functions/create-duplicate-deployment.md +3 -0
  284. package/docs/examples/functions/create-execution.md +2 -0
  285. package/docs/examples/functions/create-template-deployment.md +7 -0
  286. package/docs/examples/functions/create-variable.md +4 -0
  287. package/docs/examples/functions/create-vcs-deployment.md +4 -0
  288. package/docs/examples/functions/create.md +4 -0
  289. package/docs/examples/functions/delete-deployment.md +3 -0
  290. package/docs/examples/functions/delete-execution.md +3 -0
  291. package/docs/examples/functions/delete-variable.md +3 -0
  292. package/docs/examples/functions/delete.md +2 -0
  293. package/docs/examples/functions/get-deployment-download.md +3 -0
  294. package/docs/examples/functions/get-deployment.md +3 -0
  295. package/docs/examples/functions/get-execution.md +3 -0
  296. package/docs/examples/functions/get-template.md +2 -0
  297. package/docs/examples/functions/get-usage.md +2 -0
  298. package/docs/examples/functions/get-variable.md +3 -0
  299. package/docs/examples/functions/get.md +2 -0
  300. package/docs/examples/functions/list-deployments.md +2 -0
  301. package/docs/examples/functions/list-executions.md +2 -0
  302. package/docs/examples/functions/list-runtimes.md +1 -0
  303. package/docs/examples/functions/list-specifications.md +1 -0
  304. package/docs/examples/functions/list-templates.md +1 -0
  305. package/docs/examples/functions/list-usage.md +1 -0
  306. package/docs/examples/functions/list-variables.md +2 -0
  307. package/docs/examples/functions/list.md +1 -0
  308. package/docs/examples/functions/update-deployment-status.md +3 -0
  309. package/docs/examples/functions/update-function-deployment.md +3 -0
  310. package/docs/examples/functions/update-variable.md +4 -0
  311. package/docs/examples/functions/update.md +3 -0
  312. package/docs/examples/graphql/mutation.md +2 -0
  313. package/docs/examples/graphql/query.md +2 -0
  314. package/docs/examples/health/get-antivirus.md +1 -0
  315. package/docs/examples/health/get-cache.md +1 -0
  316. package/docs/examples/health/get-certificate.md +1 -0
  317. package/docs/examples/health/get-db.md +1 -0
  318. package/docs/examples/health/get-failed-jobs.md +2 -0
  319. package/docs/examples/health/get-pub-sub.md +1 -0
  320. package/docs/examples/health/get-queue-builds.md +1 -0
  321. package/docs/examples/health/get-queue-certificates.md +1 -0
  322. package/docs/examples/health/get-queue-databases.md +1 -0
  323. package/docs/examples/health/get-queue-deletes.md +1 -0
  324. package/docs/examples/health/get-queue-functions.md +1 -0
  325. package/docs/examples/health/get-queue-logs.md +1 -0
  326. package/docs/examples/health/get-queue-mails.md +1 -0
  327. package/docs/examples/health/get-queue-messaging.md +1 -0
  328. package/docs/examples/health/get-queue-migrations.md +1 -0
  329. package/docs/examples/health/get-queue-stats-resources.md +1 -0
  330. package/docs/examples/health/get-queue-usage.md +1 -0
  331. package/docs/examples/health/get-queue-webhooks.md +1 -0
  332. package/docs/examples/health/get-storage-local.md +1 -0
  333. package/docs/examples/health/get-storage.md +1 -0
  334. package/docs/examples/health/get-time.md +1 -0
  335. package/docs/examples/health/get.md +1 -0
  336. package/docs/examples/locale/get.md +1 -0
  337. package/docs/examples/locale/list-codes.md +1 -0
  338. package/docs/examples/locale/list-continents.md +1 -0
  339. package/docs/examples/locale/list-countries-eu.md +1 -0
  340. package/docs/examples/locale/list-countries-phones.md +1 -0
  341. package/docs/examples/locale/list-countries.md +1 -0
  342. package/docs/examples/locale/list-currencies.md +1 -0
  343. package/docs/examples/locale/list-languages.md +1 -0
  344. package/docs/examples/messaging/create-apns-provider.md +3 -0
  345. package/docs/examples/messaging/create-email.md +4 -0
  346. package/docs/examples/messaging/create-fcm-provider.md +3 -0
  347. package/docs/examples/messaging/create-mailgun-provider.md +3 -0
  348. package/docs/examples/messaging/create-msg-91-provider.md +3 -0
  349. package/docs/examples/messaging/create-push.md +2 -0
  350. package/docs/examples/messaging/create-resend-provider.md +3 -0
  351. package/docs/examples/messaging/create-sendgrid-provider.md +3 -0
  352. package/docs/examples/messaging/create-sms.md +3 -0
  353. package/docs/examples/messaging/create-smtp-provider.md +4 -0
  354. package/docs/examples/messaging/create-subscriber.md +4 -0
  355. package/docs/examples/messaging/create-telesign-provider.md +3 -0
  356. package/docs/examples/messaging/create-textmagic-provider.md +3 -0
  357. package/docs/examples/messaging/create-topic.md +3 -0
  358. package/docs/examples/messaging/create-twilio-provider.md +3 -0
  359. package/docs/examples/messaging/create-vonage-provider.md +3 -0
  360. package/docs/examples/messaging/delete-provider.md +2 -0
  361. package/docs/examples/messaging/delete-subscriber.md +3 -0
  362. package/docs/examples/messaging/delete-topic.md +2 -0
  363. package/docs/examples/messaging/delete.md +2 -0
  364. package/docs/examples/messaging/get-message.md +2 -0
  365. package/docs/examples/messaging/get-provider.md +2 -0
  366. package/docs/examples/messaging/get-subscriber.md +3 -0
  367. package/docs/examples/messaging/get-topic.md +2 -0
  368. package/docs/examples/messaging/list-message-logs.md +2 -0
  369. package/docs/examples/messaging/list-messages.md +1 -0
  370. package/docs/examples/messaging/list-provider-logs.md +2 -0
  371. package/docs/examples/messaging/list-providers.md +1 -0
  372. package/docs/examples/messaging/list-subscriber-logs.md +2 -0
  373. package/docs/examples/messaging/list-subscribers.md +2 -0
  374. package/docs/examples/messaging/list-targets.md +2 -0
  375. package/docs/examples/messaging/list-topic-logs.md +2 -0
  376. package/docs/examples/messaging/list-topics.md +1 -0
  377. package/docs/examples/messaging/update-apns-provider.md +2 -0
  378. package/docs/examples/messaging/update-email.md +2 -0
  379. package/docs/examples/messaging/update-fcm-provider.md +2 -0
  380. package/docs/examples/messaging/update-mailgun-provider.md +2 -0
  381. package/docs/examples/messaging/update-msg-91-provider.md +2 -0
  382. package/docs/examples/messaging/update-push.md +2 -0
  383. package/docs/examples/messaging/update-resend-provider.md +2 -0
  384. package/docs/examples/messaging/update-sendgrid-provider.md +2 -0
  385. package/docs/examples/messaging/update-sms.md +2 -0
  386. package/docs/examples/messaging/update-smtp-provider.md +2 -0
  387. package/docs/examples/messaging/update-telesign-provider.md +2 -0
  388. package/docs/examples/messaging/update-textmagic-provider.md +2 -0
  389. package/docs/examples/messaging/update-topic.md +2 -0
  390. package/docs/examples/messaging/update-twilio-provider.md +2 -0
  391. package/docs/examples/messaging/update-vonage-provider.md +2 -0
  392. package/docs/examples/migrations/create-appwrite-migration.md +5 -0
  393. package/docs/examples/migrations/create-csv-export.md +3 -0
  394. package/docs/examples/migrations/create-csv-import.md +4 -0
  395. package/docs/examples/migrations/create-firebase-migration.md +3 -0
  396. package/docs/examples/migrations/create-n-host-migration.md +8 -0
  397. package/docs/examples/migrations/create-supabase-migration.md +7 -0
  398. package/docs/examples/migrations/delete.md +2 -0
  399. package/docs/examples/migrations/get-appwrite-report.md +5 -0
  400. package/docs/examples/migrations/get-firebase-report.md +3 -0
  401. package/docs/examples/migrations/get-n-host-report.md +8 -0
  402. package/docs/examples/migrations/get-supabase-report.md +7 -0
  403. package/docs/examples/migrations/get.md +2 -0
  404. package/docs/examples/migrations/list.md +1 -0
  405. package/docs/examples/migrations/retry.md +2 -0
  406. package/docs/examples/project/create-variable.md +3 -0
  407. package/docs/examples/project/delete-variable.md +2 -0
  408. package/docs/examples/project/get-usage.md +3 -0
  409. package/docs/examples/project/get-variable.md +2 -0
  410. package/docs/examples/project/list-variables.md +1 -0
  411. package/docs/examples/project/update-variable.md +3 -0
  412. package/docs/examples/projects/create-dev-key.md +4 -0
  413. package/docs/examples/projects/create-jwt.md +3 -0
  414. package/docs/examples/projects/create-key.md +4 -0
  415. package/docs/examples/projects/create-platform.md +4 -0
  416. package/docs/examples/projects/create-smtp-test.md +6 -0
  417. package/docs/examples/projects/create-webhook.md +6 -0
  418. package/docs/examples/projects/create.md +4 -0
  419. package/docs/examples/projects/delete-dev-key.md +3 -0
  420. package/docs/examples/projects/delete-email-template.md +4 -0
  421. package/docs/examples/projects/delete-key.md +3 -0
  422. package/docs/examples/projects/delete-platform.md +3 -0
  423. package/docs/examples/projects/delete-sms-template.md +4 -0
  424. package/docs/examples/projects/delete-webhook.md +3 -0
  425. package/docs/examples/projects/delete.md +2 -0
  426. package/docs/examples/projects/get-dev-key.md +3 -0
  427. package/docs/examples/projects/get-email-template.md +4 -0
  428. package/docs/examples/projects/get-key.md +3 -0
  429. package/docs/examples/projects/get-platform.md +3 -0
  430. package/docs/examples/projects/get-sms-template.md +4 -0
  431. package/docs/examples/projects/get-webhook.md +3 -0
  432. package/docs/examples/projects/get.md +2 -0
  433. package/docs/examples/projects/list-dev-keys.md +2 -0
  434. package/docs/examples/projects/list-keys.md +2 -0
  435. package/docs/examples/projects/list-platforms.md +2 -0
  436. package/docs/examples/projects/list-webhooks.md +2 -0
  437. package/docs/examples/projects/list.md +1 -0
  438. package/docs/examples/projects/update-api-status-all.md +3 -0
  439. package/docs/examples/projects/update-api-status.md +4 -0
  440. package/docs/examples/projects/update-auth-duration.md +3 -0
  441. package/docs/examples/projects/update-auth-limit.md +3 -0
  442. package/docs/examples/projects/update-auth-password-dictionary.md +3 -0
  443. package/docs/examples/projects/update-auth-password-history.md +3 -0
  444. package/docs/examples/projects/update-auth-sessions-limit.md +3 -0
  445. package/docs/examples/projects/update-auth-status.md +4 -0
  446. package/docs/examples/projects/update-dev-key.md +5 -0
  447. package/docs/examples/projects/update-email-template.md +6 -0
  448. package/docs/examples/projects/update-key.md +5 -0
  449. package/docs/examples/projects/update-memberships-privacy.md +5 -0
  450. package/docs/examples/projects/update-mock-numbers.md +3 -0
  451. package/docs/examples/projects/update-o-auth-2.md +3 -0
  452. package/docs/examples/projects/update-personal-data-check.md +3 -0
  453. package/docs/examples/projects/update-platform.md +4 -0
  454. package/docs/examples/projects/update-service-status-all.md +3 -0
  455. package/docs/examples/projects/update-service-status.md +4 -0
  456. package/docs/examples/projects/update-session-alerts.md +3 -0
  457. package/docs/examples/projects/update-session-invalidation.md +3 -0
  458. package/docs/examples/projects/update-sms-template.md +5 -0
  459. package/docs/examples/projects/update-smtp.md +3 -0
  460. package/docs/examples/projects/update-team.md +3 -0
  461. package/docs/examples/projects/update-webhook-signature.md +3 -0
  462. package/docs/examples/projects/update-webhook.md +7 -0
  463. package/docs/examples/projects/update.md +3 -0
  464. package/docs/examples/proxy/create-api-rule.md +2 -0
  465. package/docs/examples/proxy/create-function-rule.md +3 -0
  466. package/docs/examples/proxy/create-redirect-rule.md +6 -0
  467. package/docs/examples/proxy/create-site-rule.md +3 -0
  468. package/docs/examples/proxy/delete-rule.md +2 -0
  469. package/docs/examples/proxy/get-rule.md +2 -0
  470. package/docs/examples/proxy/list-rules.md +1 -0
  471. package/docs/examples/proxy/update-rule-verification.md +2 -0
  472. package/docs/examples/sites/create-deployment.md +4 -0
  473. package/docs/examples/sites/create-duplicate-deployment.md +3 -0
  474. package/docs/examples/sites/create-template-deployment.md +7 -0
  475. package/docs/examples/sites/create-variable.md +4 -0
  476. package/docs/examples/sites/create-vcs-deployment.md +4 -0
  477. package/docs/examples/sites/create.md +5 -0
  478. package/docs/examples/sites/delete-deployment.md +3 -0
  479. package/docs/examples/sites/delete-log.md +3 -0
  480. package/docs/examples/sites/delete-variable.md +3 -0
  481. package/docs/examples/sites/delete.md +2 -0
  482. package/docs/examples/sites/get-deployment-download.md +3 -0
  483. package/docs/examples/sites/get-deployment.md +3 -0
  484. package/docs/examples/sites/get-log.md +3 -0
  485. package/docs/examples/sites/get-template.md +2 -0
  486. package/docs/examples/sites/get-usage.md +2 -0
  487. package/docs/examples/sites/get-variable.md +3 -0
  488. package/docs/examples/sites/get.md +2 -0
  489. package/docs/examples/sites/list-deployments.md +2 -0
  490. package/docs/examples/sites/list-frameworks.md +1 -0
  491. package/docs/examples/sites/list-logs.md +2 -0
  492. package/docs/examples/sites/list-specifications.md +1 -0
  493. package/docs/examples/sites/list-templates.md +1 -0
  494. package/docs/examples/sites/list-usage.md +1 -0
  495. package/docs/examples/sites/list-variables.md +2 -0
  496. package/docs/examples/sites/list.md +1 -0
  497. package/docs/examples/sites/update-deployment-status.md +3 -0
  498. package/docs/examples/sites/update-site-deployment.md +3 -0
  499. package/docs/examples/sites/update-variable.md +4 -0
  500. package/docs/examples/sites/update.md +4 -0
  501. package/docs/examples/storage/create-bucket.md +3 -0
  502. package/docs/examples/storage/create-file.md +4 -0
  503. package/docs/examples/storage/delete-bucket.md +2 -0
  504. package/docs/examples/storage/delete-file.md +3 -0
  505. package/docs/examples/storage/get-bucket-usage.md +2 -0
  506. package/docs/examples/storage/get-bucket.md +2 -0
  507. package/docs/examples/storage/get-file-download.md +3 -0
  508. package/docs/examples/storage/get-file-preview.md +3 -0
  509. package/docs/examples/storage/get-file-view.md +3 -0
  510. package/docs/examples/storage/get-file.md +3 -0
  511. package/docs/examples/storage/get-usage.md +1 -0
  512. package/docs/examples/storage/list-buckets.md +1 -0
  513. package/docs/examples/storage/list-files.md +2 -0
  514. package/docs/examples/storage/update-bucket.md +3 -0
  515. package/docs/examples/storage/update-file.md +3 -0
  516. package/docs/examples/tablesdb/create-boolean-column.md +5 -0
  517. package/docs/examples/tablesdb/create-datetime-column.md +5 -0
  518. package/docs/examples/tablesdb/create-email-column.md +5 -0
  519. package/docs/examples/tablesdb/create-enum-column.md +6 -0
  520. package/docs/examples/tablesdb/create-float-column.md +5 -0
  521. package/docs/examples/tablesdb/create-index.md +6 -0
  522. package/docs/examples/tablesdb/create-integer-column.md +5 -0
  523. package/docs/examples/tablesdb/create-ip-column.md +5 -0
  524. package/docs/examples/tablesdb/create-line-column.md +5 -0
  525. package/docs/examples/tablesdb/create-operations.md +2 -0
  526. package/docs/examples/tablesdb/create-point-column.md +5 -0
  527. package/docs/examples/tablesdb/create-polygon-column.md +5 -0
  528. package/docs/examples/tablesdb/create-relationship-column.md +5 -0
  529. package/docs/examples/tablesdb/create-row.md +5 -0
  530. package/docs/examples/tablesdb/create-rows.md +4 -0
  531. package/docs/examples/tablesdb/create-string-column.md +6 -0
  532. package/docs/examples/tablesdb/create-table.md +4 -0
  533. package/docs/examples/tablesdb/create-transaction.md +1 -0
  534. package/docs/examples/tablesdb/create-url-column.md +5 -0
  535. package/docs/examples/tablesdb/create.md +3 -0
  536. package/docs/examples/tablesdb/decrement-row-column.md +5 -0
  537. package/docs/examples/tablesdb/delete-column.md +4 -0
  538. package/docs/examples/tablesdb/delete-index.md +4 -0
  539. package/docs/examples/tablesdb/delete-row.md +4 -0
  540. package/docs/examples/tablesdb/delete-rows.md +3 -0
  541. package/docs/examples/tablesdb/delete-table.md +3 -0
  542. package/docs/examples/tablesdb/delete-transaction.md +2 -0
  543. package/docs/examples/tablesdb/delete.md +2 -0
  544. package/docs/examples/tablesdb/get-column.md +4 -0
  545. package/docs/examples/tablesdb/get-index.md +4 -0
  546. package/docs/examples/tablesdb/get-row.md +4 -0
  547. package/docs/examples/tablesdb/get-table-usage.md +3 -0
  548. package/docs/examples/tablesdb/get-table.md +3 -0
  549. package/docs/examples/tablesdb/get-transaction.md +2 -0
  550. package/docs/examples/tablesdb/get-usage.md +2 -0
  551. package/docs/examples/tablesdb/get.md +2 -0
  552. package/docs/examples/tablesdb/increment-row-column.md +5 -0
  553. package/docs/examples/tablesdb/list-columns.md +3 -0
  554. package/docs/examples/tablesdb/list-indexes.md +3 -0
  555. package/docs/examples/tablesdb/list-row-logs.md +4 -0
  556. package/docs/examples/tablesdb/list-rows.md +3 -0
  557. package/docs/examples/tablesdb/list-table-logs.md +3 -0
  558. package/docs/examples/tablesdb/list-tables.md +2 -0
  559. package/docs/examples/tablesdb/list-transactions.md +1 -0
  560. package/docs/examples/tablesdb/list-usage.md +1 -0
  561. package/docs/examples/tablesdb/list.md +1 -0
  562. package/docs/examples/tablesdb/update-boolean-column.md +6 -0
  563. package/docs/examples/tablesdb/update-datetime-column.md +6 -0
  564. package/docs/examples/tablesdb/update-email-column.md +6 -0
  565. package/docs/examples/tablesdb/update-enum-column.md +7 -0
  566. package/docs/examples/tablesdb/update-float-column.md +6 -0
  567. package/docs/examples/tablesdb/update-integer-column.md +6 -0
  568. package/docs/examples/tablesdb/update-ip-column.md +6 -0
  569. package/docs/examples/tablesdb/update-line-column.md +5 -0
  570. package/docs/examples/tablesdb/update-point-column.md +5 -0
  571. package/docs/examples/tablesdb/update-polygon-column.md +5 -0
  572. package/docs/examples/tablesdb/update-relationship-column.md +4 -0
  573. package/docs/examples/tablesdb/update-row.md +4 -0
  574. package/docs/examples/tablesdb/update-rows.md +3 -0
  575. package/docs/examples/tablesdb/update-string-column.md +6 -0
  576. package/docs/examples/tablesdb/update-table.md +4 -0
  577. package/docs/examples/tablesdb/update-transaction.md +2 -0
  578. package/docs/examples/tablesdb/update-url-column.md +6 -0
  579. package/docs/examples/tablesdb/update.md +3 -0
  580. package/docs/examples/tablesdb/upsert-row.md +4 -0
  581. package/docs/examples/tablesdb/upsert-rows.md +4 -0
  582. package/docs/examples/teams/create-membership.md +3 -0
  583. package/docs/examples/teams/create.md +3 -0
  584. package/docs/examples/teams/delete-membership.md +3 -0
  585. package/docs/examples/teams/delete.md +2 -0
  586. package/docs/examples/teams/get-membership.md +3 -0
  587. package/docs/examples/teams/get-prefs.md +2 -0
  588. package/docs/examples/teams/get.md +2 -0
  589. package/docs/examples/teams/list-logs.md +2 -0
  590. package/docs/examples/teams/list-memberships.md +2 -0
  591. package/docs/examples/teams/list.md +1 -0
  592. package/docs/examples/teams/update-membership-status.md +5 -0
  593. package/docs/examples/teams/update-membership.md +4 -0
  594. package/docs/examples/teams/update-name.md +3 -0
  595. package/docs/examples/teams/update-prefs.md +3 -0
  596. package/docs/examples/tokens/create-file-token.md +3 -0
  597. package/docs/examples/tokens/delete.md +2 -0
  598. package/docs/examples/tokens/get.md +2 -0
  599. package/docs/examples/tokens/list.md +3 -0
  600. package/docs/examples/tokens/update.md +2 -0
  601. package/docs/examples/users/create-argon-2-user.md +4 -0
  602. package/docs/examples/users/create-bcrypt-user.md +4 -0
  603. package/docs/examples/users/create-jwt.md +2 -0
  604. package/docs/examples/users/create-md-5-user.md +4 -0
  605. package/docs/examples/users/create-mfa-recovery-codes.md +2 -0
  606. package/docs/examples/users/create-ph-pass-user.md +4 -0
  607. package/docs/examples/users/create-scrypt-modified-user.md +7 -0
  608. package/docs/examples/users/create-scrypt-user.md +9 -0
  609. package/docs/examples/users/create-session.md +2 -0
  610. package/docs/examples/users/create-sha-user.md +4 -0
  611. package/docs/examples/users/create-target.md +5 -0
  612. package/docs/examples/users/create-token.md +2 -0
  613. package/docs/examples/users/create.md +2 -0
  614. package/docs/examples/users/delete-identity.md +2 -0
  615. package/docs/examples/users/delete-mfa-authenticator.md +3 -0
  616. package/docs/examples/users/delete-session.md +3 -0
  617. package/docs/examples/users/delete-sessions.md +2 -0
  618. package/docs/examples/users/delete-target.md +3 -0
  619. package/docs/examples/users/delete.md +2 -0
  620. package/docs/examples/users/get-mfa-recovery-codes.md +2 -0
  621. package/docs/examples/users/get-prefs.md +2 -0
  622. package/docs/examples/users/get-target.md +3 -0
  623. package/docs/examples/users/get-usage.md +1 -0
  624. package/docs/examples/users/get.md +2 -0
  625. package/docs/examples/users/list-identities.md +1 -0
  626. package/docs/examples/users/list-logs.md +2 -0
  627. package/docs/examples/users/list-memberships.md +2 -0
  628. package/docs/examples/users/list-mfa-factors.md +2 -0
  629. package/docs/examples/users/list-sessions.md +2 -0
  630. package/docs/examples/users/list-targets.md +2 -0
  631. package/docs/examples/users/list.md +1 -0
  632. package/docs/examples/users/update-email-verification.md +3 -0
  633. package/docs/examples/users/update-email.md +3 -0
  634. package/docs/examples/users/update-labels.md +3 -0
  635. package/docs/examples/users/update-mfa-recovery-codes.md +2 -0
  636. package/docs/examples/users/update-mfa.md +3 -0
  637. package/docs/examples/users/update-name.md +3 -0
  638. package/docs/examples/users/update-password.md +3 -0
  639. package/docs/examples/users/update-phone-verification.md +3 -0
  640. package/docs/examples/users/update-phone.md +3 -0
  641. package/docs/examples/users/update-prefs.md +3 -0
  642. package/docs/examples/users/update-status.md +3 -0
  643. package/docs/examples/users/update-target.md +3 -0
  644. package/docs/examples/vcs/create-repository-detection.md +4 -0
  645. package/docs/examples/vcs/create-repository.md +4 -0
  646. package/docs/examples/vcs/delete-installation.md +2 -0
  647. package/docs/examples/vcs/get-installation.md +2 -0
  648. package/docs/examples/vcs/get-repository-contents.md +3 -0
  649. package/docs/examples/vcs/get-repository.md +3 -0
  650. package/docs/examples/vcs/list-installations.md +1 -0
  651. package/docs/examples/vcs/list-repositories.md +3 -0
  652. package/docs/examples/vcs/list-repository-branches.md +3 -0
  653. package/docs/examples/vcs/update-external-deployments.md +4 -0
  654. package/index.ts +25 -165
  655. package/install.ps1 +2 -2
  656. package/install.sh +1 -1
  657. package/lib/client.ts +14 -6
  658. package/lib/commands/config.ts +494 -0
  659. package/lib/commands/db.ts +324 -0
  660. package/lib/commands/errors.ts +93 -0
  661. package/lib/commands/init.ts +25 -14
  662. package/lib/commands/pull.ts +683 -420
  663. package/lib/commands/push.ts +1677 -2404
  664. package/lib/commands/run.ts +1 -1
  665. package/lib/commands/schema.ts +122 -0
  666. package/lib/commands/services/account.ts +200 -385
  667. package/lib/commands/services/console.ts +13 -34
  668. package/lib/commands/services/databases.ts +298 -1215
  669. package/lib/commands/services/functions.ts +115 -434
  670. package/lib/commands/services/graphql.ts +5 -2
  671. package/lib/commands/services/health.ts +87 -149
  672. package/lib/commands/services/locale.ts +36 -33
  673. package/lib/commands/services/messaging.ts +180 -999
  674. package/lib/commands/services/migrations.ts +54 -226
  675. package/lib/commands/services/project.ts +19 -23
  676. package/lib/commands/services/projects.ts +182 -714
  677. package/lib/commands/services/proxy.ts +30 -58
  678. package/lib/commands/services/sites.ts +107 -379
  679. package/lib/commands/services/storage.ts +93 -302
  680. package/lib/commands/services/tables-db.ts +1150 -0
  681. package/lib/commands/services/teams.ts +48 -110
  682. package/lib/commands/services/tokens.ts +16 -28
  683. package/lib/commands/services/users.ts +133 -403
  684. package/lib/commands/services/vcs.ts +48 -151
  685. package/lib/commands/types.ts +1 -1
  686. package/lib/commands/update.ts +13 -22
  687. package/lib/commands/utils/attributes.ts +719 -0
  688. package/lib/commands/utils/change-approval.ts +186 -0
  689. package/lib/commands/utils/database-sync.ts +180 -0
  690. package/lib/commands/utils/deployment.ts +184 -0
  691. package/lib/commands/utils/error-formatter.ts +417 -0
  692. package/lib/commands/utils/pools.ts +355 -0
  693. package/lib/config.ts +46 -82
  694. package/lib/constants.ts +22 -0
  695. package/lib/emulation/docker.ts +101 -87
  696. package/lib/parser.ts +16 -11
  697. package/lib/questions.ts +20 -21
  698. package/lib/sdks.ts +15 -11
  699. package/lib/types.ts +0 -229
  700. package/lib/utils.ts +45 -4
  701. package/package.json +12 -11
  702. package/scoop/appwrite.config.json +29 -19
  703. package/.github/workflows/build-verify.yml +0 -71
  704. package/bun.lock +0 -625
  705. package/dist/lib/commands/services/avatars.d.ts +0 -3
  706. package/dist/lib/commands/services/avatars.d.ts.map +0 -1
  707. package/dist/lib/commands/services/avatars.js +0 -118
  708. package/dist/lib/commands/services/avatars.js.map +0 -1
  709. package/dist/lib/commands/services/tablesdb.d.ts +0 -3
  710. package/dist/lib/commands/services/tablesdb.d.ts.map +0 -1
  711. package/dist/lib/commands/services/tablesdb.js.map +0 -1
  712. package/dist/scripts/generate-commands.d.ts +0 -2
  713. package/dist/scripts/generate-commands.d.ts.map +0 -1
  714. package/dist/scripts/generate-commands.js +0 -398
  715. package/dist/scripts/generate-commands.js.map +0 -1
  716. package/lib/commands/services/avatars.ts +0 -400
  717. package/lib/commands/services/tablesdb.ts +0 -1928
  718. package/scripts/generate-commands.ts +0 -539
@@ -4,790 +4,1195 @@ import chalk from "chalk";
4
4
  import inquirer from "inquirer";
5
5
  import { Command } from "commander";
6
6
  import ID from "../id.js";
7
- import { localConfig, globalConfig, KeysAttributes, KeysFunction, KeysSite, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, KeysCollection, KeysTable, } from "../config.js";
8
- import { Spinner, SPINNER_ARC, SPINNER_DOTS } from "../spinner.js";
7
+ import { EXECUTABLE_NAME } from "../constants.js";
8
+ import { localConfig, globalConfig, KeysFunction, KeysSite, KeysTopics, KeysStorage, KeysTeams, KeysCollection, KeysTable, } from "../config.js";
9
+ import { createSettingsObject } from "../utils.js";
10
+ import { Spinner, SPINNER_DOTS } from "../spinner.js";
9
11
  import { paginate } from "../paginate.js";
10
- import { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionsPushTables, questionPushChanges, questionPushChangesConfirmation, questionsPushMessagingTopics, questionsPushResources, } from "../questions.js";
12
+ import { pushDeployment } from "./utils/deployment.js";
13
+ import { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionsPushTables, questionsPushMessagingTopics, questionsPushResources, } from "../questions.js";
11
14
  import { cliConfig, actionRunner, success, warn, log, hint, error, commandDescriptions, drawTable, } from "../parser.js";
12
15
  import { getProxyService, getConsoleService, getFunctionsService, getSitesService, getDatabasesService, getTablesDBService, getStorageService, getMessagingService, getTeamsService, getProjectsService, } from "../services.js";
16
+ import { sdkForProject, sdkForConsole } from "../sdks.js";
17
+ import { AppwriteException, Query, } from "@appwrite.io/console";
13
18
  import { checkDeployConditions } from "../utils.js";
14
- const STEP_SIZE = 100; // Resources
19
+ import { Pools } from "./utils/pools.js";
20
+ import { Attributes } from "./utils/attributes.js";
21
+ import { getConfirmation, approveChanges, getObjectChanges, } from "./utils/change-approval.js";
22
+ import { checkAndApplyTablesDBChanges } from "./utils/database-sync.js";
15
23
  const POLL_DEBOUNCE = 2000; // Milliseconds
16
24
  const POLL_DEFAULT_VALUE = 30;
17
- let pollMaxDebounces = POLL_DEFAULT_VALUE;
18
- const changeableKeys = [
19
- "status",
20
- "required",
21
- "xdefault",
22
- "elements",
23
- "min",
24
- "max",
25
- "default",
26
- "error",
27
- ];
28
- const awaitPools = {
29
- wipeAttributes: async (databaseId, collectionId, iteration = 1) => {
30
- if (iteration > pollMaxDebounces) {
31
- return false;
32
- }
33
- const databasesService = await getDatabasesService();
34
- const response = await databasesService.listAttributes(databaseId, collectionId, [JSON.stringify({ method: "limit", values: [1] })]);
35
- const { total } = response;
36
- if (total === 0) {
37
- return true;
25
+ const DEPLOYMENT_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
26
+ export class Push {
27
+ projectClient;
28
+ consoleClient;
29
+ silent;
30
+ constructor(projectClient, consoleClient, silent = false) {
31
+ this.projectClient = projectClient;
32
+ this.consoleClient = consoleClient;
33
+ this.silent = silent;
34
+ }
35
+ /**
36
+ * Log a message (respects silent mode)
37
+ */
38
+ log(message) {
39
+ if (!this.silent) {
40
+ log(message);
41
+ }
42
+ }
43
+ /**
44
+ * Log a success message (respects silent mode)
45
+ */
46
+ success(message) {
47
+ if (!this.silent) {
48
+ success(message);
49
+ }
50
+ }
51
+ /**
52
+ * Log a warning message (respects silent mode)
53
+ */
54
+ warn(message) {
55
+ if (!this.silent) {
56
+ warn(message);
57
+ }
58
+ }
59
+ /**
60
+ * Log an error message (respects silent mode)
61
+ */
62
+ error(message) {
63
+ if (!this.silent) {
64
+ error(message);
65
+ }
66
+ }
67
+ async pushResources(config, options = { all: true, skipDeprecated: true }) {
68
+ const { skipDeprecated = true } = options;
69
+ const results = {};
70
+ const allErrors = [];
71
+ const shouldPushAll = options.all === true;
72
+ // Push settings
73
+ if ((shouldPushAll || options.settings) &&
74
+ (config.projectName || config.settings)) {
75
+ try {
76
+ this.log("Pushing settings ...");
77
+ await this.pushSettings({
78
+ projectId: config.projectId,
79
+ projectName: config.projectName,
80
+ settings: config.settings,
81
+ });
82
+ this.success(`Successfully pushed ${chalk.bold("all")} project settings.`);
83
+ results.settings = { success: true };
84
+ }
85
+ catch (e) {
86
+ allErrors.push(e);
87
+ results.settings = { success: false, error: e.message };
88
+ }
38
89
  }
39
- if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
40
- let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
41
- if (steps > 1 && iteration === 1) {
42
- pollMaxDebounces *= steps;
43
- log("Found a large number of attributes, increasing timeout to " +
44
- (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 +
45
- " minutes");
90
+ // Push buckets
91
+ if ((shouldPushAll || options.buckets) &&
92
+ config.buckets &&
93
+ config.buckets.length > 0) {
94
+ try {
95
+ this.log("Pushing buckets ...");
96
+ const result = await this.pushBuckets(config.buckets);
97
+ this.success(`Successfully pushed ${chalk.bold(result.successfullyPushed)} buckets.`);
98
+ results.buckets = result;
99
+ allErrors.push(...result.errors);
100
+ }
101
+ catch (e) {
102
+ allErrors.push(e);
103
+ results.buckets = { successfullyPushed: 0, errors: [e] };
46
104
  }
47
105
  }
48
- await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE));
49
- return await awaitPools.wipeAttributes(databaseId, collectionId, iteration + 1);
50
- },
51
- wipeIndexes: async (databaseId, collectionId, iteration = 1) => {
52
- if (iteration > pollMaxDebounces) {
53
- return false;
106
+ // Push teams
107
+ if ((shouldPushAll || options.teams) &&
108
+ config.teams &&
109
+ config.teams.length > 0) {
110
+ try {
111
+ this.log("Pushing teams ...");
112
+ const result = await this.pushTeams(config.teams);
113
+ this.success(`Successfully pushed ${chalk.bold(result.successfullyPushed)} teams.`);
114
+ results.teams = result;
115
+ allErrors.push(...result.errors);
116
+ }
117
+ catch (e) {
118
+ allErrors.push(e);
119
+ results.teams = { successfullyPushed: 0, errors: [e] };
120
+ }
54
121
  }
55
- const databasesService = await getDatabasesService();
56
- const response = await databasesService.listIndexes(databaseId, collectionId, [JSON.stringify({ method: "limit", values: [1] })]);
57
- const { total } = response;
58
- if (total === 0) {
59
- return true;
122
+ // Push messaging topics
123
+ if ((shouldPushAll || options.topics) &&
124
+ config.topics &&
125
+ config.topics.length > 0) {
126
+ try {
127
+ this.log("Pushing topics ...");
128
+ const result = await this.pushMessagingTopics(config.topics);
129
+ this.success(`Successfully pushed ${chalk.bold(result.successfullyPushed)} topics.`);
130
+ results.topics = result;
131
+ allErrors.push(...result.errors);
132
+ }
133
+ catch (e) {
134
+ allErrors.push(e);
135
+ results.topics = { successfullyPushed: 0, errors: [e] };
136
+ }
60
137
  }
61
- if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
62
- let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
63
- if (steps > 1 && iteration === 1) {
64
- pollMaxDebounces *= steps;
65
- log("Found a large number of indexes, increasing timeout to " +
66
- (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 +
67
- " minutes");
138
+ // Push functions
139
+ if ((shouldPushAll || options.functions) &&
140
+ config.functions &&
141
+ config.functions.length > 0) {
142
+ try {
143
+ this.log("Pushing functions ...");
144
+ const result = await this.pushFunctions(config.functions, options.functionOptions);
145
+ this.success(`Successfully pushed ${chalk.bold(result.successfullyPushed)} functions.`);
146
+ results.functions = result;
147
+ allErrors.push(...result.errors);
148
+ }
149
+ catch (e) {
150
+ allErrors.push(e);
151
+ results.functions = {
152
+ successfullyPushed: 0,
153
+ successfullyDeployed: 0,
154
+ failedDeployments: [],
155
+ errors: [e],
156
+ };
68
157
  }
69
158
  }
70
- await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE));
71
- return await awaitPools.wipeIndexes(databaseId, collectionId, iteration + 1);
72
- },
73
- deleteAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
74
- if (iteration > pollMaxDebounces) {
75
- return false;
159
+ // Push sites
160
+ if ((shouldPushAll || options.sites) &&
161
+ config.sites &&
162
+ config.sites.length > 0) {
163
+ try {
164
+ this.log("Pushing sites ...");
165
+ const result = await this.pushSites(config.sites, options.siteOptions);
166
+ this.success(`Successfully pushed ${chalk.bold(result.successfullyPushed)} sites.`);
167
+ results.sites = result;
168
+ allErrors.push(...result.errors);
169
+ }
170
+ catch (e) {
171
+ allErrors.push(e);
172
+ results.sites = {
173
+ successfullyPushed: 0,
174
+ successfullyDeployed: 0,
175
+ failedDeployments: [],
176
+ errors: [e],
177
+ };
178
+ }
76
179
  }
77
- if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
78
- let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
79
- if (steps > 1 && iteration === 1) {
80
- pollMaxDebounces *= steps;
81
- log("Found a large number of attributes to be deleted. Increasing timeout to " +
82
- (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 +
83
- " minutes");
180
+ // Push tables
181
+ if ((shouldPushAll || options.tables) &&
182
+ config.tables &&
183
+ config.tables.length > 0) {
184
+ try {
185
+ this.log("Pushing tables ...");
186
+ const result = await this.pushTables(config.tables, {
187
+ attempts: options.tableOptions?.attempts,
188
+ skipConfirmation: options.skipConfirmation,
189
+ });
190
+ this.success(`Successfully pushed ${chalk.bold(result.successfullyPushed)} tables.`);
191
+ results.tables = result;
192
+ allErrors.push(...result.errors);
193
+ }
194
+ catch (e) {
195
+ allErrors.push(e);
196
+ results.tables = { successfullyPushed: 0, errors: [e] };
84
197
  }
85
198
  }
86
- const { attributes } = await paginate(async (args) => {
87
- const databasesService = await getDatabasesService();
88
- return await databasesService.listAttributes(args.databaseId, args.collectionId, args.queries || []);
89
- }, {
90
- databaseId,
91
- collectionId,
92
- }, 100, "attributes");
93
- const ready = attributeKeys.filter((attribute) => attributes.includes(attribute.key));
94
- if (ready.length === 0) {
95
- return true;
199
+ // Push collections (skipDeprecated only applies when pushing all, explicit collections option takes precedence)
200
+ if ((options.collections || (shouldPushAll && !skipDeprecated)) &&
201
+ config.collections &&
202
+ config.collections.length > 0) {
203
+ try {
204
+ this.log("Pushing collections ...");
205
+ // Add database names to collections
206
+ const collectionsWithDbNames = config.collections.map((collection) => {
207
+ const database = config.databases?.find((db) => db.$id === collection.databaseId);
208
+ return {
209
+ ...collection,
210
+ databaseName: database?.name ?? collection.databaseId,
211
+ };
212
+ });
213
+ const result = await this.pushCollections(collectionsWithDbNames, {
214
+ skipConfirmation: options.skipConfirmation,
215
+ });
216
+ this.success(`Successfully pushed ${chalk.bold(result.successfullyPushed)} collections.`);
217
+ results.collections = result;
218
+ allErrors.push(...result.errors);
219
+ }
220
+ catch (e) {
221
+ allErrors.push(e);
222
+ results.collections = { successfullyPushed: 0, errors: [e] };
223
+ }
96
224
  }
97
- await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE));
98
- return await awaitPools.expectAttributes(databaseId, collectionId, attributeKeys, iteration + 1);
99
- },
100
- expectAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
101
- if (iteration > pollMaxDebounces) {
102
- return false;
225
+ return {
226
+ results,
227
+ errors: allErrors,
228
+ };
229
+ }
230
+ async pushSettings(config) {
231
+ const projectsService = await getProjectsService(this.consoleClient);
232
+ const projectId = config.projectId;
233
+ const projectName = config.projectName;
234
+ const settings = config.settings ?? {};
235
+ if (projectName) {
236
+ this.log("Applying project name ...");
237
+ await projectsService.update({
238
+ projectId: projectId,
239
+ name: projectName,
240
+ });
103
241
  }
104
- if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
105
- let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
106
- if (steps > 1 && iteration === 1) {
107
- pollMaxDebounces *= steps;
108
- log("Creating a large number of attributes, increasing timeout to " +
109
- (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 +
110
- " minutes");
242
+ if (settings.services) {
243
+ this.log("Applying service statuses ...");
244
+ for (let [service, status] of Object.entries(settings.services)) {
245
+ await projectsService.updateServiceStatus({
246
+ projectId: projectId,
247
+ service: service,
248
+ status: status,
249
+ });
111
250
  }
112
251
  }
113
- const { attributes } = await paginate(async (args) => {
114
- const databasesService = await getDatabasesService();
115
- return await databasesService.listAttributes(args.databaseId, args.collectionId, args.queries || []);
116
- }, {
117
- databaseId,
118
- collectionId,
119
- }, 100, "attributes");
120
- const ready = attributes
121
- .filter((attribute) => {
122
- if (attributeKeys.includes(attribute.key)) {
123
- if (["stuck", "failed"].includes(attribute.status)) {
124
- throw new Error(`Attribute '${attribute.key}' failed!`);
252
+ if (settings.auth) {
253
+ if (settings.auth.security) {
254
+ this.log("Applying auth security settings ...");
255
+ await projectsService.updateAuthDuration({
256
+ projectId,
257
+ duration: settings.auth.security.duration,
258
+ });
259
+ await projectsService.updateAuthLimit({
260
+ projectId,
261
+ limit: settings.auth.security.limit,
262
+ });
263
+ await projectsService.updateAuthSessionsLimit({
264
+ projectId,
265
+ limit: settings.auth.security.sessionsLimit,
266
+ });
267
+ await projectsService.updateAuthPasswordDictionary({
268
+ projectId,
269
+ enabled: settings.auth.security.passwordDictionary,
270
+ });
271
+ await projectsService.updateAuthPasswordHistory({
272
+ projectId,
273
+ limit: settings.auth.security.passwordHistory,
274
+ });
275
+ await projectsService.updatePersonalDataCheck({
276
+ projectId,
277
+ enabled: settings.auth.security.personalDataCheck,
278
+ });
279
+ await projectsService.updateSessionAlerts({
280
+ projectId,
281
+ alerts: settings.auth.security.sessionAlerts,
282
+ });
283
+ await projectsService.updateMockNumbers({
284
+ projectId,
285
+ numbers: settings.auth.security.mockNumbers,
286
+ });
287
+ }
288
+ if (settings.auth.methods) {
289
+ this.log("Applying auth methods statuses ...");
290
+ for (let [method, status] of Object.entries(settings.auth.methods)) {
291
+ await projectsService.updateAuthStatus({
292
+ projectId,
293
+ method: method,
294
+ status: status,
295
+ });
125
296
  }
126
- return attribute.status === "available";
127
297
  }
128
- return false;
129
- })
130
- .map((attribute) => attribute.key);
131
- if (ready.length === attributeKeys.length) {
132
- return true;
133
- }
134
- await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE));
135
- return await awaitPools.expectAttributes(databaseId, collectionId, attributeKeys, iteration + 1);
136
- },
137
- deleteIndexes: async (databaseId, collectionId, indexesKeys, iteration = 1) => {
138
- if (iteration > pollMaxDebounces) {
139
- return false;
140
298
  }
141
- if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
142
- let steps = Math.max(1, Math.ceil(indexesKeys.length / STEP_SIZE));
143
- if (steps > 1 && iteration === 1) {
144
- pollMaxDebounces *= steps;
145
- log("Found a large number of indexes to be deleted. Increasing timeout to " +
146
- (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 +
147
- " minutes");
299
+ }
300
+ async pushBuckets(buckets) {
301
+ let successfullyPushed = 0;
302
+ const errors = [];
303
+ for (const bucket of buckets) {
304
+ try {
305
+ this.log(`Pushing bucket ${chalk.bold(bucket["name"])} ...`);
306
+ const storageService = await getStorageService(this.projectClient);
307
+ try {
308
+ await storageService.getBucket(bucket["$id"]);
309
+ await storageService.updateBucket({
310
+ bucketId: bucket["$id"],
311
+ name: bucket.name,
312
+ permissions: bucket["$permissions"],
313
+ fileSecurity: bucket.fileSecurity,
314
+ enabled: bucket.enabled,
315
+ maximumFileSize: bucket.maximumFileSize,
316
+ allowedFileExtensions: bucket.allowedFileExtensions,
317
+ encryption: bucket.encryption,
318
+ antivirus: bucket.antivirus,
319
+ compression: bucket.compression,
320
+ });
321
+ }
322
+ catch (e) {
323
+ if (e instanceof AppwriteException && Number(e.code) === 404) {
324
+ await storageService.createBucket({
325
+ bucketId: bucket["$id"],
326
+ name: bucket.name,
327
+ permissions: bucket["$permissions"],
328
+ fileSecurity: bucket.fileSecurity,
329
+ enabled: bucket.enabled,
330
+ maximumFileSize: bucket.maximumFileSize,
331
+ allowedFileExtensions: bucket.allowedFileExtensions,
332
+ compression: bucket.compression,
333
+ encryption: bucket.encryption,
334
+ antivirus: bucket.antivirus,
335
+ });
336
+ }
337
+ else {
338
+ throw e;
339
+ }
340
+ }
341
+ successfullyPushed++;
148
342
  }
149
- }
150
- const { indexes } = await paginate(async (args) => {
151
- const databasesService = await getDatabasesService();
152
- return await databasesService.listIndexes(args.databaseId, args.collectionId, args.queries || []);
153
- }, {
154
- databaseId,
155
- collectionId,
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
- log("Creating a large number of indexes, increasing timeout to " +
173
- (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 +
174
- " minutes");
343
+ catch (e) {
344
+ errors.push(e);
345
+ this.error(`Failed to push bucket ${bucket["name"]}: ${e.message}`);
175
346
  }
176
347
  }
177
- const { indexes } = await paginate(async (args) => {
178
- const databasesService = await getDatabasesService();
179
- return await databasesService.listIndexes(args.databaseId, args.collectionId, args.queries || []);
180
- }, {
181
- databaseId,
182
- collectionId,
183
- }, 100, "indexes");
184
- const ready = indexes
185
- .filter((index) => {
186
- if (indexKeys.includes(index.key)) {
187
- if (["stuck", "failed"].includes(index.status)) {
188
- throw new Error(`Index '${index.key}' failed!`);
348
+ return {
349
+ successfullyPushed,
350
+ errors,
351
+ };
352
+ }
353
+ async pushTeams(teams) {
354
+ let successfullyPushed = 0;
355
+ const errors = [];
356
+ for (const team of teams) {
357
+ try {
358
+ this.log(`Pushing team ${chalk.bold(team["name"])} ...`);
359
+ const teamsService = await getTeamsService(this.projectClient);
360
+ try {
361
+ await teamsService.get(team["$id"]);
362
+ await teamsService.updateName({
363
+ teamId: team["$id"],
364
+ name: team.name,
365
+ });
366
+ }
367
+ catch (e) {
368
+ if (e instanceof AppwriteException && Number(e.code) === 404) {
369
+ await teamsService.create({
370
+ teamId: team["$id"],
371
+ name: team.name,
372
+ });
373
+ }
374
+ else {
375
+ throw e;
376
+ }
189
377
  }
190
- return index.status === "available";
378
+ successfullyPushed++;
379
+ }
380
+ catch (e) {
381
+ errors.push(e);
382
+ this.error(`Failed to push team ${team["name"]}: ${e.message}`);
191
383
  }
192
- return false;
193
- })
194
- .map((index) => index.key);
195
- if (ready.length >= indexKeys.length) {
196
- return true;
197
- }
198
- await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE));
199
- return await awaitPools.expectIndexes(databaseId, collectionId, indexKeys, iteration + 1);
200
- },
201
- };
202
- const getConfirmation = async () => {
203
- if (cliConfig.force) {
204
- return true;
205
- }
206
- async function fixConfirmation() {
207
- const answers = await inquirer.prompt(questionPushChangesConfirmation);
208
- if (answers.changes !== "YES" && answers.changes !== "NO") {
209
- return await fixConfirmation();
210
384
  }
211
- return answers.changes;
212
- }
213
- let answers = await inquirer.prompt(questionPushChanges);
214
- if (answers.changes !== "YES" && answers.changes !== "NO") {
215
- answers.changes = await fixConfirmation();
216
- }
217
- if (answers.changes === "YES") {
218
- return true;
385
+ return {
386
+ successfullyPushed,
387
+ errors,
388
+ };
219
389
  }
220
- warn("Skipping push action. Changes were not applied.");
221
- return false;
222
- };
223
- const isEmpty = (value) => value === null ||
224
- value === undefined ||
225
- (typeof value === "string" && value.trim().length === 0) ||
226
- (Array.isArray(value) && value.length === 0);
227
- const approveChanges = async (resource, resourceGetFunction, keys, resourceName, resourcePlural, skipKeys = [], secondId = "", secondResourceName = "") => {
228
- log("Checking for changes ...");
229
- const changes = [];
230
- await Promise.all(resource.map(async (localResource) => {
231
- try {
232
- const options = {
233
- [resourceName]: localResource["$id"],
234
- };
235
- if (secondId !== "" && secondResourceName !== "") {
236
- options[secondResourceName] = localResource[secondId];
390
+ async pushMessagingTopics(topics) {
391
+ let successfullyPushed = 0;
392
+ const errors = [];
393
+ for (const topic of topics) {
394
+ try {
395
+ this.log(`Pushing topic ${chalk.bold(topic["name"])} ...`);
396
+ const messagingService = await getMessagingService(this.projectClient);
397
+ try {
398
+ await messagingService.getTopic(topic["$id"]);
399
+ await messagingService.updateTopic({
400
+ topicId: topic["$id"],
401
+ name: topic.name,
402
+ subscribe: topic.subscribe,
403
+ });
404
+ }
405
+ catch (e) {
406
+ if (e instanceof AppwriteException && Number(e.code) === 404) {
407
+ await messagingService.createTopic({
408
+ topicId: topic["$id"],
409
+ name: topic.name,
410
+ subscribe: topic.subscribe,
411
+ });
412
+ }
413
+ else {
414
+ throw e;
415
+ }
416
+ }
417
+ this.success(`Pushed ${topic.name} ( ${topic["$id"]} )`);
418
+ successfullyPushed++;
237
419
  }
238
- const remoteResource = await resourceGetFunction(options);
239
- for (let [key, value] of Object.entries(whitelistKeys(remoteResource, keys))) {
240
- if (skipKeys.includes(key)) {
241
- continue;
420
+ catch (e) {
421
+ errors.push(e);
422
+ this.error(`Failed to push topic ${topic["name"]}: ${e.message}`);
423
+ }
424
+ }
425
+ return {
426
+ successfullyPushed,
427
+ errors,
428
+ };
429
+ }
430
+ async pushFunctions(functions, options = {}) {
431
+ const { async: asyncDeploy, code, withVariables } = options;
432
+ Spinner.start(false);
433
+ let successfullyPushed = 0;
434
+ let successfullyDeployed = 0;
435
+ const failedDeployments = [];
436
+ const errors = [];
437
+ await Promise.all(functions.map(async (func) => {
438
+ let response = {};
439
+ const ignore = func.ignore ? "appwrite.config.json" : ".gitignore";
440
+ let functionExists = false;
441
+ let deploymentCreated = false;
442
+ const updaterRow = new Spinner({
443
+ status: "",
444
+ resource: func.name,
445
+ id: func["$id"],
446
+ end: `Ignoring using: ${ignore}`,
447
+ });
448
+ updaterRow.update({ status: "Getting" }).startSpinner(SPINNER_DOTS);
449
+ const functionsService = await getFunctionsService(this.projectClient);
450
+ try {
451
+ response = await functionsService.get({ functionId: func["$id"] });
452
+ functionExists = true;
453
+ if (response.runtime !== func.runtime) {
454
+ updaterRow.fail({
455
+ errorMessage: `Runtime mismatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.config.json`,
456
+ });
457
+ return;
242
458
  }
243
- if (isEmpty(value) && isEmpty(localResource[key])) {
244
- continue;
459
+ updaterRow
460
+ .update({ status: "Updating" })
461
+ .replaceSpinner(SPINNER_DOTS);
462
+ response = await functionsService.update({
463
+ functionId: func["$id"],
464
+ name: func.name,
465
+ runtime: func.runtime,
466
+ execute: func.execute,
467
+ events: func.events,
468
+ schedule: func.schedule,
469
+ timeout: func.timeout,
470
+ enabled: func.enabled,
471
+ logging: func.logging,
472
+ entrypoint: func.entrypoint,
473
+ commands: func.commands,
474
+ scopes: func.scopes,
475
+ specification: func.specification,
476
+ });
477
+ }
478
+ catch (e) {
479
+ if (Number(e.code) === 404) {
480
+ functionExists = false;
245
481
  }
246
- if (Array.isArray(value) && Array.isArray(localResource[key])) {
247
- if (JSON.stringify(value) !== JSON.stringify(localResource[key])) {
248
- changes.push({
249
- id: localResource["$id"],
250
- key,
251
- remote: chalk.red(value.join("\n")),
252
- local: chalk.green(localResource[key].join("\n")),
253
- });
482
+ else {
483
+ errors.push(e);
484
+ updaterRow.fail({
485
+ errorMessage: e.message ?? "General error occurs please try again",
486
+ });
487
+ return;
488
+ }
489
+ }
490
+ if (!functionExists) {
491
+ updaterRow
492
+ .update({ status: "Creating" })
493
+ .replaceSpinner(SPINNER_DOTS);
494
+ try {
495
+ response = await functionsService.create({
496
+ functionId: func.$id,
497
+ name: func.name,
498
+ runtime: func.runtime,
499
+ execute: func.execute,
500
+ events: func.events,
501
+ schedule: func.schedule,
502
+ timeout: func.timeout,
503
+ enabled: func.enabled,
504
+ logging: func.logging,
505
+ entrypoint: func.entrypoint,
506
+ commands: func.commands,
507
+ scopes: func.scopes,
508
+ specification: func.specification,
509
+ });
510
+ let domain = "";
511
+ try {
512
+ const consoleService = await getConsoleService(this.consoleClient);
513
+ const variables = await consoleService.variables();
514
+ domain = ID.unique() + "." + variables["_APP_DOMAIN_FUNCTIONS"];
515
+ }
516
+ catch (err) {
517
+ this.error("Error fetching console variables.");
518
+ throw err;
519
+ }
520
+ try {
521
+ const proxyService = await getProxyService(this.projectClient);
522
+ await proxyService.createFunctionRule(domain, func.$id);
523
+ }
524
+ catch (err) {
525
+ this.error("Error creating function rule.");
526
+ throw err;
254
527
  }
528
+ updaterRow.update({ status: "Created" });
255
529
  }
256
- else if (value !== localResource[key]) {
257
- changes.push({
258
- id: localResource["$id"],
259
- key,
260
- remote: chalk.red(value),
261
- local: chalk.green(localResource[key]),
530
+ catch (e) {
531
+ errors.push(e);
532
+ updaterRow.fail({
533
+ errorMessage: e.message ?? "General error occurs please try again",
262
534
  });
535
+ return;
263
536
  }
264
537
  }
265
- }
266
- catch (e) {
267
- if (Number(e.code) !== 404) {
268
- throw e;
538
+ if (withVariables) {
539
+ updaterRow
540
+ .update({ status: "Updating variables" })
541
+ .replaceSpinner(SPINNER_DOTS);
542
+ const functionsServiceForVars = await getFunctionsService(this.projectClient);
543
+ const { variables } = await paginate(async (args) => {
544
+ return await functionsServiceForVars.listVariables({
545
+ functionId: args.functionId,
546
+ });
547
+ }, {
548
+ functionId: func["$id"],
549
+ }, 100, "variables");
550
+ await Promise.all(variables.map(async (variable) => {
551
+ const functionsServiceDel = await getFunctionsService(this.projectClient);
552
+ await functionsServiceDel.deleteVariable({
553
+ functionId: func["$id"],
554
+ variableId: variable["$id"],
555
+ });
556
+ }));
557
+ const envFileLocation = `${func["path"]}/.env`;
558
+ let envVariables = [];
559
+ try {
560
+ if (fs.existsSync(envFileLocation)) {
561
+ const envObject = parseDotenv(fs.readFileSync(envFileLocation, "utf8"));
562
+ envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
563
+ }
564
+ }
565
+ catch (error) {
566
+ envVariables = [];
567
+ }
568
+ await Promise.all(envVariables.map(async (variable) => {
569
+ const functionsServiceCreate = await getFunctionsService(this.projectClient);
570
+ await functionsServiceCreate.createVariable({
571
+ functionId: func["$id"],
572
+ key: variable.key,
573
+ value: variable.value,
574
+ secret: false,
575
+ });
576
+ }));
269
577
  }
270
- }
271
- }));
272
- if (changes.length === 0) {
273
- return true;
274
- }
275
- drawTable(changes);
276
- if ((await getConfirmation()) === true) {
277
- return true;
278
- }
279
- success(`Successfully pushed 0 ${resourcePlural}.`);
280
- return false;
281
- };
282
- const getObjectChanges = (remote, local, index, what) => {
283
- const changes = [];
284
- const remoteNested = remote[index];
285
- const localNested = local[index];
286
- if (remoteNested &&
287
- localNested &&
288
- typeof remoteNested === "object" &&
289
- !Array.isArray(remoteNested) &&
290
- typeof localNested === "object" &&
291
- !Array.isArray(localNested)) {
292
- const remoteObj = remoteNested;
293
- const localObj = localNested;
294
- for (const [service, status] of Object.entries(remoteObj)) {
295
- const localValue = localObj[service];
296
- let valuesEqual = false;
297
- if (Array.isArray(status) && Array.isArray(localValue)) {
298
- valuesEqual = JSON.stringify(status) === JSON.stringify(localValue);
578
+ if (code === false) {
579
+ successfullyPushed++;
580
+ successfullyDeployed++;
581
+ updaterRow.update({ status: "Pushed" });
582
+ updaterRow.stopSpinner();
583
+ return;
299
584
  }
300
- else {
301
- valuesEqual = status === localValue;
585
+ try {
586
+ updaterRow.update({ status: "Pushing" }).replaceSpinner(SPINNER_DOTS);
587
+ const functionsServiceDeploy = await getFunctionsService(this.projectClient);
588
+ const result = await pushDeployment({
589
+ resourcePath: func.path,
590
+ createDeployment: async (codeFile) => {
591
+ return await functionsServiceDeploy.createDeployment({
592
+ functionId: func["$id"],
593
+ entrypoint: func.entrypoint,
594
+ commands: func.commands,
595
+ code: codeFile,
596
+ activate: true,
597
+ });
598
+ },
599
+ pollForStatus: false,
600
+ });
601
+ response = result.deployment;
602
+ updaterRow.update({ status: "Pushed" });
603
+ deploymentCreated = true;
604
+ successfullyPushed++;
605
+ }
606
+ catch (e) {
607
+ errors.push(e);
608
+ switch (e.code) {
609
+ case "ENOENT":
610
+ updaterRow.fail({
611
+ errorMessage: "Not found in the current directory. Skipping...",
612
+ });
613
+ break;
614
+ default:
615
+ updaterRow.fail({
616
+ errorMessage: e.message ?? "An unknown error occurred. Please try again.",
617
+ });
618
+ }
302
619
  }
303
- if (!valuesEqual) {
304
- changes.push({
305
- group: what,
306
- setting: service,
307
- remote: chalk.red(String(status ?? "")),
308
- local: chalk.green(String(localValue ?? "")),
620
+ if (deploymentCreated && !asyncDeploy) {
621
+ try {
622
+ const deploymentId = response["$id"];
623
+ updaterRow.update({
624
+ status: "Deploying",
625
+ end: "Checking deployment status...",
626
+ });
627
+ const timeoutDeadline = Date.now() + DEPLOYMENT_TIMEOUT_MS;
628
+ while (true) {
629
+ if (Date.now() > timeoutDeadline) {
630
+ failedDeployments.push({
631
+ name: func["name"],
632
+ $id: func["$id"],
633
+ deployment: deploymentId,
634
+ });
635
+ updaterRow.fail({
636
+ errorMessage: "Deployment timed out after 10 minutes",
637
+ });
638
+ break;
639
+ }
640
+ const functionsServicePoll = await getFunctionsService(this.projectClient);
641
+ response = await functionsServicePoll.getDeployment({
642
+ functionId: func["$id"],
643
+ deploymentId: deploymentId,
644
+ });
645
+ const status = response["status"];
646
+ if (status === "ready") {
647
+ successfullyDeployed++;
648
+ let url = "";
649
+ const proxyServiceUrl = await getProxyService(this.projectClient);
650
+ const res = await proxyServiceUrl.listRules({
651
+ queries: [
652
+ Query.limit(1),
653
+ Query.equal("deploymentResourceType", "function"),
654
+ Query.equal("deploymentResourceId", func["$id"]),
655
+ Query.equal("trigger", "manual"),
656
+ ],
657
+ });
658
+ if (Number(res.total) === 1) {
659
+ url = `https://${res.rules[0].domain}`;
660
+ }
661
+ updaterRow.update({ status: "Deployed", end: url });
662
+ break;
663
+ }
664
+ else if (status === "failed") {
665
+ failedDeployments.push({
666
+ name: func["name"],
667
+ $id: func["$id"],
668
+ deployment: response["$id"],
669
+ });
670
+ updaterRow.fail({ errorMessage: `Failed to deploy` });
671
+ break;
672
+ }
673
+ else {
674
+ updaterRow.update({
675
+ status: "Deploying",
676
+ end: `Current status: ${status}`,
677
+ });
678
+ }
679
+ await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE));
680
+ }
681
+ }
682
+ catch (e) {
683
+ errors.push(e);
684
+ updaterRow.fail({
685
+ errorMessage: e.message ?? "Unknown error occurred. Please try again",
686
+ });
687
+ }
688
+ }
689
+ updaterRow.stopSpinner();
690
+ }));
691
+ Spinner.stop();
692
+ return {
693
+ successfullyPushed,
694
+ successfullyDeployed,
695
+ failedDeployments,
696
+ errors,
697
+ };
698
+ }
699
+ async pushSites(sites, options = {}) {
700
+ const { async: asyncDeploy, code, withVariables } = options;
701
+ Spinner.start(false);
702
+ let successfullyPushed = 0;
703
+ let successfullyDeployed = 0;
704
+ const failedDeployments = [];
705
+ const errors = [];
706
+ await Promise.all(sites.map(async (site) => {
707
+ let response = {};
708
+ const ignore = site.ignore ? "appwrite.config.json" : ".gitignore";
709
+ let siteExists = false;
710
+ let deploymentCreated = false;
711
+ const updaterRow = new Spinner({
712
+ status: "",
713
+ resource: site.name,
714
+ id: site["$id"],
715
+ end: `Ignoring using: ${ignore}`,
716
+ });
717
+ updaterRow.update({ status: "Getting" }).startSpinner(SPINNER_DOTS);
718
+ const sitesService = await getSitesService(this.projectClient);
719
+ try {
720
+ response = await sitesService.get({ siteId: site["$id"] });
721
+ siteExists = true;
722
+ if (response.framework !== site.framework) {
723
+ updaterRow.fail({
724
+ errorMessage: `Framework mismatch! (local=${site.framework},remote=${response.framework}) Please delete remote site or update your appwrite.config.json`,
725
+ });
726
+ return;
727
+ }
728
+ updaterRow
729
+ .update({ status: "Updating" })
730
+ .replaceSpinner(SPINNER_DOTS);
731
+ response = await sitesService.update({
732
+ siteId: site["$id"],
733
+ name: site.name,
734
+ framework: site.framework,
735
+ enabled: site.enabled,
736
+ logging: site.logging,
737
+ timeout: site.timeout,
738
+ installCommand: site.installCommand,
739
+ buildCommand: site.buildCommand,
740
+ outputDirectory: site.outputDirectory,
741
+ buildRuntime: site.buildRuntime,
742
+ adapter: site.adapter,
743
+ specification: site.specification,
309
744
  });
310
745
  }
311
- }
312
- }
313
- return changes;
314
- };
315
- const createAttribute = async (databaseId, collectionId, attribute) => {
316
- const databasesService = await getDatabasesService();
317
- switch (attribute.type) {
318
- case "string":
319
- switch (attribute.format) {
320
- case "email":
321
- return databasesService.createEmailAttribute({
322
- databaseId,
323
- collectionId,
324
- key: attribute.key,
325
- required: attribute.required,
326
- xdefault: attribute.default,
327
- array: attribute.array,
746
+ catch (e) {
747
+ if (Number(e.code) === 404) {
748
+ siteExists = false;
749
+ }
750
+ else {
751
+ errors.push(e);
752
+ updaterRow.fail({
753
+ errorMessage: e.message ?? "General error occurs please try again",
328
754
  });
329
- case "url":
330
- return databasesService.createUrlAttribute({
331
- databaseId,
332
- collectionId,
333
- key: attribute.key,
334
- required: attribute.required,
335
- xdefault: attribute.default,
336
- array: attribute.array,
755
+ return;
756
+ }
757
+ }
758
+ if (!siteExists) {
759
+ updaterRow
760
+ .update({ status: "Creating" })
761
+ .replaceSpinner(SPINNER_DOTS);
762
+ try {
763
+ response = await sitesService.create({
764
+ siteId: site.$id,
765
+ name: site.name,
766
+ framework: site.framework,
767
+ enabled: site.enabled,
768
+ logging: site.logging,
769
+ timeout: site.timeout,
770
+ installCommand: site.installCommand,
771
+ buildCommand: site.buildCommand,
772
+ outputDirectory: site.outputDirectory,
773
+ buildRuntime: site.buildRuntime,
774
+ adapter: site.adapter,
775
+ specification: site.specification,
337
776
  });
338
- case "ip":
339
- return databasesService.createIpAttribute({
340
- databaseId,
341
- collectionId,
342
- key: attribute.key,
343
- required: attribute.required,
344
- xdefault: attribute.default,
345
- array: attribute.array,
777
+ let domain = "";
778
+ try {
779
+ const consoleService = await getConsoleService(this.consoleClient);
780
+ const variables = await consoleService.variables();
781
+ domain = ID.unique() + "." + variables["_APP_DOMAIN_SITES"];
782
+ }
783
+ catch (err) {
784
+ this.error("Error fetching console variables.");
785
+ throw err;
786
+ }
787
+ try {
788
+ const proxyService = await getProxyService(this.projectClient);
789
+ await proxyService.createSiteRule(domain, site.$id);
790
+ }
791
+ catch (err) {
792
+ this.error("Error creating site rule.");
793
+ throw err;
794
+ }
795
+ updaterRow.update({ status: "Created" });
796
+ }
797
+ catch (e) {
798
+ errors.push(e);
799
+ updaterRow.fail({
800
+ errorMessage: e.message ?? "General error occurs please try again",
346
801
  });
347
- case "enum":
348
- return databasesService.createEnumAttribute({
349
- databaseId,
350
- collectionId,
351
- key: attribute.key,
352
- elements: attribute.elements,
353
- required: attribute.required,
354
- xdefault: attribute.default,
355
- array: attribute.array,
802
+ return;
803
+ }
804
+ }
805
+ if (withVariables) {
806
+ updaterRow
807
+ .update({ status: "Creating variables" })
808
+ .replaceSpinner(SPINNER_DOTS);
809
+ const sitesServiceForVars = await getSitesService(this.projectClient);
810
+ const { variables } = await paginate(async (args) => {
811
+ return await sitesServiceForVars.listVariables({
812
+ siteId: args.siteId,
356
813
  });
357
- default:
358
- return databasesService.createStringAttribute({
359
- databaseId,
360
- collectionId,
361
- key: attribute.key,
362
- size: attribute.size,
363
- required: attribute.required,
364
- xdefault: attribute.default,
365
- array: attribute.array,
366
- encrypt: attribute.encrypt,
814
+ }, {
815
+ siteId: site["$id"],
816
+ }, 100, "variables");
817
+ await Promise.all(variables.map(async (variable) => {
818
+ const sitesServiceDel = await getSitesService(this.projectClient);
819
+ await sitesServiceDel.deleteVariable({
820
+ siteId: site["$id"],
821
+ variableId: variable["$id"],
367
822
  });
823
+ }));
824
+ const envFileLocation = `${site["path"]}/.env`;
825
+ let envVariables = [];
826
+ try {
827
+ if (fs.existsSync(envFileLocation)) {
828
+ const envObject = parseDotenv(fs.readFileSync(envFileLocation, "utf8"));
829
+ envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
830
+ }
831
+ }
832
+ catch (error) {
833
+ envVariables = [];
834
+ }
835
+ await Promise.all(envVariables.map(async (variable) => {
836
+ const sitesServiceCreate = await getSitesService(this.projectClient);
837
+ await sitesServiceCreate.createVariable({
838
+ siteId: site["$id"],
839
+ key: variable.key,
840
+ value: variable.value,
841
+ secret: false,
842
+ });
843
+ }));
368
844
  }
369
- case "integer":
370
- return databasesService.createIntegerAttribute({
371
- databaseId,
372
- collectionId,
373
- key: attribute.key,
374
- required: attribute.required,
375
- min: attribute.min,
376
- max: attribute.max,
377
- xdefault: attribute.default,
378
- array: attribute.array,
379
- });
380
- case "double":
381
- return databasesService.createFloatAttribute({
382
- databaseId,
383
- collectionId,
384
- key: attribute.key,
385
- required: attribute.required,
386
- min: attribute.min,
387
- max: attribute.max,
388
- xdefault: attribute.default,
389
- array: attribute.array,
390
- });
391
- case "boolean":
392
- return databasesService.createBooleanAttribute({
393
- databaseId,
394
- collectionId,
395
- key: attribute.key,
396
- required: attribute.required,
397
- xdefault: attribute.default,
398
- array: attribute.array,
399
- });
400
- case "datetime":
401
- return databasesService.createDatetimeAttribute({
402
- databaseId,
403
- collectionId,
404
- key: attribute.key,
405
- required: attribute.required,
406
- xdefault: attribute.default,
407
- array: attribute.array,
408
- });
409
- case "relationship":
410
- return databasesService.createRelationshipAttribute({
411
- databaseId,
412
- collectionId,
413
- relatedCollectionId: attribute.relatedTable ?? attribute.relatedCollection,
414
- type: attribute.relationType,
415
- twoWay: attribute.twoWay,
416
- key: attribute.key,
417
- twoWayKey: attribute.twoWayKey,
418
- onDelete: attribute.onDelete,
419
- });
420
- case "point":
421
- return databasesService.createPointAttribute({
422
- databaseId,
423
- collectionId,
424
- key: attribute.key,
425
- required: attribute.required,
426
- xdefault: attribute.default,
427
- });
428
- case "linestring":
429
- return databasesService.createLineAttribute({
430
- databaseId,
431
- collectionId,
432
- key: attribute.key,
433
- required: attribute.required,
434
- xdefault: attribute.default,
435
- });
436
- case "polygon":
437
- return databasesService.createPolygonAttribute({
438
- databaseId,
439
- collectionId,
440
- key: attribute.key,
441
- required: attribute.required,
442
- xdefault: attribute.default,
443
- });
444
- default:
445
- throw new Error(`Unsupported attribute type: ${attribute.type}`);
446
- }
447
- };
448
- const updateAttribute = async (databaseId, collectionId, attribute) => {
449
- const databasesService = await getDatabasesService();
450
- switch (attribute.type) {
451
- case "string":
452
- switch (attribute.format) {
453
- case "email":
454
- return databasesService.updateEmailAttribute({
455
- databaseId,
456
- collectionId,
457
- key: attribute.key,
458
- required: attribute.required,
459
- xdefault: attribute.default,
845
+ if (code === false) {
846
+ successfullyPushed++;
847
+ successfullyDeployed++;
848
+ updaterRow.update({ status: "Pushed" });
849
+ updaterRow.stopSpinner();
850
+ return;
851
+ }
852
+ try {
853
+ updaterRow.update({ status: "Pushing" }).replaceSpinner(SPINNER_DOTS);
854
+ const sitesServiceDeploy = await getSitesService(this.projectClient);
855
+ const result = await pushDeployment({
856
+ resourcePath: site.path,
857
+ createDeployment: async (codeFile) => {
858
+ return await sitesServiceDeploy.createDeployment({
859
+ siteId: site["$id"],
860
+ installCommand: site.installCommand,
861
+ buildCommand: site.buildCommand,
862
+ outputDirectory: site.outputDirectory,
863
+ code: codeFile,
864
+ activate: true,
865
+ });
866
+ },
867
+ pollForStatus: false,
868
+ });
869
+ response = result.deployment;
870
+ updaterRow.update({ status: "Pushed" });
871
+ deploymentCreated = true;
872
+ successfullyPushed++;
873
+ }
874
+ catch (e) {
875
+ errors.push(e);
876
+ switch (e.code) {
877
+ case "ENOENT":
878
+ updaterRow.fail({
879
+ errorMessage: "Not found in the current directory. Skipping...",
880
+ });
881
+ break;
882
+ default:
883
+ updaterRow.fail({
884
+ errorMessage: e.message ?? "An unknown error occurred. Please try again.",
885
+ });
886
+ }
887
+ }
888
+ if (deploymentCreated && !asyncDeploy) {
889
+ try {
890
+ const deploymentId = response["$id"];
891
+ updaterRow.update({
892
+ status: "Deploying",
893
+ end: "Checking deployment status...",
460
894
  });
461
- case "url":
462
- return databasesService.updateUrlAttribute({
463
- databaseId,
464
- collectionId,
465
- key: attribute.key,
466
- required: attribute.required,
467
- xdefault: attribute.default,
895
+ const timeoutDeadline = Date.now() + DEPLOYMENT_TIMEOUT_MS;
896
+ while (true) {
897
+ if (Date.now() > timeoutDeadline) {
898
+ failedDeployments.push({
899
+ name: site["name"],
900
+ $id: site["$id"],
901
+ deployment: deploymentId,
902
+ });
903
+ updaterRow.fail({
904
+ errorMessage: "Deployment timed out after 10 minutes",
905
+ });
906
+ break;
907
+ }
908
+ const sitesServicePoll = await getSitesService(this.projectClient);
909
+ response = await sitesServicePoll.getDeployment({
910
+ siteId: site["$id"],
911
+ deploymentId: deploymentId,
912
+ });
913
+ const status = response["status"];
914
+ if (status === "ready") {
915
+ successfullyDeployed++;
916
+ let url = "";
917
+ const proxyServiceUrl = await getProxyService(this.projectClient);
918
+ const res = await proxyServiceUrl.listRules({
919
+ queries: [
920
+ Query.limit(1),
921
+ Query.equal("deploymentResourceType", "site"),
922
+ Query.equal("deploymentResourceId", site["$id"]),
923
+ Query.equal("trigger", "manual"),
924
+ ],
925
+ });
926
+ if (Number(res.total) === 1) {
927
+ url = `https://${res.rules[0].domain}`;
928
+ }
929
+ updaterRow.update({ status: "Deployed", end: url });
930
+ break;
931
+ }
932
+ else if (status === "failed") {
933
+ failedDeployments.push({
934
+ name: site["name"],
935
+ $id: site["$id"],
936
+ deployment: response["$id"],
937
+ });
938
+ updaterRow.fail({ errorMessage: `Failed to deploy` });
939
+ break;
940
+ }
941
+ else {
942
+ updaterRow.update({
943
+ status: "Deploying",
944
+ end: `Current status: ${status}`,
945
+ });
946
+ }
947
+ await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE));
948
+ }
949
+ }
950
+ catch (e) {
951
+ errors.push(e);
952
+ updaterRow.fail({
953
+ errorMessage: e.message ?? "Unknown error occurred. Please try again",
468
954
  });
469
- case "ip":
470
- return databasesService.updateIpAttribute({
471
- databaseId,
472
- collectionId,
473
- key: attribute.key,
474
- required: attribute.required,
475
- xdefault: attribute.default,
955
+ }
956
+ }
957
+ updaterRow.stopSpinner();
958
+ }));
959
+ Spinner.stop();
960
+ return {
961
+ successfullyPushed,
962
+ successfullyDeployed,
963
+ failedDeployments,
964
+ errors,
965
+ };
966
+ }
967
+ async pushTables(tables, options = {}) {
968
+ const { attempts, skipConfirmation = false } = options;
969
+ const pollMaxDebounces = attempts ?? POLL_DEFAULT_VALUE;
970
+ const pools = new Pools(pollMaxDebounces);
971
+ const attributes = new Attributes(pools, skipConfirmation);
972
+ let tablesChanged = new Set();
973
+ const errors = [];
974
+ // Parallel tables actions
975
+ await Promise.all(tables.map(async (table) => {
976
+ try {
977
+ const tablesService = await getTablesDBService(this.projectClient);
978
+ const remoteTable = await tablesService.getTable({
979
+ databaseId: table["databaseId"],
980
+ tableId: table["$id"],
981
+ });
982
+ const changes = [];
983
+ if (remoteTable.name !== table.name)
984
+ changes.push("name");
985
+ if (remoteTable.rowSecurity !== table.rowSecurity)
986
+ changes.push("rowSecurity");
987
+ if (remoteTable.enabled !== table.enabled)
988
+ changes.push("enabled");
989
+ if (JSON.stringify(remoteTable["$permissions"]) !==
990
+ JSON.stringify(table["$permissions"]))
991
+ changes.push("permissions");
992
+ if (changes.length > 0) {
993
+ await tablesService.updateTable({
994
+ databaseId: table["databaseId"],
995
+ tableId: table["$id"],
996
+ name: table.name,
997
+ rowSecurity: table.rowSecurity,
998
+ permissions: table["$permissions"],
476
999
  });
477
- case "enum":
478
- return databasesService.updateEnumAttribute({
479
- databaseId,
480
- collectionId,
481
- key: attribute.key,
482
- elements: attribute.elements,
483
- required: attribute.required,
484
- xdefault: attribute.default,
1000
+ this.success(`Updated ${table.name} ( ${table["$id"]} ) - ${changes.join(", ")}`);
1001
+ tablesChanged.add(table["$id"]);
1002
+ }
1003
+ table.remoteVersion = remoteTable;
1004
+ table.isExisted = true;
1005
+ }
1006
+ catch (e) {
1007
+ if (Number(e.code) === 404) {
1008
+ this.log(`Table ${table.name} does not exist in the project. Creating ... `);
1009
+ const tablesService = await getTablesDBService(this.projectClient);
1010
+ await tablesService.createTable({
1011
+ databaseId: table["databaseId"],
1012
+ tableId: table["$id"],
1013
+ name: table.name,
1014
+ rowSecurity: table.rowSecurity,
1015
+ permissions: table["$permissions"]
1016
+ ? [...table["$permissions"]]
1017
+ : undefined,
485
1018
  });
486
- default:
487
- return databasesService.updateStringAttribute({
488
- databaseId,
489
- collectionId,
490
- key: attribute.key,
491
- required: attribute.required,
492
- xdefault: attribute.default,
1019
+ this.success(`Created ${table.name} ( ${table["$id"]} )`);
1020
+ tablesChanged.add(table["$id"]);
1021
+ }
1022
+ else {
1023
+ errors.push(e);
1024
+ throw e;
1025
+ }
1026
+ }
1027
+ }));
1028
+ // Serialize attribute actions
1029
+ for (let table of tables) {
1030
+ let columns = table.columns;
1031
+ let indexes = table.indexes;
1032
+ if (table.isExisted) {
1033
+ columns = await attributes.attributesToCreate(table.remoteVersion.columns, table.columns, table);
1034
+ indexes = await attributes.attributesToCreate(table.remoteVersion.indexes, table.indexes, table, true);
1035
+ if (Array.isArray(columns) &&
1036
+ columns.length <= 0 &&
1037
+ Array.isArray(indexes) &&
1038
+ indexes.length <= 0) {
1039
+ continue;
1040
+ }
1041
+ }
1042
+ this.log(`Pushing table ${table.name} ( ${table["databaseId"]} - ${table["$id"]} ) attributes`);
1043
+ try {
1044
+ await attributes.createColumns(columns, table);
1045
+ }
1046
+ catch (e) {
1047
+ errors.push(e);
1048
+ throw e;
1049
+ }
1050
+ try {
1051
+ await attributes.createIndexes(indexes, table);
1052
+ }
1053
+ catch (e) {
1054
+ errors.push(e);
1055
+ throw e;
1056
+ }
1057
+ tablesChanged.add(table["$id"]);
1058
+ this.success(`Successfully pushed ${table.name} ( ${table["$id"]} )`);
1059
+ }
1060
+ return {
1061
+ successfullyPushed: tablesChanged.size,
1062
+ errors,
1063
+ };
1064
+ }
1065
+ async pushCollections(collections, options = {}) {
1066
+ const { skipConfirmation = false } = options;
1067
+ const pools = new Pools(POLL_DEFAULT_VALUE);
1068
+ const attributes = new Attributes(pools, skipConfirmation);
1069
+ const errors = [];
1070
+ const databases = Array.from(new Set(collections.map((collection) => collection["databaseId"])));
1071
+ // Parallel db actions
1072
+ await Promise.all(databases.map(async (databaseId) => {
1073
+ const databasesService = await getDatabasesService(this.projectClient);
1074
+ try {
1075
+ const database = await databasesService.get(databaseId);
1076
+ // Note: We can't get the local database name here since we don't have access to localConfig
1077
+ // This will need to be handled by the caller if needed
1078
+ const localDatabaseName = collections.find((c) => c.databaseId === databaseId)
1079
+ ?.databaseName ?? databaseId;
1080
+ if (database.name !== localDatabaseName) {
1081
+ await databasesService.update(databaseId, localDatabaseName);
1082
+ this.success(`Updated ${localDatabaseName} ( ${databaseId} ) name`);
1083
+ }
1084
+ }
1085
+ catch (err) {
1086
+ if (Number(err.code) === 404) {
1087
+ this.log(`Database ${databaseId} not found. Creating it now ...`);
1088
+ const localDatabaseName = collections.find((c) => c.databaseId === databaseId)
1089
+ ?.databaseName ?? databaseId;
1090
+ await databasesService.create(databaseId, localDatabaseName);
1091
+ }
1092
+ else {
1093
+ throw err;
1094
+ }
1095
+ }
1096
+ }));
1097
+ // Parallel collection actions
1098
+ await Promise.all(collections.map(async (collection) => {
1099
+ try {
1100
+ const databasesService = await getDatabasesService(this.projectClient);
1101
+ const remoteCollection = await databasesService.getCollection(collection["databaseId"], collection["$id"]);
1102
+ if (remoteCollection.name !== collection.name) {
1103
+ await databasesService.updateCollection(collection["databaseId"], collection["$id"], collection.name);
1104
+ this.success(`Updated ${collection.name} ( ${collection["$id"]} ) name`);
1105
+ }
1106
+ collection.remoteVersion = remoteCollection;
1107
+ collection.isExisted = true;
1108
+ }
1109
+ catch (e) {
1110
+ if (Number(e.code) === 404) {
1111
+ this.log(`Collection ${collection.name} does not exist in the project. Creating ... `);
1112
+ const databasesService = await getDatabasesService(this.projectClient);
1113
+ await databasesService.createCollection({
1114
+ databaseId: collection["databaseId"],
1115
+ collectionId: collection["$id"],
1116
+ name: collection.name,
1117
+ documentSecurity: collection.documentSecurity,
1118
+ permissions: collection["$permissions"],
493
1119
  });
1120
+ }
1121
+ else {
1122
+ errors.push(e);
1123
+ throw e;
1124
+ }
494
1125
  }
495
- case "integer":
496
- return databasesService.updateIntegerAttribute({
497
- databaseId,
498
- collectionId,
499
- key: attribute.key,
500
- required: attribute.required,
501
- min: attribute.min,
502
- max: attribute.max,
503
- xdefault: attribute.default,
504
- });
505
- case "double":
506
- return databasesService.updateFloatAttribute({
507
- databaseId,
508
- collectionId,
509
- key: attribute.key,
510
- required: attribute.required,
511
- min: attribute.min,
512
- max: attribute.max,
513
- xdefault: attribute.default,
514
- });
515
- case "boolean":
516
- return databasesService.updateBooleanAttribute({
517
- databaseId,
518
- collectionId,
519
- key: attribute.key,
520
- required: attribute.required,
521
- xdefault: attribute.default,
522
- });
523
- case "datetime":
524
- return databasesService.updateDatetimeAttribute({
525
- databaseId,
526
- collectionId,
527
- key: attribute.key,
528
- required: attribute.required,
529
- xdefault: attribute.default,
530
- });
531
- case "relationship":
532
- return databasesService.updateRelationshipAttribute({
533
- databaseId,
534
- collectionId,
535
- key: attribute.key,
536
- onDelete: attribute.onDelete,
537
- });
538
- case "point":
539
- return databasesService.updatePointAttribute({
540
- databaseId,
541
- collectionId,
542
- key: attribute.key,
543
- required: attribute.required,
544
- xdefault: attribute.default,
545
- });
546
- case "linestring":
547
- return databasesService.updateLineAttribute({
548
- databaseId,
549
- collectionId,
550
- key: attribute.key,
551
- required: attribute.required,
552
- xdefault: attribute.default,
553
- });
554
- case "polygon":
555
- return databasesService.updatePolygonAttribute({
556
- databaseId,
557
- collectionId,
558
- key: attribute.key,
559
- required: attribute.required,
560
- xdefault: attribute.default,
561
- });
562
- default:
563
- throw new Error(`Unsupported attribute type: ${attribute.type}`);
564
- }
565
- };
566
- const deleteAttribute = async (collection, attribute, isIndex = false) => {
567
- log(`Deleting ${isIndex ? "index" : "attribute"} ${attribute.key} of ${collection.name} ( ${collection["$id"]} )`);
568
- const databasesService = await getDatabasesService();
569
- if (isIndex) {
570
- await databasesService.deleteIndex(collection["databaseId"], collection["$id"], attribute.key);
571
- return;
572
- }
573
- await databasesService.deleteAttribute(collection["databaseId"], collection["$id"], attribute.key);
574
- };
575
- const isEqual = (a, b) => {
576
- if (a === b)
577
- return true;
578
- if (a && b && typeof a === "object" && typeof b === "object") {
579
- if (a.constructor &&
580
- a.constructor.name === "BigNumber" &&
581
- b.constructor &&
582
- b.constructor.name === "BigNumber") {
583
- return a.eq(b);
584
- }
585
- if (typeof a.equals === "function") {
586
- return a.equals(b);
587
- }
588
- if (typeof a.eq === "function") {
589
- return a.eq(b);
590
- }
591
- }
592
- if (typeof a === "number" && typeof b === "number") {
593
- if (isNaN(a) && isNaN(b))
594
- return true;
595
- if (!isFinite(a) && !isFinite(b))
596
- return a === b;
597
- return Math.abs(a - b) < Number.EPSILON;
598
- }
599
- return false;
600
- };
601
- const compareAttribute = (remote, local, reason, key) => {
602
- if (isEmpty(remote) && isEmpty(local)) {
603
- return reason;
604
- }
605
- if (Array.isArray(remote) && Array.isArray(local)) {
606
- if (JSON.stringify(remote) !== JSON.stringify(local)) {
607
- const bol = reason === "" ? "" : "\n";
608
- reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`;
609
- }
610
- }
611
- else if (!isEqual(remote, local)) {
612
- const bol = reason === "" ? "" : "\n";
613
- reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`;
614
- }
615
- return reason;
616
- };
617
- /**
618
- * Check if attribute non-changeable fields has been changed
619
- * If so return the differences as an object.
620
- */
621
- const checkAttributeChanges = (remote, local, collection, recreating = true) => {
622
- if (local === undefined) {
623
- return undefined;
624
- }
625
- const keyName = `${chalk.yellow(local.key)} in ${collection.name} (${collection["$id"]})`;
626
- const action = chalk.cyan(recreating ? "recreating" : "changing");
627
- let reason = "";
628
- let attribute = recreating ? remote : local;
629
- for (let key of Object.keys(remote)) {
630
- if (!KeysAttributes.has(key)) {
631
- continue;
632
- }
633
- if (changeableKeys.includes(key)) {
634
- if (!recreating) {
635
- reason = compareAttribute(remote[key], local[key], reason, key);
1126
+ }));
1127
+ let numberOfCollections = 0;
1128
+ // Serialize attribute actions
1129
+ for (let collection of collections) {
1130
+ let collectionAttributes = collection.attributes;
1131
+ let indexes = collection.indexes;
1132
+ if (collection.isExisted) {
1133
+ collectionAttributes = await attributes.attributesToCreate(collection.remoteVersion.attributes, collection.attributes, collection);
1134
+ indexes = await attributes.attributesToCreate(collection.remoteVersion.indexes, collection.indexes, collection, true);
1135
+ if (Array.isArray(collectionAttributes) &&
1136
+ collectionAttributes.length <= 0 &&
1137
+ Array.isArray(indexes) &&
1138
+ indexes.length <= 0) {
1139
+ continue;
1140
+ }
636
1141
  }
637
- continue;
638
- }
639
- if (!recreating) {
640
- continue;
641
- }
642
- reason = compareAttribute(remote[key], local[key], reason, key);
643
- }
644
- return reason === ""
645
- ? undefined
646
- : { key: keyName, attribute, reason, action };
647
- };
648
- /**
649
- * Check if attributes contain the given attribute
650
- */
651
- const attributesContains = (attribute, attributes) => attributes.find((attr) => attr.key === attribute.key);
652
- const generateChangesObject = (attribute, collection, isAdding) => {
653
- return {
654
- key: `${chalk.yellow(attribute.key)} in ${collection.name} (${collection["$id"]})`,
655
- attribute: attribute,
656
- reason: isAdding
657
- ? "Field isn't present on the remote server"
658
- : "Field isn't present on the appwrite.config.json file",
659
- action: isAdding ? chalk.green("adding") : chalk.red("deleting"),
660
- };
661
- };
662
- /**
663
- * Filter deleted and recreated attributes,
664
- * return list of attributes to create
665
- */
666
- const attributesToCreate = async (remoteAttributes, localAttributes, collection, isIndex = false) => {
667
- const deleting = remoteAttributes
668
- .filter((attribute) => !attributesContains(attribute, localAttributes))
669
- .map((attr) => generateChangesObject(attr, collection, false));
670
- const adding = localAttributes
671
- .filter((attribute) => !attributesContains(attribute, remoteAttributes))
672
- .map((attr) => generateChangesObject(attr, collection, true));
673
- const conflicts = remoteAttributes
674
- .map((attribute) => checkAttributeChanges(attribute, attributesContains(attribute, localAttributes), collection))
675
- .filter((attribute) => attribute !== undefined);
676
- const changes = remoteAttributes
677
- .map((attribute) => checkAttributeChanges(attribute, attributesContains(attribute, localAttributes), collection, false))
678
- .filter((attribute) => attribute !== undefined)
679
- .filter((attribute) => conflicts.filter((attr) => attribute.key === attr.key).length !== 1);
680
- let changedAttributes = [];
681
- const changing = [...deleting, ...adding, ...conflicts, ...changes];
682
- if (changing.length === 0) {
683
- return changedAttributes;
684
- }
685
- log(!cliConfig.force
686
- ? "There are pending changes in your collection deployment"
687
- : "List of applied changes");
688
- drawTable(changing.map((change) => {
689
- return { Key: change.key, Action: change.action, Reason: change.reason };
690
- }));
691
- if (!cliConfig.force) {
692
- if (deleting.length > 0 && !isIndex) {
693
- console.log(`${chalk.red("------------------------------------------------------")}`);
694
- console.log(`${chalk.red("| WARNING: Attribute deletion may cause loss of data |")}`);
695
- console.log(`${chalk.red("------------------------------------------------------")}`);
696
- console.log();
697
- }
698
- if (conflicts.length > 0 && !isIndex) {
699
- console.log(`${chalk.red("--------------------------------------------------------")}`);
700
- console.log(`${chalk.red("| WARNING: Attribute recreation may cause loss of data |")}`);
701
- console.log(`${chalk.red("--------------------------------------------------------")}`);
702
- console.log();
703
- }
704
- if ((await getConfirmation()) !== true) {
705
- return changedAttributes;
706
- }
707
- }
708
- if (conflicts.length > 0) {
709
- changedAttributes = conflicts.map((change) => change.attribute);
710
- await Promise.all(changedAttributes.map((changed) => deleteAttribute(collection, changed, isIndex)));
711
- remoteAttributes = remoteAttributes.filter((attribute) => !attributesContains(attribute, changedAttributes));
712
- }
713
- if (changes.length > 0) {
714
- changedAttributes = changes.map((change) => change.attribute);
715
- await Promise.all(changedAttributes.map((changed) => updateAttribute(collection["databaseId"], collection["$id"], changed)));
716
- }
717
- const deletingAttributes = deleting.map((change) => change.attribute);
718
- await Promise.all(deletingAttributes.map((attribute) => deleteAttribute(collection, attribute, isIndex)));
719
- const attributeKeys = [
720
- ...remoteAttributes.map((attribute) => attribute.key),
721
- ...deletingAttributes.map((attribute) => attribute.key),
722
- ];
723
- if (attributeKeys.length) {
724
- const deleteAttributesPoolStatus = await awaitPools.deleteAttributes(collection["databaseId"], collection["$id"], attributeKeys);
725
- if (!deleteAttributesPoolStatus) {
726
- throw new Error("Attribute deletion timed out.");
727
- }
728
- }
729
- return localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes));
730
- };
731
- const createIndexes = async (indexes, collection) => {
732
- log(`Creating indexes ...`);
733
- const databasesService = await getDatabasesService();
734
- for (let index of indexes) {
735
- await databasesService.createIndex(collection["databaseId"], collection["$id"], index.key, index.type, index.columns ?? index.attributes, index.orders);
736
- }
737
- const result = await awaitPools.expectIndexes(collection["databaseId"], collection["$id"], indexes.map((index) => index.key));
738
- if (!result) {
739
- throw new Error("Index creation timed out.");
740
- }
741
- success(`Created ${indexes.length} indexes`);
742
- };
743
- const createAttributes = async (attributes, collection) => {
744
- for (let attribute of attributes) {
745
- if (attribute.side !== "child") {
746
- await createAttribute(collection["databaseId"], collection["$id"], attribute);
747
- }
748
- }
749
- const result = await awaitPools.expectAttributes(collection["databaseId"], collection["$id"], collection.attributes
750
- .filter((attribute) => attribute.side !== "child")
751
- .map((attribute) => attribute.key));
752
- if (!result) {
753
- throw new Error(`Attribute creation timed out.`);
754
- }
755
- success(`Created ${attributes.length} attributes`);
756
- };
757
- const createColumns = async (columns, table) => {
758
- for (let column of columns) {
759
- if (column.side !== "child") {
760
- await createAttribute(table["databaseId"], table["$id"], column);
761
- }
762
- }
763
- const result = await awaitPools.expectAttributes(table["databaseId"], table["$id"], table.columns
764
- .filter((column) => column.side !== "child")
765
- .map((column) => column.key));
766
- if (!result) {
767
- throw new Error(`Column creation timed out.`);
768
- }
769
- success(`Created ${columns.length} columns`);
770
- };
1142
+ this.log(`Pushing collection ${collection.name} ( ${collection["databaseId"]} - ${collection["$id"]} ) attributes`);
1143
+ try {
1144
+ await attributes.createAttributes(collectionAttributes, collection);
1145
+ }
1146
+ catch (e) {
1147
+ errors.push(e);
1148
+ throw e;
1149
+ }
1150
+ try {
1151
+ await attributes.createIndexes(indexes, collection);
1152
+ }
1153
+ catch (e) {
1154
+ errors.push(e);
1155
+ throw e;
1156
+ }
1157
+ numberOfCollections++;
1158
+ this.success(`Successfully pushed ${collection.name} ( ${collection["$id"]} )`);
1159
+ }
1160
+ return {
1161
+ successfullyPushed: numberOfCollections,
1162
+ errors,
1163
+ };
1164
+ }
1165
+ }
1166
+ async function createPushInstance(silent = false) {
1167
+ const projectClient = await sdkForProject();
1168
+ const consoleClient = await sdkForConsole();
1169
+ return new Push(projectClient, consoleClient, silent);
1170
+ }
771
1171
  const pushResources = async ({ skipDeprecated = false, } = {}) => {
772
- const actions = {
773
- settings: pushSettings,
774
- functions: pushFunction,
775
- sites: pushSite,
776
- collections: pushCollection,
777
- tables: pushTable,
778
- buckets: pushBucket,
779
- teams: pushTeam,
780
- messages: pushMessagingTopic,
781
- };
782
- if (skipDeprecated) {
783
- delete actions.collections;
784
- }
785
1172
  if (cliConfig.all) {
786
- for (let action of Object.values(actions)) {
787
- await action();
788
- }
1173
+ checkDeployConditions(localConfig);
1174
+ const pushInstance = await createPushInstance();
1175
+ const config = localConfig.getProject();
1176
+ await pushInstance.pushResources(config, {
1177
+ skipDeprecated,
1178
+ functionOptions: { code: true, withVariables: false },
1179
+ siteOptions: { code: true, withVariables: false },
1180
+ });
789
1181
  }
790
1182
  else {
1183
+ const actions = {
1184
+ settings: pushSettings,
1185
+ functions: pushFunction,
1186
+ sites: pushSite,
1187
+ collections: pushCollection,
1188
+ tables: pushTable,
1189
+ buckets: pushBucket,
1190
+ teams: pushTeam,
1191
+ messages: pushMessagingTopic,
1192
+ };
1193
+ if (skipDeprecated) {
1194
+ delete actions.collections;
1195
+ }
791
1196
  const answers = await inquirer.prompt(questionsPushResources);
792
1197
  const action = actions[answers.resource];
793
1198
  if (action !== undefined) {
@@ -800,7 +1205,7 @@ const pushSettings = async () => {
800
1205
  try {
801
1206
  const projectsService = await getProjectsService();
802
1207
  let response = await projectsService.get(localConfig.getProject().projectId);
803
- const remoteSettings = localConfig.createSettingsObject(response ?? {});
1208
+ const remoteSettings = createSettingsObject(response);
804
1209
  const localSettings = localConfig.getProject().projectSettings ?? {};
805
1210
  log("Checking for changes ...");
806
1211
  const changes = [];
@@ -818,39 +1223,13 @@ const pushSettings = async () => {
818
1223
  catch (e) { }
819
1224
  try {
820
1225
  log("Pushing project settings ...");
821
- const projectsService = await getProjectsService();
822
- const projectId = localConfig.getProject().projectId;
823
- const projectName = localConfig.getProject().projectName;
824
- const settings = localConfig.getProject().projectSettings ?? {};
825
- if (projectName) {
826
- log("Applying project name ...");
827
- await projectsService.update(projectId, projectName);
828
- }
829
- if (settings.services) {
830
- log("Applying service statuses ...");
831
- for (let [service, status] of Object.entries(settings.services)) {
832
- await projectsService.updateServiceStatus(projectId, service, status);
833
- }
834
- }
835
- if (settings.auth) {
836
- if (settings.auth.security) {
837
- log("Applying auth security settings ...");
838
- await projectsService.updateAuthDuration(projectId, settings.auth.security.duration);
839
- await projectsService.updateAuthLimit(projectId, settings.auth.security.limit);
840
- await projectsService.updateAuthSessionsLimit(projectId, settings.auth.security.sessionsLimit);
841
- await projectsService.updateAuthPasswordDictionary(projectId, settings.auth.security.passwordDictionary);
842
- await projectsService.updateAuthPasswordHistory(projectId, settings.auth.security.passwordHistory);
843
- await projectsService.updatePersonalDataCheck(projectId, settings.auth.security.personalDataCheck);
844
- await projectsService.updateSessionAlerts(projectId, settings.auth.security.sessionAlerts);
845
- await projectsService.updateMockNumbers(projectId, settings.auth.security.mockNumbers);
846
- }
847
- if (settings.auth.methods) {
848
- log("Applying auth methods statuses ...");
849
- for (let [method, status] of Object.entries(settings.auth.methods)) {
850
- await projectsService.updateAuthStatus(projectId, method, status);
851
- }
852
- }
853
- }
1226
+ const pushInstance = await createPushInstance();
1227
+ const config = localConfig.getProject();
1228
+ await pushInstance.pushSettings({
1229
+ projectId: config.projectId,
1230
+ projectName: config.projectName,
1231
+ settings: config.projectSettings,
1232
+ });
854
1233
  success(`Successfully pushed ${chalk.bold("all")} project settings.`);
855
1234
  }
856
1235
  catch (e) {
@@ -878,281 +1257,41 @@ const pushSite = async ({ siteId, async: asyncDeploy, code, withVariables, } = {
878
1257
  }
879
1258
  if (siteIds.length === 0) {
880
1259
  log("No sites found.");
881
- hint("Use 'appwrite pull sites' to synchronize existing one, or use 'appwrite init site' to create a new one.");
1260
+ hint(`Use '${EXECUTABLE_NAME} pull sites' to synchronize existing one, or use '${EXECUTABLE_NAME} init site' to create a new one.`);
882
1261
  return;
883
1262
  }
884
- let sites = siteIds.map((id) => {
885
- const sites = localConfig.getSites();
886
- const site = sites.find((s) => s.$id === id);
887
- if (!site) {
888
- throw new Error("Site '" + id + "' not found.");
889
- }
890
- return site;
891
- });
892
- log("Validating sites ...");
893
- // Validation is done BEFORE pushing so the deployment process can be run in async with progress update
894
- for (let site of sites) {
895
- if (!site.buildCommand) {
896
- log(`Site ${site.name} is missing build command.`);
897
- const answers = await inquirer.prompt(questionsGetEntrypoint);
898
- site.buildCommand = answers.entrypoint;
899
- localConfig.addSite(site);
900
- }
901
- }
902
- if (!(await approveChanges(sites, async (args) => {
903
- const sitesService = await getSitesService();
904
- return await sitesService.get({ siteId: args.siteId });
905
- }, KeysSite, "siteId", "sites", ["vars"]))) {
906
- return;
907
- }
908
- log("Pushing sites ...");
909
- Spinner.start(false);
910
- let successfullyPushed = 0;
911
- let successfullyDeployed = 0;
912
- const failedDeployments = [];
913
- const errors = [];
914
- await Promise.all(sites.map(async (site) => {
915
- let response = {};
916
- const ignore = site.ignore ? "appwrite.config.json" : ".gitignore";
917
- let siteExists = false;
918
- let deploymentCreated = false;
919
- const updaterRow = new Spinner({
920
- status: "",
921
- resource: site.name,
922
- id: site["$id"],
923
- end: `Ignoring using: ${ignore}`,
924
- });
925
- updaterRow.update({ status: "Getting" }).startSpinner(SPINNER_DOTS);
926
- const sitesService = await getSitesService();
927
- try {
928
- response = await sitesService.get({ siteId: site["$id"] });
929
- siteExists = true;
930
- if (response.framework !== site.framework) {
931
- updaterRow.fail({
932
- errorMessage: `Framework mismatch! (local=${site.framework},remote=${response.framework}) Please delete remote site or update your appwrite.config.json`,
933
- });
934
- return;
935
- }
936
- updaterRow.update({ status: "Updating" }).replaceSpinner(SPINNER_ARC);
937
- response = await sitesService.update({
938
- siteId: site["$id"],
939
- name: site.name,
940
- framework: site.framework,
941
- enabled: site.enabled,
942
- logging: site.logging,
943
- timeout: site.timeout,
944
- installCommand: site.installCommand,
945
- buildCommand: site.buildCommand,
946
- outputDirectory: site.outputDirectory,
947
- buildRuntime: site.buildRuntime,
948
- adapter: site.adapter,
949
- specification: site.specification,
950
- });
951
- }
952
- catch (e) {
953
- if (Number(e.code) === 404) {
954
- siteExists = false;
955
- }
956
- else {
957
- errors.push(e);
958
- updaterRow.fail({
959
- errorMessage: e.message ?? "General error occurs please try again",
960
- });
961
- return;
962
- }
963
- }
964
- if (!siteExists) {
965
- updaterRow.update({ status: "Creating" }).replaceSpinner(SPINNER_DOTS);
966
- try {
967
- response = await sitesService.create({
968
- siteId: site.$id,
969
- name: site.name,
970
- framework: site.framework,
971
- enabled: site.enabled,
972
- logging: site.logging,
973
- timeout: site.timeout,
974
- installCommand: site.installCommand,
975
- buildCommand: site.buildCommand,
976
- outputDirectory: site.outputDirectory,
977
- buildRuntime: site.buildRuntime,
978
- adapter: site.adapter,
979
- specification: site.specification,
980
- });
981
- let domain = "";
982
- try {
983
- const consoleService = await getConsoleService();
984
- const variables = await consoleService.variables();
985
- domain = ID.unique() + "." + variables["_APP_DOMAIN_SITES"];
986
- }
987
- catch (error) {
988
- console.error("Error fetching console variables.");
989
- throw error;
990
- }
991
- try {
992
- const proxyService = await getProxyService();
993
- const rule = await proxyService.createSiteRule(domain, site.$id);
994
- }
995
- catch (error) {
996
- console.error("Error creating site rule.");
997
- throw error;
998
- }
999
- updaterRow.update({ status: "Created" });
1000
- }
1001
- catch (e) {
1002
- errors.push(e);
1003
- updaterRow.fail({
1004
- errorMessage: e.message ?? "General error occurs please try again",
1005
- });
1006
- return;
1007
- }
1008
- }
1009
- if (withVariables) {
1010
- updaterRow
1011
- .update({ status: "Creating variables" })
1012
- .replaceSpinner(SPINNER_ARC);
1013
- const sitesService = await getSitesService();
1014
- const { variables } = await paginate(async (args) => {
1015
- return await sitesService.listVariables({ siteId: args.siteId });
1016
- }, {
1017
- siteId: site["$id"],
1018
- }, 100, "variables");
1019
- await Promise.all(variables.map(async (variable) => {
1020
- const sitesService = await getSitesService();
1021
- await sitesService.deleteVariable({
1022
- siteId: site["$id"],
1023
- variableId: variable["$id"],
1024
- });
1025
- }));
1026
- const envFileLocation = `${site["path"]}/.env`;
1027
- let envVariables = [];
1028
- try {
1029
- if (fs.existsSync(envFileLocation)) {
1030
- const envObject = parseDotenv(fs.readFileSync(envFileLocation, "utf8"));
1031
- envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
1032
- }
1033
- }
1034
- catch (error) {
1035
- // Handle parsing errors gracefully
1036
- envVariables = [];
1037
- }
1038
- await Promise.all(envVariables.map(async (variable) => {
1039
- const sitesService = await getSitesService();
1040
- await sitesService.createVariable({
1041
- siteId: site["$id"],
1042
- key: variable.key,
1043
- value: variable.value,
1044
- secret: false,
1045
- });
1046
- }));
1047
- }
1048
- if (code === false) {
1049
- successfullyPushed++;
1050
- successfullyDeployed++;
1051
- updaterRow.update({ status: "Pushed" });
1052
- updaterRow.stopSpinner();
1053
- return;
1054
- }
1055
- try {
1056
- updaterRow.update({ status: "Pushing" }).replaceSpinner(SPINNER_ARC);
1057
- const sitesService = await getSitesService();
1058
- response = await sitesService.createDeployment({
1059
- siteId: site["$id"],
1060
- installCommand: site.installCommand,
1061
- buildCommand: site.buildCommand,
1062
- outputDirectory: site.outputDirectory,
1063
- code: site.path,
1064
- activate: true,
1065
- });
1066
- updaterRow.update({ status: "Pushed" });
1067
- deploymentCreated = true;
1068
- successfullyPushed++;
1069
- }
1070
- catch (e) {
1071
- errors.push(e);
1072
- switch (e.code) {
1073
- case "ENOENT":
1074
- updaterRow.fail({
1075
- errorMessage: "Not found in the current directory. Skipping...",
1076
- });
1077
- break;
1078
- default:
1079
- updaterRow.fail({
1080
- errorMessage: e.message ?? "An unknown error occurred. Please try again.",
1081
- });
1082
- }
1263
+ let sites = siteIds.map((id) => {
1264
+ const sites = localConfig.getSites();
1265
+ const site = sites.find((s) => s.$id === id);
1266
+ if (!site) {
1267
+ throw new Error("Site '" + id + "' not found.");
1083
1268
  }
1084
- if (deploymentCreated && !asyncDeploy) {
1085
- try {
1086
- const deploymentId = response["$id"];
1087
- updaterRow.update({
1088
- status: "Deploying",
1089
- end: "Checking deployment status...",
1090
- });
1091
- let pollChecks = 0;
1092
- while (true) {
1093
- const sitesService = await getSitesService();
1094
- response = await sitesService.getDeployment({
1095
- siteId: site["$id"],
1096
- deploymentId: deploymentId,
1097
- });
1098
- const status = response["status"];
1099
- if (status === "ready") {
1100
- successfullyDeployed++;
1101
- let url = "";
1102
- const proxyService = await getProxyService();
1103
- const res = await proxyService.listRules([
1104
- JSON.stringify({ method: "limit", values: [1] }),
1105
- JSON.stringify({
1106
- method: "equal",
1107
- attribute: "deploymentResourceType",
1108
- values: ["site"],
1109
- }),
1110
- JSON.stringify({
1111
- method: "equal",
1112
- attribute: "deploymentResourceId",
1113
- values: [site["$id"]],
1114
- }),
1115
- JSON.stringify({
1116
- method: "equal",
1117
- attribute: "trigger",
1118
- values: ["manual"],
1119
- }),
1120
- ]);
1121
- if (Number(res.total) === 1) {
1122
- url = res.rules[0].domain;
1123
- }
1124
- updaterRow.update({ status: "Deployed", end: url });
1125
- break;
1126
- }
1127
- else if (status === "failed") {
1128
- failedDeployments.push({
1129
- name: site["name"],
1130
- $id: site["$id"],
1131
- deployment: response["$id"],
1132
- });
1133
- updaterRow.fail({ errorMessage: `Failed to deploy` });
1134
- break;
1135
- }
1136
- else {
1137
- updaterRow.update({
1138
- status: "Deploying",
1139
- end: `Current status: ${status}`,
1140
- });
1141
- }
1142
- pollChecks++;
1143
- await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE * 1.5));
1144
- }
1145
- }
1146
- catch (e) {
1147
- errors.push(e);
1148
- updaterRow.fail({
1149
- errorMessage: e.message ?? "Unknown error occurred. Please try again",
1150
- });
1151
- }
1269
+ return site;
1270
+ });
1271
+ log("Validating sites ...");
1272
+ // Validation is done BEFORE pushing so the deployment process can be run in async with progress update
1273
+ for (let site of sites) {
1274
+ if (!site.buildCommand) {
1275
+ log(`Site ${site.name} is missing build command.`);
1276
+ const answers = await inquirer.prompt(questionsGetEntrypoint);
1277
+ site.buildCommand = answers.entrypoint;
1278
+ localConfig.addSite(site);
1152
1279
  }
1153
- updaterRow.stopSpinner();
1154
- }));
1155
- Spinner.stop();
1280
+ }
1281
+ if (!(await approveChanges(sites, async (args) => {
1282
+ const sitesService = await getSitesService();
1283
+ return await sitesService.get({ siteId: args.siteId });
1284
+ }, KeysSite, "siteId", "sites", ["vars"]))) {
1285
+ return;
1286
+ }
1287
+ log("Pushing sites ...");
1288
+ const pushInstance = await createPushInstance();
1289
+ const result = await pushInstance.pushSites(sites, {
1290
+ async: asyncDeploy,
1291
+ code,
1292
+ withVariables,
1293
+ });
1294
+ const { successfullyPushed, successfullyDeployed, failedDeployments, errors, } = result;
1156
1295
  failedDeployments.forEach((failed) => {
1157
1296
  const { name, deployment, $id } = failed;
1158
1297
  const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/sites/site-${$id}/deployments/deployment-${deployment}`;
@@ -1199,7 +1338,7 @@ const pushFunction = async ({ functionId, async: asyncDeploy, code, withVariable
1199
1338
  }
1200
1339
  if (functionIds.length === 0) {
1201
1340
  log("No functions found.");
1202
- hint("Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.");
1341
+ hint(`Use '${EXECUTABLE_NAME} pull functions' to synchronize existing one, or use '${EXECUTABLE_NAME} init function' to create a new one.`);
1203
1342
  return;
1204
1343
  }
1205
1344
  let functions = functionIds.map((id) => {
@@ -1211,7 +1350,6 @@ const pushFunction = async ({ functionId, async: asyncDeploy, code, withVariable
1211
1350
  return func;
1212
1351
  });
1213
1352
  log("Validating functions ...");
1214
- // Validation is done BEFORE pushing so the deployment process can be run in async with progress update
1215
1353
  for (let func of functions) {
1216
1354
  if (!func.entrypoint) {
1217
1355
  log(`Function ${func.name} is missing an entrypoint.`);
@@ -1227,256 +1365,13 @@ const pushFunction = async ({ functionId, async: asyncDeploy, code, withVariable
1227
1365
  return;
1228
1366
  }
1229
1367
  log("Pushing functions ...");
1230
- Spinner.start(false);
1231
- let successfullyPushed = 0;
1232
- let successfullyDeployed = 0;
1233
- const failedDeployments = [];
1234
- const errors = [];
1235
- await Promise.all(functions.map(async (func) => {
1236
- let response = {};
1237
- const ignore = func.ignore ? "appwrite.config.json" : ".gitignore";
1238
- let functionExists = false;
1239
- let deploymentCreated = false;
1240
- const updaterRow = new Spinner({
1241
- status: "",
1242
- resource: func.name,
1243
- id: func["$id"],
1244
- end: `Ignoring using: ${ignore}`,
1245
- });
1246
- updaterRow.update({ status: "Getting" }).startSpinner(SPINNER_DOTS);
1247
- const functionsService = await getFunctionsService();
1248
- try {
1249
- response = await functionsService.get({ functionId: func["$id"] });
1250
- functionExists = true;
1251
- if (response.runtime !== func.runtime) {
1252
- updaterRow.fail({
1253
- errorMessage: `Runtime mismatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.config.json`,
1254
- });
1255
- return;
1256
- }
1257
- updaterRow.update({ status: "Updating" }).replaceSpinner(SPINNER_ARC);
1258
- response = await functionsService.update({
1259
- functionId: func["$id"],
1260
- name: func.name,
1261
- runtime: func.runtime,
1262
- execute: func.execute,
1263
- events: func.events,
1264
- schedule: func.schedule,
1265
- timeout: func.timeout,
1266
- enabled: func.enabled,
1267
- logging: func.logging,
1268
- entrypoint: func.entrypoint,
1269
- commands: func.commands,
1270
- scopes: func.scopes,
1271
- specification: func.specification,
1272
- });
1273
- }
1274
- catch (e) {
1275
- if (Number(e.code) === 404) {
1276
- functionExists = false;
1277
- }
1278
- else {
1279
- errors.push(e);
1280
- updaterRow.fail({
1281
- errorMessage: e.message ?? "General error occurs please try again",
1282
- });
1283
- return;
1284
- }
1285
- }
1286
- if (!functionExists) {
1287
- updaterRow.update({ status: "Creating" }).replaceSpinner(SPINNER_DOTS);
1288
- try {
1289
- response = await functionsService.create({
1290
- functionId: func.$id,
1291
- name: func.name,
1292
- runtime: func.runtime,
1293
- execute: func.execute,
1294
- events: func.events,
1295
- schedule: func.schedule,
1296
- timeout: func.timeout,
1297
- enabled: func.enabled,
1298
- logging: func.logging,
1299
- entrypoint: func.entrypoint,
1300
- commands: func.commands,
1301
- scopes: func.scopes,
1302
- specification: func.specification,
1303
- });
1304
- let domain = "";
1305
- try {
1306
- const consoleService = await getConsoleService();
1307
- const variables = await consoleService.variables();
1308
- domain = ID.unique() + "." + variables["_APP_DOMAIN_FUNCTIONS"];
1309
- }
1310
- catch (error) {
1311
- console.error("Error fetching console variables.");
1312
- throw error;
1313
- }
1314
- try {
1315
- const proxyService = await getProxyService();
1316
- const rule = await proxyService.createFunctionRule(domain, func.$id);
1317
- }
1318
- catch (error) {
1319
- console.error("Error creating function rule.");
1320
- throw error;
1321
- }
1322
- updaterRow.update({ status: "Created" });
1323
- }
1324
- catch (e) {
1325
- errors.push(e);
1326
- updaterRow.fail({
1327
- errorMessage: e.message ?? "General error occurs please try again",
1328
- });
1329
- return;
1330
- }
1331
- }
1332
- if (withVariables) {
1333
- updaterRow
1334
- .update({ status: "Updating variables" })
1335
- .replaceSpinner(SPINNER_ARC);
1336
- const functionsService = await getFunctionsService();
1337
- const { variables } = await paginate(async (args) => {
1338
- return await functionsService.listVariables({
1339
- functionId: args.functionId,
1340
- });
1341
- }, {
1342
- functionId: func["$id"],
1343
- }, 100, "variables");
1344
- await Promise.all(variables.map(async (variable) => {
1345
- const functionsService = await getFunctionsService();
1346
- await functionsService.deleteVariable({
1347
- functionId: func["$id"],
1348
- variableId: variable["$id"],
1349
- });
1350
- }));
1351
- const envFileLocation = `${func["path"]}/.env`;
1352
- let envVariables = [];
1353
- try {
1354
- if (fs.existsSync(envFileLocation)) {
1355
- const envObject = parseDotenv(fs.readFileSync(envFileLocation, "utf8"));
1356
- envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
1357
- }
1358
- }
1359
- catch (error) {
1360
- // Handle parsing errors gracefully
1361
- envVariables = [];
1362
- }
1363
- await Promise.all(envVariables.map(async (variable) => {
1364
- const functionsService = await getFunctionsService();
1365
- await functionsService.createVariable({
1366
- functionId: func["$id"],
1367
- key: variable.key,
1368
- value: variable.value,
1369
- secret: false,
1370
- });
1371
- }));
1372
- }
1373
- if (code === false) {
1374
- successfullyPushed++;
1375
- successfullyDeployed++;
1376
- updaterRow.update({ status: "Pushed" });
1377
- updaterRow.stopSpinner();
1378
- return;
1379
- }
1380
- try {
1381
- updaterRow.update({ status: "Pushing" }).replaceSpinner(SPINNER_ARC);
1382
- const functionsService = await getFunctionsService();
1383
- response = await functionsService.createDeployment({
1384
- functionId: func["$id"],
1385
- entrypoint: func.entrypoint,
1386
- commands: func.commands,
1387
- code: func.path,
1388
- activate: true,
1389
- });
1390
- updaterRow.update({ status: "Pushed" });
1391
- deploymentCreated = true;
1392
- successfullyPushed++;
1393
- }
1394
- catch (e) {
1395
- errors.push(e);
1396
- switch (e.code) {
1397
- case "ENOENT":
1398
- updaterRow.fail({
1399
- errorMessage: "Not found in the current directory. Skipping...",
1400
- });
1401
- break;
1402
- default:
1403
- updaterRow.fail({
1404
- errorMessage: e.message ?? "An unknown error occurred. Please try again.",
1405
- });
1406
- }
1407
- }
1408
- if (deploymentCreated && !asyncDeploy) {
1409
- try {
1410
- const deploymentId = response["$id"];
1411
- updaterRow.update({
1412
- status: "Deploying",
1413
- end: "Checking deployment status...",
1414
- });
1415
- let pollChecks = 0;
1416
- while (true) {
1417
- const functionsService = await getFunctionsService();
1418
- response = await functionsService.getDeployment({
1419
- functionId: func["$id"],
1420
- deploymentId: deploymentId,
1421
- });
1422
- const status = response["status"];
1423
- if (status === "ready") {
1424
- successfullyDeployed++;
1425
- let url = "";
1426
- const proxyService = await getProxyService();
1427
- const res = await proxyService.listRules([
1428
- JSON.stringify({ method: "limit", values: [1] }),
1429
- JSON.stringify({
1430
- method: "equal",
1431
- attribute: "deploymentResourceType",
1432
- values: ["function"],
1433
- }),
1434
- JSON.stringify({
1435
- method: "equal",
1436
- attribute: "deploymentResourceId",
1437
- values: [func["$id"]],
1438
- }),
1439
- JSON.stringify({
1440
- method: "equal",
1441
- attribute: "trigger",
1442
- values: ["manual"],
1443
- }),
1444
- ]);
1445
- if (Number(res.total) === 1) {
1446
- url = res.rules[0].domain;
1447
- }
1448
- updaterRow.update({ status: "Deployed", end: url });
1449
- break;
1450
- }
1451
- else if (status === "failed") {
1452
- failedDeployments.push({
1453
- name: func["name"],
1454
- $id: func["$id"],
1455
- deployment: response["$id"],
1456
- });
1457
- updaterRow.fail({ errorMessage: `Failed to deploy` });
1458
- break;
1459
- }
1460
- else {
1461
- updaterRow.update({
1462
- status: "Deploying",
1463
- end: `Current status: ${status}`,
1464
- });
1465
- }
1466
- pollChecks++;
1467
- await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE * 1.5));
1468
- }
1469
- }
1470
- catch (e) {
1471
- errors.push(e);
1472
- updaterRow.fail({
1473
- errorMessage: e.message ?? "Unknown error occurred. Please try again",
1474
- });
1475
- }
1476
- }
1477
- updaterRow.stopSpinner();
1478
- }));
1479
- Spinner.stop();
1368
+ const pushInstance = await createPushInstance();
1369
+ const result = await pushInstance.pushFunctions(functions, {
1370
+ async: asyncDeploy,
1371
+ code,
1372
+ withVariables,
1373
+ });
1374
+ const { successfullyPushed, successfullyDeployed, failedDeployments, errors, } = result;
1480
1375
  failedDeployments.forEach((failed) => {
1481
1376
  const { name, deployment, $id } = failed;
1482
1377
  const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/functions/function-${$id}/deployment-${deployment}`;
@@ -1502,145 +1397,14 @@ const pushFunction = async ({ functionId, async: asyncDeploy, code, withVariable
1502
1397
  });
1503
1398
  }
1504
1399
  };
1505
- const checkAndApplyTablesDBChanges = async () => {
1506
- log("Checking for tablesDB changes ...");
1507
- const localTablesDBs = localConfig.getTablesDBs();
1508
- const { databases: remoteTablesDBs } = await paginate(async (args) => {
1509
- const tablesDBService = await getTablesDBService();
1510
- return await tablesDBService.list(args.queries || []);
1511
- }, {}, 100, "databases");
1512
- if (localTablesDBs.length === 0 && remoteTablesDBs.length === 0) {
1513
- return { applied: false, resyncNeeded: false };
1514
- }
1515
- const changes = [];
1516
- const toCreate = [];
1517
- const toUpdate = [];
1518
- const toDelete = [];
1519
- // Check for deletions - remote DBs that aren't in local config
1520
- for (const remoteDB of remoteTablesDBs) {
1521
- const localDB = localTablesDBs.find((db) => db.$id === remoteDB.$id);
1522
- if (!localDB) {
1523
- toDelete.push(remoteDB);
1524
- changes.push({
1525
- id: remoteDB.$id,
1526
- action: chalk.red("deleting"),
1527
- key: "Database",
1528
- remote: remoteDB.name,
1529
- local: "(deleted locally)",
1530
- });
1531
- }
1532
- }
1533
- // Check for additions and updates
1534
- for (const localDB of localTablesDBs) {
1535
- const remoteDB = remoteTablesDBs.find((db) => db.$id === localDB.$id);
1536
- if (!remoteDB) {
1537
- toCreate.push(localDB);
1538
- changes.push({
1539
- id: localDB.$id,
1540
- action: chalk.green("creating"),
1541
- key: "Database",
1542
- remote: "(does not exist)",
1543
- local: localDB.name,
1544
- });
1545
- }
1546
- else {
1547
- let hasChanges = false;
1548
- if (remoteDB.name !== localDB.name) {
1549
- hasChanges = true;
1550
- changes.push({
1551
- id: localDB.$id,
1552
- action: chalk.yellow("updating"),
1553
- key: "Name",
1554
- remote: remoteDB.name,
1555
- local: localDB.name,
1556
- });
1557
- }
1558
- if (remoteDB.enabled !== localDB.enabled) {
1559
- hasChanges = true;
1560
- changes.push({
1561
- id: localDB.$id,
1562
- action: chalk.yellow("updating"),
1563
- key: "Enabled",
1564
- remote: remoteDB.enabled,
1565
- local: localDB.enabled,
1566
- });
1567
- }
1568
- if (hasChanges) {
1569
- toUpdate.push(localDB);
1570
- }
1571
- }
1572
- }
1573
- if (changes.length === 0) {
1574
- return { applied: false, resyncNeeded: false };
1575
- }
1576
- log("Found changes in tablesDB resource:");
1577
- drawTable(changes);
1578
- if (toDelete.length > 0) {
1579
- console.log(`${chalk.red("------------------------------------------------------------------")}`);
1580
- console.log(`${chalk.red("| WARNING: Database deletion will also delete all related tables |")}`);
1581
- console.log(`${chalk.red("------------------------------------------------------------------")}`);
1582
- console.log();
1583
- }
1584
- if ((await getConfirmation()) !== true) {
1585
- return { applied: false, resyncNeeded: false };
1586
- }
1587
- // Apply deletions first
1588
- let needsResync = false;
1589
- for (const db of toDelete) {
1590
- try {
1591
- log(`Deleting database ${db.name} ( ${db.$id} ) ...`);
1592
- const tablesDBService = await getTablesDBService();
1593
- await tablesDBService.delete(db.$id);
1594
- success(`Deleted ${db.name} ( ${db.$id} )`);
1595
- needsResync = true;
1596
- }
1597
- catch (e) {
1598
- error(`Failed to delete database ${db.name} ( ${db.$id} ): ${e.message}`);
1599
- throw new Error(`Database sync failed during deletion of ${db.$id}. Some changes may have been applied.`);
1600
- }
1601
- }
1602
- // Apply creations
1603
- for (const db of toCreate) {
1604
- try {
1605
- log(`Creating database ${db.name} ( ${db.$id} ) ...`);
1606
- const tablesDBService = await getTablesDBService();
1607
- await tablesDBService.create(db.$id, db.name, db.enabled);
1608
- success(`Created ${db.name} ( ${db.$id} )`);
1609
- }
1610
- catch (e) {
1611
- error(`Failed to create database ${db.name} ( ${db.$id} ): ${e.message}`);
1612
- throw new Error(`Database sync failed during creation of ${db.$id}. Some changes may have been applied.`);
1613
- }
1614
- }
1615
- // Apply updates
1616
- for (const db of toUpdate) {
1617
- try {
1618
- log(`Updating database ${db.name} ( ${db.$id} ) ...`);
1619
- const tablesDBService = await getTablesDBService();
1620
- await tablesDBService.update(db.$id, db.name, db.enabled);
1621
- success(`Updated ${db.name} ( ${db.$id} )`);
1622
- }
1623
- catch (e) {
1624
- error(`Failed to update database ${db.name} ( ${db.$id} ): ${e.message}`);
1625
- throw new Error(`Database sync failed during update of ${db.$id}. Some changes may have been applied.`);
1626
- }
1627
- }
1628
- if (toDelete.length === 0) {
1629
- console.log();
1630
- }
1631
- return { applied: true, resyncNeeded: needsResync };
1632
- };
1633
1400
  const pushTable = async ({ attempts, } = {}) => {
1634
1401
  const tables = [];
1635
- if (attempts) {
1636
- pollMaxDebounces = attempts;
1637
- }
1638
- const { applied: tablesDBApplied, resyncNeeded } = await checkAndApplyTablesDBChanges();
1402
+ const { resyncNeeded } = await checkAndApplyTablesDBChanges();
1639
1403
  if (resyncNeeded) {
1640
- log("Resyncing configuration due to tablesDB deletions ...");
1404
+ log("Resyncing configuration due to tables deletions ...");
1641
1405
  const remoteTablesDBs = (await paginate(async (args) => {
1642
- const tablesDBService = await getTablesDBService();
1643
- return await tablesDBService.list(args.queries || []);
1406
+ const tablesService = await getTablesDBService();
1407
+ return await tablesService.list(args.queries || []);
1644
1408
  }, {}, 100, "databases")).databases;
1645
1409
  const localTablesDBs = localConfig.getTablesDBs();
1646
1410
  const remoteDatabaseIds = new Set(remoteTablesDBs.map((db) => db.$id));
@@ -1659,8 +1423,8 @@ const pushTable = async ({ attempts, } = {}) => {
1659
1423
  for (const db of localTablesDBs) {
1660
1424
  try {
1661
1425
  const { tables: remoteTables } = await paginate(async (args) => {
1662
- const tablesDBService = await getTablesDBService();
1663
- return await tablesDBService.listTables(args.databaseId, args.queries || []);
1426
+ const tablesService = await getTablesDBService();
1427
+ return await tablesService.listTables(args.databaseId, args.queries || []);
1664
1428
  }, {
1665
1429
  databaseId: db.$id,
1666
1430
  }, 100, "tables");
@@ -1694,8 +1458,8 @@ const pushTable = async ({ attempts, } = {}) => {
1694
1458
  for (const table of tablesToDelete) {
1695
1459
  try {
1696
1460
  log(`Deleting table ${table.name} ( ${table.$id} ) from database ${table.databaseName} ...`);
1697
- const tablesDBService = await getTablesDBService();
1698
- await tablesDBService.deleteTable(table.databaseId, table.$id);
1461
+ const tablesService = await getTablesDBService();
1462
+ await tablesService.deleteTable(table.databaseId, table.$id);
1699
1463
  success(`Deleted ${table.name} ( ${table.$id} )`);
1700
1464
  }
1701
1465
  catch (e) {
@@ -1723,90 +1487,32 @@ const pushTable = async ({ attempts, } = {}) => {
1723
1487
  }
1724
1488
  if (tables.length === 0) {
1725
1489
  log("No tables found.");
1726
- hint("Use 'appwrite pull tables' to synchronize existing one, or use 'appwrite init table' to create a new one.");
1490
+ hint(`Use '${EXECUTABLE_NAME} pull tables' to synchronize existing one, or use '${EXECUTABLE_NAME} init table' to create a new one.`);
1727
1491
  return;
1728
1492
  }
1729
1493
  if (!(await approveChanges(tables, async (args) => {
1730
- const tablesDBService = await getTablesDBService();
1731
- return await tablesDBService.getTable(args.databaseId, args.tableId);
1494
+ const tablesService = await getTablesDBService();
1495
+ return await tablesService.getTable(args.databaseId, args.tableId);
1732
1496
  }, KeysTable, "tableId", "tables", ["columns", "indexes"], "databaseId", "databaseId"))) {
1733
1497
  return;
1734
1498
  }
1735
- let tablesChanged = new Set();
1736
- // Parallel tables actions
1737
- await Promise.all(tables.map(async (table) => {
1738
- try {
1739
- const tablesDBService = await getTablesDBService();
1740
- const remoteTable = await tablesDBService.getTable(table["databaseId"], table["$id"]);
1741
- const changes = [];
1742
- if (remoteTable.name !== table.name)
1743
- changes.push("name");
1744
- if (remoteTable.rowSecurity !== table.rowSecurity)
1745
- changes.push("rowSecurity");
1746
- if (remoteTable.enabled !== table.enabled)
1747
- changes.push("enabled");
1748
- if (JSON.stringify(remoteTable["$permissions"]) !==
1749
- JSON.stringify(table["$permissions"]))
1750
- changes.push("permissions");
1751
- if (changes.length > 0) {
1752
- await tablesDBService.updateTable(table["databaseId"], table["$id"], table.name, table.rowSecurity, table["$permissions"]);
1753
- success(`Updated ${table.name} ( ${table["$id"]} ) - ${changes.join(", ")}`);
1754
- tablesChanged.add(table["$id"]);
1755
- }
1756
- table.remoteVersion = remoteTable;
1757
- table.isExisted = true;
1758
- }
1759
- catch (e) {
1760
- if (Number(e.code) === 404) {
1761
- log(`Table ${table.name} does not exist in the project. Creating ... `);
1762
- const tablesDBService = await getTablesDBService();
1763
- await tablesDBService.createTable(table["databaseId"], table["$id"], table.name, table.rowSecurity, table["$permissions"]);
1764
- success(`Created ${table.name} ( ${table["$id"]} )`);
1765
- tablesChanged.add(table["$id"]);
1766
- }
1767
- else {
1768
- throw e;
1769
- }
1770
- }
1771
- }));
1772
- // Serialize attribute actions
1773
- for (let table of tables) {
1774
- let columns = table.columns;
1775
- let indexes = table.indexes;
1776
- if (table.isExisted) {
1777
- columns = await attributesToCreate(table.remoteVersion.columns, table.columns, table);
1778
- indexes = await attributesToCreate(table.remoteVersion.indexes, table.indexes, table, true);
1779
- if (Array.isArray(columns) &&
1780
- columns.length <= 0 &&
1781
- Array.isArray(indexes) &&
1782
- indexes.length <= 0) {
1783
- continue;
1784
- }
1785
- }
1786
- log(`Pushing table ${table.name} ( ${table["databaseId"]} - ${table["$id"]} ) attributes`);
1787
- try {
1788
- await createColumns(columns, table);
1789
- }
1790
- catch (e) {
1791
- throw e;
1792
- }
1793
- try {
1794
- await createIndexes(indexes, table);
1795
- }
1796
- catch (e) {
1797
- throw e;
1798
- }
1799
- tablesChanged.add(table["$id"]);
1800
- success(`Successfully pushed ${table.name} ( ${table["$id"]} )`);
1499
+ log("Pushing tables ...");
1500
+ const pushInstance = await createPushInstance();
1501
+ const result = await pushInstance.pushTables(tables, { attempts });
1502
+ const { successfullyPushed, errors } = result;
1503
+ if (successfullyPushed === 0) {
1504
+ error("No tables were pushed.");
1505
+ }
1506
+ else {
1507
+ success(`Successfully pushed ${successfullyPushed} tables.`);
1508
+ }
1509
+ if (cliConfig.verbose) {
1510
+ errors.forEach((e) => console.error(e));
1801
1511
  }
1802
- success(`Successfully pushed ${tablesChanged.size} tables`);
1803
1512
  };
1804
- const pushCollection = async ({ attempts }) => {
1805
- warn("appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead");
1513
+ const pushCollection = async () => {
1514
+ warn(`${EXECUTABLE_NAME} push collection has been deprecated. Please consider using '${EXECUTABLE_NAME} push tables' instead`);
1806
1515
  const collections = [];
1807
- if (attempts) {
1808
- pollMaxDebounces = attempts;
1809
- }
1810
1516
  if (cliConfig.all) {
1811
1517
  checkDeployConditions(localConfig);
1812
1518
  collections.push(...localConfig.getCollections());
@@ -1826,90 +1532,35 @@ const pushCollection = async ({ attempts }) => {
1826
1532
  }
1827
1533
  if (collections.length === 0) {
1828
1534
  log("No collections found.");
1829
- hint("Use 'appwrite pull collections' to synchronize existing one, or use 'appwrite init collection' to create a new one.");
1535
+ hint(`Use '${EXECUTABLE_NAME} pull collections' to synchronize existing one, or use '${EXECUTABLE_NAME} init collection' to create a new one.`);
1830
1536
  return;
1831
1537
  }
1832
- const databases = Array.from(new Set(collections.map((collection) => collection["databaseId"])));
1833
- // Parallel db actions
1834
- await Promise.all(databases.map(async (databaseId) => {
1835
- const localDatabase = localConfig.getDatabase(databaseId);
1836
- const databasesService = await getDatabasesService();
1837
- try {
1838
- const database = await databasesService.get(databaseId);
1839
- if (database.name !== (localDatabase.name ?? databaseId)) {
1840
- await databasesService.update(databaseId, localDatabase.name ?? databaseId);
1841
- success(`Updated ${localDatabase.name} ( ${databaseId} ) name`);
1842
- }
1843
- }
1844
- catch (err) {
1845
- log(`Database ${databaseId} not found. Creating it now ...`);
1846
- await databasesService.create(databaseId, localDatabase.name ?? databaseId);
1847
- }
1848
- }));
1538
+ // Add database names to collections for the class method
1539
+ collections.forEach((collection) => {
1540
+ const localDatabase = localConfig.getDatabase(collection.databaseId);
1541
+ collection.databaseName = localDatabase.name ?? collection.databaseId;
1542
+ });
1849
1543
  if (!(await approveChanges(collections, async (args) => {
1850
1544
  const databasesService = await getDatabasesService();
1851
1545
  return await databasesService.getCollection(args.databaseId, args.collectionId);
1852
1546
  }, KeysCollection, "collectionId", "collections", ["attributes", "indexes"], "databaseId", "databaseId"))) {
1853
1547
  return;
1854
1548
  }
1855
- // Parallel collection actions
1856
- await Promise.all(collections.map(async (collection) => {
1857
- try {
1858
- const databasesService = await getDatabasesService();
1859
- const remoteCollection = await databasesService.getCollection(collection["databaseId"], collection["$id"]);
1860
- if (remoteCollection.name !== collection.name) {
1861
- await databasesService.updateCollection(collection["databaseId"], collection["$id"], collection.name);
1862
- success(`Updated ${collection.name} ( ${collection["$id"]} ) name`);
1863
- }
1864
- collection.remoteVersion = remoteCollection;
1865
- collection.isExisted = true;
1866
- }
1867
- catch (e) {
1868
- if (Number(e.code) === 404) {
1869
- log(`Collection ${collection.name} does not exist in the project. Creating ... `);
1870
- const databasesService = await getDatabasesService();
1871
- await databasesService.createCollection(collection["databaseId"], collection["$id"], collection.name, collection.documentSecurity, collection["$permissions"]);
1872
- }
1873
- else {
1874
- throw e;
1875
- }
1876
- }
1877
- }));
1878
- let numberOfCollections = 0;
1879
- // Serialize attribute actions
1880
- for (let collection of collections) {
1881
- let attributes = collection.attributes;
1882
- let indexes = collection.indexes;
1883
- if (collection.isExisted) {
1884
- attributes = await attributesToCreate(collection.remoteVersion.attributes, collection.attributes, collection);
1885
- indexes = await attributesToCreate(collection.remoteVersion.indexes, collection.indexes, collection, true);
1886
- if (Array.isArray(attributes) &&
1887
- attributes.length <= 0 &&
1888
- Array.isArray(indexes) &&
1889
- indexes.length <= 0) {
1890
- continue;
1891
- }
1892
- }
1893
- log(`Pushing collection ${collection.name} ( ${collection["databaseId"]} - ${collection["$id"]} ) attributes`);
1894
- try {
1895
- await createAttributes(attributes, collection);
1896
- }
1897
- catch (e) {
1898
- throw e;
1899
- }
1900
- try {
1901
- await createIndexes(indexes, collection);
1902
- }
1903
- catch (e) {
1904
- throw e;
1905
- }
1906
- numberOfCollections++;
1907
- success(`Successfully pushed ${collection.name} ( ${collection["$id"]} )`);
1549
+ log("Pushing collections ...");
1550
+ const pushInstance = await createPushInstance();
1551
+ const result = await pushInstance.pushCollections(collections);
1552
+ const { successfullyPushed, errors } = result;
1553
+ if (successfullyPushed === 0) {
1554
+ error("No collections were pushed.");
1555
+ }
1556
+ else {
1557
+ success(`Successfully pushed ${successfullyPushed} collections.`);
1558
+ }
1559
+ if (cliConfig.verbose) {
1560
+ errors.forEach((e) => console.error(e));
1908
1561
  }
1909
- success(`Successfully pushed ${numberOfCollections} collections`);
1910
1562
  };
1911
1563
  const pushBucket = async () => {
1912
- let response = {};
1913
1564
  let bucketIds = [];
1914
1565
  const configBuckets = localConfig.getBuckets();
1915
1566
  if (cliConfig.all) {
@@ -1924,7 +1575,7 @@ const pushBucket = async () => {
1924
1575
  }
1925
1576
  if (bucketIds.length === 0) {
1926
1577
  log("No buckets found.");
1927
- hint("Use 'appwrite pull buckets' to synchronize existing one, or use 'appwrite init bucket' to create a new one.");
1578
+ hint(`Use '${EXECUTABLE_NAME} pull buckets' to synchronize existing one, or use '${EXECUTABLE_NAME} init bucket' to create a new one.`);
1928
1579
  return;
1929
1580
  }
1930
1581
  let buckets = [];
@@ -1939,27 +1590,20 @@ const pushBucket = async () => {
1939
1590
  return;
1940
1591
  }
1941
1592
  log("Pushing buckets ...");
1942
- for (let bucket of buckets) {
1943
- log(`Pushing bucket ${chalk.bold(bucket["name"])} ...`);
1944
- const storageService = await getStorageService();
1945
- try {
1946
- response = await storageService.getBucket(bucket["$id"]);
1947
- await storageService.updateBucket(bucket["$id"], bucket.name, bucket["$permissions"], bucket.fileSecurity, bucket.enabled, bucket.maximumFileSize, bucket.allowedFileExtensions, bucket.encryption, bucket.antivirus, bucket.compression);
1948
- }
1949
- catch (e) {
1950
- if (Number(e.code) === 404) {
1951
- log(`Bucket ${bucket.name} does not exist in the project. Creating ... `);
1952
- response = await storageService.createBucket(bucket["$id"], bucket.name, bucket["$permissions"], bucket.fileSecurity, bucket.enabled, bucket.maximumFileSize, bucket.allowedFileExtensions, bucket.compression, bucket.encryption, bucket.antivirus);
1953
- }
1954
- else {
1955
- throw e;
1956
- }
1957
- }
1593
+ const pushInstance = await createPushInstance();
1594
+ const result = await pushInstance.pushBuckets(buckets);
1595
+ const { successfullyPushed, errors } = result;
1596
+ if (successfullyPushed === 0) {
1597
+ error("No buckets were pushed.");
1598
+ }
1599
+ else {
1600
+ success(`Successfully pushed ${successfullyPushed} buckets.`);
1601
+ }
1602
+ if (cliConfig.verbose) {
1603
+ errors.forEach((e) => console.error(e));
1958
1604
  }
1959
- success(`Successfully pushed ${buckets.length} buckets.`);
1960
1605
  };
1961
1606
  const pushTeam = async () => {
1962
- let response = {};
1963
1607
  let teamIds = [];
1964
1608
  const configTeams = localConfig.getTeams();
1965
1609
  if (cliConfig.all) {
@@ -1974,7 +1618,7 @@ const pushTeam = async () => {
1974
1618
  }
1975
1619
  if (teamIds.length === 0) {
1976
1620
  log("No teams found.");
1977
- hint("Use 'appwrite pull teams' to synchronize existing one, or use 'appwrite init team' to create a new one.");
1621
+ hint(`Use '${EXECUTABLE_NAME} pull teams' to synchronize existing one, or use '${EXECUTABLE_NAME} init team' to create a new one.`);
1978
1622
  return;
1979
1623
  }
1980
1624
  let teams = [];
@@ -1989,27 +1633,20 @@ const pushTeam = async () => {
1989
1633
  return;
1990
1634
  }
1991
1635
  log("Pushing teams ...");
1992
- for (let team of teams) {
1993
- log(`Pushing team ${chalk.bold(team["name"])} ...`);
1994
- const teamsService = await getTeamsService();
1995
- try {
1996
- response = await teamsService.get(team["$id"]);
1997
- await teamsService.updateName(team["$id"], team.name);
1998
- }
1999
- catch (e) {
2000
- if (Number(e.code) === 404) {
2001
- log(`Team ${team.name} does not exist in the project. Creating ... `);
2002
- response = await teamsService.create(team["$id"], team.name);
2003
- }
2004
- else {
2005
- throw e;
2006
- }
2007
- }
1636
+ const pushInstance = await createPushInstance();
1637
+ const result = await pushInstance.pushTeams(teams);
1638
+ const { successfullyPushed, errors } = result;
1639
+ if (successfullyPushed === 0) {
1640
+ error("No teams were pushed.");
1641
+ }
1642
+ else {
1643
+ success(`Successfully pushed ${successfullyPushed} teams.`);
1644
+ }
1645
+ if (cliConfig.verbose) {
1646
+ errors.forEach((e) => console.error(e));
2008
1647
  }
2009
- success(`Successfully pushed ${teams.length} teams.`);
2010
1648
  };
2011
1649
  const pushMessagingTopic = async () => {
2012
- let response = {};
2013
1650
  let topicsIds = [];
2014
1651
  const configTopics = localConfig.getMessagingTopics();
2015
1652
  if (cliConfig.all) {
@@ -2024,7 +1661,7 @@ const pushMessagingTopic = async () => {
2024
1661
  }
2025
1662
  if (topicsIds.length === 0) {
2026
1663
  log("No topics found.");
2027
- hint("Use 'appwrite pull topics' to synchronize existing one, or use 'appwrite init topic' to create a new one.");
1664
+ hint(`Use '${EXECUTABLE_NAME} pull topics' to synchronize existing one, or use '${EXECUTABLE_NAME} init topic' to create a new one.`);
2028
1665
  return;
2029
1666
  }
2030
1667
  let topics = [];
@@ -2039,26 +1676,18 @@ const pushMessagingTopic = async () => {
2039
1676
  return;
2040
1677
  }
2041
1678
  log("Pushing topics ...");
2042
- for (let topic of topics) {
2043
- log(`Pushing topic ${chalk.bold(topic["name"])} ...`);
2044
- const messagingService = await getMessagingService();
2045
- try {
2046
- response = await messagingService.getTopic(topic["$id"]);
2047
- log(`Topic ${topic.name} ( ${topic["$id"]} ) already exists.`);
2048
- await messagingService.updateTopic(topic["$id"], topic.name, topic.subscribe);
2049
- }
2050
- catch (e) {
2051
- if (Number(e.code) === 404) {
2052
- log(`Topic ${topic.name} does not exist in the project. Creating ... `);
2053
- response = await messagingService.createTopic(topic["$id"], topic.name, topic.subscribe);
2054
- success(`Created ${topic.name} ( ${topic["$id"]} )`);
2055
- }
2056
- else {
2057
- throw e;
2058
- }
2059
- }
1679
+ const pushInstance = await createPushInstance();
1680
+ const result = await pushInstance.pushMessagingTopics(topics);
1681
+ const { successfullyPushed, errors } = result;
1682
+ if (successfullyPushed === 0) {
1683
+ error("No topics were pushed.");
1684
+ }
1685
+ else {
1686
+ success(`Successfully pushed ${successfullyPushed} topics.`);
1687
+ }
1688
+ if (cliConfig.verbose) {
1689
+ errors.forEach((e) => console.error(e));
2060
1690
  }
2061
- success(`Successfully pushed ${topics.length} topics.`);
2062
1691
  };
2063
1692
  export const push = new Command("push")
2064
1693
  .description(commandDescriptions["push"])
@@ -2120,8 +1749,8 @@ push
2120
1749
  .description("Push messaging topics in the current project.")
2121
1750
  .action(actionRunner(pushMessagingTopic));
2122
1751
  export const deploy = new Command("deploy")
2123
- .description("Removed. Use appwrite push instead")
1752
+ .description(`Removed. Use ${EXECUTABLE_NAME} push instead`)
2124
1753
  .action(actionRunner(async () => {
2125
- warn("appwrite deploy has been removed. Please use 'appwrite push' instead");
1754
+ warn(`${EXECUTABLE_NAME} deploy has been removed. Please use '${EXECUTABLE_NAME} push' instead`);
2126
1755
  }));
2127
1756
  //# sourceMappingURL=push.js.map