@wbce-d9/api 9.26.3

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