@directus/api 9.25.0

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 (855) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +89 -0
  3. package/dist/app.d.ts +2 -0
  4. package/dist/app.js +223 -0
  5. package/dist/app.test.d.ts +1 -0
  6. package/dist/auth/auth.d.ts +46 -0
  7. package/dist/auth/auth.js +36 -0
  8. package/dist/auth/drivers/index.d.ts +5 -0
  9. package/dist/auth/drivers/index.js +5 -0
  10. package/dist/auth/drivers/ldap.d.ts +20 -0
  11. package/dist/auth/drivers/ldap.js +330 -0
  12. package/dist/auth/drivers/local.d.ts +9 -0
  13. package/dist/auth/drivers/local.js +83 -0
  14. package/dist/auth/drivers/oauth2.d.ts +19 -0
  15. package/dist/auth/drivers/oauth2.js +293 -0
  16. package/dist/auth/drivers/openid.d.ts +19 -0
  17. package/dist/auth/drivers/openid.js +316 -0
  18. package/dist/auth/drivers/saml.d.ts +15 -0
  19. package/dist/auth/drivers/saml.js +145 -0
  20. package/dist/auth.d.ts +3 -0
  21. package/dist/auth.js +62 -0
  22. package/dist/cache.d.ts +20 -0
  23. package/dist/cache.js +138 -0
  24. package/dist/cli/commands/bootstrap/index.d.ts +3 -0
  25. package/dist/cli/commands/bootstrap/index.js +71 -0
  26. package/dist/cli/commands/count/index.d.ts +1 -0
  27. package/dist/cli/commands/count/index.js +21 -0
  28. package/dist/cli/commands/database/install.d.ts +1 -0
  29. package/dist/cli/commands/database/install.js +16 -0
  30. package/dist/cli/commands/database/migrate.d.ts +1 -0
  31. package/dist/cli/commands/database/migrate.js +23 -0
  32. package/dist/cli/commands/init/index.d.ts +1 -0
  33. package/dist/cli/commands/init/index.js +102 -0
  34. package/dist/cli/commands/init/questions.d.ts +20 -0
  35. package/dist/cli/commands/init/questions.js +65 -0
  36. package/dist/cli/commands/roles/create.d.ts +4 -0
  37. package/dist/cli/commands/roles/create.js +23 -0
  38. package/dist/cli/commands/schema/apply.d.ts +4 -0
  39. package/dist/cli/commands/schema/apply.js +153 -0
  40. package/dist/cli/commands/schema/snapshot.d.ts +4 -0
  41. package/dist/cli/commands/schema/snapshot.js +56 -0
  42. package/dist/cli/commands/security/key.d.ts +1 -0
  43. package/dist/cli/commands/security/key.js +5 -0
  44. package/dist/cli/commands/security/secret.d.ts +1 -0
  45. package/dist/cli/commands/security/secret.js +5 -0
  46. package/dist/cli/commands/users/create.d.ts +5 -0
  47. package/dist/cli/commands/users/create.js +23 -0
  48. package/dist/cli/commands/users/passwd.d.ts +4 -0
  49. package/dist/cli/commands/users/passwd.js +35 -0
  50. package/dist/cli/index.d.ts +2 -0
  51. package/dist/cli/index.js +89 -0
  52. package/dist/cli/run.d.ts +1 -0
  53. package/dist/cli/run.js +8 -0
  54. package/dist/cli/utils/create-db-connection.d.ts +13 -0
  55. package/dist/cli/utils/create-db-connection.js +58 -0
  56. package/dist/cli/utils/create-env/env-stub.liquid +328 -0
  57. package/dist/cli/utils/create-env/index.d.ts +3 -0
  58. package/dist/cli/utils/create-env/index.js +41 -0
  59. package/dist/cli/utils/defaults.d.ts +11 -0
  60. package/dist/cli/utils/defaults.js +11 -0
  61. package/dist/cli/utils/drivers.d.ts +3 -0
  62. package/dist/cli/utils/drivers.js +15 -0
  63. package/dist/constants.d.ts +17 -0
  64. package/dist/constants.js +70 -0
  65. package/dist/controllers/activity.d.ts +2 -0
  66. package/dist/controllers/activity.js +131 -0
  67. package/dist/controllers/assets.d.ts +2 -0
  68. package/dist/controllers/assets.js +194 -0
  69. package/dist/controllers/auth.d.ts +2 -0
  70. package/dist/controllers/auth.js +163 -0
  71. package/dist/controllers/collections.d.ts +2 -0
  72. package/dist/controllers/collections.js +101 -0
  73. package/dist/controllers/dashboards.d.ts +2 -0
  74. package/dist/controllers/dashboards.js +140 -0
  75. package/dist/controllers/extensions.d.ts +2 -0
  76. package/dist/controllers/extensions.js +42 -0
  77. package/dist/controllers/fields.d.ts +2 -0
  78. package/dist/controllers/fields.js +155 -0
  79. package/dist/controllers/files.d.ts +4 -0
  80. package/dist/controllers/files.js +267 -0
  81. package/dist/controllers/files.test.d.ts +1 -0
  82. package/dist/controllers/flows.d.ts +2 -0
  83. package/dist/controllers/flows.js +159 -0
  84. package/dist/controllers/folders.d.ts +2 -0
  85. package/dist/controllers/folders.js +149 -0
  86. package/dist/controllers/graphql.d.ts +2 -0
  87. package/dist/controllers/graphql.js +31 -0
  88. package/dist/controllers/items.d.ts +2 -0
  89. package/dist/controllers/items.js +179 -0
  90. package/dist/controllers/not-found.d.ts +14 -0
  91. package/dist/controllers/not-found.js +31 -0
  92. package/dist/controllers/notifications.d.ts +2 -0
  93. package/dist/controllers/notifications.js +149 -0
  94. package/dist/controllers/operations.d.ts +2 -0
  95. package/dist/controllers/operations.js +140 -0
  96. package/dist/controllers/panels.d.ts +2 -0
  97. package/dist/controllers/panels.js +140 -0
  98. package/dist/controllers/permissions.d.ts +2 -0
  99. package/dist/controllers/permissions.js +151 -0
  100. package/dist/controllers/presets.d.ts +2 -0
  101. package/dist/controllers/presets.js +149 -0
  102. package/dist/controllers/relations.d.ts +2 -0
  103. package/dist/controllers/relations.js +112 -0
  104. package/dist/controllers/revisions.d.ts +2 -0
  105. package/dist/controllers/revisions.js +35 -0
  106. package/dist/controllers/roles.d.ts +2 -0
  107. package/dist/controllers/roles.js +140 -0
  108. package/dist/controllers/schema.d.ts +2 -0
  109. package/dist/controllers/schema.js +93 -0
  110. package/dist/controllers/server.d.ts +2 -0
  111. package/dist/controllers/server.js +57 -0
  112. package/dist/controllers/settings.d.ts +2 -0
  113. package/dist/controllers/settings.js +36 -0
  114. package/dist/controllers/shares.d.ts +2 -0
  115. package/dist/controllers/shares.js +213 -0
  116. package/dist/controllers/users.d.ts +2 -0
  117. package/dist/controllers/users.js +357 -0
  118. package/dist/controllers/utils.d.ts +2 -0
  119. package/dist/controllers/utils.js +118 -0
  120. package/dist/controllers/webhooks.d.ts +2 -0
  121. package/dist/controllers/webhooks.js +137 -0
  122. package/dist/database/helpers/date/dialects/default.d.ts +3 -0
  123. package/dist/database/helpers/date/dialects/default.js +3 -0
  124. package/dist/database/helpers/date/dialects/mssql.d.ts +4 -0
  125. package/dist/database/helpers/date/dialects/mssql.js +8 -0
  126. package/dist/database/helpers/date/dialects/mysql.d.ts +5 -0
  127. package/dist/database/helpers/date/dialects/mysql.js +12 -0
  128. package/dist/database/helpers/date/dialects/oracle.d.ts +4 -0
  129. package/dist/database/helpers/date/dialects/oracle.js +11 -0
  130. package/dist/database/helpers/date/dialects/sqlite.d.ts +5 -0
  131. package/dist/database/helpers/date/dialects/sqlite.js +26 -0
  132. package/dist/database/helpers/date/index.d.ts +7 -0
  133. package/dist/database/helpers/date/index.js +7 -0
  134. package/dist/database/helpers/date/types.d.ts +7 -0
  135. package/dist/database/helpers/date/types.js +20 -0
  136. package/dist/database/helpers/fn/dialects/mssql.d.ts +13 -0
  137. package/dist/database/helpers/fn/dialects/mssql.js +44 -0
  138. package/dist/database/helpers/fn/dialects/mysql.d.ts +13 -0
  139. package/dist/database/helpers/fn/dialects/mysql.js +38 -0
  140. package/dist/database/helpers/fn/dialects/oracle.d.ts +13 -0
  141. package/dist/database/helpers/fn/dialects/oracle.js +44 -0
  142. package/dist/database/helpers/fn/dialects/postgres.d.ts +13 -0
  143. package/dist/database/helpers/fn/dialects/postgres.js +48 -0
  144. package/dist/database/helpers/fn/dialects/sqlite.d.ts +13 -0
  145. package/dist/database/helpers/fn/dialects/sqlite.js +68 -0
  146. package/dist/database/helpers/fn/index.d.ts +7 -0
  147. package/dist/database/helpers/fn/index.js +7 -0
  148. package/dist/database/helpers/fn/types.d.ts +22 -0
  149. package/dist/database/helpers/fn/types.js +26 -0
  150. package/dist/database/helpers/geometry/dialects/mssql.d.ts +14 -0
  151. package/dist/database/helpers/geometry/dialects/mssql.js +32 -0
  152. package/dist/database/helpers/geometry/dialects/mysql.d.ts +7 -0
  153. package/dist/database/helpers/geometry/dialects/mysql.js +12 -0
  154. package/dist/database/helpers/geometry/dialects/oracle.d.ts +15 -0
  155. package/dist/database/helpers/geometry/dialects/oracle.js +35 -0
  156. package/dist/database/helpers/geometry/dialects/postgres.d.ts +10 -0
  157. package/dist/database/helpers/geometry/dialects/postgres.js +18 -0
  158. package/dist/database/helpers/geometry/dialects/redshift.d.ts +7 -0
  159. package/dist/database/helpers/geometry/dialects/redshift.js +12 -0
  160. package/dist/database/helpers/geometry/dialects/sqlite.d.ts +6 -0
  161. package/dist/database/helpers/geometry/dialects/sqlite.js +10 -0
  162. package/dist/database/helpers/geometry/index.d.ts +7 -0
  163. package/dist/database/helpers/geometry/index.js +7 -0
  164. package/dist/database/helpers/geometry/types.d.ts +20 -0
  165. package/dist/database/helpers/geometry/types.js +49 -0
  166. package/dist/database/helpers/index.d.ts +13 -0
  167. package/dist/database/helpers/index.js +17 -0
  168. package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +6 -0
  169. package/dist/database/helpers/schema/dialects/cockroachdb.js +17 -0
  170. package/dist/database/helpers/schema/dialects/default.d.ts +3 -0
  171. package/dist/database/helpers/schema/dialects/default.js +3 -0
  172. package/dist/database/helpers/schema/dialects/mssql.d.ts +7 -0
  173. package/dist/database/helpers/schema/dialects/mssql.js +20 -0
  174. package/dist/database/helpers/schema/dialects/mysql.d.ts +5 -0
  175. package/dist/database/helpers/schema/dialects/mysql.js +14 -0
  176. package/dist/database/helpers/schema/dialects/oracle.d.ts +9 -0
  177. package/dist/database/helpers/schema/dialects/oracle.js +32 -0
  178. package/dist/database/helpers/schema/dialects/sqlite.d.ts +5 -0
  179. package/dist/database/helpers/schema/dialects/sqlite.js +13 -0
  180. package/dist/database/helpers/schema/index.d.ts +7 -0
  181. package/dist/database/helpers/schema/index.js +7 -0
  182. package/dist/database/helpers/schema/types.d.ts +26 -0
  183. package/dist/database/helpers/schema/types.js +91 -0
  184. package/dist/database/helpers/types.d.ts +5 -0
  185. package/dist/database/helpers/types.js +6 -0
  186. package/dist/database/index.d.ts +20 -0
  187. package/dist/database/index.js +267 -0
  188. package/dist/database/migrations/20201028A-remove-collection-foreign-keys.d.ts +3 -0
  189. package/dist/database/migrations/20201028A-remove-collection-foreign-keys.js +42 -0
  190. package/dist/database/migrations/20201029A-remove-system-relations.d.ts +3 -0
  191. package/dist/database/migrations/20201029A-remove-system-relations.js +122 -0
  192. package/dist/database/migrations/20201029B-remove-system-collections.d.ts +3 -0
  193. package/dist/database/migrations/20201029B-remove-system-collections.js +93 -0
  194. package/dist/database/migrations/20201029C-remove-system-fields.d.ts +3 -0
  195. package/dist/database/migrations/20201029C-remove-system-fields.js +1643 -0
  196. package/dist/database/migrations/20201105A-add-cascade-system-relations.d.ts +8 -0
  197. package/dist/database/migrations/20201105A-add-cascade-system-relations.js +131 -0
  198. package/dist/database/migrations/20201105B-change-webhook-url-type.d.ts +3 -0
  199. package/dist/database/migrations/20201105B-change-webhook-url-type.js +12 -0
  200. package/dist/database/migrations/20210225A-add-relations-sort-field.d.ts +3 -0
  201. package/dist/database/migrations/20210225A-add-relations-sort-field.js +28 -0
  202. package/dist/database/migrations/20210304A-remove-locked-fields.d.ts +3 -0
  203. package/dist/database/migrations/20210304A-remove-locked-fields.js +10 -0
  204. package/dist/database/migrations/20210312A-webhooks-collections-text.d.ts +3 -0
  205. package/dist/database/migrations/20210312A-webhooks-collections-text.js +12 -0
  206. package/dist/database/migrations/20210331A-add-refresh-interval.d.ts +3 -0
  207. package/dist/database/migrations/20210331A-add-refresh-interval.js +10 -0
  208. package/dist/database/migrations/20210415A-make-filesize-nullable.d.ts +3 -0
  209. package/dist/database/migrations/20210415A-make-filesize-nullable.js +15 -0
  210. package/dist/database/migrations/20210416A-add-collections-accountability.d.ts +3 -0
  211. package/dist/database/migrations/20210416A-add-collections-accountability.js +11 -0
  212. package/dist/database/migrations/20210422A-remove-files-interface.d.ts +3 -0
  213. package/dist/database/migrations/20210422A-remove-files-interface.js +6 -0
  214. package/dist/database/migrations/20210506A-rename-interfaces.d.ts +3 -0
  215. package/dist/database/migrations/20210506A-rename-interfaces.js +74 -0
  216. package/dist/database/migrations/20210510A-restructure-relations.d.ts +3 -0
  217. package/dist/database/migrations/20210510A-restructure-relations.js +27 -0
  218. package/dist/database/migrations/20210518A-add-foreign-key-constraints.d.ts +3 -0
  219. package/dist/database/migrations/20210518A-add-foreign-key-constraints.js +106 -0
  220. package/dist/database/migrations/20210519A-add-system-fk-triggers.d.ts +3 -0
  221. package/dist/database/migrations/20210519A-add-system-fk-triggers.js +164 -0
  222. package/dist/database/migrations/20210521A-add-collections-icon-color.d.ts +3 -0
  223. package/dist/database/migrations/20210521A-add-collections-icon-color.js +10 -0
  224. package/dist/database/migrations/20210525A-add-insights.d.ts +3 -0
  225. package/dist/database/migrations/20210525A-add-insights.js +31 -0
  226. package/dist/database/migrations/20210608A-add-deep-clone-config.d.ts +3 -0
  227. package/dist/database/migrations/20210608A-add-deep-clone-config.js +10 -0
  228. package/dist/database/migrations/20210626A-change-filesize-bigint.d.ts +3 -0
  229. package/dist/database/migrations/20210626A-change-filesize-bigint.js +19 -0
  230. package/dist/database/migrations/20210716A-add-conditions-to-fields.d.ts +3 -0
  231. package/dist/database/migrations/20210716A-add-conditions-to-fields.js +10 -0
  232. package/dist/database/migrations/20210721A-add-default-folder.d.ts +3 -0
  233. package/dist/database/migrations/20210721A-add-default-folder.js +18 -0
  234. package/dist/database/migrations/20210802A-replace-groups.d.ts +3 -0
  235. package/dist/database/migrations/20210802A-replace-groups.js +45 -0
  236. package/dist/database/migrations/20210803A-add-required-to-fields.d.ts +3 -0
  237. package/dist/database/migrations/20210803A-add-required-to-fields.js +10 -0
  238. package/dist/database/migrations/20210805A-update-groups.d.ts +3 -0
  239. package/dist/database/migrations/20210805A-update-groups.js +29 -0
  240. package/dist/database/migrations/20210805B-change-image-metadata-structure.d.ts +3 -0
  241. package/dist/database/migrations/20210805B-change-image-metadata-structure.js +84 -0
  242. package/dist/database/migrations/20210811A-add-geometry-config.d.ts +3 -0
  243. package/dist/database/migrations/20210811A-add-geometry-config.js +12 -0
  244. package/dist/database/migrations/20210831A-remove-limit-column.d.ts +3 -0
  245. package/dist/database/migrations/20210831A-remove-limit-column.js +10 -0
  246. package/dist/database/migrations/20210903A-add-auth-provider.d.ts +3 -0
  247. package/dist/database/migrations/20210903A-add-auth-provider.js +35 -0
  248. package/dist/database/migrations/20210907A-webhooks-collections-not-null.d.ts +3 -0
  249. package/dist/database/migrations/20210907A-webhooks-collections-not-null.js +13 -0
  250. package/dist/database/migrations/20210910A-move-module-setup.d.ts +3 -0
  251. package/dist/database/migrations/20210910A-move-module-setup.js +16 -0
  252. package/dist/database/migrations/20210920A-webhooks-url-not-null.d.ts +3 -0
  253. package/dist/database/migrations/20210920A-webhooks-url-not-null.js +21 -0
  254. package/dist/database/migrations/20210924A-add-collection-organization.d.ts +3 -0
  255. package/dist/database/migrations/20210924A-add-collection-organization.js +14 -0
  256. package/dist/database/migrations/20210927A-replace-fields-group.d.ts +3 -0
  257. package/dist/database/migrations/20210927A-replace-fields-group.js +48 -0
  258. package/dist/database/migrations/20210927B-replace-m2m-interface.d.ts +3 -0
  259. package/dist/database/migrations/20210927B-replace-m2m-interface.js +16 -0
  260. package/dist/database/migrations/20210929A-rename-login-action.d.ts +3 -0
  261. package/dist/database/migrations/20210929A-rename-login-action.js +14 -0
  262. package/dist/database/migrations/20211007A-update-presets.d.ts +3 -0
  263. package/dist/database/migrations/20211007A-update-presets.js +98 -0
  264. package/dist/database/migrations/20211009A-add-auth-data.d.ts +3 -0
  265. package/dist/database/migrations/20211009A-add-auth-data.js +10 -0
  266. package/dist/database/migrations/20211016A-add-webhook-headers.d.ts +3 -0
  267. package/dist/database/migrations/20211016A-add-webhook-headers.js +10 -0
  268. package/dist/database/migrations/20211103A-set-unique-to-user-token.d.ts +3 -0
  269. package/dist/database/migrations/20211103A-set-unique-to-user-token.js +10 -0
  270. package/dist/database/migrations/20211103B-update-special-geometry.d.ts +3 -0
  271. package/dist/database/migrations/20211103B-update-special-geometry.js +20 -0
  272. package/dist/database/migrations/20211104A-remove-collections-listing.d.ts +3 -0
  273. package/dist/database/migrations/20211104A-remove-collections-listing.js +10 -0
  274. package/dist/database/migrations/20211118A-add-notifications.d.ts +3 -0
  275. package/dist/database/migrations/20211118A-add-notifications.js +23 -0
  276. package/dist/database/migrations/20211211A-add-shares.d.ts +3 -0
  277. package/dist/database/migrations/20211211A-add-shares.js +33 -0
  278. package/dist/database/migrations/20211230A-add-project-descriptor.d.ts +3 -0
  279. package/dist/database/migrations/20211230A-add-project-descriptor.js +10 -0
  280. package/dist/database/migrations/20220303A-remove-default-project-color.d.ts +3 -0
  281. package/dist/database/migrations/20220303A-remove-default-project-color.js +17 -0
  282. package/dist/database/migrations/20220308A-add-bookmark-icon-and-color.d.ts +3 -0
  283. package/dist/database/migrations/20220308A-add-bookmark-icon-and-color.js +12 -0
  284. package/dist/database/migrations/20220314A-add-translation-strings.d.ts +3 -0
  285. package/dist/database/migrations/20220314A-add-translation-strings.js +10 -0
  286. package/dist/database/migrations/20220322A-rename-field-typecast-flags.d.ts +3 -0
  287. package/dist/database/migrations/20220322A-rename-field-typecast-flags.js +72 -0
  288. package/dist/database/migrations/20220323A-add-field-validation.d.ts +3 -0
  289. package/dist/database/migrations/20220323A-add-field-validation.js +12 -0
  290. package/dist/database/migrations/20220325A-fix-typecast-flags.d.ts +3 -0
  291. package/dist/database/migrations/20220325A-fix-typecast-flags.js +44 -0
  292. package/dist/database/migrations/20220325B-add-default-language.d.ts +3 -0
  293. package/dist/database/migrations/20220325B-add-default-language.js +23 -0
  294. package/dist/database/migrations/20220402A-remove-default-value-panel-icon.d.ts +3 -0
  295. package/dist/database/migrations/20220402A-remove-default-value-panel-icon.js +17 -0
  296. package/dist/database/migrations/20220429A-add-flows.d.ts +3 -0
  297. package/dist/database/migrations/20220429A-add-flows.js +77 -0
  298. package/dist/database/migrations/20220429B-add-color-to-insights-icon.d.ts +3 -0
  299. package/dist/database/migrations/20220429B-add-color-to-insights-icon.js +10 -0
  300. package/dist/database/migrations/20220429C-drop-non-null-from-ip-of-activity.d.ts +3 -0
  301. package/dist/database/migrations/20220429C-drop-non-null-from-ip-of-activity.js +10 -0
  302. package/dist/database/migrations/20220429D-drop-non-null-from-sender-of-notifications.d.ts +3 -0
  303. package/dist/database/migrations/20220429D-drop-non-null-from-sender-of-notifications.js +10 -0
  304. package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.d.ts +3 -0
  305. package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.js +6 -0
  306. package/dist/database/migrations/20220801A-update-notifications-timestamp-column.d.ts +3 -0
  307. package/dist/database/migrations/20220801A-update-notifications-timestamp-column.js +14 -0
  308. package/dist/database/migrations/20220802A-add-custom-aspect-ratios.d.ts +3 -0
  309. package/dist/database/migrations/20220802A-add-custom-aspect-ratios.js +10 -0
  310. package/dist/database/migrations/20220826A-add-origin-to-accountability.d.ts +3 -0
  311. package/dist/database/migrations/20220826A-add-origin-to-accountability.js +16 -0
  312. package/dist/database/migrations/20230401A-update-material-icons.d.ts +3 -0
  313. package/dist/database/migrations/20230401A-update-material-icons.js +19 -0
  314. package/dist/database/migrations/run.d.ts +2 -0
  315. package/dist/database/migrations/run.js +91 -0
  316. package/dist/database/migrations/run.test.d.ts +1 -0
  317. package/dist/database/run-ast.d.ts +26 -0
  318. package/dist/database/run-ast.js +445 -0
  319. package/dist/database/seeds/01-collections.yaml +42 -0
  320. package/dist/database/seeds/02-roles.yaml +36 -0
  321. package/dist/database/seeds/03-users.yaml +63 -0
  322. package/dist/database/seeds/04-fields.yaml +58 -0
  323. package/dist/database/seeds/05-activity.yaml +35 -0
  324. package/dist/database/seeds/06-folders.yaml +16 -0
  325. package/dist/database/seeds/07-files.yaml +74 -0
  326. package/dist/database/seeds/08-permissions.yaml +32 -0
  327. package/dist/database/seeds/09-presets.yaml +37 -0
  328. package/dist/database/seeds/10-relations.yaml +40 -0
  329. package/dist/database/seeds/11-revisions.yaml +33 -0
  330. package/dist/database/seeds/12-sessions.yaml +23 -0
  331. package/dist/database/seeds/13-settings.yaml +49 -0
  332. package/dist/database/seeds/14-webhooks.yaml +35 -0
  333. package/dist/database/seeds/15-migrations.yaml +14 -0
  334. package/dist/database/seeds/run.d.ts +2 -0
  335. package/dist/database/seeds/run.js +73 -0
  336. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +102 -0
  337. package/dist/database/system-data/app-access-permissions/index.d.ts +3 -0
  338. package/dist/database/system-data/app-access-permissions/index.js +17 -0
  339. package/dist/database/system-data/app-access-permissions/schema-access-permissions.yaml +17 -0
  340. package/dist/database/system-data/collections/collections.yaml +74 -0
  341. package/dist/database/system-data/collections/index.d.ts +2 -0
  342. package/dist/database/system-data/collections/index.js +9 -0
  343. package/dist/database/system-data/fields/_defaults.yaml +16 -0
  344. package/dist/database/system-data/fields/activity.yaml +83 -0
  345. package/dist/database/system-data/fields/collections.yaml +214 -0
  346. package/dist/database/system-data/fields/dashboards.yaml +20 -0
  347. package/dist/database/system-data/fields/fields.yaml +104 -0
  348. package/dist/database/system-data/fields/files.yaml +144 -0
  349. package/dist/database/system-data/fields/flows.yaml +26 -0
  350. package/dist/database/system-data/fields/folders.yaml +14 -0
  351. package/dist/database/system-data/fields/index.d.ts +2 -0
  352. package/dist/database/system-data/fields/index.js +33 -0
  353. package/dist/database/system-data/fields/migrations.yaml +10 -0
  354. package/dist/database/system-data/fields/notifications.yaml +15 -0
  355. package/dist/database/system-data/fields/operations.yaml +23 -0
  356. package/dist/database/system-data/fields/panels.yaml +29 -0
  357. package/dist/database/system-data/fields/permissions.yaml +37 -0
  358. package/dist/database/system-data/fields/presets.yaml +56 -0
  359. package/dist/database/system-data/fields/relations.yaml +34 -0
  360. package/dist/database/system-data/fields/revisions.yaml +27 -0
  361. package/dist/database/system-data/fields/roles.yaml +61 -0
  362. package/dist/database/system-data/fields/sessions.yaml +16 -0
  363. package/dist/database/system-data/fields/settings.yaml +417 -0
  364. package/dist/database/system-data/fields/shares.yaml +83 -0
  365. package/dist/database/system-data/fields/users.yaml +182 -0
  366. package/dist/database/system-data/fields/webhooks.yaml +141 -0
  367. package/dist/database/system-data/relations/index.d.ts +2 -0
  368. package/dist/database/system-data/relations/index.js +9 -0
  369. package/dist/database/system-data/relations/relations.yaml +125 -0
  370. package/dist/emitter.d.ts +19 -0
  371. package/dist/emitter.js +79 -0
  372. package/dist/env.d.ts +15 -0
  373. package/dist/env.js +465 -0
  374. package/dist/env.test.d.ts +1 -0
  375. package/dist/exceptions/database/contains-null-values.d.ts +9 -0
  376. package/dist/exceptions/database/contains-null-values.js +6 -0
  377. package/dist/exceptions/database/dialects/mssql.d.ts +2 -0
  378. package/dist/exceptions/database/dialects/mssql.js +152 -0
  379. package/dist/exceptions/database/dialects/mysql.d.ts +2 -0
  380. package/dist/exceptions/database/dialects/mysql.js +144 -0
  381. package/dist/exceptions/database/dialects/oracle.d.ts +2 -0
  382. package/dist/exceptions/database/dialects/oracle.js +23 -0
  383. package/dist/exceptions/database/dialects/postgres.d.ts +2 -0
  384. package/dist/exceptions/database/dialects/postgres.js +102 -0
  385. package/dist/exceptions/database/dialects/sqlite.d.ts +2 -0
  386. package/dist/exceptions/database/dialects/sqlite.js +51 -0
  387. package/dist/exceptions/database/dialects/types.d.ts +41 -0
  388. package/dist/exceptions/database/dialects/types.js +1 -0
  389. package/dist/exceptions/database/invalid-foreign-key.d.ts +10 -0
  390. package/dist/exceptions/database/invalid-foreign-key.js +11 -0
  391. package/dist/exceptions/database/not-null-violation.d.ts +9 -0
  392. package/dist/exceptions/database/not-null-violation.js +6 -0
  393. package/dist/exceptions/database/record-not-unique.d.ts +10 -0
  394. package/dist/exceptions/database/record-not-unique.js +11 -0
  395. package/dist/exceptions/database/translate.d.ts +11 -0
  396. package/dist/exceptions/database/translate.js +44 -0
  397. package/dist/exceptions/database/value-out-of-range.d.ts +10 -0
  398. package/dist/exceptions/database/value-out-of-range.js +11 -0
  399. package/dist/exceptions/database/value-too-long.d.ts +9 -0
  400. package/dist/exceptions/database/value-too-long.js +11 -0
  401. package/dist/exceptions/forbidden.d.ts +6 -0
  402. package/dist/exceptions/forbidden.js +13 -0
  403. package/dist/exceptions/graphql-validation.d.ts +4 -0
  404. package/dist/exceptions/graphql-validation.js +6 -0
  405. package/dist/exceptions/hit-rate-limit.d.ts +9 -0
  406. package/dist/exceptions/hit-rate-limit.js +6 -0
  407. package/dist/exceptions/illegal-asset-transformation.d.ts +4 -0
  408. package/dist/exceptions/illegal-asset-transformation.js +6 -0
  409. package/dist/exceptions/index.d.ts +21 -0
  410. package/dist/exceptions/index.js +21 -0
  411. package/dist/exceptions/invalid-config.d.ts +4 -0
  412. package/dist/exceptions/invalid-config.js +6 -0
  413. package/dist/exceptions/invalid-credentials.d.ts +4 -0
  414. package/dist/exceptions/invalid-credentials.js +6 -0
  415. package/dist/exceptions/invalid-ip.d.ts +4 -0
  416. package/dist/exceptions/invalid-ip.js +6 -0
  417. package/dist/exceptions/invalid-otp.d.ts +4 -0
  418. package/dist/exceptions/invalid-otp.js +6 -0
  419. package/dist/exceptions/invalid-payload.d.ts +4 -0
  420. package/dist/exceptions/invalid-payload.js +6 -0
  421. package/dist/exceptions/invalid-provider.d.ts +4 -0
  422. package/dist/exceptions/invalid-provider.js +6 -0
  423. package/dist/exceptions/invalid-query.d.ts +4 -0
  424. package/dist/exceptions/invalid-query.js +6 -0
  425. package/dist/exceptions/invalid-token.d.ts +4 -0
  426. package/dist/exceptions/invalid-token.js +6 -0
  427. package/dist/exceptions/method-not-allowed.d.ts +8 -0
  428. package/dist/exceptions/method-not-allowed.js +6 -0
  429. package/dist/exceptions/range-not-satisfiable.d.ts +5 -0
  430. package/dist/exceptions/range-not-satisfiable.js +9 -0
  431. package/dist/exceptions/route-not-found.d.ts +4 -0
  432. package/dist/exceptions/route-not-found.js +6 -0
  433. package/dist/exceptions/service-unavailable.d.ts +9 -0
  434. package/dist/exceptions/service-unavailable.js +6 -0
  435. package/dist/exceptions/token-expired.d.ts +4 -0
  436. package/dist/exceptions/token-expired.js +6 -0
  437. package/dist/exceptions/unexpected-response.d.ts +4 -0
  438. package/dist/exceptions/unexpected-response.js +6 -0
  439. package/dist/exceptions/unprocessable-entity.d.ts +4 -0
  440. package/dist/exceptions/unprocessable-entity.js +6 -0
  441. package/dist/exceptions/unsupported-media-type.d.ts +4 -0
  442. package/dist/exceptions/unsupported-media-type.js +6 -0
  443. package/dist/exceptions/user-suspended.d.ts +4 -0
  444. package/dist/exceptions/user-suspended.js +6 -0
  445. package/dist/extensions.d.ts +51 -0
  446. package/dist/extensions.js +490 -0
  447. package/dist/flows.d.ts +22 -0
  448. package/dist/flows.js +350 -0
  449. package/dist/index.d.ts +3 -0
  450. package/dist/index.js +3 -0
  451. package/dist/logger.d.ts +7 -0
  452. package/dist/logger.js +105 -0
  453. package/dist/logger.test.d.ts +1 -0
  454. package/dist/mailer.d.ts +2 -0
  455. package/dist/mailer.js +67 -0
  456. package/dist/messenger.d.ts +24 -0
  457. package/dist/messenger.js +57 -0
  458. package/dist/middleware/authenticate.d.ts +8 -0
  459. package/dist/middleware/authenticate.js +75 -0
  460. package/dist/middleware/authenticate.test.d.ts +1 -0
  461. package/dist/middleware/cache.d.ts +3 -0
  462. package/dist/middleware/cache.js +56 -0
  463. package/dist/middleware/check-ip.d.ts +2 -0
  464. package/dist/middleware/check-ip.js +18 -0
  465. package/dist/middleware/collection-exists.d.ts +6 -0
  466. package/dist/middleware/collection-exists.js +25 -0
  467. package/dist/middleware/cors.d.ts +3 -0
  468. package/dist/middleware/cors.js +14 -0
  469. package/dist/middleware/error-handler.d.ts +3 -0
  470. package/dist/middleware/error-handler.js +90 -0
  471. package/dist/middleware/extract-token.d.ts +11 -0
  472. package/dist/middleware/extract-token.js +30 -0
  473. package/dist/middleware/extract-token.test.d.ts +1 -0
  474. package/dist/middleware/get-permissions.d.ts +3 -0
  475. package/dist/middleware/get-permissions.js +10 -0
  476. package/dist/middleware/graphql.d.ts +2 -0
  477. package/dist/middleware/graphql.js +63 -0
  478. package/dist/middleware/rate-limiter-global.d.ts +5 -0
  479. package/dist/middleware/rate-limiter-global.js +43 -0
  480. package/dist/middleware/rate-limiter-ip.d.ts +5 -0
  481. package/dist/middleware/rate-limiter-ip.js +29 -0
  482. package/dist/middleware/respond.d.ts +2 -0
  483. package/dist/middleware/respond.js +82 -0
  484. package/dist/middleware/sanitize-query.d.ts +7 -0
  485. package/dist/middleware/sanitize-query.js +19 -0
  486. package/dist/middleware/schema.d.ts +3 -0
  487. package/dist/middleware/schema.js +7 -0
  488. package/dist/middleware/use-collection.d.ts +7 -0
  489. package/dist/middleware/use-collection.js +6 -0
  490. package/dist/middleware/validate-batch.d.ts +3 -0
  491. package/dist/middleware/validate-batch.js +42 -0
  492. package/dist/middleware/validate-batch.test.d.ts +1 -0
  493. package/dist/operations/condition/index.d.ts +6 -0
  494. package/dist/operations/condition/index.js +13 -0
  495. package/dist/operations/condition/index.test.d.ts +1 -0
  496. package/dist/operations/exec/index.d.ts +5 -0
  497. package/dist/operations/exec/index.js +38 -0
  498. package/dist/operations/exec/index.test.d.ts +1 -0
  499. package/dist/operations/item-create/index.d.ts +8 -0
  500. package/dist/operations/item-create/index.js +36 -0
  501. package/dist/operations/item-create/index.test.d.ts +1 -0
  502. package/dist/operations/item-delete/index.d.ts +10 -0
  503. package/dist/operations/item-delete/index.js +44 -0
  504. package/dist/operations/item-delete/index.test.d.ts +1 -0
  505. package/dist/operations/item-read/index.d.ts +10 -0
  506. package/dist/operations/item-read/index.js +44 -0
  507. package/dist/operations/item-read/index.test.d.ts +1 -0
  508. package/dist/operations/item-update/index.d.ts +11 -0
  509. package/dist/operations/item-update/index.js +48 -0
  510. package/dist/operations/item-update/index.test.d.ts +1 -0
  511. package/dist/operations/log/index.d.ts +5 -0
  512. package/dist/operations/log/index.js +8 -0
  513. package/dist/operations/log/index.test.d.ts +1 -0
  514. package/dist/operations/mail/index.d.ts +8 -0
  515. package/dist/operations/mail/index.js +17 -0
  516. package/dist/operations/notification/index.d.ts +8 -0
  517. package/dist/operations/notification/index.js +38 -0
  518. package/dist/operations/notification/index.test.d.ts +1 -0
  519. package/dist/operations/request/index.d.ts +11 -0
  520. package/dist/operations/request/index.js +39 -0
  521. package/dist/operations/request/index.test.d.ts +1 -0
  522. package/dist/operations/sleep/index.d.ts +5 -0
  523. package/dist/operations/sleep/index.js +7 -0
  524. package/dist/operations/sleep/index.test.d.ts +1 -0
  525. package/dist/operations/transform/index.d.ts +5 -0
  526. package/dist/operations/transform/index.js +7 -0
  527. package/dist/operations/transform/index.test.d.ts +1 -0
  528. package/dist/operations/trigger/index.d.ts +8 -0
  529. package/dist/operations/trigger/index.js +37 -0
  530. package/dist/operations/trigger/index.test.d.ts +1 -0
  531. package/dist/rate-limiter.d.ts +4 -0
  532. package/dist/rate-limiter.js +33 -0
  533. package/dist/request/index.d.ts +5 -0
  534. package/dist/request/index.js +14 -0
  535. package/dist/request/index.test.d.ts +1 -0
  536. package/dist/request/request-interceptor.d.ts +2 -0
  537. package/dist/request/request-interceptor.js +26 -0
  538. package/dist/request/request-interceptor.test.d.ts +1 -0
  539. package/dist/request/response-interceptor.d.ts +2 -0
  540. package/dist/request/response-interceptor.js +5 -0
  541. package/dist/request/response-interceptor.test.d.ts +1 -0
  542. package/dist/request/validate-ip.d.ts +1 -0
  543. package/dist/request/validate-ip.js +20 -0
  544. package/dist/request/validate-ip.test.d.ts +1 -0
  545. package/dist/server.d.ts +5 -0
  546. package/dist/server.js +135 -0
  547. package/dist/services/activity.d.ts +10 -0
  548. package/dist/services/activity.js +94 -0
  549. package/dist/services/assets.d.ts +18 -0
  550. package/dist/services/assets.js +151 -0
  551. package/dist/services/authentication.d.ts +21 -0
  552. package/dist/services/authentication.js +338 -0
  553. package/dist/services/authorization.d.ts +17 -0
  554. package/dist/services/authorization.js +444 -0
  555. package/dist/services/collections.d.ts +63 -0
  556. package/dist/services/collections.js +568 -0
  557. package/dist/services/dashboards.d.ts +5 -0
  558. package/dist/services/dashboards.js +6 -0
  559. package/dist/services/fields.d.ts +31 -0
  560. package/dist/services/fields.js +596 -0
  561. package/dist/services/files.d.ts +34 -0
  562. package/dist/services/files.js +273 -0
  563. package/dist/services/files.test.d.ts +1 -0
  564. package/dist/services/flows.d.ts +11 -0
  565. package/dist/services/flows.js +39 -0
  566. package/dist/services/folders.d.ts +5 -0
  567. package/dist/services/folders.js +6 -0
  568. package/dist/services/graphql/index.d.ts +86 -0
  569. package/dist/services/graphql/index.js +2512 -0
  570. package/dist/services/graphql/types/bigint.d.ts +2 -0
  571. package/dist/services/graphql/types/bigint.js +36 -0
  572. package/dist/services/graphql/types/date.d.ts +2 -0
  573. package/dist/services/graphql/types/date.js +6 -0
  574. package/dist/services/graphql/types/geojson.d.ts +2 -0
  575. package/dist/services/graphql/types/geojson.js +7 -0
  576. package/dist/services/graphql/types/hash.d.ts +2 -0
  577. package/dist/services/graphql/types/hash.js +6 -0
  578. package/dist/services/graphql/types/string-or-float.d.ts +5 -0
  579. package/dist/services/graphql/types/string-or-float.js +31 -0
  580. package/dist/services/graphql/types/void.d.ts +2 -0
  581. package/dist/services/graphql/types/void.js +14 -0
  582. package/dist/services/graphql/utils/add-path-to-validation-error.d.ts +2 -0
  583. package/dist/services/graphql/utils/add-path-to-validation-error.js +15 -0
  584. package/dist/services/graphql/utils/process-error.d.ts +4 -0
  585. package/dist/services/graphql/utils/process-error.js +41 -0
  586. package/dist/services/graphql/utils/process-error.test.d.ts +1 -0
  587. package/dist/services/import-export.d.ts +37 -0
  588. package/dist/services/import-export.js +293 -0
  589. package/dist/services/index.d.ts +33 -0
  590. package/dist/services/index.js +33 -0
  591. package/dist/services/items.d.ts +88 -0
  592. package/dist/services/items.js +753 -0
  593. package/dist/services/items.test.d.ts +1 -0
  594. package/dist/services/mail/index.d.ts +20 -0
  595. package/dist/services/mail/index.js +91 -0
  596. package/dist/services/mail/templates/base.liquid +162 -0
  597. package/dist/services/mail/templates/password-reset.liquid +24 -0
  598. package/dist/services/mail/templates/user-invitation.liquid +19 -0
  599. package/dist/services/meta.d.ts +12 -0
  600. package/dist/services/meta.js +71 -0
  601. package/dist/services/notifications.d.ts +13 -0
  602. package/dist/services/notifications.js +52 -0
  603. package/dist/services/operations.d.ts +11 -0
  604. package/dist/services/operations.js +37 -0
  605. package/dist/services/panels.d.ts +5 -0
  606. package/dist/services/panels.js +6 -0
  607. package/dist/services/payload.d.ts +73 -0
  608. package/dist/services/payload.js +648 -0
  609. package/dist/services/payload.test.d.ts +1 -0
  610. package/dist/services/permissions.d.ts +17 -0
  611. package/dist/services/permissions.js +80 -0
  612. package/dist/services/presets.d.ts +5 -0
  613. package/dist/services/presets.js +6 -0
  614. package/dist/services/relations.d.ts +60 -0
  615. package/dist/services/relations.js +447 -0
  616. package/dist/services/revisions.d.ts +6 -0
  617. package/dist/services/revisions.js +20 -0
  618. package/dist/services/roles.d.ts +14 -0
  619. package/dist/services/roles.js +144 -0
  620. package/dist/services/roles.test.d.ts +1 -0
  621. package/dist/services/schema.d.ts +15 -0
  622. package/dist/services/schema.js +49 -0
  623. package/dist/services/schema.test.d.ts +1 -0
  624. package/dist/services/server.d.ts +13 -0
  625. package/dist/services/server.js +339 -0
  626. package/dist/services/settings.d.ts +5 -0
  627. package/dist/services/settings.js +6 -0
  628. package/dist/services/shares.d.ts +17 -0
  629. package/dist/services/shares.js +129 -0
  630. package/dist/services/specifications.d.ts +53 -0
  631. package/dist/services/specifications.js +492 -0
  632. package/dist/services/specifications.test.d.ts +1 -0
  633. package/dist/services/tfa.d.ts +12 -0
  634. package/dist/services/tfa.js +50 -0
  635. package/dist/services/users.d.ts +63 -0
  636. package/dist/services/users.js +399 -0
  637. package/dist/services/users.test.d.ts +1 -0
  638. package/dist/services/utils.d.ts +13 -0
  639. package/dist/services/utils.js +108 -0
  640. package/dist/services/webhooks.d.ts +11 -0
  641. package/dist/services/webhooks.js +29 -0
  642. package/dist/services/webhooks.test.d.ts +1 -0
  643. package/dist/start.d.ts +1 -0
  644. package/dist/start.js +2 -0
  645. package/dist/storage/get-storage-driver.d.ts +3 -0
  646. package/dist/storage/get-storage-driver.js +16 -0
  647. package/dist/storage/get-storage-driver.test.d.ts +1 -0
  648. package/dist/storage/index.d.ts +5 -0
  649. package/dist/storage/index.js +16 -0
  650. package/dist/storage/index.test.d.ts +1 -0
  651. package/dist/storage/register-drivers.d.ts +2 -0
  652. package/dist/storage/register-drivers.js +18 -0
  653. package/dist/storage/register-drivers.test.d.ts +1 -0
  654. package/dist/storage/register-locations.d.ts +2 -0
  655. package/dist/storage/register-locations.js +13 -0
  656. package/dist/storage/register-locations.test.d.ts +1 -0
  657. package/dist/types/assets.d.ts +15 -0
  658. package/dist/types/assets.js +51 -0
  659. package/dist/types/ast.d.ts +56 -0
  660. package/dist/types/ast.js +1 -0
  661. package/dist/types/auth.d.ts +54 -0
  662. package/dist/types/auth.js +1 -0
  663. package/dist/types/collection.d.ts +19 -0
  664. package/dist/types/collection.js +1 -0
  665. package/dist/types/database.d.ts +3 -0
  666. package/dist/types/database.js +1 -0
  667. package/dist/types/events.d.ts +18 -0
  668. package/dist/types/events.js +1 -0
  669. package/dist/types/files.d.ts +29 -0
  670. package/dist/types/files.js +1 -0
  671. package/dist/types/graphql.d.ts +14 -0
  672. package/dist/types/graphql.js +1 -0
  673. package/dist/types/index.d.ts +15 -0
  674. package/dist/types/index.js +15 -0
  675. package/dist/types/items.d.ts +55 -0
  676. package/dist/types/items.js +5 -0
  677. package/dist/types/meta.d.ts +4 -0
  678. package/dist/types/meta.js +5 -0
  679. package/dist/types/migration.d.ts +5 -0
  680. package/dist/types/migration.js +1 -0
  681. package/dist/types/revision.d.ts +7 -0
  682. package/dist/types/revision.js +1 -0
  683. package/dist/types/services.d.ts +21 -0
  684. package/dist/types/services.js +1 -0
  685. package/dist/types/snapshot.d.ts +55 -0
  686. package/dist/types/snapshot.js +13 -0
  687. package/dist/types/webhooks.d.ts +15 -0
  688. package/dist/types/webhooks.js +1 -0
  689. package/dist/utils/apply-diff.d.ts +9 -0
  690. package/dist/utils/apply-diff.js +257 -0
  691. package/dist/utils/apply-diff.test.d.ts +1 -0
  692. package/dist/utils/apply-function-to-column-name.d.ts +12 -0
  693. package/dist/utils/apply-function-to-column-name.js +22 -0
  694. package/dist/utils/apply-function-to-column-name.test.d.ts +1 -0
  695. package/dist/utils/apply-query.d.ts +34 -0
  696. package/dist/utils/apply-query.js +555 -0
  697. package/dist/utils/apply-snapshot.d.ts +9 -0
  698. package/dist/utils/apply-snapshot.js +15 -0
  699. package/dist/utils/apply-snapshot.test.d.ts +1 -0
  700. package/dist/utils/async-handler.d.ts +3 -0
  701. package/dist/utils/async-handler.js +2 -0
  702. package/dist/utils/async-handler.test.d.ts +1 -0
  703. package/dist/utils/calculate-field-depth.d.ts +33 -0
  704. package/dist/utils/calculate-field-depth.js +71 -0
  705. package/dist/utils/calculate-field-depth.test.d.ts +1 -0
  706. package/dist/utils/compress.d.ts +3 -0
  707. package/dist/utils/compress.js +12 -0
  708. package/dist/utils/construct-flow-tree.d.ts +2 -0
  709. package/dist/utils/construct-flow-tree.js +27 -0
  710. package/dist/utils/filter-items.d.ts +2 -0
  711. package/dist/utils/filter-items.js +33 -0
  712. package/dist/utils/filter-items.test.d.ts +1 -0
  713. package/dist/utils/generate-hash.d.ts +1 -0
  714. package/dist/utils/generate-hash.js +9 -0
  715. package/dist/utils/get-accountability-for-role.d.ts +7 -0
  716. package/dist/utils/get-accountability-for-role.js +41 -0
  717. package/dist/utils/get-ast-from-query.d.ts +13 -0
  718. package/dist/utils/get-ast-from-query.js +297 -0
  719. package/dist/utils/get-auth-providers.d.ts +8 -0
  720. package/dist/utils/get-auth-providers.js +12 -0
  721. package/dist/utils/get-auth-providers.test.d.ts +1 -0
  722. package/dist/utils/get-cache-headers.d.ts +10 -0
  723. package/dist/utils/get-cache-headers.js +36 -0
  724. package/dist/utils/get-cache-headers.test.d.ts +1 -0
  725. package/dist/utils/get-cache-key.d.ts +2 -0
  726. package/dist/utils/get-cache-key.js +14 -0
  727. package/dist/utils/get-cache-key.test.d.ts +1 -0
  728. package/dist/utils/get-collection-from-alias.d.ts +6 -0
  729. package/dist/utils/get-collection-from-alias.js +12 -0
  730. package/dist/utils/get-collection-from-alias.test.d.ts +1 -0
  731. package/dist/utils/get-column-path.d.ts +26 -0
  732. package/dist/utils/get-column-path.js +61 -0
  733. package/dist/utils/get-column-path.test.d.ts +1 -0
  734. package/dist/utils/get-column.d.ts +20 -0
  735. package/dist/utils/get-column.js +48 -0
  736. package/dist/utils/get-config-from-env.d.ts +1 -0
  737. package/dist/utils/get-config-from-env.js +41 -0
  738. package/dist/utils/get-config-from-env.test.d.ts +1 -0
  739. package/dist/utils/get-date-formatted.d.ts +1 -0
  740. package/dist/utils/get-date-formatted.js +10 -0
  741. package/dist/utils/get-date-formatted.test.d.ts +1 -0
  742. package/dist/utils/get-default-index-name.d.ts +10 -0
  743. package/dist/utils/get-default-index-name.js +21 -0
  744. package/dist/utils/get-default-value.d.ts +3 -0
  745. package/dist/utils/get-default-value.js +56 -0
  746. package/dist/utils/get-graphql-query-and-variables.d.ts +2 -0
  747. package/dist/utils/get-graphql-query-and-variables.js +5 -0
  748. package/dist/utils/get-graphql-query-and-variables.test.d.ts +1 -0
  749. package/dist/utils/get-graphql-type.d.ts +3 -0
  750. package/dist/utils/get-graphql-type.js +36 -0
  751. package/dist/utils/get-ip-from-req.d.ts +2 -0
  752. package/dist/utils/get-ip-from-req.js +17 -0
  753. package/dist/utils/get-local-type.d.ts +9 -0
  754. package/dist/utils/get-local-type.js +128 -0
  755. package/dist/utils/get-milliseconds.d.ts +4 -0
  756. package/dist/utils/get-milliseconds.js +7 -0
  757. package/dist/utils/get-milliseconds.test.d.ts +1 -0
  758. package/dist/utils/get-module-default.d.ts +3 -0
  759. package/dist/utils/get-module-default.js +6 -0
  760. package/dist/utils/get-os-info.d.ts +9 -0
  761. package/dist/utils/get-os-info.js +40 -0
  762. package/dist/utils/get-permissions.d.ts +2 -0
  763. package/dist/utils/get-permissions.js +151 -0
  764. package/dist/utils/get-relation-info.d.ts +7 -0
  765. package/dist/utils/get-relation-info.js +45 -0
  766. package/dist/utils/get-relation-info.test.d.ts +1 -0
  767. package/dist/utils/get-relation-type.d.ts +6 -0
  768. package/dist/utils/get-relation-type.js +18 -0
  769. package/dist/utils/get-relation-type.test.d.ts +1 -0
  770. package/dist/utils/get-schema.d.ts +10 -0
  771. package/dist/utils/get-schema.js +131 -0
  772. package/dist/utils/get-snapshot-diff.d.ts +2 -0
  773. package/dist/utils/get-snapshot-diff.js +78 -0
  774. package/dist/utils/get-snapshot.d.ts +7 -0
  775. package/dist/utils/get-snapshot.js +55 -0
  776. package/dist/utils/get-string-byte-size.d.ts +4 -0
  777. package/dist/utils/get-string-byte-size.js +6 -0
  778. package/dist/utils/get-string-byte-size.test.d.ts +1 -0
  779. package/dist/utils/get-versioned-hash.d.ts +1 -0
  780. package/dist/utils/get-versioned-hash.js +5 -0
  781. package/dist/utils/get-versioned-hash.test.d.ts +1 -0
  782. package/dist/utils/is-directus-jwt.d.ts +5 -0
  783. package/dist/utils/is-directus-jwt.js +16 -0
  784. package/dist/utils/is-directus-jwt.test.d.ts +1 -0
  785. package/dist/utils/is-url-allowed.d.ts +4 -0
  786. package/dist/utils/is-url-allowed.js +30 -0
  787. package/dist/utils/job-queue.d.ts +9 -0
  788. package/dist/utils/job-queue.js +22 -0
  789. package/dist/utils/jwt.d.ts +3 -0
  790. package/dist/utils/jwt.js +29 -0
  791. package/dist/utils/jwt.test.d.ts +1 -0
  792. package/dist/utils/map-values-deep.d.ts +1 -0
  793. package/dist/utils/map-values-deep.js +25 -0
  794. package/dist/utils/map-values-deep.test.d.ts +1 -0
  795. package/dist/utils/md.d.ts +4 -0
  796. package/dist/utils/md.js +8 -0
  797. package/dist/utils/md.test.d.ts +1 -0
  798. package/dist/utils/merge-permissions-for-share.d.ts +4 -0
  799. package/dist/utils/merge-permissions-for-share.js +109 -0
  800. package/dist/utils/merge-permissions.d.ts +3 -0
  801. package/dist/utils/merge-permissions.js +95 -0
  802. package/dist/utils/merge-permissions.test.d.ts +1 -0
  803. package/dist/utils/package.d.ts +2 -0
  804. package/dist/utils/package.js +6 -0
  805. package/dist/utils/parse-image-metadata.d.ts +3 -0
  806. package/dist/utils/parse-image-metadata.js +68 -0
  807. package/dist/utils/reduce-schema.d.ts +9 -0
  808. package/dist/utils/reduce-schema.js +78 -0
  809. package/dist/utils/require-yaml.d.ts +1 -0
  810. package/dist/utils/require-yaml.js +6 -0
  811. package/dist/utils/sanitize-query.d.ts +2 -0
  812. package/dist/utils/sanitize-query.js +172 -0
  813. package/dist/utils/sanitize-query.test.d.ts +1 -0
  814. package/dist/utils/sanitize-schema.d.ts +26 -0
  815. package/dist/utils/sanitize-schema.js +87 -0
  816. package/dist/utils/sanitize-schema.test.d.ts +1 -0
  817. package/dist/utils/should-skip-cache.d.ts +7 -0
  818. package/dist/utils/should-skip-cache.js +26 -0
  819. package/dist/utils/should-skip-cache.test.d.ts +1 -0
  820. package/dist/utils/stall.d.ts +26 -0
  821. package/dist/utils/stall.js +34 -0
  822. package/dist/utils/stall.test.d.ts +1 -0
  823. package/dist/utils/strip-function.d.ts +4 -0
  824. package/dist/utils/strip-function.js +12 -0
  825. package/dist/utils/strip-function.test.d.ts +1 -0
  826. package/dist/utils/telemetry.d.ts +1 -0
  827. package/dist/utils/telemetry.js +23 -0
  828. package/dist/utils/transformations.d.ts +6 -0
  829. package/dist/utils/transformations.js +30 -0
  830. package/dist/utils/url.d.ts +17 -0
  831. package/dist/utils/url.js +59 -0
  832. package/dist/utils/url.test.d.ts +1 -0
  833. package/dist/utils/user-name.d.ts +2 -0
  834. package/dist/utils/user-name.js +15 -0
  835. package/dist/utils/user-name.test.d.ts +1 -0
  836. package/dist/utils/validate-diff.d.ts +7 -0
  837. package/dist/utils/validate-diff.js +110 -0
  838. package/dist/utils/validate-diff.test.d.ts +1 -0
  839. package/dist/utils/validate-env.d.ts +1 -0
  840. package/dist/utils/validate-env.js +11 -0
  841. package/dist/utils/validate-env.test.d.ts +1 -0
  842. package/dist/utils/validate-keys.d.ts +6 -0
  843. package/dist/utils/validate-keys.js +21 -0
  844. package/dist/utils/validate-keys.test.d.ts +1 -0
  845. package/dist/utils/validate-query.d.ts +2 -0
  846. package/dist/utils/validate-query.js +198 -0
  847. package/dist/utils/validate-query.test.d.ts +1 -0
  848. package/dist/utils/validate-snapshot.d.ts +5 -0
  849. package/dist/utils/validate-snapshot.js +64 -0
  850. package/dist/utils/validate-snapshot.test.d.ts +1 -0
  851. package/dist/utils/validate-storage.d.ts +1 -0
  852. package/dist/utils/validate-storage.js +31 -0
  853. package/dist/webhooks.d.ts +4 -0
  854. package/dist/webhooks.js +79 -0
  855. package/package.json +231 -0
@@ -0,0 +1,2512 @@
1
+ import { FUNCTIONS } from '@directus/constants';
2
+ import { Action } from '@directus/constants';
3
+ import { parseFilterFunctionPath } from '@directus/utils';
4
+ import argon2 from 'argon2';
5
+ import { execute, GraphQLBoolean, GraphQLEnumType, GraphQLError, GraphQLFloat, GraphQLID, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLString, GraphQLUnionType, NoSchemaIntrospectionCustomRule, specifiedRules, validate, } from 'graphql';
6
+ import { GraphQLJSON, SchemaComposer, toInputObjectType, } from 'graphql-compose';
7
+ import { flatten, get, mapKeys, merge, omit, pick, set, transform, uniq } from 'lodash-es';
8
+ import { clearSystemCache, getCache } from '../../cache.js';
9
+ import { DEFAULT_AUTH_PROVIDER, GENERATE_SPECIAL } from '../../constants.js';
10
+ import getDatabase from '../../database/index.js';
11
+ import env from '../../env.js';
12
+ import { ForbiddenException, GraphQLValidationException, InvalidPayloadException } from '../../exceptions/index.js';
13
+ import { getExtensionManager } from '../../extensions.js';
14
+ import { generateHash } from '../../utils/generate-hash.js';
15
+ import { getGraphQLType } from '../../utils/get-graphql-type.js';
16
+ import { getMilliseconds } from '../../utils/get-milliseconds.js';
17
+ import { reduceSchema } from '../../utils/reduce-schema.js';
18
+ import { sanitizeQuery } from '../../utils/sanitize-query.js';
19
+ import { validateQuery } from '../../utils/validate-query.js';
20
+ import { ActivityService } from '../activity.js';
21
+ import { AuthenticationService } from '../authentication.js';
22
+ import { CollectionsService } from '../collections.js';
23
+ import { FieldsService } from '../fields.js';
24
+ import { FilesService } from '../files.js';
25
+ import { FlowsService } from '../flows.js';
26
+ import { FoldersService } from '../folders.js';
27
+ import { ItemsService } from '../items.js';
28
+ import { NotificationsService } from '../notifications.js';
29
+ import { OperationsService } from '../operations.js';
30
+ import { PermissionsService } from '../permissions.js';
31
+ import { PresetsService } from '../presets.js';
32
+ import { RelationsService } from '../relations.js';
33
+ import { RevisionsService } from '../revisions.js';
34
+ import { RolesService } from '../roles.js';
35
+ import { ServerService } from '../server.js';
36
+ import { SettingsService } from '../settings.js';
37
+ import { SharesService } from '../shares.js';
38
+ import { SpecificationService } from '../specifications.js';
39
+ import { TFAService } from '../tfa.js';
40
+ import { UsersService } from '../users.js';
41
+ import { UtilsService } from '../utils.js';
42
+ import { WebhooksService } from '../webhooks.js';
43
+ import { GraphQLBigInt } from './types/bigint.js';
44
+ import { GraphQLDate } from './types/date.js';
45
+ import { GraphQLGeoJSON } from './types/geojson.js';
46
+ import { GraphQLHash } from './types/hash.js';
47
+ import { GraphQLStringOrFloat } from './types/string-or-float.js';
48
+ import { GraphQLVoid } from './types/void.js';
49
+ import { addPathToValidationError } from './utils/add-path-to-validation-error.js';
50
+ import processError from './utils/process-error.js';
51
+ const validationRules = Array.from(specifiedRules);
52
+ if (env['GRAPHQL_INTROSPECTION'] === false) {
53
+ validationRules.push(NoSchemaIntrospectionCustomRule);
54
+ }
55
+ /**
56
+ * These should be ignored in the context of GraphQL, and/or are replaced by a custom resolver (for non-standard structures)
57
+ */
58
+ const SYSTEM_DENY_LIST = [
59
+ 'directus_collections',
60
+ 'directus_fields',
61
+ 'directus_relations',
62
+ 'directus_migrations',
63
+ 'directus_sessions',
64
+ ];
65
+ const READ_ONLY = ['directus_activity', 'directus_revisions'];
66
+ export class GraphQLService {
67
+ accountability;
68
+ knex;
69
+ schema;
70
+ scope;
71
+ constructor(options) {
72
+ this.accountability = options?.accountability || null;
73
+ this.knex = options?.knex || getDatabase();
74
+ this.schema = options.schema;
75
+ this.scope = options.scope;
76
+ }
77
+ /**
78
+ * Execute a GraphQL structure
79
+ */
80
+ async execute({ document, variables, operationName, contextValue, }) {
81
+ const schema = this.getSchema();
82
+ const validationErrors = validate(schema, document, validationRules).map((validationError) => addPathToValidationError(validationError));
83
+ if (validationErrors.length > 0) {
84
+ throw new GraphQLValidationException({ graphqlErrors: validationErrors });
85
+ }
86
+ let result;
87
+ try {
88
+ result = await execute({
89
+ schema,
90
+ document,
91
+ contextValue,
92
+ variableValues: variables,
93
+ operationName,
94
+ });
95
+ }
96
+ catch (err) {
97
+ throw new InvalidPayloadException('GraphQL execution error.', { graphqlErrors: [err.message] });
98
+ }
99
+ const formattedResult = {};
100
+ if (result['data'])
101
+ formattedResult.data = result['data'];
102
+ if (result['errors'])
103
+ formattedResult.errors = result['errors'].map((error) => processError(this.accountability, error));
104
+ if (result['extensions'])
105
+ formattedResult.extensions = result['extensions'];
106
+ return formattedResult;
107
+ }
108
+ getSchema(type = 'schema') {
109
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
110
+ const self = this;
111
+ const schemaComposer = new SchemaComposer();
112
+ const schema = {
113
+ read: this.accountability?.admin === true
114
+ ? this.schema
115
+ : reduceSchema(this.schema, this.accountability?.permissions || null, ['read']),
116
+ create: this.accountability?.admin === true
117
+ ? this.schema
118
+ : reduceSchema(this.schema, this.accountability?.permissions || null, ['create']),
119
+ update: this.accountability?.admin === true
120
+ ? this.schema
121
+ : reduceSchema(this.schema, this.accountability?.permissions || null, ['update']),
122
+ delete: this.accountability?.admin === true
123
+ ? this.schema
124
+ : reduceSchema(this.schema, this.accountability?.permissions || null, ['delete']),
125
+ };
126
+ const { ReadCollectionTypes } = getReadableTypes();
127
+ const { CreateCollectionTypes, UpdateCollectionTypes, DeleteCollectionTypes } = getWritableTypes();
128
+ const scopeFilter = (collection) => {
129
+ if (this.scope === 'items' && collection.collection.startsWith('directus_') === true)
130
+ return false;
131
+ if (this.scope === 'system') {
132
+ if (collection.collection.startsWith('directus_') === false)
133
+ return false;
134
+ if (SYSTEM_DENY_LIST.includes(collection.collection))
135
+ return false;
136
+ }
137
+ return true;
138
+ };
139
+ if (this.scope === 'system') {
140
+ this.injectSystemResolvers(schemaComposer, {
141
+ CreateCollectionTypes,
142
+ ReadCollectionTypes,
143
+ UpdateCollectionTypes,
144
+ DeleteCollectionTypes,
145
+ }, schema);
146
+ }
147
+ const readableCollections = Object.values(schema.read.collections)
148
+ .filter((collection) => collection.collection in ReadCollectionTypes)
149
+ .filter(scopeFilter);
150
+ if (readableCollections.length > 0) {
151
+ schemaComposer.Query.addFields(readableCollections.reduce((acc, collection) => {
152
+ const collectionName = this.scope === 'items' ? collection.collection : collection.collection.substring(9);
153
+ acc[collectionName] = ReadCollectionTypes[collection.collection].getResolver(collection.collection);
154
+ if (this.schema.collections[collection.collection].singleton === false) {
155
+ acc[`${collectionName}_by_id`] = ReadCollectionTypes[collection.collection].getResolver(`${collection.collection}_by_id`);
156
+ acc[`${collectionName}_aggregated`] = ReadCollectionTypes[collection.collection].getResolver(`${collection.collection}_aggregated`);
157
+ }
158
+ return acc;
159
+ }, {}));
160
+ }
161
+ else {
162
+ schemaComposer.Query.addFields({
163
+ _empty: {
164
+ type: GraphQLVoid,
165
+ description: "There's no data to query.",
166
+ },
167
+ });
168
+ }
169
+ if (Object.keys(schema.create.collections).length > 0) {
170
+ schemaComposer.Mutation.addFields(Object.values(schema.create.collections)
171
+ .filter((collection) => collection.collection in CreateCollectionTypes && collection.singleton === false)
172
+ .filter(scopeFilter)
173
+ .filter((collection) => READ_ONLY.includes(collection.collection) === false)
174
+ .reduce((acc, collection) => {
175
+ const collectionName = this.scope === 'items' ? collection.collection : collection.collection.substring(9);
176
+ acc[`create_${collectionName}_items`] = CreateCollectionTypes[collection.collection].getResolver(`create_${collection.collection}_items`);
177
+ acc[`create_${collectionName}_item`] = CreateCollectionTypes[collection.collection].getResolver(`create_${collection.collection}_item`);
178
+ return acc;
179
+ }, {}));
180
+ }
181
+ if (Object.keys(schema.update.collections).length > 0) {
182
+ schemaComposer.Mutation.addFields(Object.values(schema.update.collections)
183
+ .filter((collection) => collection.collection in UpdateCollectionTypes)
184
+ .filter(scopeFilter)
185
+ .filter((collection) => READ_ONLY.includes(collection.collection) === false)
186
+ .reduce((acc, collection) => {
187
+ const collectionName = this.scope === 'items' ? collection.collection : collection.collection.substring(9);
188
+ if (collection.singleton) {
189
+ acc[`update_${collectionName}`] = UpdateCollectionTypes[collection.collection].getResolver(`update_${collection.collection}`);
190
+ }
191
+ else {
192
+ acc[`update_${collectionName}_items`] = UpdateCollectionTypes[collection.collection].getResolver(`update_${collection.collection}_items`);
193
+ acc[`update_${collectionName}_batch`] = UpdateCollectionTypes[collection.collection].getResolver(`update_${collection.collection}_batch`);
194
+ acc[`update_${collectionName}_item`] = UpdateCollectionTypes[collection.collection].getResolver(`update_${collection.collection}_item`);
195
+ }
196
+ return acc;
197
+ }, {}));
198
+ }
199
+ if (Object.keys(schema.delete.collections).length > 0) {
200
+ schemaComposer.Mutation.addFields(Object.values(schema.delete.collections)
201
+ .filter((collection) => collection.singleton === false)
202
+ .filter(scopeFilter)
203
+ .filter((collection) => READ_ONLY.includes(collection.collection) === false)
204
+ .reduce((acc, collection) => {
205
+ const collectionName = this.scope === 'items' ? collection.collection : collection.collection.substring(9);
206
+ acc[`delete_${collectionName}_items`] = DeleteCollectionTypes['many'].getResolver(`delete_${collection.collection}_items`);
207
+ acc[`delete_${collectionName}_item`] = DeleteCollectionTypes['one'].getResolver(`delete_${collection.collection}_item`);
208
+ return acc;
209
+ }, {}));
210
+ }
211
+ if (type === 'sdl') {
212
+ return schemaComposer.toSDL();
213
+ }
214
+ return schemaComposer.buildSchema();
215
+ /**
216
+ * Construct an object of types for every collection, using the permitted fields per action type
217
+ * as it's fields.
218
+ */
219
+ function getTypes(action) {
220
+ const CollectionTypes = {};
221
+ const CountFunctions = schemaComposer.createObjectTC({
222
+ name: 'count_functions',
223
+ fields: {
224
+ count: {
225
+ type: GraphQLInt,
226
+ },
227
+ },
228
+ });
229
+ const DateFunctions = schemaComposer.createObjectTC({
230
+ name: 'date_functions',
231
+ fields: {
232
+ year: {
233
+ type: GraphQLInt,
234
+ },
235
+ month: {
236
+ type: GraphQLInt,
237
+ },
238
+ week: {
239
+ type: GraphQLInt,
240
+ },
241
+ day: {
242
+ type: GraphQLInt,
243
+ },
244
+ weekday: {
245
+ type: GraphQLInt,
246
+ },
247
+ },
248
+ });
249
+ const TimeFunctions = schemaComposer.createObjectTC({
250
+ name: 'time_functions',
251
+ fields: {
252
+ hour: {
253
+ type: GraphQLInt,
254
+ },
255
+ minute: {
256
+ type: GraphQLInt,
257
+ },
258
+ second: {
259
+ type: GraphQLInt,
260
+ },
261
+ },
262
+ });
263
+ const DateTimeFunctions = schemaComposer.createObjectTC({
264
+ name: 'datetime_functions',
265
+ fields: {
266
+ ...DateFunctions.getFields(),
267
+ ...TimeFunctions.getFields(),
268
+ },
269
+ });
270
+ for (const collection of Object.values(schema[action].collections)) {
271
+ if (Object.keys(collection.fields).length === 0)
272
+ continue;
273
+ if (SYSTEM_DENY_LIST.includes(collection.collection))
274
+ continue;
275
+ CollectionTypes[collection.collection] = schemaComposer.createObjectTC({
276
+ name: action === 'read' ? collection.collection : `${action}_${collection.collection}`,
277
+ fields: Object.values(collection.fields).reduce((acc, field) => {
278
+ let type = getGraphQLType(field.type, field.special);
279
+ // GraphQL doesn't differentiate between not-null and has-to-be-submitted. We
280
+ // can't non-null in update, as that would require every not-nullable field to be
281
+ // submitted on updates
282
+ if (field.nullable === false &&
283
+ !field.defaultValue &&
284
+ !GENERATE_SPECIAL.some((flag) => field.special.includes(flag)) &&
285
+ action !== 'update') {
286
+ type = new GraphQLNonNull(type);
287
+ }
288
+ if (collection.primary === field.field) {
289
+ if (!field.defaultValue && !field.special.includes('uuid') && action === 'create')
290
+ type = new GraphQLNonNull(GraphQLID);
291
+ else if (['create', 'update'].includes(action))
292
+ type = GraphQLID;
293
+ else
294
+ type = new GraphQLNonNull(GraphQLID);
295
+ }
296
+ acc[field.field] = {
297
+ type,
298
+ description: field.note,
299
+ resolve: (obj) => {
300
+ return obj[field.field];
301
+ },
302
+ };
303
+ if (action === 'read') {
304
+ if (field.type === 'date') {
305
+ acc[`${field.field}_func`] = {
306
+ type: DateFunctions,
307
+ resolve: (obj) => {
308
+ const funcFields = Object.keys(DateFunctions.getFields()).map((key) => `${field.field}_${key}`);
309
+ return mapKeys(pick(obj, funcFields), (_value, key) => key.substring(field.field.length + 1));
310
+ },
311
+ };
312
+ }
313
+ if (field.type === 'time') {
314
+ acc[`${field.field}_func`] = {
315
+ type: TimeFunctions,
316
+ resolve: (obj) => {
317
+ const funcFields = Object.keys(TimeFunctions.getFields()).map((key) => `${field.field}_${key}`);
318
+ return mapKeys(pick(obj, funcFields), (_value, key) => key.substring(field.field.length + 1));
319
+ },
320
+ };
321
+ }
322
+ if (field.type === 'dateTime' || field.type === 'timestamp') {
323
+ acc[`${field.field}_func`] = {
324
+ type: DateTimeFunctions,
325
+ resolve: (obj) => {
326
+ const funcFields = Object.keys(DateTimeFunctions.getFields()).map((key) => `${field.field}_${key}`);
327
+ return mapKeys(pick(obj, funcFields), (_value, key) => key.substring(field.field.length + 1));
328
+ },
329
+ };
330
+ }
331
+ if (field.type === 'json' || field.type === 'alias') {
332
+ acc[`${field.field}_func`] = {
333
+ type: CountFunctions,
334
+ resolve: (obj) => {
335
+ const funcFields = Object.keys(CountFunctions.getFields()).map((key) => `${field.field}_${key}`);
336
+ return mapKeys(pick(obj, funcFields), (_value, key) => key.substring(field.field.length + 1));
337
+ },
338
+ };
339
+ }
340
+ }
341
+ return acc;
342
+ }, {}),
343
+ });
344
+ }
345
+ for (const relation of schema[action].relations) {
346
+ if (relation.related_collection) {
347
+ if (SYSTEM_DENY_LIST.includes(relation.related_collection))
348
+ continue;
349
+ CollectionTypes[relation.collection]?.addFields({
350
+ [relation.field]: {
351
+ type: CollectionTypes[relation.related_collection],
352
+ resolve: (obj, _, __, info) => {
353
+ return obj[info?.path?.key ?? relation.field];
354
+ },
355
+ },
356
+ });
357
+ if (relation.meta?.one_field) {
358
+ CollectionTypes[relation.related_collection]?.addFields({
359
+ [relation.meta.one_field]: {
360
+ type: [CollectionTypes[relation.collection]],
361
+ resolve: (obj, _, __, info) => {
362
+ return obj[info?.path?.key ?? relation.meta.one_field];
363
+ },
364
+ },
365
+ });
366
+ }
367
+ }
368
+ else if (relation.meta?.one_allowed_collections && action === 'read') {
369
+ // NOTE: There are no union input types in GraphQL, so this only applies to Read actions
370
+ CollectionTypes[relation.collection]?.addFields({
371
+ [relation.field]: {
372
+ type: new GraphQLUnionType({
373
+ name: `${relation.collection}_${relation.field}_union`,
374
+ types: relation.meta.one_allowed_collections.map((collection) => CollectionTypes[collection].getType()),
375
+ resolveType(_value, context, info) {
376
+ let path = [];
377
+ let currentPath = info.path;
378
+ while (currentPath.prev) {
379
+ path.push(currentPath.key);
380
+ currentPath = currentPath.prev;
381
+ }
382
+ path = path.reverse().slice(0, -1);
383
+ let parent = context['data'];
384
+ for (const pathPart of path) {
385
+ parent = parent[pathPart];
386
+ }
387
+ const collection = parent[relation.meta.one_collection_field];
388
+ return CollectionTypes[collection].getType().name;
389
+ },
390
+ }),
391
+ resolve: (obj, _, __, info) => {
392
+ return obj[info?.path?.key ?? relation.field];
393
+ },
394
+ },
395
+ });
396
+ }
397
+ }
398
+ return { CollectionTypes };
399
+ }
400
+ /**
401
+ * Create readable types and attach resolvers for each. Also prepares full filter argument structures
402
+ */
403
+ function getReadableTypes() {
404
+ const { CollectionTypes: ReadCollectionTypes } = getTypes('read');
405
+ const ReadableCollectionFilterTypes = {};
406
+ const AggregatedFunctions = {};
407
+ const AggregatedFields = {};
408
+ const AggregateMethods = {};
409
+ const StringFilterOperators = schemaComposer.createInputTC({
410
+ name: 'string_filter_operators',
411
+ fields: {
412
+ _eq: {
413
+ type: GraphQLString,
414
+ },
415
+ _neq: {
416
+ type: GraphQLString,
417
+ },
418
+ _contains: {
419
+ type: GraphQLString,
420
+ },
421
+ _icontains: {
422
+ type: GraphQLString,
423
+ },
424
+ _ncontains: {
425
+ type: GraphQLString,
426
+ },
427
+ _starts_with: {
428
+ type: GraphQLString,
429
+ },
430
+ _nstarts_with: {
431
+ type: GraphQLString,
432
+ },
433
+ _ends_with: {
434
+ type: GraphQLString,
435
+ },
436
+ _nends_with: {
437
+ type: GraphQLString,
438
+ },
439
+ _in: {
440
+ type: new GraphQLList(GraphQLString),
441
+ },
442
+ _nin: {
443
+ type: new GraphQLList(GraphQLString),
444
+ },
445
+ _null: {
446
+ type: GraphQLBoolean,
447
+ },
448
+ _nnull: {
449
+ type: GraphQLBoolean,
450
+ },
451
+ _empty: {
452
+ type: GraphQLBoolean,
453
+ },
454
+ _nempty: {
455
+ type: GraphQLBoolean,
456
+ },
457
+ },
458
+ });
459
+ const BooleanFilterOperators = schemaComposer.createInputTC({
460
+ name: 'boolean_filter_operators',
461
+ fields: {
462
+ _eq: {
463
+ type: GraphQLBoolean,
464
+ },
465
+ _neq: {
466
+ type: GraphQLBoolean,
467
+ },
468
+ _null: {
469
+ type: GraphQLBoolean,
470
+ },
471
+ _nnull: {
472
+ type: GraphQLBoolean,
473
+ },
474
+ },
475
+ });
476
+ const DateFilterOperators = schemaComposer.createInputTC({
477
+ name: 'date_filter_operators',
478
+ fields: {
479
+ _eq: {
480
+ type: GraphQLString,
481
+ },
482
+ _neq: {
483
+ type: GraphQLString,
484
+ },
485
+ _gt: {
486
+ type: GraphQLString,
487
+ },
488
+ _gte: {
489
+ type: GraphQLString,
490
+ },
491
+ _lt: {
492
+ type: GraphQLString,
493
+ },
494
+ _lte: {
495
+ type: GraphQLString,
496
+ },
497
+ _null: {
498
+ type: GraphQLBoolean,
499
+ },
500
+ _nnull: {
501
+ type: GraphQLBoolean,
502
+ },
503
+ _in: {
504
+ type: new GraphQLList(GraphQLString),
505
+ },
506
+ _nin: {
507
+ type: new GraphQLList(GraphQLString),
508
+ },
509
+ _between: {
510
+ type: new GraphQLList(GraphQLStringOrFloat),
511
+ },
512
+ _nbetween: {
513
+ type: new GraphQLList(GraphQLStringOrFloat),
514
+ },
515
+ },
516
+ });
517
+ // Uses StringOrFloat rather than Float to support api dynamic variables (like `$NOW`)
518
+ const NumberFilterOperators = schemaComposer.createInputTC({
519
+ name: 'number_filter_operators',
520
+ fields: {
521
+ _eq: {
522
+ type: GraphQLStringOrFloat,
523
+ },
524
+ _neq: {
525
+ type: GraphQLStringOrFloat,
526
+ },
527
+ _in: {
528
+ type: new GraphQLList(GraphQLStringOrFloat),
529
+ },
530
+ _nin: {
531
+ type: new GraphQLList(GraphQLStringOrFloat),
532
+ },
533
+ _gt: {
534
+ type: GraphQLStringOrFloat,
535
+ },
536
+ _gte: {
537
+ type: GraphQLStringOrFloat,
538
+ },
539
+ _lt: {
540
+ type: GraphQLStringOrFloat,
541
+ },
542
+ _lte: {
543
+ type: GraphQLStringOrFloat,
544
+ },
545
+ _null: {
546
+ type: GraphQLBoolean,
547
+ },
548
+ _nnull: {
549
+ type: GraphQLBoolean,
550
+ },
551
+ _between: {
552
+ type: new GraphQLList(GraphQLStringOrFloat),
553
+ },
554
+ _nbetween: {
555
+ type: new GraphQLList(GraphQLStringOrFloat),
556
+ },
557
+ },
558
+ });
559
+ const GeometryFilterOperators = schemaComposer.createInputTC({
560
+ name: 'geometry_filter_operators',
561
+ fields: {
562
+ _eq: {
563
+ type: GraphQLGeoJSON,
564
+ },
565
+ _neq: {
566
+ type: GraphQLGeoJSON,
567
+ },
568
+ _intersects: {
569
+ type: GraphQLGeoJSON,
570
+ },
571
+ _nintersects: {
572
+ type: GraphQLGeoJSON,
573
+ },
574
+ _intersects_bbox: {
575
+ type: GraphQLGeoJSON,
576
+ },
577
+ _nintersects_bbox: {
578
+ type: GraphQLGeoJSON,
579
+ },
580
+ _null: {
581
+ type: GraphQLBoolean,
582
+ },
583
+ _nnull: {
584
+ type: GraphQLBoolean,
585
+ },
586
+ },
587
+ });
588
+ const HashFilterOperators = schemaComposer.createInputTC({
589
+ name: 'hash_filter_operators',
590
+ fields: {
591
+ _null: {
592
+ type: GraphQLBoolean,
593
+ },
594
+ _nnull: {
595
+ type: GraphQLBoolean,
596
+ },
597
+ _empty: {
598
+ type: GraphQLBoolean,
599
+ },
600
+ _nempty: {
601
+ type: GraphQLBoolean,
602
+ },
603
+ },
604
+ });
605
+ const CountFunctionFilterOperators = schemaComposer.createInputTC({
606
+ name: 'count_function_filter_operators',
607
+ fields: {
608
+ count: {
609
+ type: NumberFilterOperators,
610
+ },
611
+ },
612
+ });
613
+ const DateFunctionFilterOperators = schemaComposer.createInputTC({
614
+ name: 'date_function_filter_operators',
615
+ fields: {
616
+ year: {
617
+ type: NumberFilterOperators,
618
+ },
619
+ month: {
620
+ type: NumberFilterOperators,
621
+ },
622
+ week: {
623
+ type: NumberFilterOperators,
624
+ },
625
+ day: {
626
+ type: NumberFilterOperators,
627
+ },
628
+ weekday: {
629
+ type: NumberFilterOperators,
630
+ },
631
+ },
632
+ });
633
+ const TimeFunctionFilterOperators = schemaComposer.createInputTC({
634
+ name: 'time_function_filter_operators',
635
+ fields: {
636
+ hour: {
637
+ type: NumberFilterOperators,
638
+ },
639
+ minute: {
640
+ type: NumberFilterOperators,
641
+ },
642
+ second: {
643
+ type: NumberFilterOperators,
644
+ },
645
+ },
646
+ });
647
+ const DateTimeFunctionFilterOperators = schemaComposer.createInputTC({
648
+ name: 'datetime_function_filter_operators',
649
+ fields: {
650
+ ...DateFunctionFilterOperators.getFields(),
651
+ ...TimeFunctionFilterOperators.getFields(),
652
+ },
653
+ });
654
+ for (const collection of Object.values(schema.read.collections)) {
655
+ if (Object.keys(collection.fields).length === 0)
656
+ continue;
657
+ if (SYSTEM_DENY_LIST.includes(collection.collection))
658
+ continue;
659
+ ReadableCollectionFilterTypes[collection.collection] = schemaComposer.createInputTC({
660
+ name: `${collection.collection}_filter`,
661
+ fields: Object.values(collection.fields).reduce((acc, field) => {
662
+ const graphqlType = getGraphQLType(field.type, field.special);
663
+ let filterOperatorType;
664
+ switch (graphqlType) {
665
+ case GraphQLBoolean:
666
+ filterOperatorType = BooleanFilterOperators;
667
+ break;
668
+ case GraphQLBigInt:
669
+ case GraphQLInt:
670
+ case GraphQLFloat:
671
+ filterOperatorType = NumberFilterOperators;
672
+ break;
673
+ case GraphQLDate:
674
+ filterOperatorType = DateFilterOperators;
675
+ break;
676
+ case GraphQLGeoJSON:
677
+ filterOperatorType = GeometryFilterOperators;
678
+ break;
679
+ case GraphQLHash:
680
+ filterOperatorType = HashFilterOperators;
681
+ break;
682
+ default:
683
+ filterOperatorType = StringFilterOperators;
684
+ }
685
+ acc[field.field] = filterOperatorType;
686
+ if (field.type === 'date') {
687
+ acc[`${field.field}_func`] = {
688
+ type: DateFunctionFilterOperators,
689
+ };
690
+ }
691
+ if (field.type === 'time') {
692
+ acc[`${field.field}_func`] = {
693
+ type: TimeFunctionFilterOperators,
694
+ };
695
+ }
696
+ if (field.type === 'dateTime' || field.type === 'timestamp') {
697
+ acc[`${field.field}_func`] = {
698
+ type: DateTimeFunctionFilterOperators,
699
+ };
700
+ }
701
+ if (field.type === 'json' || field.type === 'alias') {
702
+ acc[`${field.field}_func`] = {
703
+ type: CountFunctionFilterOperators,
704
+ };
705
+ }
706
+ return acc;
707
+ }, {}),
708
+ });
709
+ ReadableCollectionFilterTypes[collection.collection].addFields({
710
+ _and: [ReadableCollectionFilterTypes[collection.collection]],
711
+ _or: [ReadableCollectionFilterTypes[collection.collection]],
712
+ });
713
+ AggregatedFields[collection.collection] = schemaComposer.createObjectTC({
714
+ name: `${collection.collection}_aggregated_fields`,
715
+ fields: Object.values(collection.fields).reduce((acc, field) => {
716
+ const graphqlType = getGraphQLType(field.type, field.special);
717
+ switch (graphqlType) {
718
+ case GraphQLBigInt:
719
+ case GraphQLInt:
720
+ case GraphQLFloat:
721
+ acc[field.field] = {
722
+ type: GraphQLFloat,
723
+ description: field.note,
724
+ };
725
+ break;
726
+ default:
727
+ break;
728
+ }
729
+ return acc;
730
+ }, {}),
731
+ });
732
+ const countType = schemaComposer.createObjectTC({
733
+ name: `${collection.collection}_aggregated_count`,
734
+ fields: Object.values(collection.fields).reduce((acc, field) => {
735
+ acc[field.field] = {
736
+ type: GraphQLInt,
737
+ description: field.note,
738
+ };
739
+ return acc;
740
+ }, {}),
741
+ });
742
+ AggregateMethods[collection.collection] = {
743
+ group: {
744
+ name: 'group',
745
+ type: GraphQLJSON,
746
+ },
747
+ countAll: {
748
+ name: 'countAll',
749
+ type: GraphQLInt,
750
+ },
751
+ count: {
752
+ name: 'count',
753
+ type: countType,
754
+ },
755
+ countDistinct: {
756
+ name: 'countDistinct',
757
+ type: countType,
758
+ },
759
+ };
760
+ const hasNumericAggregates = Object.values(collection.fields).some((field) => {
761
+ const graphqlType = getGraphQLType(field.type, field.special);
762
+ if (graphqlType === GraphQLInt || graphqlType === GraphQLFloat) {
763
+ return true;
764
+ }
765
+ return false;
766
+ });
767
+ if (hasNumericAggregates) {
768
+ Object.assign(AggregateMethods[collection.collection], {
769
+ avg: {
770
+ name: 'avg',
771
+ type: AggregatedFields[collection.collection],
772
+ },
773
+ sum: {
774
+ name: 'sum',
775
+ type: AggregatedFields[collection.collection],
776
+ },
777
+ avgDistinct: {
778
+ name: 'avgDistinct',
779
+ type: AggregatedFields[collection.collection],
780
+ },
781
+ sumDistinct: {
782
+ name: 'sumDistinct',
783
+ type: AggregatedFields[collection.collection],
784
+ },
785
+ min: {
786
+ name: 'min',
787
+ type: AggregatedFields[collection.collection],
788
+ },
789
+ max: {
790
+ name: 'max',
791
+ type: AggregatedFields[collection.collection],
792
+ },
793
+ });
794
+ }
795
+ AggregatedFunctions[collection.collection] = schemaComposer.createObjectTC({
796
+ name: `${collection.collection}_aggregated`,
797
+ fields: AggregateMethods[collection.collection],
798
+ });
799
+ const resolver = {
800
+ name: collection.collection,
801
+ type: collection.singleton
802
+ ? ReadCollectionTypes[collection.collection]
803
+ : new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(ReadCollectionTypes[collection.collection].getType()))),
804
+ resolve: async ({ info, context }) => {
805
+ const result = await self.resolveQuery(info);
806
+ context['data'] = result;
807
+ return result;
808
+ },
809
+ };
810
+ if (collection.singleton === false) {
811
+ resolver.args = {
812
+ filter: ReadableCollectionFilterTypes[collection.collection],
813
+ sort: {
814
+ type: new GraphQLList(GraphQLString),
815
+ },
816
+ limit: {
817
+ type: GraphQLInt,
818
+ },
819
+ offset: {
820
+ type: GraphQLInt,
821
+ },
822
+ page: {
823
+ type: GraphQLInt,
824
+ },
825
+ search: {
826
+ type: GraphQLString,
827
+ },
828
+ };
829
+ }
830
+ ReadCollectionTypes[collection.collection].addResolver(resolver);
831
+ ReadCollectionTypes[collection.collection].addResolver({
832
+ name: `${collection.collection}_aggregated`,
833
+ type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(AggregatedFunctions[collection.collection].getType()))),
834
+ args: {
835
+ groupBy: new GraphQLList(GraphQLString),
836
+ filter: ReadableCollectionFilterTypes[collection.collection],
837
+ limit: {
838
+ type: GraphQLInt,
839
+ },
840
+ offset: {
841
+ type: GraphQLInt,
842
+ },
843
+ page: {
844
+ type: GraphQLInt,
845
+ },
846
+ search: {
847
+ type: GraphQLString,
848
+ },
849
+ sort: {
850
+ type: new GraphQLList(GraphQLString),
851
+ },
852
+ },
853
+ resolve: async ({ info, context }) => {
854
+ const result = await self.resolveQuery(info);
855
+ context['data'] = result;
856
+ return result;
857
+ },
858
+ });
859
+ if (collection.singleton === false) {
860
+ ReadCollectionTypes[collection.collection].addResolver({
861
+ name: `${collection.collection}_by_id`,
862
+ type: ReadCollectionTypes[collection.collection],
863
+ args: {
864
+ id: new GraphQLNonNull(GraphQLID),
865
+ },
866
+ resolve: async ({ info, context }) => {
867
+ const result = await self.resolveQuery(info);
868
+ context['data'] = result;
869
+ return result;
870
+ },
871
+ });
872
+ }
873
+ }
874
+ for (const relation of schema.read.relations) {
875
+ if (relation.related_collection) {
876
+ if (SYSTEM_DENY_LIST.includes(relation.related_collection))
877
+ continue;
878
+ ReadableCollectionFilterTypes[relation.collection]?.addFields({
879
+ [relation.field]: ReadableCollectionFilterTypes[relation.related_collection],
880
+ });
881
+ ReadCollectionTypes[relation.collection]?.addFieldArgs(relation.field, {
882
+ filter: ReadableCollectionFilterTypes[relation.related_collection],
883
+ sort: {
884
+ type: new GraphQLList(GraphQLString),
885
+ },
886
+ limit: {
887
+ type: GraphQLInt,
888
+ },
889
+ offset: {
890
+ type: GraphQLInt,
891
+ },
892
+ page: {
893
+ type: GraphQLInt,
894
+ },
895
+ search: {
896
+ type: GraphQLString,
897
+ },
898
+ });
899
+ if (relation.meta?.one_field) {
900
+ ReadableCollectionFilterTypes[relation.related_collection]?.addFields({
901
+ [relation.meta.one_field]: ReadableCollectionFilterTypes[relation.collection],
902
+ });
903
+ ReadCollectionTypes[relation.related_collection]?.addFieldArgs(relation.meta.one_field, {
904
+ filter: ReadableCollectionFilterTypes[relation.collection],
905
+ sort: {
906
+ type: new GraphQLList(GraphQLString),
907
+ },
908
+ limit: {
909
+ type: GraphQLInt,
910
+ },
911
+ offset: {
912
+ type: GraphQLInt,
913
+ },
914
+ page: {
915
+ type: GraphQLInt,
916
+ },
917
+ search: {
918
+ type: GraphQLString,
919
+ },
920
+ });
921
+ }
922
+ }
923
+ else if (relation.meta?.one_allowed_collections) {
924
+ ReadableCollectionFilterTypes[relation.collection]?.removeField('item');
925
+ for (const collection of relation.meta.one_allowed_collections) {
926
+ ReadableCollectionFilterTypes[relation.collection]?.addFields({
927
+ [`item__${collection}`]: ReadableCollectionFilterTypes[collection],
928
+ });
929
+ }
930
+ }
931
+ }
932
+ return { ReadCollectionTypes, ReadableCollectionFilterTypes };
933
+ }
934
+ function getWritableTypes() {
935
+ const { CollectionTypes: CreateCollectionTypes } = getTypes('create');
936
+ const { CollectionTypes: UpdateCollectionTypes } = getTypes('update');
937
+ const DeleteCollectionTypes = {};
938
+ for (const collection of Object.values(schema.create.collections)) {
939
+ if (Object.keys(collection.fields).length === 0)
940
+ continue;
941
+ if (SYSTEM_DENY_LIST.includes(collection.collection))
942
+ continue;
943
+ if (collection.collection in CreateCollectionTypes === false)
944
+ continue;
945
+ const collectionIsReadable = collection.collection in ReadCollectionTypes;
946
+ const creatableFields = CreateCollectionTypes[collection.collection]?.getFields() || {};
947
+ if (Object.keys(creatableFields).length > 0) {
948
+ const resolverDefinition = {
949
+ name: `create_${collection.collection}_items`,
950
+ type: collectionIsReadable
951
+ ? new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(ReadCollectionTypes[collection.collection].getType())))
952
+ : GraphQLBoolean,
953
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
954
+ };
955
+ if (collectionIsReadable) {
956
+ resolverDefinition.args = ReadCollectionTypes[collection.collection].getResolver(collection.collection).getArgs();
957
+ }
958
+ CreateCollectionTypes[collection.collection].addResolver(resolverDefinition);
959
+ CreateCollectionTypes[collection.collection].addResolver({
960
+ name: `create_${collection.collection}_item`,
961
+ type: collectionIsReadable ? ReadCollectionTypes[collection.collection] : GraphQLBoolean,
962
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
963
+ });
964
+ CreateCollectionTypes[collection.collection].getResolver(`create_${collection.collection}_items`).addArgs({
965
+ ...CreateCollectionTypes[collection.collection].getResolver(`create_${collection.collection}_items`).getArgs(),
966
+ data: [
967
+ toInputObjectType(CreateCollectionTypes[collection.collection]).setTypeName(`create_${collection.collection}_input`).NonNull,
968
+ ],
969
+ });
970
+ CreateCollectionTypes[collection.collection].getResolver(`create_${collection.collection}_item`).addArgs({
971
+ ...CreateCollectionTypes[collection.collection].getResolver(`create_${collection.collection}_item`).getArgs(),
972
+ data: toInputObjectType(CreateCollectionTypes[collection.collection]).setTypeName(`create_${collection.collection}_input`).NonNull,
973
+ });
974
+ }
975
+ }
976
+ for (const collection of Object.values(schema.update.collections)) {
977
+ if (Object.keys(collection.fields).length === 0)
978
+ continue;
979
+ if (SYSTEM_DENY_LIST.includes(collection.collection))
980
+ continue;
981
+ if (collection.collection in UpdateCollectionTypes === false)
982
+ continue;
983
+ const collectionIsReadable = collection.collection in ReadCollectionTypes;
984
+ const updatableFields = UpdateCollectionTypes[collection.collection]?.getFields() || {};
985
+ if (Object.keys(updatableFields).length > 0) {
986
+ if (collection.singleton) {
987
+ UpdateCollectionTypes[collection.collection].addResolver({
988
+ name: `update_${collection.collection}`,
989
+ type: collectionIsReadable ? ReadCollectionTypes[collection.collection] : GraphQLBoolean,
990
+ args: {
991
+ data: toInputObjectType(UpdateCollectionTypes[collection.collection]).setTypeName(`update_${collection.collection}_input`).NonNull,
992
+ },
993
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
994
+ });
995
+ }
996
+ else {
997
+ UpdateCollectionTypes[collection.collection].addResolver({
998
+ name: `update_${collection.collection}_batch`,
999
+ type: collectionIsReadable
1000
+ ? new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(ReadCollectionTypes[collection.collection].getType())))
1001
+ : GraphQLBoolean,
1002
+ args: {
1003
+ ...(collectionIsReadable
1004
+ ? ReadCollectionTypes[collection.collection].getResolver(collection.collection).getArgs()
1005
+ : {}),
1006
+ data: [
1007
+ toInputObjectType(UpdateCollectionTypes[collection.collection]).setTypeName(`update_${collection.collection}_input`).NonNull,
1008
+ ],
1009
+ },
1010
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
1011
+ });
1012
+ UpdateCollectionTypes[collection.collection].addResolver({
1013
+ name: `update_${collection.collection}_items`,
1014
+ type: collectionIsReadable
1015
+ ? new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(ReadCollectionTypes[collection.collection].getType())))
1016
+ : GraphQLBoolean,
1017
+ args: {
1018
+ ...(collectionIsReadable
1019
+ ? ReadCollectionTypes[collection.collection].getResolver(collection.collection).getArgs()
1020
+ : {}),
1021
+ ids: new GraphQLNonNull(new GraphQLList(GraphQLID)),
1022
+ data: toInputObjectType(UpdateCollectionTypes[collection.collection]).setTypeName(`update_${collection.collection}_input`).NonNull,
1023
+ },
1024
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
1025
+ });
1026
+ UpdateCollectionTypes[collection.collection].addResolver({
1027
+ name: `update_${collection.collection}_item`,
1028
+ type: collectionIsReadable ? ReadCollectionTypes[collection.collection] : GraphQLBoolean,
1029
+ args: {
1030
+ id: new GraphQLNonNull(GraphQLID),
1031
+ data: toInputObjectType(UpdateCollectionTypes[collection.collection]).setTypeName(`update_${collection.collection}_input`).NonNull,
1032
+ },
1033
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
1034
+ });
1035
+ }
1036
+ }
1037
+ }
1038
+ DeleteCollectionTypes['many'] = schemaComposer.createObjectTC({
1039
+ name: `delete_many`,
1040
+ fields: {
1041
+ ids: new GraphQLNonNull(new GraphQLList(GraphQLID)),
1042
+ },
1043
+ });
1044
+ DeleteCollectionTypes['one'] = schemaComposer.createObjectTC({
1045
+ name: `delete_one`,
1046
+ fields: {
1047
+ id: new GraphQLNonNull(GraphQLID),
1048
+ },
1049
+ });
1050
+ for (const collection of Object.values(schema.delete.collections)) {
1051
+ DeleteCollectionTypes['many'].addResolver({
1052
+ name: `delete_${collection.collection}_items`,
1053
+ type: DeleteCollectionTypes['many'],
1054
+ args: {
1055
+ ids: new GraphQLNonNull(new GraphQLList(GraphQLID)),
1056
+ },
1057
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
1058
+ });
1059
+ DeleteCollectionTypes['one'].addResolver({
1060
+ name: `delete_${collection.collection}_item`,
1061
+ type: DeleteCollectionTypes['one'],
1062
+ args: {
1063
+ id: new GraphQLNonNull(GraphQLID),
1064
+ },
1065
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
1066
+ });
1067
+ }
1068
+ return { CreateCollectionTypes, UpdateCollectionTypes, DeleteCollectionTypes };
1069
+ }
1070
+ }
1071
+ /**
1072
+ * Generic resolver that's used for every "regular" items/system query. Converts the incoming GraphQL AST / fragments into
1073
+ * Directus' query structure which is then executed by the services.
1074
+ */
1075
+ async resolveQuery(info) {
1076
+ let collection = info.fieldName;
1077
+ if (this.scope === 'system')
1078
+ collection = `directus_${collection}`;
1079
+ const selections = this.replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
1080
+ if (!selections)
1081
+ return null;
1082
+ const args = this.parseArgs(info.fieldNodes[0].arguments || [], info.variableValues);
1083
+ let query;
1084
+ const isAggregate = collection.endsWith('_aggregated') && collection in this.schema.collections === false;
1085
+ if (isAggregate) {
1086
+ query = this.getAggregateQuery(args, selections);
1087
+ collection = collection.slice(0, -11);
1088
+ }
1089
+ else {
1090
+ query = this.getQuery(args, selections, info.variableValues);
1091
+ if (collection.endsWith('_by_id') && collection in this.schema.collections === false) {
1092
+ collection = collection.slice(0, -6);
1093
+ }
1094
+ }
1095
+ if (args['id']) {
1096
+ query.filter = {
1097
+ _and: [
1098
+ query.filter || {},
1099
+ {
1100
+ [this.schema.collections[collection].primary]: {
1101
+ _eq: args['id'],
1102
+ },
1103
+ },
1104
+ ],
1105
+ };
1106
+ query.limit = 1;
1107
+ }
1108
+ // Transform count(a.b.c) into a.b.count(c)
1109
+ if (query.fields?.length) {
1110
+ for (let fieldIndex = 0; fieldIndex < query.fields.length; fieldIndex++) {
1111
+ query.fields[fieldIndex] = parseFilterFunctionPath(query.fields[fieldIndex]);
1112
+ }
1113
+ }
1114
+ const result = await this.read(collection, query);
1115
+ if (args['id']) {
1116
+ return result?.[0] || null;
1117
+ }
1118
+ if (query.group) {
1119
+ // for every entry in result add a group field based on query.group;
1120
+ const aggregateKeys = Object.keys(query.aggregate ?? {});
1121
+ result['map']((field) => {
1122
+ field['group'] = omit(field, aggregateKeys);
1123
+ });
1124
+ }
1125
+ return result;
1126
+ }
1127
+ async resolveMutation(args, info) {
1128
+ const action = info.fieldName.split('_')[0];
1129
+ let collection = info.fieldName.substring(action.length + 1);
1130
+ if (this.scope === 'system')
1131
+ collection = `directus_${collection}`;
1132
+ const selections = this.replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
1133
+ const query = this.getQuery(args, selections || [], info.variableValues);
1134
+ const singleton = collection.endsWith('_batch') === false &&
1135
+ collection.endsWith('_items') === false &&
1136
+ collection.endsWith('_item') === false &&
1137
+ collection in this.schema.collections;
1138
+ const single = collection.endsWith('_items') === false && collection.endsWith('_batch') === false;
1139
+ const batchUpdate = action === 'update' && collection.endsWith('_batch');
1140
+ if (collection.endsWith('_batch'))
1141
+ collection = collection.slice(0, -6);
1142
+ if (collection.endsWith('_items'))
1143
+ collection = collection.slice(0, -6);
1144
+ if (collection.endsWith('_item'))
1145
+ collection = collection.slice(0, -5);
1146
+ if (singleton && action === 'update') {
1147
+ return await this.upsertSingleton(collection, args['data'], query);
1148
+ }
1149
+ const service = this.getService(collection);
1150
+ const hasQuery = (query.fields || []).length > 0;
1151
+ try {
1152
+ if (single) {
1153
+ if (action === 'create') {
1154
+ const key = await service.createOne(args['data']);
1155
+ return hasQuery ? await service.readOne(key, query) : true;
1156
+ }
1157
+ if (action === 'update') {
1158
+ const key = await service.updateOne(args['id'], args['data']);
1159
+ return hasQuery ? await service.readOne(key, query) : true;
1160
+ }
1161
+ if (action === 'delete') {
1162
+ await service.deleteOne(args['id']);
1163
+ return { id: args['id'] };
1164
+ }
1165
+ return undefined;
1166
+ }
1167
+ else {
1168
+ if (action === 'create') {
1169
+ const keys = await service.createMany(args['data']);
1170
+ return hasQuery ? await service.readMany(keys, query) : true;
1171
+ }
1172
+ if (action === 'update') {
1173
+ const keys = [];
1174
+ if (batchUpdate) {
1175
+ keys.push(...(await service.updateBatch(args['data'])));
1176
+ }
1177
+ else {
1178
+ keys.push(...(await service.updateMany(args['ids'], args['data'])));
1179
+ }
1180
+ return hasQuery ? await service.readMany(keys, query) : true;
1181
+ }
1182
+ if (action === 'delete') {
1183
+ const keys = await service.deleteMany(args['ids']);
1184
+ return { ids: keys };
1185
+ }
1186
+ return undefined;
1187
+ }
1188
+ }
1189
+ catch (err) {
1190
+ return this.formatError(err);
1191
+ }
1192
+ }
1193
+ /**
1194
+ * Execute the read action on the correct service. Checks for singleton as well.
1195
+ */
1196
+ async read(collection, query) {
1197
+ const service = this.getService(collection);
1198
+ const result = this.schema.collections[collection].singleton
1199
+ ? await service.readSingleton(query, { stripNonRequested: false })
1200
+ : await service.readByQuery(query, { stripNonRequested: false });
1201
+ return result;
1202
+ }
1203
+ /**
1204
+ * Upsert and read singleton item
1205
+ */
1206
+ async upsertSingleton(collection, body, query) {
1207
+ const service = this.getService(collection);
1208
+ try {
1209
+ await service.upsertSingleton(body);
1210
+ if ((query.fields || []).length > 0) {
1211
+ const result = await service.readSingleton(query);
1212
+ return result;
1213
+ }
1214
+ return true;
1215
+ }
1216
+ catch (err) {
1217
+ throw this.formatError(err);
1218
+ }
1219
+ }
1220
+ /**
1221
+ * GraphQL's regular resolver `args` variable only contains the "top-level" arguments. Seeing that we convert the
1222
+ * whole nested tree into one big query using Directus' own query resolver, we want to have a nested structure of
1223
+ * arguments for the whole resolving tree, which can later be transformed into Directus' AST using `deep`.
1224
+ * In order to do that, we'll parse over all ArgumentNodes and ObjectFieldNodes to manually recreate an object structure
1225
+ * of arguments
1226
+ */
1227
+ parseArgs(args, variableValues) {
1228
+ if (!args || args['length'] === 0)
1229
+ return {};
1230
+ const parse = (node) => {
1231
+ switch (node.kind) {
1232
+ case 'Variable':
1233
+ return variableValues[node.name.value];
1234
+ case 'ListValue':
1235
+ return node.values.map(parse);
1236
+ case 'ObjectValue':
1237
+ return Object.fromEntries(node.fields.map((node) => [node.name.value, parse(node.value)]));
1238
+ case 'NullValue':
1239
+ return null;
1240
+ case 'StringValue':
1241
+ return String(node.value);
1242
+ case 'IntValue':
1243
+ case 'FloatValue':
1244
+ return Number(node.value);
1245
+ case 'BooleanValue':
1246
+ return Boolean(node.value);
1247
+ case 'EnumValue':
1248
+ default:
1249
+ return 'value' in node ? node.value : null;
1250
+ }
1251
+ };
1252
+ const argsObject = Object.fromEntries(args['map']((arg) => [arg.name.value, parse(arg.value)]));
1253
+ return argsObject;
1254
+ }
1255
+ /**
1256
+ * Get a Directus Query object from the parsed arguments (rawQuery) and GraphQL AST selectionSet. Converts SelectionSet into
1257
+ * Directus' `fields` query for use in the resolver. Also applies variables where appropriate.
1258
+ */
1259
+ getQuery(rawQuery, selections, variableValues) {
1260
+ const query = sanitizeQuery(rawQuery, this.accountability);
1261
+ const parseAliases = (selections) => {
1262
+ const aliases = {};
1263
+ for (const selection of selections) {
1264
+ if (selection.kind !== 'Field')
1265
+ continue;
1266
+ if (selection.alias?.value) {
1267
+ aliases[selection.alias.value] = selection.name.value;
1268
+ }
1269
+ }
1270
+ return aliases;
1271
+ };
1272
+ const parseFields = (selections, parent) => {
1273
+ const fields = [];
1274
+ for (let selection of selections) {
1275
+ if ((selection.kind === 'Field' || selection.kind === 'InlineFragment') !== true)
1276
+ continue;
1277
+ selection = selection;
1278
+ let current;
1279
+ let currentAlias = null;
1280
+ // Union type (Many-to-Any)
1281
+ if (selection.kind === 'InlineFragment') {
1282
+ if (selection.typeCondition.name.value.startsWith('__'))
1283
+ continue;
1284
+ current = `${parent}:${selection.typeCondition.name.value}`;
1285
+ }
1286
+ // Any other field type
1287
+ else {
1288
+ // filter out graphql pointers, like __typename
1289
+ if (selection.name.value.startsWith('__'))
1290
+ continue;
1291
+ current = selection.name.value;
1292
+ if (selection.alias) {
1293
+ currentAlias = selection.alias.value;
1294
+ }
1295
+ if (parent) {
1296
+ current = `${parent}.${current}`;
1297
+ if (currentAlias) {
1298
+ currentAlias = `${parent}.${currentAlias}`;
1299
+ // add nested aliases into deep query
1300
+ if (selection.selectionSet) {
1301
+ if (!query.deep)
1302
+ query.deep = {};
1303
+ set(query.deep, parent, merge({}, get(query.deep, parent), { _alias: { [selection.alias.value]: selection.name.value } }));
1304
+ }
1305
+ }
1306
+ }
1307
+ }
1308
+ if (selection.selectionSet) {
1309
+ let children;
1310
+ if (current.endsWith('_func')) {
1311
+ children = [];
1312
+ const rootField = current.slice(0, -5);
1313
+ for (const subSelection of selection.selectionSet.selections) {
1314
+ if (subSelection.kind !== 'Field')
1315
+ continue;
1316
+ if (subSelection.name.value.startsWith('__'))
1317
+ continue;
1318
+ children.push(`${subSelection.name.value}(${rootField})`);
1319
+ }
1320
+ }
1321
+ else {
1322
+ children = parseFields(selection.selectionSet.selections, currentAlias ?? current);
1323
+ }
1324
+ fields.push(...children);
1325
+ }
1326
+ else {
1327
+ fields.push(current);
1328
+ }
1329
+ if (selection.kind === 'Field' && selection.arguments && selection.arguments.length > 0) {
1330
+ if (selection.arguments && selection.arguments.length > 0) {
1331
+ if (!query.deep)
1332
+ query.deep = {};
1333
+ const args = this.parseArgs(selection.arguments, variableValues);
1334
+ set(query.deep, currentAlias ?? current, merge({}, get(query.deep, currentAlias ?? current), mapKeys(sanitizeQuery(args, this.accountability), (_value, key) => `_${key}`)));
1335
+ }
1336
+ }
1337
+ }
1338
+ return uniq(fields);
1339
+ };
1340
+ query.alias = parseAliases(selections);
1341
+ query.fields = parseFields(selections);
1342
+ if (query.filter)
1343
+ query.filter = this.replaceFuncs(query.filter);
1344
+ query.deep = this.replaceFuncs(query.deep);
1345
+ validateQuery(query);
1346
+ return query;
1347
+ }
1348
+ /**
1349
+ * Resolve the aggregation query based on the requested aggregated fields
1350
+ */
1351
+ getAggregateQuery(rawQuery, selections) {
1352
+ const query = sanitizeQuery(rawQuery, this.accountability);
1353
+ query.aggregate = {};
1354
+ for (let aggregationGroup of selections) {
1355
+ if ((aggregationGroup.kind === 'Field') !== true)
1356
+ continue;
1357
+ aggregationGroup = aggregationGroup;
1358
+ // filter out graphql pointers, like __typename
1359
+ if (aggregationGroup.name.value.startsWith('__'))
1360
+ continue;
1361
+ const aggregateProperty = aggregationGroup.name.value;
1362
+ query.aggregate[aggregateProperty] =
1363
+ aggregationGroup.selectionSet?.selections
1364
+ // filter out graphql pointers, like __typename
1365
+ .filter((selectionNode) => !selectionNode?.name.value.startsWith('__'))
1366
+ .map((selectionNode) => {
1367
+ selectionNode = selectionNode;
1368
+ return selectionNode.name.value;
1369
+ }) ?? [];
1370
+ }
1371
+ if (query.filter) {
1372
+ query.filter = this.replaceFuncs(query.filter);
1373
+ }
1374
+ validateQuery(query);
1375
+ return query;
1376
+ }
1377
+ /**
1378
+ * Replace functions from GraphQL format to Directus-Filter format
1379
+ */
1380
+ replaceFuncs(filter) {
1381
+ return replaceFuncDeep(filter);
1382
+ function replaceFuncDeep(filter) {
1383
+ return transform(filter, (result, value, key) => {
1384
+ const isFunctionKey = typeof key === 'string' && key.endsWith('_func') && FUNCTIONS.includes(Object.keys(value)[0]);
1385
+ if (isFunctionKey) {
1386
+ const functionName = Object.keys(value)[0];
1387
+ const fieldName = key.slice(0, -5);
1388
+ result[`${functionName}(${fieldName})`] = Object.values(value)[0];
1389
+ }
1390
+ else {
1391
+ result[key] = value?.constructor === Object || value?.constructor === Array ? replaceFuncDeep(value) : value;
1392
+ }
1393
+ });
1394
+ }
1395
+ }
1396
+ /**
1397
+ * Convert Directus-Exception into a GraphQL format, so it can be returned by GraphQL properly.
1398
+ */
1399
+ formatError(error) {
1400
+ if (Array.isArray(error)) {
1401
+ set(error[0], 'extensions.code', error[0].code);
1402
+ return new GraphQLError(error[0].message, undefined, undefined, undefined, undefined, error[0]);
1403
+ }
1404
+ set(error, 'extensions.code', error.code);
1405
+ return new GraphQLError(error.message, undefined, undefined, undefined, undefined, error);
1406
+ }
1407
+ /**
1408
+ * Select the correct service for the given collection. This allows the individual services to run
1409
+ * their custom checks (f.e. it allows UsersService to prevent updating TFA secret from outside)
1410
+ */
1411
+ getService(collection) {
1412
+ const opts = {
1413
+ knex: this.knex,
1414
+ accountability: this.accountability,
1415
+ schema: this.schema,
1416
+ };
1417
+ switch (collection) {
1418
+ case 'directus_activity':
1419
+ return new ActivityService(opts);
1420
+ case 'directus_files':
1421
+ return new FilesService(opts);
1422
+ case 'directus_folders':
1423
+ return new FoldersService(opts);
1424
+ case 'directus_permissions':
1425
+ return new PermissionsService(opts);
1426
+ case 'directus_presets':
1427
+ return new PresetsService(opts);
1428
+ case 'directus_notifications':
1429
+ return new NotificationsService(opts);
1430
+ case 'directus_revisions':
1431
+ return new RevisionsService(opts);
1432
+ case 'directus_roles':
1433
+ return new RolesService(opts);
1434
+ case 'directus_settings':
1435
+ return new SettingsService(opts);
1436
+ case 'directus_users':
1437
+ return new UsersService(opts);
1438
+ case 'directus_webhooks':
1439
+ return new WebhooksService(opts);
1440
+ case 'directus_shares':
1441
+ return new SharesService(opts);
1442
+ case 'directus_flows':
1443
+ return new FlowsService(opts);
1444
+ case 'directus_operations':
1445
+ return new OperationsService(opts);
1446
+ default:
1447
+ return new ItemsService(collection, opts);
1448
+ }
1449
+ }
1450
+ /**
1451
+ * Replace all fragments in a selectionset for the actual selection set as defined in the fragment
1452
+ * Effectively merges the selections with the fragments used in those selections
1453
+ */
1454
+ replaceFragmentsInSelections(selections, fragments) {
1455
+ if (!selections)
1456
+ return null;
1457
+ const result = flatten(selections.map((selection) => {
1458
+ // Fragments can contains fragments themselves. This allows for nested fragments
1459
+ if (selection.kind === 'FragmentSpread') {
1460
+ return this.replaceFragmentsInSelections(fragments[selection.name.value].selectionSet.selections, fragments);
1461
+ }
1462
+ // Nested relational fields can also contain fragments
1463
+ if ((selection.kind === 'Field' || selection.kind === 'InlineFragment') && selection.selectionSet) {
1464
+ selection.selectionSet.selections = this.replaceFragmentsInSelections(selection.selectionSet.selections, fragments);
1465
+ }
1466
+ return selection;
1467
+ })).filter((s) => s);
1468
+ return result;
1469
+ }
1470
+ injectSystemResolvers(schemaComposer, { CreateCollectionTypes, ReadCollectionTypes, UpdateCollectionTypes, DeleteCollectionTypes, }, schema) {
1471
+ const AuthTokens = schemaComposer.createObjectTC({
1472
+ name: 'auth_tokens',
1473
+ fields: {
1474
+ access_token: GraphQLString,
1475
+ expires: GraphQLBigInt,
1476
+ refresh_token: GraphQLString,
1477
+ },
1478
+ });
1479
+ const AuthMode = new GraphQLEnumType({
1480
+ name: 'auth_mode',
1481
+ values: {
1482
+ json: { value: 'json' },
1483
+ cookie: { value: 'cookie' },
1484
+ },
1485
+ });
1486
+ const ServerInfo = schemaComposer.createObjectTC({
1487
+ name: 'server_info',
1488
+ fields: {
1489
+ project: {
1490
+ type: new GraphQLObjectType({
1491
+ name: 'server_info_project',
1492
+ fields: {
1493
+ project_name: { type: GraphQLString },
1494
+ project_descriptor: { type: GraphQLString },
1495
+ project_logo: { type: GraphQLString },
1496
+ project_color: { type: GraphQLString },
1497
+ default_language: { type: GraphQLString },
1498
+ public_foreground: { type: GraphQLString },
1499
+ public_background: { type: GraphQLString },
1500
+ public_note: { type: GraphQLString },
1501
+ custom_css: { type: GraphQLString },
1502
+ },
1503
+ }),
1504
+ },
1505
+ },
1506
+ });
1507
+ if (this.accountability?.user) {
1508
+ ServerInfo.addFields({
1509
+ rateLimit: env['RATE_LIMITER_ENABLED']
1510
+ ? {
1511
+ type: new GraphQLObjectType({
1512
+ name: 'server_info_rate_limit',
1513
+ fields: {
1514
+ points: { type: GraphQLInt },
1515
+ duration: { type: GraphQLInt },
1516
+ },
1517
+ }),
1518
+ }
1519
+ : GraphQLBoolean,
1520
+ rateLimitGlobal: env['RATE_LIMITER_GLOBAL_ENABLED']
1521
+ ? {
1522
+ type: new GraphQLObjectType({
1523
+ name: 'server_info_rate_limit_global',
1524
+ fields: {
1525
+ points: { type: GraphQLInt },
1526
+ duration: { type: GraphQLInt },
1527
+ },
1528
+ }),
1529
+ }
1530
+ : GraphQLBoolean,
1531
+ flows: {
1532
+ type: new GraphQLObjectType({
1533
+ name: 'server_info_flows',
1534
+ fields: {
1535
+ execAllowedModules: {
1536
+ type: new GraphQLList(GraphQLString),
1537
+ },
1538
+ },
1539
+ }),
1540
+ },
1541
+ });
1542
+ }
1543
+ if (this.accountability?.admin === true) {
1544
+ ServerInfo.addFields({
1545
+ directus: {
1546
+ type: new GraphQLObjectType({
1547
+ name: 'server_info_directus',
1548
+ fields: {
1549
+ version: {
1550
+ type: GraphQLString,
1551
+ },
1552
+ },
1553
+ }),
1554
+ },
1555
+ node: {
1556
+ type: new GraphQLObjectType({
1557
+ name: 'server_info_node',
1558
+ fields: {
1559
+ version: {
1560
+ type: GraphQLString,
1561
+ },
1562
+ uptime: {
1563
+ type: GraphQLInt,
1564
+ },
1565
+ },
1566
+ }),
1567
+ },
1568
+ os: {
1569
+ type: new GraphQLObjectType({
1570
+ name: 'server_info_os',
1571
+ fields: {
1572
+ type: {
1573
+ type: GraphQLString,
1574
+ },
1575
+ version: {
1576
+ type: GraphQLString,
1577
+ },
1578
+ uptime: {
1579
+ type: GraphQLInt,
1580
+ },
1581
+ totalmem: {
1582
+ type: GraphQLInt,
1583
+ },
1584
+ },
1585
+ }),
1586
+ },
1587
+ });
1588
+ }
1589
+ /** Globally available query */
1590
+ schemaComposer.Query.addFields({
1591
+ extensions: {
1592
+ type: schemaComposer.createObjectTC({
1593
+ name: 'extensions',
1594
+ fields: {
1595
+ interfaces: new GraphQLList(GraphQLString),
1596
+ displays: new GraphQLList(GraphQLString),
1597
+ layouts: new GraphQLList(GraphQLString),
1598
+ modules: new GraphQLList(GraphQLString),
1599
+ },
1600
+ }),
1601
+ resolve: async () => {
1602
+ const extensionManager = getExtensionManager();
1603
+ return {
1604
+ interfaces: extensionManager.getExtensionsList('interface'),
1605
+ displays: extensionManager.getExtensionsList('display'),
1606
+ layouts: extensionManager.getExtensionsList('layout'),
1607
+ modules: extensionManager.getExtensionsList('module'),
1608
+ };
1609
+ },
1610
+ },
1611
+ server_specs_oas: {
1612
+ type: GraphQLJSON,
1613
+ resolve: async () => {
1614
+ const service = new SpecificationService({ schema: this.schema, accountability: this.accountability });
1615
+ return await service.oas.generate();
1616
+ },
1617
+ },
1618
+ server_specs_graphql: {
1619
+ type: GraphQLString,
1620
+ args: {
1621
+ scope: new GraphQLEnumType({
1622
+ name: 'graphql_sdl_scope',
1623
+ values: {
1624
+ items: { value: 'items' },
1625
+ system: { value: 'system' },
1626
+ },
1627
+ }),
1628
+ },
1629
+ resolve: async (_, args) => {
1630
+ const service = new GraphQLService({
1631
+ schema: this.schema,
1632
+ accountability: this.accountability,
1633
+ scope: args['scope'] ?? 'items',
1634
+ });
1635
+ return service.getSchema('sdl');
1636
+ },
1637
+ },
1638
+ server_ping: {
1639
+ type: GraphQLString,
1640
+ resolve: () => 'pong',
1641
+ },
1642
+ server_info: {
1643
+ type: ServerInfo,
1644
+ resolve: async () => {
1645
+ const service = new ServerService({
1646
+ accountability: this.accountability,
1647
+ schema: this.schema,
1648
+ });
1649
+ return await service.serverInfo();
1650
+ },
1651
+ },
1652
+ server_health: {
1653
+ type: GraphQLJSON,
1654
+ resolve: async () => {
1655
+ const service = new ServerService({
1656
+ accountability: this.accountability,
1657
+ schema: this.schema,
1658
+ });
1659
+ return await service.health();
1660
+ },
1661
+ },
1662
+ });
1663
+ const Collection = schemaComposer.createObjectTC({
1664
+ name: 'directus_collections',
1665
+ });
1666
+ const Field = schemaComposer.createObjectTC({
1667
+ name: 'directus_fields',
1668
+ });
1669
+ const Relation = schemaComposer.createObjectTC({
1670
+ name: 'directus_relations',
1671
+ });
1672
+ /**
1673
+ * Globally available mutations
1674
+ */
1675
+ schemaComposer.Mutation.addFields({
1676
+ auth_login: {
1677
+ type: AuthTokens,
1678
+ args: {
1679
+ email: new GraphQLNonNull(GraphQLString),
1680
+ password: new GraphQLNonNull(GraphQLString),
1681
+ mode: AuthMode,
1682
+ otp: GraphQLString,
1683
+ },
1684
+ resolve: async (_, args, { req, res }) => {
1685
+ const accountability = { role: null };
1686
+ if (req?.ip)
1687
+ accountability.ip = req.ip;
1688
+ const userAgent = req?.get('user-agent');
1689
+ if (userAgent)
1690
+ accountability.userAgent = userAgent;
1691
+ const origin = req?.get('origin');
1692
+ if (origin)
1693
+ accountability.origin = origin;
1694
+ const authenticationService = new AuthenticationService({
1695
+ accountability: accountability,
1696
+ schema: this.schema,
1697
+ });
1698
+ const result = await authenticationService.login(DEFAULT_AUTH_PROVIDER, args, args?.otp);
1699
+ if (args['mode'] === 'cookie') {
1700
+ res?.cookie(env['REFRESH_TOKEN_COOKIE_NAME'], result['refreshToken'], {
1701
+ httpOnly: true,
1702
+ domain: env['REFRESH_TOKEN_COOKIE_DOMAIN'],
1703
+ maxAge: getMilliseconds(env['REFRESH_TOKEN_TTL']),
1704
+ secure: env['REFRESH_TOKEN_COOKIE_SECURE'] ?? false,
1705
+ sameSite: env['REFRESH_TOKEN_COOKIE_SAME_SITE'] || 'strict',
1706
+ });
1707
+ }
1708
+ return {
1709
+ access_token: result['accessToken'],
1710
+ expires: result['expires'],
1711
+ refresh_token: result['refreshToken'],
1712
+ };
1713
+ },
1714
+ },
1715
+ auth_refresh: {
1716
+ type: AuthTokens,
1717
+ args: {
1718
+ refresh_token: GraphQLString,
1719
+ mode: AuthMode,
1720
+ },
1721
+ resolve: async (_, args, { req, res }) => {
1722
+ const accountability = { role: null };
1723
+ if (req?.ip)
1724
+ accountability.ip = req.ip;
1725
+ const userAgent = req?.get('user-agent');
1726
+ if (userAgent)
1727
+ accountability.userAgent = userAgent;
1728
+ const origin = req?.get('origin');
1729
+ if (origin)
1730
+ accountability.origin = origin;
1731
+ const authenticationService = new AuthenticationService({
1732
+ accountability: accountability,
1733
+ schema: this.schema,
1734
+ });
1735
+ const currentRefreshToken = args['refresh_token'] || req?.cookies[env['REFRESH_TOKEN_COOKIE_NAME']];
1736
+ if (!currentRefreshToken) {
1737
+ throw new InvalidPayloadException(`"refresh_token" is required in either the JSON payload or Cookie`);
1738
+ }
1739
+ const result = await authenticationService.refresh(currentRefreshToken);
1740
+ if (args['mode'] === 'cookie') {
1741
+ res?.cookie(env['REFRESH_TOKEN_COOKIE_NAME'], result['refreshToken'], {
1742
+ httpOnly: true,
1743
+ domain: env['REFRESH_TOKEN_COOKIE_DOMAIN'],
1744
+ maxAge: getMilliseconds(env['REFRESH_TOKEN_TTL']),
1745
+ secure: env['REFRESH_TOKEN_COOKIE_SECURE'] ?? false,
1746
+ sameSite: env['REFRESH_TOKEN_COOKIE_SAME_SITE'] || 'strict',
1747
+ });
1748
+ }
1749
+ return {
1750
+ access_token: result['accessToken'],
1751
+ expires: result['expires'],
1752
+ refresh_token: result['refreshToken'],
1753
+ };
1754
+ },
1755
+ },
1756
+ auth_logout: {
1757
+ type: GraphQLBoolean,
1758
+ args: {
1759
+ refresh_token: GraphQLString,
1760
+ },
1761
+ resolve: async (_, args, { req }) => {
1762
+ const accountability = { role: null };
1763
+ if (req?.ip)
1764
+ accountability.ip = req.ip;
1765
+ const userAgent = req?.get('user-agent');
1766
+ if (userAgent)
1767
+ accountability.userAgent = userAgent;
1768
+ const origin = req?.get('origin');
1769
+ if (origin)
1770
+ accountability.origin = origin;
1771
+ const authenticationService = new AuthenticationService({
1772
+ accountability: accountability,
1773
+ schema: this.schema,
1774
+ });
1775
+ const currentRefreshToken = args['refresh_token'] || req?.cookies[env['REFRESH_TOKEN_COOKIE_NAME']];
1776
+ if (!currentRefreshToken) {
1777
+ throw new InvalidPayloadException(`"refresh_token" is required in either the JSON payload or Cookie`);
1778
+ }
1779
+ await authenticationService.logout(currentRefreshToken);
1780
+ return true;
1781
+ },
1782
+ },
1783
+ auth_password_request: {
1784
+ type: GraphQLBoolean,
1785
+ args: {
1786
+ email: new GraphQLNonNull(GraphQLString),
1787
+ reset_url: GraphQLString,
1788
+ },
1789
+ resolve: async (_, args, { req }) => {
1790
+ const accountability = { role: null };
1791
+ if (req?.ip)
1792
+ accountability.ip = req.ip;
1793
+ const userAgent = req?.get('user-agent');
1794
+ if (userAgent)
1795
+ accountability.userAgent = userAgent;
1796
+ const origin = req?.get('origin');
1797
+ if (origin)
1798
+ accountability.origin = origin;
1799
+ const service = new UsersService({ accountability, schema: this.schema });
1800
+ try {
1801
+ await service.requestPasswordReset(args['email'], args['reset_url'] || null);
1802
+ }
1803
+ catch (err) {
1804
+ if (err instanceof InvalidPayloadException) {
1805
+ throw err;
1806
+ }
1807
+ }
1808
+ return true;
1809
+ },
1810
+ },
1811
+ auth_password_reset: {
1812
+ type: GraphQLBoolean,
1813
+ args: {
1814
+ token: new GraphQLNonNull(GraphQLString),
1815
+ password: new GraphQLNonNull(GraphQLString),
1816
+ },
1817
+ resolve: async (_, args, { req }) => {
1818
+ const accountability = { role: null };
1819
+ if (req?.ip)
1820
+ accountability.ip = req.ip;
1821
+ const userAgent = req?.get('user-agent');
1822
+ if (userAgent)
1823
+ accountability.userAgent = userAgent;
1824
+ const origin = req?.get('origin');
1825
+ if (origin)
1826
+ accountability.origin = origin;
1827
+ const service = new UsersService({ accountability, schema: this.schema });
1828
+ await service.resetPassword(args['token'], args['password']);
1829
+ return true;
1830
+ },
1831
+ },
1832
+ users_me_tfa_generate: {
1833
+ type: new GraphQLObjectType({
1834
+ name: 'users_me_tfa_generate_data',
1835
+ fields: {
1836
+ secret: { type: GraphQLString },
1837
+ otpauth_url: { type: GraphQLString },
1838
+ },
1839
+ }),
1840
+ args: {
1841
+ password: new GraphQLNonNull(GraphQLString),
1842
+ },
1843
+ resolve: async (_, args) => {
1844
+ if (!this.accountability?.user)
1845
+ return null;
1846
+ const service = new TFAService({
1847
+ accountability: this.accountability,
1848
+ schema: this.schema,
1849
+ });
1850
+ const authService = new AuthenticationService({
1851
+ accountability: this.accountability,
1852
+ schema: this.schema,
1853
+ });
1854
+ await authService.verifyPassword(this.accountability.user, args['password']);
1855
+ const { url, secret } = await service.generateTFA(this.accountability.user);
1856
+ return { secret, otpauth_url: url };
1857
+ },
1858
+ },
1859
+ users_me_tfa_enable: {
1860
+ type: GraphQLBoolean,
1861
+ args: {
1862
+ otp: new GraphQLNonNull(GraphQLString),
1863
+ secret: new GraphQLNonNull(GraphQLString),
1864
+ },
1865
+ resolve: async (_, args) => {
1866
+ if (!this.accountability?.user)
1867
+ return null;
1868
+ const service = new TFAService({
1869
+ accountability: this.accountability,
1870
+ schema: this.schema,
1871
+ });
1872
+ await service.enableTFA(this.accountability.user, args['otp'], args['secret']);
1873
+ return true;
1874
+ },
1875
+ },
1876
+ users_me_tfa_disable: {
1877
+ type: GraphQLBoolean,
1878
+ args: {
1879
+ otp: new GraphQLNonNull(GraphQLString),
1880
+ },
1881
+ resolve: async (_, args) => {
1882
+ if (!this.accountability?.user)
1883
+ return null;
1884
+ const service = new TFAService({
1885
+ accountability: this.accountability,
1886
+ schema: this.schema,
1887
+ });
1888
+ const otpValid = await service.verifyOTP(this.accountability.user, args['otp']);
1889
+ if (otpValid === false) {
1890
+ throw new InvalidPayloadException(`"otp" is invalid`);
1891
+ }
1892
+ await service.disableTFA(this.accountability.user);
1893
+ return true;
1894
+ },
1895
+ },
1896
+ utils_random_string: {
1897
+ type: GraphQLString,
1898
+ args: {
1899
+ length: GraphQLInt,
1900
+ },
1901
+ resolve: async (_, args) => {
1902
+ const { nanoid } = await import('nanoid');
1903
+ if (args['length'] && Number(args['length']) > 500) {
1904
+ throw new InvalidPayloadException(`"length" can't be more than 500 characters`);
1905
+ }
1906
+ return nanoid(args['length'] ? Number(args['length']) : 32);
1907
+ },
1908
+ },
1909
+ utils_hash_generate: {
1910
+ type: GraphQLString,
1911
+ args: {
1912
+ string: new GraphQLNonNull(GraphQLString),
1913
+ },
1914
+ resolve: async (_, args) => {
1915
+ return await generateHash(args['string']);
1916
+ },
1917
+ },
1918
+ utils_hash_verify: {
1919
+ type: GraphQLBoolean,
1920
+ args: {
1921
+ string: new GraphQLNonNull(GraphQLString),
1922
+ hash: new GraphQLNonNull(GraphQLString),
1923
+ },
1924
+ resolve: async (_, args) => {
1925
+ return await argon2.verify(args['hash'], args['string']);
1926
+ },
1927
+ },
1928
+ utils_sort: {
1929
+ type: GraphQLBoolean,
1930
+ args: {
1931
+ collection: new GraphQLNonNull(GraphQLString),
1932
+ item: new GraphQLNonNull(GraphQLID),
1933
+ to: new GraphQLNonNull(GraphQLID),
1934
+ },
1935
+ resolve: async (_, args) => {
1936
+ const service = new UtilsService({
1937
+ accountability: this.accountability,
1938
+ schema: this.schema,
1939
+ });
1940
+ const { item, to } = args;
1941
+ await service.sort(args['collection'], { item, to });
1942
+ return true;
1943
+ },
1944
+ },
1945
+ utils_revert: {
1946
+ type: GraphQLBoolean,
1947
+ args: {
1948
+ revision: new GraphQLNonNull(GraphQLID),
1949
+ },
1950
+ resolve: async (_, args) => {
1951
+ const service = new RevisionsService({
1952
+ accountability: this.accountability,
1953
+ schema: this.schema,
1954
+ });
1955
+ await service.revert(args['revision']);
1956
+ return true;
1957
+ },
1958
+ },
1959
+ utils_cache_clear: {
1960
+ type: GraphQLVoid,
1961
+ resolve: async () => {
1962
+ if (this.accountability?.admin !== true) {
1963
+ throw new ForbiddenException();
1964
+ }
1965
+ const { cache } = getCache();
1966
+ await cache?.clear();
1967
+ await clearSystemCache();
1968
+ return;
1969
+ },
1970
+ },
1971
+ users_invite_accept: {
1972
+ type: GraphQLBoolean,
1973
+ args: {
1974
+ token: new GraphQLNonNull(GraphQLString),
1975
+ password: new GraphQLNonNull(GraphQLString),
1976
+ },
1977
+ resolve: async (_, args) => {
1978
+ const service = new UsersService({
1979
+ accountability: this.accountability,
1980
+ schema: this.schema,
1981
+ });
1982
+ await service.acceptInvite(args['token'], args['password']);
1983
+ return true;
1984
+ },
1985
+ },
1986
+ });
1987
+ if ('directus_collections' in schema.read.collections) {
1988
+ Collection.addFields({
1989
+ collection: GraphQLString,
1990
+ meta: schemaComposer.createObjectTC({
1991
+ name: 'directus_collections_meta',
1992
+ fields: Object.values(schema.read.collections['directus_collections'].fields).reduce((acc, field) => {
1993
+ acc[field.field] = {
1994
+ type: field.nullable
1995
+ ? getGraphQLType(field.type, field.special)
1996
+ : new GraphQLNonNull(getGraphQLType(field.type, field.special)),
1997
+ description: field.note,
1998
+ };
1999
+ return acc;
2000
+ }, {}),
2001
+ }),
2002
+ schema: schemaComposer.createObjectTC({
2003
+ name: 'directus_collections_schema',
2004
+ fields: {
2005
+ name: GraphQLString,
2006
+ comment: GraphQLString,
2007
+ },
2008
+ }),
2009
+ });
2010
+ schemaComposer.Query.addFields({
2011
+ collections: {
2012
+ type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Collection.getType()))),
2013
+ resolve: async () => {
2014
+ const collectionsService = new CollectionsService({
2015
+ accountability: this.accountability,
2016
+ schema: this.schema,
2017
+ });
2018
+ return await collectionsService.readByQuery();
2019
+ },
2020
+ },
2021
+ collections_by_name: {
2022
+ type: Collection,
2023
+ args: {
2024
+ name: new GraphQLNonNull(GraphQLString),
2025
+ },
2026
+ resolve: async (_, args) => {
2027
+ const collectionsService = new CollectionsService({
2028
+ accountability: this.accountability,
2029
+ schema: this.schema,
2030
+ });
2031
+ return await collectionsService.readOne(args['name']);
2032
+ },
2033
+ },
2034
+ });
2035
+ }
2036
+ if ('directus_fields' in schema.read.collections) {
2037
+ Field.addFields({
2038
+ collection: GraphQLString,
2039
+ field: GraphQLString,
2040
+ type: GraphQLString,
2041
+ meta: schemaComposer.createObjectTC({
2042
+ name: 'directus_fields_meta',
2043
+ fields: Object.values(schema.read.collections['directus_fields'].fields).reduce((acc, field) => {
2044
+ acc[field.field] = {
2045
+ type: field.nullable
2046
+ ? getGraphQLType(field.type, field.special)
2047
+ : new GraphQLNonNull(getGraphQLType(field.type, field.special)),
2048
+ description: field.note,
2049
+ };
2050
+ return acc;
2051
+ }, {}),
2052
+ }),
2053
+ schema: schemaComposer.createObjectTC({
2054
+ name: 'directus_fields_schema',
2055
+ fields: {
2056
+ name: GraphQLString,
2057
+ table: GraphQLString,
2058
+ data_type: GraphQLString,
2059
+ default_value: GraphQLString,
2060
+ max_length: GraphQLInt,
2061
+ numeric_precision: GraphQLInt,
2062
+ numeric_scale: GraphQLInt,
2063
+ is_nullable: GraphQLBoolean,
2064
+ is_unique: GraphQLBoolean,
2065
+ is_primary_key: GraphQLBoolean,
2066
+ has_auto_increment: GraphQLBoolean,
2067
+ foreign_key_column: GraphQLString,
2068
+ foreign_key_table: GraphQLString,
2069
+ comment: GraphQLString,
2070
+ },
2071
+ }),
2072
+ });
2073
+ schemaComposer.Query.addFields({
2074
+ fields: {
2075
+ type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Field.getType()))),
2076
+ resolve: async () => {
2077
+ const service = new FieldsService({
2078
+ accountability: this.accountability,
2079
+ schema: this.schema,
2080
+ });
2081
+ return await service.readAll();
2082
+ },
2083
+ },
2084
+ fields_in_collection: {
2085
+ type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Field.getType()))),
2086
+ args: {
2087
+ collection: new GraphQLNonNull(GraphQLString),
2088
+ },
2089
+ resolve: async (_, args) => {
2090
+ const service = new FieldsService({
2091
+ accountability: this.accountability,
2092
+ schema: this.schema,
2093
+ });
2094
+ return await service.readAll(args['collection']);
2095
+ },
2096
+ },
2097
+ fields_by_name: {
2098
+ type: Field,
2099
+ args: {
2100
+ collection: new GraphQLNonNull(GraphQLString),
2101
+ field: new GraphQLNonNull(GraphQLString),
2102
+ },
2103
+ resolve: async (_, args) => {
2104
+ const service = new FieldsService({
2105
+ accountability: this.accountability,
2106
+ schema: this.schema,
2107
+ });
2108
+ return await service.readOne(args['collection'], args['field']);
2109
+ },
2110
+ },
2111
+ });
2112
+ }
2113
+ if ('directus_relations' in schema.read.collections) {
2114
+ Relation.addFields({
2115
+ collection: GraphQLString,
2116
+ field: GraphQLString,
2117
+ related_collection: GraphQLString,
2118
+ schema: schemaComposer.createObjectTC({
2119
+ name: 'directus_relations_schema',
2120
+ fields: {
2121
+ table: new GraphQLNonNull(GraphQLString),
2122
+ column: new GraphQLNonNull(GraphQLString),
2123
+ foreign_key_table: new GraphQLNonNull(GraphQLString),
2124
+ foreign_key_column: new GraphQLNonNull(GraphQLString),
2125
+ constraint_name: GraphQLString,
2126
+ on_update: new GraphQLNonNull(GraphQLString),
2127
+ on_delete: new GraphQLNonNull(GraphQLString),
2128
+ },
2129
+ }),
2130
+ meta: schemaComposer.createObjectTC({
2131
+ name: 'directus_relations_meta',
2132
+ fields: Object.values(schema.read.collections['directus_relations'].fields).reduce((acc, field) => {
2133
+ acc[field.field] = {
2134
+ type: getGraphQLType(field.type, field.special),
2135
+ description: field.note,
2136
+ };
2137
+ return acc;
2138
+ }, {}),
2139
+ }),
2140
+ });
2141
+ schemaComposer.Query.addFields({
2142
+ relations: {
2143
+ type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Relation.getType()))),
2144
+ resolve: async () => {
2145
+ const service = new RelationsService({
2146
+ accountability: this.accountability,
2147
+ schema: this.schema,
2148
+ });
2149
+ return await service.readAll();
2150
+ },
2151
+ },
2152
+ relations_in_collection: {
2153
+ type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Relation.getType()))),
2154
+ args: {
2155
+ collection: new GraphQLNonNull(GraphQLString),
2156
+ },
2157
+ resolve: async (_, args) => {
2158
+ const service = new RelationsService({
2159
+ accountability: this.accountability,
2160
+ schema: this.schema,
2161
+ });
2162
+ return await service.readAll(args['collection']);
2163
+ },
2164
+ },
2165
+ relations_by_name: {
2166
+ type: Relation,
2167
+ args: {
2168
+ collection: new GraphQLNonNull(GraphQLString),
2169
+ field: new GraphQLNonNull(GraphQLString),
2170
+ },
2171
+ resolve: async (_, args) => {
2172
+ const service = new RelationsService({
2173
+ accountability: this.accountability,
2174
+ schema: this.schema,
2175
+ });
2176
+ return await service.readOne(args['collection'], args['field']);
2177
+ },
2178
+ },
2179
+ });
2180
+ }
2181
+ if (this.accountability?.admin === true) {
2182
+ schemaComposer.Mutation.addFields({
2183
+ create_collections_item: {
2184
+ type: Collection,
2185
+ args: {
2186
+ data: toInputObjectType(Collection.clone('create_directus_collections'), {
2187
+ postfix: '_input',
2188
+ }).addFields({
2189
+ fields: [
2190
+ toInputObjectType(Field.clone('create_directus_collections_fields'), { postfix: '_input' }).NonNull,
2191
+ ],
2192
+ }).NonNull,
2193
+ },
2194
+ resolve: async (_, args) => {
2195
+ const collectionsService = new CollectionsService({
2196
+ accountability: this.accountability,
2197
+ schema: this.schema,
2198
+ });
2199
+ const collectionKey = await collectionsService.createOne(args['data']);
2200
+ return await collectionsService.readOne(collectionKey);
2201
+ },
2202
+ },
2203
+ update_collections_item: {
2204
+ type: Collection,
2205
+ args: {
2206
+ collection: new GraphQLNonNull(GraphQLString),
2207
+ data: toInputObjectType(Collection.clone('update_directus_collections'), {
2208
+ postfix: '_input',
2209
+ }).removeField(['collection', 'schema']).NonNull,
2210
+ },
2211
+ resolve: async (_, args) => {
2212
+ const collectionsService = new CollectionsService({
2213
+ accountability: this.accountability,
2214
+ schema: this.schema,
2215
+ });
2216
+ const collectionKey = await collectionsService.updateOne(args['collection'], args['data']);
2217
+ return await collectionsService.readOne(collectionKey);
2218
+ },
2219
+ },
2220
+ delete_collections_item: {
2221
+ type: schemaComposer.createObjectTC({
2222
+ name: 'delete_collection',
2223
+ fields: {
2224
+ collection: GraphQLString,
2225
+ },
2226
+ }),
2227
+ args: {
2228
+ collection: new GraphQLNonNull(GraphQLString),
2229
+ },
2230
+ resolve: async (_, args) => {
2231
+ const collectionsService = new CollectionsService({
2232
+ accountability: this.accountability,
2233
+ schema: this.schema,
2234
+ });
2235
+ await collectionsService.deleteOne(args['collection']);
2236
+ return { collection: args['collection'] };
2237
+ },
2238
+ },
2239
+ });
2240
+ schemaComposer.Mutation.addFields({
2241
+ create_fields_item: {
2242
+ type: Field,
2243
+ args: {
2244
+ collection: new GraphQLNonNull(GraphQLString),
2245
+ data: toInputObjectType(Field.clone('create_directus_fields'), { postfix: '_input' }).NonNull,
2246
+ },
2247
+ resolve: async (_, args) => {
2248
+ const service = new FieldsService({
2249
+ accountability: this.accountability,
2250
+ schema: this.schema,
2251
+ });
2252
+ await service.createField(args['collection'], args['data']);
2253
+ return await service.readOne(args['collection'], args['data'].field);
2254
+ },
2255
+ },
2256
+ update_fields_item: {
2257
+ type: Field,
2258
+ args: {
2259
+ collection: new GraphQLNonNull(GraphQLString),
2260
+ field: new GraphQLNonNull(GraphQLString),
2261
+ data: toInputObjectType(Field.clone('update_directus_fields'), { postfix: '_input' }).NonNull,
2262
+ },
2263
+ resolve: async (_, args) => {
2264
+ const service = new FieldsService({
2265
+ accountability: this.accountability,
2266
+ schema: this.schema,
2267
+ });
2268
+ await service.updateField(args['collection'], {
2269
+ ...args['data'],
2270
+ field: args['field'],
2271
+ });
2272
+ return await service.readOne(args['collection'], args['data'].field);
2273
+ },
2274
+ },
2275
+ delete_fields_item: {
2276
+ type: schemaComposer.createObjectTC({
2277
+ name: 'delete_field',
2278
+ fields: {
2279
+ collection: GraphQLString,
2280
+ field: GraphQLString,
2281
+ },
2282
+ }),
2283
+ args: {
2284
+ collection: new GraphQLNonNull(GraphQLString),
2285
+ field: new GraphQLNonNull(GraphQLString),
2286
+ },
2287
+ resolve: async (_, args) => {
2288
+ const service = new FieldsService({
2289
+ accountability: this.accountability,
2290
+ schema: this.schema,
2291
+ });
2292
+ await service.deleteField(args['collection'], args['field']);
2293
+ const { collection, field } = args;
2294
+ return { collection, field };
2295
+ },
2296
+ },
2297
+ });
2298
+ schemaComposer.Mutation.addFields({
2299
+ create_relations_item: {
2300
+ type: Relation,
2301
+ args: {
2302
+ data: toInputObjectType(Relation.clone('create_directus_relations'), { postfix: '_input' }).NonNull,
2303
+ },
2304
+ resolve: async (_, args) => {
2305
+ const relationsService = new RelationsService({
2306
+ accountability: this.accountability,
2307
+ schema: this.schema,
2308
+ });
2309
+ await relationsService.createOne(args['data']);
2310
+ return await relationsService.readOne(args['data'].collection, args['data'].field);
2311
+ },
2312
+ },
2313
+ update_relations_item: {
2314
+ type: Relation,
2315
+ args: {
2316
+ collection: new GraphQLNonNull(GraphQLString),
2317
+ field: new GraphQLNonNull(GraphQLString),
2318
+ data: toInputObjectType(Relation.clone('update_directus_relations'), { postfix: '_input' }).NonNull,
2319
+ },
2320
+ resolve: async (_, args) => {
2321
+ const relationsService = new RelationsService({
2322
+ accountability: this.accountability,
2323
+ schema: this.schema,
2324
+ });
2325
+ await relationsService.updateOne(args['collection'], args['field'], args['data']);
2326
+ return await relationsService.readOne(args['data'].collection, args['data'].field);
2327
+ },
2328
+ },
2329
+ delete_relations_item: {
2330
+ type: schemaComposer.createObjectTC({
2331
+ name: 'delete_relation',
2332
+ fields: {
2333
+ collection: GraphQLString,
2334
+ field: GraphQLString,
2335
+ },
2336
+ }),
2337
+ args: {
2338
+ collection: new GraphQLNonNull(GraphQLString),
2339
+ field: new GraphQLNonNull(GraphQLString),
2340
+ },
2341
+ resolve: async (_, args) => {
2342
+ const relationsService = new RelationsService({
2343
+ accountability: this.accountability,
2344
+ schema: this.schema,
2345
+ });
2346
+ await relationsService.deleteOne(args['collection'], args['field']);
2347
+ return { collection: args['collection'], field: args['field'] };
2348
+ },
2349
+ },
2350
+ });
2351
+ }
2352
+ if ('directus_users' in schema.read.collections) {
2353
+ schemaComposer.Query.addFields({
2354
+ users_me: {
2355
+ type: ReadCollectionTypes['directus_users'],
2356
+ resolve: async (_, args, __, info) => {
2357
+ if (!this.accountability?.user)
2358
+ return null;
2359
+ const service = new UsersService({ schema: this.schema, accountability: this.accountability });
2360
+ const selections = this.replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
2361
+ const query = this.getQuery(args, selections || [], info.variableValues);
2362
+ return await service.readOne(this.accountability.user, query);
2363
+ },
2364
+ },
2365
+ });
2366
+ }
2367
+ if ('directus_users' in schema.update.collections && this.accountability?.user) {
2368
+ schemaComposer.Mutation.addFields({
2369
+ update_users_me: {
2370
+ type: ReadCollectionTypes['directus_users'],
2371
+ args: {
2372
+ data: toInputObjectType(UpdateCollectionTypes['directus_users']),
2373
+ },
2374
+ resolve: async (_, args, __, info) => {
2375
+ if (!this.accountability?.user)
2376
+ return null;
2377
+ const service = new UsersService({
2378
+ schema: this.schema,
2379
+ accountability: this.accountability,
2380
+ });
2381
+ await service.updateOne(this.accountability.user, args['data']);
2382
+ if ('directus_users' in ReadCollectionTypes) {
2383
+ const selections = this.replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
2384
+ const query = this.getQuery(args, selections || [], info.variableValues);
2385
+ return await service.readOne(this.accountability.user, query);
2386
+ }
2387
+ return true;
2388
+ },
2389
+ },
2390
+ });
2391
+ }
2392
+ if ('directus_activity' in schema.create.collections) {
2393
+ schemaComposer.Mutation.addFields({
2394
+ create_comment: {
2395
+ type: ReadCollectionTypes['directus_activity'] ?? GraphQLBoolean,
2396
+ args: {
2397
+ collection: new GraphQLNonNull(GraphQLString),
2398
+ item: new GraphQLNonNull(GraphQLID),
2399
+ comment: new GraphQLNonNull(GraphQLString),
2400
+ },
2401
+ resolve: async (_, args, __, info) => {
2402
+ const service = new ActivityService({
2403
+ accountability: this.accountability,
2404
+ schema: this.schema,
2405
+ });
2406
+ const primaryKey = await service.createOne({
2407
+ ...args,
2408
+ action: Action.COMMENT,
2409
+ user: this.accountability?.user,
2410
+ ip: this.accountability?.ip,
2411
+ user_agent: this.accountability?.userAgent,
2412
+ origin: this.accountability?.origin,
2413
+ });
2414
+ if ('directus_activity' in ReadCollectionTypes) {
2415
+ const selections = this.replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
2416
+ const query = this.getQuery(args, selections || [], info.variableValues);
2417
+ return await service.readOne(primaryKey, query);
2418
+ }
2419
+ return true;
2420
+ },
2421
+ },
2422
+ });
2423
+ }
2424
+ if ('directus_activity' in schema.update.collections) {
2425
+ schemaComposer.Mutation.addFields({
2426
+ update_comment: {
2427
+ type: ReadCollectionTypes['directus_activity'] ?? GraphQLBoolean,
2428
+ args: {
2429
+ id: new GraphQLNonNull(GraphQLID),
2430
+ comment: new GraphQLNonNull(GraphQLString),
2431
+ },
2432
+ resolve: async (_, args, __, info) => {
2433
+ const service = new ActivityService({
2434
+ accountability: this.accountability,
2435
+ schema: this.schema,
2436
+ });
2437
+ const primaryKey = await service.updateOne(args['id'], { comment: args['comment'] });
2438
+ if ('directus_activity' in ReadCollectionTypes) {
2439
+ const selections = this.replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
2440
+ const query = this.getQuery(args, selections || [], info.variableValues);
2441
+ return await service.readOne(primaryKey, query);
2442
+ }
2443
+ return true;
2444
+ },
2445
+ },
2446
+ });
2447
+ }
2448
+ if ('directus_activity' in schema.delete.collections) {
2449
+ schemaComposer.Mutation.addFields({
2450
+ delete_comment: {
2451
+ type: DeleteCollectionTypes['one'],
2452
+ args: {
2453
+ id: new GraphQLNonNull(GraphQLID),
2454
+ },
2455
+ resolve: async (_, args) => {
2456
+ const service = new ActivityService({
2457
+ accountability: this.accountability,
2458
+ schema: this.schema,
2459
+ });
2460
+ await service.deleteOne(args['id']);
2461
+ return { id: args['id'] };
2462
+ },
2463
+ },
2464
+ });
2465
+ }
2466
+ if ('directus_files' in schema.create.collections) {
2467
+ schemaComposer.Mutation.addFields({
2468
+ import_file: {
2469
+ type: ReadCollectionTypes['directus_files'] ?? GraphQLBoolean,
2470
+ args: {
2471
+ url: new GraphQLNonNull(GraphQLString),
2472
+ data: toInputObjectType(CreateCollectionTypes['directus_files']).setTypeName('create_directus_files_input'),
2473
+ },
2474
+ resolve: async (_, args, __, info) => {
2475
+ const service = new FilesService({
2476
+ accountability: this.accountability,
2477
+ schema: this.schema,
2478
+ });
2479
+ const primaryKey = await service.importOne(args['url'], args['data']);
2480
+ if ('directus_files' in ReadCollectionTypes) {
2481
+ const selections = this.replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
2482
+ const query = this.getQuery(args, selections || [], info.variableValues);
2483
+ return await service.readOne(primaryKey, query);
2484
+ }
2485
+ return true;
2486
+ },
2487
+ },
2488
+ });
2489
+ }
2490
+ if ('directus_users' in schema.create.collections) {
2491
+ schemaComposer.Mutation.addFields({
2492
+ users_invite: {
2493
+ type: GraphQLBoolean,
2494
+ args: {
2495
+ email: new GraphQLNonNull(GraphQLString),
2496
+ role: new GraphQLNonNull(GraphQLString),
2497
+ invite_url: GraphQLString,
2498
+ },
2499
+ resolve: async (_, args) => {
2500
+ const service = new UsersService({
2501
+ accountability: this.accountability,
2502
+ schema: this.schema,
2503
+ });
2504
+ await service.inviteUser(args['email'], args['role'], args['invite_url'] || null);
2505
+ return true;
2506
+ },
2507
+ },
2508
+ });
2509
+ }
2510
+ return schemaComposer;
2511
+ }
2512
+ }